WSAProvider.psm1

#########################################################################################
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# WSA Provider Module
#
#########################################################################################

$script:ProviderName = "WSAProvider"
$script:AppxPackageExtension = ".appx"
$script:AppxManifestFile = "AppxManifest.xml"
$script:AppxPkgZipFile = "AppxPkg.zip"
$script:Architecture = "Architecture"
$script:ResourceId = "ResourceId"
$script:AppxPackageSources = $null
$script:AppxLocalPath="$env:LOCALAPPDATA\Microsoft\Windows\PowerShell\AppxProvider"
$script:AppxPackageSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:AppxLocalPath -ChildPath "AppxPackageSources.xml"
$Script:ResponseUri = "ResponseUri"
$Script:StatusCode = "StatusCode"
# Wildcard pattern matching configuration.
$script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor `
                          [System.Management.Automation.WildcardOptions]::IgnoreCase
#Localized Data
Microsoft.PowerShell.Utility\Import-LocalizedData  LocalizedData -filename WSAProvider.Resource.psd1
$script:isNanoServer = $null -ne ('System.Runtime.Loader.AssemblyLoadContext' -as [Type])



if(-not($script:isNanoServer))
{
    throw 'WSAProvider is only supported on nano server'
}


function Find-AppxPackage 
{
    <#
    .ExternalHelp PSGet.psm1-help.xml
    #>
    
    [outputtype("PSCustomObject[]")]
    Param
    (
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $Name,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $MinimumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $RequiredVersion,
                
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Architecture,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ResourceId,
        
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $Source
    )

    Begin
    {
    }

    Process
    {   
        $PSBoundParameters["ProviderName"] = $script:ProviderName         
        PackageManagement\Find-Package @PSBoundParameters 
    }
}

#region Appx Provider APIs Implementation
function Get-PackageProviderName
{ 
    return $script:ProviderName
}

function Initialize-Provider{ 
  param(
  )
}

function Get-DynamicOptions
{
    param
    (
        [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory] 
        $category
    )

    Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-DynamicOptions'))
               
    switch($category)
    {
        Install {
                    Write-Output -InputObject (New-DynamicOption -Category $category -Name Architecture -ExpectedType String -IsRequired $false)
                    Write-Output -InputObject (New-DynamicOption -Category $category -Name ResourceId -ExpectedType String -IsRequired $false)
                }
        Package {
                    Write-Output -InputObject (New-DynamicOption -Category $category -Name Architecture -ExpectedType String -IsRequired $false)
                    Write-Output -InputObject (New-DynamicOption -Category $category -Name ResourceId -ExpectedType String -IsRequired $false)
                }
    }
}

function Find-Package
{ 
    [CmdletBinding()]
    param
    (
        [string[]]
        $names,

        [Version]
        $requiredVersion,

        [Version]
        $minimumVersion,

        [Version]
        $maximumVersion
    )   

    Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Find-Package'))    

    $ResourceId = $null
    $Architecture = $null
    $Sources = @()    
    $streamedResults = @()    
    $namesParameterEmpty = (-not $names) -or (($names.Count -eq 1) -and ($names[0] -eq ''))

    Set-PackageSourcesVariable

    if($RequiredVersion -and $MinimumVersion)
    {

        ThrowError -ExceptionName "System.ArgumentException" `
                   -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether `
                   -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" `
                   -CallerPSCmdlet $PSCmdlet `
                   -ErrorCategory InvalidArgument
    }    
    if($RequiredVersion -or $MinimumVersion)
    {
        if(-not $names -or $names.Count -ne 1 -or (Test-WildcardPattern -Name $names[0]))
        {
            ThrowError -ExceptionName "System.ArgumentException" `
                       -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSinglePackage `
                       -ErrorId "VersionParametersAreAllowedOnlyWithSinglePackage" `
                       -CallerPSCmdlet $PSCmdlet `
                       -ErrorCategory InvalidArgument
        }
    }    

    $options = $request.Options            
    if($options)
    {
        foreach( $o in $options.Keys )
        {
            Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) )
        }

        if($options.ContainsKey('Source'))
        {        
            $SourceNames = $($options['Source'])
            Write-Verbose ($LocalizedData.SpecifiedSourceName -f ($SourceNames))        
            foreach($sourceName in $SourceNames)
            {            
                if($script:AppxPackageSources.Contains($sourceName))
                {
                    $Sources += $script:AppxPackageSources[$sourceName]                
                }
                else
                {
                    $sourceByLocation = Get-SourceName -Location $sourceName
                    if ($sourceByLocation -ne $null)
                    {
                        $Sources += $script:AppxPackageSources[$sourceByLocation]                                        
                    }
                    else
                    {
                            $message = $LocalizedData.PackageSourceNotFound -f ($sourceName)
                            ThrowError -ExceptionName "System.ArgumentException" `
                                -ExceptionMessage $message `
                                -ErrorId "PackageSourceNotFound" `
                                -CallerPSCmdlet $PSCmdlet `
                                -ErrorCategory InvalidArgument `
                                -ExceptionObject $sourceName
                    }
                }
            }
        }
        else
        {
            Write-Verbose $LocalizedData.NoSourceNameIsSpecified        
            $script:AppxPackageSources.Values | Microsoft.PowerShell.Core\ForEach-Object { $Sources += $_ }
        }        

        if($options.ContainsKey($script:Architecture))
        {
            $Architecture = $options[$script:Architecture]     
        }
        if($options.ContainsKey($script:ResourceId))
        {
            $ResourceId = $options[$script:ResourceId]
        }
    }             
        
    #allow searching for package with packagename and packagename.appx extension
    $pkgNames = @()
    if(-not($namesParameterEmpty))
    {        
        foreach($name in $names)
        {            
            if(-not($name.EndsWith(".appx")))
            {
                $pkgNames += ($name+".appx")
            }
            else
            {
                $pkgNames+=$name
            }
        }
    }
    
    foreach($source in $Sources)
    {
        $location = $source.SourceLocation
        if($request.IsCanceled)
        {
            return
        }
        if(-not(Test-Path $location))
        {
            $message = $LocalizedData.PathNotFound -f ($Location)
            Write-Verbose $message            
            continue
        }

        $packages = Get-AppxPackagesFromPath -path $location   
           
        foreach($pkg in  $packages)
        {
            if($request.IsCanceled)
            {
                return
            }
            
            $pkgName = $pkg.Name
            $pkgManifest = Get-PackageManfiestData -PackageFullPath $pkg.FullName
            if(-not $pkgManifest)
            {               
                continue            
            }

            # $pkgName has to match any of the supplied names, using PowerShell wildcards
            if(-not($namesParameterEmpty))
            {
                if(-not(($pkgNames | Microsoft.PowerShell.Core\ForEach-Object {if ($pkgName -like $_){return $true; break} } -End {return $false})))
                {
                    continue
                }
            }

            # Version
            if($RequiredVersion)
            {
                if($RequiredVersion -ne $pkgManifest.Version)
                {
                    continue
                }
            }                

            if($minimumVersion)
            {

                if(-not($pkgManifest.Version -ge $minimumVersion))
                {
                    continue
                }
            }             

            if($maximumVersion)
            {
                if(-not($pkgManifest.Version -le $maximumVersion))
                {
                    continue
                }                
            }             
              
            if($Architecture)
            {                
                $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Architecture, $script:wildcardOptions
                if(-not($wildcardPattern.IsMatch($pkgManifest.Architecture)))
                {
                    continue
                }                
            }                        
            if($ResourceId)
            {                
                $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $ResourceId, $script:wildcardOptions
                if(-not($wildcardPattern.IsMatch($pkgManifest.ResourceId)))
                {
                    continue
                }                
            }           
            $sid = New-SoftwareIdentityPackageManifestData -PackageManifest $pkgManifest -Source $source.Name -pkgName $pkgName
            $fastPackageReference = $sid.fastPackageReference            
            if($streamedResults -notcontains $fastPackageReference)
            {
                $streamedResults += $fastPackageReference
                Write-Output -InputObject $sid
            }
        }
    }
}

