Definitions.psm1

#########################################################################################
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# Licensed under the MIT license.
#
# PSSwagger Module
#
#########################################################################################

Microsoft.PowerShell.Core\Set-StrictMode -Version Latest
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath Utilities.psm1) -DisableNameChecking
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath SwaggerUtils.psm1) -DisableNameChecking
. "$PSScriptRoot\PSSwagger.Constants.ps1" -Force
Microsoft.PowerShell.Utility\Import-LocalizedData  LocalizedData -filename PSSwagger.Resources.psd1

<#
.DESCRIPTION
  Gets Definition function details.
#>

function Get-SwaggerSpecDefinitionInfo
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [PSObject]
        $JsonDefinitionItemObject,

        [Parameter(Mandatory=$true)]
        [PSCustomObject] 
        $DefinitionFunctionsDetails,

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

        [Parameter(Mandatory=$true)]
        [string] 
        $Models
    )

    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState

    $Name = Get-CSharpModelName -Name $JsonDefinitionItemObject.Name
    $FunctionDescription = ""
    if((Get-Member -InputObject $JsonDefinitionItemObject.Value -Name 'Description') -and 
       $JsonDefinitionItemObject.Value.Description)
    {
        $FunctionDescription = $JsonDefinitionItemObject.Value.Description
    }

    $AllOf_DefinitionNames = @()
    $ParametersTable = @{}
    $isModel = $false
    $AllOf_InlineObjects = @()
    if((Get-Member -InputObject $JsonDefinitionItemObject.Value -Name 'AllOf') -and 
       $JsonDefinitionItemObject.Value.'AllOf')
    {
       $JsonDefinitionItemObject.Value.'AllOf' | ForEach-Object {
            if(Get-Member -InputObject $_ -Name '$ref')
            {
                $AllOfRefFullName = $_.'$ref'
                $AllOfRefName = Get-CSharpModelName -Name $AllOfRefFullName.Substring( $( $AllOfRefFullName.LastIndexOf('/') ) + 1 )
                $AllOf_DefinitionNames += $AllOfRefName
                            
                $ReferencedFunctionDetails = @{}
                if($DefinitionFunctionsDetails.ContainsKey($AllOfRefName))
                {
                    $ReferencedFunctionDetails = $DefinitionFunctionsDetails[$AllOfRefName]
                }

                $ReferencedFunctionDetails['Name'] = $AllOfRefName
                $ReferencedFunctionDetails['IsUsedAs_AllOf'] = $true

                $DefinitionFunctionsDetails[$AllOfRefName] = $ReferencedFunctionDetails
            } elseif ((Get-Member -InputObject $_ -Name 'type') -and $_.type -eq 'object') {
                # Create an anonymous type for objects defined inline
                $anonObjName = Get-CSharpModelName -Name ([Guid]::NewGuid().Guid)
                [PSCustomObject]$obj = New-Object -TypeName PsObject
                Add-Member -InputObject $obj -MemberType NoteProperty -Name 'Name' -Value $anonObjName
                Add-Member -InputObject $obj -MemberType NoteProperty -Name 'Value' -Value $_
                Get-SwaggerSpecDefinitionInfo -JsonDefinitionItemObject $obj -DefinitionFunctionsDetails $DefinitionFunctionsDetails -Namespace $Namespace -Models $Models
                $DefinitionFunctionsDetails[$anonObjName]['IsUsedAs_AllOf'] = $true
                $DefinitionFunctionsDetails[$anonObjName]['IsModel'] = $false
                $AllOf_InlineObjects += $DefinitionFunctionsDetails[$anonObjName]
                $isModel = $true
            }
            else {
                $Message = $LocalizedData.UnsupportedSwaggerProperties -f ('JsonDefinitionItemObject', $($_ | Out-String))
                Write-Warning -Message $Message
            }
       }
    }

    Get-DefinitionParameters -JsonDefinitionItemObject $JsonDefinitionItemObject `
                             -DefinitionFunctionsDetails $DefinitionFunctionsDetails `
                             -DefinitionName $Name `
                             -Namespace $Namespace `
                             -ParametersTable $ParametersTable `
                             -Models $Models

    # AutoRest doesn't generate a property for a discriminator property
    if((Get-Member -InputObject $JsonDefinitionItemObject.Value -Name 'discriminator') -and 
       $JsonDefinitionItemObject.Value.'discriminator')
    {
        $discriminator = $JsonDefinitionItemObject.Value.'discriminator'
        if ($ParametersTable.ContainsKey($discriminator)) {
            $ParametersTable[$discriminator]['Discriminator'] = $true
        }
    }

    $FunctionDetails = @{}
    $x_ms_Client_flatten_DefinitionNames = @()
    if($DefinitionFunctionsDetails.ContainsKey($Name))
    {
        $FunctionDetails = $DefinitionFunctionsDetails[$Name]

        if($FunctionDetails.ContainsKey('x_ms_Client_flatten_DefinitionNames'))
        {
            $x_ms_Client_flatten_DefinitionNames = $FunctionDetails.x_ms_Client_flatten_DefinitionNames
        }
    }

    $Unexpanded_AllOf_DefinitionNames = $AllOf_DefinitionNames
    $Unexpanded_x_ms_client_flatten_DefinitionNames = $x_ms_Client_flatten_DefinitionNames
    $ExpandedParameters = (-not $Unexpanded_AllOf_DefinitionNames -and -not $Unexpanded_x_ms_client_flatten_DefinitionNames)

    $FunctionDetails['Name'] = $Name
    $FunctionDetails['Description'] = $FunctionDescription
    # Definition doesn't have Summary property, so using specifying Description as Function Synopsis.
    $FunctionDetails['Synopsis'] = $FunctionDescription
    $FunctionDetails['ParametersTable'] = $ParametersTable
    $FunctionDetails['x_ms_Client_flatten_DefinitionNames'] = $x_ms_Client_flatten_DefinitionNames
    $FunctionDetails['AllOf_DefinitionNames'] = $AllOf_DefinitionNames
    $FunctionDetails['Unexpanded_x_ms_client_flatten_DefinitionNames'] = $Unexpanded_x_ms_client_flatten_DefinitionNames
    $FunctionDetails['Unexpanded_AllOf_DefinitionNames'] = $Unexpanded_AllOf_DefinitionNames
    $FunctionDetails['ExpandedParameters'] = $ExpandedParameters

    $DefinitionType = ""
    $ValidateSet = $null
    if ((Get-HashtableKeyCount -Hashtable $ParametersTable) -lt 1)
    {
        $GetDefinitionParameterType_params = @{
            ParameterJsonObject = $JsonDefinitionItemObject.value
            DefinitionName = $Name
            ModelsNamespace = "$NameSpace.$Models"
            DefinitionFunctionsDetails = $DefinitionFunctionsDetails
        }
        $TypeResult = Get-DefinitionParameterType @GetDefinitionParameterType_params
        $DefinitionType = $TypeResult['ParameterType']
        $ValidateSet = $TypeResult['ValidateSet']
    }
    $FunctionDetails['Type'] = $DefinitionType
    $FunctionDetails['ValidateSet'] = $ValidateSet

    if(-not $FunctionDetails.ContainsKey('IsUsedAs_x_ms_client_flatten'))
    {
        $FunctionDetails['IsUsedAs_x_ms_client_flatten'] = $false
    }

    if(-not $FunctionDetails.ContainsKey('IsUsedAs_AllOf'))
    {
        $FunctionDetails['IsUsedAs_AllOf'] = $false
    }

    if((Get-Member -InputObject $JsonDefinitionItemObject -Name Value) -and
       (Get-Member -InputObject $JsonDefinitionItemObject.Value -Name properties) -and
       ((Get-HashtableKeyCount -Hashtable $JsonDefinitionItemObject.Value.Properties.PSObject.Properties) -ge 1))
    {
        $isModel = $true
    }

    $FunctionDetails['IsModel'] = $isModel
    $AllOf_InlineObjects | ForEach-Object {
        Copy-FunctionDetailsParameters -RefFunctionDetails $_ -FunctionDetails $FunctionDetails
    }
    
    $DefinitionFunctionsDetails[$Name] = $FunctionDetails
}

function Get-DefinitionParameters
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [PSObject]
        $JsonDefinitionItemObject,

        [Parameter(Mandatory=$true)]
        [PSCustomObject] 
        $DefinitionFunctionsDetails,

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

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

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

        [Parameter(Mandatory=$true)]
        [PSCustomObject] 
        $ParametersTable
    )

    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
    if((Get-Member -InputObject $JsonDefinitionItemObject -Name Value) -and
       (Get-Member -InputObject $JsonDefinitionItemObject.Value -Name properties))
    {
        $JsonDefinitionItemObject.Value.properties.PSObject.Properties | ForEach-Object {

            if((Get-Member -InputObject $_ -Name 'Name') -and $_.Name)
            {                
                $ParameterJsonObject = $_.Value
                if ((Get-Member -InputObject $ParameterJsonObject -Name 'x-ms-client-name') -and $ParameterJsonObject.'x-ms-client-name') {
                    $parameterName = Get-PascalCasedString -Name $ParameterJsonObject.'x-ms-client-name'
                } else {
                    $ParameterName = Get-PascalCasedString -Name $_.Name
                }

                if(($ParameterName -eq 'Properties') -and
                   (Get-Member -InputObject $ParameterJsonObject -Name 'x-ms-client-flatten') -and
                   ($ParameterJsonObject.'x-ms-client-flatten') -and
                   (Get-Member -InputObject $ParameterJsonObject -Name 'properties'))
                {
                    # Flatten the properties with x-ms-client-flatten
                    $null = Get-DefinitionParameters -JsonDefinitionItemObject $_ `
                                                     -DefinitionName $DefinitionName `
                                                     -Namespace $Namespace `
                                                     -DefinitionFunctionsDetails $DefinitionFunctionsDetails `
                                                     -ParametersTable $ParametersTable `
                                                     -Models $Models
                }
                else
                {
                    $ParameterDetails = @{}
                    $IsParamMandatory = '$false'
                    $ValidateSetString = $null
                    $ParameterDescription = ''
                    
                    $GetDefinitionParameterType_params = @{
                        ParameterJsonObject        = $ParameterJsonObject
                        DefinitionName             = $DefinitionName
                        ParameterName              = $ParameterName
                        DefinitionFunctionsDetails = $DefinitionFunctionsDetails
                        ModelsNamespace            = "$NameSpace.Models"
                        ParametersTable            = $ParametersTable
                    }
                    $TypeResult = Get-DefinitionParameterType @GetDefinitionParameterType_params
            
                    $ParameterType = $TypeResult['ParameterType']
                    if($TypeResult['ValidateSet']) {
                        $ValidateSetString = "'$($TypeResult['ValidateSet'] -join "', '")'"
                    }
                    if ((Get-Member -InputObject $JsonDefinitionItemObject.Value -Name 'Required') -and 
                        $JsonDefinitionItemObject.Value.Required -and
                        ($JsonDefinitionItemObject.Value.Required -contains $ParameterName) )
                    {
                        $IsParamMandatory = '$true'
                    }

                    if ((Get-Member -InputObject $ParameterJsonObject -Name 'Enum') -and $ParameterJsonObject.Enum)
                    {
                        if(-not ((Get-Member -InputObject $ParameterJsonObject -Name 'x-ms-enum') -and 
                                 $ParameterJsonObject.'x-ms-enum' -and 
                                 (-not (Get-Member -InputObject $ParameterJsonObject.'x-ms-enum' -Name 'modelAsString') -or
                                 ($ParameterJsonObject.'x-ms-enum'.modelAsString -eq $false))))
                        {
                            $EnumValues = $ParameterJsonObject.Enum | ForEach-Object {$_ -replace "'","''"}
                            $ValidateSetString = "'$($EnumValues -join "', '")'"
                        }
                    }

                    if ((Get-Member -InputObject $ParameterJsonObject -Name 'Description') -and $ParameterJsonObject.Description)
                    {
                        $ParameterDescription = $ParameterJsonObject.Description
                    }

                    $ParameterDetails['Name'] = $ParameterName
                    $ParameterDetails['Type'] = $ParameterType
                    $ParameterDetails['ValidateSet'] = $ValidateSetString
                    $ParameterDetails['Mandatory'] = $IsParamMandatory
                    $ParameterDetails['Description'] = $ParameterDescription
                    $ParameterDetails['OriginalParameterName'] = $_.Name

                    if($ParameterType)
                    {
                        $ParametersTable[$ParameterName] = $ParameterDetails
                    }
                }
            }
        } #Properties
    }
}

