public/New-AppVentiXPublishingTask.ps1

<#
    .SYNOPSIS
        Creates a new AppVentiX publishing task.
 
    .DESCRIPTION
        The New-AppVentiXPublishingTask function creates a new publishing task for AppVentiX. It allows you to specify various parameters such as the type of package, machine group, priority, name, version, group, path, and more. The function also checks if the package exists and if AppVentiX is licensed before creating the publishing task.
 
    .PARAMETER Type
        Specifies the type of package. Valid values are 'MSIX', 'APPV', and 'Sharedcontainer'.
 
    .PARAMETER MachineGroupFriendlyname
        Specifies the friendly name of the machine group.
 
    .PARAMETER Priority
        Specifies the priority of the publishing task. Default value is 100.
 
    .PARAMETER Group
        Specifies the group of the publishing task.
        Example: 'contoso.com\group1'
 
    .PARAMETER Path
        Specifies the path to the package file.
 
    .PARAMETER AlwaysPublish
        Indicates whether the package should always be published.
 
    .PARAMETER WhenNotExist
        Specifies the action to take when the package does not exist.
        Valid values are 'Add' and 'Skip'.
 
    .PARAMETER ForceApplicationShutdownWhenUnpublishing
        Indicates whether to force application shutdown when unpublishing.
 
    .PARAMETER PublishSeamless
        Indicates whether to publish the package seamlessly.
 
    .PARAMETER ConfigShare
        Specifies the path to the AppVentiX configuration share.
        You can ommit this parameter if Set-AppVentiXConfigShare has been called.
 
    .EXAMPLE
        New-AppVentiXPublishingTask -Type 'MSIX' -MachineGroupFriendlyname 'Group1' -Priority 50 -Name 'Task1' -Version '1.0' -Group 'Group1' -Path 'C:\Packages\Package1.msix' -AlwaysPublish -WhenNotExist 'Add' -PackageFullName 'Package1' -ForceApplicationShutdownWhenUnpublishing -PublishSeamless -Task 'Add'
 
        Creates a new publishing task with the specified parameters.
 
    .NOTES
        Function : New-AppVentiXPublishingTask
        Author : John Billekens
        Copyright: Copyright (c) AppVentiX
        Version : 1.5
#>

