public/Get-IvantiWCPrinterMapping.ps1

function Get-IvantiWCPrinterMapping {
    <#
    .SYNOPSIS
        Parses Ivanti Workspace Control XML file(s) to extract printer mappings.
 
    .DESCRIPTION
        This function reads specified Ivanti Workspace Control XML export file(s), filters for printer mappings,
        and transforms the data into structured PowerShell objects or a single JSON string.
 
        Supports both single large XML files and directories containing multiple separate XML files.
 
        It processes each printer mapping to:
        - Convert the printer's SMB path to a Fully Qualified Domain Name (FQDN) using a helper function.
        - Determine if it's the default printer.
        - Extract associated access control objects (users and groups).
        - Collect other metadata like comments, location, and driver names.
 
    .PARAMETER XmlFilePath
        (Legacy parameter) Path to a single Ivanti Workspace Control XML building block file.
        This parameter is maintained for backward compatibility. Use -XmlPath instead.
 
    .PARAMETER XmlPath
        Path to either:
        - A single XML file containing all printer configurations
        - A directory containing multiple XML files
 
    .PARAMETER DomainFqdn
        Specifies the domain FQDN (e.g., 'corp.domain.com') to append to any printer SMB paths that are not already fully qualified.
 
    .PARAMETER AsJson
        If specified, the function collects all results and outputs them as a single, multi-line JSON string.
        Otherwise, it streams each printer mapping object to the pipeline as it's processed.
 
    .PARAMETER ExportFor
        Target system for export: AppVentiX or WEM.
 
    .EXAMPLE
        PS C:\> Get-IvantiWCPrinterMapping -XmlFilePath "C:\IvantiConfig\Printers.xml" -DomainFqdn "corp.contoso.com"
 
        Description
        -----------
        This command processes the 'Printers.xml' file (legacy parameter usage).
 
    .EXAMPLE
        PS C:\> Get-IvantiWCPrinterMapping -XmlPath "C:\IvantiConfig\Printers\" -DomainFqdn "corp.contoso.com"
 
        Description
        -----------
        This command processes all XML files in the specified directory.
 
    .EXAMPLE
        PS C:\> Get-IvantiWCPrinterMapping -XmlPath "C:\IvantiConfig\Printers.xml" -DomainFqdn "corp.contoso.com" -AsJson | Out-File -FilePath "C:\Output\printers.json"
 
        Description
        -----------
        This command processes the XML file and outputs as JSON to a file.
 
    .NOTES
        Function : Get-IvantiWCPrinterMapping
        Author : John Billekens
        CoAuthor : Claude (Anthropic)
        Copyright : (c) John Billekens Consultancy
        Version : 2026.130.1000
        Dependencies : This function assumes a helper function named 'ConvertTo-SmbPath' and 'Test-SmbPathIsFqdn' are available in the runspace.
#>

    [CmdletBinding()]
    param (
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'ByFilePath',
            HelpMessage = "Path to the Ivanti Workspace Control XML configuration file."
        )]
        [ValidateScript({
                if (-not (Test-Path $_ -PathType Leaf)) {
                    throw "File '$_' does not exist."
                }
                return $true
            })]
        [string]$XmlFilePath,

        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'ByPath',
            HelpMessage = "Path to the Ivanti Workspace Control XML building block file or directory containing XML files."
        )]
        [ValidateScript({
                if (-not (Test-Path $_)) {
                    throw "Path '$_' does not exist."
                }
                return $true
            })]
        [string]$XmlPath,

        [Parameter(
            Mandatory = $false,
            HelpMessage = "Domain FQDN to append to non-FQDN SMB paths."
        )]
        [string]$DomainFqdn,

        [Parameter(
            Mandatory = $false,
            HelpMessage = "Output the results as JSON."
        )]
        [switch]$AsJson,

        [ValidateSet("AppVentiX", "WEM")]
        [string]$ExportFor = "WEM"
    )

    $JsonOutput = @()
    $PrintersToProcess = @()

    if ($PSCmdlet.ParameterSetName -eq 'ByFilePath') {
        $XmlPath = $XmlFilePath
    }

    # Determine if XmlPath is a file or directory
    if (Test-Path -Path $XmlPath -PathType Leaf) {
        # Single XML file mode
        try {
            Write-Verbose "Reading and parsing the Ivanti XML file at '$($XmlPath)'."
            [xml]$IvantiXmlData = ConvertFrom-IvantiBB -XmlFilePath $XmlPath
        } catch {
            Write-Error "Failed to read or parse the XML file '$($XmlPath)'. Error: $($_.Exception.Message)"
            return
        }
        $PrintersToProcess = @(@($IvantiXmlData.SelectNodes("//printermapping")) | Where-Object { (-not [string]::IsNullOrEmpty($_.printer)) })

    } elseif (Test-Path -Path $XmlPath -PathType Container) {
        # Directory with multiple XML files mode
        Write-Verbose "Processing directory containing multiple XML files: $XmlPath"
        $XmlFiles = Get-ChildItem -Path $XmlPath -Filter "*.xml" -File

        if ($XmlFiles.Count -eq 0) {
            Write-Warning "No XML files found in directory: $XmlPath"
            return
        }

        Write-Verbose "Found $($XmlFiles.Count) XML file(s) in directory."

        foreach ($XmlFile in $XmlFiles) {
            try {
                [xml]$XmlData = ConvertFrom-IvantiBB -XmlFilePath $XmlFile.FullName
                $Printers = @(@($XmlData.SelectNodes("//printermapping")) | Where-Object { (-not [string]::IsNullOrEmpty($_.printer)) })

                if ($Printers.Count -gt 0) {
                    $PrintersToProcess += $Printers
                    Write-Verbose "Loaded $($Printers.Count) printer mapping(s) from '$($XmlFile.Name)'"
                } else {
                    Write-Warning "No printer mapping nodes found in file: $($XmlFile.Name)"
                }
            } catch {
                Write-Warning "Failed to load XML file '$($XmlFile.Name)': $_"
                continue
            }
        }
    } else {
        Write-Error "XmlPath must be either a file or a directory."
        return
    }

    if (-not [string]::IsNullOrEmpty($DomainFqdn)) {
        Write-Verbose "Using Domain FQDN: $DomainFqdn"
        $DomainNetBIOS = Get-ADDomainNetBIOS -FQDN $DomainFqdn
    }

    if ($PrintersToProcess.Count -eq 0) {
        Write-Warning "No printer mappings found to process."
        return
    }

    $TotalNumberOfItems = $PrintersToProcess.Count
    Write-Verbose "Found $($TotalNumberOfItems) printer mappings to process."

    # Initialize collections for tracking
    $Counter = 0
    $PrinterGUIDS = @()

    foreach ($Printer in $PrintersToProcess) {
        $Counter++
        [string]$PrinterName = $Printer.printer
        Write-Progress -Activity "Processing Printer Mappings" -Status "Processing item $($Counter) of $($TotalNumberOfItems)" -CurrentOperation "Printer: $($PrinterName)" -PercentComplete (($Counter / $TotalNumberOfItems) * 100)
        if ($PrinterGUIDS -contains $Printer.guid) {
            Write-Warning "Duplicate printer GUID '$($Printer.guid)' found for printer '$($PrinterName)' in Ivanti Building Block. Skipping this entry."
            continue
        }
        if ((Get-Command -Name ConvertTo-SmbFqdnPath -ErrorAction SilentlyContinue) -and (-not [string]::IsNullOrEmpty($DomainFqdn))) {
            [string]$PrinterPath = ConvertTo-SmbFqdnPath -Path $PrinterName -Domain $DomainFqdn
        } else {
            Write-Warning "The Printer mapping is not a FQDN, but a single name. Best practice is to use FQDN."
            [string]$PrinterPath = $PrinterName
        }

        $Enabled = $false
        if ($Printer.enabled -ieq "yes") {
            $Enabled = $true
        }

        $Assignments = @(ConvertFrom-IvantiAccessControl -AccessControl $Printer.accesscontrol -IWCComponentName $PrinterName -IWCComponent "Printer")

        if (-not [string]::IsNullOrEmpty($Printer.backupprinter)) {
            Write-Warning "Backup printer setting is not supported and will be ignored for printer '$($PrinterName)'."
        }

        if ($Printer.comment -and $Printer.location) {
            $Description = "$($Printer.comment) ($($Printer.location))"
        } elseif ($Printer.comment) {
            $Description = $Printer.comment
        } elseif ($Printer.location) {
            $Description = $Printer.location
        } elseif ($Printer.description) {
            $Description = $Printer.description
        } else {
            $Description = ""
        }
        try {
            $Name = $PrinterPath.Split('\')[-1]
        } catch {
            $Name = $PrinterPath
        }
        if ($Printer.default -ieq "no") {
            $IsDefault = $false
        } elseif ($Printer.default -ieq "yes") {
            $IsDefault = $true
        } else {
            $IsDefault = $false
        }

        # Construct the final output object for this printer
        $Output = [PSCustomObject]@{
            PrinterPath = $PrinterPath
            IsDefault   = $IsDefault
            Comment     = $Printer.comment
            Location    = $Printer.location
            Description = $Printer.description
            Persistent  = $false
            Enabled     = $Enabled
            Driver      = $Printer.driver
            GUID        = $Printer.guid
        }
        switch ($ExportFor) {
            "WEM" {
                $WEMAssignments = @($Assignments | Select-Object Sid, Name, Type)
                $Output | Add-Member -MemberType NoteProperty -Name "WEMAssignments" -Value $WEMAssignments
                $WEMAssignmentParams = [PSCustomObject]@{
                    isDefault = $IsDefault
                }
                $Output | Add-Member -MemberType NoteProperty -Name "WEMAssignmentParams" -Value $WEMAssignmentParams

                $WEMPrinterParams = [PSCustomObject]@{
                    Name        = $Name
                    PrinterPath = $PrinterPath
                    DisplayName = $Name
                    Description = $Description
                    Enabled     = $Enabled
                }
                $Output | Add-Member -MemberType NoteProperty -Name "WEMPrinterParams" -Value $WEMPrinterParams
            }
            "AppVentiX" {
                $AppVentiXAssignments = @($Assignments | Select-Object Sid, Name, Type, DomainFQDN)
                $Output | Add-Member -MemberType NoteProperty -Name "AppVentiXAssignments" -Value $AppVentiXAssignments
                $AppVentiXParams = [PSCustomObject]@{
                    FriendlyName = $PrinterPath
                    Description  = $Description
                    PrinterPath  = $PrinterPath
                    SetAsDefault = $IsDefault
                }
                $Output | Add-Member -MemberType NoteProperty -Name "AppVentiXParams" -Value $AppVentiXParams
            }
        }
        $PrinterGUIDS += $Printer.guid
        if ($AsJson.IsPresent) {
            $JsonOutput += $Output
        } else {
            Write-Output $Output
        }
    }

    Write-Progress -Activity "Processing Printer Mappings" -Completed
    Write-Verbose "Processing completed. Processed $TotalNumberOfItems printer mappings."

    if ($AsJson.IsPresent -and $JsonOutput.Count -gt 0) {
        Write-Verbose "Converting output to JSON format."
        return ($JsonOutput | ConvertTo-Json -Depth 5)
    }
}

