public/Import-AppVManagementPackage.ps1

<#
.SYNOPSIS
    Imports App-V Management packages from an App-V Management SQL database into AppVentiX as publishing tasks.
 
.DESCRIPTION
    Import-AppVManagementPackage retrieves packages from an App-V Management SQL database and converts them into
    AppVentiX publishing tasks. The function matches package URLs against the configured AppVentiX Content Shares
    and optionally associates packages with the appropriate Machine Groups based on Content Share location.
    If a Deployment Configuration XML is present in the database, it is saved as an .appd file alongside the package.
 
.PARAMETER SQLServer
    The name or IP address of the SQL Server hosting the App-V Management database.
    Default: 'localhost'.
 
.PARAMETER SQLInstance
    The SQL Server instance name (optional). Leave empty for the default instance.
 
.PARAMETER SQLDatabase
    The name of the App-V Management database.
    Default: 'AppVManagement'.
 
.PARAMETER SQLCredential
    A PSCredential object for SQL Server authentication. Use [System.Management.Automation.PSCredential]::Empty
    for Windows authentication (default).
 
.PARAMETER MatchPackageWithMachineGroup
    When specified, attempts to match each package to the appropriate AppVentiX Machine Group based on its
    Content Share location. If no match is found, the package is published to all Machine Groups.
 
.PARAMETER GUI
    When specified, displays a graphical selection window allowing the user to manually choose which packages
    to import.
 
.PARAMETER ConfigShare
    Internal parameter. Points to the AppVentiX configuration share path. Automatically populated from the
    module configuration and does not normally need to be specified manually.
 
.EXAMPLE
    Import-AppVManagementPackage
 
    Imports all enabled App-V packages from the local SQL Server ('localhost', database 'AppVManagement')
    and publishes them to all Machine Groups.
 
.EXAMPLE
    Import-AppVManagementPackage -SQLServer 'sql01' -SQLDatabase 'AppVManagement' -MatchPackageWithMachineGroup
 
    Imports all enabled App-V packages from SQL Server 'sql01' and associates each package with the corresponding
    AppVentiX Machine Group based on its Content Share location.
 
.EXAMPLE
    Import-AppVManagementPackage -SQLServer 'sql01' -GUI -MatchPackageWithMachineGroup
 
    Displays a selection window listing all available packages so the user can choose which ones to import,
    then associates them with the appropriate Machine Group.
 
.NOTES
    Function : Import-AppVManagementPackage
    Author : John Billekens
    Copyright : (c) John Billekens Consultancy & AppVentiX
    Version : 2026.130.1000
    Requires : SqlServer PowerShell module
#>