function New-AppVentiXPublishingTask {
    [CmdletBinding(DefaultParameterSetName = 'General', SupportsShouldProcess, ConfirmImpact = 'Low')]
    Param(
        [Parameter(ParameterSetName = 'General', Mandatory)]
        [ValidateSet('MSIX', 'APPV', 'Sharedcontainer')]
        [String]$Type,

        [Parameter(ParameterSetName = 'General')]
        [String]$MachineGroupFriendlyname = 'All Machine Groups',

        [Parameter(ParameterSetName = 'General')]
        [int]$Priority = 100,

        [Parameter(ParameterSetName = 'General', Mandatory)]
        [ValidatePattern('^.*\.*$')]
        [String]$Group,

        [Parameter(ParameterSetName = 'General', Mandatory)]
        [System.IO.FileInfo]$Path,

        [Parameter(ParameterSetName = 'General')]
        [Switch]$AlwaysPublish,

        [Parameter(ParameterSetName = 'General')]
        [ValidateSet('Add', 'Skip')]
        [String]$WhenNotExist = "Add",

        [Parameter(ParameterSetName = 'General')]
        [Switch]$ForceApplicationShutdownWhenUnpublishing,

        [Parameter(ParameterSetName = 'General')]
        [Switch]$PublishSeamless,

        [Parameter(ParameterSetName = 'General')]
        [String]$WVDapplicationgroup,

        [Parameter(ParameterSetName = 'General')]
        [Switch]$PublishInAzure,

        [Parameter(ParameterSetName = 'General')]
        [String]$DynamicUserConfigurationPath,

        [Parameter(ParameterSetName = 'General')]
        [Switch]$ReturnPublishCommand,

        [Parameter(DontShow, ParameterSetName = 'General')]
        [ValidateNotNullOrEmpty()]
        [String]$ConfigShare = $Script:AppVentix.ConfigShare

    )
    if (Test-AppVentiXIsLicensed -ConfigShare $ConfigShare) {
        if (-Not ($Path.Exists)) {
            Throw [System.Management.Automation.ItemNotFoundException] "Package not found: `"$Path`""
        }
        $publishingTasksFullname = Join-Path -Path $ConfigShare -ChildPath $Script:AppVentiX.PublishingTasksFilename
        Write-Verbose "Reading data from $($publishingTasksFullname)"
        $publishingTasksXml = New-Object -TypeName System.Xml.XmlDocument
        try {
            $publishingTasksXml.Load($publishingTasksFullname)
        } catch {
            Write-Verbose "Could not load the Publishing Tasks file, $($_.Exception.Message)"
            if (Test-Path -Path $publishingTasksFullname) {
                Write-Warning "The Publishing Tasks file exists but is not accessible!"
                Throw "The Publishing Tasks file exists but is not accessible!"
            } else {
                Write-Warning "The Publishing Tasks file does not yet exists, creating a new file!"
            }
        }
        $publishingTasksXml = Format-AppVentiXPublishingTasksXml -XmlDocument $publishingTasksXml
        Write-Verbose "Checking the machine group `"$MachineGroupFriendlyname`""
        if (([String]::IsNullOrEmpty($MachineGroupFriendlyname)) -or ($MachineGroupFriendlyname -like 'All Machine Groups')) {
            $MachineGroupFriendlyname = 'All Machine Groups'
            $MachineGroup = 'All'
        } else {
            try {
                $machineGroup = Get-AppVentiXMachineGroup -Name $MachineGroupFriendlyname -ConfigShare $ConfigShare
                if ($null -eq $machineGroup.FriendlyName -or $machineGroup.FriendlyName -notlike $MachineGroupFriendlyname) {
                    Throw "Machine group `"$MachineGroupFriendlyname`" not found!"
                }
            } catch {
                Write-Error $_
                Throw "Machine group `"$MachineGroupFriendlyname`" not found!"
            }
            $MachineGroupFriendlyname = $machineGroup.FriendlyName
            $MachineGroup = $machineGroup.GroupName
        }
        $Action = 'Publish'
        Write-Verbose "Generating a new GUID for the task"
        $Id = [GUID]::NewGuid()

        if ($Group -notlike '*\*')  {
            Write-Warning "The parameter -Group should contain the domain name and the groupname, e.g. `"DOMAIN.LOCAL\GROUP`""
            Write-Warning "Falling back on default (user dns) value: `"$($env:USERDOMAIN)\$Group`""
        }
        $packageDetails = Get-ManifestDetail -Filename $Path
        if ($packageDetails.Type -like 'APPV') {
            Write-Verbose "Package type is APPV"
            $name = $packageDetails.DisplayName
            if ([String]::IsNullOrEmpty($DynamicUserConfigurationPath)) {
                $DynamicUserConfigurationPath = 'None'
            }
            if ($ForceApplicationShutdownWhenUnpublishing -eq $true) {
                Write-Warning "The parameter -ForceApplicationShutdownWhenUnpublishing is not used for APPV files, ignoring the parameter"
            }
        } else {
            Write-Verbose "Package type is MSIX"
            $Name = $packageDetails.Name
            if (-Not [String]::IsNullOrEmpty($DynamicUserConfigurationPath)) {
                Write-Warning "The parameter -DynamicUserConfigurationPath is not used for MSIX files, ignoring the parameter"
                $DynamicUserConfigurationPath = $null
            }
        }
        $Version = $packageDetails.Version
        $PackageFullName = $packageDetails.PackageFullName
        Write-Verbose "Creating a new task element in the XML file"
        $ptUserPackagesElement = $publishingTasksXml.SelectSingleNode("//UserPublishingTasks/Packages")
        $ptTaskElement = $ptUserPackagesElement.AppendChild($publishingTasksXml.CreateElement("Task"))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Type"))).AppendChild($publishingTasksXml.CreateTextNode($Type))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("MachineGroup"))).AppendChild($publishingTasksXml.CreateTextNode($MachineGroup))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("MachineGroupFriendlyname"))).AppendChild($publishingTasksXml.CreateTextNode($MachineGroupFriendlyname))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Priority"))).AppendChild($publishingTasksXml.CreateTextNode($Priority))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Id"))).AppendChild($publishingTasksXml.CreateTextNode($Id))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Action"))).AppendChild($publishingTasksXml.CreateTextNode($Action))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Name"))).AppendChild($publishingTasksXml.CreateTextNode($Name))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Version"))).AppendChild($publishingTasksXml.CreateTextNode($Version))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Group"))).AppendChild($publishingTasksXml.CreateTextNode($Group))
        try {
            Write-Verbose "Retrieving the SID for group `"$Group`""
            $groupSID = Get-GroupSID -GroupName $Group -ErrorAction Stop
            $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("ADGroupSID"))).AppendChild($publishingTasksXml.CreateTextNode($groupSID))
        } catch {
            Write-Verbose "Could not retrieve the SID for group `"$Group`", $($_.Exception.Message)"
        }
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Path"))).AppendChild($publishingTasksXml.CreateTextNode($Path))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("AlwaysPublish"))).AppendChild($publishingTasksXml.CreateTextNode($AlwaysPublish.ToString()))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Whennotexist"))).AppendChild($publishingTasksXml.CreateTextNode($WhenNotExist))
        $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("PublishSeamless"))).AppendChild($publishingTasksXml.CreateTextNode($PublishSeamless.ToString()))
        if ($packageDetails.Type -like 'APPV') {
            Write-Verbose "Adding APPV specific elements"
            $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("PackageId"))).AppendChild($publishingTasksXml.CreateTextNode($packageDetails.PackageId.ToString()))
            $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("VersionId"))).AppendChild($publishingTasksXml.CreateTextNode($packageDetails.VersionId.ToString()))
            $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("DynamicUserConfigurationPath"))).AppendChild($publishingTasksXml.CreateTextNode($DynamicUserConfigurationPath))
            $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("GlobalPublishForUser"))).AppendChild($publishingTasksXml.CreateTextNode('False'))
        } elseif ($packageDetails.Type -like 'MSIX'){
            Write-Verbose "Adding MSIX specific elements"
            $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("PackageFullName"))).AppendChild($publishingTasksXml.CreateTextNode($PackageFullName))
            $null = $($ptTaskElement.AppendChild($publishingTasksXml.CreateElement("ForceApplicationShutdownWhenUnpublishing"))).AppendChild($publishingTasksXml.CreateTextNode($ForceApplicationShutdownWhenUnpublishing.ToString()))
        }
        if ($PublishSeamless.ToBool() -eq $true) {
            Write-Verbose "Adding Seamless elements"
            $ptSeamlessElement = $ptTaskElement.AppendChild($publishingTasksXml.CreateElement("Seamless"))
            $seamlessAppCounter = 0
            $publishedApps = @()
            ForEach ($app in $packageDetails.Applications) {
                Write-Verbose "Adding SeamlessApplication element for `"$($app.FriendlyName)`" / `"$($app.Description)`""
                $ptSeamlessApplicationElement = $ptSeamlessElement.AppendChild($publishingTasksXml.CreateElement("SeamlessApplication"))
                $null = $($ptSeamlessApplicationElement.AppendChild($publishingTasksXml.CreateElement("SeamlessApplicationNumber"))).AppendChild($publishingTasksXml.CreateTextNode($seamlessAppCounter.ToString()))
                $null = $($ptSeamlessApplicationElement.AppendChild($publishingTasksXml.CreateElement("SeamlessApplicationExecutable"))).AppendChild($publishingTasksXml.CreateTextNode($app.AppVentiXExecutable))
                $null = $($ptSeamlessApplicationElement.AppendChild($publishingTasksXml.CreateElement("SeamlessApplicationArgument"))).AppendChild($publishingTasksXml.CreateTextNode(""))
                if ($packageDetails.Type -like 'APPV') {
                    $seamlessApplicationFriendlyName = ''
                    $seamlessApplicationIconPath = ''
                } elseif ($packageDetails.Type -like 'MSIX') {
                    $seamlessApplicationFriendlyName = $app.FriendlyName
                    $seamlessApplicationIconPath = $app.IconWindowsPath
                }
                $null = $($ptSeamlessApplicationElement.AppendChild($publishingTasksXml.CreateElement("SeamlessApplicationFriendlyName"))).AppendChild($publishingTasksXml.CreateTextNode($seamlessApplicationFriendlyName))
                $null = $($ptSeamlessApplicationElement.AppendChild($publishingTasksXml.CreateElement("SeamlessApplicationIconPath"))).AppendChild($publishingTasksXml.CreateTextNode($seamlessApplicationIconPath))
                $null = $($ptSeamlessApplicationElement.AppendChild($publishingTasksXml.CreateElement("SeamlessApplicationRunVirtual"))).AppendChild($publishingTasksXml.CreateTextNode("False"))
                $publishedApp = @{}
                $publishedApp.Path = 'C:\Program Files\AppVentiX\AppVentiX Agent\AppVentiX Wrapper.exe'
                $publishedApp.identifier = "$($WVDapplicationgroup)/$($app.FriendlyName)"
                $publishedApp.DisplayName = "$($seamlessApplicationFriendlyName)"
                $publishedApp.Description = "$($app.Description)"
                $publishedApp.RequireCommandLine = $true
                $publishedApp.CommandLine = "$($Id)#$($seamlessAppCounter.ToString())"
                $publishedApp.IconPath = "$($app.IconWindowsPath)"
                $publishedApp.IconIndex = 0
                if ($ReturnPublishCommand) {
                    Write-Output $([PSCustomObject]@{
                            Name      = $app.FriendlyName
                            Program   = "C:\Program Files\AppVentiX\AppVentiX Agent\AppVentiX Wrapper.exe"
                            Parameter = '{0}#{1}' -f $Id, $seamlessAppCounter
                        })
                }
                $publishedApps += $publishedApp.Clone()
                $seamlessAppCounter++
            }
            if (-Not [String]::IsNullOrEmpty($WVDapplicationgroup)) {
                $null = $($ptSeamlessElement.AppendChild($publishingTasksXml.CreateElement("SeamlessWVDapplicationgroup"))).AppendChild($publishingTasksXml.CreateTextNode($WVDapplicationgroup))
                if ($PublishInAzure) {
                    Write-Warning "PublishInAzure is not yet supported for AVD, create Application group `"$WVDapplicationgroup`" manually in Azure Portal"
                }
            }
        } else {
            Write-Verbose "No Seamless elements added"
        }
        if ($PSCmdlet.ShouldProcess("$($Script:AppVentiX.PublishingTasksFilename)")) {
            try {
                $publishingTasksXml.Save($publishingTasksFullname)
            } catch {
                Write-Warning "Could not save the file `"$($publishingTasksFullname)`"! No changes made."
            }
        }
    } else {
        Write-Warning 'AppVentiX is not licensed!'
    }
}

