AnyPackage.PowerShellGet.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 module PowerShellGet

using namespace System.Collections.Generic
using namespace AnyPackage.Provider
using namespace Microsoft.PowerShell.PowerShellGet.UtilClasses

[PackageProvider('PowerShellGet')]
class PowerShellGetProvider : PackageProvider, IGetPackage, IFindPackage,
IInstallPackage, ISavePackage, IUninstallPackage,
IUpdatePackage, IPublishPackage, IGetSource, ISetSource {
    
    PowerShellGetProvider() : base('c9a39544-274b-4935-9cad-7423e8c47e6b') { }

    #region GetPackage
    [void] GetPackage([PackageRequest] $request) {
        $params = @{ Name = $request.Name }

        if ($request.Version) {
            $params['Version'] = $request.Version
        }

        if ($request.DynamicParameters.Path) {
            $params['Path'] = $request.DynamicParameters.Path
        }

        if ($request.DynamicParameters.Scope) {
            $params['Scope'] = $request.DynamicParameters.Scope
        }

        [List[PSResourceInfo]] $resources = [List[PSResourceInfo]]::new()
        
        try {
            $resources = Get-PSResource @params -ErrorAction Stop
        }
        catch {
            throw $_
        }

        $this.ProcessResources($resources, $request)
    }
    #endregion

    #region FindPackage
    [void] FindPackage([PackageRequest] $request) {
        $params = @{
            Name       = $request.Name
            Prerelease = $request.Prerelease
        }

        if ($request.Version) {
            $params['Version'] = $request.Version
        }

        if ($request.Source) {
            $params['Repository'] = $request.Source
        }

        if ($request.DynamicParameters.Tag) {
            $params['Tag'] = $request.DynamicParameters.Tag
        }

        if ($request.DynamicParameters.Type) {
            $params['Type'] = $request.DynamicParameters.Type
        }

        [List[PSResourceInfo]] $resources = [List[PSResourceInfo]]::new()
        
        try {
            $resources = Find-PSResource @params -ErrorAction Stop
        }
        catch {
            throw $_
        }

        $this.ProcessResources($resources, $request)
    }
    #endregion

    #region InstallPackage
    [void] InstallPackage([PackageRequest] $request) {
        $params = @{
            Name            = $request.Name
            Prerelease      = $request.Prerelease
            TrustRepository = $true
            PassThru        = $true
        }

        if ($request.Version) {
            $params['Version'] = $request.Version
        }

        if ($request.Source) {
            $params['Source'] = $request.Source
        }

        [List[PSResourceInfo]] $resources = [List[PSResourceInfo]]::new()
        
        try {
            $resources = Install-PSResource @params -ErrorAction Stop
        }
        catch {
            throw $_
        }

        $this.ProcessResources($resources, $request)
    }
    #endregion

    #region SavePackage
    [void] SavePackage([PackageRequest] $request) {
        $params = @{
            Name            = $request.Name
            Path            = $request.Path
            Prerelease      = $request.Prerelease
            TrustRepository = $true
            PassThru        = $true
        }

        if ($request.Version) {
            $params['Version'] = $request.Version
        }

        if ($request.Source) {
            $params['Source'] = $request.Source
        }

        [List[PSResourceInfo]] $resources = [List[PSResourceInfo]]::new()
        
        try {
            $resources = Save-PSResource @params -ErrorAction Stop
        }
        catch {
            throw $_
        }

        $this.ProcessResources($resources, $request)
    }
    #endregion

    #region UninstallPackage
    [void] UninstallPackage([PackageRequest] $request) {
        $params = @{
            Name = $request.Name
        }

        if ($request.Version) {
            $params['Version'] = $request.Version
        }

        [List[PSResourceInfo]] $beforeResources = [List[PSResourceInfo]]::new()
        $beforeResources = Get-PSResource @params

        if (-not $beforeResources) { return }

        # Issue to get PassThru parameter added
        # https://github.com/PowerShell/PowerShellGet/issues/667

        # Prerelease parameter causes it to silently fail
        # https://github.com/PowerShell/PowerShellGet/issues/842
        try {
            Uninstall-PSResource @params -ErrorAction Stop
        }
        catch {
            throw $_
        }

        $afterResources = Get-PSResource @params

        if ($afterResources) {
            throw "Failed uninstalling package '$($request.Name)'. One or more versions are still installed."
        }
        else {
            $this.ProcessResources($beforeResources, $request)
        }
    }
    #endregion

    #region UpdatePackage
    [void] UpdatePackage([PackageRequest] $request) {
        $params = @{
            Name            = $request.Name
            Prerelease      = $request.Prerelease
            TrustRepository = $true
            PassThru        = $true
        }

        if ($request.Version) {
            $params['Version'] = $request.Version
        }

        if ($request.Source) {
            $params['Source'] = $request.Source
        }

        [List[PSResourceInfo]] $resources = [List[PSResourceInfo]]::new()

        try {
            $resources = Update-PSResource @params -ErrorAction Stop
        }
        catch {
            throw $_
        }

        $this.ProcessResources($resources, $request)
    }
    #endregion

    #region PublishPackage
    [void] PublishPackage([PackageRequest] $request) {
        $params = @{
            Path = $request.Path
        }

        if ($request.Source) {
            $params['Source'] = $request.Source
        }

        try {
            Publish-PSResource @params -ErrorAction Stop

            $resourceName = Get-Item -Path $request.Path | Select-Object -ExpandProperty BaseName

            if ($request.Source) {
                $resource = Find-PSResource -Name $resourceName -Source $request.Source
            }
            else {
                $resource = Find-PSResource -Name $resourceName
            }

            $this.ProcessResource($resource, $request)
        }
        catch {
            throw $_
        }
    }
    #endregion

    #region Source
    [void] GetSource([SourceRequest] $request) {
        $repos = Get-PSResourceRepository -Name $request.Name -ErrorAction SilentlyContinue

        foreach ($repo in $repos) {
            $request.WriteSource($repo.Name, $repo.Uri, [bool]::Parse($repo.Trusted), @{ Priority = $repo.Priority })
        }
    }

    [void] SetSource([SourceRequest] $request) {
        $params = @{
            Name     = $request.Name
            PassThru = $true
        }

        if ($request.Location) {
            $params.Uri = $request.Location
        }

        if ($null -ne $request.Trusted) {
            $params.Trusted = $request.Trusted
        }

        $repo = Set-PSResourceRepository @params

        $request.WriteSource($repo.Name, $repo.Uri, [bool]::Parse($repo.Trusted), @{ Priority = $repo.Priority })
    }

    [void] RegisterSource([SourceRequest] $request) {
        $params = @{
            Name     = $request.Name
            Uri      = $request.Location
            Trusted  = $request.Trusted
            PassThru = $true
        }

        $repo = Register-PSResourceRepository @params

        $request.WriteSource($repo.Name, $repo.Uri, [bool]::Parse($repo.Trusted), @{ Priority = $repo.Priority })
    }

    [void] UnregisterSource([SourceRequest] $request) {
        $params = @{
            Name     = $request.Name
            PassThru = $true
        }

        $repo = Unregister-PSResourceRepository @params

        $request.WriteSource($repo.Name, $repo.Uri, [bool]::Parse($repo.Trusted), @{ Priority = $repo.Priority })
    }
    #endregion

    [object] GetDynamicParameters([string] $commandName) {
        switch ($commandName) {
            'Get-Package' { return [GetPackageDynamicParameters]::new() }
            'Find-Package' { return [FindPackageDynamicParameters]::new() }
            default { return $null }
        }

        #bug shouldn't have to do this.
        return $null
    }

    #region ProcessResource
    hidden [void] ProcessResources([IEnumerable[PSResourceInfo]] $resources, [PackageRequest] $request) {
        foreach ($resource in $resources) {
            $this.ProcessResource($resource, $request)
        }
    }

    hidden [void] ProcessResource([PSResourceInfo] $resource, [PackageRequest] $request) {
        $request.WriteVerbose("Processing '$($resource.Name)' resource.")
            
        $repo = Get-PSResourceRepository -Name $resource.Repository
        $ht = ConvertTo-PackageMetadata $resource
        
        $deps = [List[PackageDependency]]::new()
        foreach ($dep in $resource.Dependencies) {
            $dependency = [PackageDependency]::new($dep.Name, $dep.VersionRange)
            $deps.Add($dependency)
        }
        
        if ($repo) {
            $repoInfo = $request.NewSourceInfo($repo.Name, $repo.Url, [bool]::Parse($repo.Trusted), @{ Priority = $repo.Priority; CredentialInfo = $repo.CredentialInfo })
        }
        else {
            $repoInfo = $request.NewSourceInfo($resource.Repository, $resource.RepositorySourceLocation, $false, $null)
        }

        $version = $resource.Version.ToString()

        if ($resource.Prerelease) {
            $version = $version + '-' + $resource.Prerelease
        }

        $request.WritePackage($resource.Name, $version, $resource.Description, $repoInfo, $ht, $deps)
    }
    #endregion
}

