PSSwaggerUtility/PSSwaggerUtility.psm1

#########################################################################################
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# Licensed under the MIT license.
#
# PSSwaggerUtility Module
#
#########################################################################################
Microsoft.PowerShell.Core\Set-StrictMode -Version Latest
Microsoft.PowerShell.Utility\Import-LocalizedData  LocalizedData -filename PSSwaggerUtility.Resources.psd1

<#
.DESCRIPTION
  Gets the content of a file. Removes the signature block, if it exists.
 
.PARAMETER Path
  Path to the file whose contents should be read.
#>

function Remove-AuthenticodeSignatureBlock {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Path
    )

    $content = Get-Content -Path $Path
    $skip = $false
    foreach ($line in $content) {
        if ($line -eq "# SIG # Begin signature block") {
            $skip = $true
        } elseif ($line -eq "# SIG # End signature block") {
            $skip = $false
        } elseif (-not $skip) {
            $line
        }
    }
}

<#
.DESCRIPTION
  Gets the list of required modules to be imported for the scriptblock.
 
.PARAMETER ModuleInfo
  PSModuleInfo object of the Swagger command.
#>

function Get-RequiredModulesPath
{
    param(
        [Parameter(Mandatory=$true)]
        [System.Management.Automation.PSModuleInfo]
        $ModuleInfo
    )

    $ModulePaths = @()
    $ModulePaths += $ModuleInfo.RequiredModules | ForEach-Object { Get-RequiredModulesPath -ModuleInfo $_}

    $ManifestPath = Join-Path -Path (Split-Path -Path $ModuleInfo.Path -Parent) -ChildPath "$($ModuleInfo.Name).psd1"
    if(Test-Path -Path $ManifestPath)
    {
        $ModulePaths += $ManifestPath
    }
    else
    {
        $ModulePaths += $ModuleInfo.Path
    }

    return $ModulePaths | Select-Object -Unique
}

<#
.DESCRIPTION
  Invokes the specified script block as PSSwaggerJob.
 
.PARAMETER ScriptBlock
  ScriptBlock to be executed in the PSSwaggerJob
 
.PARAMETER CallerPSCmdlet
  Called $PSCmldet object to set the failure status.
 
.PARAMETER CallerPSBoundParameters
  Parameters to be passed into the specified script block.
 
.PARAMETER CallerModule
  PSModuleInfo object of the Swagger command.
#>

function Start-PSSwaggerJobHelper
{
    param(
        [Parameter(Mandatory=$true)]
        [System.Management.Automation.ScriptBlock]
        $ScriptBlock,

        [Parameter(Mandatory=$false)]
        [System.Management.Automation.PSCmdlet]
        $CallerPSCmdlet,

        [Parameter(Mandatory=$true)]
        $CallerPSBoundParameters,

        [Parameter(Mandatory=$false)]
        [System.Management.Automation.PSModuleInfo]
        $CallerModule
    )

    $AsJob = $false
    if($CallerPSBoundParameters.ContainsKey('AsJob'))
    {
        $AsJob = $true
    }

    $null = $CallerPSBoundParameters.Remove('WarningVariable')
    $null = $CallerPSBoundParameters.Remove('ErrorVariable')
    $null = $CallerPSBoundParameters.Remove('OutVariable')
    $null = $CallerPSBoundParameters.Remove('OutBuffer')
    $null = $CallerPSBoundParameters.Remove('PipelineVariable')
    $null = $CallerPSBoundParameters.Remove('InformationVariable')
    $null = $CallerPSBoundParameters.Remove('InformationAction')
    $null = $CallerPSBoundParameters.Remove('AsJob')

    $PSSwaggerJobParameters = @{}
    $PSSwaggerJobParameters['ScriptBlock'] = $ScriptBlock

    # Required modules list
    if ($CallerModule)
    {
        $PSSwaggerJobParameters['RequiredModules'] = Get-RequiredModulesPath -ModuleInfo $CallerModule
    }

    $VerbosePresent = $false
    if (-not $CallerPSBoundParameters.ContainsKey('Verbose'))
    {
        if($VerbosePreference -in 'Continue','Inquire')
        {
            $CallerPSBoundParameters['Verbose'] = [System.Management.Automation.SwitchParameter]::Present
            $VerbosePresent = $true
        }
    }
    else
    {
        $VerbosePresent = $true
    }

    $DebugPresent = $false
    if (-not $CallerPSBoundParameters.ContainsKey('Debug'))
    {
        if($debugPreference -in 'Continue','Inquire')
        {
            $CallerPSBoundParameters['Debug'] = [System.Management.Automation.SwitchParameter]::Present
            $DebugPresent = $true
        }
    }
    else
    {
        $DebugPresent = $true
    }

    if (-not $CallerPSBoundParameters.ContainsKey('ErrorAction'))
    {
        $CallerPSBoundParameters['ErrorAction'] = $errorActionPreference
    }

    if(Test-Path variable:\errorActionPreference)
    {
        $errorAction = $errorActionPreference
    }
    else
    {
        $errorAction = 'Continue'
    }

    if ($CallerPSBoundParameters['ErrorAction'] -eq 'SilentlyContinue')
    {
        $errorAction = 'SilentlyContinue'
    }

    if($CallerPSBoundParameters['ErrorAction'] -eq 'Ignore')
    {
        $CallerPSBoundParameters['ErrorAction'] = 'SilentlyContinue'
        $errorAction = 'SilentlyContinue'
    }

    if ($CallerPSBoundParameters['ErrorAction'] -eq 'Inquire')
    {
        $CallerPSBoundParameters['ErrorAction'] = 'Continue'
        $errorAction = 'Continue'
    }

    if (-not $CallerPSBoundParameters.ContainsKey('WarningAction'))
    {
        $CallerPSBoundParameters['WarningAction'] = $warningPreference
    }

    if(Test-Path variable:\warningPreference)
    {
        $warningAction = $warningPreference
    }
    else
    {
        $warningAction = 'Continue'
    }

    if ($CallerPSBoundParameters['WarningAction'] -in 'SilentlyContinue','Ignore')
    {
        $warningAction = 'SilentlyContinue'
    }

    if ($CallerPSBoundParameters['WarningAction'] -eq 'Inquire')
    {
        $CallerPSBoundParameters['WarningAction'] = 'Continue'
        $warningAction = 'Continue'
    }

    if($CallerPSBoundParameters)
    {
        $PSSwaggerJobParameters['Parameters'] = $CallerPSBoundParameters
    }

    $job = Start-PSSwaggerJob @PSSwaggerJobParameters

    if($job)
    {
        if($AsJob)
        {
            $job
        }
        else
        {
            try
            {
                Receive-Job -Job $job -Wait -Verbose:$VerbosePresent -Debug:$DebugPresent -ErrorAction $errorAction -WarningAction $warningAction

                if($CallerPSCmdlet)
                {
                    $CallerPSCmdlet.InvokeCommand.HasErrors = $job.State -eq 'Failed'
                }
            }
            finally
            {
                if($job.State -ne "Suspended" -and $job.State -ne "Stopped")
                {
                    Get-Job -Id $job.Id -ErrorAction Ignore | Remove-Job -Force -ErrorAction Ignore
                }
                else
                {
                    $job
                }
            }
        }
    }
}

<#
.DESCRIPTION
  Gets operating system information. Returns an object with the following boolean properties: IsCore, IsLinux, IsWindows, IsMacOS, IsNanoServer, IsIoT
#>

function Get-OperatingSystemInfo {
    $info = @{
        IsCore = $false
        IsLinux = $false
        IsMacOS = $false
        IsWindows = $false
        IsNanoServer = $false
        IsIoT = $false
    }

    if ('System.Management.Automation.Platform' -as [Type]) {
        $info.IsCore = [System.Management.Automation.Platform]::IsCoreCLR
        $info.IsLinux = [System.Management.Automation.Platform]::IsLinux
        $info.IsMacOS = [System.Management.Automation.Platform]::IsMacOS
        $info.IsWindows = [System.Management.Automation.Platform]::IsWindows
        $info.IsNanoServer = [System.Management.Automation.Platform]::IsNanoServer
        $info.IsIoT = [System.Management.Automation.Platform]::IsIoT
    } else {
        # If this type doesn't exist, this should be full CLR Windows
        $info.IsWindows = $true
    }

    return $info
}

<#
.DESCRIPTION
  Gets the platform-specific directory for the given DirectoryType. Shared is a non-XDG concept for all-users access. Caller is expected to handle creation, deletion, and permissions.
  Note that this does NOT mean that PSSwagger follows the XDG specification on non-Windows systems exactly.
 
.PARAMETER DirectoryType
  Type of directory to resolve.
#>