# SIG # Begin signature block
# MIITYgYJKoZIhvcNAQcCoIITUzCCE08CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA/IA/bNeaRhDXA
# 7Kjg4hDkXyiaUlhvrUNHl5ujtNwllKCCEHUwggTzMIID26ADAgECAhAsJ03zZBC0
# i/247uUvWN5TMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoT
# D1NlY3RpZ28gTGltaXRlZDEkMCIGA1UEAxMbU2VjdGlnbyBSU0EgQ29kZSBTaWdu
# aW5nIENBMB4XDTIxMDUwNTAwMDAwMFoXDTI0MDUwNDIzNTk1OVowWzELMAkGA1UE
# BhMCTkwxEjAQBgNVBAcMCVZlbGRob3ZlbjEbMBkGA1UECgwSSm9oYW5uZXMgQmls
# bGVrZW5zMRswGQYDVQQDDBJKb2hhbm5lcyBCaWxsZWtlbnMwggEiMA0GCSqGSIb3
# DQEBAQUAA4IBDwAwggEKAoIBAQCsfgRG81keOHalHfCUgxOa1Qy4VNOnGxB8SL8e
# rjP9SfcF13McP7F1HGka5Be495pTZ+duGbaQMNozwg/5Dg9IRJEeBabeSSJJCbZo
# SNpmUu7NNRRfidQxlPC81LxTVHxJ7In0MEfCVm7rWcri28MRCAuafqOfSE+hyb1Z
# /tKyCyQ5RUq3kjs/CF+VfMHsJn6ZT63YqewRkwHuc7UogTTZKjhPJ9prGLTer8UX
# UgvsGRbvhYZXIEuy+bmx/iJ1yRl1kX4nj6gUYzlhemOnlSDD66YOrkLDhXPMXLym
# AN7h0/W5Bo//R5itgvdGBkXkWCKRASnq/9PTcoxW6mwtgU8xAgMBAAGjggGQMIIB
# jDAfBgNVHSMEGDAWgBQO4TqoUzox1Yq+wbutZxoDha00DjAdBgNVHQ4EFgQUZWMy
# gC0i1u2NZ1msk2Mm5nJm5AswDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAw
# EwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYJYIZIAYb4QgEBBAQDAgQQMEoGA1UdIARD
# MEEwNQYMKwYBBAGyMQECAQMCMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGln
# by5jb20vQ1BTMAgGBmeBDAEEATBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3Js
# LnNlY3RpZ28uY29tL1NlY3RpZ29SU0FDb2RlU2lnbmluZ0NBLmNybDBzBggrBgEF
# BQcBAQRnMGUwPgYIKwYBBQUHMAKGMmh0dHA6Ly9jcnQuc2VjdGlnby5jb20vU2Vj
# dGlnb1JTQUNvZGVTaWduaW5nQ0EuY3J0MCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz
# cC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEARjv9ieRocb1DXRWm3XtY
# jjuSRjlvkoPd9wS6DNfsGlSU42BFd9LCKSyRREZVu8FDq7dN0PhD4bBTT+k6AgrY
# KG6f/8yUponOdxskv850SjN2S2FeVuR20pqActMrpd1+GCylG8mj8RGjdrLQ3QuX
# qYKS68WJ39WWYdVB/8Ftajir5p6sAfwHErLhbJS6WwmYjGI/9SekossvU8mZjZwo
# Gbu+fjZhPc4PhjbEh0ABSsPMfGjQQsg5zLFjg/P+cS6hgYI7qctToo0TexGe32DY
# fFWHrHuBErW2qXEJvzSqM5OtLRD06a4lH5ZkhojhMOX9S8xDs/ArDKgX1j1Xm4Tu
# DjCCBYEwggRpoAMCAQICEDlyRDr5IrdR19NsEN0xNZUwDQYJKoZIhvcNAQEMBQAw
# ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
# A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
# BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0xOTAzMTIwMDAwMDBaFw0y
# ODEyMzEyMzU5NTlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNl
# eTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1Qg
# TmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0aW9uIEF1
# dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIASZRc2DsPb
# CLPQrFcNdu3NJ9NMrVCDYeKqIE0JLWQJ3M6Jn8w9qez2z8Hc8dOx1ns3KBErR9o5
# xrw6GbRfpr19naNjQrZ28qk7K5H44m/Q7BYgkAk+4uh0yRi0kdRiZNt/owbxiBhq
# kCI8vP4T8IcUe/bkH47U5FHGEWdGCFHLhhRUP7wz/n5snP8WnRi9UY41pqdmyHJn
# 2yFmsdSbeAPAUDrozPDcvJ5M/q8FljUfV1q3/875PbcstvZU3cjnEjpNrkyKt1ya
# tLcgPcp/IjSufjtoZgFE5wFORlObM2D3lL5TN5BzQ/Myw1Pv26r+dE5px2uMYJPe
# xMcM3+EyrsyTO1F4lWeL7j1W/gzQaQ8bD/MlJmszbfduR/pzQ+V+DqVmsSl8MoRj
# VYnEDcGTVDAZE6zTfTen6106bDVc20HXEtqpSQvf2ICKCZNijrVmzyWIzYS4sT+k
# OQ/ZAp7rEkyVfPNrBaleFoPMuGfi6BOdzFuC00yz7Vv/3uVzrCM7LQC/NVV0CUnY
# SVgaf5I25lGSDvMmfRxNF7zJ7EMm0L9BX0CpRET0medXh55QH1dUqD79dGMvsVBl
# CeZYQi5DGky08CVHWfoEHpPUJkZKUIGy3r54t/xnFeHJV4QeD2PW6WK61l9VLupc
# xigIBCU5uA4rqfJMlxwHPw1S9e3vL4IPAgMBAAGjgfIwge8wHwYDVR0jBBgwFoAU
# oBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYEFFN5v1qqK0rPVIDh2JvAnfKy
# A2bLMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MBEGA1UdIAQKMAgw
# BgYEVR0gADBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNv
# bS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDA0BggrBgEFBQcBAQQoMCYwJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwF
# AAOCAQEAGIdR3HQhPZyK4Ce3M9AuzOzw5steEd4ib5t1jp5y/uTW/qofnJYt7wNK
# fq70jW9yPEM7wD/ruN9cqqnGrvL82O6je0P2hjZ8FODN9Pc//t64tIrwkZb+/UNk
# fv3M0gGhfX34GRnJQisTv1iLuqSiZgR2iJFODIkUzqJNyTKzuugUGrxx8VvwQQuY
# AAoiAxDlDLH5zZI3Ge078eQ6tvlFEyZ1r7uq7z97dzvSxAKRPRkA0xdcOds/exgN
# Rc2ThZYvXd9ZFk8/Ub3VRRg/7UqO6AZhdCMWtQ1QcydER38QXYkqa4UxFMToqWpM
# gLxqeM+4f452cpkMnf7XkQgWoaNflTCCBfUwggPdoAMCAQICEB2iSDBvmyYY0ILg
# ln0z02owDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpO
# ZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVT
# RVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmlj
# YXRpb24gQXV0aG9yaXR5MB4XDTE4MTEwMjAwMDAwMFoXDTMwMTIzMTIzNTk1OVow
# fDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
# A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSQwIgYDVQQD
# ExtTZWN0aWdvIFJTQSBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA
# A4IBDwAwggEKAoIBAQCGIo0yhXoYn0nwli9jCB4t3HyfFM/jJrYlZilAhlRGdDFi
# xRDtsocnppnLlTDAVvWkdcapDlBipVGREGrgS2Ku/fD4GKyn/+4uMyD6DBmJqGx7
# rQDDYaHcaWVtH24nlteXUYam9CflfGqLlR5bYNV+1xaSnAAvaPeX7Wpyvjg7Y96P
# v25MQV0SIAhZ6DnNj9LWzwa0VwW2TqE+V2sfmLzEYtYbC43HZhtKn52BxHJAteJf
# 7wtF/6POF6YtVbC3sLxUap28jVZTxvC6eVBJLPcDuf4vZTXyIuosB69G2flGHNyM
# fHEo8/6nxhTdVZFuihEN3wYklX0Pp6F8OtqGNWHTAgMBAAGjggFkMIIBYDAfBgNV
# HSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUDuE6qFM6MdWK
# vsG7rWcaA4WtNA4wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw
# HQYDVR0lBBYwFAYIKwYBBQUHAwMGCCsGAQUFBwMIMBEGA1UdIAQKMAgwBgYEVR0g
# ADBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNF
# UlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEE
# ajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRy
# dXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVz
# ZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAE1jUO1HNEphpNveaiqMm/EA
# AB4dYns61zLC9rPgY7P7YQCImhttEAcET7646ol4IusPRuzzRl5ARokS9At3Wpwq
# QTr81vTr5/cVlTPDoYMot94v5JT3hTODLUpASL+awk9KsY8k9LOBN9O3ZLCmI2pZ
# aFJCX/8E6+F0ZXkI9amT3mtxQJmWunjxucjiwwgWsatjWsgVgG10Xkp1fqW4w2y1
# z99KeYdcx0BNYzX2MNPPtQoOCwR/oEuuu6Ol0IQAkz5TXTSlADVpbL6fICUQDRn7
# UJBhvjmPeo5N9p8OHv4HURJmgyYZSJXOSsnBf/M6BZv5b9+If8AjntIeQ3pFMcGc
# TanwWbJZGehqjSkEAnd8S0vNcL46slVaeD68u28DECV3FTSK+TbMQ5Lkuk/xYpMo
# JVcp+1EZx6ElQGqEV8aynbG8HArafGd+fS7pKEwYfsR7MUFxmksp7As9V1DSyt39
# ngVR5UR43QHesXWYDVQk/fBO4+L4g71yuss9Ou7wXheSaG3IYfmm8SoKC6W59J7u
# mDIFhZ7r+YMp08Ysfb06dy6LN0KgaoLtO0qqlBCk4Q34F8W2WnkzGJLjtXX4oemO
# CiUe5B7xn1qHI/+fpFGe+zmAEc3btcSnqIBv5VPU4OOiwtJbGvoyJi1qV3AcPKRY
# LqPzW0sH3DJZ84enGm1YMYICQzCCAj8CAQEwgZAwfDELMAkGA1UEBhMCR0IxGzAZ
# BgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYG
# A1UEChMPU2VjdGlnbyBMaW1pdGVkMSQwIgYDVQQDExtTZWN0aWdvIFJTQSBDb2Rl
# IFNpZ25pbmcgQ0ECECwnTfNkELSL/bju5S9Y3lMwDQYJYIZIAWUDBAIBBQCggYQw
# GAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGC
# NwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQx
# IgQgyGfRrgFTPZykhNbHW8uLvm2p3dQKWzhpcSEons/z2kIwDQYJKoZIhvcNAQEB
# BQAEggEAIs81XR4H3lqvONEDPfqw2TsBZt2HoK3LkmYUqhgw1wg3qOH5dQf6macv
# 04PmxO/jiy5m/n9OA0t1vW/evMV+ENX9SL10SV0KgEm1l1ST0NtcYwy79+ORoXSj
# cP3a5MZUltJXd27kZHHJlw+UT0EAagBfKP2v1isz8IBh17jCVAPB2rwdKQTE5D1v
# 3N2YLz94+rR7VY815KhQd8WeSSk7VUVEAzzYv7XINtqMSqwbg1UC5nBzLUghz7uP
# T3stgJZZZdSFT2LK2E6lbxG1G/Iv8zF6kM/XZyz0YTOh5+2c/xye3ea273so7rK8
# ux5BeVXvr21vlvoi2cPlVw6JW/GXKw==
# SIG # End signature block