function Get-InstalledPackage
{ 
    [CmdletBinding()]
    param
    (
        [Parameter()]
        [string]
        $Name,

        [Parameter()]
        [string]
        $RequiredVersion,

        [Parameter()]
        [string]
        $MinimumVersion,

        [Parameter()]
        [string]
        $MaximumVersion
    )

    Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Get-InstalledPackage'))
    
    $Architecture = $null
    $ResourceId = $null

    $options = $request.Options
    if($options)
    {
        if($options.ContainsKey($script:Architecture))
        {
            $Architecture = $options[$script:Architecture]
        }
        if($options.ContainsKey($script:ResourceId))
        {
            $ResourceId = $options[$script:ResourceId]
        }
    }

    $params = @{}
    if($Name)
    {
        $params.Add("Name", $Name)
    }
    $packages = Appx\Get-AppxPackage @params

    foreach($package in $packages)
    {
        if($RequiredVersion)
        {
            if($RequiredVersion -ne $package.Version)
            {
                continue
            }
        }
        else
        {
            if(-not((-not $MinimumVersion -or ($MinimumVersion -le $package.Version)) -and 
                    (-not $MaximumVersion -or ($MaximumVersion -ge $package.Version))))
            {
                continue
            }
        }

        if($Architecture)
        {            
            $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Architecture, $script:wildcardOptions
            if(-not($wildcardPattern.IsMatch($package.Architecture)))
            {
                continue
            }                
        }
        if($ResourceId)
        {            
            $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $ResourceId,$script:wildcardOptions
            if(-not($wildcardPattern.IsMatch($package.ResourceId)))                
            {
                continue
            }
        }        
        $sid = New-SoftwareIdentityFromPackage -Package $package
        write-Output $sid
    }
}

function Install-Package
{ 
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $fastPackageReference
    )

    Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Install-Package'))
    Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference)
    
    Appx\Add-AppxPackage -Path $fastPackageReference
}

function Download-Package
{ 
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $FastPackageReference,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Location
    )
        
    Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Download-Package'))
    Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference)    

    $copyItemSuccedded = Copy-Item -Path $FastPackageReference -Destination $Location -PassThru
    if($copyItemSuccedded)
    {
        $pkgManifest = Get-PackageManfiestData -PackageFullPath $FastPackageReference
        $sid = New-SoftwareIdentityPackageManifestData -PackageManifest $pkgManifest -pkgName (Get-Item $FastPackageReference).Name
        Write-Output -InputObject $sid
    }
}


function UnInstall-Package
{ 
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $fastPackageReference
    )

    Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Uninstall-Package'))
    Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference)

    Appx\Remove-AppxPackage -Package $fastPackageReference
}