function Get-XDGDirectory {
    param(
        [Parameter(Mandatory = $true)]
        [ValidateSet('Config', 'Data', 'Cache', 'Shared')]
        [string]
        $DirectoryType
    )

    if ((Get-OperatingSystemInfo).IsWindows) {
        # Windows filesystem is not included in the XDG specification
        if ('Shared' -eq $DirectoryType) {
            return Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramData -ChildPath 'Microsoft' | Join-Path -ChildPath 'Windows' | Join-Path -ChildPath 'PowerShell'
        } elseif ('Cache' -eq $DirectoryType) {
            return ([System.IO.Path]::GetTempPath())
        } else {
            return Microsoft.PowerShell.Management\Join-Path -Path $env:LOCALAPPDATA -ChildPath 'Microsoft' | Join-Path -ChildPath 'Windows' | Join-Path -ChildPath 'PowerShell'
        }
    } else {
        # The rest should follow: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
        $dirHome = $null
        $dirDefault = $null
        $homeVar = Get-EnvironmentVariable -Name "HOME"
        if ('Config' -eq $DirectoryType) {
            $dirHome = Get-EnvironmentVariable -Name "XDG_CONFIG_HOME"
            $dirDefault = Join-Path -Path "$homeVar" -ChildPath ".config"
        } elseif ('Data' -eq $DirectoryType) {
            $dirHome = Get-EnvironmentVariable -Name "XDG_DATA_HOME"
            $dirDefault = Join-Path -Path "$homeVar" -ChildPath ".local" | Join-Path -ChildPath "share"
        } elseif ('Cache' -eq $DirectoryType) {
            $dirHome = Get-EnvironmentVariable -Name "XDG_CACHE_HOME"
            $dirDefault = Join-Path -Path "$homeVar" -ChildPath ".cache"
        } else {
             # As global access isn't part of the XDG Base Directory Specification, we use PowerShell Core's definition: /usr/local/share
            return '/usr/local/share'
        }

        if (-not $dirHome) {
            return $dirDefault
        }

        return $dirHome
    }
}

<# .DESCRIPTION
  Helper method to get an environment variable.
#>

function Get-EnvironmentVariable {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]
        $Name
    )

    $value = [System.Environment]::GetEnvironmentVariable($Name)
    if (-not $value) {
        # If the variable doesn't exist as an environment variable, check if it exists locally
        $variable = Get-Variable -Name $Name -ErrorAction Ignore
        if ($variable) {
            return $variable.Value
        } else {
            return $value
        }
    }

    return $value
}

#region Compilation utils for PSSwagger

# go fwlink for latest nuget.exe for win10 x86
$script:NuGetClientSourceURL = 'https://go.microsoft.com/fwlink/?linkid=843467'
$script:ProgramDataPath = $null
$script:AppLocalPath = $null

<#
.DESCRIPTION
  Compiles AutoRest generated C# code using the framework of the current PowerShell process.
 
.PARAMETER CSharpFiles
  All C# files to compile. Only AutoRest generated code is fully supported.
 
.PARAMETER OutputAssembly
  Full Path to the output assembly.
 
.PARAMETER NewtonsoftJsonRequiredVersion
  Optional string specifying required version of Newtonsoft.Json package.
 
.PARAMETER MicrosoftRestClientRuntimeRequiredVersion
  Optional string specifying required version of Microsoft.Rest.ClientRuntime package.
 
.PARAMETER MicrosoftRestClientRuntimeAzureRequiredVersion
  Optional string specifying required version of Microsoft.Rest.ClientRuntime.Azure package. Only used if -CodeCreatedByAzureGenerator is also used.
 
.PARAMETER AllUsers
  User wants to install local tools for all users.
 
.PARAMETER BootstrapConsent
  User has consented to bootstrap dependencies.
 
.PARAMETER TestBuild
  Build binaries for testing (disable compiler optimizations, enable full debug information).
 
.PARAMETER CodeCreatedByAzureGenerator
  C# code generated by Azure.CSharp AutoRest code generator.
 
.PARAMETER SymbolPath
  Path to store PDB file and matching source file.
#>

function Add-PSSwaggerClientType {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [System.IO.FileInfo[]]
        $CSharpFiles,

        [Parameter(Mandatory=$true)]
        [AllowEmptyString()]
        [string]
        $ClrPath,

        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $OutputAssemblyName,

        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $NewtonsoftJsonRequiredVersion,

        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $MicrosoftRestClientRuntimeRequiredVersion,

        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $MicrosoftRestClientRuntimeAzureRequiredVersion,

        [Parameter(Mandatory=$false)]
        [switch]
        $AllUsers,

        [Parameter(Mandatory=$false)]
        [switch]
        $BootstrapConsent,

        [Parameter(Mandatory=$false)]
        [switch]
        $TestBuild,

        [Parameter(Mandatory=$false)]
        [switch]
        $CodeCreatedByAzureGenerator,

        [Parameter(Mandatory=$false)]
        [string]
        $SymbolPath
    )

    # Remake the required version map
    $requiredVersionMap = @{}
    if ($NewtonsoftJsonRequiredVersion) {
        $requiredVersionMap['Newtonsoft.Json'] = $NewtonsoftJsonRequiredVersion
    }
    if ($MicrosoftRestClientRuntimeRequiredVersion) {
        $requiredVersionMap['Microsoft.Rest.ClientRuntime'] = $MicrosoftRestClientRuntimeRequiredVersion
    }
    if ($MicrosoftRestClientRuntimeAzureRequiredVersion) {
        $requiredVersionMap['Microsoft.Rest.ClientRuntime.Azure'] = $MicrosoftRestClientRuntimeAzureRequiredVersion
    }

    # Find the reference assemblies to use
    # System refs are expected to exist on the system
    # Extra refs are shipped by PSSwagger
    $systemRefs = @()
    $preprocessorDirectives = @()
    if ((Get-OperatingSystemInfo).IsCore) {
        # Base framework references
        $preprocessorDirectives = @('#define DNXCORE50','#define PORTABLE')
        $systemRefs = @('System.dll',
                        'System.Core.dll',
                        'System.Net.Http.dll',
                        'Microsoft.CSharp.dll',
                        'System.Private.Uri.dll',
                        'System.Runtime.dll',
                        'System.Threading.Tasks.dll',
                        'System.Text.RegularExpressions.dll',
                        'System.Collections.dll',
                        'System.Net.Primitives.dll',
                        'System.Text.Encoding.dll',
                        'System.Linq.dll',
                        'System.Runtime.Serialization.Primitives.dll')
        $externalReferencesFramework = 'netstandard1'
    } else {
        # Base framework references
        $systemRefs = @('System.dll',
                        'System.Core.dll',
                        'System.Net.Http.dll',
                        'System.Net.Http.WebRequest.dll',
                        'System.Runtime.Serialization.dll',
                        'System.Xml.dll')
        $externalReferencesFramework = 'net4'
    }

    # Get dependencies for AutoRest SDK
    $externalReferences = Get-PSSwaggerExternalDependencies -Framework $externalReferencesFramework -Azure:$CodeCreatedByAzureGenerator -RequiredVersionMap $requiredVersionMap

    $AddClientTypeHelperParams = @{
        Path                   = $CSharpFiles | ForEach-Object { $_.FullName }
        AllUsers               = $AllUsers
        BootstrapConsent       = $BootstrapConsent
        PackageDependencies    = $externalReferences
        PreprocessorDirectives = $PreprocessorDirectives
    }
    if ($OutputAssemblyName) {
        $AddClientTypeHelperParams['OutputDirectory']    = $clrPath
        $AddClientTypeHelperParams['OutputAssemblyName'] = $OutputAssemblyName
        $AddClientTypeHelperParams['TestBuild']          = $TestBuild
        $AddClientTypeHelperParams['SymbolPath']         = $SymbolPath
    }
    $HelperResult = Add-PSSwaggerClientTypeHelper @AddClientTypeHelperParams

    $CompilerHelperParams = @{
        ReferencedAssemblies = $systemRefs + $HelperResult['ResolvedPackageReferences']
        SourceCodeFilePath   = $HelperResult['SourceCodeFilePath']
        OutputAssembly       = $HelperResult['OutputAssembly']
        TestBuild            = $TestBuild
    }

    if ((Get-OperatingSystemInfo).IsCore) {
        $addTypeParams = Get-AddTypeParameters @CompilerHelperParams
        Add-Type @addTypeParams
    }
    else {
        $CscArgumentList = Get-CscParameters @CompilerHelperParams
        $output = & 'Csc.exe' $CscArgumentList
        if ($output) {
            Write-Error -ErrorId 'SOURCE_CODE_ERROR' -Message ($output | Out-String)
            return $false
        }
    }

    # Copy the PDB to the symbol path if specified
    if ($HelperResult['OutputAssembly']) {
        # Verify result of assembly compilation
        $outputAssemblyItem = Get-Item -Path $HelperResult['OutputAssembly']
        if ((-not (Test-Path -Path $HelperResult['OutputAssembly'])) -or ($outputAssemblyItem.Length -eq 0kb)) {
            return $false
        }

        if(-not $OutputAssemblyName) {
            Add-Type -Path $outputAssemblyItem
        }
        else {
            $OutputPdbName = "$($outputAssemblyItem.BaseName).pdb"
            if ($SymbolPath -and (Test-Path -Path (Join-Path -Path $ClrPath -ChildPath $OutputPdbName))) {
                $null = Copy-Item -Path (Join-Path -Path $ClrPath -ChildPath $OutputPdbName) -Destination (Join-Path -Path $SymbolPath -ChildPath $OutputPdbName)
            }
        }
    }

    return $true
}

