Library/New-WinGetSource.ps1

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
Function New-WinGetSource
{
    <#
    .SYNOPSIS
    Creates a Windows Package Manager REST source in Azure.

    .DESCRIPTION
    Creates a Windows Package Manager REST source in Azure.

    .PARAMETER Name
    The base name of Azure Resources (Windows Package Manager REST source components) that will be created.

    .PARAMETER ResourceGroup
    [Optional] The name of the Resource Group that the Windows Package Manager REST source will reside. All Azure
    Resources will be created in in this Resource Group (Default: WinGetRestSource)

    .PARAMETER SubscriptionName
    [Optional] The name of the subscription that will be used to host the Windows Package Manager REST source. (Default: Current connected subscription)

    .PARAMETER Region
    [Optional] The Azure location where Azure Resources (Windows Package Manager REST source components) will be created in. (Default: westus)

    .PARAMETER TemplateFolderPath
    [Optional] The directory containing required ARM templates. (Default: $PSScriptRoot\..\Data\ARMTemplates)

    .PARAMETER ParameterOutputPath
    [Optional] The directory where ARM Template Parameter files will be created in. (Default: Current Directory\Parameters)

    .PARAMETER RestSourcePath
    [Optional] Path to the compiled Azure Function (Windows Package Manager REST source) Zip file. (Default: $PSScriptRoot\..\Data\WinGet.RestSource.Functions.zip)

    .PARAMETER PublisherName
    [Optional] The Windows Package Manager REST source publisher name. (Default: Signed in user email Or WinGetRestSource@DomainName)

    .PARAMETER PublisherEmail
    [Optional] The Windows Package Manager REST source publisher email. (Default: Signed in user email Or WinGetRestSource@DomainName)

    .PARAMETER ImplementationPerformance
    [Optional] ["Developer", "Basic", "Enhanced"] specifies the performance of the Azure Resources to be created for the Windows Package Manager REST source.
    | Preference | Description |
    |------------|-------------------------------------------------------------------------------------------------------------------------|
    | Developer | Specifies lowest cost for developing the Windows Package Manager REST source. Uses free-tier options when available. |
    | Basic | Specifies a basic functioning Windows Package Manager REST source. |
    | Enhanced | Specifies a higher tier functionality with data replication across multiple data centers. |

    (Default: Basic)

    .PARAMETER RestSourceAuthentication
    [Optional] ["None", "MicrosoftEntraId"] The Windows Package Manager REST source authentication type. (Default: None)

    .PARAMETER CreateNewMicrosoftEntraIdAppRegistration
    [Optional] If specified, a new Microsoft Entra Id app registration will be created. (Default: False)

    .PARAMETER MicrosoftEntraIdResource
    [Optional] Microsoft Entra Id authentication resource. (Default: None)

    .PARAMETER MicrosoftEntraIdResourceScope
    [Optional] Microsoft Entra Id authentication resource scope. (Default: None)

    .PARAMETER ShowConnectionInstructions
    [Optional] If specified, shows the instructions for connecting to the Windows Package Manager REST source. (Default: False)

    .PARAMETER MaxRetryCount
    [Optional] Max ARM Templates deployment retry count upon failure. (Default: 5)

    .EXAMPLE
    New-WinGetSource -Name "contosorestsource" -InformationAction Continue -Verbose

    Creates the Windows Package Manager REST source in Azure with resources named "contosorestsource" in the westus region of
    Azure with the basic level performance.

    .EXAMPLE
    New-WinGetSource -Name "contosorestsource" -ResourceGroup "WinGet" -SubscriptionName "Visual Studio Subscription" -Region "westus" -ParameterOutput "C:\WinGet" -ImplementationPerformance "Basic" -ShowConnectionInformation -InformationAction Continue -Verbose

    Creates the Windows Package Manager REST source in Azure with resources named "contosorestsource" in the westus region of
    Azure with the basic level performance in the "Visual Studio Subscription" subscription. Displays the required command
    to connect the WinGet client to the new Windows Package Manager REST source after the source has been created.
 
    .EXAMPLE
    New-WinGetSource -Name "contosorestsource" -RestSourceAuthentication "MicrosoftEntraId" -CreateNewMicrosoftEntraIdAppRegistration -ShowConnectionInformation -InformationAction Continue -Verbose

    Creates the Windows Package Manager REST source in Azure with resources named "contosorestsource" in the westus region of
    Azure with the basic level performance. The Windows Package Manager REST source is protected with Microsoft Entra Id authentication.
    A new Microsoft Entra Id app registration is created.
 
    .EXAMPLE
    New-WinGetSource -Name "contosorestsource" -RestSourceAuthentication "MicrosoftEntraId" -MicrosoftEntraIdResource "GUID" -MicrosoftEntraIdResourceScope "user-impersonation" -ShowConnectionInformation -InformationAction Continue -Verbose

    Creates the Windows Package Manager REST source in Azure with resources named "contosorestsource" in the westus region of
    Azure with the basic level performance. The Windows Package Manager REST source is protected with Microsoft Entra Id authentication.
    Uses existing Microsoft Entra Id app registration.

    #>

    PARAM(
        [Parameter(Position=0, Mandatory=$true)] [string]$Name,
        [Parameter(Mandatory=$false)] [string]$ResourceGroup = "WinGetRestSource",
        [Parameter(Mandatory=$false)] [string]$SubscriptionName = "",
        [Parameter(Mandatory=$false)] [string]$Region = "westus",
        [Parameter(Mandatory=$false)] [string]$TemplateFolderPath = "$PSScriptRoot\..\Data\ARMTemplates",
        [Parameter(Mandatory=$false)] [string]$ParameterOutputPath = "$($(Get-Location).Path)\Parameters",
        [Parameter(Mandatory=$false)] [string]$RestSourcePath = "$PSScriptRoot\..\Data\WinGet.RestSource.Functions.zip",
        [Parameter(Mandatory=$false)] [string]$PublisherName = "",
        [Parameter(Mandatory=$false)] [string]$PublisherEmail = "",
        [ValidateSet("Developer", "Basic", "Enhanced")]
        [Parameter(Mandatory=$false)] [string]$ImplementationPerformance = "Basic",
        [ValidateSet("None", "MicrosoftEntraId")]
        [Parameter(Mandatory=$false)] [string]$RestSourceAuthentication = "None",
        [Parameter()] [switch]$CreateNewMicrosoftEntraIdAppRegistration,
        [Parameter(Mandatory=$false)] [string]$MicrosoftEntraIdResource = "",
        [Parameter(Mandatory=$false)] [string]$MicrosoftEntraIdResourceScope = "",
        [Parameter()] [switch]$ShowConnectionInstructions,
        [Parameter(Mandatory=$false)] [int]$MaxRetryCount = 5
    )

    if($ImplementationPerformance -eq "Developer") {
        Write-Warning "The ""Developer"" build creates the Azure Cosmos DB Account with the ""Free-tier"" option selected which offset the total cost. Only 1 Cosmos DB Account per tenant can make use of this tier.`n"
    }

    $TemplateFolderPath = [System.IO.Path]::GetFullPath($TemplateFolderPath, $pwd.Path)
    $ParameterOutputPath = [System.IO.Path]::GetFullPath($ParameterOutputPath, $pwd.Path)
    $RestSourcePath = [System.IO.Path]::GetFullPath($RestSourcePath, $pwd.Path)

    ###############################
    ## Check input paths
    if (!$(Test-Path -Path $TemplateFolderPath)) {
        Write-Error "REST Source Function Code is missing in specified path ($TemplateFolderPath)"
        return $false
    }
    if (!$(Test-Path -Path $RestSourcePath)) {
        Write-Error "REST Source Function Code is missing in specified path ($RestSourcePath)"
        return $false
    }

    ###############################
    ## Check Microsoft Entra Id input
    if ($RestSourceAuthentication -eq "MicrosoftEntraId" -and !$CreateNewMicrosoftEntraIdAppRegistration -and !$MicrosoftEntraIdResource) {
        Write-Error "When Microsoft Entra Id authentication is requested, either CreateNewMicrosoftEntraIdAppRegistration should be requested or MicrosoftEntraIdResource should be provided."
        return $false
    }

    ###############################
    ## Create folder for the Parameter output path
    $Result = New-Item -ItemType Directory -Path $ParameterOutputPath -Force
    if ($Result) {
        Write-Verbose -Message "Created Directory to contain the ARM Parameter files ($($Result.FullName))."
    }
    else {
        Write-Error "Failed to create ARM parameter files output path. Path: $ParameterOutputPath"
        return $false
    }

    ###############################
    ## Connects to Azure, if not already connected.
    Write-Information "Validating connection to azure, will attempt to connect if not already connected."
    $Result = Connect-ToAzure -SubscriptionName $SubscriptionName
    if (!($Result)) {
        Write-Error "Failed to connect to Azure. Please run Connect-AzAccount to connect to Azure, or re-run the cmdlet and enter your credentials."
        return $false
    }

    ###############################
    ## Create new Microsoft Entra Id app registration if requested
    if ($RestSourceAuthentication -eq "MicrosoftEntraId" -and $CreateNewMicrosoftEntraIdAppRegistration) {
        $Result = New-MicrosoftEntraIdApp -Name $Name
        if (!$Result.Result) {
            Write-Error "Failed to create new Microsoft Entra Id app registration."
            return $false
        }
        else {
            $MicrosoftEntraIdResource = $Result.Resource
            $MicrosoftEntraIdResourceScope = $Result.ResourceScope
        }
    }

    ###############################
    ## Creates the ARM files
    $ARMObjects = New-ARMParameterObjects -ParameterFolderPath $ParameterOutputPath -TemplateFolderPath $TemplateFolderPath -Name $Name -Region $Region -ImplementationPerformance $ImplementationPerformance -PublisherName $PublisherName -PublisherEmail $PublisherEmail -RestSourceAuthentication $RestSourceAuthentication -MicrosoftEntraIdResource $MicrosoftEntraIdResource -MicrosoftEntraIdResourceScope $MicrosoftEntraIdResourceScope
    if (!$ARMObjects) {
        Write-Error "Failed to create ARM parameter objects."
        return $false
    }

    ###############################
    ## Create Resource Group
    Write-Information "Creating the Resource Group used to host the Windows Package Manager REST source. Name: $ResourceGroup, Region: $Region"
    $Result = Add-AzureResourceGroup -Name $ResourceGroup -Region $Region
    if (!$Result) {
        Write-Error "Failed to create Azure resource group. Name: $ResourceGroup Region: $Region"
        return $false
    }

    ###############################
    ## Verifies ARM Parameters are correct. If any failed, the return results will contain failed objects. Otherwise, success.
    $Result = Test-ARMTemplates -ARMObjects $ARMObjects -ResourceGroup $ResourceGroup
    if($Result){
        $ErrReturnObject = @{
            ARMObjects    = $ARMObjects
            ResourceGroup = $ResourceGroup
            Result        = $Result
        }

        Write-Error -Message "Testing found an error with the ARM template or parameter files. Error: $err" -TargetObject $ErrReturnObject
        return $false
    }

    ###############################
    ## Creates Azure Objects with ARM Templates and Parameters
    $Attempt = 0
    $Retry = $false
    do {
        $Attempt++
        $Retry = $false

        $Result = New-ARMObjects -ARMObjects ([ref]$ARMObjects) -RestSourcePath $RestSourcePath -ResourceGroup $ResourceGroup
        if (!$Result) {
            if ($Attempt -lt $MaxRetryCount) {
                $Retry = $true
                Write-Verbose "Retrying deployment after 15 seconds."
                Start-Sleep -Seconds 15
            }
            else {
                Write-Error "Failed to create Azure resources for WinGet rest source."
                return $false
            }
        }
    } while ($Retry)

    ###############################
    ## Shows how to connect local Windows Package Manager Client to newly created REST source
    if($ShowConnectionInstructions) {
        $ApiManagementName  = $ARMObjects.Where({$_.ObjectType -eq "ApiManagement"}).Parameters.Parameters.serviceName.value
        $ApiManagementURL   = (Get-AzApiManagement -Name $ApiManagementName -ResourceGroupName $ResourceGroup).RuntimeUrl

        ## Post script Run Informational:
        #### Instructions on how to add the REST source to your Windows Package Manager Client
        Write-Information -MessageData "Use the following command to register the new REST source with your Windows Package Manager Client:" -InformationAction Continue
        Write-Information -MessageData " winget source add -n ""$Name"" -a ""$ApiManagementURL/winget/"" -t ""Microsoft.Rest""" -InformationAction Continue

        #### For more information about how to use the solution, visit the aka.ms link.
        Write-Information -MessageData "`nFor more information on the Windows Package Manager Client, go to: https://aka.ms/winget-command-help`n" -InformationAction Continue
    }

    return $true
}