function Get-DefinitionParameterType
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [PSObject]
        $ParameterJsonObject,

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

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

        [Parameter(Mandatory=$true)]
        [PSCustomObject] 
        $DefinitionFunctionsDetails,

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

        [Parameter(Mandatory=$false)]
        [PSCustomObject] 
        $ParametersTable = @{}
    )

    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState

    $DefinitionTypeNamePrefix = "$ModelsNamespace."

    $ParameterType = $null
    $ValidateSet = $null

    if ((Get-Member -InputObject $ParameterJsonObject -Name 'Type') -and $ParameterJsonObject.Type)
    {
        $ParameterType = $ParameterJsonObject.Type

        # When a definition property has single enum value, AutoRest doesn't generate an enum type.
        if ((Get-Member -InputObject $ParameterJsonObject -Name 'Enum') -and 
            $ParameterJsonObject.Enum -and ($ParameterJsonObject.Enum.Count -gt 1))
        {
            if ((Get-Member -InputObject $ParameterJsonObject -Name 'x-ms-enum') -and
                $ParameterJsonObject.'x-ms-enum' -and
                (-not (Get-Member -InputObject $ParameterJsonObject.'x-ms-enum' -Name 'modelAsString') -or
                ($ParameterJsonObject.'x-ms-enum'.modelAsString -eq $false)))
            {
                $ParameterType = $DefinitionTypeNamePrefix + (Get-CSharpModelName -Name $ParameterJsonObject.'x-ms-enum'.Name)
            }
            else {
                $ValidateSet = $ParameterJsonObject.Enum | ForEach-Object {$_ -replace "'", "''"}
            }
        }
        # Use the format as parameter type if that is available as a type in PowerShell
        elseif ((Get-Member -InputObject $ParameterJsonObject -Name 'Format') -and 
                $ParameterJsonObject.Format -and 
                ($null -ne ($ParameterJsonObject.Format -as [Type])) ) 
        {
            $ParameterType = $ParameterJsonObject.Format
        }
        elseif (($ParameterJsonObject.Type -eq 'array') -and
                (Get-Member -InputObject $ParameterJsonObject -Name 'Items') -and 
                $ParameterJsonObject.Items)
        {
            if((Get-Member -InputObject $ParameterJsonObject.Items -Name '$ref') -and 
                $ParameterJsonObject.Items.'$ref')
            {
                $ReferenceTypeValue = $ParameterJsonObject.Items.'$ref'
                $ReferenceTypeName = Get-CSharpModelName -Name $ReferenceTypeValue.Substring( $( $ReferenceTypeValue.LastIndexOf('/') ) + 1 )                
                $ResolveReferenceParameterType_params = @{
                    DefinitionFunctionsDetails = $DefinitionFunctionsDetails
                    ReferenceTypeName          = $ReferenceTypeName
                    DefinitionTypeNamePrefix   = $DefinitionTypeNamePrefix
                }
                $ResolvedResult = Resolve-ReferenceParameterType @ResolveReferenceParameterType_params
                $ParameterType = $ResolvedResult.ParameterType + '[]'
                if($ResolvedResult.ValidateSet) {
                    $ValidateSet = $ResolvedResult.ValidateSet
                }
            }
            elseif((Get-Member -InputObject $ParameterJsonObject.Items -Name 'Type') -and $ParameterJsonObject.Items.Type)
            {
                $ReferenceTypeName = Get-PSTypeFromSwaggerObject -JsonObject $ParameterJsonObject.Items
                $ParameterType = "$($ReferenceTypeName)[]"
            }
        }
        elseif ((Get-Member -InputObject $ParameterJsonObject -Name 'AdditionalProperties') -and 
                $ParameterJsonObject.AdditionalProperties)
        {
            if($ParameterJsonObject.Type -eq 'object') {                
                if((Get-Member -InputObject $ParameterJsonObject.AdditionalProperties -Name 'Type') -and
                $ParameterJsonObject.AdditionalProperties.Type) {
                    $AdditionalPropertiesType = Get-PSTypeFromSwaggerObject -JsonObject $ParameterJsonObject.AdditionalProperties
                    # Dictionary
                    $ParameterType = "System.Collections.Generic.Dictionary[[$AdditionalPropertiesType],[$AdditionalPropertiesType]]"
                }
                elseif((Get-Member -InputObject $ParameterJsonObject.AdditionalProperties -Name '$ref') -and
                    $ParameterJsonObject.AdditionalProperties.'$ref')
                {
                    $ReferenceTypeValue = $ParameterJsonObject.AdditionalProperties.'$ref'
                    $ReferenceTypeName = Get-CSharpModelName -Name $ReferenceTypeValue.Substring( $( $ReferenceTypeValue.LastIndexOf('/') ) + 1 )
                    $ResolveReferenceParameterType_params = @{
                        DefinitionFunctionsDetails = $DefinitionFunctionsDetails
                        ReferenceTypeName          = $ReferenceTypeName
                        DefinitionTypeNamePrefix   = $DefinitionTypeNamePrefix
                    }
                    $ResolvedResult = Resolve-ReferenceParameterType @ResolveReferenceParameterType_params
                    # Dictionary
                    $ParameterType = "System.Collections.Generic.Dictionary[[string],[$($ResolvedResult.ParameterType)]]"
                }
                else {
                    $Message = $LocalizedData.UnsupportedSwaggerProperties -f ('ParameterJsonObject', $($ParameterJsonObject | Out-String))
                    Write-Warning -Message $Message
                }
            }
            elseif($ParameterJsonObject.Type -eq 'string') {
                if((Get-Member -InputObject $ParameterJsonObject.AdditionalProperties -Name 'Type') -and
                   ($ParameterJsonObject.AdditionalProperties.Type -eq 'array'))
                {
                    if(Get-Member -InputObject $ParameterJsonObject.AdditionalProperties -Name 'Items')
                    {
                        if((Get-Member -InputObject $ParameterJsonObject.AdditionalProperties.Items -Name 'Type') -and
                           $ParameterJsonObject.AdditionalProperties.Items.Type)
                        { 
                            $ItemsType = Get-PSTypeFromSwaggerObject -JsonObject $ParameterJsonObject.AdditionalProperties.Items
                            $ParameterType = "System.Collections.Generic.Dictionary[[string],[System.Collections.Generic.List[$ItemsType]]]"
                        }
                        elseif((Get-Member -InputObject $ParameterJsonObject.AdditionalProperties.Items -Name '$ref') -and
                               $ParameterJsonObject.AdditionalProperties.Items.'$ref')
                        {
                            $ReferenceTypeValue = $ParameterJsonObject.AdditionalProperties.Items.'$ref'
                            $ReferenceTypeName = Get-CSharpModelName -Name $ReferenceTypeValue.Substring( $( $ReferenceTypeValue.LastIndexOf('/') ) + 1 )
                            $ResolveReferenceParameterType_params = @{
                                DefinitionFunctionsDetails = $DefinitionFunctionsDetails
                                ReferenceTypeName          = $ReferenceTypeName
                                DefinitionTypeNamePrefix   = $DefinitionTypeNamePrefix
                            }
                            $ResolvedResult = Resolve-ReferenceParameterType @ResolveReferenceParameterType_params
                            $ParameterType = "System.Collections.Generic.Dictionary[[string],[System.Collections.Generic.List[$($ResolvedResult.ParameterType)]]]"
                        }
                        else
                        {
                            $Message = $LocalizedData.UnsupportedSwaggerProperties -f ('ParameterJsonObject', $($ParameterJsonObject | Out-String))
                            Write-Warning -Message $Message
                        }
                    }
                    else
                    {
                        $Message = $LocalizedData.UnsupportedSwaggerProperties -f ('ParameterJsonObject', $($ParameterJsonObject | Out-String))
                        Write-Warning -Message $Message
                    }
                }
                else
                {
                    $Message = $LocalizedData.UnsupportedSwaggerProperties -f ('ParameterJsonObject', $($ParameterJsonObject | Out-String))
                    Write-Warning -Message $Message
                }
            }
            else {
                $Message = $LocalizedData.UnsupportedSwaggerProperties -f ('ParameterJsonObject', $($ParameterJsonObject | Out-String))
                Write-Warning -Message $Message
            }
        }
    }
    elseif ($ParameterName -and ($ParameterName -eq 'Properties') -and
            (Get-Member -InputObject $ParameterJsonObject -Name 'x-ms-client-flatten') -and 
            ($ParameterJsonObject.'x-ms-client-flatten') )
    {                         
        # 'x-ms-client-flatten' extension allows to flatten deeply nested properties into the current definition.
        # Users often provide feedback that they don't want to create multiple levels of properties to be able to use an operation.
        # By applying the x-ms-client-flatten extension, you move the inner properties to the top level of your definition.

        $ReferenceParameterValue = $ParameterJsonObject.'$ref'
        $ReferenceDefinitionName = Get-CSharpModelName -Name $ReferenceParameterValue.Substring( $( $ReferenceParameterValue.LastIndexOf('/') ) + 1 )

        $x_ms_Client_flatten_DefinitionNames = @($ReferenceDefinitionName)

        Set-TypeUsedAsClientFlatten -ReferenceTypeName $ReferenceDefinitionName -DefinitionFunctionsDetails $DefinitionFunctionsDetails

        # Add/Update FunctionDetails to $DefinitionFunctionsDetails
        $FunctionDetails = @{}
        if($DefinitionFunctionsDetails.ContainsKey($DefinitionName))
        {
            $FunctionDetails = $DefinitionFunctionsDetails[$DefinitionName]
            $FunctionDetails['x_ms_Client_flatten_DefinitionNames'] += $x_ms_Client_flatten_DefinitionNames
        }
        else
        {
            $FunctionDetails['Name'] = $DefinitionName
            $FunctionDetails['x_ms_Client_flatten_DefinitionNames'] = $x_ms_Client_flatten_DefinitionNames
        }

        $DefinitionFunctionsDetails[$DefinitionName] = $FunctionDetails
    }
    elseif ( (Get-Member -InputObject $ParameterJsonObject -Name '$ref') -and ($ParameterJsonObject.'$ref') )
    {
        $ReferenceParameterValue = $ParameterJsonObject.'$ref'        
        $ReferenceTypeName = Get-CSharpModelName -Name $ReferenceParameterValue.Substring( $( $ReferenceParameterValue.LastIndexOf('/') ) + 1 )
        $ResolveReferenceParameterType_params = @{
            DefinitionFunctionsDetails = $DefinitionFunctionsDetails
            ReferenceTypeName          = $ReferenceTypeName
            DefinitionTypeNamePrefix   = $DefinitionTypeNamePrefix
        }
        $ResolvedResult = Resolve-ReferenceParameterType @ResolveReferenceParameterType_params
        $ParameterType = $ResolvedResult.ParameterType
        if($ResolvedResult.ValidateSet) {
            $ValidateSet = $ResolvedResult.ValidateSet
        }
    }
    else
    {
        $ParameterType = 'object'
    }

    $ParameterType = Get-PSTypeFromSwaggerObject -ParameterType $ParameterType

    if($ParameterType -and 
       (-not $ParameterType.Contains($DefinitionTypeNamePrefix)) -and
       ($null -eq ($ParameterType -as [Type])))
    {
        Write-Warning -Message ($LocalizedData.InvalidDefinitionParameterType -f $ParameterType, $ParameterName, $DefinitionName)
    }

    return @{
        ParameterType = $ParameterType
        ValidateSet   = $ValidateSet
    }
}