<#
.DESCRIPTION
  Helper function to validate and install the required package dependencies. Also prepares the source code for compilation.
 
.PARAMETER Path
  All *.Code.ps1 C# files to compile.
 
.PARAMETER OutputDirectory
  Full Path to output directory.
 
.PARAMETER OutputAssemblyName
  Optional assembly file name.
 
.PARAMETER AllUsers
  User has specified to install package dependencies to global location.
 
.PARAMETER BootstrapConsent
  User has consented to bootstrap dependencies.
 
.PARAMETER TestBuild
  Build binaries for testing (disable compiler optimizations, enable full debug information).
 
.PARAMETER SymbolPath
  Path to store PDB file and matching source file.
 
.PARAMETER PackageDependencies
  Map of package dependencies to add as referenced assemblies but don't exist on disk.
 
.PARAMETER PreprocessorDirectives
  Preprocessor directives to add to the top of the combined source code file.
#>

function Add-PSSwaggerClientTypeHelper {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string[]]
        $Path,

        [Parameter(Mandatory = $false)]
        [AllowEmptyString()]
        [string]
        $OutputDirectory,

        [Parameter(Mandatory = $false)]
        [AllowEmptyString()]
        [string]
        $OutputAssemblyName,

        [Parameter(Mandatory = $false)]
        [switch]
        $AllUsers,

        [Parameter(Mandatory = $false)]
        [switch]
        $BootstrapConsent,

        [Parameter(Mandatory = $false)]
        [switch]
        $TestBuild,

        [Parameter(Mandatory = $false)]
        [string]
        $SymbolPath,

        [Parameter(Mandatory = $false)]
        [hashtable]
        $PackageDependencies,

        [Parameter(Mandatory = $false)]
        [string[]]
        $PreprocessorDirectives
    )

    $resultObj = @{
        # Full path to resolved package reference assemblies
        ResolvedPackageReferences = @()

        # The expected output assembly full path
        OutputAssembly            = $null

        # The actual source to be emitted
        SourceCode                = $null

        # The file name the returned params expect to exist, if required
        SourceCodeFilePath        = $null
    }

    if (-not $OutputDirectory -or -not $SymbolPath) {
        $TempOutputPath = Join-Path -Path (Get-XDGDirectory -DirectoryType Cache) -ChildPath ([Guid]::NewGuid().Guid)
        $null = New-Item -Path $TempOutputPath -ItemType Directory -Force
    }

    if (-not $SymbolPath) {
        $SymbolPath = $TempOutputPath
    }

    if (-not $OutputDirectory) {
        $OutputDirectory = $TempOutputPath
    }
    elseif (-not (Test-Path -Path $OutputDirectory -PathType Container)) {
        $null = New-Item -Path $OutputDirectory -ItemType Directory -Force
    }

    if (-not $OutputAssemblyName) {
        $OutputAssemblyName = [Guid]::NewGuid().Guid + '.dll'
    }

    # Resolve package dependencies
    if ($PackageDependencies) {
        foreach ($entry in ($PackageDependencies.GetEnumerator() | Sort-Object { $_.Value.LoadOrder })) {
            $reference = $entry.Value
            $resolvedRef = Get-PSSwaggerDependency -PackageName $reference.PackageName `
                -RequiredVersion $reference.RequiredVersion `
                -References $reference.References `
                -Framework $reference.Framework `
                -AllUsers:$AllUsers `
                -Install `
                -BootstrapConsent:$BootstrapConsent
            $resultObj['ResolvedPackageReferences'] += $resolvedRef

            # Copy package references to OutputDirectory
            $null = Copy-Item -Path $resolvedRef -Destination (Join-Path -Path $OutputDirectory -ChildPath (Split-Path -Path $resolvedRef -Leaf)) -Force
            Add-Type -Path $resolvedRef -ErrorAction Ignore
        }
    }

    # Combine the possibly authenticode-signed *.Code.ps1 files into a single file, adding preprocessor directives to the beginning if specified
    $srcContent = @()
    $srcContent += $Path | ForEach-Object { "// File $_"; Remove-AuthenticodeSignatureBlock -Path $_ }
    if ($PreprocessorDirectives) {
        foreach ($preprocessorDirective in $PreprocessorDirectives) {
            $srcContent = , $preprocessorDirective + $srcContent
        }
    }

    $oneSrc = $srcContent -join "`n"
    $resultObj['SourceCode'] = $oneSrc

    $OutputAssemblyBaseName = [System.IO.Path]::GetFileNameWithoutExtension("$OutputAssemblyName")
    $SourceCodeFilePath = Join-Path -Path $SymbolPath -ChildPath "Generated.$OutputAssemblyBaseName.cs"
    $resultObj['SourceCodeFilePath'] = $SourceCodeFilePath
    Out-File -InputObject $oneSrc -FilePath $SourceCodeFilePath

    $resultObj['OutputAssembly'] = Join-Path -Path $OutputDirectory -ChildPath $OutputAssemblyName

    return $resultObj
}

function Get-AddTypeParameters {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]
        $SourceCodeFilePath,

        [Parameter(Mandatory = $false)]
        [string[]]
        $ReferencedAssemblies,

        [Parameter(Mandatory = $false)]
        [ValidateSet("ConsoleApplication", "Library")]
        [string]
        $OutputType = 'Library',

        [Parameter(Mandatory = $false)]
        [switch]
        $TestBuild,

        [Parameter(Mandatory = $false)]
        [string]
        $OutputAssembly
    )

    $AddTypeParams = @{
        WarningAction = 'Ignore'
    }

    if (-not (Get-OperatingSystemInfo).IsCore) {
        $AddTypeParams['Path'] = $SourceCodeFilePath
        $compilerParameters = New-Object -TypeName System.CodeDom.Compiler.CompilerParameters
        $compilerParameters.WarningLevel = 1
        $compilerParameters.CompilerOptions = '/debug:full'
        if ($TestBuild) {
            $compilerParameters.IncludeDebugInformation = $true
        }
        else {
            $compilerParameters.CompilerOptions += ' /optimize+'
        }

        if ($OutputType -eq 'ConsoleApplication') {
            $compilerParameters.GenerateExecutable = $true
        }

        $ReferencedAssemblies | ForEach-Object {
            $null = $compilerParameters.ReferencedAssemblies.Add($_)
        }
        $AddTypeParams['CompilerParameters'] = $compilerParameters
    }
    else {
        $AddTypeParams['TypeDefinition'] = Get-Content -Path $SourceCodeFilePath -Raw
        $AddTypeParams['ReferencedAssemblies'] = $ReferencedAssemblies
        $AddTypeParams['OutputType'] = $OutputType
        $AddTypeParams['Language'] = 'CSharp'
    }

    if ($OutputAssembly) {
        if ($AddTypeParams.ContainsKey('CompilerParameters')) {
            $AddTypeParams['CompilerParameters'].OutputAssembly = $OutputAssembly
        }
        else {
            $AddTypeParams['OutputAssembly'] = $OutputAssembly
        }
    }
    else {
        if ($AddTypeParams.ContainsKey('CompilerParameters')) {
            $AddTypeParams['CompilerParameters'].GenerateInMemory = $true
        }
    }

    return $AddTypeParams
}
function Get-CscParameters {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]
        $SourceCodeFilePath,

        [Parameter(Mandatory = $false)]
        [ValidateSet('Exe', 'Library')]
        [string]
        $TargetType = 'Library',

        [Parameter(Mandatory = $false)]
        [string[]]
        $ReferencedAssemblies,

        [Parameter(Mandatory = $false)]
        [string[]]
        $ConditionalCompilationSymbol,

        [Parameter(Mandatory = $false)]
        [switch]
        $TestBuild,

        [Parameter(Mandatory = $false)]
        [string]
        $OutputAssembly
    )

    $CscParameter = @(
        $SourceCodeFilePath
        '/nologo',
        '/checked',
        '/warn:1',
        '/debug:full',
        '/platform:anycpu',
        "/target:$TargetType"
    )

    $ReferencedAssemblies | ForEach-Object { $CscParameter += "/reference:$_" }
    if (-not $TestBuild) { $CscParameter += '/optimize+' }
    if ($OutputAssembly) { $CscParameter += "/out:$OutputAssembly" }
    if ($ConditionalCompilationSymbol) {
        $ConditionalCompilationSymbol | ForEach-Object { $CscParameter += "/define:$_" }
    }

    return $CscParameter
}