function Add-PackageSource
{
    [CmdletBinding()]
    param
    (
        [string]
        $Name,
         
        [string]
        $Location,

        [bool]
        $Trusted
    )     
    
    Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Add-PackageSource'))

    Set-PackageSourcesVariable -Force

    if(-not (Microsoft.PowerShell.Management\Test-Path $Location) -and
       -not (Test-WebUri -uri $Location))
    {
        $LocationUri = [Uri]$Location
        if($LocationUri.Scheme -eq 'file')
        {
            $message = $LocalizedData.PathNotFound -f ($Location)
            ThrowError -ExceptionName "System.ArgumentException" `
                       -ExceptionMessage $message `
                       -ErrorId "PathNotFound" `
                       -CallerPSCmdlet $PSCmdlet `
                       -ErrorCategory InvalidArgument `
                       -ExceptionObject $Location
        }
        else
        {
            $message = $LocalizedData.InvalidWebUri -f ($Location, "Location")
            ThrowError -ExceptionName "System.ArgumentException" `
                       -ExceptionMessage $message `
                       -ErrorId "InvalidWebUri" `
                       -CallerPSCmdlet $PSCmdlet `
                       -ErrorCategory InvalidArgument `
                       -ExceptionObject $Location
        }
    }

    if(Test-WildcardPattern $Name)
    {
        $message = $LocalizedData.PackageSourceNameContainsWildCards -f ($Name)
        ThrowError -ExceptionName "System.ArgumentException" `
                    -ExceptionMessage $message `
                    -ErrorId "PackageSourceNameContainsWildCards" `
                    -CallerPSCmdlet $PSCmdlet `
                    -ErrorCategory InvalidArgument `
                    -ExceptionObject $Name
    }

    $LocationString = Get-ValidPackageLocation -LocationString $Location -ParameterName "Location"
           
    # Check if Location is already registered with another Name
    $existingSourceName = Get-SourceName -Location $LocationString

    if($existingSourceName -and 
       ($Name -ne $existingSourceName))
    {
        $message = $LocalizedData.PackageSourceAlreadyRegistered -f ($existingSourceName, $Location, $Name)
        ThrowError -ExceptionName "System.ArgumentException" `
                   -ExceptionMessage $message `
                   -ErrorId "PackageSourceAlreadyRegistered" `
                   -CallerPSCmdlet $PSCmdlet `
                   -ErrorCategory InvalidArgument
    }
        
    # Check if Name is already registered
    if($script:AppxPackageSources.Contains($Name))
    {
        $currentSourceObject = $script:AppxPackageSources[$Name]
        $null = $script:AppxPackageSources.Remove($Name)
    }
  
    # Add new package source
    $packageSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{
            Name = $Name
            SourceLocation = $LocationString
            Trusted=$Trusted
            Registered= $true
        })    

    $script:AppxPackageSources.Add($Name, $packageSource)
    $message = $LocalizedData.SourceRegistered -f ($Name, $LocationString)
    Write-Verbose $message

    # Persist the package sources
    Save-PackageSources

    # return the package source object.
    Write-Output -InputObject (New-PackageSourceFromSource -Source $packageSource)

}

function Resolve-PackageSource
{ 
    Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Resolve-PackageSource'))

    Set-PackageSourcesVariable

    $SourceName = $request.PackageSources

    if(-not $SourceName)
    {
        $SourceName = "*"
    }

    foreach($src in $SourceName)
    {
        if($request.IsCanceled)
        {
            return
        }

        $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $src,$script:wildcardOptions
        $sourceFound = $false

        $script:AppxPackageSources.GetEnumerator() | 
            Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} | 
                Microsoft.PowerShell.Core\ForEach-Object {
                    $source = $script:AppxPackageSources[$_.Key]
                    $packageSource = New-PackageSourceFromSource -Source $source
                    Write-Output -InputObject $packageSource
                    $sourceFound = $true
                }

        if(-not $sourceFound)
        {
            $sourceName  = Get-SourceName -Location $src
            if($sourceName)
            {
                $source = $script:AppxPackageSources[$sourceName]
                $packageSource = New-PackageSourceFromSource -Source $source
                Write-Output -InputObject $packageSource
            }
            elseif( -not (Test-WildcardPattern $src))
            {
                $message = $LocalizedData.PackageSourceNotFound -f ($src)
                Write-Error -Message $message -ErrorId "PackageSourceNotFound" -Category InvalidOperation -TargetObject $src
            }
        }
    }
}

function Remove-PackageSource
{ 
    param
    (
        [string]
        $Name
    )

    Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Remove-PackageSource'))

    Set-PackageSourcesVariable -Force

    $SourcesToBeRemoved = @()

    foreach ($sourceName in $Name)
    {
        if($request.IsCanceled)
        {
            return
        }

        # Check if $Name contains any wildcards
        if(Test-WildcardPattern $sourceName)
        {
            $message = $LocalizedData.PackageSourceNameContainsWildCards -f ($sourceName)
            Write-Error -Message $message -ErrorId "PackageSourceNameContainsWildCards" -Category InvalidOperation -TargetObject $sourceName
            continue
        }

        # Check if the specified package source name is in the registered package sources
        if(-not $script:AppxPackageSources.Contains($sourceName))
        {
            $message = $LocalizedData.PackageSourceNotFound -f ($sourceName)
            Write-Error -Message $message -ErrorId "PackageSourceNotFound" -Category InvalidOperation -TargetObject $sourceName
            continue
        }

        $SourcesToBeRemoved += $sourceName
        $message = $LocalizedData.PackageSourceUnregistered -f ($sourceName)
        Write-Verbose $message
    }

    # Remove the SourcesToBeRemoved
    $SourcesToBeRemoved | Microsoft.PowerShell.Core\ForEach-Object { $null = $script:AppxPackageSources.Remove($_) }

    # Persist the package sources
    Save-PackageSources
}
#endregion

#region Common functions

function Get-AppxPackagesFromPath
{
    param
    (
        [Parameter(Mandatory=$true)]
        $Path
    )

    $filterAppxPackages = "*"+$script:AppxPackageExtension
    $packages = Get-ChildItem -path $Path -filter $filterAppxPackages

    return $packages

}


function ZipFileApisAvailable
{
    $ZipFileApisAvailable = $false
    try 
    {
        [System.IO.Compression.ZipFile]
        $ZipFileApisAvailable = $true
    } 
    catch 
    {
    }
    return $ZipFileApisAvailable
}

function Expand-ZIPFile($file, $destination)
{
    try
    {
        if(-not(Test-Path $destination))
        {
            New-Item -ItemType directory -Path $Destination
        } 
        if(ZipFileApisAvailable)
        {         
            [System.IO.Compression.ZipFile]::ExtractToDirectory($file, $destination)
            return true
        }
        else
        {      
            Copy-Item -Path $file -Destination "$destination\$script:AppxPkgZipFile" -Force
            $shell = new-object -com shell.application
            $zip = $shell.NameSpace("$destination\$script:AppxPkgZipFile")
            foreach($item in $zip.items())
            {
                if($item.Path -eq "$destination\$script:AppxPkgZipFile\$script:AppxManifestFile")
                {
                    $shell.Namespace($destination).copyhere($item)
                }
            }
            return $true
        }
    }
    catch
    {
        return $false
    }
}

function Get-PackageManfiestData
{
    param
    (
        [Parameter(Mandatory=$true)]
        $PackageFullPath
    )        
    $guid = [System.Guid]::NewGuid().toString()    
    $destination = "$env:TEMP\$guid"
    Expand-ZIPFile -file $PackageFullPath -destination $destination
    [xml] $packageManifest = Get-Content "$destination\$script:AppxManifestFile" -ErrorAction SilentlyContinue    
    if($packageManifest)
    {
        $Identity = $packageManifest.Package.Identity   
        $manifestData = new-object psobject -Property @{pkgName=$Identity.Name; Architecture=$Identity.ProcessorArchitecture; Publisher=$Identity.Publisher; Version=$Identity.Version; ResourceId=$Identity.resourceId; PackageFullName=$PackageFullPath}
        Remove-Item -Path "$env:TEMP\$guid" -Recurse -Force -ErrorAction SilentlyContinue
        return $manifestData
    }
    else
    {        
        Write-Verbose ($LocalizedData.MetaDataExtractionFailed -f ($PackageFullPath) )
    }
    return $null    
}

function New-FastPackageReference
{
    param
    (
        [Parameter(Mandatory=$true)]
        [string]
        $PackageFullName
    )
    return "$PackageFullName"
}

function New-SoftwareIdentityPackageManifestData
{
    param
    (
        [Parameter(Mandatory=$true)]
        $PackageManifest,

        [string]
        $Source,

        [Parameter(Mandatory=$true)]
        $pkgName

    )        
    $fastPackageReference = New-FastPackageReference -PackageFullName $PackageManifest.PackageFullName    
    if(-not($Source))
    {
        $Source = $PackageManifest.Publisher
    }    

    $details =  @{
                    Publisher = $PackageManifest.Publisher
                    Architecture = $PackageManifest.Architecture
                    ResourceId = $PackageManifest.ResourceId
                    PackageFullName = $PackageManifest.PackageFullName
                    PackageName = $PackageManifest.pkgName
                 }

    $params = @{    
                FastPackageReference = $fastPackageReference;
                Name = $pkgName;
                Version = $PackageManifest.Version;
                versionScheme  = "MultiPartNumeric";
                Source = $source;
                Details = $details;
    }
    
    $sid = New-SoftwareIdentity @params
    return $sid       
}


function New-SoftwareIdentityFromPackage
{
    param
    (
        [Parameter(Mandatory=$true)]
        $Package,

        [string]
        $Source

    )    
    $fastPackageReference = New-FastPackageReference -PackageFullName $Package.PackageFullName                                         
    if(-not($Source))
    {
        $Source = $Package.Publisher
    }    
    $details =  @{
                    Publisher = $Package.Publisher
                    Architecture = $Package.Architecture
                    ResourceId = $Package.ResourceId
                    PackageFullName = $Package.PackageFullName
                 }

    $params = @{    
                FastPackageReference = $fastPackageReference;
                Name = $Package.Name;
                Version = $Package.Version;
                versionScheme  = "MultiPartNumeric";
                Source = $source;
                Details = $details;
    }
    
    $sid = New-SoftwareIdentity @params
    return $sid       
}

function Test-WebUri
{
    [CmdletBinding()]
    [OutputType([bool])]
    Param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [Uri]
        $uri
    )

    return ($uri.AbsoluteURI -ne $null) -and ($uri.Scheme -match '[http|https]')
}

function Test-WildcardPattern
{
    [CmdletBinding()]
    [OutputType([bool])]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNull()]
        $Name
    )

    return [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name)    
}

function DeSerialize-PSObject
{
    [CmdletBinding(PositionalBinding=$false)]    
    Param
    (
        [Parameter(Mandatory=$true)]        
        $Path
    )
    $filecontent = Microsoft.PowerShell.Management\Get-Content -Path $Path
    [System.Management.Automation.PSSerializer]::Deserialize($filecontent)    
}

function Get-SourceName
{
    [CmdletBinding()]
    [OutputType("string")]
    Param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Location
    )

    Set-PackageSourcesVariable

    foreach($source in $script:AppxPackageSources.Values)
    {
        if($source.SourceLocation -eq $Location)
        {
            return $source.Name
        }
    }
}

function WebRequestApisAvailable
{
    $webRequestApiAvailable = $false
    try 
    {
        [System.Net.WebRequest]
        $webRequestApiAvailable = $true
    } 
    catch 
    {
    }
    return $webRequestApiAvailable
}

function Ping-Endpoint
{
    param
    (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $Endpoint
    )   
        
    $results = @{}

    if(WebRequestApisAvailable)
    {
        $iss = [System.Management.Automation.Runspaces.InitialSessionState]::Create()
        $iss.types.clear()
        $iss.formats.clear()
        $iss.LanguageMode = "FullLanguage"

        $WebRequestcmd =  @'
            try
            {{
                $request = [System.Net.WebRequest]::Create("{0}")
                $request.Method = 'GET'
                $request.Timeout = 30000
                $response = [System.Net.HttpWebResponse]$request.GetResponse()
                $response
                $response.Close()
            }}
            catch [System.Net.WebException]
            {{
                "Error:System.Net.WebException"
            }}
'@
 -f $EndPoint

        $ps = [powershell]::Create($iss).AddScript($WebRequestcmd)
        $response = $ps.Invoke()
        $ps.dispose()

        if ($response -ne "Error:System.Net.WebException")
        {
            $results.Add($Script:ResponseUri,$response.ResponseUri.ToString())
            $results.Add($Script:StatusCode,$response.StatusCode.value__)
        }        
    }
    else
    {
        $response = $null
        try
        {
            $httpClient = New-Object 'System.Net.Http.HttpClient'
            $response = $httpclient.GetAsync($endpoint)          
        }
        catch
        {            
        } 

        if ($response -ne $null -and $response.result -ne $null)
        {        
            $results.Add($Script:ResponseUri,$response.Result.RequestMessage.RequestUri.AbsoluteUri.ToString())
            $results.Add($Script:StatusCode,$response.result.StatusCode.value__)            
        }
    }
    return $results
}

function Get-ValidPackageLocation
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $LocationString,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ParameterName
    )

    # Get the actual Uri from the Location
    if(-not (Microsoft.PowerShell.Management\Test-Path $LocationString))
    {
        $results = Ping-Endpoint -Endpoint $LocationString
    
        if ($results.ContainsKey("Exception"))
        {
            $Exception = $results["Exception"]
            if($Exception)
            {
                $message = $LocalizedData.InvalidWebUri -f ($LocationString, $ParameterName)
                ThrowError -ExceptionName "System.ArgumentException" `
                            -ExceptionMessage $message `
                            -ErrorId "InvalidWebUri" `
                            -ExceptionObject $Exception `
                            -CallerPSCmdlet $PSCmdlet `
                            -ErrorCategory InvalidArgument
            }
        }

        if ($results.ContainsKey("ResponseUri"))
        {
            $LocationString = $results["ResponseUri"]
        }
    }

    return $LocationString
}