class GetPackageDynamicParameters {
    [Parameter()]
    [string] $Path

    [Parameter()]
    [ScopeType] $Scope
}

class FindPackageDynamicParameters {
    [Parameter()]
    [string[]] $Tag

    [Parameter()]
    [ResourceType] $Type
}

[PackageProviderManager]::RegisterProvider([PowerShellGetProvider], $MyInvocation.MyCommand.ScriptBlock.Module)

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

function ConvertTo-PackageMetadata {
    [CmdletBinding()]
    [OutputType([hashtable])]
    param (
        [PSResourceInfo]
        [Parameter(Position = 0,
            ValueFromPipeline,
            ValueFromPipelineByPropertyName)]
        $InputObject
    )
    
    begin {
        $properties = $InputObject | 
            Get-Member -MemberType Properties |
            Select-Object -ExpandProperty Name
    }
    
    process {
        $hashtable = @{}
        
        foreach ($property in $properties) {
            $hashtable[$property] = $InputObject.$property
        }

        $hashtable
    }
}

# SIG # Begin signature block
# MIIfNQYJKoZIhvcNAQcCoIIfJjCCHyICAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAjrtC0uqBYEmUU
# L5uyd9Pc1FbqpR3sp7UKKGt+daRF9qCCGPgwggURMIID+aADAgECAhATixZVeYWc
# HXmMNSvpIJGBMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoT
# D1NlY3RpZ28gTGltaXRlZDEkMCIGA1UEAxMbU2VjdGlnbyBSU0EgQ29kZSBTaWdu
# aW5nIENBMB4XDTIwMDExMDAwMDAwMFoXDTIyMTIwOTIzNTk1OVowZDELMAkGA1UE
# BhMCVVMxDzANBgNVBAgMBkthbnNhczEWMBQGA1UEBwwNT3ZlcmxhbmQgUGFyazEV
# MBMGA1UECgwMVGhvbWFzIE5pZXRvMRUwEwYDVQQDDAxUaG9tYXMgTmlldG8wggEi
# MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCd4um34YFz0hPHGIEnLecf/i/Q
# 8LBmTqD9h04IApHwyIanvbOuY5f/BziNUHnLNZSlHuq8eqlpQ59r4D5pmy+cm0de
# S/qqYYoloLb9ZLvBS0e8fSx+o/ZL5wveakN6TMfCwXxSA3slEEiHVnUmlH0I57JT
# Md3/QHIsBzw0Rk15lEOlw/lYQZNIi0md8yKdAWk+ABmcuLnkmPXK2wlXebmONfiO
# iDj5TpN2QzmZ3OGFExER8sfdhuOnlehbv7q3/sDhFCKYIY6LxED3CA4cHjOMs2Of
# Z9Sl66ee3J75fY7484jgiMjrTCY6ED2LVLwYwpluBuAUBklpd2VjH5LP2QFfAgMB
# AAGjggGlMIIBoTAfBgNVHSMEGDAWgBQO4TqoUzox1Yq+wbutZxoDha00DjAdBgNV
# HQ4EFgQU8gLY5rCOaNmN211EfMTJfYdbvAAwDgYDVR0PAQH/BAQDAgeAMAwGA1Ud
# EwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYJYIZIAYb4QgEBBAQDAgQQ
# MEAGA1UdIAQ5MDcwNQYMKwYBBAGyMQECAQMCMCUwIwYIKwYBBQUHAgEWF2h0dHBz
# Oi8vc2VjdGlnby5jb20vQ1BTMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwu
# c2VjdGlnby5jb20vU2VjdGlnb1JTQUNvZGVTaWduaW5nQ0EuY3JsMHMGCCsGAQUF
# BwEBBGcwZTA+BggrBgEFBQcwAoYyaHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0
# aWdvUlNBQ29kZVNpZ25pbmdDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3Nw
# LnNlY3RpZ28uY29tMB0GA1UdEQQWMBSBEnRuaWV0bzg4QGdtYWlsLmNvbTANBgkq
# hkiG9w0BAQsFAAOCAQEAPwFaeuhYzcuenOU8fhxgfxpjkPFwov9yV9rTkkozAw73
# qJzbxf1VBDvRbtbcz9bvwytdeVY4sF1lAccn8df/QVdf7Xlk7RaObNxPwXuY6T5C
# vZT8GvzE4RtBUyq2xxwV/SMDZ9X3qh3OFxyxZD/XyU08+s39jHUuAYAzMX/QTnLX
# 9v7eM7W8Ls+282Sd0onzaRLTk9hD6ZH552hAJQG3ftUGDP4YDLz77utwCdRK9Fne
# Qo+jic/jr6JD0LdsCTlfOH+5q2/AJcShLCrV0WXvKZaVsZkFKpQD2uJ24C719pkn
# dHoFP7S9hhdQFQ4YBI5Kce5HOTXA+3VfDBFG9PXDhTCCBfUwggPdoAMCAQICEB2i
# SDBvmyYY0ILgln0z02owDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UE
# ChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNB
# IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MTEwMjAwMDAwMFoXDTMwMTIz
# MTIzNTk1OVowfDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hl
# c3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVk
# MSQwIgYDVQQDExtTZWN0aWdvIFJTQSBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqG
# SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCGIo0yhXoYn0nwli9jCB4t3HyfFM/jJrYl
# ZilAhlRGdDFixRDtsocnppnLlTDAVvWkdcapDlBipVGREGrgS2Ku/fD4GKyn/+4u
# MyD6DBmJqGx7rQDDYaHcaWVtH24nlteXUYam9CflfGqLlR5bYNV+1xaSnAAvaPeX
# 7Wpyvjg7Y96Pv25MQV0SIAhZ6DnNj9LWzwa0VwW2TqE+V2sfmLzEYtYbC43HZhtK
# n52BxHJAteJf7wtF/6POF6YtVbC3sLxUap28jVZTxvC6eVBJLPcDuf4vZTXyIuos
# B69G2flGHNyMfHEo8/6nxhTdVZFuihEN3wYklX0Pp6F8OtqGNWHTAgMBAAGjggFk
# MIIBYDAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQU
# DuE6qFM6MdWKvsG7rWcaA4WtNA4wDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQI
# MAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwMGCCsGAQUFBwMIMBEGA1UdIAQK
# MAgwBgYEVR0gADBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVz
# dC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYI
# KwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5j
# b20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6
# Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAE1jUO1HNEph
# pNveaiqMm/EAAB4dYns61zLC9rPgY7P7YQCImhttEAcET7646ol4IusPRuzzRl5A
# RokS9At3WpwqQTr81vTr5/cVlTPDoYMot94v5JT3hTODLUpASL+awk9KsY8k9LOB
# N9O3ZLCmI2pZaFJCX/8E6+F0ZXkI9amT3mtxQJmWunjxucjiwwgWsatjWsgVgG10
# Xkp1fqW4w2y1z99KeYdcx0BNYzX2MNPPtQoOCwR/oEuuu6Ol0IQAkz5TXTSlADVp
# bL6fICUQDRn7UJBhvjmPeo5N9p8OHv4HURJmgyYZSJXOSsnBf/M6BZv5b9+If8Aj
# ntIeQ3pFMcGcTanwWbJZGehqjSkEAnd8S0vNcL46slVaeD68u28DECV3FTSK+TbM
# Q5Lkuk/xYpMoJVcp+1EZx6ElQGqEV8aynbG8HArafGd+fS7pKEwYfsR7MUFxmksp
# 7As9V1DSyt39ngVR5UR43QHesXWYDVQk/fBO4+L4g71yuss9Ou7wXheSaG3IYfmm
# 8SoKC6W59J7umDIFhZ7r+YMp08Ysfb06dy6LN0KgaoLtO0qqlBCk4Q34F8W2Wnkz
# GJLjtXX4oemOCiUe5B7xn1qHI/+fpFGe+zmAEc3btcSnqIBv5VPU4OOiwtJbGvoy
# Ji1qV3AcPKRYLqPzW0sH3DJZ84enGm1YMIIG7DCCBNSgAwIBAgIQMA9vrN1mmHR8
# qUY2p3gtuTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg
# VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlm
# aWNhdGlvbiBBdXRob3JpdHkwHhcNMTkwNTAyMDAwMDAwWhcNMzgwMTE4MjM1OTU5
# WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAw
# DgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxJTAjBgNV
# BAMTHFNlY3RpZ28gUlNBIFRpbWUgU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQDIGwGv2Sx+iJl9AZg/IJC9nIAhVJO5z6A+U++zWsB2
# 1hoEpc5Hg7XrxMxJNMvzRWW5+adkFiYJ+9UyUnkuyWPCE5u2hj8BBZJmbyGr1XEQ
# eYf0RirNxFrJ29ddSU1yVg/cyeNTmDoqHvzOWEnTv/M5u7mkI0Ks0BXDf56iXNc4
# 8RaycNOjxN+zxXKsLgp3/A2UUrf8H5VzJD0BKLwPDU+zkQGObp0ndVXRFzs0IXuX
# AZSvf4DP0REKV4TJf1bgvUacgr6Unb+0ILBgfrhN9Q0/29DqhYyKVnHRLZRMyIw8
# 0xSinL0m/9NTIMdgaZtYClT0Bef9Maz5yIUXx7gpGaQpL0bj3duRX58/Nj4OMGcr
# Rrc1r5a+2kxgzKi7nw0U1BjEMJh0giHPYla1IXMSHv2qyghYh3ekFesZVf/QOVQt
# Ju5FGjpvzdeE8NfwKMVPZIMC1Pvi3vG8Aij0bdonigbSlofe6GsO8Ft96XZpkyAc
# Spcsdxkrk5WYnJee647BeFbGRCXfBhKaBi2fA179g6JTZ8qx+o2hZMmIklnLqEbA
# yfKm/31X2xJ2+opBJNQb/HKlFKLUrUMcpEmLQTkUAx4p+hulIq6lw02C0I3aa7fb
# 9xhAV3PwcaP7Sn1FNsH3jYL6uckNU4B9+rY5WDLvbxhQiddPnTO9GrWdod6VQXqn
# gwIDAQABo4IBWjCCAVYwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZssw
# HQYDVR0OBBYEFBqh+GEZIA/DQXdFKI7RNV8GEgRVMA4GA1UdDwEB/wQEAwIBhjAS
# BgNVHRMBAf8ECDAGAQH/AgEAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBEGA1UdIAQK
# MAgwBgYEVR0gADBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVz
# dC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYI
# KwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5j
# b20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6
# Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAG1UgaUzXRbh
# tVOBkXXfA3oyCy0lhBGysNsqfSoF9bw7J/RaoLlJWZApbGHLtVDb4n35nwDvQMOt
# 0+LkVvlYQc/xQuUQff+wdB+PxlwJ+TNe6qAcJlhc87QRD9XVw+K81Vh4v0h24URn
# bY+wQxAPjeT5OGK/EwHFhaNMxcyyUzCVpNb0llYIuM1cfwGWvnJSajtCN3wWeDmT
# k5SbsdyybUFtZ83Jb5A9f0VywRsj1sJVhGbks8VmBvbz1kteraMrQoohkv6ob1ol
# cGKBc2NeoLvY3NdK0z2vgwY4Eh0khy3k/ALWPncEvAQ2ted3y5wujSMYuaPCRx3w
# Xdahc1cFaJqnyTdlHb7qvNhCg0MFpYumCf/RoZSmTqo9CfUFbLfSZFrYKiLCS53x
# OV5M3kg9mzSWmglfjv33sVKRzj+J9hyhtal1H3G/W0NdZT1QgW6r8NDT/LKzH7aZ
# lib0PHmLXGTMze4nmuWgwAxyh8FuTVrTHurwROYybxzrF06Uw3hlIDsPQaof6aFB
# nf6xuKBlKjTg3qj5PObBMLvAoGMs/FwWAKjQxH/qEZ0eBsambTJdtDgJK0kHqv3s
# MNrxpy/Pt/360KOE2See+wFmd7lWEOEgbsausfm2usg1XTN2jvF8IAwqd661ogKG
# uinutFoAsYyr4/kKyVRd1LlqdJ69SK6YMIIG9jCCBN6gAwIBAgIRAJA5f5rSSjoT
# 8r2RXwg4qUMwDQYJKoZIhvcNAQEMBQAwfTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
# EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMP
# U2VjdGlnbyBMaW1pdGVkMSUwIwYDVQQDExxTZWN0aWdvIFJTQSBUaW1lIFN0YW1w
# aW5nIENBMB4XDTIyMDUxMTAwMDAwMFoXDTMzMDgxMDIzNTk1OVowajELMAkGA1UE
# BhMCR0IxEzARBgNVBAgTCk1hbmNoZXN0ZXIxGDAWBgNVBAoTD1NlY3RpZ28gTGlt
# aXRlZDEsMCoGA1UEAwwjU2VjdGlnbyBSU0EgVGltZSBTdGFtcGluZyBTaWduZXIg
# IzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCQsnE/eeHUuYoXzMOX
# wpCUcu1aOm8BQ39zWiifJHygNUAG+pSvCqGDthPkSxUGXmqKIDRxe7slrT9bCqQf
# L2x9LmFR0IxZNz6mXfEeXYC22B9g480Saogfxv4Yy5NDVnrHzgPWAGQoViKxSxnS
# 8JbJRB85XZywlu1aSY1+cuRDa3/JoD9sSq3VAE+9CriDxb2YLAd2AXBF3sPwQmnq
# /ybMA0QfFijhanS2nEX6tjrOlNEfvYxlqv38wzzoDZw4ZtX8fR6bWYyRWkJXVVAW
# DUt0cu6gKjH8JgI0+WQbWf3jOtTouEEpdAE/DeATdysRPPs9zdDn4ZdbVfcqA23V
# zWLazpwe/OpwfeZ9S2jOWilh06BcJbOlJ2ijWP31LWvKX2THaygM2qx4Qd6S7w/F
# 7KvfLW8aVFFsM7ONWWDn3+gXIqN5QWLP/Hvzktqu4DxPD1rMbt8fvCKvtzgQmjSn
# C//+HV6k8+4WOCs/rHaUQZ1kHfqA/QDh/vg61MNeu2lNcpnl8TItUfphrU3qJo5t
# /KlImD7yRg1psbdu9AXbQQXGGMBQ5Pit/qxjYUeRvEa1RlNsxfThhieThDlsdeAd
# DHpZiy7L9GQsQkf0VFiFN+XHaafSJYuWv8at4L2xN/cf30J7qusc6es9Wt340pDV
# SZo6HYMaV38cAcLOHH3M+5YVxQIDAQABo4IBgjCCAX4wHwYDVR0jBBgwFoAUGqH4
# YRkgD8NBd0UojtE1XwYSBFUwHQYDVR0OBBYEFCUuaDxrmiskFKkfot8mOs8UpvHg
# MA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsG
# AQUFBwMIMEoGA1UdIARDMEEwNQYMKwYBBAGyMQECAQMIMCUwIwYIKwYBBQUHAgEW
# F2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAEEAjBEBgNVHR8EPTA7MDmg
# N6A1hjNodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29SU0FUaW1lU3RhbXBp
# bmdDQS5jcmwwdAYIKwYBBQUHAQEEaDBmMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0
# LnNlY3RpZ28uY29tL1NlY3RpZ29SU0FUaW1lU3RhbXBpbmdDQS5jcnQwIwYIKwYB
# BQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqGSIb3DQEBDAUAA4IC
# AQBz2u1ocsvCuUChMbu0A6MtFHsk57RbFX2o6f2t0ZINfD02oGnZ85ow2qxp1nRX
# JD9+DzzZ9cN5JWwm6I1ok87xd4k5f6gEBdo0wxTqnwhUq//EfpZsK9OU67Rs4EVN
# LLL3OztatcH714l1bZhycvb3Byjz07LQ6xm+FSx4781FoADk+AR2u1fFkL53VJB0
# ngtPTcSqE4+XrwE1K8ubEXjp8vmJBDxO44ISYuu0RAx1QcIPNLiIncgi8RNq2xgv
# bnitxAW06IQIkwf5fYP+aJg05Hflsc6MlGzbA20oBUd+my7wZPvbpAMxEHwa+zwZ
# gNELcLlVX0e+OWTOt9ojVDLjRrIy2NIphskVXYCVrwL7tNEunTh8NeAPHO0bR0ic
# ImpVgtnyughlA+XxKfNIigkBTKZ58qK2GpmU65co4b59G6F87VaApvQiM5DkhFP8
# KvrAp5eo6rWNes7k4EuhM6sLdqDVaRa3jma/X/ofxKh/p6FIFJENgvy9TZntyeZs
# Nv53Q5m4aS18YS/to7BJ/lu+aSSR/5P8V2mSS9kFP22GctOi0MBk0jpCwRoD+9Dt
# miG4P6+mslFU1UzFyh8SjVfGOe1c/+yfJnatZGZn6Kow4NKtt32xakEnbgOKo3Tg
# igmCbr/j9re8ngspGGiBoZw/bhZZSxQJCZrmrr9gFd2G9TGCBZMwggWPAgEBMIGQ
# MHwxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
# BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEkMCIGA1UE
# AxMbU2VjdGlnbyBSU0EgQ29kZSBTaWduaW5nIENBAhATixZVeYWcHXmMNSvpIJGB
# MA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJ
# KoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQB
# gjcCARUwLwYJKoZIhvcNAQkEMSIEIHYJWed9GzQexLWE6pUFFGmCGtEiHIbp59ll
# ZKVzBf7lMA0GCSqGSIb3DQEBAQUABIIBADRfIcTJ7aZWYOQv4Uh7Zn9l89pp4gzc
# 3ciEobmwZx3slsB1HFpde6baG37XBR5XBt+miugHW3wZl0HnF3NWKKxuLSPzNKJI
# zpC9ka6yclIRokxmMuMjUTFYwIBCUqFdAM4qi+nsJFZsH0nycM8JoUtcljvJplLv
# RDbj6bqa4pu69Is/Bv2/yAqPpK6To5rYh++a+YGBzPFi60LuafJ12ZOs5xtJh1ux
# yGfSfgM+QgWk471I2Zbm0qUB6Dau123xMnya7ihdoBD4KAXlccSMGd8xz5Rjm5MG
# gnpt98TOF5Ibec+x7y87XYn4z+bMNFeQLecH3jopCHi1pmMFMZgGZeOhggNMMIID
# SAYJKoZIhvcNAQkGMYIDOTCCAzUCAQEwgZIwfTELMAkGA1UEBhMCR0IxGzAZBgNV
# BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
# ChMPU2VjdGlnbyBMaW1pdGVkMSUwIwYDVQQDExxTZWN0aWdvIFJTQSBUaW1lIFN0
# YW1waW5nIENBAhEAkDl/mtJKOhPyvZFfCDipQzANBglghkgBZQMEAgIFAKB5MBgG
# CSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIyMTAyODAw
# NDI0NlowPwYJKoZIhvcNAQkEMTIEMKRSSlX5cKCpVNOW0RrW15hwI1APVL7NmLxh
# i8ZTTkRMRFbkxuMVElyq7Gi2Z43JaDANBgkqhkiG9w0BAQEFAASCAgBNVTis7Trk
# r1EkpQ/HznO3Gn7PxmlKG/lumm7jgvWRs57Op6XSTvpuiAMp0c8SZXR6mD+sZiAw
# zWd6OejZbcpjF6WnllpmGYuIPszMcKhdjkSckXXGSplt54eJfpoKofWkTxcZO3Ko
# 2IHfOvnFNx0KWN/57ad9M//mN8ZzalgoEzLGhCdniVPQf5bF1a1cPFtOqPbNY8LX
# nxpiD7uHupRPlMrmGEoXHhMAPi56BAnyTLSaJ2F7ekI+Y2xKw0gqazte2zhwPIqc
# U7ufk5TDNySRGPWKRZMuFNqgUMSCvgIJ23ywgg1n2C8iy1P/rqzs9g2q29+UwJS+
# oL0E9lQV3U1p8XbX/VThkWTumUZL8n3/hG5xMIM/fERaptdvR6fjghSRr+uy0kSq
# nsgBvo2To7EbuKPuq8Ip/fLEnyLPv1krBB2QUyD+2H/y4TPJDC6SqFoBL/ydWe8J
# x2biHG19PBEl4nHMxjVfccybH5ot+Z2+7JqxtI8/0VpDxrpBpBfv3dOFdrkEGRrg
# Bhb11lqavk6BFnk4Y7x/Ez2yv16j2xfOVtTmWTga74HYrFeuktzc/GyBysrkzQLj
# RPthjZo4BmlQbpeUAIHJvPq63OcEDNjCTkglhouwixTyoXo124CJVAtiLl1wmWVy
# zHkcuxMC9Hi4mZcEDynA56bSa4pea2nUlQ==
# SIG # End signature block