PSSwagger.psm1

#########################################################################################
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# Licensed under the MIT license.
#
# PSSwagger Module
#
#########################################################################################
Microsoft.PowerShell.Core\Set-StrictMode -Version Latest

$SubScripts = @(
    'PSSwagger.Constants.ps1'
)
$SubScripts | ForEach-Object {. (Join-Path -Path $PSScriptRoot -ChildPath $_) -Force}

$SubModules = @(
    'SwaggerUtils.psm1',
    'Utilities.psm1',
    'Paths.psm1',
    'Definitions.psm1'
)

$SubModules | ForEach-Object {Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath $_) -Force -Scope Local -DisableNameChecking}

Microsoft.PowerShell.Utility\Import-LocalizedData  LocalizedData -filename PSSwagger.Resources.psd1

<#
.SYNOPSIS
    PowerShell command to generate the PowerShell commands for a given RESTful Web Services using Swagger/OpenAPI documents.
 
.DESCRIPTION
    PowerShell command to generate the PowerShell commands for a given RESTful Web Services using Swagger/OpenAPI documents.
 
.EXAMPLE
    PS> New-PSSwaggerModule -SpecificationUri 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-batch/2015-12-01/swagger/BatchManagement.json' -Path 'C:\GeneratedModules\' -Name 'AzBatchManagement' -UseAzureCsharpGenerator
    Generates a PS Module for the specified SpecificationUri.
 
.EXAMPLE
    PS> New-PSSwaggerModule -SpecificationPath 'C:\SwaggerSpecs\BatchManagement.json' -Path 'C:\GeneratedModules\' -Name 'AzBatchManagement' -UseAzureCsharpGenerator
    Generates a PS Module for the specified SpecificationPath.
 
.PARAMETER SpecificationPath
    Full Path to a Swagger based JSON spec.
 
.PARAMETER SpecificationUri
    Uri to a Swagger based JSON spec.
 
.PARAMETER Path
    Full Path to a file where the commands are exported to.
 
.PARAMETER Name
    Name of the module to be generated. A folder with this name will be created in the location specified by Path parameter.
 
.PARAMETER Version
    Version of the generated PowerShell module.
 
.PARAMETER DefaultCommandPrefix
    Prefix value to be prepended to cmdlet noun or to cmdlet name without verb.
 
.PARAMETER NoAssembly
    Switch to disable saving the precompiled module assembly and instead enable dynamic compilation.
 
.PARAMETER PowerShellCorePath
    Path to PowerShell.exe for PowerShell Core.
    Only required if PowerShell Core not installed via MSI in the default path.
 
.PARAMETER IncludeCoreFxAssembly
    Switch to additionally compile the module's binary component for Core CLR.
 
.PARAMETER InstallToolsForAllUsers
    User wants to install local tools for all users.
   
.PARAMETER TestBuild
    Switch to disable optimizations during build of full CLR binary component.
   
.PARAMETER SymbolPath
    Path to save the generated C# code and PDB file. Defaults to $Path\symbols.
 
.PARAMETER ConfirmBootstrap
    Automatically consent to downloading nuget.exe or NuGet packages as required.
 
.PARAMETER UseAzureCsharpGenerator
    Switch to specify whether AzureCsharp code generator is required. By default, this command uses CSharp code generator.
 
.INPUTS
 
.OUTPUTS
 
.NOTES
 
.LINK
 
#>