# SIG # Begin signature block
# MIIoUQYJKoZIhvcNAQcCoIIoQjCCKD4CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCARzvMB0n5Pup5c
# pCc08GnaYLcvTMYsmvhKqndUmza6yKCCDYUwggYDMIID66ADAgECAhMzAAAEA73V
# lV0POxitAAAAAAQDMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTEzWhcNMjUwOTExMjAxMTEzWjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQCfdGddwIOnbRYUyg03O3iz19XXZPmuhEmW/5uyEN+8mgxl+HJGeLGBR8YButGV
# LVK38RxcVcPYyFGQXcKcxgih4w4y4zJi3GvawLYHlsNExQwz+v0jgY/aejBS2EJY
# oUhLVE+UzRihV8ooxoftsmKLb2xb7BoFS6UAo3Zz4afnOdqI7FGoi7g4vx/0MIdi
# kwTn5N56TdIv3mwfkZCFmrsKpN0zR8HD8WYsvH3xKkG7u/xdqmhPPqMmnI2jOFw/
# /n2aL8W7i1Pasja8PnRXH/QaVH0M1nanL+LI9TsMb/enWfXOW65Gne5cqMN9Uofv
# ENtdwwEmJ3bZrcI9u4LZAkujAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU6m4qAkpz4641iK2irF8eWsSBcBkw
# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzUwMjkyNjAfBgNVHSMEGDAW
# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw
# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx
# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB
# AFFo/6E4LX51IqFuoKvUsi80QytGI5ASQ9zsPpBa0z78hutiJd6w154JkcIx/f7r
# EBK4NhD4DIFNfRiVdI7EacEs7OAS6QHF7Nt+eFRNOTtgHb9PExRy4EI/jnMwzQJV
# NokTxu2WgHr/fBsWs6G9AcIgvHjWNN3qRSrhsgEdqHc0bRDUf8UILAdEZOMBvKLC
# rmf+kJPEvPldgK7hFO/L9kmcVe67BnKejDKO73Sa56AJOhM7CkeATrJFxO9GLXos
# oKvrwBvynxAg18W+pagTAkJefzneuWSmniTurPCUE2JnvW7DalvONDOtG01sIVAB
# +ahO2wcUPa2Zm9AiDVBWTMz9XUoKMcvngi2oqbsDLhbK+pYrRUgRpNt0y1sxZsXO
# raGRF8lM2cWvtEkV5UL+TQM1ppv5unDHkW8JS+QnfPbB8dZVRyRmMQ4aY/tx5x5+
# sX6semJ//FbiclSMxSI+zINu1jYerdUwuCi+P6p7SmQmClhDM+6Q+btE2FtpsU0W
# +r6RdYFf/P+nK6j2otl9Nvr3tWLu+WXmz8MGM+18ynJ+lYbSmFWcAj7SYziAfT0s
# IwlQRFkyC71tsIZUhBHtxPliGUu362lIO0Lpe0DOrg8lspnEWOkHnCT5JEnWCbzu
# iVt8RX1IV07uIveNZuOBWLVCzWJjEGa+HhaEtavjy6i7MIIHejCCBWKgAwIBAgIK
# YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV
# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv
# c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm
# aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw
# OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD
# VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la
# UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc
# 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D
# dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+
# lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk
# kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6
# A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd
# X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL
# 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd
# sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3
# T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS
# 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI
# bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL
# BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD
# uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv
# c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
# MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
# MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF
# BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h
# cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA
# YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn
# 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7
# v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b
# pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/
# KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy
# CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp
# mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi
# hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb
# BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS
# oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL
# gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX
# cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGiIwghoeAgEBMIGVMH4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAQDvdWVXQ87GK0AAAAA
# BAMwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIA4i
# tUGpkNyEdgZqyRFXUljVqt5t0rDrBFBoF+cdqHPyMEIGCisGAQQBgjcCAQwxNDAy
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20wDQYJKoZIhvcNAQEBBQAEggEAF6nF4Xx+6dybJ4iuJ1jxQ41MtJXGVJL9+Lhg
# d6ITH8lMLuIoGSnUi1QY32KrYUr0kK9lXL9I91f6NINX71tJRYIqdWSn4woFEyV5
# p2GKXZs04jL/XGit49FtbPT9d8V0j0WkA8yL3E1bnct5CQGi7tErGUEr233K2Ok0
# zRmtT9HpWoinnUhAbuOCydipt19zOnvhic7WZGYbN+8NQVbF4nqe9zXmTXPjG0R3
# qgnrKkyryA0u5iEkwxalZIIdiW8Mxvby1hndJ5cD2wLMRKTUesh/LlCiCEcEIHxN
# kX+ubdT/kcZ8BNsxtFWKKFuMy7rPUlnj0aSan9tz98tHktMu0qGCF6wwgheoBgor
# BgEEAYI3AwMBMYIXmDCCF5QGCSqGSIb3DQEHAqCCF4UwgheBAgEDMQ8wDQYJYIZI
# AWUDBAIBBQAwggFZBgsqhkiG9w0BCRABBKCCAUgEggFEMIIBQAIBAQYKKwYBBAGE
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCDiTp4IxQRMbvaEGrJGxLd3HcsRwVoXzvt3
# PfHKSQcGmgIGZ2LjquIaGBIyMDI0MTIyMDIyMjcyNS41MlowBIACAfSggdmkgdYw
# gdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsT
# JE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMe
# blNoaWVsZCBUU1MgRVNOOjUyMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3Nv
# ZnQgVGltZS1TdGFtcCBTZXJ2aWNloIIR+zCCBygwggUQoAMCAQICEzMAAAIAC9eq
# fxsqF1YAAQAAAgAwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNV
# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv
# c29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAg
# UENBIDIwMTAwHhcNMjQwNzI1MTgzMTIxWhcNMjUxMDIyMTgzMTIxWjCB0zELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9z
# b2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMScwJQYDVQQLEx5uU2hpZWxk
# IFRTUyBFU046NTIxQS0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1l
# LVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCv
# Vdpp0qQ/ZOS6ehMXnvf+0Xsokz0OiK/dxy/bqaqdSGa/YMzn2KQRPhadF+jluIUg
# dzouqsh6oKBP19P8aSzlUo73RlBbZq+H88weeXSRl9f8jnN1Wihcdt1RSQ+Jl81e
# zNazCYv1SVajybPK/0un1MC3D+hc5hMDF1hKo4HlTPPVDcDy4Kk2W6ZA0MkYNjpx
# KfQyVi6ReSUCsKGrqX4piuXqv9ac6pdKScAGmCBKwnfegveieYOI31hQClnCOc2H
# 0zqQNqd5LPvz9i0P/akanH38tcQuhrMRQXGHKDgp2ahYY1jB1Hv+J3zWB44RHr2X
# l0m/vVL+Yf4vFvovr3afy4SYBXDp9W8T5zzCOBhluVkI08DKcKcN25Et2TWOzAKq
# Oo1zdf9YjMDsYazgdRLhgisBTHwfYD3i8M2IDwBZrtn8dLBMLIiB5VuV1dgzYG3E
# wqreSd5GhPbs1DtjufxlNoCN7sGV+O7zeykY/9BZg1nXBjNhUZHI6l0DxabGrlXx
# /mvgdob3M9zKQ7ImlFnL5XdEaKCEWawIlcBwzOI7voeKfAIiMiacIUoYn8hsuMfo
# nt8lepE9uD4fqtgtnxcGmZcEUfg9NqRlVjEH8/4RBsvks3DRkgz565/EKWNXg76c
# eQz7OBLHz7TsFVk8EqyWih5uyaEhwE7Tvv2R6FyJgwIDAQABo4IBSTCCAUUwHQYD
# VR0OBBYEFIAlJNq+CSMqqB7nFA5effl9d3c6MB8GA1UdIwQYMBaAFJ+nFV0AXmJd
# g/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0El
# MjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGlt
# ZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwGA1UdEwEB/wQCMAAwFgYDVR0l
# AQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUA
# A4ICAQAo8Ib2eNG0ipD5+4QKDHNYyxA4jce9buxX0+YRYII5aVO4YIjM2LeJt0tl
# LRvYgMeDTIuu11W4GLcXFV16whe7NjKh8h79qVMF1XgOGKMtNe0Hs2A6ejsbXaI7
# e3qPLWE9Kq7MYuvL/aYRkHAixKhLYP4f7ccInE8PKHMwWo/6mWW08AIH9A3Bnur4
# cbJm/e/x636tBiDywXc9O5Z4ODd1H/OTU1rAn918UINiVY14IEIu809AFx4xhcVE
# UqFxJTCzuYV0gMOFmnGrIgoPZYPAXI0gYR7Of6d3iRdG6l40TH55KklfKVEP7V3j
# mFvo/M4gXsGRw+1G0VbbBeCSMuq1NZaUGS/OXa419gncI9lVoPIwNppeA74foOKu
# wnggb2KQh33jX6ZYN6OSPlpif1A3pE5+j8c0eDW2KbCkWhSK+oAW7qKtZkXDlX7I
# uvwUtzudsxraUVKLHO73rN2cOw8ibPRzpK1tjKEpKUze4NGL1RbJ1IqqcRu0noyT
# 5i7G/OmuS5ZAlhZ+k++6D7BOeKjKRXBzTJFVyx3jEzOeedG1kMYxJQSX20xWd5th
# GyHBkjIlOwGAtmYczurZMUr9f33jhKQirJjbYBy4t7Qaqg18BIIhxm3Ntn/M/iVP
# b83SkNufZ98DONmSEj5Cuqv3zeZBlbBl2vdOTUxgSUNOHPYPQzCCB3EwggVZoAMC
# AQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29m
# dCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTIxMDkzMDE4MjIy
# NVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAw
# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDk4aZM57RyIQt5osvXJHm9
# DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25PhdgM/9cT8dm95VTcVrifkpa/rg2
# Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPFdvWGUNzBRMhxXFExN6AKOG6N
# 7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6GnszrYBbfowQHJ1S/rboYiXc
# ag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJ
# j361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50ZuyjLVwIYwXE8s4mKyzbnijYjk
# lqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3EXzTdEonW/aUgfX782Z5F37Zy
# L9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0lBw0gg/wEPK3Rxjtp+iZfD9M
# 269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLX
# pyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ+QuJYfM2BjUYhEfb3BvR/bLU
# HMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode
# 2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkwEgYJKwYBBAGCNxUBBAUCAwEA
# ATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxGNSnPEP8vBO4wHQYDVR0OBBYE
# FJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARVMFMwUQYMKwYBBAGCN0yDfQEB
# MEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv
# RG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEE
# AYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
# /zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEug
# SaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9N
# aWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsG
# AQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jv
# b0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt
# 4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0xM7U518JxNj/aZGx80HU5bbsP
# MeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmCVgADsAW+iehp4LoJ7nvfam++
# Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449xvNo32X2pFaq95W2KFUn0CS9
# QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wMnosZiefwC2qBwoEZQhlSdYo2
# wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aR
# AfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2dY3RILLFORy3BFARxv2T5JL5z
# bcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxnGSgkujhLmm77IVRrakURR6nx
# t67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+CrvsQWY9af3LwUFJfn6Tvsv4O+S3
# Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokLjzbaukz5m/8K6TT4JDVnK+AN
# uOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL6Xu/OHBE0ZDxyKs6ijoIYn/Z
# cGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNWMIICPgIBATCCAQGhgdmkgdYw
# gdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsT
# JE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMe
# blNoaWVsZCBUU1MgRVNOOjUyMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3Nv
# ZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQCMk58tlveK+Kkv
# exIuVYVsutaOZKCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
# MA0GCSqGSIb3DQEBCwUAAgUA6xAFBjAiGA8yMDI0MTIyMDE1MDAyMloYDzIwMjQx
# MjIxMTUwMDIyWjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDrEAUGAgEAMAcCAQAC
# Agg8MAcCAQACAhMWMAoCBQDrEVaGAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisG
# AQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQELBQAD
# ggEBAHqr3942EEmyU3L8xmbfH/vGEIs4BWkbsXPv/Lf80DrxwvIiNwTO3DreQNU2
# gGXKKWJwSIiwpHKmuD9C0qESmJHbFzaHHQMe0GOOccmp//iNq+bsXSlUgx/xd6tn
# 7+KUkE0kiShq1jyVqkNI0VSCuztPv1J6o1cjVTwb287bdLuLQmIcvmA9qDO+JMQv
# zDouz/jqkkFA0MgJ/pYYcjCkwMIqltusBPlR4cDhjowFUUfFwryykQSqPEdPUKuW
# Iwl4hb8d7DmpfZmpMRwY3vY6A0zTbYXC64pLodHeWYvyOYPUC/bL9H0mCDgh/AmI
# xy1/i32F8b2NnHrKVrh5jBDgUaYxggQNMIIECQIBATCBkzB8MQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGlt
# ZS1TdGFtcCBQQ0EgMjAxMAITMwAAAgAL16p/GyoXVgABAAACADANBglghkgBZQME
# AgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJ
# BDEiBCDqcGyAuVt6enVOuV12UvOkzWw3y7etCh4e+DCYFUNwdzCB+gYLKoZIhvcN
# AQkQAi8xgeowgecwgeQwgb0EINTI7ew1ndu6sE0MZQJXg18zaAfhpa5G50iT/0oC
# T9knMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAIA
# C9eqfxsqF1YAAQAAAgAwIgQgxwoY/21+2Z0tcvz5eFLheu6BZQwVPySUC7dr1Ftu
# VsQwDQYJKoZIhvcNAQELBQAEggIANnyWtgIcQi4atPNOVXI6O33vrwJORaOwNrnE
# Ahe0WxQzjmEchQkDiHxY92v5/SjGHcMXdBia6e84eSKIp7w6EN9T96Pu5/nVRP0L
# iO4dcWd3XEuEiEzQtsy93tGhECDSQcFLP8Xj8Z3Vl12fLm4UtVOG+/VM6BHdaUf/
# dWJqWI5yrhvKJHL/RtQKtTlid4S9OV7mwk+v21D3WsxCxIxgGpq3ptulSpt2MJiP
# FoWGerh+hxONN+G8JHC0ypa7uoQRdTSLS10ul9X1Rf/7/l5nA6En07cudWFXmLAp
# zXcEiGcf7cAUD7ke2QzM637ooXAwwAL5Mq3LwfDd4HoXp+q+rKk48PEcjwQNe6Wx
# dtzNypVL1w3KN0fXNvzY+LPy1cM1RGTDz79Qpyd8VHooQl6Pf0wLNQO/JgFoAz39
# JkNkIXC4dYEqEq03DtJFJMfhWnQRADZUCVwikdjMprQvPRRHfg886TVKht7GST/r
# UE9+N5Kfw6Z0ZcsOChQOMDn19hxCQEOA2u7Z1M7WyXU0CsvpG6Ajru6Gw2c4alkR
# 1cWPzzUNfC/Ea03j2bYlZ4anYL/cu4jOPT51zNzyVwojIHG76MA/B4KrFAeWEPk8
# 3V8ioW8YFeLYwZmHEfPqFnsDVB8p2Hw8q091E1dbGwIofeQEr02diIQSpKeTkV4W
# pl9I7l8=
# SIG # End signature block