AnyPackage.Pkgx.psm1

# Copyright (c) Thomas Nieto - All Rights Reserved
# You may use, distribute and modify this code under the
# terms of the MIT license.

using module AnyPackage
using namespace AnyPackage.Provider

[PackageProvider('pkgx')]
class PkgxProvider : PackageProvider, IFindPackage, IGetPackage, IInstallPackage, IUninstallPackage {
    [void] FindPackage([PackageRequest] $request) {
        if ($request.Name -eq '*') {
            $request.WriteVerbose('pkgx does not support wildcards.')
            return
        }

        pkgx mash pkgx/pantry-inventory $request.Name |
            ForEach-Object {
                if ($request.IsMatch([PackageVersion]$_)) {
                    $package = [PackageInfo]::new($request.Name, $_, $request.ProviderInfo)
                    $request.WritePackage($package)
                }
            }
    }

    [void] GetPackage([PackageRequest] $request) {
        $pattern = 'exec pkgx \+(?<name>[\w\./]+)((?:[@^])(?<version>[\d\.]+))?'
        $packages = Select-String -Path ~/.local/bin/* -Pattern $pattern |
            Select-Object -ExpandProperty Matches -Unique

        $basePath = '~/.pkgx'

        foreach ($package in $packages) {
            $name = $package.Groups['name']

            if ($package.Groups['version'].Success) {
                $versionBin = $package.Groups['version'].Value
                $versionPath = Join-Path -Path $basePath -ChildPath "$name/v$versionBin"
            } else {
                $versionPath = Join-Path -Path $basePath -ChildPath "$name/v*"
                $versionBin = $null
            }

            $versionDirectory = Get-Item -LiteralPath $versionPath -ErrorAction SilentlyContinue

            if (-not $versionDirectory -and $versionBin) {
                $version = $versionBin
            } elseif (-not $versionDirectory) {
                $version = $null
            } elseif ($versionDirectory.Target) {
                $version = $versionDirectory.Target -replace 'v', ''
            } else {
                $version = $versionDirectory.Name -replace 'v', ''
            }

            if ($version -and $request.IsMatch($name, $version)) {
                $packageInfo = [PackageInfo]::new($name, $version, $request.ProviderInfo)
                $request.WritePackage($packageInfo)
            } elseif ($request.IsMatch($name)) {
                $packageInfo = [PackageInfo]::new($name, $request.ProviderInfo)
                $request.WritePackage($packageInfo)
            }
        }
    }

    [void] InstallPackage([PackageRequest] $request) {
        if ($request.Version -and $request.Version.MinVersion -ne $request.Version.MaxVersion) {
            $findPackageParams = @{
                Name     = $request.Name
                Version  = $request.Version
                Provider = $request.ProviderInfo.FullName
            }

            $version = Find-Package @findPackageParams |
                Sort-Object -Property Version -Descending |
                Select-Object -ExpandProperty Version -First 1

            $name = '{0}@{1}' -f $request.Name, $version
        } elseif ($request.Version) {
            $version = $request.Version.MinVersion
            $name = '{0}@{1}' -f $request.Name, $version
        } elseif ($request.Name.Contains('@')) {
            $name, $version = $request.Name -split '@'
        } else {
            $version = $null
            $name = $request.Name
        }

        $output = pkgx install $name 2>&1 |
            ForEach-Object {
                $request.WriteVerbose($_)
                $_
            }

        foreach ($line in $output) {
            if ($line -match '^pkgx: installed:') {
                $package = [PackageInfo]::new($request.Name, $version, $request.ProviderInfo)
                $request.WritePackage($package)
                break
            }
        }
    }

    [void] UninstallPackage([PackageRequest] $request) {
        if ((-not $request.Package -and $request.Version) -or $request.Name.Contains('@')) {
            throw 'pkgx does not support specifying version.'
        }

        $output = pkgx uninstall $request.Name 2>&1 |
            ForEach-Object {
                $request.WriteVerbose($_)
                $_
            }

        foreach ($line in $output) {
            if ($line -match '^uninstalled:') {
                $package = [PackageInfo]::new($request.Name, $request.Package.Version, $request.ProviderInfo)
                $request.WritePackage($package)
                break
            }
        }
    }

    [bool] IsSource([string] $source) {
        return $false
    }
}

[guid] $id = '95ab509b-e244-4c8b-ad5f-ecea73c68495'
[PackageProviderManager]::RegisterProvider($id, [PkgxProvider], $MyInvocation.MyCommand.ScriptBlock.Module)

$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
    [PackageProviderManager]::UnregisterProvider($id)
}

# SIG # Begin signature block
# MIIlQgYJKoZIhvcNAQcCoIIlMzCCJS8CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCXe0OabFDdSjRF
# EysJDsUwP5Admg+bkva6Pa3y/sCj5qCCHtcwggW2MIIEHqADAgECAhEApPLKEVUi
# zMqDeJHsqFBBojANBgkqhkiG9w0BAQwFADBUMQswCQYDVQQGEwJHQjEYMBYGA1UE
# ChMPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBDb2Rl
# IFNpZ25pbmcgQ0EgUjM2MB4XDTIyMTIwNjAwMDAwMFoXDTI1MTIwNTIzNTk1OVow
# TDELMAkGA1UEBhMCVVMxDzANBgNVBAgMBkthbnNhczEVMBMGA1UECgwMVGhvbWFz
# IE5pZXRvMRUwEwYDVQQDDAxUaG9tYXMgTmlldG8wggGiMA0GCSqGSIb3DQEBAQUA
# A4IBjwAwggGKAoIBgQDKp+8DxaXlIDZh+gMApqRZ4hD4IDTdRkUEZZqSnUwxQnD5
# k8VpbDeqrEkmww2TKUeOWQbSRMT70T/8R8+ld2GrwzLDQ83k5mrGXIXSXCHRiLIZ
# UnLmVjDtf/4FXTEni+acu8dddbCS0GAAzDfnINFgVRQR9GdoaYLqoipRVpLVRBzb
# eR2gSCtzwmpuX1d4NR58NvfUkfzNxy0kaLfqamHl9ae0JHyGvyzrHgOUyt2ttA/F
# idNo8KudwGau/gfyko5egOAURpEqgJHrcaekTVio+GRQs2IFNHIvNnfF9Rm7kn5w
# PZuxWL4UaV5xGyYWLupny3Lpp1n+XlVg6UgYZX25BWwbdbfLvsDPHnlbPB2L0WgC
# CeG6ZOZjB2dmFaYHhwozRzcvX0FLoYXv1/Vo9QviUTm2QIqb/gaxt3xl/rtcCZOj
# ly518iHNR2f1ClS+dPiD7KO5r2owmUsaMZiPVeMnD8/dKT8c9jPhyRBntbX9V6ho
# RXD6J2mf5SKSql8pwC8CAwEAAaOCAYkwggGFMB8GA1UdIwQYMBaAFA8qyyCHKLjs
# b0iuK1SmKaoXpM0MMB0GA1UdDgQWBBQOV7tpbOOE2AnSg3DwNoU56VePWzAOBgNV
# HQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzBK
# BgNVHSAEQzBBMDUGDCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUFBwIBFhdodHRwczov
# L3NlY3RpZ28uY29tL0NQUzAIBgZngQwBBAEwSQYDVR0fBEIwQDA+oDygOoY4aHR0
# cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIz
# Ni5jcmwweQYIKwYBBQUHAQEEbTBrMEQGCCsGAQUFBzAChjhodHRwOi8vY3J0LnNl
# Y3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NBUjM2LmNydDAjBggr
# BgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQAD
# ggGBADWsCefpJbT4oKIh1SXIR4hnfGN/YqI6g3aFIntNgoiurd5uxLkow2WSpfaC
# iXjWjMubDpBvynVvaBsRfcrwT0WGBTwz4miuITPKKkIXYIVb5dCf33ghMJ4UD+zH
# P73ioUtDV545Yeb5WVLrPN8ZCC++u0kX+jck30w56LCvng6gDpPHU/KNroQxENjG
# pcycTf7Gq9tkcEVbGersD6R64NhI6r8uDH6l0s5NMep1x4yTs0MBPmlB6ZHK+88Y
# GDVdfTSYbLpQuvmLkEMHNaPOL0YyTjJJbeaHvGuTfqQb17HDLFJGd70CKrQumvcI
# CrJM9il3B+bNsSKjTLQtGbp5JdJ5paUahybiJKyZlDw5QPRrFEnwHiWaTI/9zfRc
# iZyX4kYnLkPpp8rlZFXBqfIzf0gRhgCjVVZoMwZHWqyZNL7gS4C6uvEn2t/3BqM7
# 548OuoPLH7W07orz8T7iP7aNYtJpAttZOhAbqB2EKoY3qcKClqKOMQGvc12/16mA
# KE7E+TCCBhQwggP8oAMCAQICEHojrtpTaZYPkcg+XPTH4z8wDQYJKoZIhvcNAQEM
# BQAwVzELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEuMCwG
# A1UEAxMlU2VjdGlnbyBQdWJsaWMgVGltZSBTdGFtcGluZyBSb290IFI0NjAeFw0y
# MTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5NTlaMFUxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLDAqBgNVBAMTI1NlY3RpZ28gUHVibGljIFRp
# bWUgU3RhbXBpbmcgQ0EgUjM2MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKC
# AYEAzZjYQ0GrboIr7PYzfiY05ImM0+8iEoBUPu8mr4wOgYPjoiIz5vzf7d5wu8GF
# K1JWN5hciN9rdqOhbdxLcSVwnOTJmUGfAMQm4eXOls3iQwfapEFWuOsYmBKXPNSp
# wZAFoLGl5y1EaGGc5LByM8wjcbSF52/Z42YaJRsPXY545E3QAPN2mxDh0OLozhiG
# gYT1xtjXVfEzYBVmfQaI5QL35cTTAjsJAp85R+KAsOfuL9Z7LFnjdcuPkZWjssME
# TFIueH69rxbFOUD64G+rUo7xFIdRAuDNvWBsv0iGDPGaR2nZlY24tz5fISYk1sPY
# 4gir99aXAGnoo0vX3Okew4MsiyBn5ZnUDMKzUcQrpVavGacrIkmDYu/bcOUR1mVB
# IZ0X7P4bKf38JF7Mp7tY3LFF/h7hvBS2tgTYXlD7TnIMPrxyXCfB5yQq3FFoXRXM
# 3/DvqQ4shoVWF/mwwz9xoRku05iphp22fTfjKRIVpm4gFT24JKspEpM8mFa9eTgK
# WWCvAgMBAAGjggFcMIIBWDAfBgNVHSMEGDAWgBT2d2rdP/0BE/8WoWyCAi/QCj0U
# JTAdBgNVHQ4EFgQUX1jtTDF6omFCjVKAurNhlxmiMpswDgYDVR0PAQH/BAQDAgGG
# MBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwgwEQYDVR0g
# BAowCDAGBgRVHSAAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuc2VjdGln
# by5jb20vU2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ1Jvb3RSNDYuY3JsMHwGCCsG
# AQUFBwEBBHAwbjBHBggrBgEFBQcwAoY7aHR0cDovL2NydC5zZWN0aWdvLmNvbS9T
# ZWN0aWdvUHVibGljVGltZVN0YW1waW5nUm9vdFI0Ni5wN2MwIwYIKwYBBQUHMAGG
# F2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAS13sg
# rQ41WAyegR0lWP1MLWd0r8diJiH2VVRpxqFGhnZbaF+IQ7JATGceTWOS+kgnMAzG
# YRzpm8jIcjlSQ8JtcqymKhgx1s6cFZBSfvfeoyigF8iCGlH+SVSo3HHr98NepjSF
# JTU5KSRKK+3nVSWYkSVQgJlgGh3MPcz9IWN4I/n1qfDGzqHCPWZ+/Mb5vVyhgaeq
# xLPbBIqv6cM74Nvyo1xNsllECJJrOvsrJQkajVz4xJwZ8blAdX5umzwFfk7K/0K3
# fpjgiXpqNOpXaJ+KSRW0HdE0FSDC7+ZKJJSJx78mn+rwEyT+A3z7Ss0gT5CpTrcm
# hUwIw9jbvnYuYRKxFVWjKklW3z83epDVzoWJttxFpujdrNmRwh1YZVIB2guAAjEQ
# oF42H0BA7WBCueHVMDyV1e4nM9K4As7PVSNvQ8LI1WRaTuGSFUd9y8F8jw22BZC6
# mJoB40d7SlZIYfaildlgpgbgtu6SDsek2L8qomG57Yp5qTqof0DwJ4Q4HsShvRl/
# 59T4IJBovRwmqWafH0cIPEX7cEttS5+tXrgRtMjjTOp6A9l0D6xcKZtxnLqiTH9K
# PCy6xZEi0UDcMTww5Fl4VvoGbMG2oonuX3f1tsoHLaO/Fwkj3xVr3lDkmeUqiveb
# QTvGkx5hGuJaSVQ+x60xJ/Y29RBr8Tm9XJ59AjCCBhowggQCoAMCAQICEGIdbQxS
# AZ47kHkVIIkhHAowDQYJKoZIhvcNAQEMBQAwVjELMAkGA1UEBhMCR0IxGDAWBgNV
# BAoTD1NlY3RpZ28gTGltaXRlZDEtMCsGA1UEAxMkU2VjdGlnbyBQdWJsaWMgQ29k
# ZSBTaWduaW5nIFJvb3QgUjQ2MB4XDTIxMDMyMjAwMDAwMFoXDTM2MDMyMTIzNTk1
# OVowVDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDErMCkG
# A1UEAxMiU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5nIENBIFIzNjCCAaIwDQYJ
# KoZIhvcNAQEBBQADggGPADCCAYoCggGBAJsrnVP6NT+OYAZDasDP9X/2yFNTGMjO
# 02x+/FgHlRd5ZTMLER4ARkZsQ3hAyAKwktlQqFZOGP/I+rLSJJmFeRno+DYDY1UO
# AWKA4xjMHY4qF2p9YZWhhbeFpPb09JNqFiTCYy/Rv/zedt4QJuIxeFI61tqb7/fo
# XT1/LW2wHyN79FXSYiTxcv+18Irpw+5gcTbXnDOsrSHVJYdPE9s+5iRF2Q/TlnCZ
# GZOcA7n9qudjzeN43OE/TpKF2dGq1mVXn37zK/4oiETkgsyqA5lgAQ0c1f1IkOb6
# rGnhWqkHcxX+HnfKXjVodTmmV52L2UIFsf0l4iQ0UgKJUc2RGarhOnG3B++OxR53
# LPys3J9AnL9o6zlviz5pzsgfrQH4lrtNUz4Qq/Va5MbBwuahTcWk4UxuY+PynPjg
# w9nV/35gRAhC3L81B3/bIaBb659+Vxn9kT2jUztrkmep/aLb+4xJbKZHyvahAEx2
# XKHafkeKtjiMqcUf/2BG935A591GsllvWwIDAQABo4IBZDCCAWAwHwYDVR0jBBgw
# FoAUMuuSmv81lkgvKEBCcCA2kVwXheYwHQYDVR0OBBYEFA8qyyCHKLjsb0iuK1Sm
# KaoXpM0MMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBMGA1Ud
# JQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYEVR0gADAIBgZngQwBBAEwSwYD
# VR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVi
# bGljQ29kZVNpZ25pbmdSb290UjQ2LmNybDB7BggrBgEFBQcBAQRvMG0wRgYIKwYB
# BQUHMAKGOmh0dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVT
# aWduaW5nUm9vdFI0Ni5wN2MwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3Rp
# Z28uY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAG/4Lhd2M2bnuhFSCbE/8E/ph1RGHD
# VpVx0ZE/haHrQECxyNbgcv2FymQ5PPmNS6Dah66dtgCjBsULYAor5wxxcgEPRl05
# pZOzI3IEGwwsepp+8iGsLKaVpL3z5CmgELIqmk/Q5zFgR1TSGmxqoEEhk60FqONz
# Dn7D8p4W89h8sX+V1imaUb693TGqWp3T32IKGfIgy9jkd7GM7YCa2xulWfQ6E1xZ
# tYNEX/ewGnp9ZeHPsNwwviJMBZL4xVd40uPWUnOJUoSiugaz0yWLODRtQxs5qU6E
# 58KKmfHwJotl5WZ7nIQuDT0mWjwEx7zSM7fs9Tx6N+Q/3+49qTtUvAQsrEAxwmzO
# TJ6Jp6uWmHCgrHW4dHM3ITpvG5Ipy62KyqYovk5O6cC+040Si15KJpuQ9VJnbPvq
# YqfMB9nEKX/d2rd1Q3DiuDexMKCCQdJGpOqUsxLuCOuFOoGbO7Uv3RjUpY39jkkp
# 0a+yls6tN85fJe+Y8voTnbPU1knpy24wUFBkfenBa+pRFHwCBB1QtS+vGNRhsceP
# 3kSPNrrfN2sRzFYsNfrFaWz8YOdU254qNZQfd9O/VjxZ2Gjr3xgANHtM3HxfzPYF
# 6/pKK8EE4dj66qKKtm2DTL1KFCg/OYJyfrdLJq1q2/HXntgr2GVw+ZWhrWgMTn8v
# 1SjZsLlrgIfZHDCCBl0wggTFoAMCAQICEDpSaiyEzlXmHWX8zBLY6YkwDQYJKoZI
# hvcNAQEMBQAwVTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRl
# ZDEsMCoGA1UEAxMjU2VjdGlnbyBQdWJsaWMgVGltZSBTdGFtcGluZyBDQSBSMzYw
# HhcNMjQwMTE1MDAwMDAwWhcNMzUwNDE0MjM1OTU5WjBuMQswCQYDVQQGEwJHQjET
# MBEGA1UECBMKTWFuY2hlc3RlcjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTAw
# LgYDVQQDEydTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIFNpZ25lciBSMzUw
# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCN0Wf0wUibvf04STpNYYGb
# w9jcRaVhBDaNBp7jmJaA9dQZW5ighrXGNMYjK7Dey5RIHMqLIbT9z9if753mYboj
# JrKWO4ZP0N5dBT2TwZZaPb8E+hqaDZ8Vy2c+x1NiEwbEzTrPX4W3QFq/zJvDDbWK
# L99qLL42GJQzX3n5wWo60KklfFn+Wb22mOZWYSqkCVGl8aYuE12SqIS4MVO4PUax
# XeO+4+48YpQlNqbc/ndTgszRQLF4MjxDPjRDD1M9qvpLTZcTGVzxfViyIToRNxPP
# 6DUiZDU6oXARrGwyP9aglPXwYbkqI2dLuf9fiIzBugCDciOly8TPDgBkJmjAfILN
# iGcVEzg+40xUdhxNcaC+6r0juPiR7bzXHh7v/3RnlZuT3ZGstxLfmE7fRMAFwbHd
# Dz5gtHLqjSTXDiNF58IxPtvmZPG2rlc+Yq+2B8+5pY+QZn+1vEifI0MDtiA6BxxQ
# uOnj4PnqDaK7NEKwtD1pzoA3jJFuoJiwbatwhDkg1PIjYnMDbDW+wAc9FtRN6pUs
# O405jaBgigoFZCw9hWjLNqgFVTo7lMb5rVjJ9aSBVVL2dcqzyFW2LdWk5Xdp65oe
# eOALod7YIIMv1pbqC15R7QCYLxcK1bCl4/HpBbdE5mjy9JR70BHuYx27n4XNOZbw
# rXcG3wZf9gEUk7stbPAoBQIDAQABo4IBjjCCAYowHwYDVR0jBBgwFoAUX1jtTDF6
# omFCjVKAurNhlxmiMpswHQYDVR0OBBYEFGjvpDJJabZSOB3qQzks9BRqngyFMA4G
# A1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF
# BwMIMEoGA1UdIARDMEEwNQYMKwYBBAGyMQECAQMIMCUwIwYIKwYBBQUHAgEWF2h0
# dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAEEAjBKBgNVHR8EQzBBMD+gPaA7
# hjlodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1lU3RhbXBp
# bmdDQVIzNi5jcmwwegYIKwYBBQUHAQEEbjBsMEUGCCsGAQUFBzAChjlodHRwOi8v
# Y3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1lU3RhbXBpbmdDQVIzNi5j
# cnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqGSIb3
# DQEBDAUAA4IBgQCw3C7J+k82TIov9slP1e8YTx+fDsa//hJ62Y6SMr2E89rv82y/
# n8we5W6z5pfBEWozlW7nWp+sdPCdUTFw/YQcqvshH6b9Rvs9qZp5Z+V7nHwPTH8y
# zKwgKzTTG1I1XEXLAK9fHnmXpaDeVeI8K6Lw3iznWZdLQe3zl+Rejdq5l2jU7iUf
# MkthfhFmi+VVYPkR/BXpV7Ub1QyyWebqkjSHJHRmv3lBYbQyk08/S7TlIeOr9iQ+
# UN57fJg4QI0yqdn6PyiehS1nSgLwKRs46T8A6hXiSn/pCXaASnds0LsM5OVoKYfb
# gOOlWCvKfwUySWoSgrhncihSBXxH2pAuDV2vr8GOCEaePZc0Dy6O1rYnKjGmqm/I
# RNkJghSMizr1iIOPN+23futBXAhmx8Ji/4NTmyH9K0UvXHiuA2Pa3wZxxR9r9XeI
# UVb2V8glZay+2ULlc445CzCvVSZV01ZB6bgvCuUuBx079gCcepjnZDCcEuIC5Se4
# F6yFaZ8RvmiJ4hgwggaCMIIEaqADAgECAhA2wrC9fBs656Oz3TbLyXVoMA0GCSqG
# SIb3DQEBDAUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNleTEU
# MBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0
# d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0aW9uIEF1dGhv
# cml0eTAeFw0yMTAzMjIwMDAwMDBaFw0zODAxMTgyMzU5NTlaMFcxCzAJBgNVBAYT
# AkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3RpZ28g
# UHVibGljIFRpbWUgU3RhbXBpbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCIndi5RWedHd3ouSaBmlRUwHxJBZvMWhUP2ZQQRLRBQIF3
# FJmp1OR2LMgIU14g0JIlL6VXWKmdbmKGRDILRxEtZdQnOh2qmcxGzjqemIk8et8s
# E6J+N+Gl1cnZocew8eCAawKLu4TRrCoqCAT8uRjDeypoGJrruH/drCio28aqIVEn
# 45NZiZQI7YYBex48eL78lQ0BrHeSmqy1uXe9xN04aG0pKG9ki+PC6VEfzutu6Q3I
# cZZfm00r9YAEp/4aeiLhyaKxLuhKKaAdQjRaf/h6U13jQEV1JnUTCm511n5avv4N
# +jSVwd+Wb8UMOs4netapq5Q/yGyiQOgjsP/JRUj0MAT9YrcmXcLgsrAimfWY3MzK
# m1HCxcquinTqbs1Q0d2VMMQyi9cAgMYC9jKc+3mW62/yVl4jnDcw6ULJsBkOkrcP
# LUwqj7poS0T2+2JMzPP+jZ1h90/QpZnBkhdtixMiWDVgh60KmLmzXiqJc6lGwqoU
# qpq/1HVHm+Pc2B6+wCy/GwCcjw5rmzajLbmqGygEgaj/OLoanEWP6Y52Hflef3XL
# vYnhEY4kSirMQhtberRvaI+5YsD3XVxHGBjlIli5u+NrLedIxsE88WzKXqZjj9Zi
# 5ybJL2WjeXuOTbswB7XjkZbErg7ebeAQUQiS/uRGZ58NHs57ZPUfECcgJC+v2wID
# AQABo4IBFjCCARIwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYD
# VR0OBBYEFPZ3at0//QET/xahbIICL9AKPRQlMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMIMBEGA1UdIAQKMAgwBgYE
# VR0gADBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20v
# VVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwNQYIKwYBBQUH
# AQEEKTAnMCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0G
# CSqGSIb3DQEBDAUAA4ICAQAOvmVB7WhEuOWhxdQRh+S3OyWM637ayBeR7djxQ8Si
# hTnLf2sABFoB0DFR6JfWS0snf6WDG2gtCGflwVvcYXZJJlFfym1Doi+4PfDP8s0c
# qlDmdfyGOwMtGGzJ4iImyaz3IBae91g50QyrVbrUoT0mUGQHbRcF57olpfHhQESt
# z5i6hJvVLFV/ueQ21SM99zG4W2tB1ExGL98idX8ChsTwbD/zIExAopoe3l6JrzJt
# Pxj8V9rocAnLP2C8Q5wXVVZcbw4x4ztXLsGzqZIiRh5i111TW7HV1AtsQa6vXy63
# 3vCAbAOIaKcLAo/IU7sClyZUk62XD0VUnHD+YvVNvIGezjM6CRpcWed/ODiptK+e
# vDKPU2K6synimYBaNH49v9Ih24+eYXNtI38byt5kIvh+8aW88WThRpv8lUJKaPn3
# 7+YHYafob9Rg7LyTrSYpyZoBmwRWSE4W6iPjB7wJjJpH29308ZkpKKdpkiS9WNsf
# /eeUtvRrtIEiSJHN899L1P4l6zKVsdrUu1FX1T/ubSrsxrYJD+3f3aKg6yxdbugo
# t06YwGXXiy5UUGZvOu3lXlxA+fC13dQ5OlL2gIb5lmF6Ii8+CQOYDwXM+yd9dbmo
# cQsHjcRPsccUd5E9FiswEqORvz8g3s+jR3SFCgXhN4wz7NgAnOgpCdUo4uDyllU9
# PzGCBcEwggW9AgEBMGkwVDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28g
# TGltaXRlZDErMCkGA1UEAxMiU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5nIENB
# IFIzNgIRAKTyyhFVIszKg3iR7KhQQaIwDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYB
# BAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAc
# BgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgR0YT
# tMLZfQFlAMifIaXyo03+5AAHe+2urK0HVNTk2vYwDQYJKoZIhvcNAQEBBQAEggGA
# dwH0RnkILCpO4fTswiAf8gYGdCZ6Zoy+vFNUBDl+yTuUOAZRj4N0rDmcy9XCzFDo
# wyiGc0x46uCXxWn8cukCgoynDQBya/q+dxOyw3HzW68OasYdPCvXA5RuQd+MZn9e
# kCM7IsrUniwcF3tWxX3ZKaXfuvJHpHxn8Awj6kjoP6eq7FspGGrcWQ2gJn+fQw9N
# GpvACdI5TnfHXCo9IJpCg6jlKGGEfl9t2MNE7L/GjVrx9tPrEPbFIz2SKFNLNmx1
# nygHGBLdzx1NfVGjO7YEnyCt5vv7hANdrjwH7Rk9y3ADyGRea9cezwQjjvRGkh0+
# +GTQWzoiowdf8dSYEs9VgD+Sbuf3IkLKgU9oeemyT1SAF33hPBSaUBiiDgxwPe4J
# TB9RTqLV0UeA5Sa+zjvEddunSb8UAUtRnu9AWkj1aPK1RM6GjgV3xzKAmh72THNC
# hEzE3iA4X3XJUnXK2D9k0f7DjLWolxSkekvYfv8nPph1BdPR/haVKj/bKFfeBKit
# oYIDIjCCAx4GCSqGSIb3DQEJBjGCAw8wggMLAgEBMGkwVTELMAkGA1UEBhMCR0Ix
# GDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEsMCoGA1UEAxMjU2VjdGlnbyBQdWJs
# aWMgVGltZSBTdGFtcGluZyBDQSBSMzYCEDpSaiyEzlXmHWX8zBLY6YkwDQYJYIZI
# AWUDBAICBQCgeTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJ
# BTEPFw0yNDA5MjExODI3MTFaMD8GCSqGSIb3DQEJBDEyBDDz46LDBEakTqA3Uinp
# E2wp/HI5A+WjHfyEpewluopq0+eQVCErL69bCq7jvU0EScEwDQYJKoZIhvcNAQEB
# BQAEggIARGh4W1WUmIyZzo/iVPSnXh84OeUY7rASEAb71SMOQtyYH2QLQCM7WmL3
# u3EHDqFKZ/am5tnncyMfaKsBTjduKq+iUg+cv96uN7fTWXaUIggfRMPVbS3P48so
# 1ZB8GIcxuRXcpDnm+YM5TfeOxMLiKM4KB8G1Ila/BgkJI7m+S/Vpg776TW6mZFtD
# 0fArmVmwmeiI9UNXuIbQVgV0P0wNNW8at01172RnJMHk2G97MSxDSQkd6rECQheD
# md4UHsArNv2+QIVOry31oUVYtF1CK3dKSc9UwHE2JU5CIblZx0xRUJuz9lavcPys
# ytjuwFo6DKLaFK+O6JNSmf7w5kBwgVsflcx3YNkz3omd8RK63ZISsAnBgnbdrnFO
# +bc23+Tb9SsQkrsOB/Ui/LtHbhMevdXGxrnbMsAWT0fGz5igGiJwZO3jVELj9UyK
# uTA1mbee10jNIN05oz24H8yyY++u9R6EHgvwLc/G+HLemXULdN8Qvgbi3fFd7XFu
# rqm2K0MvDcL26e/Y4z9Bf+NwrSr0/gJh0oOlyQOzDvfCir9ff7gYgH/Brb5hj2+f
# 6/myeny7qrUgPZJX9ZrX8XjbX0RIWlwSDQCeerg76uWNaEG/UkY+rCJBbp6RHkNR
# Pja3YDdKi8ePIwoZPH4n6fm7kffq73QVdT2T0wQgDRC8eTB+fNU=
# SIG # End signature block