ConnectedKubernetes.Autorest/custom/Set-AzConnectedKubernetes.ps1


# ----------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# 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.
# Code generated by Microsoft (R) AutoRest Code Generator.Changes may cause incorrect behavior and will be lost if the code
# is regenerated.
# ----------------------------------------------------------------------------------

[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '',
    Justification = 'Kubernetes is a recognised term', Scope = 'Function', Target = 'Set-AzConnectedKubernetes')]
[CmdletBinding()]
param()

<#
.Synopsis
API to set properties of the connected cluster resource
.Description
API to set properties of the connected cluster resource
.Example
Set-AzConnectedKubernetes -ClusterName azps_test_cluster -ResourceGroupName azps_test_group -Location eastus -GatewayResourceId $gatewayResourceId
.Example
Set-AzConnectedKubernetes -ClusterName azps_test_cluster1 -ResourceGroupName azps_test_group -Location eastus -KubeConfig $HOME\.kube\config -KubeContext azps_aks_t01 -DisableGateway
 
.Outputs
Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Models.Api20240715Preview.IConnectedCluster
.Notes
COMPLEX PARAMETER PROPERTIES
 
To create the parameters described below, construct a hash table containing the appropriate properties. For information on hash tables, run Get-Help about_Hash_Tables.
 
INPUTOBJECT <IConnectedCluster>:
  Location <String>: The geo-location where the resource lives
  AgentPublicKeyCertificate <String>: Base64 encoded public certificate used by the agent to do the initial handshake to the backend services in Azure.
  IdentityType <ResourceIdentityType>: The type of identity used for the connected cluster. The type 'SystemAssigned, includes a system created identity. The type 'None' means no identity is assigned to the connected cluster.
  [Tag <ITrackedResourceTags>]: Resource tags.
    [(Any) <String>]: This indicates any property can be added to this object.
  [AadProfileAdminGroupObjectID <String[]>]: The list of AAD group object IDs that will have admin role of the cluster.
  [AadProfileEnableAzureRbac <Boolean?>]: Whether to enable Azure RBAC for Kubernetes authorization.
  [AadProfileTenantId <String>]: The AAD tenant ID to use for authentication. If not specified, will use the tenant of the deployment subscription.
  [ArcAgentProfileAgentAutoUpgrade <AutoUpgradeOptions?>]: Indicates whether the Arc agents on the be upgraded automatically to the latest version. Defaults to Enabled.
  [ArcAgentProfileAgentError <IAgentError[]>]: List of arc agentry and system components errors on the cluster resource.
  [ArcAgentProfileDesiredAgentVersion <String>]: Version of the Arc agents to be installed on the cluster resource
  [ArcAgentProfileSystemComponent <ISystemComponent[]>]: List of system extensions that are installed on the cluster resource.
    [MajorVersion <Int32?>]: Major Version of the system extension that is currently installed on the cluster resource.
    [Type <String>]: Type of the system extension
    [UserSpecifiedVersion <String>]: Version of the system extension to be installed on the cluster resource.
  [ArcAgentryConfiguration <IArcAgentryConfigurations[]>]: Configuration settings for customizing the behavior of the connected cluster.
    [Feature <String>]: Specifies the name of the feature for the configuration setting.
    [ProtectedSetting <IArcAgentryConfigurationsProtectedSettings>]: The configuration settings for the feature that contain any sensitive or secret information.
      [(Any) <String>]: This indicates any property can be added to this object.
    [Setting <IArcAgentryConfigurationsSettings>]: The configuration settings for the feature that do not contain any sensitive or secret information.
      [(Any) <String>]: This indicates any property can be added to this object.
  [AzureHybridBenefit <AzureHybridBenefit?>]: Indicates whether Azure Hybrid Benefit is opted in
  [Distribution <String>]: The Kubernetes distribution running on this connected cluster.
  [DistributionVersion <String>]: The Kubernetes distribution version on this connected cluster.
  [GatewayEnabled <Boolean?>]: Indicates whether the gateway for arc router connectivity is enabled.
  [GatewayResourceId <String>]: The resource ID of the gateway used for the Arc router feature.
  [Infrastructure <String>]: The infrastructure on which the Kubernetes cluster represented by this connected cluster is running on.
  [Kind <ConnectedClusterKind?>]: The kind of connected cluster.
  [OidcIssuerProfileEnabled <Boolean?>]: Whether to enable oidc issuer for workload identity integration.
  [OidcIssuerProfileSelfHostedIssuerUrl <String>]: The issuer url for public cloud clusters - AKS, EKS, GKE - used for the workload identity feature.
  [PrivateLinkScopeResourceId <String>]: This is populated only if privateLinkState is enabled. The resource id of the private link scope this connected cluster is assigned to, if any.
  [PrivateLinkState <PrivateLinkState?>]: Property which describes the state of private link on a connected cluster resource.
  [ProvisioningState <ProvisioningState?>]: Provisioning state of the connected cluster resource.
  [SystemDataCreatedAt <DateTime?>]: The timestamp of resource creation (UTC).
  [SystemDataCreatedBy <String>]: The identity that created the resource.
  [SystemDataCreatedByType <CreatedByType?>]: The type of identity that created the resource.
  [SystemDataLastModifiedAt <DateTime?>]: The timestamp of resource modification (UTC).
  [SystemDataLastModifiedBy <String>]: The identity that last modified the resource.
  [SystemDataLastModifiedByType <LastModifiedByType?>]: The type of identity that last modified the resource.
  [WorkloadIdentityEnabled <Boolean?>]: Whether to enable or disable the workload identity Webhook
.Link
https://learn.microsoft.com/powershell/module/az.connectedkubernetes/set-azconnectedkubernetes
#>