<#
.DESCRIPTION
  Manually initialize PSSwagger's external dependencies. By default, initializes dependencies only for the current CLR. Use this function with -AcceptBootstrap for silent execution scenarios.
 
.PARAMETER AllUsers
  Install dependencies in PSSwagger's global package cache.
 
.PARAMETER Azure
  Additionally install dependencies for Microsoft Azure modules.
 
.PARAMETER AcceptBootstrap
  Automatically consent to downloading missing packages. If not specified, an interactive prompt will be appear.
 
.PARAMETER AllFrameworks
  Initialize dependencies for all frameworks.
#>

function Initialize-PSSwaggerDependencies {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        [switch]
        $AllUsers,

        [Parameter(Mandatory=$false)]
        [switch]
        $Azure,

        [Parameter(Mandatory=$false)]
        [switch]
        $AcceptBootstrap,

        [Parameter(Mandatory=$false)]
        [switch]
        $AllFrameworks
    )

    if ($AllFrameworks) {
        $framework = @('netstandard1', 'net4')
        $clr = 'fullclr'
    } else {
        $framework = if ((Get-OperatingSystemInfo).IsCore) { 'netstandard1' } else { 'net4' }
        $clr = 'coreclr'
    }

    $null = Initialize-PSSwaggerUtilities
}

<#
.DESCRIPTION
  Gets PSSwagger external dependencies.
 
.PARAMETER Framework
  Framework of package dependencies.
 
.PARAMETER Azure
  Additionally get PSSwagger dependencies for Azure module generation.
 
.PARAMETER RequiredVersionMap
  Optionally specifies custom required versions of packages.
#>

function Get-PSSwaggerExternalDependencies {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [AllowEmptyString()]
        [string]
        $Framework,

        [Parameter(Mandatory=$false)]
        [switch]
        $Azure,

        [Parameter(Mandatory=$false)]
        [hashtable]
        $RequiredVersionMap
    )

    $dependencies = @{}
    $dependencies['Newtonsoft.Json'] = @{
                                            PackageName = 'Newtonsoft.Json'
                                            References = @('Newtonsoft.Json.dll')
                                            Framework = $Framework
                                            RequiredVersion = if ($Framework.Contains('standard')) { '9.0.1' } else { '6.0.8' }
                                            LoadOrder = 0
                                        }
    $dependencies['Microsoft.Rest.ClientRuntime'] = @{
                                                         PackageName = 'Microsoft.Rest.ClientRuntime'
                                                         References = @('Microsoft.Rest.ClientRuntime.dll')
                                                         Framework = $Framework
                                                         RequiredVersion = '2.3.4'
                                                         LoadOrder = 1
                                                     }

    if ($Azure) {
        $dependencies['Microsoft.Rest.ClientRuntime.Azure'] = @{
                                                                   PackageName = 'Microsoft.Rest.ClientRuntime.Azure'
                                                                   References = @('Microsoft.Rest.ClientRuntime.Azure.dll')
                                                                   Framework = $Framework
                                                                   RequiredVersion = '3.3.4'
                                                                   LoadOrder = 2
                                                               }
    }

    if ($RequiredVersionMap) {
        foreach ($requiredVersionEntry in $RequiredVersionMap.GetEnumerator()) {
            if ($requiredVersionEntry.Value -and $dependencies.ContainsKey($requiredVersionEntry.Name)) {
                $dependencies[$requiredVersionEntry.Name].RequiredVersion = $requiredVersionEntry.Value
            }
        }
    }

    return $dependencies
}

<#
.DESCRIPTION
  Find PSSwagger external reference assemblies, optionally installing missing packages.
 
.PARAMETER PackageName
  Name of NuGet package where external reference assemblies reside.
 
.PARAMETER RequiredVersion
  Optionally specifies required version of NuGet package.
 
.PARAMETER References
  Array of reference assembly names.
 
.PARAMETER Framework
  Framework of reference assemblies to find.
 
.PARAMETER AllUsers
  Install missing packages for all users.
 
.PARAMETER Install
  Install missing packages.
 
.PARAMETER BootstrapConsent
  User has consented to downloading missing packages.
#>

function Get-PSSwaggerDependency {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        $PackageName,

        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $RequiredVersion,

        [Parameter(Mandatory=$true)]
        [string[]]
        $References,

        [Parameter(Mandatory=$true)]
        [string]
        $Framework,

        [Parameter(Mandatory=$false)]
        [switch]
        $AllUsers,

        [Parameter(Mandatory=$false)]
        [switch]
        $Install,

        [Parameter(Mandatory=$false)]
        [switch]
        $BootstrapConsent
    )

    $package = Get-PSSwaggerDependencyPackage -PackageName $PackageName -RequiredVersion $RequiredVersion -AllUsers:$AllUsers -Install:$Install -BootstrapConsent:$BootstrapConsent
    if ($package) {
        $allPaths = @()
        foreach ($ref in $References) {
            # The following is the expected path for NuGet packages
            $paths = Get-ChildItem -Path (Join-Path -Path $package.Location -ChildPath 'lib' | Join-Path -ChildPath "$Framework*") -Directory | Sort-Object -Property Name -Descending
            if ($paths) {
                foreach ($p in $paths) {
                    $path = Join-Path -Path $p -ChildPath $ref
                    if (Test-Path -Path $path) {
                        break;
                    }
                }
            } else {
                # In case the specified framework isn't found, the backup case is to use the net45 version
                $path = Join-Path -Path $package.Location -ChildPath 'lib' `
                            | Join-Path -ChildPath 'net45' `
                                | Join-Path -ChildPath $ref
            }

            $allPaths += $path
        }

        return $allPaths
    } else {
        if ($Install) {
            throw ($LocalizedData.FailedToInstallNuGetPackage -f ($PackageName))
        }

        return $null
    }
}

<#
.DESCRIPTION
  Finds the package in which a PSSwagger external reference assembly resides, optionally installing.
 
.PARAMETER PackageName
  Name of NuGet package where external reference assemblies reside.
 
.PARAMETER RequiredVersion
  Optionally specifies required version of NuGet package.
 
.PARAMETER AllUsers
  Install missing packages for all users.
 
.PARAMETER Install
  Install missing packages.
 
.PARAMETER BootstrapConsent
  User has consented to downloading missing packages.
#>

function Get-PSSwaggerDependencyPackage {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $PackageName,

        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $RequiredVersion,

        [Parameter(Mandatory=$false)]
        [switch]
        $AllUsers,

        [Parameter(Mandatory=$false)]
        [switch]
        $Install,

        [Parameter(Mandatory=$false)]
        [switch]
        $BootstrapConsent
    )

    # Although PackageManagement has been removed, we should leave this level of indirection here for future support.
    Get-PSSwaggerDependencyPackageWithNuGetCli -PackageName $PackageName -RequiredVersion $RequiredVersion -Install:$Install -BootstrapConsent:$BootstrapConsent -AllUsers:$AllUsers
}

<#
.DESCRIPTION
  Finds the package in which a PSSwagger external reference assembly resides, optionally installing, using NuGet.exe.
 
.PARAMETER PackageName
  Name of NuGet package where external reference assemblies reside.
 
.PARAMETER RequiredVersion
  Optionally specifies required version of NuGet package.
 
.PARAMETER AllUsers
  Install missing packages for all users.
 
.PARAMETER Install
  Install missing packages.
 
.PARAMETER BootstrapConsent
  User has consented to downloading missing packages.
#>

function Get-PSSwaggerDependencyPackageWithNuGetCli {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $PackageName,

        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $RequiredVersion,

        [Parameter(Mandatory=$false)]
        [switch]
        $Install,

        [Parameter(Mandatory=$false)]
        [switch]
        $BootstrapConsent,

        [Parameter(Mandatory=$false)]
        [switch]
        $AllUsers
    )

    # Attempt to get the package from the local cache first, then the global cache
    $path = Get-LocalNugetPackagePath -PackageName $PackageName -RequiredVersion $RequiredVersion
    if (-not $path) {
        $path = Get-LocalNugetPackagePath -PackageName $PackageName -RequiredVersion $RequiredVersion -GlobalCache
    }

    if ($path) {
        $versionMatch = [Regex]::Match($path, "(.+?)($($PackageName.Replace('.','[.]'))[.])([0-9.]*).*")
        $packageProps = @{
            Name = $PackageName;
            Version = $versionMatch.Groups[3].Value;
            Location = $path
        }

        return New-Object -TypeName PSObject -Property $packageProps
    } else {
        return $null
    }
}

<#
.DESCRIPTION
  Get the expected path to the given NuGet package.
 
.PARAMETER PackageName
  Name of NuGet package to find.
 
.PARAMETER RequiredVersion
  Optionally specifies required version of NuGet package.
 
.PARAMETER GlobalCache
  Use the global package cache. When not specified, uses the local user package cache.
#>