function Expand-SwaggerDefinition
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [hashtable]
        $DefinitionFunctionsDetails,

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

        [Parameter(Mandatory = $true)]
        [string]
        $Models
    )

    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState

    # Expand the definition parameters from 'AllOf' definitions and x_ms_client-flatten declarations.
    $ExpandedAllDefinitions = $false

    while(-not $ExpandedAllDefinitions)
    {
        $ExpandedAllDefinitions = $true

        $DefinitionFunctionsDetails.GetEnumerator() | ForEach-Object {
            
            $FunctionDetails = $_.Value

            if(-not $FunctionDetails.ExpandedParameters)
            {
                $message = $LocalizedData.ExpandDefinition -f ($FunctionDetails.Name)
                Write-Verbose -Message $message

                $Unexpanded_AllOf_DefinitionNames = @()
                $Unexpanded_AllOf_DefinitionNames += $FunctionDetails.Unexpanded_AllOf_DefinitionNames | ForEach-Object {
                                                        $ReferencedDefinitionName = $_
                                                        if($DefinitionFunctionsDetails.ContainsKey($ReferencedDefinitionName) -and
                                                           $DefinitionFunctionsDetails[$ReferencedDefinitionName].ExpandedParameters)
                                                        {
                                                            $RefFunctionDetails = $DefinitionFunctionsDetails[$ReferencedDefinitionName]
                                                            $RefFunctionDetails.ParametersTable.GetEnumerator() | ForEach-Object {
                                                                $RefParameterName = $_.Name
                                                                if($RefParameterName)
                                                                {
                                                                    if($FunctionDetails.ParametersTable.ContainsKey($RefParameterName))
                                                                    {
                                                                        Write-Verbose -Message ($LocalizedData.SamePropertyName -f ($RefParameterName, $FunctionDetails.Name))
                                                                    }
                                                                    else
                                                                    {
                                                                        $FunctionDetails.ParametersTable[$RefParameterName] = $RefFunctionDetails.ParametersTable[$RefParameterName]
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        else
                                                        {
                                                            $_
                                                        }
                                                    }
                $Unexpanded_x_ms_client_flatten_DefinitionNames = @()
                $Unexpanded_x_ms_client_flatten_DefinitionNames += $FunctionDetails.Unexpanded_x_ms_client_flatten_DefinitionNames | ForEach-Object {
                                                                        $ReferencedDefinitionName = $_
                                                                        if($ReferencedDefinitionName)
                                                                        {
                                                                            if($DefinitionFunctionsDetails.ContainsKey($ReferencedDefinitionName) -and
                                                                               $DefinitionFunctionsDetails[$ReferencedDefinitionName].ExpandedParameters)
                                                                            {
                                                                                $RefFunctionDetails = $DefinitionFunctionsDetails[$ReferencedDefinitionName]
                                                                                Copy-FunctionDetailsParameters -RefFunctionDetails $RefFunctionDetails -FunctionDetails $FunctionDetails
                                                                            }
                                                                            else
                                                                            {
                                                                                $_
                                                                            }
                                                                        }
                                                                    }


                $FunctionDetails.ExpandedParameters = (-not $Unexpanded_AllOf_DefinitionNames -and -not $Unexpanded_x_ms_client_flatten_DefinitionNames)
                $FunctionDetails.Unexpanded_AllOf_DefinitionNames = $Unexpanded_AllOf_DefinitionNames
                $FunctionDetails.Unexpanded_x_ms_client_flatten_DefinitionNames = $Unexpanded_x_ms_client_flatten_DefinitionNames

                if(-not $FunctionDetails.ExpandedParameters)
                {
                    $message = $LocalizedData.UnableToExpandDefinition -f ($FunctionDetails.Name)
                    Write-Verbose -Message $message
                    $ExpandedAllDefinitions = $false
                }
            } # ExpandedParameters
        } # Foeach-Object
    } # while()

    Expand-NonModelDefinition -DefinitionFunctionsDetails $DefinitionFunctionsDetails -NameSpace $NameSpace -Models $Models

    $DefinitionFunctionsDetails.GetEnumerator() | ForEach-Object {
        $FunctionDetails = $_.Value
        if ($FunctionDetails.ContainsKey('UsedAsPathOperationInputType') -and $FunctionDetails.UsedAsPathOperationInputType) {
            Set-GenerateDefinitionCmdlet -DefinitionFunctionsDetails $DefinitionFunctionsDetails -FunctionDetails $FunctionDetails -ModelsNamespaceWithDot "$Namespace.$Models."
        }
    }
}

function New-SwaggerDefinitionCommand
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [hashtable]
        $DefinitionFunctionsDetails,

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

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

        [Parameter(Mandatory = $true)]
        [string]
        $Models,
        
        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $HeaderContent
    )

    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState

    $PSHeaderComment = $null
    $XmlHeaderComment = $null

    if($HeaderContent) {
        $PSHeaderComment = ($PSCommentFormatString -f $HeaderContent)
        $XmlHeaderComment = ($XmlCommentFormatString -f $HeaderContent)
    }

    $FunctionsToExport = @()
    $GeneratedCommandsPath = Join-Path -Path $SwaggerMetaDict['outputDirectory'] -ChildPath $GeneratedCommandsName
    $SwaggerDefinitionCommandsPath = Join-Path -Path $GeneratedCommandsPath -ChildPath 'SwaggerDefinitionCommands'
    $FormatFilesPath = Join-Path -Path $GeneratedCommandsPath -ChildPath 'FormatFiles'

    $DefinitionFunctionsDetails.GetEnumerator() | ForEach-Object {        
        $FunctionDetails = $_.Value
        # Denifitions defined as x_ms_client_flatten are not used as an object anywhere.
        # Also AutoRest doesn't generate a Model class for the definitions declared as x_ms_client_flatten for other definitions.
        if((-not $FunctionDetails.IsUsedAs_x_ms_client_flatten) -and $FunctionDetails.IsModel)
        {
            if ($FunctionDetails.ContainsKey('GenerateDefinitionCmdlet') -and ($FunctionDetails['GenerateDefinitionCmdlet'] -eq $true)) {
                $FunctionsToExport += New-SwaggerSpecDefinitionCommand -FunctionDetails $FunctionDetails `
                                                                    -GeneratedCommandsPath $SwaggerDefinitionCommandsPath `
                                                                    -ModelsNamespace "$Namespace.$Models" `
                                                                    -PSHeaderComment $PSHeaderComment
            }

            New-SwaggerDefinitionFormatFile -FunctionDetails $FunctionDetails `
                                            -FormatFilesPath $FormatFilesPath `
                                            -Namespace $NameSpace `
                                            -Models $Models `
                                            -XmlHeaderComment $XmlHeaderComment
        }
    }

    return $FunctionsToExport
}

function Set-GenerateDefinitionCmdlet
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [hashtable]
        $DefinitionFunctionsDetails,

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

        [Parameter(Mandatory = $true)]
        [string]
        $ModelsNamespaceWithDot
    )

    if($FunctionDetails.ContainsKey('GenerateDefinitionCmdlet') -or -not $FunctionDetails.IsModel)
    {
        return
    }
    $FunctionDetails['GenerateDefinitionCmdlet'] = $true
    
    if($FunctionDetails.ContainsKey('ParametersTable') -and (Get-HashtableKeyCount -Hashtable $FunctionDetails.ParametersTable)) {
        $FunctionDetails.ParametersTable.GetEnumerator() | ForEach-Object {
            Set-GenerateDefinitionCmdletUtility -ParameterType $_.Value.Type -DefinitionFunctionsDetails $DefinitionFunctionsDetails -ModelsNamespaceWithDot $ModelsNamespaceWithDot
        }
    } elseif ($FunctionDetails.ContainsKey('Type') -and $FunctionDetails.Type) {
        Set-GenerateDefinitionCmdletUtility -ParameterType $FunctionDetails.Type -DefinitionFunctionsDetails $DefinitionFunctionsDetails -ModelsNamespaceWithDot $ModelsNamespaceWithDot
    }
}

function Set-GenerateDefinitionCmdletUtility
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [hashtable]
        $DefinitionFunctionsDetails,

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

        [Parameter(Mandatory = $true)]
        [string]
        $ModelsNamespaceWithDot
    )

    $RefDefName = $null
    if ($ParameterType.StartsWith($ModelsNamespaceWithDot, [System.StringComparison]::OrdinalIgnoreCase)) {
        $RefDefName = $ParameterType.Replace($ModelsNamespaceWithDot, '').Replace('[]','')
    } elseif ($ParameterType.StartsWith("System.Collections.Generic.Dictionary[[string],[$ModelsNamespaceWithDot", [System.StringComparison]::OrdinalIgnoreCase)) {
        $RefDefName = $ParameterType.Replace("System.Collections.Generic.Dictionary[[string],[$ModelsNamespaceWithDot", '').Replace(']]','')
    }

    if($RefDefName -and $DefinitionFunctionsDetails.ContainsKey($RefDefName)) {
        $RefDefFunctionDetails = $DefinitionFunctionsDetails[$RefDefName]
        if($RefDefFunctionDetails) {
            Set-GenerateDefinitionCmdlet -FunctionDetails $RefDefFunctionDetails -DefinitionFunctionsDetails $DefinitionFunctionsDetails -ModelsNamespaceWithDot $ModelsNamespaceWithDot
        }
    }
}

function Copy-FunctionDetailsParameters {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        $RefFunctionDetails,

        [Parameter(Mandatory = $true)]
        $FunctionDetails
    )

    $RefFunctionDetails.ParametersTable.GetEnumerator() | ForEach-Object {
                                                                $RefParameterName = $_.Name
                                                                if($RefParameterName)
                                                                {
                                                                    if($FunctionDetails.ParametersTable.ContainsKey($RefParameterName))
                                                                    {
                                                                        Write-Verbose -Message ($LocalizedData.SamePropertyName -f ($RefParameterName, $FunctionDetails.Name))
                                                                    }
                                                                    else
                                                                    {
                                                                        $FunctionDetails.ParametersTable[$RefParameterName] = $RefFunctionDetails.ParametersTable[$RefParameterName]
                                                                    }
                                                                }
                                                            }
}
function Expand-NonModelDefinition
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [hashtable]
        $DefinitionFunctionsDetails,

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

        [Parameter(Mandatory = $true)]
        [string]
        $Models
    )

    $DefinitionFunctionsDetails.GetEnumerator() | ForEach-Object {
        $DefFunctionDetails = $_.Value 

        if(-not $DefFunctionDetails.IsModel) {
            # Replace parameter details from referenced definition details.
            $DefinitionFunctionsDetails.GetEnumerator() | ForEach-Object {
                $FunctionDetails = $_.Value
                $ParamsToBeReplaced = @{}
                if($DefFunctionDetails.ContainsKey('ParametersTable') -and 
                    ((Get-HashtableKeyCount -Hashtable $DefFunctionDetails.ParametersTable) -eq 1)) {
                    $DefFunctionDetails.ParametersTable.GetEnumerator() | ForEach-Object { $SourceDetails = $_.Value }
                } else {
                    $SourceDetails = $DefFunctionDetails
                }

                if(Get-HashtableKeyCount -Hashtable $FunctionDetails.ParametersTable)
                {
                    $FunctionDetails.ParametersTable.GetEnumerator() | ForEach-Object {
                        $ParameterDetails = $_.Value
                        if (($ParameterDetails.Type -eq "$Namespace.$Models.$($DefFunctionDetails.Name)") -or
                            ($ParameterDetails.Type -eq "$Namespace.$Models.$($DefFunctionDetails.Name)[]")) {
                            
                            if($SourceDetails.ContainsKey('Type')) {
                                if($ParameterDetails.Type -eq "$Namespace.$Models.$($DefFunctionDetails.Name)[]") {
                                    $ParameterDetails['Type'] = $SourceDetails.Type + '[]'
                                }
                                else {
                                    $ParameterDetails['Type'] = $SourceDetails.Type
                                }
                            }

                            if($SourceDetails.ContainsKey('ValidateSet')) {
                                if($SourceDetails.ValidateSet.PSTypeNames -contains 'System.Array') {
                                    $ParameterDetails['ValidateSet'] = "'$($SourceDetails.ValidateSet -join "', '")'"
                                }
                                else {
                                    $ParameterDetails['ValidateSet'] = $SourceDetails.ValidateSet
                                }
                            }

                            if((-not $ParameterDetails.Description) -and 
                               $SourceDetails.ContainsKey('Description') -and $SourceDetails.Description)
                            {
                                $ParameterDetails['Description'] = $SourceDetails.Description
                            }

                            $ParamsToBeReplaced[$ParameterDetails.Name] = $ParameterDetails 
                        }
                    }

                    $ParamsToBeReplaced.GetEnumerator() | ForEach-Object {
                        $FunctionDetails.ParametersTable[$_.Key] = $_.Value
                    }
                }
                elseif (($FunctionDetails.Type -eq "$Namespace.$Models.$($DefFunctionDetails.Name)") -and 
                        $SourceDetails.ContainsKey('Type'))
                {
                    $FunctionDetails.Type = $SourceDetails.Type
                }
            }
        }
    }
}

<#
.DESCRIPTION
  Generates a cmdlet for the definition
#>

function New-SwaggerSpecDefinitionCommand
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [PSCustomObject]
        $FunctionDetails,

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

        [Parameter(Mandatory=$true)]
        [string] 
        $ModelsNamespace,
        
        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $PSHeaderComment
    )

    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
    
    $commandName = "New-$($FunctionDetails.Name)Object"

    $description = $FunctionDetails.description
    $synopsis = $FunctionDetails.synopsis
    $commandHelp = $executionContext.InvokeCommand.ExpandString($helpDescStr)

    [string]$paramHelp = ""
    $paramblock = ""
    $body = ""
    $DefinitionTypeNamePrefix = "$ModelsNamespace."
    $ParameterSetPropertyString = ""
    $parameterDefaultValueOption = ""

    $FunctionDetails.ParametersTable.GetEnumerator() | ForEach-Object {
        $ParameterDetails = $_.Value
        if (-not ($ParameterDetails.ContainsKey('Discriminator')) -or (-not $ParameterDetails.Discriminator)) {
            $isParamMandatory = $ParameterDetails.Mandatory
            $parameterName = $ParameterDetails.Name
            $paramName = "`$$parameterName" 
            $paramType = "[$($ParameterDetails.Type)]$([Environment]::NewLine) "
            $AllParameterSetsString = $executionContext.InvokeCommand.ExpandString($parameterAttributeString)
            $ValidateSetDefinition = $null
            if ($ParameterDetails.ValidateSet)
            {
                $ValidateSetString = $ParameterDetails.ValidateSet
                $ValidateSetDefinition = $executionContext.InvokeCommand.ExpandString($ValidateSetDefinitionString)
            }
            $paramblock += $executionContext.InvokeCommand.ExpandString($parameterDefString)

            $pDescription = $ParameterDetails.Description
            $paramHelp += $executionContext.InvokeCommand.ExpandString($helpParamStr)
        }
    }

    $paramblock = $paramBlock.TrimEnd().TrimEnd(",")

    $DefinitionTypeName = $DefinitionTypeNamePrefix + $FunctionDetails.Name
    $body = $executionContext.InvokeCommand.ExpandString($createObjectStr)

    $CommandString = $executionContext.InvokeCommand.ExpandString($advFnSignatureForDefintion)

    if(-not (Test-Path -Path $GeneratedCommandsPath -PathType Container)) {
        $null = New-Item -Path $GeneratedCommandsPath -ItemType Directory
    }

    $CommandFilePath = Join-Path -Path $GeneratedCommandsPath -ChildPath "$CommandName.ps1"
    Out-File -InputObject @($PSHeaderComment, $CommandString) -FilePath $CommandFilePath -Encoding ascii -Force -Confirm:$false -WhatIf:$false

    Write-Verbose -Message ($LocalizedData.GeneratedDefinitionCommand -f ($commandName, $FunctionDetails.Name))

    return $CommandName
}

<#
.DESCRIPTION
  Creates a format file for the given definition details
#>

function New-SwaggerDefinitionFormatFile
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [PSCustomObject]
        $FunctionDetails,

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

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

        [Parameter(Mandatory=$true)]
        [string]
        $Models,
        
        [Parameter(Mandatory=$false)]
        [AllowEmptyString()]
        [string]
        $XmlHeaderComment
    )
    
    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState

    $ViewName = "$Namespace.$Models.$($FunctionDetails.Name)"
    $ViewTypeName = $ViewName
    $TableColumnItemsList = @()
    $TableColumnItemCount = 0

    $FunctionDetails.ParametersTable.GetEnumerator() | ForEach-Object {        
        $ParameterDetails = $_.Value
        # Add all properties otherthan complex typed properties.
        # Complex typed properties are not displayed by the PowerShell Format viewer.
        if(-not $ParameterDetails.Type.StartsWith($Namespace, [System.StringComparison]::OrdinalIgnoreCase))
        {
            $TableColumnItemsList += $TableColumnItemStr -f ($ParameterDetails.Name)
            $TableColumnItemCount += 1
        }
    }

    if(-not $TableColumnItemCount) {
        Write-Verbose -Message ($LocalizedData.FormatFileNotRequired -f $FunctionDetails.Name)
        return    
    }
    
    $TableColumnHeadersList = @()
    $DefaultWindowSizeWidth = 120
    # Getting the width value for each property column. Default console window width is 120.
    $TableColumnHeaderWidth = [int]($DefaultWindowSizeWidth/$TableColumnItemCount)
    
    if ($TableColumnItemCount -ge 2) {
        1..($TableColumnItemCount - 1) | ForEach-Object {
            $TableColumnHeadersList += $TableColumnHeaderStr -f ($TableColumnHeaderWidth)
        }
    }
    # Allowing the last property to get the remaining column width, this is useful when customer increases the default window width.
    $TableColumnHeadersList += $LastTableColumnHeaderStr

    $TableColumnHeaders = $TableColumnHeadersList -join "`r`n"
    $TableColumnItems = $TableColumnItemsList -join "`r`n"
    $FormatViewDefinition = $FormatViewDefinitionStr -f ($ViewName, $ViewTypeName, $TableColumnHeaders, $TableColumnItems, $XmlHeaderComment)

    if(-not (Test-Path -Path $FormatFilesPath -PathType Container))
    {
        $null = New-Item -Path $FormatFilesPath -ItemType Directory
    }
    $FormatFilePath = Join-Path -Path $FormatFilesPath -ChildPath "$($FunctionDetails.Name).ps1xml"
    Out-File -InputObject $FormatViewDefinition -FilePath $FormatFilePath -Encoding ascii -Force -Confirm:$false -WhatIf:$false
    Write-Verbose -Message ($LocalizedData.GeneratedFormatFile -f $FunctionDetails.Name)
}
# SIG # Begin signature block
# MIIarQYJKoZIhvcNAQcCoIIanjCCGpoCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUpREqi4BmcBqE7W24YjDcKUGA
# J2SgghWAMIIEwjCCA6qgAwIBAgITMwAAALu2dyRxSiAAIAAAAAAAuzANBgkqhkiG
# 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw
# HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTYwOTA3MTc1ODQ3
# WhcNMTgwOTA3MTc1ODQ3WjCBsjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjEMMAoGA1UECxMDQU9DMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046
# MERFOC0yREM1LTNDQTkxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNl
# cnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC48+U38sLxQNu8
# OO1wnT9mKeHv+f/jxafTFXzx9VF59IK/n/jLv4HIXt8ucy3KjBTM5Jf6D0nQlI4h
# Sizjrn6lO61q+V8oZiYYhjgR258rg8MDIrPpZMxK6OmD0d1wtksHW1cG21YKg5jg
# idT2hmQBpiL9Cra3ccY5keu0kl6OfZFoj4DF0i0JRVFSy1C9gKP4H950XIjlA2Yo
# TWN0LuHEHYMvwD1mOpAq2dVwPZh6xeNnpV8U/qLneyb9I/SqY/87tsZCn4FH7R3x
# 0TgK2eRwpWXfwGbUb1R/UTLd20aQ+my4NWwSsndeG+0vsYwaF40heB2lo1ThmByr
# OTBmEosTAgMBAAGjggEJMIIBBTAdBgNVHQ4EFgQUj9yNX+4+R8GZ7rcy4MdnJHXO
# KkswHwYDVR0jBBgwFoAUIzT42VJGcArtQPt2+7MrsMM1sw8wVAYDVR0fBE0wSzBJ
# oEegRYZDaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv
# TWljcm9zb2Z0VGltZVN0YW1wUENBLmNybDBYBggrBgEFBQcBAQRMMEowSAYIKwYB
# BQUHMAKGPGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljcm9z
# b2Z0VGltZVN0YW1wUENBLmNydDATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG
# 9w0BAQUFAAOCAQEAcMI8Q0PxQVvxZSD1fjszuD6VF/qPZjKZj9WLTjWjZT2k9lzG
# yvSL7vy9J7lnyMATrbm5ptqAfdonNygLaBm05MnrIvgPJYK89wyTIyS1u71ro7z+
# EVrGPaKZiD+WvH8SWP+OWZQNf55fEL8tZo+a1oHm3lUARi5rR916OQvb4UnCENyV
# g8IfmupnwpxHcmIBUWZtTKAuKmuX/c8G2z4KJ8WhruYjPDWYQXJrQ5t7PhZa19Ge
# kOOtigge9EKIAWhZUJkw9fnfRm2IFX0gWtOzRXVNhR109ISacbNxd0oUboRYHmlq
# wGrOz64/3SDdOeN7PjvLwFmThuoXIsxrjQD8ODCCBOswggPToAMCAQICEzMAAAF4
# JVq1zSPGX5UAAQAAAXgwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMCVVMxEzAR
# BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
# Y3Jvc29mdCBDb3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWljcm9zb2Z0IENvZGUgU2ln
# bmluZyBQQ0EwHhcNMTcwODExMjAxMTE1WhcNMTgwODExMjAxMTE1WjCBgjELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEMMAoGA1UECxMDQU9DMR4w
# HAYDVQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUA
# A4IBDwAwggEKAoIBAQCZbh1TVaudsrIbXUPPB9c8S+E+dKSbskHKYlG6SGTH8jhT
# hpuvGiAO87F2b9GHVN+DvszaMkGy/xQgHaGEJLfpnb3kpakic7E0bjDHdG4KnHRb
# no/wfUkGLfS79o+cw//RY8Ck6yE+0czDBcxp0Gbw5JyGP+KFqvzRR/3Tv3nt/5x0
# 5ZnEOHYP+eDVikDvn/DH+oxxtiCfX3tkvtm/yX4eOb47YdmYKQjCgz2+Nil/lupY
# vU0QFIjvke3jshqQINDng/vO9ys2qA0ex/q5hlLKQTST99dGoM86Ge6F723ReToq
# KnGLN8kiCG7uNapOAIQrpCHZq96CVumiaA5ZvxU9AgMBAAGjggFgMIIBXDATBgNV
# HSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUjuhtD3FD7tk/RKloJFX05cpgLjcw
# UQYDVR0RBEowSKRGMEQxDDAKBgNVBAsTA0FPQzE0MDIGA1UEBRMrMjI5ODAzKzFh
# YmY5ZTVmLWNlZDAtNDJlNi1hNjVkLWQ5MzUwOTU5ZmUwZTAfBgNVHSMEGDAWgBTL
# EejK0rQWWAHJNy4zFha5TJoKHzBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3Js
# Lm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNDb2RTaWdQQ0FfMDgt
# MzEtMjAxMC5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY0NvZFNpZ1BDQV8wOC0zMS0y
# MDEwLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAYnG/oHG/xgZYR8NAMHZ/vE9GM0e4
# 7YdhuTea2uY7pSGwM707wp8Wan0Fa6evK1PWfcd/XNOh2BpEv5o8RmKDoEsG0ECP
# 13Jug7cklfKreBVHQ+Djg43VVFLZpuo7aOAVK6wjlcnpPUtn+SfH9K0aM2FjDKVJ
# FW6XFKXBat5R+Zp6uOxWTxpSeMTeDC5zF6IY6ogR1uzU+9EQoRlAvkwX6po+exEL
# nMLr4++P+fqOxIU+PODIoB8ijClAqwwKvLlMPa3qlrNHt+LweTMu7lvGC/RA18wU
# zzXAeomuZ03blUw+bkOiVgWOk4S0RN7EnW7zjJV8gd/+G2dbToUi1cB/fTCCBbww
# ggOkoAMCAQICCmEzJhoAAAAAADEwDQYJKoZIhvcNAQEFBQAwXzETMBEGCgmSJomT
# 8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMk
# TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDgzMTIy
# MTkzMloXDTIwMDgzMTIyMjkzMloweTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0Ew
# ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCycllcGTBkvx2aYCAgQpl2
# U2w+G9ZvzMvx6mv+lxYQ4N86dIMaty+gMuz/3sJCTiPVcgDbNVcKicquIEn08Gis
# TUuNpb15S3GbRwfa/SXfnXWIz6pzRH/XgdvzvfI2pMlcRdyvrT3gKGiXGqelcnNW
# 8ReU5P01lHKg1nZfHndFg4U4FtBzWwW6Z1KNpbJpL9oZC/6SdCnidi9U3RQwWfjS
# jWL9y8lfRjFQuScT5EAwz3IpECgixzdOPaAyPZDNoTgGhVxOVoIoKgUyt0vXT2Pn
# 0i1i8UU956wIAPZGoZ7RW4wmU+h6qkryRs83PDietHdcpReejcsRj1Y8wawJXwPT
# AgMBAAGjggFeMIIBWjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLEejK0rQW
# WAHJNy4zFha5TJoKHzALBgNVHQ8EBAMCAYYwEgYJKwYBBAGCNxUBBAUCAwEAATAj
# BgkrBgEEAYI3FQIEFgQU/dExTtMmipXhmGA7qDFvpjy82C0wGQYJKwYBBAGCNxQC
# BAweCgBTAHUAYgBDAEEwHwYDVR0jBBgwFoAUDqyCYEBWJ5flJRP8KuEKU5VZ5KQw
# UAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9j
# cmwvcHJvZHVjdHMvbWljcm9zb2Z0cm9vdGNlcnQuY3JsMFQGCCsGAQUFBwEBBEgw
# RjBEBggrBgEFBQcwAoY4aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0
# cy9NaWNyb3NvZnRSb290Q2VydC5jcnQwDQYJKoZIhvcNAQEFBQADggIBAFk5Pn8m
# Rq/rb0CxMrVq6w4vbqhJ9+tfde1MOy3XQ60L/svpLTGjI8x8UJiAIV2sPS9MuqKo
# VpzjcLu4tPh5tUly9z7qQX/K4QwXaculnCAt+gtQxFbNLeNK0rxw56gNogOlVuC4
# iktX8pVCnPHz7+7jhh80PLhWmvBTI4UqpIIck+KUBx3y4k74jKHK6BOlkU7IG9KP
# cpUqcW2bGvgc8FPWZ8wi/1wdzaKMvSeyeWNWRKJRzfnpo1hW3ZsCRUQvX/TartSC
# Mm78pJUT5Otp56miLL7IKxAOZY6Z2/Wi+hImCWU4lPF6H0q70eFW6NB4lhhcyTUW
# X92THUmOLb6tNEQc7hAVGgBd3TVbIc6YxwnuhQ6MT20OE049fClInHLR82zKwexw
# o1eSV32UjaAbSANa98+jZwp0pTbtLS8XyOZyNxL0b7E8Z4L5UrKNMxZlHg6K3RDe
# ZPRvzkbU0xfpecQEtNP7LN8fip6sCvsTJ0Ct5PnhqX9GuwdgR2VgQE6wQuxO7bN2
# edgKNAltHIAxH+IOVN3lofvlRxCtZJj/UBYufL8FIXrilUEnacOTj5XJjdibIa4N
# XJzwoq6GaIMMai27dmsAHZat8hZ79haDJLmIz2qoRzEvmtzjcT3XAH5iR9HOiMm4
# GPoOco3Boz2vAkBq/2mbluIQqBC0N1AI1sM9MIIGBzCCA++gAwIBAgIKYRZoNAAA
# AAAAHDANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZImiZPyLGQBGRYDY29tMRkwFwYK
# CZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQDEyRNaWNyb3NvZnQgUm9vdCBD
# ZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcwNDAzMTI1MzA5WhcNMjEwNDAzMTMw
# MzA5WjB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEwHwYD
# VQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwggEiMA0GCSqGSIb3DQEBAQUA
# A4IBDwAwggEKAoIBAQCfoWyx39tIkip8ay4Z4b3i48WZUSNQrc7dGE4kD+7Rp9FM
# rXQwIBHrB9VUlRVJlBtCkq6YXDAm2gBr6Hu97IkHD/cOBJjwicwfyzMkh53y9Gcc
# LPx754gd6udOo6HBI1PKjfpFzwnQXq/QsEIEovmmbJNn1yjcRlOwhtDlKEYuJ6yG
# T1VSDOQDLPtqkJAwbofzWTCd+n7Wl7PoIZd++NIT8wi3U21StEWQn0gASkdmEScp
# ZqiX5NMGgUqi+YSnEUcUCYKfhO1VeP4Bmh1QCIUAEDBG7bfeI0a7xC1Un68eeEEx
# d8yb3zuDk6FhArUdDbH895uyAc4iS1T/+QXDwiALAgMBAAGjggGrMIIBpzAPBgNV
# HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQjNPjZUkZwCu1A+3b7syuwwzWzDzALBgNV
# HQ8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwgZgGA1UdIwSBkDCBjYAUDqyCYEBW
# J5flJRP8KuEKU5VZ5KShY6RhMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAXBgoJ
# kiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290IENl
# cnRpZmljYXRlIEF1dGhvcml0eYIQea0WoUqgpa1Mc1j0BxMuZTBQBgNVHR8ESTBH
# MEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0
# cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEESDBGMEQGCCsGAQUF
# BzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jvc29m
# dFJvb3RDZXJ0LmNydDATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQUF
# AAOCAgEAEJeKw1wDRDbd6bStd9vOeVFNAbEudHFbbQwTq86+e4+4LtQSooxtYrhX
# AstOIBNQmd16QOJXu69YmhzhHQGGrLt48ovQ7DsB7uK+jwoFyI1I4vBTFd1Pq5Lk
# 541q1YDB5pTyBi+FA+mRKiQicPv2/OR4mS4N9wficLwYTp2OawpylbihOZxnLcVR
# DupiXD8WmIsgP+IHGjL5zDFKdjE9K3ILyOpwPf+FChPfwgphjvDXuBfrTot/xTUr
# XqO/67x9C0J71FNyIe4wyrt4ZVxbARcKFA7S2hSY9Ty5ZlizLS/n+YWGzFFW6J1w
# lGysOUzU9nm/qhh6YinvopspNAZ3GmLJPR5tH4LwC8csu89Ds+X57H2146SodDW4
# TsVxIxImdgs8UoxxWkZDFLyzs7BNZ8ifQv+AeSGAnhUwZuhCEl4ayJ4iIdBD6Svp
# u/RIzCzU2DKATCYqSCRfWupW76bemZ3KOm+9gSd0BhHudiG/m4LBJ1S2sWo9iaF2
# YbRuoROmv6pH8BJv/YoybLL+31HIjCPJZr2dHYcSZAI9La9Zj7jkIeW1sMpjtHhU
# BdRBLlCslLCleKuzoJZ1GtmShxN1Ii8yqAhuoFuMJb+g74TKIdbrHk/Jmu5J4PcB
# ZW+JC33Iacjmbuqnl84xKf8OxVtc2E0bodj6L54/LlUWa8kTo/0xggSXMIIEkwIB
# ATCBkDB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSMwIQYD
# VQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQQITMwAAAXglWrXNI8ZflQAB
# AAABeDAJBgUrDgMCGgUAoIGwMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwG
# CisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTMklNn
# tH2vYWvWDV+86DdIsgE/XzBQBgorBgEEAYI3AgEMMUIwQKAWgBQAUABvAHcAZQBy
# AFMAaABlAGwAbKEmgCRodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUG93ZXJTaGVs
# bCAwDQYJKoZIhvcNAQEBBQAEggEAdIQ7x333DjiQ+D2Ign6fj/Ew93dkmPzE48yt
# XZfBRK6hUKKkwiDoaPMaRQ6jonMWb6VfDkZhSkVG47WcWXvIeR/3HCWE6E3HaFuq
# FZ3aYQdpXwyyHYFc2yVfZRzHEuz+58Q4JwH4Rp9UOu4Mmxr8meEZDzy8u0BbBx1n
# lNiouXwGg/Ku0R6Uix1cMs7b48cK1EuvjPmTLj2Zua23XA2lWYh/fEu8ucsY+xH3
# C/hSjz6xfrgF8XX4TcAFdG/vgYuYeYJDysIOq9NLna0ZkWjYTwTgCjeqpU8Hnxxt
# swnI96QHDTFi/qJXXWTtUIn6ZvHAUbuBBbnWAWkzKrYIH6otYaGCAigwggIkBgkq
# hkiG9w0BCQYxggIVMIICEQIBATCBjjB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EC
# EzMAAAC7tnckcUogACAAAAAAALswCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzEL
# BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE3MTAxMDIwNDc1MlowIwYJKoZI
# hvcNAQkEMRYEFPJLoJdzbopZOKBZtSVqIG7/I1IDMA0GCSqGSIb3DQEBBQUABIIB
# ACRF+7tgpwcmWBP+mNxVcQJ0FMFEkz23yqBiBi2pSu2a2M/8RrhGcg+bKyiBxBrb
# Xbf1hF+M+cgupHdKKUt3czaklI7Fl1L+/COAHBarAo9nLsRUnAuoMhohwiDKmH/w
# L0F2/oOf/WldGifokaRgzkeHHSsHNrfLacDqfJcF9/ipzKDh6Uaorlzd7bI9kiml
# zwCT0iQQ71WVy+AK2BEmkS2frGxy7F+Q9X8Y2BHpVfyBqtvO+q5Ni7MBQW3Rc+5w
# lOVAFhy35HnlZO72hYGNT2j7GKMd6GlxzbM7ptbU7JgtPh1FTRsRfRuWci4xQa1n
# I/lXwrLnDvw6SdBzd6W/+jg=
# SIG # End signature block