# SIG # Begin signature block
# MIImdwYJKoZIhvcNAQcCoIImaDCCJmQCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCHED/Fm1P7qH95
# qU3n0BMojne4dKZepwArpVv11Ea5WaCCIAowggYUMIID/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
# MC8GCSqGSIb3DQEJBDEiBCBspspeTNuMjprb5XJaVEwfTrZPfO+C4xGCXsC4JP4s
# oDANBgkqhkiG9w0BAQEFAASCAYAzyLDrfpQEdAE0QwheLq+sucKnyTx8jINbhZpV
# K4LCGRr+8EdEuWEVidPabR1eenFn7swbMCOvmj+uSpeGfw8gGIZ4s0fKu2ulHYgT
# oLnKNasTrTXNSlCvqvy8feMeR3A3dgHZq5ecZcNVd3dZ4WSstetZxOIkSK/kVYKS
# S7+jUNgYxgC9IQfb5Gwoss7GxHS+4QqQZxcR94zx7GKD4aeFfWm+6t2AO9MfEOGP
# /yeoA/eJEvGoAr6mDCsXlA96g43lGIzrgHZwEZsTK36dzXl++7ae5OHFRwCA0Ek2
# hAhfJxlOdSX9mWFwwJDW1AE7SUkVrLIvbmjJGbK1nttcliB/m6xW+Jkl792ygKRm
# KyGVSsLZ45W5V42ALi84oj1uUgtzETaLubhrjy+3kuQne2Efs4AhK4z4u/m3RWn1
# La1sdWmK1dBzpZsoQZHrEe/16JU1Y1sFgThBe0vaJInuxyw0rEwEI67J5tna7+EY
# qjRURlag2exAmn2gX1oPBsb251KhggMjMIIDHwYJKoZIhvcNAQkGMYIDEDCCAwwC
# AQEwajBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSww
# KgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNgIRAKQp
# O24e3denNAiHrXpOtyQwDQYJYIZIAWUDBAICBQCgeTAYBgkqhkiG9w0BCQMxCwYJ
# KoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNjAxMzAxMTAyMDFaMD8GCSqGSIb3
# DQEJBDEyBDC9heOYCMnaaNIDufjH8zA3yi7fA0LlZWIuB4A/HCdy0vik6iYAl03o
# x4sGtdzxu30wDQYJKoZIhvcNAQEBBQAEggIAdGJeTgvTEyFt7OOv5rMfGQmvHFeQ
# ZmqG92xFFBDdfK8aoh6RUChGgiR3xO4Si6/0hrKfE/cJ0hHsmX54vczQpauhvC4t
# SBfVlTFUZcpI2ux/9ohO5Gv7e0VSI25yJyYpOcF8Y9EAPJa4UNsl5EID1ziJYTfI
# sbMtzFalvgafqmtSraw1XKB7JxtGnkHSfjlNLG4WLX0KQBHF0FDWQvmUAKid+krf
# 6+2Cnti2biZUNuomIQkWAiR/ombe+x/3VfYR1GzPY/hLtt/DWNw52Y2MzZTvgrch
# IpNgjMLBKW3wIQPBfmVm+V9w0a9hnA8AeVMrqxpomJ6vElgU7usvnKjpoySmPd7d
# q0f3+2Culptu8c1awu3bpFfhTpOT45VO4vcYoUd6NdBU+kta16rsNaltcnpZ58u7
# MijKrtvYHA4gkBvG9yURFG2MvZEX81QlG4WoniDPDfhrsZFQ/xNlZcHFoHX821zh
# Bg5Bwz6r9vHz7YZyZ9G6HLx5KoFOA+maufC8H2MP0tHstxHvYs1EJPL/r2VrMy+j
# LX8JWHqTPYPmvOeBbw8dCbTRlKd6S+6W3U8snQK+q4L6H6F//qMls7Fn5baZhuFk
# KnA/53RuLtsQQ2aFNc6kh6ZK6N7ldc77aULJNeAfuYQCLyqXXOWeCZVb7cIBv7W3
# Y1w4pQU1hArEbWk=
# SIG # End signature block