function Get-LocalNugetPackagePath {
    param(
        [Parameter(Mandatory=$true)]
        [AllowEmptyString()]
        [string]
        $PackageName,

        [Parameter(Mandatory=$false)]
        [switch]
        $GlobalCache,

        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $RequiredVersion
    )

    $outputSubPath = $PackageName
    if ($RequiredVersion) {
        $outputSubPath += ".$RequiredVersion"
    }

    if (Test-Path -Path (Join-Path -Path (Get-PackageCache -GlobalCache:$GlobalCache) -ChildPath "$outputSubPath*")) {
        $path = (Get-ChildItem -Path (Join-Path -Path (Get-PackageCache -GlobalCache:$GlobalCache) -ChildPath "$outputSubPath*") | Select-Object -First 1 | ForEach-Object FullName)
        return $path
    }

    return ''
}

<#
.DESCRIPTION
  Gets the expected path to NuGet.exe. If NuGet.exe is in the path, just returns nuget.exe. Checks both the local and global path.
 
.PARAMETER SpecificPath
  Return only the specific (local or global, based on the value of -GlobalCache) path.
 
.PARAMETER GlobalCache
  Use the global package cache. When not specified, uses the local user package cache.
#>

function Get-NugetExePath {
    param(
        [Parameter(Mandatory=$false)]
        [switch]
        $SpecificPath,

        [Parameter(Mandatory=$false)]
        [switch]
        $GlobalCache
    )

    if ((Get-Command nuget.exe -ErrorAction Ignore)) {
        return "nuget.exe"
    }

    if ($SpecificPath) {
        return (Join-Path -Path (Get-PackageCache -GlobalCache:$GlobalCache) -ChildPath "nuget.exe")
    }

    $localCachePath = (Join-Path -Path (Get-PackageCache) -ChildPath "nuget.exe")
    if (-not (Test-Path -Path $localCachePath)) {
        $localCachePath = (Join-Path -Path (Get-PackageCache -GlobalCache) -ChildPath "nuget.exe")
    }

    return $localCachePath
}

<#
.DESCRIPTION
  Gets the location of the package cache. Creates the package cache folder if it doesn't already exist.
 
.PARAMETER GlobalCache
  Use the global package cache. When not specified, uses the local user package cache.
#>

function Get-PackageCache {
    param(
        [Parameter(Mandatory=$false)]
        [switch]
        $GlobalCache
    )

    $newPathCandidate = $false
    if ($null -eq $script:AppLocalPath) {
        $newPathCandidate = $true
        $script:ProgramDataPath = Microsoft.PowerShell.Management\Join-Path -Path (Get-XDGDirectory -DirectoryType Shared) -ChildPath 'PSSwagger'
        $script:AppLocalPath = Microsoft.PowerShell.Management\Join-Path -Path (Get-XDGDirectory -DirectoryType Data) -ChildPath 'PSSwagger'
    }

    if ($GlobalCache) {
        $cache = $script:ProgramDataPath
    } else {
        $cache = $script:AppLocalPath
    }

    if ($newPathCandidate -and (-not (Test-Path -Path $cache))) {
        $null = New-Item -Path $cache `
                         -ItemType Directory -Force `
                         -ErrorAction SilentlyContinue `
                         -WarningAction SilentlyContinue `
                         -Confirm:$false `
                         -WhatIf:$false
    }

    return $cache
}

<#
.DESCRIPTION
  Get a NuGet package source with location nuget.org/api/v2.
#>

function Get-NugetPackageSource
{
    Get-PackageSource -Provider NuGet `
                      -ForceBootstrap `
                      -Verbose:$false `
                      -Debug:$false |
        Where-Object { $_.Location -match 'nuget.org/api/v2' } |
            Select-Object -First 1 -ErrorAction Ignore |
                Foreach-Object {$_.Name}
}

<#
.DESCRIPTION
  Creates a temporary NuGet package source with given location.
 
.PARAMETER Location
  Location of NuGet package source. Defaults to 'https://nuget.org/api/v2'.
#>

function Register-NugetPackageSource
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        [string]
        $Location = 'https://nuget.org/api/v2'
    )

    $SourceName = "PSSwaggerNuGetSource_$([System.Guid]::NewGuid())"

    $params = @{
        Name = $SourceName
        Location = $Location
        ProviderName = 'NuGet'
        ForceBootstrap = $true
        Verbose = $false
        Debug = $false
        Confirm = $false
        WhatIf = $false
    }

    if(Register-PackageSource @params)
    {
        return $SourceName
    }
}

<#
.DESCRIPTION
  Get PowerShell Common parameter/preference values.
 
.PARAMETER CallerPSBoundParameters
  PSBoundParameters of the caller.
#>

function Get-PSCommonParameter
{
    param(
        [Parameter(Mandatory=$true)]
        $CallerPSBoundParameters
    )

    $VerbosePresent = $false
    if (-not $CallerPSBoundParameters.ContainsKey('Verbose'))
    {
        if($VerbosePreference -in 'Continue','Inquire')
        {
            $VerbosePresent = $true
        }
    }
    else
    {
        $VerbosePresent = $true
    }

    $DebugPresent = $false
    if (-not $CallerPSBoundParameters.ContainsKey('Debug'))
    {
        if($debugPreference -in 'Continue','Inquire')
        {
            $DebugPresent = $true
        }
    }
    else
    {
        $DebugPresent = $true
    }

    if(Test-Path variable:\errorActionPreference)
    {
        $errorAction = $errorActionPreference
    }
    else
    {
        $errorAction = 'Continue'
    }

    if ($CallerPSBoundParameters['ErrorAction'] -eq 'SilentlyContinue')
    {
        $errorAction = 'SilentlyContinue'
    }

    if($CallerPSBoundParameters['ErrorAction'] -eq 'Ignore')
    {
        $errorAction = 'SilentlyContinue'
    }

    if ($CallerPSBoundParameters['ErrorAction'] -eq 'Inquire')
    {
        $errorAction = 'Continue'
    }

    if(Test-Path variable:\warningPreference)
    {
        $warningAction = $warningPreference
    }
    else
    {
        $warningAction = 'Continue'
    }

    if ($CallerPSBoundParameters['WarningAction'] -in 'SilentlyContinue','Ignore')
    {
        $warningAction = 'SilentlyContinue'
    }

    if ($CallerPSBoundParameters['WarningAction'] -eq 'Inquire')
    {
        $warningAction = 'Continue'
    }

    return @{
        Verbose = $VerbosePresent
        Debug = $DebugPresent
        WarningAction = $warningAction
        ErrorAction = $errorAction
    }
}

<#
.DESCRIPTION
  Tests if current PowerShell session is considered downlevel.
#>

function Test-Downlevel {
    return ($PSVersionTable.PSVersion -lt '5.0.0')
}

<#
.DESCRIPTION
  Finds local MSI installations.
 
.PARAMETER Name
  Name of MSIs to find. Supports * wildcard.
 
.PARAMETER MaximumVersion
  Maximum version of MSIs to find.
#>

function Get-PSSwaggerMsi {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        $Name,

        [Parameter(Mandatory=$false)]
        [string]
        $MaximumVersion
    )

    if (Test-Downlevel) {
        return Get-MsiWithCim -Name $Name -MaximumVersion $MaximumVersion
    } else {
        return Get-MsiWithPackageManagement -Name $Name -MaximumVersion $MaximumVersion
    }
}

<#
.DESCRIPTION
  Finds local MSI installations using WMI.
 
.PARAMETER Name
  Name of MSIs to find. Supports * wildcard.
 
.PARAMETER MaximumVersion
  Maximum version of MSIs to find.
#>

function Get-MsiWithCim {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        $Name,

        [Parameter(Mandatory=$false)]
        [string]
        $MaximumVersion
    )

    $wqlNameFilter = $Name.Replace('*', '%')
    $filter = "Name like '$wqlNameFilter'"
    if ($MaximumVersion) {
        $filter += " AND Version <= '$MaximumVersion'"
    }

    $products = Get-CimInstance -ClassName Win32_Product -Filter $filter
    $returnObjects = @()
    $products | ForEach-Object {
        $objectProps = @{
            'Name'=$_.Name;
            'Version'=$_.Version
        }

        $returnObjects += (New-Object -TypeName PSObject -Prop $objectProps)
    }

    return $returnObjects
}

<#
.DESCRIPTION
  Finds local MSI installations using PackageManagement.
 
.PARAMETER Name
  Name of MSIs to find. Supports * wildcard.
 
.PARAMETER MaximumVersion
  Maximum version of MSIs to find.
#>

function Get-MsiWithPackageManagement {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        $Name,

        [Parameter(Mandatory=$false)]
        [string]
        $MaximumVersion
    )

    $products = Get-Package -Name $Name `
                            -MaximumVersion $MaximumVersion `
                            -ProviderName msi `
                            -Verbose:$false `
                            -Debug:$false
    $returnObjects = @()
    $products | ForEach-Object {
        $objectProps = @{
            'Name'=$_.Name;
            'Version'=$_.Version
        }

        $returnObjects += (New-Object -TypeName PSObject -Prop $objectProps)
    }

    return $returnObjects
}
#endregion