function Set-PackageSourcesVariable
{
    param([switch]$Force)

    if(-not $script:AppxPackageSources -or $Force)
    {
        if(Microsoft.PowerShell.Management\Test-Path $script:AppxPackageSourcesFilePath)
        {
            $script:AppxPackageSources = DeSerialize-PSObject -Path $script:AppxPackageSourcesFilePath
        }
        else
        {
            $script:AppxPackageSources = [ordered]@{}
        }
    }   
}

function Save-PackageSources
{
    if($script:AppxPackageSources)
    {
        if(-not (Microsoft.PowerShell.Management\Test-Path $script:AppxLocalPath))
        {
            $null = Microsoft.PowerShell.Management\New-Item -Path $script:AppxLocalPath `
                                                             -ItemType Directory -Force `
                                                             -ErrorAction SilentlyContinue `
                                                             -WarningAction SilentlyContinue `
                                                             -Confirm:$false -WhatIf:$false
        }        
        Microsoft.PowerShell.Utility\Out-File -FilePath $script:AppxPackageSourcesFilePath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:AppxPackageSources))
   }   
}

function New-PackageSourceFromSource
{
    param
    (
        [Parameter(Mandatory)]
        $Source
    )
     
    # create a new package source
    $src =  New-PackageSource -Name $Source.Name `
                              -Location $Source.SourceLocation `
                              -Trusted $Source.Trusted `
                              -Registered $Source.Registered `

    Write-Verbose ( $LocalizedData.PackageSourceDetails -f ($src.Name, $src.Location, $src.IsTrusted, $src.IsRegistered) )

    # return the package source object.
    Write-Output -InputObject $src
}
#endregion