function Set-AzConnectedKubernetes {
    [OutputType([Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Models.Api20240715Preview.IConnectedCluster])]
    [CmdletBinding(DefaultParameterSetName = 'SetExpanded', PositionalBinding = $false, SupportsShouldProcess, ConfirmImpact = 'Medium')]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '',
        Justification = 'Code published before this issue was identified')]
    param(
        [Parameter(ParameterSetName = 'SetExpanded', Mandatory)]
        [Parameter(ParameterSetName = 'SetExpandedDisableGateway', Mandatory)]
        [Alias('Name')]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Path')]
        [System.String]
        # The name of the Kubernetes cluster on which get is called.
        ${ClusterName},

        [Parameter(ParameterSetName = 'SetExpanded', Mandatory)]
        [Parameter(ParameterSetName = 'SetExpandedDisableGateway', Mandatory)]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Path')]
        [System.String]
        # The name of the resource group.
        # The name is case insensitive.
        ${ResourceGroupName},

        [Parameter(ParameterSetName = 'SetExpanded', Mandatory)]
        [Parameter(ParameterSetName = 'SetExpandedDisableGateway', Mandatory)]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.String]
        # The geo-location where the resource lives
        ${Location},

        [Parameter(ParameterSetName = 'Set', Mandatory)]
        [Parameter(ParameterSetName = 'SetDisableGateway', Mandatory)]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Models.Api20240715Preview.IConnectedCluster]
        ${InputObject},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Path')]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Runtime.DefaultInfo(Script = '(Get-AzContext).Subscription.Id')]
        [System.String]
        # The ID of the target subscription.
        ${SubscriptionId},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Path')]
        [System.Uri]
        # The http URI of the proxy server for the kubernetes cluster to use
        ${HttpProxy},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Path')]
        [System.Uri]
        # The https URI of the proxy server for the kubernetes cluster to use
        ${HttpsProxy},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Path')]
        [System.String]
        # The comma-separated list of hostnames that should be excluded from the proxy server for the kubernetes cluster to use
        ${NoProxy},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Path')]
        [System.String]
        # The path to the certificate file for proxy or custom Certificate Authority.
        ${ProxyCert},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Path')]
        [System.Management.Automation.SwitchParameter]
        # Flag to disable auto upgrade of arc agents.
        ${DisableAutoUpgrade},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Path')]
        [System.String]
        # Override the default container log path to enable fluent-bit logging.
        ${ContainerLogPath},

        [Parameter(HelpMessage = "Path to the kube config file")]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.String]
        # Path to the kube config file
        ${KubeConfig},

        [Parameter(HelpMessage = "Kubconfig context from current machine")]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.String]
        # Kubconfig context from current machine
        ${KubeContext},

        [Parameter()]
        [ArgumentCompleter([Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Support.AzureHybridBenefit])]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Support.AzureHybridBenefit]
        # Indicates whether Azure Hybrid Benefit is opted in
        ${AzureHybridBenefit},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.String]
        # The Kubernetes distribution running on this connected cluster.
        ${Distribution},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.String]
        # The Kubernetes distribution version on this connected cluster.
        ${DistributionVersion},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.String]
        # The infrastructure on which the Kubernetes cluster represented by this connected cluster is running on.
        ${Infrastructure},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.String]
        # The resource id of the private link scope this connected cluster is assigned to, if any.
        ${PrivateLinkScopeResourceId},

        [Parameter()]
        [ArgumentCompleter([Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Support.PrivateLinkState])]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Support.PrivateLinkState]
        # Property which describes the state of private link on a connected cluster resource.
        ${PrivateLinkState},

        [Parameter()]
        [ArgumentCompleter([Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Support.ProvisioningState])]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Support.ProvisioningState]
        # Provisioning state of the connected cluster resource.
        ${ProvisioningState},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Runtime.Info(PossibleTypes = ([Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Models.Api20.ITrackedResourceTags]))]
        [System.Collections.Hashtable]
        # Resource tags.
        ${Tag},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.String]
        # OID of 'custom-locations' app.
        ${CustomLocationsOid},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.Management.Automation.SwitchParameter]
        # Whether to enable oidc issuer for workload identity integration.
        ${OidcIssuerProfileEnabled},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.String]
        # The issuer url for public cloud clusters - AKS, EKS, GKE - used for the workload identity feature.
        ${OidcIssuerProfileSelfHostedIssuerUrl},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.Management.Automation.SwitchParameter]
        # Whether to enable or disable the workload identity Webhook
        ${WorkloadIdentityEnabled},

        [Parameter()]
        [System.Management.Automation.SwitchParameter]
        # Accept EULA of ConnectedKubernetes, legal term will pop up without this parameter provided
        ${AcceptEULA},

        [Parameter()]
        [Alias('AzureRMContext', 'AzureCredential')]
        [ValidateNotNull()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Azure')]
        [System.Management.Automation.PSObject]
        # The credentials, account, tenant, and subscription used for communication with Azure.
        ${DefaultProfile},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Runtime')]
        [System.Management.Automation.SwitchParameter]
        # Run the command as a job
        ${AsJob},

        [Parameter(DontShow)]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Runtime')]
        [System.Management.Automation.SwitchParameter]
        # Wait for .NET debugger to attach
        ${Break},

        [Parameter(DontShow)]
        [ValidateNotNull()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Runtime')]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Runtime.SendAsyncStep[]]
        # SendAsync Pipeline Steps to be appended to the front of the pipeline
        ${HttpPipelineAppend},

        [Parameter(DontShow)]
        [ValidateNotNull()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Runtime')]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Runtime.SendAsyncStep[]]
        # SendAsync Pipeline Steps to be prepended to the front of the pipeline
        ${HttpPipelinePrepend},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Runtime')]
        [System.Management.Automation.SwitchParameter]
        # Run the command asynchronously
        ${NoWait},

        [Parameter(DontShow)]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Runtime')]
        [System.Uri]
        # The URI of the proxy server for host os to use
        ${Proxy},

        [Parameter(DontShow)]
        [ValidateNotNull()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Runtime')]
        [System.Management.Automation.PSCredential]
        # The credential of the proxy server for host os to use
        ${ProxyCredential},

        [Parameter(DontShow)]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Runtime')]
        [System.Management.Automation.SwitchParameter]
        # Use the default credentials for the proxy
        ${ProxyUseDefaultCredentials},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.Collections.Hashtable]
        # Arc Agentry System Configuration
        ${ConfigurationSetting},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('Body')]
        [System.Collections.Hashtable]
        # Arc Agentry System Protected Configuration
        ${ConfigurationProtectedSetting},

        [Parameter(ParameterSetName = 'SetDisableGateway', Mandatory)]
        [Parameter(ParameterSetName = 'SetExpandedDisableGateway', Mandatory)]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('body')]
        [System.Management.Automation.SwitchParameter]
        ${DisableGateway},

        [Parameter()]
        [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Category('body')]
        [System.String]
        # Arc Gateway resource Id, providing this will enable the gateway
        ${GatewayResourceId}
    )

    process {
        Write-Debug "Checking if Azure Hybrid Benefit is opted in and processing the EULA."
        . "$PSScriptRoot/helpers/HelmHelper.ps1"
        . "$PSScriptRoot/helpers/ConfigDPHelper.ps1"
        . "$PSScriptRoot/helpers/AzCloudMetadataHelper.ps1"
        . "$PSScriptRoot/helpers/UtilsHelper.ps1"

        # Configuration is structured as a hashtable of hashtables where the final
        # values must be strings. Check this!
        Test-ConfigurationSyntax -name 'ConfigurationSetting'
        Test-ConfigurationSyntax -configuration 'ConfigurationProtectedSetting'

        $ProtectedSettingsPlaceholderValue = "redacted"

        if ($AzureHybridBenefit) {
            if (!$AcceptEULA) {
                $legalTermPath = Join-Path $PSScriptRoot -ChildPath "LegalTerm.txt"
                try {
                    $legalTerm = (Get-Content -Path $legalTermPath) -join "`r`n"
                }
                catch {
                    Write-Error "Get legal term failed."
                    throw
                }
                $confirmation = Read-Host $legalTerm"`n[Y] Yes [N] No (default is `"N`")"
                if ($confirmation -ine "Y") {
                    Return
                }
            }
        }
        Write-Debug "Removed the AcceptEULA and InputObject parameters after processing."
        $null = $PSBoundParameters.Remove('AcceptEULA')
        $null = $PSBoundParameters.Remove('InputObject')

        Write-Debug "Determining the kube config file path."
        if ($PSBoundParameters.ContainsKey("KubeConfig")) {
            $Null = $PSBoundParameters.Remove('KubeConfig')
        }
        elseif (Test-Path Env:KUBECONFIG) {
            $KubeConfig = Get-ChildItem -Path $Env:KUBECONFIG
        }
        elseif (Test-Path Env:Home) {
            $KubeConfig = Join-Path -Path $Env:Home -ChildPath '.kube' | Join-Path -ChildPath 'config'
        }
        else {
            $KubeConfig = Join-Path -Path $Home -ChildPath '.kube' | Join-Path -ChildPath 'config'
        }
        Write-Debug "Setting the kube context."
        if (-not (Test-Path $KubeConfig)) {
            Write-Error 'Cannot find the kube-config. Please make sure that you have the kube-config on your machine.'
            return
        }
        if ($PSBoundParameters.ContainsKey('KubeContext')) {
            $Null = $PSBoundParameters.Remove('KubeContext')
        }
        if (($null -eq $KubeContext) -or ($KubeContext -eq '')) {
            $KubeContext = kubectl config current-context
        }

        # Parse value from inputObject
        if ($null -ne $InputObject) {
            $Location = $InputObject.Location
            $PSBoundParameters.Add('Location', $Location)

            $ClusterName = $InputObject.Name
            $PSBoundParameters.Add('ClusterName', $ClusterName)

            $ResourceGroupName = $InputObject.ResourceGroupName
            $PSBoundParameters.Add('ResourceGroupName', $ResourceGroupName)

            if (-not $PSBoundParameters.ContainsKey('DisableGateway')) {
                if (-not $InputObject.GatewayEnabled) {
                    $DisableGateway = -not $InputObject.GatewayEnabled
                }
            }
            if ((-not $PSBoundParameters.ContainsKey('GatewayResourceId')) -and (-not [String]::IsNullOrEmpty($InputObject.GatewayResourceId))) {
                $GatewayResourceId = $InputObject.GatewayResourceId
                $PSBoundParameters.Add('GatewayResourceId', $GatewayResourceId)
            }

            if (-not $PSBoundParameters.ContainsKey('DisableAutoUpgrade')) {
                $DisableAutoUpgrade = ($InputObject.ArcAgentProfileAgentAutoUpgrade -eq 'Disabled')
            }
        }

        if (-not [String]::IsNullOrEmpty($GatewayResourceId) -and -not $DisableGateway) {
            Write-Debug "Gateway enabled"
            $PSBoundParameters.Add('GatewayEnabled', $true)
        }
        # If DisableGateway is provided then set the gateway as disabled and remove gateway resourceId from parameters
        if ($DisableGateway) {
            Write-Debug "Gateway disabled"
            $Null = $PSBoundParameters.Remove('DisableGateway')
            $PSBoundParameters.Add('GatewayEnabled', $false)
        }

        $CommonPSBoundParameters = @{}
        if ($PSBoundParameters.ContainsKey('HttpPipelineAppend')) {
            $CommonPSBoundParameters['HttpPipelineAppend'] = $HttpPipelineAppend
        }
        if ($PSBoundParameters.ContainsKey('HttpPipelinePrepend')) {
            $CommonPSBoundParameters['HttpPipelinePrepend'] = $HttpPipelinePrepend
        }
        if ($PSBoundParameters.ContainsKey('SubscriptionId')) {
            $CommonPSBoundParameters['SubscriptionId'] = $SubscriptionId
        }
        if ($PSBoundParameters.ContainsKey('PrivateLinkState') -and ($null -ne $CustomLocationsOid) -and ($CustomLocationsOid -ne '')) {
            Write-Warning "The features 'cluster-connect' and 'custom-locations' cannot be enabled for a private link enabled connected cluster."
            $CustomLocationsOid = $null
        }
        if ($PSBoundParameters.ContainsKey('CustomLocationsOid')) {
            $Null = $PSBoundParameters.Remove('CustomLocationsOid')
        }
        $IdentityType = [Microsoft.Azure.PowerShell.Cmdlets.ConnectedKubernetes.Support.ResourceIdentityType]::SystemAssigned
        $PSBoundParameters.Add('IdentityType', $IdentityType)

        #Region check helm install
        Confirm-HelmVersion `
            -KubeConfig $KubeConfig `
            -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
            -Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)

        #EndRegion
        $helmClientLocation = 'helm'

        #Region get release namespace
        $ReleaseNamespaces = Get-HelmReleaseNamespaces -KubeConfig $KubeConfig -KubeContext $KubeContext
        $ReleaseNamespace = $ReleaseNamespaces['ReleaseNamespace']
        $ReleaseInstallNamespace = $ReleaseNamespaces['ReleaseInstallNamespace']

        #Endregion

        #Region validate release namespace
        if (-not ([string]::IsNullOrEmpty($ReleaseNamespace))) {
            $Configmap = kubectl get configmap --namespace azure-arc azure-clusterconfig -o json --kubeconfig $KubeConfig | ConvertFrom-Json
            $ConfigmapRgName = $Configmap.data.AZURE_RESOURCE_GROUP
            $ConfigmapClusterName = $Configmap.data.AZURE_RESOURCE_NAME
            try {
                $ExistConnectedKubernetes = Get-AzConnectedKubernetes `
                    -ResourceGroupName $ConfigmapRgName `
                    -ClusterName $ConfigmapClusterName `
                    @CommonPSBoundParameters `
                    -ErrorAction 'silentlycontinue'
                $PSBoundParameters.Add('AgentPublicKeyCertificate', $ExistConnectedKubernetes.AgentPublicKeyCertificate)

                if (($ResourceGroupName.ToLower() -ne $ConfigmapRgName.ToLower()) -or ($ClusterName.ToLower() -ne $ConfigmapClusterName.ToLower())) {
                    Write-Error "The provided cluster name and rg correspond to different cluster"
                    return
                }
            }
            catch {
                Write-Error "The corresponding connected cluster resource does not exist"
                return
            }
        }
        else {
            Write-Error "The azure-arc release namespace couldn't be retrieved, which implies that the kubernetes cluster has not been onboarded to azure-arc."
            return
        }
        #Endregion

        # Adding Helm repo
        $RegistryPath = Set-HelmRepositoryAndModules -KubeConfig $KubeConfig -KubeContext $KubeContext -Location $Location -ProxyCert $ProxyCert -DisableAutoUpgrade $DisableAutoUpgrade -ContainerLogPath $ContainerLogPath -CustomLocationsOid $CustomLocationsOid

        Write-Debug "Processing Helm chart installation options."

        $options = ""

        if ($DisableAutoUpgrade -or ($ExistConnectedKubernetes.ArcAgentProfileAgentAutoUpgrade -eq 'Disabled')) {
            $Null = $PSBoundParameters.Remove('DisableAutoUpgrade')
            $PSBoundParameters.Add('ArcAgentProfileAgentAutoUpgrade', 'Disabled')
        }
        if (-not ([string]::IsNullOrEmpty($ContainerLogPath))) {
            $options += " --set systemDefaultValues.fluent-bit.containerLogPath=$ContainerLogPath"
            $Null = $PSBoundParameters.Remove('ContainerLogPath')
        }
        if (-not ([string]::IsNullOrEmpty($KubeConfig))) {
            $options += " --kubeconfig $KubeConfig"
        }
        if (-not ([string]::IsNullOrEmpty($KubeContext))) {
            $options += " --kube-context $KubeContext"
        }
        if (-not ([string]::IsNullOrEmpty($CustomLocationsOid))) {
            $options += " --set systemDefaultValues.customLocations.oid=$CustomLocationsOid"
            $options += " --set systemDefaultValues.customLocations.enabled=true"
        }

        if ((-not ([string]::IsNullOrEmpty($Proxy))) -and (-not $PSBoundParameters.ContainsKey('ProxyCredential'))) {
            if (-not ([string]::IsNullOrEmpty($Proxy.UserInfo))) {
                try {
                    $userInfo = $Proxy.UserInfo -Split ':'
                    $pass = ConvertTo-SecureString $userInfo[1] -AsPlainText -Force
                    $ProxyCredential = New-Object System.Management.Automation.PSCredential ($userInfo[0] , $pass)
                    $PSBoundParameters.Add('ProxyCredential', $ProxyCredential)
                }
                catch {
                    throw "Please set ProxyCredential or provide username and password in the Proxy parameter"
                }
            }
            else {
                Write-Warning "If the proxy is a private proxy, pass ProxyCredential parameter or provide username and password in the Proxy parameter"
            }
        }
        #Endregion

        #Region Deal with configuration settings and protected settings
        
        # If the user does not provide proxy settings, or configuration settings, we shall use arc config of existing object
        $userProvidedArcConfiguration = (
            ($null -ne $InputObject) -and ($InputObject.ArcAgentryConfiguration.Length > 0) `
                -and (-not ([string]::IsNullOrEmpty($HttpProxy))) `
                -and (-not ([string]::IsNullOrEmpty($HttpsProxy))) `
                -and (-not ([string]::IsNullOrEmpty($NoProxy))) `
                -and ((-not ([string]::IsNullOrEmpty($ProxyCert)))) `
                -and ($PSBoundParameters.ContainsKey('ConfigurationSetting')) `
                -and ($PSBoundParameters.ContainsKey('ConfigurationProtectedSetting')))
        
        if ($null -eq $ConfigurationSetting) {
            $ConfigurationSetting = @{}
        }
        if ($null -eq $ConfigurationProtectedSetting) {
            $ConfigurationProtectedSetting = @{}
        }

        if ($null -ne $InputObject) {
            foreach ($arcAgentConfig in $InputObject.ArcAgentryConfiguration) {
                $ConfigurationSetting[$arcAgentConfig.feature] = $arcAgentConfig.settings
                $ConfigurationProtectedSetting[$arcAgentConfig.feature] = $arcAgentConfig.protectedSettings
            }
        }

        if (-not $ConfigurationProtectedSetting.ContainsKey("proxy")) {
            $ConfigurationProtectedSetting["proxy"] = @{}
        }

        if (-not ([string]::IsNullOrEmpty($HttpProxy))) {
            $HttpProxyStr = $HttpProxy.ToString()
            $HttpProxyStr = $HttpProxyStr -replace ',', '\,'
            $HttpProxyStr = $HttpProxyStr -replace '/', '\/'
            $ConfigurationProtectedSetting["proxy"]["http_proxy"] = $HttpProxyStr
            # Note how we are removing k8s parameters from the list of parameters
            # to pass to the internal (creates ARM object) command.
            $Null = $PSBoundParameters.Remove('HttpProxy')
        }
        if (-not ([string]::IsNullOrEmpty($HttpsProxy))) {
            $HttpsProxyStr = $HttpsProxy.ToString()
            $HttpsProxyStr = $HttpsProxyStr -replace ',', '\,'
            $HttpsProxyStr = $HttpsProxyStr -replace '/', '\/'
            $ConfigurationProtectedSetting["proxy"]["https_proxy"] = $HttpsProxyStr
            $Null = $PSBoundParameters.Remove('HttpsProxy')
        }
        if (-not ([string]::IsNullOrEmpty($NoProxy))) {
            $NoProxy = $NoProxy -replace ',', '\,'
            $NoProxy = $NoProxy -replace '/', '\/'
            $ConfigurationProtectedSetting["proxy"]["no_proxy"] = $NoProxy
            $Null = $PSBoundParameters.Remove('NoProxy')
        }        

        try {
            if ((-not ([string]::IsNullOrEmpty($ProxyCert))) -and (Test-Path $ProxyCert)) {
                $ConfigurationProtectedSetting["proxy"]["proxy_cert"] = $ProxyCert
            }
        }
        catch {
            throw "Unable to find ProxyCert from file path"
        }

        $RedactedProtectedConfiguration = @{}
        # Duplicate the protected settings into the settings.
        foreach ($feature in $ConfigurationProtectedSetting.Keys) {
            if (-not $RedactedProtectedConfiguration.ContainsKey($feature)) {
                $RedactedProtectedConfiguration[$feature] = @{}
            }
            foreach ($setting in $ConfigurationProtectedSetting[$feature].Keys) {
                $RedactedProtectedConfiguration[$feature][$setting] = "${ProtectedSettingsPlaceholderValue}:${feature}:${setting}"
            }
        }
        #Endregion

        # A lot of what follows relies on knowing the cloud we are using and the
        # various endpoints so get that information now.
        $cloudMetadata = Get-AzCloudMetadata `
            -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
            -Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)

        # Perform DP health check
        $configDpinfo = Get-ConfigDPEndpoint `
            -location $Location `
            -Cloud $cloudMetadata `
            -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
            -Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)

        $configDPEndpoint = $configDpInfo.configDPEndpoint

        # If the health check fails (not 200 response), an exception is thrown
        # so we can ignore the output.
        $null = Invoke-ConfigDPHealthCheck `
            -configDPEndpoint $configDPEndpoint `
            -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
            -Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)

        # This call does the "pure ARM" update of the ARM objects.
        Write-Debug "Updating Connected Kubernetes ARM objects."

        # Process the Arc agentry settings and protected settings
        # Create any empty array of IArcAgentryConfigurations.
        # shortened name to avoid class with type name.
        #
        # **NOTE** The Swagger naming does NOT match the names that will be used
        # in the final helm values file. Instead there needs to be an
        # explicit mapping which is done in TWO places:
        # 1. The ConfigDP is able to map the (unprotected) settings but
        # does not have access to the protected settings so...
        # 2. This Powershell script has to perform the mapping for
        # protected settings.
        #
        # This DOES mean that code changes are required both in the
        # Config DP annd this Powershell script if a new Kubernetes
        # feature is added.
        # Do not send protected settings to CCRP
        $arcAgentryConfigs = ConvertTo-ArcAgentryConfiguration `
            -ConfigurationSetting $ConfigurationSetting `
            -RedactedProtectedConfiguration @{} `
            -CCRP $true `
            -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
            -Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)

        # It is possible to set an empty value for these parameters and then
        # the code above gets skipped but we still need to remove the empty
        # values from $PSBoundParameters.
        if ($PSBoundParameters.ContainsKey('ConfigurationSetting')) {
            $PSBoundParameters.Remove('ConfigurationSetting')
        }
        if ($PSBoundParameters.ContainsKey('ConfigurationProtectedSetting')) {
            $PSBoundParameters.Remove('ConfigurationProtectedSetting')
        }

        if ($userProvidedArcConfiguration) {
            $PSBoundParameters.Add('ArcAgentryConfiguration', $arcAgentryConfigs)
        }
        else {
            $PSBoundParameters.Add('ArcAgentryConfiguration', $ExistConnectedKubernetes.ArcAgentryConfiguration)        
        }

        Write-Output "Updating the connected cluster resource...."
        $Response = Az.ConnectedKubernetes.internal\Set-AzConnectedKubernetes @PSBoundParameters
        if ((-not $WhatIfPreference) -and (-not $Response)) {
            Write-Error "Failed to update the 'Kubernetes - Azure Arc' resource"
            return
        }
        $arcAgentryConfigs = ConvertTo-ArcAgentryConfiguration `
            -ConfigurationSetting $ConfigurationSetting `
            -RedactedProtectedConfiguration $RedactedProtectedConfiguration `
            -CCRP $false `
            -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
            -Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)


        # Convert the $Response object into a nested hashtable.
        Write-Debug "PUT response: $Response"
        $Response = ConvertFrom-Json "$Response" -AsHashTable -Depth 10
        
        # Whatif may return empty response
        if (-not $Response) {
            $Response = @{}
        }
        if (-not $Response.ContainsKey('properties')) {
            $Response['properties'] = @{}
        }

        if ($userProvidedArcConfiguration) {
            $Response['properties']['arcAgentryConfigurations'] = $arcAgentryConfigs
        }
        else {
            $Response['properties']['arcAgentryConfigurations'] = $ExistConnectedKubernetes.ArcAgentryConfiguration
        }
        

        # Retrieving Helm chart OCI (Open Container Initiative) Artifact location
        Write-Debug "Retrieving Helm chart OCI (Open Container Initiative) Artifact location."
        $ResponseStr = $Response | ConvertTo-Json -Depth 10
        Write-Debug "PUT response: $ResponseStr"
        
        Write-Output "Preparing helm ...."

        if ($PSCmdlet.ShouldProcess('configDP', 'get helm values from config DP')) {
            $helmValuesDp = Get-HelmValuesFromConfigDP `
                -configDPEndpoint $configDPEndpoint `
                -releaseTrain $ReleaseTrain `
                -requestBody $ResponseStr `
                -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
                -Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)

            Write-Debug "helmValuesDp: $helmValuesDp"
            Write-Debug "OCI Artifact location: ${helmValuesDp.repositoryPath}."

            $registryPath = if ($env:HELMREGISTRY) { $env:HELMREGISTRY } else { $helmValuesDp.repositoryPath }
            Write-Debug "RegistryPath: ${registryPath}."

            $helmValuesContent = $helmValuesDp.helmValuesContent
            Write-Debug "Helm values: ${helmValuesContent}."

            $optionsFromDp = ""
            foreach ($field in $helmValuesContent.PSObject.Properties) {
                if ($field.Value.StartsWith($ProtectedSettingsPlaceholderValue)) {
                    $parsedValue = $field.Value.Split(":")
                    # "${ProtectedSettingsPlaceholderValue}:${feature}:${setting}"
                    $field.Value = $ConfigurationProtectedSetting[$parsedValue[1]][$parsedValue[2]]
                }
                if ($field.Name -eq "global.proxyCert") {
                    $optionsFromDp += " --set-file $($field.Name)=$($field.Value)"
                }
                $optionsFromDp += " --set $($field.Name)=$($field.Value)"
            }
            # In helm, priority is given to new values, so we append $options contains user input last
            $options = $optionsFromDp + $options

            # Set agent version in registry path
            if ($ExistConnectedKubernetes.AgentVersion) {
                $repositoryPath = $repositoryPath -replace "(?<=:).*", $ExistConnectedKubernetes.AgentVersion
            }
        }   

        if ($PSCmdlet.ShouldProcess('configDP', 'get helm chart path')) {
            # Get helm chart path (within the OCI registry).
            $chartPath = Get-HelmChartPath `
                -registryPath $registryPath `
                -kubeConfig $KubeConfig `
                -kubeContext $KubeContext `
                -helmClientLocation $HelmClientLocation `
                -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) `
                -Debug:($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent -eq $true)
            if (Test-Path Env:HELMCHART) {
                $ChartPath = Get-ChildItem -Path $Env:HELMCHART
            }
        }

        # Get current helm values
        if ($PSCmdlet.ShouldProcess($ClusterName, "Get current helm values")) {

            try {
                $userValuesLocation = Join-Path $env:USERPROFILE ".azure\userValues.txt"

                helm get values azure-arc `
                    --debug `
                    --namespace $ReleaseInstallNamespace `
                    --kubeconfig $KubeConfig `
                    --kube-context $KubeContext > $userValuesLocation
            }
            catch {
                throw "Unable to get helm values"
            }
        }

        Write-Output "Executing helm upgrade, this can take a few minutes ...."
        Write-Debug $options -ErrorAction Continue
        if ($DebugPreference -eq "Continue") {
            $options += " --debug"
        }
        if ($PSCmdlet.ShouldProcess($ClusterName, "Update Kubernetes cluster with Azure Arc")) {
            try {
                helm upgrade `
                    --debug `
                    azure-arc `
                    $ChartPath `
                    --namespace $ReleaseInstallNamespace `
                    -f $userValuesLocation `
                    --wait (-split $options)
            }
            catch {
                throw "Unable to install helm release"
            }
            Return $Response
        }

        if ($PSCmdlet.ShouldProcess($ClusterName, "Check agent state of the connected cluster")) {
            if ($PSBoundParameters.ContainsKey('OidcIssuerProfileEnabled') -or $PSBoundParameters.ContainsKey('WorkloadIdentityEnabled') ) {
                $ExistConnectedKubernetes = Get-AzConnectedKubernetes -ResourceGroupName $ResourceGroupName -ClusterName $ClusterName @CommonPSBoundParameters
    
                Write-Output "Cluster configuration is in progress..."
                $timeout = [datetime]::Now.AddMinutes(60)
    
                while (($ExistConnectedKubernetes.ArcAgentProfileAgentState -ne "Succeeded") -and ($ExistConnectedKubernetes.ArcAgentProfileAgentState -ne "Failed") -and ([datetime]::Now -lt $timeout)) {
                    Start-Sleep -Seconds 30
                    $ExistConnectedKubernetes = Get-AzConnectedKubernetes -ResourceGroupName $ResourceGroupName -ClusterName $ClusterName @CommonPSBoundParameters
                }
    
                if ($ExistConnectedKubernetes.ArcAgentProfileAgentState -eq "Succeeded") {
                    Write-Output "Cluster configuration succeeded."
                }
                elseif ($ExistConnectedKubernetes.ArcAgentProfileAgentState -eq "Failed") {
                    Write-Error "Cluster configuration failed."
                }
                else {
                    Write-Error "Cluster configuration timed out after 60 minutes."
                }      
            }
        }
    }
}

# SIG # Begin signature block
# MIIoLQYJKoZIhvcNAQcCoIIoHjCCKBoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCCPSxDOB6+MCgv
# TUhWOpm3yMeuZ14OQgH6eaJNR5y0E6CCDXYwggX0MIID3KADAgECAhMzAAAEBGx0
# Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz
# NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo
# DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3
# a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF
# HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy
# 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC
# Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj
# L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp
# h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3
# cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X
# dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL
# E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi
# u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1
# sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq
# 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb
# DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/
# V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGg0wghoJAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIHAWfmlkBeva/6tHN3v/UHcX
# kGljHyOF/3bB8+T4mXzxMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAnaSvRn/LNKC1jddsXIaMSGZOUk7kthln3g7xIH+mCm2wCe3qITuGyWLt
# r0wVvAdUSjfWmq4tXDVVyPDJzYglJLQZN1slyzC2oL8vUlsVxdWKJXARswWjS/VN
# o578aV0DPKAfwsnU0S6l5qcaBM5bEAL11z/UtIUCdpTS6m35yBkOQyEX3tyu8ryB
# HRfLQ5+0XJARG5tQ7AMNZpWBLwiTNylzHEcxOj2EIiAwJuCEqbvztt7Xhi22JNGY
# y9GgTlW5bSdM5cDh49qy7DZx1WSesz0GbN2oTWG6uElFU3CAF+13uncAiTSN7x5H
# G2qgIBuxmxDKaQPSu1bA/YHC9QSJv6GCF5cwgheTBgorBgEEAYI3AwMBMYIXgzCC
# F38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCAI14zu2IcLMfTP9+ozyEvK4Jv02Yb9vd24yI/HmVO0XQIGZwf/s/n3
# GBMyMDI0MTAxNzA3NTQxNy45NTlaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OTYwMC0w
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
# ghHtMIIHIDCCBQigAwIBAgITMwAAAe+JP1ahWMyo2gABAAAB7zANBgkqhkiG9w0B
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzEyMDYxODQ1
# NDhaFw0yNTAzMDUxODQ1NDhaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OTYwMC0wNUUwLUQ5NDcxJTAjBgNV
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCjC1jinwzgHwhOakZqy17oE4BIBKsm5kX4DUmCBWI0
# lFVpEiK5mZ2Kh59soL4ns52phFMQYGG5kypCipungwP9Nob4VGVE6aoMo5hZ9Nyt
# XR5ZRgb9Z8NR6EmLKICRhD4sojPMg/RnGRTcdf7/TYvyM10jLjmLyKEegMHfvIwP
# mM+AP7hzQLfExDdqCJ2u64Gd5XlnrFOku5U9jLOKk1y70c+Twt04/RLqruv1fGP8
# LmYmtHvrB4TcBsADXSmcFjh0VgQkX4zXFwqnIG8rgY+zDqJYQNZP8O1Yo4kSckHT
# 43XC0oM40ye2+9l/rTYiDFM3nlZe2jhtOkGCO6GqiTp50xI9ITpJXi0vEek8AejT
# 4PKMEO2bPxU63p63uZbjdN5L+lgIcCNMCNI0SIopS4gaVR4Sy/IoDv1vDWpe+I28
# /Ky8jWTeed0O3HxPJMZqX4QB3I6DnwZrHiKn6oE38tgBTCCAKvEoYOTg7r2lF0Iu
# bt/3+VPvKtTCUbZPFOG8jZt9q6AFodlvQntiolYIYtqSrLyXAQIlXGhZ4gNcv4dv
# 1YAilnbWA9CsnYh+OKEFr/4w4M69lI+yaoZ3L/t/UfXpT/+yc7hS/FolcmrGFJTB
# YlS4nE1cuKblwZ/UOG26SLhDONWXGZDKMJKN53oOLSSk4ldR0HlsbT4heLlWlOEl
# JQIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFO1MWqKFwrCbtrw9P8A63bAVSJzLMB8G
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQAYGZa3aCDudbk9EVdkP8xcQGZuIAIPRx9K
# 1CA7uRzBt80fC0aWkuYYhQMvHHJRHUobSM4Uw3zN7fHEN8hhaBDb9NRaGnFWdtHx
# mJ9eMz6Jpn6KiIyi9U5Og7QCTZMl17n2w4eddq5vtk4rRWOVvpiDBGJARKiXWB9u
# 2ix0WH2EMFGHqjIhjWUXhPgR4C6NKFNXHvWvXecJ2WXrJnvvQGXAfNJGETJZGpR4
# 1nUN3ijfiCSjFDxamGPsy5iYu904Hv9uuSXYd5m0Jxf2WNJSXkPGlNhrO27pPxgT
# 111myAR61S3S2hc572zN9yoJEObE98Vy5KEM3ZX53cLefN81F1C9p/cAKkE6u9V6
# ryyl/qSgxu1UqeOZCtG/iaHSKMoxM7Mq4SMFsPT/8ieOdwClYpcw0CjZe5KBx2xL
# a4B1neFib8J8/gSosjMdF3nHiyHx1YedZDtxSSgegeJsi0fbUgdzsVMJYvqVw52W
# qQNu0GRC79ZuVreUVKdCJmUMBHBpTp6VFopL0Jf4Srgg+zRD9iwbc9uZrn+89odp
# InbznYrnPKHiO26qe1ekNwl/d7ro2ItP/lghz0DoD7kEGeikKJWHdto7eVJoJhkr
# UcanTuUH08g+NYwG6S+PjBSB/NyNF6bHa/xR+ceAYhcjx0iBiv90Mn0JiGfnA2/h
# Lj5evhTcAjCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNQ
# MIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjk2MDAtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQBL
# cI81gxbea1Ex2mFbXx7ck+0g/6CBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA6rsPXDAiGA8yMDI0MTAxNzA0MjE0
# OFoYDzIwMjQxMDE4MDQyMTQ4WjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDquw9c
# AgEAMAoCAQACAhKDAgH/MAcCAQACAhPCMAoCBQDqvGDcAgEAMDYGCisGAQQBhFkK
# BAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJ
# KoZIhvcNAQELBQADggEBADAyIv2U6Cq/fHOtH+gvaeHDhYbMR0DDp2iZvcwgqx1W
# xUU/aAS4reQHpqUw0cCVtl2cc35R2MrdKTaZLtpo4/oTGJlRBtpa6jbr4cI5FneT
# HHGs9gPR+ujHI7EGwfGZH8hbHABoe7rsegXr+rfz4BDUFKHl1mzh988npLXwf2iC
# 7456dct2AJyY7QeG5rzWJyPy7j6WJy5lMxDxA8u2h5iAG92L34YbZnRHHgWnOsfK
# zj1DhwNkJssFZvVhNWzKaBkEarh5YpaqS4JOUWxMZt2M0vfY2OtuSmcDqF5NBvbt
# 9W2iH3m9zy2JwbMXUZW2dkpnFI/VVCXsoKYaNQfnKdwxggQNMIIECQIBATCBkzB8
# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N
# aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAe+JP1ahWMyo2gABAAAB
# 7zANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE
# MC8GCSqGSIb3DQEJBDEiBCBWEMuXw9BNB2d8FvLEDuOni0q3Esnd61INc4P1rgMc
# szCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIPBhKEW4Fo3wUz09NQx2a0Db
# cdsX8jovM5LizHmnyX+jMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
# IDIwMTACEzMAAAHviT9WoVjMqNoAAQAAAe8wIgQgqx6ZyCJ8iMdOeGoIiC7NRUdu
# AqCUNrkDstfgGmaOIBwwDQYJKoZIhvcNAQELBQAEggIATmcVBVQdCzzLfdcLEbpm
# osZ5K3FQxjSTIHu1QZ+00i91kOMLcJF6EkwriLnD9kiI8nNayOlBBzorllxt5md8
# 7m04zWcyCtDNsUxem8CPDEYXhCPFgLhRZsABoya/L+oP91hfy2PEEkurz0IAjR3u
# 6d95wo0CX1yjWRkZGIazsi4V1qCBIXhjMQVQYWdYr/UuVzfmsuFY5qnO5wXpzHxA
# uMVOStDFvlCSh2supNORFRQmx/Q5WQOU5rAJXxk62RSW7zQV3a3Lm42DH/fOike4
# lBnZDn3VPLDgIwMJO1wC1xRA83+CxGNvyTkVuETIrOn2y72XRrj7Uu/ERP2Kn2ti
# lQJuTujbmqdr4HsKMs0O2d6CUeWO1tvrRgsGLB0Z49k+Ow6g566FhLbx4VzpGHC2
# hWC9SKJvPz8Ky5O2m4Rqaegi5d0+HpUaatoEncn9mzQaCDa1ClXPlSth18xp31ip
# GmfKL1KwdTtCl0DtzN3eyvbcG+VNvA9jyH9zNLVC32DUwQ+DjfPRFn8YIt6yiigM
# JZGUMdCMZj/6VH4hBqVHowRnqkUczxB7NgatFExaB1XOHmHwZQyFFyOq/2X0On+2
# Zu9YtkQ5Aql65zYAM9ctWDqnryd2GPZOFQYroNRQf6CnClYKHDC3qp6IxNHW2ncR
# 8IKm9RjSzGgXgCfaIUMN7qE=
# SIG # End signature block