<#
.DESCRIPTION
  Initialize the PSSwagger utilities assembly, compiling if it isn't already found.
#>

function Initialize-PSSwaggerUtilities {
    if (Get-Command Start-PSSwaggerJob -ErrorAction Ignore) {
        return;
    }

    $PSSwaggerJobAssemblyPath = $null
    $PSSwaggerJobAssemblyUnsafePath = $null
    $useExternalDependencies = $true
    if ((Get-OperatingSystemInfo).IsCore) {
        $externalReferencesFramework = 'netstandard1.'
        $clr = 'coreclr'
    } else {
        $externalReferencesFramework = 'net4'
        $clr = 'fullclr'
    }

    if(("$($LocalizedData.CSharpNamespace).PSSwaggerJob" -as [Type]) -and
    (Test-Path -Path ("$($LocalizedData.CSharpNamespace).PSSwaggerJob" -as [Type]).Assembly.Location -PathType Leaf))
    {
        # This is for re-import scenario.
        $PSSwaggerJobAssemblyPath = ("$($LocalizedData.CSharpNamespace).PSSwaggerJob" -as [Type]).Assembly.Location
        if(("$($LocalizedData.CSharpNamespace).PSBasicAuthenticationEx" -as [Type]) -and
        (Test-Path -Path ("$($LocalizedData.CSharpNamespace).PSBasicAuthenticationEx" -as [Type]).Assembly.Location -PathType Leaf))
        {
            $PSSwaggerJobAssemblyUnsafePath = ("$($LocalizedData.CSharpNamespace).PSBasicAuthenticationEx" -as [Type]).Assembly.Location
        }
    }
    else
    {
        # Compile the regular utilities
        $coreCodeFileName = 'PSSwaggerNetUtilities.Core.Code.ps1'
        $codeFileName = 'PSSwaggerNetUtilities.Code.ps1'
        $PSSwaggerJobFilePath = Join-Path -Path $PSScriptRoot -ChildPath $codeFileName
        $PSSwaggerCoreJobFilePath = Join-Path -Path $PSScriptRoot -ChildPath $coreCodeFileName
        if(Test-Path -Path $PSSwaggerCoreJobFilePath -PathType Leaf)
        {
            $useExternalDependencies = $false
            if ((Get-OperatingSystemInfo).IsWindows) {
                $sig = Get-AuthenticodeSignature -FilePath $PSSwaggerCoreJobFilePath
                if (('Valid' -ne $sig.Status) -and ('NotSigned' -ne $sig.Status)) {
                    throw ($LocalizedData.CodeFileSignatureValidationFailed -f ($coreCodeFileName))
                }
            }

            $PSSwaggerJobSourceString = Remove-AuthenticodeSignatureBlock -Path $PSSwaggerCoreJobFilePath
            if (Test-Path -Path $PSSwaggerJobFilePath -PathType Leaf) {
                $useExternalDependencies = $true
                if ((Get-OperatingSystemInfo).IsWindows) {
                    $sig = Get-AuthenticodeSignature -FilePath $PSSwaggerJobFilePath
                    if (('Valid' -ne $sig.Status) -and ('NotSigned' -ne $sig.Status)) {
                        throw ($LocalizedData.CodeFileSignatureValidationFailed -f ($codeFileName))
                    }
                }

                $PSSwaggerJobSourceString = $PSSwaggerJobSourceString + (Remove-AuthenticodeSignatureBlock -Path $PSSwaggerJobFilePath)
            }

            $PSSwaggerJobSourceString = $PSSwaggerJobSourceString | Out-String
            $PSSwaggerJobSourceString = $ExecutionContext.InvokeCommand.ExpandString($PSSwaggerJobSourceString)
            Add-Type -AssemblyName System.Net.Http
            $RequiredAssemblies = @(
                [System.Management.Automation.PSCmdlet].Assembly.FullName,
                [System.ComponentModel.AsyncCompletedEventArgs].Assembly.FullName,
                [System.Linq.Enumerable].Assembly.FullName,
                [System.Collections.StructuralComparisons].Assembly.FullName,
                [System.Net.Http.HttpRequestMessage].Assembly.FullName
            )

            if ((Get-OperatingSystemInfo).IsCore) {
                # On core CLR, these "additional" assemblies are required due to type redirection
                $RequiredAssemblies += 'System.Threading.Tasks'
                $RequiredAssemblies += 'System.Threading'
            }

            $TempPath = Join-Path -Path (Get-XDGDirectory -DirectoryType Data) -ChildPath ([System.IO.Path]::GetRandomFileName())
            $null = New-Item -Path $TempPath -ItemType Directory -Force

            # Compile the main utility assembly
            $PSSwaggerJobAssemblyPath = Join-Path -Path $TempPath -ChildPath "$($LocalizedData.CSharpNamespace).Utility.dll"

            Add-Type -ReferencedAssemblies $RequiredAssemblies `
                    -TypeDefinition $PSSwaggerJobSourceString `
                    -OutputAssembly $PSSwaggerJobAssemblyPath `
                    -Language CSharp `
                    -WarningAction Ignore `
                    -IgnoreWarnings
        }
    }

    if(("$($LocalizedData.CSharpNamespace).PSBasicAuthenticationEx" -as [Type]) -and
    (Test-Path -Path ("$($LocalizedData.CSharpNamespace).PSBasicAuthenticationEx" -as [Type]).Assembly.Location -PathType Leaf))
    {
        # This is for re-import scenario.
        $PSSwaggerJobAssemblyUnsafePath = ("$($LocalizedData.CSharpNamespace).PSBasicAuthenticationEx" -as [Type]).Assembly.Location
    }
    elseif (-not (Get-OperatingSystemInfo).IsCore)
    {
        # Compile the utilities requiring the /unsafe flag (only for Full CLR because of no Core CLR CompilerParameters support)
        # If we move to dotnet CLI, we can remove this restriction
        $codeFileName = 'PSSwaggerNetUtilities.Unsafe.Code.ps1'
        $PSSwaggerJobFilePath = Join-Path -Path $PSScriptRoot -ChildPath $codeFileName
        if(Test-Path -Path $PSSwaggerJobFilePath -PathType Leaf) {
            if ((Get-OperatingSystemInfo).IsWindows) {
                $sig = Get-AuthenticodeSignature -FilePath $PSSwaggerJobFilePath
                if (('Valid' -ne $sig.Status) -and ('NotSigned' -ne $sig.Status)) {
                    throw ($LocalizedData.CodeFileSignatureValidationFailed -f ($codeFileName))
                }
            }

            $PSSwaggerJobSourceString = Remove-AuthenticodeSignatureBlock -Path $PSSwaggerJobFilePath | Out-String
            $PSSwaggerJobSourceString = $ExecutionContext.InvokeCommand.ExpandString($PSSwaggerJobSourceString)
            Add-Type -AssemblyName System.Net.Http
            $compilerParameters = New-Object -TypeName System.CodeDom.Compiler.CompilerParameters
            $compilerParameters.CompilerOptions = '/debug:full /optimize+ /unsafe'

            $compilerParameters.ReferencedAssemblies.Add([System.ComponentModel.AsyncCompletedEventArgs].Assembly.Location)
            $compilerParameters.ReferencedAssemblies.Add([System.Linq.Enumerable].Assembly.Location)
            $compilerParameters.ReferencedAssemblies.Add([System.Collections.StructuralComparisons].Assembly.Location)
            $compilerParameters.ReferencedAssemblies.Add([System.Net.Http.HttpRequestMessage].Assembly.Location)

            $externalReferencesFramework = 'net4'
            $clr = 'fullclr'

            $TempPath = Join-Path -Path (Get-XDGDirectory -DirectoryType Data) -ChildPath ([System.IO.Path]::GetRandomFileName())
            $null = New-Item -Path $TempPath -ItemType Directory -Force

            # Compile the main utility assembly
            $PSSwaggerJobAssemblyUnsafePath = Join-Path -Path $TempPath -ChildPath 'Microsoft.PowerShell.PSSwagger.Utility.Unsafe.dll'
            $compilerParameters.OutputAssembly = $PSSwaggerJobAssemblyUnsafePath

            Add-Type -TypeDefinition $PSSwaggerJobSourceString `
                     -WarningAction Ignore `
                     -CompilerParameters $compilerParameters
        }
    }

    if(Test-Path -LiteralPath $PSSwaggerJobAssemblyPath -PathType Leaf)
    {
        if ($useExternalDependencies) {
            $externalReferences = Get-PSSwaggerExternalDependencies -Framework $externalReferencesFramework
            foreach ($entry in ($externalReferences.GetEnumerator() | Sort-Object { $_.Value.LoadOrder })) {
                $reference = $entry.Value
                $extraRefs = Get-PSSwaggerDependency -PackageName $reference.PackageName `
                                                            -References $reference.References `
                                                            -Framework $reference.Framework `
                                                            -RequiredVersion $reference.RequiredVersion
                if ($extraRefs) {
                    foreach ($extraRef in $extraRefs) {
                        Add-Type -Path $extraRef
                    }
                }
            }
        }

        # It is required to import the generated assembly into the module scope
        # to register the PSSwaggerJobSourceAdapter with the PowerShell Job infrastructure.
        Import-Module -Name $PSSwaggerJobAssemblyPath -Verbose:$false
    }

    if ((-not (Get-OperatingSystemInfo).IsCore) -and $PSSwaggerJobAssemblyUnsafePath) {
        $externalReferences = Get-PSSwaggerExternalDependencies -Framework $externalReferencesFramework
        foreach ($entry in ($externalReferences.GetEnumerator() | Sort-Object { $_.Value.LoadOrder })) {
            $reference = $entry.Value
            $extraRefs = Get-PSSwaggerDependency -PackageName $reference.PackageName `
                                                        -References $reference.References `
                                                        -Framework $reference.Framework `
                                                        -RequiredVersion $reference.RequiredVersion
            if ($extraRefs) {
                foreach ($extraRef in $extraRefs) {
                    Add-Type -Path $extraRef
                }
            }
        }

        if(Test-Path -LiteralPath $PSSwaggerJobAssemblyUnsafePath -PathType Leaf)
        {
            Add-Type -Path $PSSwaggerJobAssemblyUnsafePath
        }
    }

    if(-not ("$($LocalizedData.CSharpNamespace).PSSwaggerJob" -as [Type]))
    {
        Write-Error -Message ($LocalizedData.FailedToAddType -f ('PSSwaggerJob'))
    }

    if((-not (Get-OperatingSystemInfo).IsCore) -and $PSSwaggerJobAssemblyUnsafePath -and (-not ("$($LocalizedData.CSharpNamespace).PSBasicAuthenticationEx" -as [Type])))
    {
        Write-Error -Message ($LocalizedData.FailedToAddType -f ('PSBasicAuthenticationEx'))
    }

    Import-Module -Name (Join-Path -Path "$PSScriptRoot" -ChildPath 'PSSwaggerClientTracing.psm1') -Verbose:$false
    Import-Module -Name (Join-Path -Path "$PSScriptRoot" -ChildPath 'PSSwaggerServiceCredentialsHelpers.psm1') -Verbose:$false
}

function New-PSSwaggerClientTracing {
    [CmdletBinding()]
    param()

    Initialize-PSSwaggerDependencies
    return New-PSSwaggerClientTracingInternal
}

function Register-PSSwaggerClientTracing {
    [CmdletBinding()]
    param(
        [object]$TracerObject
    )

    Initialize-PSSwaggerDependencies
    Register-PSSwaggerClientTracingInternal -TracerObject $TracerObject
}

function Unregister-PSSwaggerClientTracing {
    [CmdletBinding()]
    param(
        [object]$TracerObject
    )

    Initialize-PSSwaggerDependencies
    Unregister-PSSwaggerClientTracingInternal -TracerObject $TracerObject
}

function Get-AutoRestCredential {
    [CmdletBinding(DefaultParameterSetName='NoAuth')]
    param(
        [Parameter(Mandatory=$true, ParameterSetName='BasicAuth')]
        [PSCredential]
        $Credential,

        [Parameter(Mandatory=$true, ParameterSetName='ApiKeyAuth')]
        [string]
        $APIKey,

        [Parameter(Mandatory=$false, ParameterSetName='ApiKeyAuth')]
        [string]
        $Location,

        [Parameter(Mandatory=$false, ParameterSetName='ApiKeyAuth')]
        [string]
        $Name
    )

    if ('BasicAuth' -eq $PsCmdlet.ParameterSetName) {
        Get-BasicAuthCredentialInternal -Credential $Credential
    } elseif ('ApiKeyAuth' -eq $PsCmdlet.ParameterSetName) {
        Get-ApiKeyCredentialInternal -APIKey $APIKey -Location $Location -Name $Name
    } else {
        Get-EmptyAuthCredentialInternal
    }
}

# SIG # Begin signature block
# MIIkXAYJKoZIhvcNAQcCoIIkTTCCJEkCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDBQ8/5OuvHS4E1
# Db9aNBY4DcJ0w8fEi9M4naTyqxRhzKCCDYEwggX/MIID56ADAgECAhMzAAABA14l
# HJkfox64AAAAAAEDMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMTgwNzEyMjAwODQ4WhcNMTkwNzI2MjAwODQ4WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDRlHY25oarNv5p+UZ8i4hQy5Bwf7BVqSQdfjnnBZ8PrHuXss5zCvvUmyRcFrU5
# 3Rt+M2wR/Dsm85iqXVNrqsPsE7jS789Xf8xly69NLjKxVitONAeJ/mkhvT5E+94S
# nYW/fHaGfXKxdpth5opkTEbOttU6jHeTd2chnLZaBl5HhvU80QnKDT3NsumhUHjR
# hIjiATwi/K+WCMxdmcDt66VamJL1yEBOanOv3uN0etNfRpe84mcod5mswQ4xFo8A
# DwH+S15UD8rEZT8K46NG2/YsAzoZvmgFFpzmfzS/p4eNZTkmyWPU78XdvSX+/Sj0
# NIZ5rCrVXzCRO+QUauuxygQjAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUR77Ay+GmP/1l1jjyA123r3f3QP8w
# UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1
# ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDM3OTY1MB8GA1UdIwQYMBaAFEhu
# ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu
# bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w
# Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx
# MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAn/XJ
# Uw0/DSbsokTYDdGfY5YGSz8eXMUzo6TDbK8fwAG662XsnjMQD6esW9S9kGEX5zHn
# wya0rPUn00iThoj+EjWRZCLRay07qCwVlCnSN5bmNf8MzsgGFhaeJLHiOfluDnjY
# DBu2KWAndjQkm925l3XLATutghIWIoCJFYS7mFAgsBcmhkmvzn1FFUM0ls+BXBgs
# 1JPyZ6vic8g9o838Mh5gHOmwGzD7LLsHLpaEk0UoVFzNlv2g24HYtjDKQ7HzSMCy
# RhxdXnYqWJ/U7vL0+khMtWGLsIxB6aq4nZD0/2pCD7k+6Q7slPyNgLt44yOneFuy
# bR/5WcF9ttE5yXnggxxgCto9sNHtNr9FB+kbNm7lPTsFA6fUpyUSj+Z2oxOzRVpD
# MYLa2ISuubAfdfX2HX1RETcn6LU1hHH3V6qu+olxyZjSnlpkdr6Mw30VapHxFPTy
# 2TUxuNty+rR1yIibar+YRcdmstf/zpKQdeTr5obSyBvbJ8BblW9Jb1hdaSreU0v4
# 6Mp79mwV+QMZDxGFqk+av6pX3WDG9XEg9FGomsrp0es0Rz11+iLsVT9qGTlrEOla
# P470I3gwsvKmOMs1jaqYWSRAuDpnpAdfoP7YO0kT+wzh7Qttg1DO8H8+4NkI6Iwh
# SkHC3uuOW+4Dwx1ubuZUNWZncnwa6lL2IsRyP64wggd6MIIFYqADAgECAgphDpDS
# AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0
# ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla
# MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT
# H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG
# OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S
# 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz
# y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7
# 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u
# M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33
# X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl
# XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP
# 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB
# l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF
# RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM
# CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ
# BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud
# DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO
# 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0
# LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
# Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p
# Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
# Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB
# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw
# cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA
# XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY
# 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj
# 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd
# d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ
# Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf
# wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ
# aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j
# NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B
# xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96
# eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7
# r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I
# RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIWMTCCFi0CAQEwgZUwfjELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z
# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAQNeJRyZH6MeuAAAAAABAzAN
# BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgKPt38weh
# EMliVicoFf4CrhrCEkNmVdIyEXx6yPGPpJ4wQgYKKwYBBAGCNwIBDDE0MDKgFIAS
# AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN
# BgkqhkiG9w0BAQEFAASCAQAnR53BFljWzeIPwpdoy5LpCfBbR2oeL1cpa9tzGJ6a
# 1/sSEiuA7Z2TgnB1DDuikNH73JL4DN+Jvs+FkXt+Ok/JePFGnGJCy7CBT/jB+BuL
# OZS0OxkMLNGLQzHOBscP6Qv+6iG0PiBBojHSZ3n89cpHC6ABB4cu3zSEsjFAXZKy
# lSJq4Ub5TYIPFoSm3/682XoZ/wWY1agP1snsTLZgH4jx0gzew9hUaurNoUkA4Vnd
# ERz/isZ881UDmXMrGbj6IBvCWmIH3dZqc+XLrfOfu+mLUWN2fcNBGdvPriPPxEyz
# ybu0Fyk8wfpkQhCfnA/66SXbOr/nvjv6l7CbUUnA6tLToYITuzCCE7cGCisGAQQB
# gjcDAwExghOnMIITowYJKoZIhvcNAQcCoIITlDCCE5ACAQMxDzANBglghkgBZQME
# AgEFADCCAVgGCyqGSIb3DQEJEAEEoIIBRwSCAUMwggE/AgEBBgorBgEEAYRZCgMB
# MDEwDQYJYIZIAWUDBAIBBQAEIBiOIDngxdKbEcJ2gdVH6MobP8y8eO9+Zsth/h5L
# NbuCAgZclA/tWxkYEzIwMTkwMzI3MTg0ODA5LjgwMVowBwIBAYACAfSggdSkgdEw
# gc4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsT
# IE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFs
# ZXMgVFNTIEVTTjpCOEVDLTMwQTQtNzE0NDElMCMGA1UEAxMcTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgU2VydmljZaCCDyMwggZxMIIEWaADAgECAgphCYEqAAAAAAACMA0G
# CSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3Jp
# dHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3MDEyMTQ2NTVaMHwxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m
# dCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
# CgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3
# PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMw
# VyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FUsc+TTJLBxKZd0WETbijG
# GvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wGPmd/
# 9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4HLDpmc085y9Euqf03GS9
# pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB5jCCAeIwEAYJKwYBBAGCNxUB
# BAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvFM2hahW1VMBkGCSsGAQQBgjcU
# AgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8G
# A1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeG
# RWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jv
# b0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUH
# MAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2Vy
# QXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8EgZUwgZIwgY8GCSsGAQQBgjcu
# AzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL1BLSS9k
# b2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwA
# XwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0B
# AQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Prpsz1Mb7PBeKp/vpXbRkws8LF
# Zslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOMzPRgEop2zEBAQZvcXBf/XPle
# FzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCvOA8X9S95gWXZqbVr5MfO9sp6
# AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v/rbljjO7Yl+a21dA6fHOmWaQ
# jP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99lmqQeKZt0uGc+R38ONiU9Mal
# CpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1klD3ouOVd2onGqBooPiRa6YacR
# y5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQHm+98eEA3+cxB6STOvdlR3jo
# +KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30uIUBHoD7G4kqVDmyW9rIDVWZ
# eodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp25ayp0Kiyc8ZQU3ghvkqmqMR
# ZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HSxVXjad5XwdHeMMD9zOZN+w2/
# XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi62jbb01+P3nSISRIwggT1MIID
# 3aADAgECAhMzAAAAzDq9O3I4EQW6AAAAAADMMA0GCSqGSIb3DQEBCwUAMHwxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jv
# c29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTE4MDgyMzIwMjYyNVoXDTE5MTEy
# MzIwMjYyNVowgc4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# KTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYD
# VQQLEx1UaGFsZXMgVFNTIEVTTjpCOEVDLTMwQTQtNzE0NDElMCMGA1UEAxMcTWlj
# cm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCASIwDQYJKoZIhvcNAQEBBQADggEP
# ADCCAQoCggEBAMfQVaWKJhVrFd3wd5i7tfnMU0sGcTEnEmTqPS8j+nlRKLVotbrf
# HVvTuguDClWIc1+lnsw6gnz+mgJT5Y6VzIGpwaRYTMe3cJ9X//XOZBa7xuXu9A46
# HiO2T5roJBkJ9lIt268voSvXmjGQA913N1nWhsc6UE4VuOsP56iHutiHStJ2AgMY
# rDrpJEBI2KUVk/XCEbpiIaZyEn59sh7iMBIk1OJp3ISjQXt+AYjxgSoWaqzSvN/o
# j1RWu+v0gFeLRBldrFihFO9PvZ3HqSJ6s7ctmOZkYnfmNjOwheVmdHj3QnuebbeY
# 0hODFtVXYlvQU7Dw2SBQ6XEcnl6xYHLlIosCAwEAAaOCARswggEXMB0GA1UdDgQW
# BBStqU2mSsJlEE/X63seIZoxM0jrqTAfBgNVHSMEGDAWgBTVYzpcijGQ80N7fEYb
# xTNoWoVtVTBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5j
# b20vcGtpL2NybC9wcm9kdWN0cy9NaWNUaW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmww
# WgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29m
# dC5jb20vcGtpL2NlcnRzL01pY1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNV
# HRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IB
# AQA9XV1qguniZVE1UsPJHL/gEWBWEKeYcuZDunghCMGzq3Ap20k8qsRjKEwmLpwj
# QK4ErHhgZLujYCCRkxpAcHcqUrzfBQl6hMbLqJwJNRmFu/7H4MJAckl+4lImOUsJ
# RAjiheHl67fq5V+i8LMBg8LYNPKy4kCoTUvS/qgUhOrVnQCqtENJTDMxjmOeezO9
# kvqPtvIx76DSdKtg+PXoE/UgXc3xL6RBeNix76MdU8lLOqg4S1Gs9B5KyxZv8Ttf
# f1yTU/E2kMwOf8QnzWnq5NfaDZ18TUzlyacL47GHW3K53TWdWyt+xfhYGrk0KVcH
# ipz1p92Ae1Be5X7pSiJrLtjfoYIDsTCCApkCAQEwgf6hgdSkgdEwgc4xCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29m
# dCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVT
# TjpCOEVDLTMwQTQtNzE0NDElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg
# U2VydmljZaIlCgEBMAkGBSsOAwIaBQADFQBz2ocx/S77PGis5+hGlHNEh7+WTaCB
# 3jCB26SB2DCB1TELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO
# BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEp
# MCcGA1UECxMgTWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJzAlBgNV
# BAsTHm5DaXBoZXIgTlRTIEVTTjo0REU5LTBDNUUtM0UwOTErMCkGA1UEAxMiTWlj
# cm9zb2Z0IFRpbWUgU291cmNlIE1hc3RlciBDbG9jazANBgkqhkiG9w0BAQUFAAIF
# AOBFrRUwIhgPMjAxOTAzMjcwODA0MzdaGA8yMDE5MDMyODA4MDQzN1oweDA+Bgor
# BgEEAYRZCgQBMTAwLjAKAgUA4EWtFQIBADALAgEAAgMB26ECAf8wBwIBAAICGwcw
# CgIFAOBG/pUCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAaAKMAgC
# AQACAxbjYKEKMAgCAQACAwehIDANBgkqhkiG9w0BAQUFAAOCAQEAAqISY7ZaKL+T
# j12G/LPDpZoHfcXIJi6yXXSgxjp7s8/py9eov20Znr8GOvSt0B1KEL2ccM/MIVnM
# ccKMfaT+sXJwDmSgOAwj13ZT5XRyHOoAeiyczFZbXndOSpe8cjqQ1vjREBTnQkHB
# o3zBl4PJOx5O9gNLxjhbeSR+Flx/NFAlVIqoyZ95GxgklnTw1ZYhcSZ/E/TpIn/j
# wLEN8FjiIWrRTu3rYny4JYexs3+rB+VHv7cOpSqD7Z44YiEmgM+KvGfhMwPLUgn2
# QRqjiINFN5GAZjDqaxhBRGurkFfm/s5f3XOXy6PLZBl9vv0TPrEDujNERLE3pyUc
# DBKNVutNNzGCAvUwggLxAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX
# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAy
# MDEwAhMzAAAAzDq9O3I4EQW6AAAAAADMMA0GCWCGSAFlAwQCAQUAoIIBMjAaBgkq
# hkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEILCEtv1Db+AY
# AduhP6CB4+oVd2xgaMcFdN0xUBLqhG6LMIHiBgsqhkiG9w0BCRACDDGB0jCBzzCB
# zDCBsQQUc9qHMf0u+zxorOfoRpRzRIe/lk0wgZgwgYCkfjB8MQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGlt
# ZS1TdGFtcCBQQ0EgMjAxMAITMwAAAMw6vTtyOBEFugAAAAAAzDAWBBRT8Q2MGfN7
# FL2dQxdMt1t5ruVvdzANBgkqhkiG9w0BAQsFAASCAQAJbtJEy7j2/TjWfzuOTmrA
# /Nii8X2KT20bFtNBGP3THX8iOLtAF3GU0Ab3CNOiZTq7f8BRq4XDfnqgtAHGn363
# ion0ttsK7BcVugfDZt233HZgxNA25m/0iOHdh/KMgS01Zzp5+Wa+Dw6npQLOG312
# Rvv7VJDSEaK3k+LkjIw1GHa9AnD3CJsV4ANUIkWuw0o2dVs9Dhh0gNiXOQI37o4M
# U7UewyiLwqiTQmemgxz4VTUEP48Liu1qrR1YwfUknQkqpVpPVE+GRyMw0QCLx2Ri
# WbrryAdPECQH5537Jbq7297RzpxyK8Yo008ePZV3/Vlpp33sfYX+VavBCXW8UFgK
# SIG # End signature block