Public/New-LnvRMRepository.ps1

function New-LnvRMRepository {
    <#
    .SYNOPSIS
        Creates a new TVRM update repository.
    .DESCRIPTION
        Creates the folder structure and empty database.xml for a new local update repository.
        Registers the repository in the configuration and optionally sets it as active.
    .PARAMETER Path
        The root folder path for the new repository.
    .PARAMETER Name
        A friendly name for this repository.
    .PARAMETER Mode
        Repository mode: 'Full' stores all update files, 'Hybrid' stores metadata only.
        Default: Full.
    .PARAMETER SetActive
        If specified, sets this repository as the active repository.
    .EXAMPLE
        New-LnvRMRepository -Path 'D:\LenovoUpdates' -Name 'Production' -SetActive
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    [OutputType([bool])]
    param(
        [Parameter(Mandatory)]
        [string]$Path,

        [Parameter(Mandatory)]
        [ValidateScript({ if ([string]::IsNullOrWhiteSpace($_)) { throw 'Name cannot be blank or whitespace.' } $true })]
        [string]$Name,

        [Parameter()]
        [ValidateSet('Full', 'Hybrid')]
        [string]$Mode = 'Full',

        [Parameter()]
        [switch]$SetActive
    )

    $Name = $Name.Trim()

    if ($Name -match "[^A-Za-z0-9 '\-_.(),]") {
        Write-Warning "Repository name '$Name' contains special characters. Enter a valid name "
        return
    }

    $resolvedPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)

    # Registration checks run BEFORE any filesystem changes.
    $config = Get-LnvRMConfig

    $existing = @($config.Repositories) | Where-Object { $_.Path -eq $resolvedPath }
    if ($existing) {
        Write-Warning "A repository at '$resolvedPath' is already registered."
        return
    }

    $nameClash = @($config.Repositories) | Where-Object { $_.Name -eq $Name }
    if ($nameClash) {
        Write-Warning "A repository named '$Name' already exists (path: '$($nameClash[0].Path)'). Choose a different name."
        return
    }

    if (-not $PSCmdlet.ShouldProcess($resolvedPath, "Create TVRM repository '$Name' (Mode: $Mode)")) {
        return
    }

    # Create directory structure
    try {
        if (-not (Test-Path $resolvedPath)) {
            New-Item -Path $resolvedPath -ItemType Directory -Force -ErrorAction Stop | Out-Null
        }

        $logsDir = Join-Path $resolvedPath 'logs'
        if (-not (Test-Path $logsDir)) {
            New-Item -Path $logsDir -ItemType Directory -Force -ErrorAction Stop | Out-Null
        }
    }
    catch {
        Write-Error "Failed to create repository directories at '$resolvedPath': $_"
        return
    }

    $xsdDest = Join-Path $resolvedPath 'database.xsd'
    if (-not (Test-Path $xsdDest)) {
        $databaseXsd = @'
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="Database">
            <xs:complexType>
                <xs:sequence>
                        <xs:element name="Package" type="PackageType" minOccurs="0" maxOccurs="unbounded"/>
                </xs:sequence>
                <xs:attribute name="version" use="required">
                    <xs:simpleType>
                        <xs:restriction base="xs:string"/>
                    </xs:simpleType>
                </xs:attribute>
                <xs:attribute name="cloud" type="xs:string" use="optional"/>
            </xs:complexType>
    </xs:element>
    <xs:element name="FileName">
            <xs:simpleType>
                <xs:restriction base="xs:string"/>
            </xs:simpleType>
    </xs:element>
    <xs:element name="LocalPath">
            <xs:simpleType>
                <xs:restriction base="xs:string"/>
            </xs:simpleType>
    </xs:element>
    <xs:element name="Mode">
            <xs:simpleType>
                <xs:restriction base="xs:string"/>
            </xs:simpleType>
    </xs:element>
    <xs:complexType name="PackageType">
            <xs:sequence>
                <xs:element ref="FileName"/>
                <xs:element ref="Version"/>
                <xs:element ref="ReleaseDate"/>
                <xs:element ref="Size"/>
                <xs:element ref="URL"/>
                <xs:element ref="Mode"/>
                <xs:element ref="Type"/>
                <xs:element ref="Status"/>
                <xs:element ref="PreviousStatus"/>
                <xs:element ref="LocalPath"/>
                <xs:element ref="Severity"/>
                <xs:element ref="DisplayLicense"/>
                <xs:element name="SystemCompatibility" type="SystemCompatibilityType"/>
            </xs:sequence>
            <xs:attribute name="id" use="required">
                <xs:simpleType>
                        <xs:restriction base="xs:string"/>
                </xs:simpleType>
            </xs:attribute>
            <xs:attribute name="name" use="required">
                <xs:simpleType>
                        <xs:restriction base="xs:string"/>
                </xs:simpleType>
            </xs:attribute>
            <xs:attribute name="description" use="required">
                <xs:simpleType>
                        <xs:restriction base="xs:string"/>
                </xs:simpleType>
            </xs:attribute>
    </xs:complexType>
    <xs:element name="PreviousStatus">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                        <xs:enumeration value="Active"/>
                        <xs:enumeration value="Archived"/>
                        <xs:enumeration value="Test"/>
                        <xs:enumeration value="Draft"/>
                        <xs:enumeration value="Hidden"/>
                        <xs:enumeration value="Default"/>
                        <xs:enumeration value="None"/>
                </xs:restriction>
            </xs:simpleType>
    </xs:element>
    <xs:element name="ReleaseDate">
            <xs:simpleType>
                <xs:restriction base="xs:string"/>
            </xs:simpleType>
    </xs:element>
    <xs:element name="Size">
            <xs:simpleType>
                <xs:restriction base="xs:long"/>
            </xs:simpleType>
    </xs:element>
    <xs:element name="Status">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                        <xs:enumeration value="Active"/>
                        <xs:enumeration value="Archived"/>
                        <xs:enumeration value="Test"/>
                        <xs:enumeration value="Draft"/>
                        <xs:enumeration value="Hidden"/>
                        <xs:enumeration value="Default"/>
                </xs:restriction>
            </xs:simpleType>
    </xs:element>
    <xs:element name="Severity">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                        <xs:enumeration value="Critical"/>
                        <xs:enumeration value="Recommended"/>
                        <xs:enumeration value="Optional"/>
                        <xs:enumeration value="Default"/>
                </xs:restriction>
            </xs:simpleType>
    </xs:element>
    <xs:element name="DisplayLicense">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                        <xs:enumeration value="Display"/>
                        <xs:enumeration value="NotDisplay"/>
                        <xs:enumeration value="Default"/>
                </xs:restriction>
            </xs:simpleType>
    </xs:element>
    <xs:complexType name="SystemType">
            <xs:attribute name="mtm" use="required">
                <xs:simpleType>
                        <xs:restriction base="xs:string"/>
                </xs:simpleType>
            </xs:attribute>
            <xs:attribute name="os" use="required">
                <xs:simpleType>
                        <xs:restriction base="xs:string"/>
                </xs:simpleType>
            </xs:attribute>
    </xs:complexType>
    <xs:complexType name="SystemCompatibilityType">
            <xs:sequence>
                <xs:element name="System" type="SystemType" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
    </xs:complexType>
    <xs:element name="Type">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                        <xs:enumeration value="Quest"/>
                        <xs:enumeration value="Local"/>
                </xs:restriction>
            </xs:simpleType>
    </xs:element>
    <xs:element name="URL">
            <xs:simpleType>
                <xs:restriction base="xs:string"/>
            </xs:simpleType>
    </xs:element>
    <xs:element name="Version">
            <xs:simpleType>
                <xs:restriction base="xs:string"/>
            </xs:simpleType>
    </xs:element>
</xs:schema>
'@

        [System.IO.File]::WriteAllText($xsdDest, $databaseXsd, [System.Text.Encoding]::UTF8)
    }

    # Create empty database.xml if it doesn't exist
    $dbPath = Join-Path $resolvedPath 'database.xml'
    if (-not (Test-Path $dbPath)) {
        if ($Mode -eq 'Hybrid' ) {
            $emptyDb = @'
<?xml version="1.0" encoding="UTF-8"?>
<Database version="301" cloud="True">
</Database>
'@

        } else {
            $emptyDb = @'
<?xml version="1.0" encoding="UTF-8"?>
<Database version="301">
</Database>
'@

        }
        [System.IO.File]::WriteAllText($dbPath, $emptyDb, [System.Text.Encoding]::UTF8)
    }

    # Register in config (duplicate checks already ran above before any
    # filesystem changes; $config is still the value we loaded then).
    $repo = [PSCustomObject]@{
        Name = $Name
        Path = $resolvedPath
        Mode = $Mode
    }

    $config.Repositories = @(@($config.Repositories) + $repo)

    if ($SetActive -or -not $config.ActiveRepository) {
        $config.ActiveRepository = $resolvedPath
    }

    Set-LnvRMConfig -Config $config

    Write-LnvRMAuditLog -RepositoryPath $resolvedPath -Action 'REPO_CREATE' `
        -Message "Created repository '$Name' at '$resolvedPath' (Mode: $Mode)"

    # If database.xml already had content, discover existing packages and unique models
    $discoveredModels = @()
    $packageCount = 0
    $dbPath = Join-Path $resolvedPath 'database.xml'
    if (Test-Path $dbPath) {
        $packages = Read-LnvRMDatabaseXml -RepositoryPath $resolvedPath
        $packageCount = $packages.Count
        if ($packageCount -gt 0) {
            $discoveredModels = $packages |
                ForEach-Object { $_.Systems } |
                Select-Object MachineType, OS -Unique |
                Sort-Object MachineType, OS
            Write-Verbose "Existing repository detected: $packageCount packages, $($discoveredModels.Count) unique model/OS combinations."
        }
    }

    $repo | Add-Member -NotePropertyName 'PackageCount' -NotePropertyValue $packageCount -Force
    $repo | Add-Member -NotePropertyName 'DiscoveredModels' -NotePropertyValue $discoveredModels -Force

    Write-Verbose "Created repository '$Name' at '$resolvedPath'"
    return $repo
}

# SIG # Begin signature block
# MIItugYJKoZIhvcNAQcCoIItqzCCLacCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU1h6+8Ul/qDOhoh4QuJujv5/S
# 3pCggibcMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B
# AQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk
# IElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQsw
# CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
# ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw
# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz
# 7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS
# 5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7
# bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfI
# SKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jH
# trHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14
# Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2
# h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt
# 6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPR
# iQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ER
# ElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4K
# Jpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAd
# BgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SS
# y4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAC
# hjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS
# b290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRV
# HSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyh
# hyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO
# 0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo
# 8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++h
# UD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5x
# aiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMIIFkDCCA3ig
# AwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
# EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
# cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMw
# ODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD
# VQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Y
# q3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lX
# FllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxe
# TsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbu
# yntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I
# 9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmg
# Z92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse
# 5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKy
# Ebe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwh
# HbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/
# Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwID
# AQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4E
# FgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQADggIBALth2X2p
# bL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
# ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdN
# Oj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4
# i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJ
# EVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9NcCOGDErcgdLM
# MpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N0XWs0Mr7QbhD
# parTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb/UdK
# Dd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP
# 0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLS
# oCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9T
# dSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+MIIGsDCCBJigAwIBAgIQCK1AsmDS
# nEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD
# VQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjEwNDI5MDAwMDAwWhcN
# MzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs
# IEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5n
# IFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
# MIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zrPYGXcMW7xIUmMJ+kjmjYXPXr
# NCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHMgQM+TXAkZLON4gh9NH1MgFcS
# a0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8IrgnQnAZaf6mIBJNYc9URnokCF4
# RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyCEUhSaN4QvRRXXegYE2XFf7JP
# hSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0p6MDDnSlrzm2q2AS4+jWufcx
# 4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQakhCBj7A7CdfHmzJawv9qYFSL
# ScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0XLyTRSiDNipmKF+wc86LJiUG
# soPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960IHnWmZcy740hQ83eRGv7bUKJG
# yGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2FKZbS110YU0/EpF23r9Yy3IQ
# KUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBHX8mBUHOFECMhWWCKZFTBzCEa
# 6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q27IwyCQLMbDwMVhECAwEAAaOC
# AVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFGg34Ou2O/hfEYb7
# /mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1Ud
# DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB3BggrBgEFBQcBAQRrMGkw
# JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcw
# AoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv
# b3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQu
# Y29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwHAYDVR0gBBUwEzAHBgVngQwB
# AzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIBADojRD2NCHbuj7w6mdNW4AIa
# pfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6jfCbVN7w6XUhtldU/SfQnuxaB
# RVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmImoqKwba9oUgYftzYgBoRGRjN
# YZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtfJqGVWEjVGv7XJz/9kNF2ht0c
# sGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrxoj7bQ7gzyE84FJKZ9d3OVG3Z
# XQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3LIU/Gs4m6Ri+kAewQ3+ViCCC
# cPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx4b6cpwoG1iZnt5LmTl/eeqxJ
# zy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9Oj9FpsToFpFSi0HASIRLlk2r
# REDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+ICw2/O/TOHnuO77Xry7fwdxPm
# 5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug0wcCampAMEhLNKhRILutG4UI
# 4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5Vzu0nAPthkX0tGFuv2jiJmCG
# 6sivqf6UHedjGzqGVnhOMIIGtDCCBJygAwIBAgIQDcesVwX/IZkuQEMiDDpJhjAN
# BgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQg
# SW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2Vy
# dCBUcnVzdGVkIFJvb3QgRzQwHhcNMjUwNTA3MDAwMDAwWhcNMzgwMTE0MjM1OTU5
# WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNV
# BAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hB
# MjU2IDIwMjUgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtHgx
# 0wqYQXK+PEbAHKx126NGaHS0URedTa2NDZS1mZaDLFTtQ2oRjzUXMmxCqvkbsDpz
# 4aH+qbxeLho8I6jY3xL1IusLopuW2qftJYJaDNs1+JH7Z+QdSKWM06qchUP+AbdJ
# gMQB3h2DZ0Mal5kYp77jYMVQXSZH++0trj6Ao+xh/AS7sQRuQL37QXbDhAktVJMQ
# bzIBHYJBYgzWIjk8eDrYhXDEpKk7RdoX0M980EpLtlrNyHw0Xm+nt5pnYJU3Gmq6
# bNMI1I7Gb5IBZK4ivbVCiZv7PNBYqHEpNVWC2ZQ8BbfnFRQVESYOszFI2Wv82wnJ
# RfN20VRS3hpLgIR4hjzL0hpoYGk81coWJ+KdPvMvaB0WkE/2qHxJ0ucS638ZxqU1
# 4lDnki7CcoKCz6eum5A19WZQHkqUJfdkDjHkccpL6uoG8pbF0LJAQQZxst7VvwDD
# jAmSFTUms+wV/FbWBqi7fTJnjq3hj0XbQcd8hjj/q8d6ylgxCZSKi17yVp2NL+cn
# T6Toy+rN+nM8M7LnLqCrO2JP3oW//1sfuZDKiDEb1AQ8es9Xr/u6bDTnYCTKIsDq
# 1BtmXUqEG1NqzJKS4kOmxkYp2WyODi7vQTCBZtVFJfVZ3j7OgWmnhFr4yUozZtqg
# PrHRVHhGNKlYzyjlroPxul+bgIspzOwbtmsgY1MCAwEAAaOCAV0wggFZMBIGA1Ud
# EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFO9vU0rp5AZ8esrikFb2L9RJ7MtOMB8G
# A1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjAT
# BgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGG
# GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2Nh
# Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYD
# VR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9
# bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQAXzvsWgBz+Bz0RdnEwvb4LyLU0pn/N0IfF
# iBowf0/Dm1wGc/Do7oVMY2mhXZXjDNJQa8j00DNqhCT3t+s8G0iP5kvN2n7Jd2E4
# /iEIUBO41P5F448rSYJ59Ib61eoalhnd6ywFLerycvZTAz40y8S4F3/a+Z1jEMK/
# DMm/axFSgoR8n6c3nuZB9BfBwAQYK9FHaoq2e26MHvVY9gCDA/JYsq7pGdogP8HR
# trYfctSLANEBfHU16r3J05qX3kId+ZOczgj5kjatVB+NdADVZKON/gnZruMvNYY2
# o1f4MXRJDMdTSlOLh0HCn2cQLwQCqjFbqrXuvTPSegOOzr4EWj7PtspIHBldNE2K
# 9i697cvaiIo2p61Ed2p8xMJb82Yosn0z4y25xUbI7GIN/TpVfHIqQ6Ku/qjTY6hc
# 3hsXMrS+U0yy+GWqAXam4ToWd2UQ1KYT70kZjE4YtL8Pbzg0c1ugMZyZZd/BdHLi
# Ru7hAWE6bTEm4XYRkA6Tl4KSFLFk43esaUeqGkH/wyW4N7OigizwJWeukcyIPbAv
# jSabnf7+Pu0VrFgoiovRDiyx3zEdmcif/sYQsfch28bZeUz2rtY/9TCA6TD8dC3J
# E3rYkrhLULy7Dc90G6e8BlqmyIjlgp2+VqsS9/wQD7yFylIz0scmbKvFoW2jNrbM
# 1pD2T7m3XDCCBu0wggTVoAMCAQICEAhP3DNPfkVO28MPj/mSGDUwDQYJKoZIhvcN
# AQELBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEw
# PwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2
# IFNIQTI1NiAyMDI1IENBMTAeFw0yNjA4MDUwMDAwMDBaFw0zNzExMDQyMzU5NTla
# MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UE
# AxMyRGlnaUNlcnQgU0hBMjU2IFJTQTQwOTYgVGltZXN0YW1wIFJlc3BvbmRlciAy
# MDI2IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2e6byyf7NSvjU
# m0xls/04xjD4fAkOkbnGQi7+Wpx81iYxfzViaxSIctuH3KSl5YEYpMuFgGsA31N2
# D9ATMbfZdw5uaAhuWevQKhDdZIB4NnqcfpfpWQXJiQnDdAElETC+bhSEvNLGbA8D
# twUpFMQ4yyYQSPqomT92osQAv6hBi47ATZS6JfVWe6XxhF4jJZ3iSAuf2Cros1cz
# RSmWRHqMv9AfGZvp8ygYElhudpQjtcPpwoOl6QrZJUyV3iINvN4cO05prGV0fkjG
# 426xDr2d3z9lcSIHkdvGPdGUrXdxfVbgOUVcp2/8ISEzwKPW++Wa+E2ujI91EZtu
# kGWDJ/xZ27k3oHKEXBRGfRTqjOU+jE3ba/5++JSE/7oNHnjs5mekExYN96LV/mxU
# bCKJb8pBNY4r3uD7hEmk/M81XhVgwDA7aMzYC3LZBg9WY5BMmbSay5ecmtJuXaB/
# 0nKWmQmVZeqTVDgsmzHP5MQuhAJkiWNuC9MmCg9TZHXbJ2/yLVSov9p16UDTLtT0
# +aa1vN71fHeu1qMLlLNB3WOB/ADCxr3S/1hxI92Z6jKgEED/btwIvbfuXkNNhg8M
# tDg43c4tMZae9FvqMOt/9PvmAxF9TNIsIFB8G6yb36ZJZGUL8N/pL971DyLXcK6H
# M5PYnH5X+eVtczhCgHCVQCF6XDAlPQIDAQABo4IBlTCCAZEwDAYDVR0TAQH/BAIw
# ADAdBgNVHQ4EFgQUFMljijAu1Er7bpTz5uNAfvXszeIwHwYDVR0jBBgwFoAU729T
# SunkBnx6yuKQVvYv1Ensy04wDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoG
# CCsGAQUFBwMIMIGVBggrBgEFBQcBAQSBiDCBhTAkBggrBgEFBQcwAYYYaHR0cDov
# L29jc3AuZGlnaWNlcnQuY29tMF0GCCsGAQUFBzAChlFodHRwOi8vY2FjZXJ0cy5k
# aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2
# U0hBMjU2MjAyNUNBMS5jcnQwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL2NybDMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0YW1waW5nUlNBNDA5
# NlNIQTI1NjIwMjVDQTEuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG
# /WwHATANBgkqhkiG9w0BAQsFAAOCAgEAjcU6YR6dUgrfmawJgH59KECxa9Ji8sEi
# 2g10CBDaMiqsaxWyW5cwlT/6ZF5sFznazqVsoC85U9dqLOYqQwst+UQQoNlDHgKR
# La3xoc+OReFreFhnTXSG0Vrd2E2CZqUfm+5a+He1MJ/h+tNLuA+0Zzhn/Fo+FDYA
# HWZHx4R79ZsfRFYe9UiXpXBDf6DkUo183Y38NYmR/XfDYf7YZ+oR9t3flbDwK+hg
# GMs0gNNp1w9Z2CyOyI5or/sSwomAuNQ0hWC9xoU4stD8aWsD7RkcmgVRs6vlIk3z
# PKQ+ylcheWkMlj+CoVRlFE55pv0ZWCaFt04lwP/rdGHE9qEVQZtyRE42ox7oNgC/
# r+Y4bSlZ3dw9K2x1xLtu6PkPKeLBFjzKigwfqm3Hm+k/+lnME8F5kPZTgiy2HLEH
# klpryqs6QHnPXrRNeIzkAMyylnRN8P0wmirS0WkU+ywpEWFZ4QNg+9xS43tTuW9x
# 0eXh7NDc1P/sV+zWxHXKH8tFt1ncHdVzqrZaYPyYMLSn2TOXajveJW1L3joiQSPs
# WRGxkbDDW15jERFE4LvjnGu2O9zD1nLJSMdlYZEikl4w2w+q4IN/R+TIe0H4ngCI
# 1moJCTbevGH4punIxM1Uoi0nmX3ZK+XbRT01uowE5ViXWHng0RgsmrX/EdYUo80r
# 3TfMlkD0/YMwggdWMIIFPqADAgECAhAFfARoFtaNDha0m0G6FxiVMA0GCSqGSIb3
# DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFB
# MD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5
# NiBTSEEzODQgMjAyMSBDQTEwHhcNMjYwNTE0MDAwMDAwWhcNMjcwNjE3MjM1OTU5
# WjBeMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV
# BAcTC01vcnJpc3ZpbGxlMQ8wDQYDVQQKEwZMZW5vdm8xDzANBgNVBAMTBkxlbm92
# bzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALVacqHydjmqo6bF2tHw
# cETPkOZLgPv1tJeIerpLcfmxLoX40GsUiY5l96B13bcfKjKBJQvHsj5D08RfGnif
# K+sGsAX8xCgaYNLxq0COKn51GgLLMNgzlE4rR/8mUMuWK2fKXs24dmn7teE2+e+2
# dz/GfHXgrAIPvIr4PN+dZAFeoj6/wfpLLHZXtQLxKVmtDFc7gQZkM6Z8o0HrH2eX
# 2MVNQwbZZWvSQhqRN66/LMcXxbLP8SAb6nKRCExflbI5i+MpEq+xOdiJxkP5dC5s
# rQ31JGLDdhbuAcUJEdXATzgP1pT9is3uWZm3fro71Kvfa0XLwBZWR2ut8sQ6KUhd
# 0Nsmd5c0f2PiD2uTd9mDWHQ34bu9mDunZaeWZrIlUP9MJ8TMM82ao/4tjFNK5m3T
# hZUbCGwoepenXq8yjbKMKqHHvcoJY0SmkAIlUzWoRBbRC+uN0TwcR048sZDPo+ZC
# gdONLPrjnsIU+NxuhfDMnj4UYbkRbtvnJ+U0O4Eu+ajRS87Li+jN2jHrABvAUXtP
# J7DkkxTTfaspzlfxueoqVKcGLnu4PUAthKg3g4hleGgeo7s+krEDAzyvdBnY+b8U
# dRH/BCxDr7G5ys/bCMPEzcUFT5LrrVBHO6N2U65iYkamzEo4okrrCNFDJPZC1G/p
# NleTeiIadSPTT0tJGPK+nDo1AgMBAAGjggIDMIIB/zAfBgNVHSMEGDAWgBRoN+Dr
# tjv4XxGG+/5hewiIZfROQjAdBgNVHQ4EFgQU7R8eucYUNncCkcWYWfCltSt/mxYw
# PgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5k
# aWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEF
# BQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIx
# Q0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwgZQG
# CCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
# dC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E
# aWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEu
# Y3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBAC0PiOF1B8Qdp2pcfb3P
# 6MuzaeTUw77bfMSCcnwY8xFtkyRRp9H6X4ZaSTdAQge3d6NG7OcHnGQ3FKraZqT3
# ugjNEXvH1MXr8SNgFb7t7TyKDK0RmRK9idsycLJfRsmbj0FSTL12jqrzyHrQqkTq
# KaDqYfIVan7VxP2On8gq3/OT368z1YJbRgfu/rNpXoYpXTKSfxaIXNE7rEiUwu+T
# vi8wgfLqC/a7ujC8vbYRWgaHHsz3bjFVN/h1p78adds2GdxPzYFoS12+JKq2cKGe
# Ma5Hbr2YQfHsbpQlzZglB3mGCci+uhN5YGaHleo3Ohd0BHci32RFOA1xdD8fS9TD
# pGRMGLKF9z5WTmiGZVR4x54Qwtf4clbA5V0P9d4ppmLZJKdeaHd/JKONVJ9nYV1H
# NA52CgvgRWpUc+jxnPL5A3J9qIvUXp98ZQifEyHBFX2VqWTdu9MldzklRo/eAT1k
# MUVheRAcd32yLDiFvn7lp2nasJs8Hh+6bUxfHKbKBrNrw7CmcTDzFK119BkykWS0
# vL7xsbCEbavLIhW/ZqEjWA9k/v2FS2wbBQ9YOC8F3magnslxWlZWsym3Dxdm0Hr1
# WKHbnFcBscMiBQ+fhLDAqIG8tPPnNhc7QhOOlxQlbfEDh8QmQbUo2H9hJJEGiHJS
# VwuAKbcWembFyAgLV02ASxS7MYIGSDCCBkQCAQEwfTBpMQswCQYDVQQGEwJVUzEX
# MBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0
# ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAFfARo
# FtaNDha0m0G6FxiVMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh
# AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM
# BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBT7Q5VvxASlPmNawCi85IUNsxYA
# EDANBgkqhkiG9w0BAQEFAASCAgBcO78C+LALYBoYStY7IKMsF9loBbY7q9pfQgVj
# jyGmQj4J3pi/YqOXbC9ZwRRLNh7NA3oYLFf80cO7yiIhUTGvn8dnQqtikKVKuJpU
# pGQmNIe2Hlxlb26+fKmTBY5DcG4U2JFN2gcddA9liSO9c3E1+42fUSrICBIqzE9S
# bnzUG7/soatXyVHDB1ZfZi9wtOlI0icJFzJxbBSsUyCvC0mdLYEQO5WRO/Nile17
# M3Ov7zQc6Om1FV43unQk6SWc43gCMx9Yn8URvHluHemAk3EU+Ahnc8ZmjnndupvQ
# 9QOhkpwLVHUTXZvJr+0a0UszAsDpatITRt+DKQgD6ld9xmTvYsVAV6UAVOnI3Uk4
# itv9L3jBa1+hhneaxtX0eC4Jd3jsW9X53zmMkPyr1S6u7wP8NL7AL6l/uvsQGf2D
# idPtaf9ThNvwDlMLq2QC8TD2ToAsGHfoOmL/yOtGdlwMtHJbXAuzN+fc//5f7Fnm
# zoLBJvC+S7YQZUhwqRQP4s0Va4qhfJ+5H9rNNTVa0tROFhIfliADvHxxzPyqoD+I
# Hg/uhNdyZ+bSAopIjJC05Uj7iHvSXuppSH6GjYPJ+ZckbVmaUyqoflI+6eSWTXbZ
# dzhNPvCf0olKgFToosKYbdYtWe+V0Ocj84OVGhBS94dec7HPFKxzZ1k7HuTUhgMi
# //T126GCAyYwggMiBgkqhkiG9w0BCQYxggMTMIIDDwIBATB9MGkxCzAJBgNVBAYT
# AlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQg
# VHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEC
# EAhP3DNPfkVO28MPj/mSGDUwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMx
# CwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNjEwMDExMzI2MzRaMC8GCSqG
# SIb3DQEJBDEiBCCGewvZOBU/8DY5Js67lznNhZtTNr82+rh9zt5yFaqaUzANBgkq
# hkiG9w0BAQEFAASCAgBd6fAilMA6iN7g9wOX9N1XWSjJLLJC785kNzYVl5lt8q4v
# c1KoPsiYR8Ecmq3laLZ714GrWBj64WDnFsQaqEuVQelpwwKFnI59W7eW1zqw9PZx
# +0qNeNfcmc/Pdb1Ki8tqhRd74nDkYJAKzrD217LE97xkdBRL64GBWX6Ss4/jHSnd
# eCz0V1s4pwuyznRRgv7ngwDuTv/rOws9L6XvVOoSJTra4qO5K2qqGo6nhqnFdCrJ
# Sp6pLqoK6u8CCuc0Crlu3/+ryPCz4CaJxJ5hLR9u4TtRkBhrA4N5TxEMCF7Se0g6
# vhsDdGf7iI60MWcM1s2coSrTZ4PG/YxE/Dn3aabfTi8D72j8KpjN3coezZ+lE562
# kfFLs3YgS7A7fVsbhW7wzaTU6O+zVNZzcWzQZBtE8PZ4vmIBKmGRiRVNAG+ws01L
# vwyiv/pfoxCBIoH8U4K4x002kF+UQOnyEg6gl8s85ohERtUYpqjqigfejj9Anwd6
# uTmlK1ZqixlSh6Ub4kNdvXW3hLNd77mBC/9WOguvsVB8p2DCcC+TwgjzB1SAaJMe
# lzqlaZQDZhknqWA3RlHzNdRgl1kK+l0Nxf7L4n1xy9JC61wdOgu4HXEgq4XD2yMk
# a0a9he0VDwLhj5w1Kh6IXsuYWG0WOJISCDd4vmaHjBxIu3x7VK7+DQ1BHmC16Q==
# SIG # End signature block