function New-PSSwaggerModule
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ParameterSetName = 'SwaggerPath')]
        [string] 
        $SpecificationPath,

        [Parameter(Mandatory = $true, ParameterSetName = 'SwaggerURI')]
        [Uri]
        $SpecificationUri,

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

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

        [Parameter(Mandatory = $false)]
        [Version]
        $Version = '0.0.1',

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

        [Parameter()]
        [switch]
        $UseAzureCsharpGenerator,

        [Parameter()]
        [switch]
        $NoAssembly,

        [Parameter()]
        [string]
        $PowerShellCorePath,

        [Parameter()]
        [switch]
        $IncludeCoreFxAssembly,

        [Parameter()]
        [switch]
        $InstallToolsForAllUsers,

        [Parameter()]
        [switch]
        $TestBuild,

        [Parameter()]
        [string]
        $SymbolPath,

        [Parameter()]
        [switch]
        $ConfirmBootstrap
    )

    if ($NoAssembly -and $IncludeCoreFxAssembly) {
        $message = $LocalizedData.ParameterSetNotAllowed -f ('IncludeCoreFxAssembly', 'NoAssembly')
        throw $message
        return
    }

    if ($NoAssembly -and $TestBuild) {
        $message = $LocalizedData.ParameterSetNotAllowed -f ('TestBuild', 'NoAssembly')
        throw $message
        return
    }

    if ($NoAssembly -and $PowerShellCorePath) {
        $message = $LocalizedData.ParameterSetNotAllowed -f ('PowerShellCorePath', 'NoAssembly')
        throw $message
        return
    }

    if ($NoAssembly -and $SymbolPath) {
        $message = $LocalizedData.ParameterSetNotAllowed -f ('SymbolPath', 'NoAssembly')
        throw $message
        return
    }
    
    $SwaggerSpecFilePaths = @()
    $AutoRestModeler = 'Swagger'
    
    if ($PSCmdlet.ParameterSetName -eq 'SwaggerURI')
    {
        # Ensure that if the URI is coming from github, it is getting the raw content
        if($SpecificationUri.Host -eq 'github.com'){
            $SpecificationUri = "https://raw.githubusercontent.com$($SpecificationUri.AbsolutePath.Replace('/blob/','/'))"
            $message = $LocalizedData.ConvertingSwaggerSpecToGithubContent -f ($SpecificationUri)
            Write-Verbose -Message $message -Verbose
        }

        $TempPath = Join-Path -Path (Get-XDGDirectory -DirectoryType Cache) -ChildPath (Get-Random)
        $null = New-Item -Path $TempPath -ItemType Directory -Force -Confirm:$false -WhatIf:$false

        $SwaggerFileName = Split-Path -Path $SpecificationUri -Leaf
        $SpecificationPath = Join-Path -Path $TempPath -ChildPath $SwaggerFileName

        $message = $LocalizedData.SwaggerSpecDownloadedTo -f ($SpecificationUri, $SpecificationPath)
        Write-Verbose -Message $message
        
        $ev = $null
        Invoke-WebRequest -Uri $SpecificationUri -OutFile $SpecificationPath -ErrorVariable ev
        if($ev) {
            return 
        }

        $jsonObject = ConvertFrom-Json -InputObject ((Get-Content -Path $SpecificationPath) -join [Environment]::NewLine) -ErrorAction Stop
        if((Get-Member -InputObject $jsonObject -Name 'Documents') -and ($jsonObject.Documents.Count))
        {
            $AutoRestModeler = 'CompositeSwagger'
            $BaseSwaggerUri = "$SpecificationUri".Substring(0, "$SpecificationUri".LastIndexOf('/'))
            foreach($document in $jsonObject.Documents)
            {
                $FileName = Split-Path -Path $document -Leaf
                $DocumentFolderPrefix = (Split-Path -Path $document -Parent).Replace('/', [System.IO.Path]::DirectorySeparatorChar).TrimStart('.')
                
                $DocumentFolderPath = Join-Path -Path $TempPath -ChildPath $DocumentFolderPrefix

                if(-not (Test-Path -LiteralPath $DocumentFolderPath -PathType Container))
                {
                    $null = New-Item -Path $DocumentFolderPath -ItemType Container -Force -Confirm:$false -WhatIf:$false
                }
                $SwaggerDocumentPath = Join-Path -Path $DocumentFolderPath -ChildPath $FileName

                $ev = $null
                Invoke-WebRequest -Uri $($BaseSwaggerUri + $($document.replace('\','/').TrimStart('.'))) -OutFile $SwaggerDocumentPath -ErrorVariable ev
                if($ev) {
                    return 
                }
                $SwaggerSpecFilePaths += $SwaggerDocumentPath
            }
        }
        else
        {
            $SwaggerSpecFilePaths += $SpecificationPath
        }
    }    

    $outputDirectory = Microsoft.PowerShell.Management\Resolve-Path -Path $Path | Select-Object -First 1 -ErrorAction Ignore
    $outputDirectory = "$outputDirectory".TrimEnd('\').TrimEnd('/')
    if (-not $SymbolPath) {
        $SymbolPath = Join-Path -Path $Path -ChildPath "symbols"
    }

    if (-not $outputDirectory -or (-not (Test-path -Path $outputDirectory -PathType Container)))
    {
        throw $LocalizedData.PathNotFound -f ($Path)
        return
    }
  
    # Validate swagger path and composite swagger paths
    if (-not (Test-path -Path $SpecificationPath))
    {
        throw $LocalizedData.SwaggerSpecPathNotExist -f ($SpecificationPath)
        return
    }

    # Get the PowerShell Metadata if .psmeta.json file is available.
    $PSMetaJsonObject = $null
    $PSMetaFilePath = [regex]::replace($SpecificationPath, ".json$", ".psmeta.json")
    if (Test-Path -Path $PSMetaFilePath -PathType Leaf) {
        $PSMetaJsonObject = ConvertFrom-Json -InputObject ((Get-Content -Path $PSMetaFilePath) -join [Environment]::NewLine) -ErrorAction Stop
    }

    if ($PSCmdlet.ParameterSetName -eq 'SwaggerPath')
    {
        $jsonObject = ConvertFrom-Json -InputObject ((Get-Content -Path $SpecificationPath) -join [Environment]::NewLine) -ErrorAction Stop
        if((Get-Member -InputObject $jsonObject -Name 'Documents') -and ($jsonObject.Documents.Count))
        {
            $AutoRestModeler = 'CompositeSwagger'
            $SwaggerBaseDir = Split-Path -Path $SpecificationPath -Parent
            foreach($document in $jsonObject.Documents)
            {
                $FileName = Split-Path -Path $document -Leaf
                if(Test-Path -Path $document -PathType Leaf)
                {
                    $SwaggerSpecFilePaths += $document
                }
                elseif(Test-Path -Path (Join-Path -Path $SwaggerBaseDir -ChildPath $document) -PathType Leaf)
                {
                    $SwaggerSpecFilePaths += Join-Path -Path $SwaggerBaseDir -ChildPath $document
                }
                else {
                    throw $LocalizedData.PathNotFound -f ($document)
                    return
                }
            }
        }
        else
        {
            $SwaggerSpecFilePaths += $SpecificationPath
        }
    }

    $frameworksToCheckDependencies = @('net4')
    if ($IncludeCoreFxAssembly) {
        if ((-not (Get-OperatingSystemInfo).IsCore) -and (-not $PowerShellCorePath)) {
            $psCore = Get-PSSwaggerMsi -Name "PowerShell*" -MaximumVersion "6.0.0.11" | Sort-Object -Property Version -Descending
            if ($null -ne $psCore) {
                # PSCore exists via MSI, but the MSI provider doesn't seem to provide an install path
                # First check the default path (for now, just Windows)
                $psCore | ForEach-Object {
                    if (-not $PowerShellCorePath) {
                        $message = $LocalizedData.FoundPowerShellCoreMsi -f ($($_.Version))
                        Write-Verbose -Message $message
                        $possiblePsPath = (Join-Path -Path "$env:ProgramFiles" -ChildPath "PowerShell" | Join-Path -ChildPath "$($_.Version)" | Join-Path -ChildPath "PowerShell.exe")
                        if (Test-Path -Path $possiblePsPath) {
                            $PowerShellCorePath = $possiblePsPath
                        }
                    }
                }
            }
        }

        if (-not $PowerShellCorePath) {
            throw $LocalizedData.MustSpecifyPsCorePath
        }

        if ((Get-Item $PowerShellCorePath).PSIsContainer) {
            $PowerShellCorePath = Join-Path -Path $PowerShellCorePath -ChildPath "PowerShell.exe"
        }

        if (-not (Test-Path -Path $PowerShellCorePath)) {
            $message = $LocalizedData.PsCorePathNotFound -f ($PowerShellCorePath)
            throw $message
        }

        $frameworksToCheckDependencies += 'netstandard1'
    }

    $userConsent = Initialize-PSSwaggerLocalTool -AllUsers:$InstallToolsForAllUsers -Azure:$UseAzureCsharpGenerator -Framework $frameworksToCheckDependencies -AcceptBootstrap:$ConfirmBootstrap

    $DefinitionFunctionsDetails = @{}
    $PowerShellCodeGen = @{
        CodeGenerator = ""
        Path = ""
        NoAssembly = ""
        PowerShellCorePath = ""
        IncludeCoreFxAssembly = ""
        TestBuild = ""
        SymbolPath = ""
        ConfirmBootstrap = ""
        AdditionalFilesPath = ""
        ServiceType = ""
        CustomAuthCommand = ""
        HostOverrideCommand = ""
        NoAuthChallenge = $false
        NameSpacePrefix = ''
    }

    # Parse the JSON and populate the dictionary
    $ConvertToSwaggerDictionary_params = @{
        SwaggerSpecPath = $SpecificationPath
        ModuleName = $Name
        ModuleVersion = $Version
        DefaultCommandPrefix = $DefaultCommandPrefix
        SwaggerSpecFilePaths = $SwaggerSpecFilePaths
        DefinitionFunctionsDetails = $DefinitionFunctionsDetails
        AzureSpec = $UseAzureCsharpGenerator
        PowerShellCodeGen = $PowerShellCodeGen
        PSMetaJsonObject = $PSMetaJsonObject
    }
    $swaggerDict = ConvertTo-SwaggerDictionary @ConvertToSwaggerDictionary_params

    Get-PowerShellCodeGenSettings -Path $SpecificationPath -CodeGenSettings $PowerShellCodeGen -PSMetaJsonObject $PSMetaJsonObject
    if(-not $PSMetaJsonObject) {
        foreach ($additionalSwaggerSpecPath in $SwaggerSpecFilePaths) {
            Get-PowerShellCodeGenSettings -Path $additionalSwaggerSpecPath -CodeGenSettings $PowerShellCodeGen
        }
    }

    # Expand partner metadata
    if ($PowerShellCodeGen['ServiceType']) {
        $partnerFilePath = Join-Path -Path $PSScriptRoot -ChildPath "ServiceTypes" | Join-Path -ChildPath "$($PowerShellCodeGen['ServiceType'].ToLowerInvariant()).PSMeta.json"
        if (-not (Test-Path -Path $partnerFilePath -PathType Leaf)) {
            Write-Warning -Message ($LocalizedData.ServiceTypeMetadataFileNotFound -f $partnerFilePath)
        } else {
            Get-PowerShellCodeGenSettings -Path $partnerFilePath -CodeGenSettings $PowerShellCodeGen
        }
    }
    
    $nameSpace = $swaggerDict['info'].NameSpace
    $models = $swaggerDict['info'].Models
    if($PSVersionTable.PSVersion -lt '5.0.0') {
        if (-not $outputDirectory.EndsWith($Name, [System.StringComparison]::OrdinalIgnoreCase)) {
            $outputDirectory = Join-Path -Path $outputDirectory -ChildPath $Name
            $SymbolPath = Join-Path -Path $SymbolPath -ChildPath $Name
        }
    } else {
        $ModuleNameandVersionFolder = Join-Path -Path $Name -ChildPath $Version

        if ($outputDirectory.EndsWith($Name, [System.StringComparison]::OrdinalIgnoreCase)) {
            $outputDirectory = Join-Path -Path $outputDirectory -ChildPath $ModuleVersion
            $SymbolPath = Join-Path -Path $SymbolPath -ChildPath $ModuleVersion
        } elseif (-not $outputDirectory.EndsWith($ModuleNameandVersionFolder, [System.StringComparison]::OrdinalIgnoreCase)) {
            $outputDirectory = Join-Path -Path $outputDirectory -ChildPath $ModuleNameandVersionFolder
            $SymbolPath = Join-Path -Path $SymbolPath -ChildPath $ModuleNameandVersionFolder
        }
    }

    $null = New-Item -ItemType Directory $outputDirectory -Force -ErrorAction Stop -Confirm:$false -WhatIf:$false
    $null = New-Item -ItemType Directory $SymbolPath -Force -ErrorAction Stop -Confirm:$false -WhatIf:$false

    $swaggerMetaDict = @{
        OutputDirectory = $outputDirectory
        UseAzureCsharpGenerator = $UseAzureCsharpGenerator
        SwaggerSpecPath = $SpecificationPath
        SwaggerSpecFilePaths = $SwaggerSpecFilePaths
        AutoRestModeler = $AutoRestModeler
        PowerShellCodeGen = $PowerShellCodeGen
    }

    $ParameterGroupCache = @{}
    $PathFunctionDetails = @{}

    foreach($FilePath in $SwaggerSpecFilePaths) {
        $jsonObject = ConvertFrom-Json -InputObject ((Get-Content -Path $FilePath) -join [Environment]::NewLine) -ErrorAction Stop

        if(Get-Member -InputObject $jsonObject -Name 'Definitions') {
            # Handle the Definitions
            $jsonObject.Definitions.PSObject.Properties | ForEach-Object {
                Get-SwaggerSpecDefinitionInfo -JsonDefinitionItemObject $_ `
                                            -Namespace $Namespace `
                                            -DefinitionFunctionsDetails $DefinitionFunctionsDetails `
                                            -Models $models
            }
        }

        if(Get-Member -InputObject $jsonObject -Name 'Paths') {
            # Handle the Paths
            $jsonObject.Paths.PSObject.Properties | ForEach-Object {
                Get-SwaggerSpecPathInfo -JsonPathItemObject $_ `
                                        -PathFunctionDetails $PathFunctionDetails `
                                        -SwaggerDict $swaggerDict `
                                        -SwaggerMetaDict $swaggerMetaDict `
                                        -DefinitionFunctionsDetails $DefinitionFunctionsDetails `
                                        -ParameterGroupCache $ParameterGroupCache `
                                        -PSMetaJsonObject $PSMetaJsonObject
            }
        }

        if(Get-Member -InputObject $jsonObject -Name 'x-ms-paths') {
            # Handle extended paths
            $jsonObject.'x-ms-paths'.PSObject.Properties | ForEach-Object {
                Get-SwaggerSpecPathInfo -JsonPathItemObject $_ `
                                        -PathFunctionDetails $PathFunctionDetails `
                                        -SwaggerDict $swaggerDict `
                                        -SwaggerMetaDict $swaggerMetaDict `
                                        -DefinitionFunctionsDetails $DefinitionFunctionsDetails `
                                        -ParameterGroupCache $ParameterGroupCache `
                                        -PSMetaJsonObject $PSMetaJsonObject

            }
        }
    }

    $codePhaseResult = ConvertTo-CsharpCode -SwaggerDict $swaggerDict `
                                            -SwaggerMetaDict $swaggerMetaDict `
                                            -PowerShellCorePath $PowerShellCorePath `
                                            -InstallToolsForAllUsers:$InstallToolsForAllUsers `
                                            -UserConsent:$userConsent `
                                            -TestBuild:$TestBuild `
                                            -PathFunctionDetails $PathFunctionDetails `
                                            -NoAssembly:$NoAssembly `
                                            -SymbolPath $SymbolPath

    $PathFunctionDetails = $codePhaseResult.PathFunctionDetails
    $generatedCSharpFilePath = $codePhaseResult.GeneratedCSharpPath

    # Need to expand the definitions early as parameter flattening feature requires the parameters list of the definition/model types.
    Expand-SwaggerDefinition -DefinitionFunctionsDetails $DefinitionFunctionsDetails -NameSpace $NameSpace -Models $Models

    $FunctionsToExport = @()
    $FunctionsToExport += New-SwaggerSpecPathCommand -PathFunctionDetails $PathFunctionDetails `
                                                     -SwaggerMetaDict $swaggerMetaDict `
                                                     -SwaggerDict $swaggerDict `
                                                     -DefinitionFunctionsDetails $DefinitionFunctionsDetails

    $FunctionsToExport += New-SwaggerDefinitionCommand -DefinitionFunctionsDetails $DefinitionFunctionsDetails `
                                                       -SwaggerMetaDict $swaggerMetaDict `
                                                       -NameSpace $nameSpace `
                                                       -Models $models

    $RootModuleFilePath = Join-Path $outputDirectory "$Name.psm1"
    $testCoreModuleRequirements = ''
    $testFullModuleRequirements = ''
    if ($UseAzureCSharpGenerator) {
        $testCoreModuleRequirements = '. (Join-Path -Path $PSScriptRoot "Test-CoreRequirements.ps1")' + [Environment]::NewLine + " "
        $testFullModuleRequirements = '. (Join-Path -Path $PSScriptRoot "Test-FullRequirements.ps1")' + [Environment]::NewLine + " "
    }

    Out-File -FilePath $RootModuleFilePath `
             -InputObject $ExecutionContext.InvokeCommand.ExpandString($RootModuleContents)`
             -Encoding ascii `
             -Force `
             -Confirm:$false `
             -WhatIf:$false

    New-ModuleManifestUtility -Path $outputDirectory `
                              -FunctionsToExport $FunctionsToExport `
                              -Info $swaggerDict['info']

    Copy-Item (Join-Path -Path "$PSScriptRoot" -ChildPath "Generated.Resources.psd1") (Join-Path -Path "$outputDirectory" -ChildPath "$Name.Resources.psd1") -Force
    Copy-Item (Join-Path -Path "$PSScriptRoot" -ChildPath "GeneratedHelpers.psm1") (Join-Path -Path "$outputDirectory" -ChildPath "GeneratedHelpers.psm1") -Force
    Copy-Item (Join-Path -Path "$PSScriptRoot" -ChildPath "Test-CoreRequirements.ps1") (Join-Path -Path "$outputDirectory" -ChildPath "Test-CoreRequirements.ps1") -Force
    Copy-Item (Join-Path -Path "$PSScriptRoot" -ChildPath "Test-FullRequirements.ps1") (Join-Path -Path "$outputDirectory" -ChildPath "Test-FullRequirements.ps1") -Force

    Write-Verbose -Message ($LocalizedData.SuccessfullyGeneratedModule -f $Name,$outputDirectory)
}

#region Module Generation Helpers

function ConvertTo-CsharpCode
{
    param
    (
        [Parameter(Mandatory=$true)]
        [hashtable]
        $SwaggerDict,
        
        [Parameter(Mandatory = $true)]
        [hashtable]
        $SwaggerMetaDict,

        [Parameter()]
        [string]
        $PowerShellCorePath,

        [Parameter()]
        [switch]
        $InstallToolsForAllUsers,

        [Parameter()]
        [switch]
        $UserConsent,

        [Parameter()]
        [switch]
        $TestBuild,

        [Parameter(Mandatory=$true)]
        [hashtable]
        $PathFunctionDetails,

        [Parameter()]
        [switch]
        $NoAssembly,

        [Parameter()]
        [string]
        $SymbolPath
    )

    Write-Verbose -Message $LocalizedData.GenerateCodeUsingAutoRest
    $info = $SwaggerDict['Info']

    $autoRestExePath = "AutoRest"
    if (-not (get-command -name $autoRestExePath)) {
            throw $LocalizedData.AutoRestNotInPath
    }

    $outputDirectory = $SwaggerMetaDict['outputDirectory']
    $nameSpace = $info.NameSpace
    $generatedCSharpPath = Join-Path -Path $outputDirectory -ChildPath "Generated.Csharp"
    $codeGenerator = "CSharp"

    if ($SwaggerMetaDict['UseAzureCsharpGenerator'])
    { 
        $codeGenerator = "Azure.CSharp"
    }

    $clrPath = Join-Path -Path $outputDirectory -ChildPath 'ref' | Join-Path -ChildPath 'fullclr'
    if (-not (Test-Path -Path $clrPath)) {
        $null = New-Item -Path $clrPath -ItemType Directory -Force -Confirm:$false -WhatIf:$false
    }

    $outAssembly = "$NameSpace.dll"
    # Delete the previously generated assembly, even if -NoAssembly is specified
    if (Test-Path -Path (Join-Path -Path $clrPath -ChildPath $outAssembly)) {
        $null = Remove-Item -Path (Join-Path -Path $clrPath -ChildPath $outAssembly) -Force
    }

    # Clean old generated code for when operations change or the command is re-run (Copy-Item can't clobber)
    # Note that we don't need to require this as empty as this folder is generated by PSSwagger, not a user folder
    if (Test-Path -Path $generatedCSharpPath) {
        $null = Remove-Item -Path $generatedCSharpPath -Recurse -Force
    }

    if ($NoAssembly) {
        $outAssembly = ''
    }

    $return = @{
        GeneratedCSharpPath = $generatedCSharpPath
    }

    $tempCodeGenSettingsPath = ''
    try {
        if ($info.ContainsKey('CodeGenFileRequired') -and $info.CodeGenFileRequired) {
            # Some settings need to be overwritten
            # Write the following parameters: AddCredentials, CodeGenerator, Modeler
            $tempCodeGenSettings = @{
                AddCredentials = $true
                CodeGenerator = $codeGenerator
                Modeler = $swaggerMetaDict['AutoRestModeler']
            }

            $tempCodeGenSettingsPath = "$(Join-Path -Path (Get-XDGDirectory -DirectoryType Cache) -ChildPath (Get-Random)).json"
            $tempCodeGenSettings | ConvertTo-Json | Out-File -FilePath $tempCodeGenSettingsPath

            $autoRestParams = @('-Input', $swaggerMetaDict['SwaggerSpecPath'], '-OutputDirectory', $generatedCSharpPath, '-Namespace', $NameSpace, '-CodeGenSettings', $tempCodeGenSettingsPath)
        } else {
            # None of the PSSwagger-required params are being overwritten, just call the CLI directly to avoid the extra disk op
            $autoRestParams = @('-Input', $swaggerMetaDict['SwaggerSpecPath'], '-OutputDirectory', $generatedCSharpPath, '-Namespace', $NameSpace, '-AddCredentials', $true, '-CodeGenerator', $codeGenerator, '-Modeler', $swaggerMetaDict['AutoRestModeler'])
        }

        Write-Verbose -Message $LocalizedData.InvokingAutoRestWithParams
        for ($i = 0; $i -lt $autoRestParams.Length; $i += 2) {
            Write-Verbose -Message ($LocalizedData.AutoRestParam -f ($autoRestParams[$i], $autoRestParams[$i+1]))
        }

        $null = & $autoRestExePath $autoRestParams
        if ($LastExitCode)
        {
            throw $LocalizedData.AutoRestError
        }
    }
    finally {
        if ($tempCodeGenSettingsPath -and (Test-Path -Path $tempCodeGenSettingsPath)) {
            $null = Remove-Item -Path $tempCodeGenSettingsPath -Force -ErrorAction Ignore
        }
    }
    

    Write-Verbose -Message $LocalizedData.GenerateAssemblyFromCode
    if ($info.ContainsKey('CodeOutputDirectory') -and $info.CodeOutputDirectory) {
        $null = Copy-Item -Path $info.CodeOutputDirectory -Destination $generatedCSharpPath -Filter "*.cs" -Recurse -ErrorAction Ignore
    }

    $allCSharpFiles= Get-ChildItem -Path "$generatedCSharpPath\*.cs" `
                                   -Recurse `
                                   -File `
                                   -Exclude Program.cs,TemporaryGeneratedFile* |
                                        Where-Object DirectoryName -notlike '*Azure.Csharp.Generated*'
    $allCodeFiles = @()
    foreach ($file in $allCSharpFiles) {
        $newFileName = Join-Path -Path $file.Directory -ChildPath "$($file.BaseName).Code.ps1"
        $null = Move-Item -Path $file.FullName -Destination $newFileName -Force
        $allCodeFiles += $newFileName
    }
    
    $allCSharpFilesArrayString = "@('"+ $($allCodeFiles -join "','") + "')"
    # Compile full CLR (PSSwagger requires to be invoked from full PowerShell)
    $codeCreatedByAzureGenerator = [bool]$SwaggerMetaDict['UseAzureCsharpGenerator']

    # As of 3/2/2017, there's a version mismatch between the latest Microsoft.Rest.ClientRuntime.Azure package and the latest AzureRM.Profile package
    # So we have to hardcode Microsoft.Rest.ClientRuntime.Azure to at most version 3.3.4
    $modulePostfix = $info['infoName']
    $NameSpace = $info.namespace
    $fullModuleName = $Namespace + '.' + $modulePostfix
    $cliXmlTmpPath = Get-TemporaryCliXmlFilePath -FullModuleName $fullModuleName
    try {
        Export-CliXml -InputObject $PathFunctionDetails -Path $cliXmlTmpPath
        $dependencies = Get-PSSwaggerExternalDependencies -Azure:$codeCreatedByAzureGenerator -Framework 'net4'
        $microsoftRestClientRuntimeAzureRequiredVersion = if ($dependencies.ContainsKey('Microsoft.Rest.ClientRuntime.Azure')) { $dependencies['Microsoft.Rest.ClientRuntime.Azure'].RequiredVersion } else { '' }
        $command = "Import-Module '$PSScriptRoot\PSSwaggerUtility';
                    Add-PSSwaggerClientType -OutputAssemblyName '$outAssembly' ``
                                                -ClrPath '$clrPath' ``
                                                -CSharpFiles $allCSharpFilesArrayString ``
                                                -CodeCreatedByAzureGenerator:`$$codeCreatedByAzureGenerator ``
                                                -MicrosoftRestClientRuntimeAzureRequiredVersion '$microsoftRestClientRuntimeAzureRequiredVersion' ``
                                                -MicrosoftRestClientRuntimeRequiredVersion '$($dependencies['Microsoft.Rest.ClientRuntime'].RequiredVersion)' ``
                                                -NewtonsoftJsonRequiredVersion '$($dependencies['Newtonsoft.Json'].RequiredVersion)' ``
                                                -AllUsers:`$$InstallToolsForAllUsers ``
                                                -BootstrapConsent:`$$UserConsent ``
                                                -TestBuild:`$$TestBuild ``
                                                -SymbolPath $SymbolPath;
                    if('$outAssembly') {
                        # Load the generated assembly to extract the extended metadata
                        `$AssemblyPath = Join-Path -Path '$clrPath' -ChildPath '$outAssembly'
                        if(Test-Path -Path `$AssemblyPath -PathType Leaf) {
                            Add-Type -Path `$AssemblyPath
                        }
                    }
 
                    Import-Module `"`$(Join-Path -Path `"$PSScriptRoot`" -ChildPath `"Paths.psm1`")` -DisableNameChecking;
                    Set-ExtendedCodeMetadata -MainClientTypeName $fullModuleName ``
                                                -CliXmlTmpPath $cliXmlTmpPath"


        $success = & "powershell" -command "& {$command}"
        
        $codeReflectionResult = Import-CliXml -Path $cliXmlTmpPath
        if ($codeReflectionResult.ContainsKey('VerboseMessages') -and $codeReflectionResult.VerboseMessages -and ($codeReflectionResult.VerboseMessages.Count -gt 0)) {
            $verboseMessages = $codeReflectionResult.VerboseMessages -Join [Environment]::NewLine
            Write-Verbose -Message $verboseMessages
        }

        if ($codeReflectionResult.ContainsKey('WarningMessages') -and $codeReflectionResult.WarningMessages -and ($codeReflectionResult.WarningMessages.Count -gt 0)) {
            $warningMessages = $codeReflectionResult.WarningMessages -Join [Environment]::NewLine
            Write-Warning -Message $warningMessages
        }

        if ((Test-AssemblyCompilationSuccess -Output ($success | Out-String))) {
            $message = $LocalizedData.GeneratedAssembly -f ($outAssembly)
            Write-Verbose -Message $message
        } else {
            # This should be enough to let the user know we failed to generate their module's assembly.
            if (-not $outAssembly) {
                $outAssembly = "$NameSpace.dll"
            }

            $message = $LocalizedData.UnableToGenerateAssembly -f ($outAssembly)
            Throw $message
        }

        if (-not $codeReflectionResult.Result -or $codeReflectionResult.ErrorMessages.Count -gt 0) {
            $errorMessage = (,($LocalizedData.MetadataExtractFailed) + 
                $codeReflectionResult.ErrorMessages) -Join [Environment]::NewLine
            throw $errorMessage
        }

        $return.PathFunctionDetails = $codeReflectionResult.Result
    } finally {
        if (Test-Path -Path $cliXmlTmpPath) {
            $null = Remove-Item -Path $cliXmlTmpPath
        }
    }
    
    # If we're not going to save the assembly, no need to generate the core CLR one now
    if ($PowerShellCorePath -and (-not $NoAssembly)) {
        if (-not $outAssembly) {
            $outAssembly = "$NameSpace.dll"
        }

        # Compile core CLR
        $clrPath = Join-Path -Path $outputDirectory -ChildPath 'ref' | Join-Path -ChildPath 'coreclr'
        if (Test-Path (Join-Path -Path $outputDirectory -ChildPath $outAssembly)) {
            $null = Remove-Item -Path $outAssembly -Force
        }

        if (-not (Test-Path -Path $clrPath)) {
            $null = New-Item $clrPath -ItemType Directory -Force -Confirm:$false -WhatIf:$false
        }
        $dependencies = Get-PSSwaggerExternalDependencies -Azure:$codeCreatedByAzureGenerator -Framework 'netstandard1'
        $microsoftRestClientRuntimeAzureRequiredVersion = if ($dependencies.ContainsKey('Microsoft.Rest.ClientRuntime.Azure')) { $dependencies['Microsoft.Rest.ClientRuntime.Azure'].RequiredVersion } else { '' }
        $command = "Import-Module '$PSScriptRoot\PSSwaggerUtility';
                    Add-PSSwaggerClientType -OutputAssemblyName '$outAssembly' ``
                                               -ClrPath '$clrPath' ``
                                               -CSharpFiles $allCSharpFilesArrayString ``
                                               -MicrosoftRestClientRuntimeAzureRequiredVersion '$microsoftRestClientRuntimeAzureRequiredVersion' ``
                                               -MicrosoftRestClientRuntimeRequiredVersion '$($dependencies['Microsoft.Rest.ClientRuntime'].RequiredVersion)' ``
                                               -NewtonsoftJsonRequiredVersion '$($dependencies['Newtonsoft.Json'].RequiredVersion)' ``
                                               -CodeCreatedByAzureGenerator:`$$codeCreatedByAzureGenerator ``
                                               -BootstrapConsent:`$$UserConsent"


        $success = & "$PowerShellCorePath" -command "& {$command}"
        if ((Test-AssemblyCompilationSuccess -Output ($success | Out-String))) {
            $message = $LocalizedData.GeneratedAssembly -f ($outAssembly)
            Write-Verbose -Message $message
        } else {
            $message = $LocalizedData.UnableToGenerateAssembly -f ($outAssembly)
            Throw $message
        }
    }

    return $return
}

function Test-AssemblyCompilationSuccess {
    param(
        [Parameter(Mandatory = $true)]
        [string]
        $Output
    )

    Write-Verbose -Message ($LocalizedData.AssemblyCompilationResult -f ($Output))
    $tokens = $Output.Split(' ')
    return ($tokens[$tokens.Count-1].Trim().EndsWith('True'))
}

function New-ModuleManifestUtility
{
    param(
        [Parameter(Mandatory = $true)]
        [string]
        $Path,

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

        [Parameter(Mandatory=$true)]
        [hashtable]
        $Info
    )

    $FormatsToProcess = Get-ChildItem -Path "$Path\$GeneratedCommandsName\FormatFiles\*.ps1xml" `
                                      -File `
                                      -ErrorAction Ignore | Foreach-Object { $_.FullName.Replace($Path, '.') }

    $NewModuleManifest_params = @{
        Path = "$(Join-Path -Path $Path -ChildPath $Info.ModuleName).psd1"
        ModuleVersion = $Info.Version
        Description = $Info.Description
        CopyRight = $info.LicenseName
        Author = $info.ContactEmail
        NestedModules = @('PSSwaggerUtility')
        RootModule = "$($Info.ModuleName).psm1"
        FormatsToProcess = $FormatsToProcess
        FunctionsToExport = $FunctionsToExport
        CmdletsToExport = @()
        AliasesToExport = @()
        VariablesToExport = @()
    }

    if($Info.DefaultCommandPrefix)
    {
        $NewModuleManifest_params['DefaultCommandPrefix'] = $Info.DefaultCommandPrefix
    }

    if($PSVersionTable.PSVersion -ge '5.0.0')
    {
        # Below parameters are not available on PS 3 and 4 versions.
        if($Info.ProjectUri)
        {
            $NewModuleManifest_params['ProjectUri'] = $Info.ProjectUri
        }

        if($Info.LicenseUri)
        {
            $NewModuleManifest_params['LicenseUri'] = $Info.LicenseUri
        }
    }

    New-ModuleManifest @NewModuleManifest_params
}

#endregion

Export-ModuleMember -Function New-PSSwaggerModule, New-PSSwaggerMetadataFile
# SIG # Begin signature block
# MIIasAYJKoZIhvcNAQcCoIIaoTCCGp0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUqIIiB8129iPHjf6xGhwaLDLZ
# vKagghWDMIIEwzCCA6ugAwIBAgITMwAAALfuAa/68MeouwAAAAAAtzANBgkqhkiG
# 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw
# HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTYwOTA3MTc1ODQ1
# WhcNMTgwOTA3MTc1ODQ1WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNO
# OkJCRUMtMzBDQS0yREJFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT
# ZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuCMjQSw3ep1m
# SndFRK0xgVRgm9wSl3i2llRtDdxzAWN9gQtYAE3hJP0/pV/7HHkshYPfMIRf7Pm/
# dxSsAN+7ATnNUk+wpe46rfe0FDNxoE6CYaiMSNjKcMXH55bGXNnwrrcsMaZrVXzS
# IQcmAhUQw1jdLntbdTyCAwJ2UqF/XmVtWV/U466G8JP8VGLddeaucY0YKhgYwMnt
# Sp9ElCkVDcUP01L9pgn9JmKUfD3yFt2p1iZ9VKCrlla10JQwe7aNW7xjzXxvcvlV
# IXeA4QSabo4dq8HUh7JoYMqh3ufr2yNgTs/rSxG6D5ITcI0PZkH4PYjO2GbGIcOF
# RVOf5RxVrwIDAQABo4IBCTCCAQUwHQYDVR0OBBYEFJZnqouaH5kw+n1zGHTDXjCT
# 5OMAMB8GA1UdIwQYMBaAFCM0+NlSRnAK7UD7dvuzK7DDNbMPMFQGA1UdHwRNMEsw
# SaBHoEWGQ2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz
# L01pY3Jvc29mdFRpbWVTdGFtcFBDQS5jcmwwWAYIKwYBBQUHAQEETDBKMEgGCCsG
# AQUFBzAChjxodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv
# c29mdFRpbWVTdGFtcFBDQS5jcnQwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZI
# hvcNAQEFBQADggEBAG7J+Fdd7DgxG6awnA8opmQfW5DHnNDC/JPLof1sA8Nqczym
# cnWIHmlWhqA7TUy4q02lKenO+R/vbmHna1BrC/KkczAyhOzkI2WFU3PeYubv8EjK
# fYPmrNvS8fCsHJXj3N6fuFwXkHmCVBjTchK93auG09ckBYx5Mt4zW0TUbbw4/QAZ
# X64rbut6Aw/C1bpxqBb8vvMssBB9Hw2m8ApFTApaEVOE/sKemVlq0VIo0fCXqRST
# Lb6/QOav3S8S+N34RBNx/aKKOFzBDy6Ni45QvtRfBoNX3f4/mm4TFdNs+SeLQA+0
# oBs7UgdoxGSpX6vsWaH8dtlBw3NZK7SFi9bBMI4wggTtMIID1aADAgECAhMzAAAB
# QJap7nBW/swHAAEAAAFAMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBMB4XDTE2MDgxODIwMTcxN1oXDTE3MTEwMjIwMTcxN1owgYMxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIx
# HjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIwDQYJKoZIhvcNAQEB
# BQADggEPADCCAQoCggEBANtLi+kDal/IG10KBTnk1Q6S0MThi+ikDQUZWMA81ynd
# ibdobkuffryavVSGOanxODUW5h2s+65r3Akw77ge32z4SppVl0jII4mzWSc0vZUx
# R5wPzkA1Mjf+6fNPpBqks3m8gJs/JJjE0W/Vf+dDjeTc8tLmrmbtBDohlKZX3APb
# LMYb/ys5qF2/Vf7dSd9UBZSrM9+kfTGmTb1WzxYxaD+Eaxxt8+7VMIruZRuetwgc
# KX6TvfJ9QnY4ItR7fPS4uXGew5T0goY1gqZ0vQIz+lSGhaMlvqqJXuI5XyZBmBre
# ueZGhXi7UTICR+zk+R+9BFF15hKbduuFlxQiCqET92ECAwEAAaOCAWEwggFdMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBSc5ehtgleuNyTe6l6pxF+QHc7Z
# ezBSBgNVHREESzBJpEcwRTENMAsGA1UECxMETU9QUjE0MDIGA1UEBRMrMjI5ODAz
# K2Y3ODViMWMwLTVkOWYtNDMxNi04ZDZhLTc0YWU2NDJkZGUxYzAfBgNVHSMEGDAW
# gBTLEejK0rQWWAHJNy4zFha5TJoKHzBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8v
# Y3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNDb2RTaWdQQ0Ff
# MDgtMzEtMjAxMC5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY0NvZFNpZ1BDQV8wOC0z
# MS0yMDEwLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAa+RW49cTHSBA+W3p3k7bXR7G
# bCaj9+UJgAz/V+G01Nn5XEjhBn/CpFS4lnr1jcmDEwxxv/j8uy7MFXPzAGtOJar0
# xApylFKfd00pkygIMRbZ3250q8ToThWxmQVEThpJSSysee6/hU+EbkfvvtjSi0lp
# DimD9aW9oxshraKlPpAgnPWfEj16WXVk79qjhYQyEgICamR3AaY5mLPuoihJbKwk
# Mig+qItmLPsC2IMvI5KR91dl/6TV6VEIlPbW/cDVwCBF/UNJT3nuZBl/YE7ixMpT
# Th/7WpENW80kg3xz6MlCdxJfMSbJsM5TimFU98KNcpnxxbYdfqqQhAQ6l3mtYDCC
# BbwwggOkoAMCAQICCmEzJhoAAAAAADEwDQYJKoZIhvcNAQEFBQAwXzETMBEGCgmS
# JomT8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UE
# AxMkTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDgz
# MTIyMTkzMloXDTIwMDgzMTIyMjkzMloweTELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQ
# Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCycllcGTBkvx2aYCAg
# Qpl2U2w+G9ZvzMvx6mv+lxYQ4N86dIMaty+gMuz/3sJCTiPVcgDbNVcKicquIEn0
# 8GisTUuNpb15S3GbRwfa/SXfnXWIz6pzRH/XgdvzvfI2pMlcRdyvrT3gKGiXGqel
# cnNW8ReU5P01lHKg1nZfHndFg4U4FtBzWwW6Z1KNpbJpL9oZC/6SdCnidi9U3RQw
# WfjSjWL9y8lfRjFQuScT5EAwz3IpECgixzdOPaAyPZDNoTgGhVxOVoIoKgUyt0vX
# T2Pn0i1i8UU956wIAPZGoZ7RW4wmU+h6qkryRs83PDietHdcpReejcsRj1Y8wawJ
# XwPTAgMBAAGjggFeMIIBWjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLEejK
# 0rQWWAHJNy4zFha5TJoKHzALBgNVHQ8EBAMCAYYwEgYJKwYBBAGCNxUBBAUCAwEA
# ATAjBgkrBgEEAYI3FQIEFgQU/dExTtMmipXhmGA7qDFvpjy82C0wGQYJKwYBBAGC
# NxQCBAweCgBTAHUAYgBDAEEwHwYDVR0jBBgwFoAUDqyCYEBWJ5flJRP8KuEKU5VZ
# 5KQwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br
# aS9jcmwvcHJvZHVjdHMvbWljcm9zb2Z0cm9vdGNlcnQuY3JsMFQGCCsGAQUFBwEB
# BEgwRjBEBggrBgEFBQcwAoY4aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9j
# ZXJ0cy9NaWNyb3NvZnRSb290Q2VydC5jcnQwDQYJKoZIhvcNAQEFBQADggIBAFk5
# Pn8mRq/rb0CxMrVq6w4vbqhJ9+tfde1MOy3XQ60L/svpLTGjI8x8UJiAIV2sPS9M
# uqKoVpzjcLu4tPh5tUly9z7qQX/K4QwXaculnCAt+gtQxFbNLeNK0rxw56gNogOl
# VuC4iktX8pVCnPHz7+7jhh80PLhWmvBTI4UqpIIck+KUBx3y4k74jKHK6BOlkU7I
# G9KPcpUqcW2bGvgc8FPWZ8wi/1wdzaKMvSeyeWNWRKJRzfnpo1hW3ZsCRUQvX/Ta
# rtSCMm78pJUT5Otp56miLL7IKxAOZY6Z2/Wi+hImCWU4lPF6H0q70eFW6NB4lhhc
# yTUWX92THUmOLb6tNEQc7hAVGgBd3TVbIc6YxwnuhQ6MT20OE049fClInHLR82zK
# wexwo1eSV32UjaAbSANa98+jZwp0pTbtLS8XyOZyNxL0b7E8Z4L5UrKNMxZlHg6K
# 3RDeZPRvzkbU0xfpecQEtNP7LN8fip6sCvsTJ0Ct5PnhqX9GuwdgR2VgQE6wQuxO
# 7bN2edgKNAltHIAxH+IOVN3lofvlRxCtZJj/UBYufL8FIXrilUEnacOTj5XJjdib
# Ia4NXJzwoq6GaIMMai27dmsAHZat8hZ79haDJLmIz2qoRzEvmtzjcT3XAH5iR9HO
# iMm4GPoOco3Boz2vAkBq/2mbluIQqBC0N1AI1sM9MIIGBzCCA++gAwIBAgIKYRZo
# NAAAAAAAHDANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZImiZPyLGQBGRYDY29tMRkw
# FwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQDEyRNaWNyb3NvZnQgUm9v
# dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcwNDAzMTI1MzA5WhcNMjEwNDAz
# MTMwMzA5WjB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw
# HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwggEiMA0GCSqGSIb3DQEB
# AQUAA4IBDwAwggEKAoIBAQCfoWyx39tIkip8ay4Z4b3i48WZUSNQrc7dGE4kD+7R
# p9FMrXQwIBHrB9VUlRVJlBtCkq6YXDAm2gBr6Hu97IkHD/cOBJjwicwfyzMkh53y
# 9GccLPx754gd6udOo6HBI1PKjfpFzwnQXq/QsEIEovmmbJNn1yjcRlOwhtDlKEYu
# J6yGT1VSDOQDLPtqkJAwbofzWTCd+n7Wl7PoIZd++NIT8wi3U21StEWQn0gASkdm
# EScpZqiX5NMGgUqi+YSnEUcUCYKfhO1VeP4Bmh1QCIUAEDBG7bfeI0a7xC1Un68e
# eEExd8yb3zuDk6FhArUdDbH895uyAc4iS1T/+QXDwiALAgMBAAGjggGrMIIBpzAP
# BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQjNPjZUkZwCu1A+3b7syuwwzWzDzAL
# BgNVHQ8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwgZgGA1UdIwSBkDCBjYAUDqyC
# YEBWJ5flJRP8KuEKU5VZ5KShY6RhMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAX
# BgoJkiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290
# IENlcnRpZmljYXRlIEF1dGhvcml0eYIQea0WoUqgpa1Mc1j0BxMuZTBQBgNVHR8E
# STBHMEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9k
# dWN0cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEESDBGMEQGCCsG
# AQUFBzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv
# c29mdFJvb3RDZXJ0LmNydDATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0B
# AQUFAAOCAgEAEJeKw1wDRDbd6bStd9vOeVFNAbEudHFbbQwTq86+e4+4LtQSooxt
# YrhXAstOIBNQmd16QOJXu69YmhzhHQGGrLt48ovQ7DsB7uK+jwoFyI1I4vBTFd1P
# q5Lk541q1YDB5pTyBi+FA+mRKiQicPv2/OR4mS4N9wficLwYTp2OawpylbihOZxn
# LcVRDupiXD8WmIsgP+IHGjL5zDFKdjE9K3ILyOpwPf+FChPfwgphjvDXuBfrTot/
# xTUrXqO/67x9C0J71FNyIe4wyrt4ZVxbARcKFA7S2hSY9Ty5ZlizLS/n+YWGzFFW
# 6J1wlGysOUzU9nm/qhh6YinvopspNAZ3GmLJPR5tH4LwC8csu89Ds+X57H2146So
# dDW4TsVxIxImdgs8UoxxWkZDFLyzs7BNZ8ifQv+AeSGAnhUwZuhCEl4ayJ4iIdBD
# 6Svpu/RIzCzU2DKATCYqSCRfWupW76bemZ3KOm+9gSd0BhHudiG/m4LBJ1S2sWo9
# iaF2YbRuoROmv6pH8BJv/YoybLL+31HIjCPJZr2dHYcSZAI9La9Zj7jkIeW1sMpj
# tHhUBdRBLlCslLCleKuzoJZ1GtmShxN1Ii8yqAhuoFuMJb+g74TKIdbrHk/Jmu5J
# 4PcBZW+JC33Iacjmbuqnl84xKf8OxVtc2E0bodj6L54/LlUWa8kTo/0xggSXMIIE
# kwIBATCBkDB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSMw
# IQYDVQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQQITMwAAAUCWqe5wVv7M
# BwABAAABQDAJBgUrDgMCGgUAoIGwMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEE
# MBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQV
# BEZVkFArwLsYLIFqYKtIVYyN1jBQBgorBgEEAYI3AgEMMUIwQKAWgBQAUABvAHcA
# ZQByAFMAaABlAGwAbKEmgCRodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUG93ZXJT
# aGVsbCAwDQYJKoZIhvcNAQEBBQAEggEABhVg5PNDPonOvQGHEuQB7SINs/WpekJS
# 2dR3svzzYN7vyxjYwkdKyYkEsek1aP25j3r4AJPgOzjYhv9uJ44qAl6gy5qoy05U
# sTggRgxLM3JDv38lPYgjs6WDIT16Q87JUJvGIOA0I7qPvocwyKMnRnr8o3VNscXm
# ThdX3cDRP0nVQjT1EuqyzkLtGaSV0T5Gs0HNtQqJ0Nm3SVEI4VvIkats17DHRR26
# v+Mscf1Vz3GZmFdaIatJFzR9SQdIvqGsbnVE95TXqlWpxZlMX5CNrby9xa76ar0H
# YpmlSClzqftPSn72O5+W+6A2hArY/aSfVvJNWPkaMSWgaB18e6St2qGCAigwggIk
# BgkqhkiG9w0BCQYxggIVMIICEQIBATCBjjB3MQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQ
# Q0ECEzMAAAC37gGv+vDHqLsAAAAAALcwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJ
# AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE3MDgwODE3MzUyMVowIwYJ
# KoZIhvcNAQkEMRYEFF+wykVoxoZkEQPO8E+abLKN1DDJMA0GCSqGSIb3DQEBBQUA
# BIIBAG/U1wtM2vK68n0eS3CqGbOQUL2+0JPSwuIpr0OD2w4raTrAwEa/Q9COPGny
# 7nWUpdJSydQ4BXpcmOJsLCWKnExu/KAx075ktvTViSOSCPh64EN/SO2+jx3UO+Cn
# kzTYt42d0wKDbDOs1jAbhBIuWwinSUKe+N4Q3Kli6xRE3ghCKn79vTk/0XLpL0S5
# NKHPab/ceVmP2qsw3qwtma/qouvAeDueq3iL7jTpNxs0Mey3FdY8tMnC5oHiMKci
# s+BesdCWWkrQT5iGRryO2VNamtppVCS/wxUXa1pB31ztz87Wsgbdu1e9hj7KUDyi
# J4oQin5H9DjHdp4EaQ04syDuwkM=
# SIG # End signature block