function Import-AppVManagementPackage {
    [CmdletBinding()]
    param (
        [String]$SQLServer = "localhost",

        [String]$SQLInstance,

        [String]$SQLDatabase = 'AppVManagement',

        [System.Management.Automation.PSCredential]$SQLCredential = [System.Management.Automation.PSCredential]::Empty,

        [switch]$MatchPackageWithMachineGroup,

        [switch]$GUI,

        [Parameter(DontShow)]
        [ValidateNotNullOrEmpty()]
        [String]$ConfigShare = $Script:AppVentiX.ConfigShare
    )
    $PSDefaultParameterValues['Write-AppVentiXError:Cmdlet'] = $PSCmdlet
    if ($Script:AppVentiXDebugLogEnabled) {
        # Only re-detect the layout (a few Test-Path probes) when debug logging is on.
        Write-AppVentiXDebugLog -Message 'Import-AppVManagementPackage started' -Data @{
            SQLServer                    = $SQLServer
            SQLDatabase                  = $SQLDatabase
            MatchPackageWithMachineGroup = [bool]$MatchPackageWithMachineGroup
            GUI                          = [bool]$GUI
            ConfigShare                  = "$ConfigShare"
            Layout                       = "$(Get-AppVentiXConfigStoreLayout -ConfigShare $ConfigShare)"
            BackendType                  = "$($Script:AppVentiX.BackendType)"
        }
    }
    if (Test-AppVentiXIsLicensed -ConfigShare $ConfigShare) {
        try {
            $SQLParams = @{
                SQLServer     = $SQLServer
                SQLInstance   = $SQLInstance
                SQLDatabase   = $SQLDatabase
                SQLCredential = $SQLCredential
            }
            try {
                $connectionResult = Test-AppVManagementSQLConnection @SQLParams -ErrorAction Stop
                if (-not $connectionResult) {
                    Write-AppVentiXError -Message "Cannot connect to the App-V Management database on server '$serverInstance'." `
                        -ErrorId 'SQLConnectionFailed' `
                        -Category ConnectionError `
                        -Cmdlet $PSCmdlet
                    return
                }
            } catch {
                Write-AppVentiXError -Message "Cannot connect to the App-V Management database on server '$serverInstance'." `
                    -ErrorId 'SQLConnectionFailed' `
                    -Category ConnectionError `
                    -Cmdlet $PSCmdlet
                return
            }
            Write-Host "Connected to App-V Management database '$SQLDatabase' on server '$SQLServer'"
            Write-AppVentiXDebugLog -Message 'SQL connection verified' -Level Timing
            Write-Host "Retrieving App-V Management Packages..."
            $AppVentiXContentSharePackages = Get-AppVentiXContentSharePackages -ConfigShare $ConfigShare
            $MachineGroups = Get-AppVentiXMachineGroup -ConfigShare $ConfigShare
            Write-AppVentiXDebugLog -Message 'Retrieved Content Share packages and Machine Groups' -Level Timing -Data @{
                ContentSharePackageCount = @($AppVentiXContentSharePackages).Count
                MachineGroupCount        = @($MachineGroups).Count
            }
            if ($AppVManagementPackageDetails = Get-AppVManagementPackage @SQLParams) {
                Write-AppVentiXDebugLog -Message 'Retrieved App-V Management packages from database' -Level Timing -Data @{
                    PackageCount = @($AppVManagementPackageDetails).Count
                }
                if ($GUI.IsPresent -eq $true) {
                    $AppVManagementPackageDetails = @(
                        $AppVManagementPackageDetails | Select-ObjectFromGrid -Title "Select App-V Management Packages to import" `
                            -ColumnsToShow @('Name', 'Version', 'IsEnabled', 'PackageGuid', 'VersionGuid', 'PackageUrl')
                    )
                }
                if (-not $AppVManagementPackageDetails -or $AppVManagementPackageDetails.Count -eq 0) {
                    Write-Warning "No App-V Management Packages selected for import."
                    return
                }
                Write-Host "Found $($AppVManagementPackageDetails.Count) App-V Management Packages to import."
                foreach ($appVManagementPackage in $AppVManagementPackageDetails) {
                    Write-Host "`r`n================================" -ForegroundColor Cyan
                    if ($appVManagementPackage.IsEnabled -eq $false) {
                        Write-Host "`r`nSkipping disabled App-V Management Package '$($appVManagementPackage.Name)'" -ForegroundColor Yellow
                        continue
                    }
                    Write-Host "`r`nProcessing package '$($appVManagementPackage.Name)'..." -ForegroundColor Cyan
                    Write-AppVentiXDebugLog -Message 'Processing package' -Level Timing -Data @{
                        Package     = "$($appVManagementPackage.Name)"
                        PackageGuid = "$($appVManagementPackage.PackageGuid)"
                        ADGroups    = @($appVManagementPackage.ADGroups).Count
                    }
                    if (-not [string]::IsNullOrEmpty($appVManagementPackage.PackageUrl) -and $appVManagementPackage.PackageUrl.StartsWith('\\')) {
                        $fileServer, $fileserverPath = $appVManagementPackage.PackageUrl.TrimStart('\\').Split('\', 2)
                        $AppVentiXPackage = @($AppVentiXContentSharePackages | Where-Object {
                                $_.FullName -like "\\$($fileServer)*\$($fileserverPath)"
                            })
                        $MachineGroupFriendlyName = 'All Machine Groups'
                        $MachineGroup = $MachineGroups
                        if ($MatchPackageWithMachineGroup.IsPresent -eq $false) {
                            if ($AppVentiXPackage.Count -eq 0) {
                                Write-Warning "Package URL: '$($appVManagementPackage.PackageUrl)'"
                                Write-Warning "Package not found in any of the configured Machine Group Content Shares."
                            }

                        } elseif ($AppVentiXPackage.Count -eq 0) {
                            Write-Warning "Package URL: '$($appVManagementPackage.PackageUrl)'"
                            Write-Warning "Package not found in AppVentiX Content Share Packages. Publishing to All Machine Groups."

                        } elseif ($AppVentiXPackage.Count -gt 1) {
                            Write-Warning "Package URL: '$($appVManagementPackage.PackageUrl)'"
                            Write-Warning "Multiple packages found ($($AppVentiXPackage.Count)) in AppVentiX Content Share Packages matching the specified URL."
                            Write-Warning "Publishing to All Machine Groups."
                        } else {
                            Write-Host "Found package in AppVentiX Content Share Packages." -ForegroundColor Green
                            $MachineGroupFriendlyName = $AppVentiXPackage | Select-Object -ExpandProperty MachineGroup
                            $MachineGroup = $MachineGroups | Where-Object { $_.FriendlyName -ieq $MachineGroupFriendlyName }
                        }
                    } else {
                        Write-Warning "Package URL: '$($appVManagementPackage.PackageUrl)'"
                        Write-Warning "Package is not a valid UNC path. Skipping package."
                        continue
                    }
                    $ContentSharePackageRoots = @($MachineGroup.GroupContentshares | ForEach-Object { $_.ContentShare } | Select-Object -ExpandProperty Path)

                    Write-Host "Importing App-V Management Package to Machine Group '$MachineGroupFriendlyName'" -ForegroundColor Cyan
                    $Fileserver, $Share, $SharePath = "$($appVManagementPackage.PackageUrl)".TrimStart("\\").Split('\', 3)
                    $PackageContentShareMatch = "\\{0}*\{1}" -f $Fileserver, $Share
                    Write-Verbose "Looking for content share matching pattern '$PackageContentShareMatch' in machine group '$MachineGroupFriendlyName'"

                    $ContentSharePackageRoot = $ContentSharePackageRoots | Where-Object { $_ -like $PackageContentShareMatch }

                    if ([string]::IsNullOrEmpty($ContentSharePackageRoot)) {
                        Write-Warning "No matching content share found for package in machine group '$MachineGroupFriendlyName'. Using Original Package URL."
                        $PackagePath = $appVManagementPackage.PackageUrl
                        Write-AppVentiXDebugLog -Message 'Resolved package path (no content share match, using original URL)' -Level Warning -Data @{
                            Package      = "$($appVManagementPackage.Name)"
                            PackagePath  = "$PackagePath"
                            MachineGroup = "$MachineGroupFriendlyName"
                            Matched      = $false
                        }
                    } else {
                        Write-Host "Found matching content share for package." -ForegroundColor Green
                        $ContentShareFileserver, $ContentShareShare = $ContentSharePackageRoot.TrimStart("\\").Split('\', 2)
                        $PackagePath = '\\{0}\{1}\{2}' -f $ContentShareFileserver, $ContentShareShare, $SharePath
                        Write-AppVentiXDebugLog -Message 'Resolved package path from content share match' -Data @{
                            Package         = "$($appVManagementPackage.Name)"
                            PackagePath     = "$PackagePath"
                            ContentShareRoot = "$ContentSharePackageRoot"
                            MachineGroup    = "$MachineGroupFriendlyName"
                            Matched         = $true
                        }
                    }
                    if (Test-Path -Path $PackagePath) {
                        Write-Host "Package found in content share" -ForegroundColor Green
                        $adGroups = @()
                        $appVManagementPackage.ADGroups | ForEach-Object {
                            $adGroupName = '{0}\{1}' -f $_.Domain, $_.Name
                            $adGroups += $adGroupName
                            if (-not [string]::IsNullOrEmpty($($_.UserConfigurationXml))) {
                                Write-Warning "User configuration detected, but only default Deployment Configuration is supported during import."
                            }
                        }
                        $publishingTaskParams = @{
                            MachineGroupFriendlyName = $MachineGroupFriendlyName
                            Group                    = $adGroups
                            Path                     = $PackagePath
                        }
                        Write-Verbose "Creating publishing task with parameters: $($publishingTaskParams | Out-String)"
                        Write-Host "Creating publishing task..."
                        $newTaskId = New-AppVentiXPublishingTask @publishingTaskParams
                        Write-AppVentiXDebugLog -Message 'Created publishing task' -Level Timing -Data @{
                            Package      = "$($appVManagementPackage.Name)"
                            TaskId       = "$($newTaskId.Id)"
                            MachineGroup = "$MachineGroupFriendlyName"
                            ADGroupCount = @($adGroups).Count
                        }
                        Write-Output ([PSCustomObject]@{
                                Name = $appVManagementPackage.Name
                                Id   = $newTaskId.Id
                            })
                        try {
                            if (-not [string]::IsNullOrEmpty($($appVManagementPackage.DeploymentConfigurationXml))) {
                                Write-Host "Deployment configuration XML found. Saving XML data to appd file..." -ForegroundColor Cyan
                                [xml]$DeploymentConfigXml = $($appVManagementPackage.DeploymentConfigurationXml) | Format-XML
                                $appdFilePath = "$PackagePath".Replace('.appv', '_DeploymentConfig.appd')
                                $DeploymentConfigXml.Save($appdFilePath)
                            }
                        } catch {
                            Write-Warning "Failed to save deployment configuration XML to appd file: $($_.Exception.Message)"
                            Write-AppVentiXDebugLog -Message 'Failed to save deployment configuration appd file' -ErrorRecord $_ -Data @{
                                Package      = "$($appVManagementPackage.Name)"
                                AppdFilePath = "$appdFilePath"
                            }
                        }
                    } else {
                        Write-Warning "The package could not be found at path '$PackagePath'. Skipping package import."
                        continue
                    }
                    Write-Host "Successfully created publishing task with Task ID '$($newTaskId.Id)'." -ForegroundColor Green
                }
                Write-Host "`r`n================================" -ForegroundColor Cyan
                Write-Host "`r`nFinished processing App-V Management Packages.`r`n" -ForegroundColor Cyan
                Write-AppVentiXDebugLog -Message 'Finished processing App-V Management packages' -Level Timing
            } else {
                Write-Warning "No App-V Management Packages found in the database '$SQLDatabase' on server '$SQLServer'."
                return
            }
        } catch {
            Write-AppVentiXDebugLog -Message 'Import failed' -ErrorRecord $_
            $ErrorMessage = @{
                Message      = "Failed to import App-V Management Packages: $($_.Exception.Message)"
                ErrorId      = "ImportAppVManagementPackageFailed"
                Category     = [System.Management.Automation.ErrorCategory]::NotSpecified
                TargetObject = $_.Exception
            }
            Write-Verbose $($_ | Get-ExceptionDetails -AsPlainText)
            Write-AppVentiXError @ErrorMessage
        }
    } else {
        throw "AppVentiX is not licensed. Please run the license setup before using this function."
    }
}

# SIG # Begin signature block
# MIImdwYJKoZIhvcNAQcCoIImaDCCJmQCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBZYztFqo2aXDs/
# Alcnebem83QwLCyNvO7yWUw357nZL6CCIAowggYUMIID/KADAgECAhB6I67aU2mW
# D5HIPlz0x+M/MA0GCSqGSIb3DQEBDAUAMFcxCzAJBgNVBAYTAkdCMRgwFgYDVQQK
# Ew9TZWN0aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3RpZ28gUHVibGljIFRpbWUg
# U3RhbXBpbmcgUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNMzYwMzIxMjM1OTU5
# WjBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSwwKgYD
# VQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNjCCAaIwDQYJ
# KoZIhvcNAQEBBQADggGPADCCAYoCggGBAM2Y2ENBq26CK+z2M34mNOSJjNPvIhKA
# VD7vJq+MDoGD46IiM+b83+3ecLvBhStSVjeYXIjfa3ajoW3cS3ElcJzkyZlBnwDE
# JuHlzpbN4kMH2qRBVrjrGJgSlzzUqcGQBaCxpectRGhhnOSwcjPMI3G0hedv2eNm
# GiUbD12OeORN0ADzdpsQ4dDi6M4YhoGE9cbY11XxM2AVZn0GiOUC9+XE0wI7CQKf
# OUfigLDn7i/WeyxZ43XLj5GVo7LDBExSLnh+va8WxTlA+uBvq1KO8RSHUQLgzb1g
# bL9Ihgzxmkdp2ZWNuLc+XyEmJNbD2OIIq/fWlwBp6KNL19zpHsODLIsgZ+WZ1AzC
# s1HEK6VWrxmnKyJJg2Lv23DlEdZlQSGdF+z+Gyn9/CRezKe7WNyxRf4e4bwUtrYE
# 2F5Q+05yDD68clwnweckKtxRaF0VzN/w76kOLIaFVhf5sMM/caEZLtOYqYadtn03
# 4ykSFaZuIBU9uCSrKRKTPJhWvXk4CllgrwIDAQABo4IBXDCCAVgwHwYDVR0jBBgw
# FoAU9ndq3T/9ARP/FqFsggIv0Ao9FCUwHQYDVR0OBBYEFF9Y7UwxeqJhQo1SgLqz
# YZcZojKbMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBMGA1Ud
# JQQMMAoGCCsGAQUFBwMIMBEGA1UdIAQKMAgwBgYEVR0gADBMBgNVHR8ERTBDMEGg
# P6A9hjtodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1lU3Rh
# bXBpbmdSb290UjQ2LmNybDB8BggrBgEFBQcBAQRwMG4wRwYIKwYBBQUHMAKGO2h0
# dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ1Jv
# b3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTAN
# BgkqhkiG9w0BAQwFAAOCAgEAEtd7IK0ONVgMnoEdJVj9TC1ndK/HYiYh9lVUacah
# RoZ2W2hfiEOyQExnHk1jkvpIJzAMxmEc6ZvIyHI5UkPCbXKspioYMdbOnBWQUn73
# 3qMooBfIghpR/klUqNxx6/fDXqY0hSU1OSkkSivt51UlmJElUICZYBodzD3M/SFj
# eCP59anwxs6hwj1mfvzG+b1coYGnqsSz2wSKr+nDO+Db8qNcTbJZRAiSazr7KyUJ
# Go1c+MScGfG5QHV+bps8BX5Oyv9Ct36Y4Il6ajTqV2ifikkVtB3RNBUgwu/mSiSU
# ice/Jp/q8BMk/gN8+0rNIE+QqU63JoVMCMPY2752LmESsRVVoypJVt8/N3qQ1c6F
# ibbcRabo3azZkcIdWGVSAdoLgAIxEKBeNh9AQO1gQrnh1TA8ldXuJzPSuALOz1Uj
# b0PCyNVkWk7hkhVHfcvBfI8NtgWQupiaAeNHe0pWSGH2opXZYKYG4Lbukg7HpNi/
# KqJhue2Keak6qH9A8CeEOB7Eob0Zf+fU+CCQaL0cJqlmnx9HCDxF+3BLbUufrV64
# EbTI40zqegPZdA+sXCmbcZy6okx/SjwsusWRItFA3DE8MORZeFb6BmzBtqKJ7l93
# 9bbKBy2jvxcJI98Va95Q5JnlKor3m0E7xpMeYRriWklUPsetMSf2NvUQa/E5vVye
# fQIwggZFMIIELaADAgECAhAIMk+dt9qRb2Pk8qM8Xl1RMA0GCSqGSIb3DQEBCwUA
# MFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMu
# QS4xJDAiBgNVBAMTG0NlcnR1bSBDb2RlIFNpZ25pbmcgMjAyMSBDQTAeFw0yNDA0
# MDQxNDA0MjRaFw0yNzA0MDQxNDA0MjNaMGsxCzAJBgNVBAYTAk5MMRIwEAYDVQQH
# DAlTY2hpam5kZWwxIzAhBgNVBAoMGkpvaG4gQmlsbGVrZW5zIENvbnN1bHRhbmN5
# MSMwIQYDVQQDDBpKb2huIEJpbGxla2VucyBDb25zdWx0YW5jeTCCAaIwDQYJKoZI
# hvcNAQEBBQADggGPADCCAYoCggGBAMslntDbSQwHZXwFhmibivbnd0Qfn6sqe/6f
# os3pKzKxEsR907RkDMet2x6RRg3eJkiIr3TFPwqBooyXXgK3zxxpyhGOcuIqyM9J
# 28DVf4kUyZHsjGO/8HFjrr3K1hABNUszP0o7H3o6J31eqV1UmCXYhQlNoW9FOmRC
# 1amlquBmh7w4EKYEytqdmdOBavAD5Xq4vLPxNP6kyA+B2YTtk/xM27TghtbwFGKn
# u9Vwnm7dFcpLxans4ONt2OxDQOMA5NwgcUv/YTpjhq9qoz6ivG55NRJGNvUXsM3w
# 2o7dR6Xh4MuEGrTSrOWGg2A5EcLH1XqQtkF5cZnAPM8W/9HUp8ggornWnFVQ9/6M
# ga+ermy5wy5XrmQpN+x3u6tit7xlHk1Hc+4XY4a4ie3BPXG2PhJhmZAn4ebNSBwN
# Hh8z7WTT9X9OFERepGSytZVeEP7hgyptSLcuhpwWeR4QdBb7dV++4p3PsAUQVHFp
# wkSbrRTv4EiJ0Lcz9P1HPGFoHiFAQQIDAQABo4IBeDCCAXQwDAYDVR0TAQH/BAIw
# ADA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY2NzY2EyMDIxLmNybC5jZXJ0dW0u
# cGwvY2NzY2EyMDIxLmNybDBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0
# dHA6Ly9jY3NjYTIwMjEub2NzcC1jZXJ0dW0uY29tMDUGCCsGAQUFBzAChilodHRw
# Oi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvY2NzY2EyMDIxLmNlcjAfBgNVHSMEGDAW
# gBTddF1MANt7n6B0yrFu9zzAMsBwzTAdBgNVHQ4EFgQUO6KtBpOBgmrlANVAnyiQ
# C6W6lJwwSwYDVR0gBEQwQjAIBgZngQwBBAEwNgYLKoRoAYb2dwIFAQQwJzAlBggr
# BgEFBQcCARYZaHR0cHM6Ly93d3cuY2VydHVtLnBsL0NQUzATBgNVHSUEDDAKBggr
# BgEFBQcDAzAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBAEQsN8wg
# PMdWVkwHPPTN+jKpdns5AKVFjcn00psf2NGVVgWWNQBIQc9lEuTBWb54IK6Ga3hx
# QRZfnPNo5HGl73YLmFgdFQrFzZ1lnaMdIcyh8LTWv6+XNWfoyCM9wCp4zMIDPOs8
# LKSMQqA/wRgqiACWnOS4a6fyd5GUIAm4CuaptpFYr90l4Dn/wAdXOdY32UhgzmSu
# xpUbhD8gVJUaBNVmQaRqeU8y49MxiVrUKJXde1BCrtR9awXbqembc7Nqvmi60tYK
# lD27hlpKtj6eGPjkht0hHEsgzU0Fxw7ZJghYG2wXfpF2ziN893ak9Mi/1dmCNmor
# GOnybKYfT6ff6YTCDDNkod4egcMZdOSv+/Qv+HAeIgEvrxE9QsGlzTwbRtbm6gwY
# YcVBs/SsVUdBn/TSB35MMxRhHE5iC3aUTkDbceo/XP3uFhVL4g2JZHpFfCSu2TQr
# rzRn2sn07jfMvzeHArCOJgBW1gPqR3WrJ4hUxL06Rbg1gs9tU5HGGz9KNQMfQFQ7
# 0Wz7UIhezGcFcRfkIfSkMmQYYpsc7rfzj+z0ThfDVzzJr2dMOFsMlfj1T6l22GBq
# 9XQx0A4lcc5Fl9pRxbOuHHWFqIBD/BCEhwniOCySzqENd2N+oz8znKooSISStnkN
# aYXt6xblJF2dx9Dn89FK7d1IquNxOwt0tI5dMIIGYjCCBMqgAwIBAgIRAKQpO24e
# 3denNAiHrXpOtyQwDQYJKoZIhvcNAQEMBQAwVTELMAkGA1UEBhMCR0IxGDAWBgNV
# BAoTD1NlY3RpZ28gTGltaXRlZDEsMCoGA1UEAxMjU2VjdGlnbyBQdWJsaWMgVGlt
# ZSBTdGFtcGluZyBDQSBSMzYwHhcNMjUwMzI3MDAwMDAwWhcNMzYwMzIxMjM1OTU5
# WjByMQswCQYDVQQGEwJHQjEXMBUGA1UECBMOV2VzdCBZb3Jrc2hpcmUxGDAWBgNV
# BAoTD1NlY3RpZ28gTGltaXRlZDEwMC4GA1UEAxMnU2VjdGlnbyBQdWJsaWMgVGlt
# ZSBTdGFtcGluZyBTaWduZXIgUjM2MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEA04SV9G6kU3jyPRBLeBIHPNyUgVNnYayfsGOyYEXrn3+SkDYTLs1crcw/
# ol2swE1TzB2aR/5JIjKNf75QBha2Ddj+4NEPKDxHEd4dEn7RTWMcTIfm492TW22I
# 8LfH+A7Ehz0/safc6BbsNBzjHTt7FngNfhfJoYOrkugSaT8F0IzUh6VUwoHdYDpi
# ln9dh0n0m545d5A5tJD92iFAIbKHQWGbCQNYplqpAFasHBn77OqW37P9BhOASdmj
# p3IijYiFdcA0WQIe60vzvrk0HG+iVcwVZjz+t5OcXGTcxqOAzk1frDNZ1aw8nFhG
# EvG0ktJQknnJZE3D40GofV7O8WzgaAnZmoUn4PCpvH36vD4XaAF2CjiPsJWiY/j2
# xLsJuqx3JtuI4akH0MmGzlBUylhXvdNVXcjAuIEcEQKtOBR9lU4wXQpISrbOT8ux
# +96GzBq8TdbhoFcmYaOBZKlwPP7pOp5Mzx/UMhyBA93PQhiCdPfIVOCINsUY4U23
# p4KJ3F1HqP3H6Slw3lHACnLilGETXRg5X/Fp8G8qlG5Y+M49ZEGUp2bneRLZoyHT
# yynHvFISpefhBCV0KdRZHPcuSL5OAGWnBjAlRtHvsMBrI3AAA0Tu1oGvPa/4yeei
# Ayu+9y3SLC98gDVbySnXnkujjhIh+oaatsk/oyf5R2vcxHahajMCAwEAAaOCAY4w
# ggGKMB8GA1UdIwQYMBaAFF9Y7UwxeqJhQo1SgLqzYZcZojKbMB0GA1UdDgQWBBSI
# YYyhKjdkgShgoZsx0Iz9LALOTzAOBgNVHQ8BAf8EBAMCBsAwDAYDVR0TAQH/BAIw
# ADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDBKBgNVHSAEQzBBMDUGDCsGAQQBsjEB
# AgEDCDAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZn
# gQwBBAIwSgYDVR0fBEMwQTA/oD2gO4Y5aHR0cDovL2NybC5zZWN0aWdvLmNvbS9T
# ZWN0aWdvUHVibGljVGltZVN0YW1waW5nQ0FSMzYuY3JsMHoGCCsGAQUFBwEBBG4w
# bDBFBggrBgEFBQcwAoY5aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVi
# bGljVGltZVN0YW1waW5nQ0FSMzYuY3J0MCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz
# cC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAYEAAoE+pIZyUSH5ZakuPVKK
# 4eWbzEsTRJOEjbIu6r7vmzXXLpJx4FyGmcqnFZoa1dzx3JrUCrdG5b//LfAxOGy9
# Ph9JtrYChJaVHrusDh9NgYwiGDOhyyJ2zRy3+kdqhwtUlLCdNjFjakTSE+hkC9F5
# ty1uxOoQ2ZkfI5WM4WXA3ZHcNHB4V42zi7Jk3ktEnkSdViVxM6rduXW0jmmiu71Z
# pBFZDh7Kdens+PQXPgMqvzodgQJEkxaION5XRCoBxAwWwiMm2thPDuZTzWp/gUFz
# i7izCmEt4pE3Kf0MOt3ccgwn4Kl2FIcQaV55nkjv1gODcHcD9+ZVjYZoyKTVWb4V
# qMQy/j8Q3aaYd/jOQ66Fhk3NWbg2tYl5jhQCuIsE55Vg4N0DUbEWvXJxtxQQaVR5
# xzhEI+BjJKzh3TQ026JxHhr2fuJ0mV68AluFr9qshgwS5SpN5FFtaSEnAwqZv3IS
# +mlG50rK7W3qXbWwi4hmpylUfygtYLEdLQukNEX1jiOKMIIGgjCCBGqgAwIBAgIQ
# NsKwvXwbOuejs902y8l1aDANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UEBhMCVVMx
# EzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYD
# VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBS
# U0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjEwMzIyMDAwMDAwWhcNMzgw
# MTE4MjM1OTU5WjBXMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1p
# dGVkMS4wLAYDVQQDEyVTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIFJvb3Qg
# UjQ2MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAiJ3YuUVnnR3d6Lkm
# gZpUVMB8SQWbzFoVD9mUEES0QUCBdxSZqdTkdizICFNeINCSJS+lV1ipnW5ihkQy
# C0cRLWXUJzodqpnMRs46npiJPHrfLBOifjfhpdXJ2aHHsPHggGsCi7uE0awqKggE
# /LkYw3sqaBia67h/3awoqNvGqiFRJ+OTWYmUCO2GAXsePHi+/JUNAax3kpqstbl3
# vcTdOGhtKShvZIvjwulRH87rbukNyHGWX5tNK/WABKf+Gnoi4cmisS7oSimgHUI0
# Wn/4elNd40BFdSZ1EwpuddZ+Wr7+Dfo0lcHflm/FDDrOJ3rWqauUP8hsokDoI7D/
# yUVI9DAE/WK3Jl3C4LKwIpn1mNzMyptRwsXKrop06m7NUNHdlTDEMovXAIDGAvYy
# nPt5lutv8lZeI5w3MOlCybAZDpK3Dy1MKo+6aEtE9vtiTMzz/o2dYfdP0KWZwZIX
# bYsTIlg1YIetCpi5s14qiXOpRsKqFKqav9R1R5vj3NgevsAsvxsAnI8Oa5s2oy25
# qhsoBIGo/zi6GpxFj+mOdh35Xn91y72J4RGOJEoqzEIbW3q0b2iPuWLA911cRxgY
# 5SJYubvjay3nSMbBPPFsyl6mY4/WYucmyS9lo3l7jk27MAe145GWxK4O3m3gEFEI
# kv7kRmefDR7Oe2T1HxAnICQvr9sCAwEAAaOCARYwggESMB8GA1UdIwQYMBaAFFN5
# v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBT2d2rdP/0BE/8WoWyCAi/QCj0U
# JTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zATBgNVHSUEDDAKBggr
# BgEFBQcDCDARBgNVHSAECjAIMAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0
# cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25B
# dXRob3JpdHkuY3JsMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDov
# L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEADr5lQe1oRLjl
# ocXUEYfktzsljOt+2sgXke3Y8UPEooU5y39rAARaAdAxUeiX1ktLJ3+lgxtoLQhn
# 5cFb3GF2SSZRX8ptQ6IvuD3wz/LNHKpQ5nX8hjsDLRhsyeIiJsms9yAWnvdYOdEM
# q1W61KE9JlBkB20XBee6JaXx4UBErc+YuoSb1SxVf7nkNtUjPfcxuFtrQdRMRi/f
# InV/AobE8Gw/8yBMQKKaHt5eia8ybT8Y/Ffa6HAJyz9gvEOcF1VWXG8OMeM7Vy7B
# s6mSIkYeYtddU1ux1dQLbEGur18ut97wgGwDiGinCwKPyFO7ApcmVJOtlw9FVJxw
# /mL1TbyBns4zOgkaXFnnfzg4qbSvnrwyj1NiurMp4pmAWjR+Pb/SIduPnmFzbSN/
# G8reZCL4fvGlvPFk4Uab/JVCSmj59+/mB2Gn6G/UYOy8k60mKcmaAZsEVkhOFuoj
# 4we8CYyaR9vd9PGZKSinaZIkvVjbH/3nlLb0a7SBIkiRzfPfS9T+JesylbHa1LtR
# V9U/7m0q7Ma2CQ/t392ioOssXW7oKLdOmMBl14suVFBmbzrt5V5cQPnwtd3UOTpS
# 9oCG+ZZheiIvPgkDmA8FzPsnfXW5qHELB43ET7HHFHeRPRYrMBKjkb8/IN7Po0d0
# hQoF4TeMM+zYAJzoKQnVKOLg8pZVPT8wgga5MIIEoaADAgECAhEAmaOACiZVO2Wr
# 3G6EprPqOTANBgkqhkiG9w0BAQwFADCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoT
# GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0
# aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0
# d29yayBDQSAyMB4XDTIxMDUxOTA1MzIxOFoXDTM2MDUxODA1MzIxOFowVjELMAkG
# A1UEBhMCUEwxITAfBgNVBAoTGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEkMCIG
# A1UEAxMbQ2VydHVtIENvZGUgU2lnbmluZyAyMDIxIENBMIICIjANBgkqhkiG9w0B
# AQEFAAOCAg8AMIICCgKCAgEAnSPPBDAjO8FGLOczcz5jXXp1ur5cTbq96y34vuTm
# flN4mSAfgLKTvggv24/rWiVGzGxT9YEASVMw1Aj8ewTS4IndU8s7VS5+djSoMcbv
# IKck6+hI1shsylP4JyLvmxwLHtSworV9wmjhNd627h27a8RdrT1PH9ud0IF+njvM
# k2xqbNTIPsnWtw3E7DmDoUmDQiYi/ucJ42fcHqBkbbxYDB7SYOouu9Tj1yHIohzu
# C8KNqfcYf7Z4/iZgkBJ+UFNDcc6zokZ2uJIxWgPWXMEmhu1gMXgv8aGUsRdaCtVD
# 2bSlbfsq7BiqljjaCun+RJgTgFRCtsuAEw0pG9+FA+yQN9n/kZtMLK+Wo837Q4QO
# ZgYqVWQ4x6cM7/G0yswg1ElLlJj6NYKLw9EcBXE7TF3HybZtYvj9lDV2nT8mFSkc
# SkAExzd4prHwYjUXTeZIlVXqj+eaYqoMTpMrfh5MCAOIG5knN4Q/JHuurfTI5XDY
# O962WZayx7ACFf5ydJpoEowSP07YaBiQ8nXpDkNrUA9g7qf/rCkKbWpQ5boufUnq
# 1UiYPIAHlezf4muJqxqIns/kqld6JVX8cixbd6PzkDpwZo4SlADaCi2JSplKShBS
# ND36E/ENVv8urPS0yOnpG4tIoBGxVCARPCg1BnyMJ4rBJAcOSnAWd18Jx5n858JS
# qPECAwEAAaOCAVUwggFRMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFN10XUwA
# 23ufoHTKsW73PMAywHDNMB8GA1UdIwQYMBaAFLahVDkCw6A/joq8+tT4HKbROg79
# MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDAzAwBgNVHR8EKTAn
# MCWgI6Ahhh9odHRwOi8vY3JsLmNlcnR1bS5wbC9jdG5jYTIuY3JsMGwGCCsGAQUF
# BwEBBGAwXjAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2VydHVtLmNv
# bTAyBggrBgEFBQcwAoYmaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBsL2N0bmNh
# Mi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6Ly93
# d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQwFAAOCAgEAdYhYD+WPUCiaU58Q
# 7EP89DttyZqGYn2XRDhJkL6P+/T0IPZyxfxiXumYlARMgwRzLRUStJl490L94C9L
# GF3vjzzH8Jq3iR74BRlkO18J3zIdmCKQa5LyZ48IfICJTZVJeChDUyuQy6rGDxLU
# UAsO0eqeLNhLVsgw6/zOfImNlARKn1FP7o0fTbj8ipNGxHBIutiRsWrhWM2f8pXd
# d3x2mbJCKKtl2s42g9KUJHEIiLni9ByoqIUul4GblLQigO0ugh7bWRLDm0CdY9rN
# LqyA3ahe8WlxVWkxyrQLjH8ItI17RdySaYayX3PhRSC4Am1/7mATwZWwSD+B7eMc
# ZNhpn8zJ+6MTyE6YoEBSRVrs0zFFIHUR08Wk0ikSf+lIe5Iv6RY3/bFAEloMU+vU
# BfSouCReZwSLo8WdrDlPXtR0gicDnytO7eZ5827NS2x7gCBibESYkOh1/w1tVxTp
# V2Na3PR7nxYVlPu1JPoRZCbH86gc96UTvuWiOruWmyOEMLOGGniR+x+zPF/2DaGg
# K2W1eEJfo2qyrBNPvF7wuAyQfiFXLwvWHamoYtPZo0LHuH8X3n9C+xN4YaNjt2yw
# zOr+tKyEVAotnyU9vyEVOaIYMk3IeBrmFnn0gbKeTTyYeEEUz/Qwt4HOUBCrW602
# NCmvO1nm+/80nLy5r0AZvCQxaQ4xggXDMIIFvwIBATBqMFYxCzAJBgNVBAYTAlBM
# MSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0Nl
# cnR1bSBDb2RlIFNpZ25pbmcgMjAyMSBDQQIQCDJPnbfakW9j5PKjPF5dUTANBglg
# hkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3
# DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEV
# MC8GCSqGSIb3DQEJBDEiBCCRDBp5sVy87tuL2/8OgbL5qU9HBh/b8NyzBLk7xcxn
# PTANBgkqhkiG9w0BAQEFAASCAYCfgaPbojx83HDONITwkIkzi6Qioebmve5iSaJX
# PBtF1iUjjtW/OWBuWcACrXF5d3m3Bdh2OmuaQnrZFdI5WuSCGp/hoYO9Dero1J+M
# QHN/I4pA3p+SCnl3yO4TkipyT+2TPl5KhH0P0iVSUOSgo2sa1Q3U+XYj2UbsOCN+
# kztlwIVjoysxxyNKo8sKymXj0/Odinvd4Wkwqk9KKfoPM58SA4IetNNtFCCWAUtI
# P5PLSmieM7UwrqhNYI6o0+1+6maSsXcvKvAIcCvTnybb2G5y4A1XOAzPJjf7qxBd
# ZJEHcbamegHHLD78272gk9CcXQVzQOs6Fbe/eSc6uHt/sVZ2m/YXAk4xK6EVMmxs
# Ixt+01dzoSk2Edg3uqUwciLvLoIM99s5RmVMrNUV/L9yDqYpbVtCZkGjTtEIBcvk
# hcO14VEHVrs9KYIZOs9fDGA+GjhWoDfs/TSd/Q1klwyb0meoLPDaIZZ4zy02oDdW
# gajn5unS0BP7GT31G48jYaWm9IehggMjMIIDHwYJKoZIhvcNAQkGMYIDEDCCAwwC
# AQEwajBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSww
# KgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNgIRAKQp
# O24e3denNAiHrXpOtyQwDQYJYIZIAWUDBAICBQCgeTAYBgkqhkiG9w0BCQMxCwYJ
# KoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNjA2MTYxODMyNTJaMD8GCSqGSIb3
# DQEJBDEyBDCOR+3n/PN5nQAuJGfxV18GlmJkxvs+4zkEAzAa6azus8Ki/I41L8e2
# +ekMTKqzHU4wDQYJKoZIhvcNAQEBBQAEggIAGBi3xpaiB6htnRRW9IM/NJVENTuU
# cymhqfwOuAt5D0iFxmW7fMsWBCbnp9U+qn0CUKkgDiScYIpN9lLtva4mPADPJEye
# DVDPBVPVsZRXLq3Zt7t1ME4cUSJ7vCk8MHHazwdQN1KDJFHrznkc95ZEwTHO/lDn
# jJC+YLGZWSGThazz9PIY079OCQE2oPernVQ+LZ1WhDkRqUyMEB/sSOsvX5qWRXKb
# jbkMkUreZGkwNNMNsPua2o7tOXb3gCnHj++f1w5vqLXeE2VOoxt7Lts0TZPwnynS
# zEf8eaOLGHdwZLdoiYagHFMriGd3sVzxIQWYG4NEKkIRxWnsvjLcop0f+POw83xQ
# llVjdCGIliSQbFhMYGcjjR2T6HQUexLbpqOFwMP6GXhdRApWKaWvFE+MdPEzr8jo
# AQWV46odo1d19e0BxGFRNGXev+j00gT8KhuVOCJhvGX3lY9rM2d4sfuY+JMkgW2p
# NSIgURZ5dhJLBvvLS03OL/+ZNq51rsPWmlNCivaKYPsupN6CHtO41jNL4Q+gtojb
# j6Ux+eaXij8AULFTEzlVw4fNH0sXadmefabsZjaBNXZzJ0Q8sVqLM8HhAEJiZKOO
# JCmEUo1cbGeQ7trw7/zQxrtUi/LUGPJRxSfd7vhDKUl1eSk/JGjDpjxhBby70DN4
# /Zto+cPjg7gNmcc=
# SIG # End signature block