# Utility to throw an errorrecord
function ThrowError
{
    param
    (        
        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.Management.Automation.PSCmdlet]
        $CallerPSCmdlet,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.String]        
        $ExceptionName,

        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $ExceptionMessage,
        
        [System.Object]
        $ExceptionObject,
        
        [parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $ErrorId,

        [parameter(Mandatory = $true)]
        [ValidateNotNull()]
        [System.Management.Automation.ErrorCategory]
        $ErrorCategory
    )
          
    $exception = New-Object $ExceptionName $ExceptionMessage;
    $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $ErrorId, $ErrorCategory, $ExceptionObject    
    $CallerPSCmdlet.ThrowTerminatingError($errorRecord)    
}
#endregion

Export-ModuleMember -Function  Find-AppxPackage , `
                              Find-Package, `
                              Install-Package, `
                              Download-Package, `
                              Uninstall-Package, `
                              Get-InstalledPackage, `
                              Remove-PackageSource, `
                              Resolve-PackageSource, `
                              Add-PackageSource, `
                              Get-DynamicOptions, `
                              Initialize-Provider, `
                              Get-PackageProviderName


# SIG # Begin signature block
# MIIarwYJKoZIhvcNAQcCoIIaoDCCGpwCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU1GcdTcBQPd+qVU4hAR1uVqDU
# HqSgghWCMIIEwzCCA6ugAwIBAgITMwAAAJb6gDHvN2RGRQAAAAAAljANBgkqhkiG
# 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw
# HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTUxMDA3MTgxNDI0
# WhcNMTcwMTA3MTgxNDI0WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNO
# OkJCRUMtMzBDQS0yREJFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT
# ZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm1pYSwjyVGa6
# tIZe8M6+zXQQ33WKYIyKYcI3oiZcZgVcxdizVjv3hKmjqmRTC5REuLtaSYbdeCuG
# bdMP2+NGWrqeWKLQIxb/Gs/BkEzrr+ewnZ+UQ7xON8jkhPhMSdT5ZiVVNdhVgo+y
# 3hvrk0tk4iDpr5Xwqk5U2W5yZkXras/mIIfO54mjfS31tKQbIsxxubm8Np9ioBit
# boqgiC1iwSxGh7/LGPp1NJVacuQc1JMuzkhRNXxwALbWbyrsUV8Aztz5eaUASLoF
# jkK43ety0X/rV9Qlws43Q2LjKhztpEaxloEr0gioCAEmkJssDjd1qqCZ6X/bht1e
# ggluXnz2tQIDAQABo4IBCTCCAQUwHQYDVR0OBBYEFMfD/XvxW9NCtvwEw94qmvuS
# ht7IMB8GA1UdIwQYMBaAFCM0+NlSRnAK7UD7dvuzK7DDNbMPMFQGA1UdHwRNMEsw
# SaBHoEWGQ2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz
# L01pY3Jvc29mdFRpbWVTdGFtcFBDQS5jcmwwWAYIKwYBBQUHAQEETDBKMEgGCCsG
# AQUFBzAChjxodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv
# c29mdFRpbWVTdGFtcFBDQS5jcnQwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZI
# hvcNAQEFBQADggEBADQzONHGQV0X/NPCsvaZQv26Syn1rUGW85E9wUCgtf0iWG55
# ntOcHryYkkVIkjB/vd9ixfzGlW2Bz08YdPHJc5he9ZNkfwhjHqW9r6ii06pa4kzE
# PbgYlLwVRRvxzJwLZpSe56UceM8FmEnsRUSVKzabhLjmiIAFpnNlGgYd6g0eDvxT
# FM9SOJozV4Mjyb7e+Gv//ZxUeZcTK2S/Nam+B6m/mlRVajUYotCDwziVxrm1irMt
# a15M55pT3aawt+QrwXaRUMRSRmIgXTHgFWdM3AksQGA0a77rRKGYldX0iPyH2XOw
# rTHQww9kEcX1r+2R+9QjmsljYc3ZPGnA+2YCADEwggTsMIID1KADAgECAhMzAAAB
# Cix5rtd5e6asAAEAAAEKMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBMB4XDTE1MDYwNDE3NDI0NVoXDTE2MDkwNDE3NDI0NVowgYMxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIx
# HjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIwDQYJKoZIhvcNAQEB
# BQADggEPADCCAQoCggEBAJL8bza74QO5KNZG0aJhuqVG+2MWPi75R9LH7O3HmbEm
# UXW92swPBhQRpGwZnsBfTVSJ5E1Q2I3NoWGldxOaHKftDXT3p1Z56Cj3U9KxemPg
# 9ZSXt+zZR/hsPfMliLO8CsUEp458hUh2HGFGqhnEemKLwcI1qvtYb8VjC5NJMIEb
# e99/fE+0R21feByvtveWE1LvudFNOeVz3khOPBSqlw05zItR4VzRO/COZ+owYKlN
# Wp1DvdsjusAP10sQnZxN8FGihKrknKc91qPvChhIqPqxTqWYDku/8BTzAMiwSNZb
# /jjXiREtBbpDAk8iAJYlrX01boRoqyAYOCj+HKIQsaUCAwEAAaOCAWAwggFcMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBSJ/gox6ibN5m3HkZG5lIyiGGE3
# NDBRBgNVHREESjBIpEYwRDENMAsGA1UECxMETU9QUjEzMDEGA1UEBRMqMzE1OTUr
# MDQwNzkzNTAtMTZmYS00YzYwLWI2YmYtOWQyYjFjZDA1OTg0MB8GA1UdIwQYMBaA
# FMsR6MrStBZYAck3LjMWFrlMmgofMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9j
# cmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY0NvZFNpZ1BDQV8w
# OC0zMS0yMDEwLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljQ29kU2lnUENBXzA4LTMx
# LTIwMTAuY3J0MA0GCSqGSIb3DQEBBQUAA4IBAQCmqFOR3zsB/mFdBlrrZvAM2PfZ
# hNMAUQ4Q0aTRFyjnjDM4K9hDxgOLdeszkvSp4mf9AtulHU5DRV0bSePgTxbwfo/w
# iBHKgq2k+6apX/WXYMh7xL98m2ntH4LB8c2OeEti9dcNHNdTEtaWUu81vRmOoECT
# oQqlLRacwkZ0COvb9NilSTZUEhFVA7N7FvtH/vto/MBFXOI/Enkzou+Cxd5AGQfu
# FcUKm1kFQanQl56BngNb/ErjGi4FrFBHL4z6edgeIPgF+ylrGBT6cgS3C6eaZOwR
# XU9FSY0pGi370LYJU180lOAWxLnqczXoV+/h6xbDGMcGszvPYYTitkSJlKOGMIIF
# vDCCA6SgAwIBAgIKYTMmGgAAAAAAMTANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZIm
# iZPyLGQBGRYDY29tMRkwFwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQD
# EyRNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMTAwODMx
# MjIxOTMyWhcNMjAwODMxMjIyOTMyWjB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMSMwIQYDVQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBD
# QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJyWVwZMGS/HZpgICBC
# mXZTbD4b1m/My/Hqa/6XFhDg3zp0gxq3L6Ay7P/ewkJOI9VyANs1VwqJyq4gSfTw
# aKxNS42lvXlLcZtHB9r9Jd+ddYjPqnNEf9eB2/O98jakyVxF3K+tPeAoaJcap6Vy
# c1bxF5Tk/TWUcqDWdl8ed0WDhTgW0HNbBbpnUo2lsmkv2hkL/pJ0KeJ2L1TdFDBZ
# +NKNYv3LyV9GMVC5JxPkQDDPcikQKCLHN049oDI9kM2hOAaFXE5WgigqBTK3S9dP
# Y+fSLWLxRT3nrAgA9kahntFbjCZT6HqqSvJGzzc8OJ60d1ylF56NyxGPVjzBrAlf
# A9MCAwEAAaOCAV4wggFaMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMsR6MrS
# tBZYAck3LjMWFrlMmgofMAsGA1UdDwQEAwIBhjASBgkrBgEEAYI3FQEEBQIDAQAB
# MCMGCSsGAQQBgjcVAgQWBBT90TFO0yaKleGYYDuoMW+mPLzYLTAZBgkrBgEEAYI3
# FAIEDB4KAFMAdQBiAEMAQTAfBgNVHSMEGDAWgBQOrIJgQFYnl+UlE/wq4QpTlVnk
# pDBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtp
# L2NybC9wcm9kdWN0cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEE
# SDBGMEQGCCsGAQUFBzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2Nl
# cnRzL01pY3Jvc29mdFJvb3RDZXJ0LmNydDANBgkqhkiG9w0BAQUFAAOCAgEAWTk+
# fyZGr+tvQLEytWrrDi9uqEn361917Uw7LddDrQv+y+ktMaMjzHxQmIAhXaw9L0y6
# oqhWnONwu7i0+Hm1SXL3PupBf8rhDBdpy6WcIC36C1DEVs0t40rSvHDnqA2iA6VW
# 4LiKS1fylUKc8fPv7uOGHzQ8uFaa8FMjhSqkghyT4pQHHfLiTviMocroE6WRTsgb
# 0o9ylSpxbZsa+BzwU9ZnzCL/XB3Nooy9J7J5Y1ZEolHN+emjWFbdmwJFRC9f9Nqu
# 1IIybvyklRPk62nnqaIsvsgrEA5ljpnb9aL6EiYJZTiU8XofSrvR4Vbo0HiWGFzJ
# NRZf3ZMdSY4tvq00RBzuEBUaAF3dNVshzpjHCe6FDoxPbQ4TTj18KUicctHzbMrB
# 7HCjV5JXfZSNoBtIA1r3z6NnCnSlNu0tLxfI5nI3EvRvsTxngvlSso0zFmUeDord
# EN5k9G/ORtTTF+l5xAS00/ss3x+KnqwK+xMnQK3k+eGpf0a7B2BHZWBATrBC7E7t
# s3Z52Ao0CW0cgDEf4g5U3eWh++VHEK1kmP9QFi58vwUheuKVQSdpw5OPlcmN2Jsh
# rg1cnPCiroZogwxqLbt2awAdlq3yFnv2FoMkuYjPaqhHMS+a3ONxPdcAfmJH0c6I
# ybgY+g5yjcGjPa8CQGr/aZuW4hCoELQ3UAjWwz0wggYHMIID76ADAgECAgphFmg0
# AAAAAAAcMA0GCSqGSIb3DQEBBQUAMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAX
# BgoJkiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290
# IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0wNzA0MDMxMjUzMDlaFw0yMTA0MDMx
# MzAzMDlaMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xITAf
# BgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQTCCASIwDQYJKoZIhvcNAQEB
# BQADggEPADCCAQoCggEBAJ+hbLHf20iSKnxrLhnhveLjxZlRI1Ctzt0YTiQP7tGn
# 0UytdDAgEesH1VSVFUmUG0KSrphcMCbaAGvoe73siQcP9w4EmPCJzB/LMySHnfL0
# Zxws/HvniB3q506jocEjU8qN+kXPCdBer9CwQgSi+aZsk2fXKNxGU7CG0OUoRi4n
# rIZPVVIM5AMs+2qQkDBuh/NZMJ36ftaXs+ghl3740hPzCLdTbVK0RZCfSABKR2YR
# JylmqJfk0waBSqL5hKcRRxQJgp+E7VV4/gGaHVAIhQAQMEbtt94jRrvELVSfrx54
# QTF3zJvfO4OToWECtR0Nsfz3m7IBziJLVP/5BcPCIAsCAwEAAaOCAaswggGnMA8G
# A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM0+NlSRnAK7UD7dvuzK7DDNbMPMAsG
# A1UdDwQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADCBmAYDVR0jBIGQMIGNgBQOrIJg
# QFYnl+UlE/wq4QpTlVnkpKFjpGEwXzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcG
# CgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJvb3Qg
# Q2VydGlmaWNhdGUgQXV0aG9yaXR5ghB5rRahSqClrUxzWPQHEy5lMFAGA1UdHwRJ
# MEcwRaBDoEGGP2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1
# Y3RzL21pY3Jvc29mdHJvb3RjZXJ0LmNybDBUBggrBgEFBQcBAQRIMEYwRAYIKwYB
# BQUHMAKGOGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljcm9z
# b2Z0Um9vdENlcnQuY3J0MBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEB
# BQUAA4ICAQAQl4rDXANENt3ptK132855UU0BsS50cVttDBOrzr57j7gu1BKijG1i
# uFcCy04gE1CZ3XpA4le7r1iaHOEdAYasu3jyi9DsOwHu4r6PCgXIjUji8FMV3U+r
# kuTnjWrVgMHmlPIGL4UD6ZEqJCJw+/b85HiZLg33B+JwvBhOnY5rCnKVuKE5nGct
# xVEO6mJcPxaYiyA/4gcaMvnMMUp2MT0rcgvI6nA9/4UKE9/CCmGO8Ne4F+tOi3/F
# NSteo7/rvH0LQnvUU3Ih7jDKu3hlXFsBFwoUDtLaFJj1PLlmWLMtL+f5hYbMUVbo
# nXCUbKw5TNT2eb+qGHpiKe+imyk0BncaYsk9Hm0fgvALxyy7z0Oz5fnsfbXjpKh0
# NbhOxXEjEiZ2CzxSjHFaRkMUvLOzsE1nyJ9C/4B5IYCeFTBm6EISXhrIniIh0EPp
# K+m79EjMLNTYMoBMJipIJF9a6lbvpt6Znco6b72BJ3QGEe52Ib+bgsEnVLaxaj2J
# oXZhtG6hE6a/qkfwEm/9ijJssv7fUciMI8lmvZ0dhxJkAj0tr1mPuOQh5bWwymO0
# eFQF1EEuUKyUsKV4q7OglnUa2ZKHE3UiLzKoCG6gW4wlv6DvhMoh1useT8ma7kng
# 9wFlb4kLfchpyOZu6qeXzjEp/w7FW1zYTRuh2Povnj8uVRZryROj/TGCBJcwggST
# AgEBMIGQMHkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xIzAh
# BgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBAhMzAAABCix5rtd5e6as
# AAEAAAEKMAkGBSsOAwIaBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFHNs
# WB3wAUBvNjZX/j8CapRxHOBmMFAGCisGAQQBgjcCAQwxQjBAoBaAFABQAG8AdwBl
# AHIAUwBoAGUAbABsoSaAJGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9Qb3dlclNo
# ZWxsIDANBgkqhkiG9w0BAQEFAASCAQAc3o5bn1HBYxqdkPUIb1dROY0d7gxYQUNj
# 7W/jexyidR2/FHNWHh4Pt+tqLz/sn/QTHv5DcZQF47QMFyvFVF5uZbEqOhc0PBAJ
# MhZYA265A7Gn1DPseTsJvWOFhlVyegxCRJLnP9biMBBomFNU7sR7nFVZXOhAII1N
# hgcWHx7XQgk8KHa8lpLuJ8R5TL3PJzbrre2PDVso6WaMQ/UHuIv1qmddfJ1dD7cz
# HT8jFs26BYV0Vh2Ix81mm7IJfW7Kdk8mB6FAj4Y21Vc22aL1x836pwmn1glmJ/ya
# GIeA8Ej0d6DXIMne40H8sFqMGrYpVC/ouKwWl4aHGj810FZzP0EWoYICKDCCAiQG
# CSqGSIb3DQEJBjGCAhUwggIRAgEBMIGOMHcxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xITAfBgNVBAMTGE1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
# QQITMwAAAJb6gDHvN2RGRQAAAAAAljAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkD
# MQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTYwNDI1MTk0NjIzWjAjBgkq
# hkiG9w0BCQQxFgQUuhEhJzDkaM7OedmGS4fs60HBoW0wDQYJKoZIhvcNAQEFBQAE
# ggEAavJmnoykIG65f9TA2KgQ58DmoxiE30QcwvohW2W1x2hISfaMhjS4Ys6XTh7s
# C5TVGAejEjSpvvcDL9Jp/xYx5RnKc4bEHfIL7vlpXnAl+yITbL+GKa2NXnYCx4dD
# 7MLsGtDCijM5AH/jGjF2OsvQz66NnLWULilSiwLn1UuPWGXA/jgZkpherhm4WT0T
# RaMR/XNzJEVYmiLm31u/JetXeKR84iL+30hJVNPhTEEwrGpNsODfbAoIbtkAT8b8
# vzCTONKuvH/wMlm3O13VS8Q+1YxhwgPoTgkD4nz8FJBdTMNawl+yRDaPZPA43lGE
# +eHeXiR0z1vQeN3Oj4k2me1STw==
# SIG # End signature block