Public/New-DeclarativeCopilot.ps1

<#
.SYNOPSIS
    Create a Declarative Copilot app package.
.DESCRIPTION
    This cmdlet creates a Declarative Copilot app package, which includes a Teams app with a Declarative Copilot.
.PARAMETER author
    The author of the Declarative Copilot app. It is optional, if not specified, the author will be Ares Chen.
.PARAMETER name
    The name of the Declarative Copilot.
.PARAMETER description
    The description of the Declarative Copilot.
.PARAMETER instructions
    The instructions of the Declarative Copilot, this is very important to guide the user to use the Declarative Copilot.
.PARAMETER outlineIcon192x192
    The path of the outline icon of the Declarative Copilot, it should be a 192x192 png file. It is optional, if not specified, the default icon will be used.
.PARAMETER colorIcon32x32
    The path of the color icon of the Declarative Copilot, it should be a 32x32 png file. It is optional, if not specified, the default icon will be used.
.PARAMETER starterPrompts
    The starter prompts of the Declarative Copilot. You can define at most 6 starter prompts. Each one should be a string, format as "title,text", for example, "Create a new document,Create a new document in Word". It means the title is "Create a new document" and the text is "Create a new document in Word". If you don't specify "," the title and text will be the same.
.PARAMETER enableWebSearch
    Enable the Web Search capability.
.PARAMETER enableGraphicArt
    Enable the Graphic Art capability which allows the user to generate image or video.
.PARAMETER enableCodeInterpreter
    Enable the Code Interpreter capability which allows the user to run code.
.PARAMETER onedriveOrSharePointUrls
    The URLs of the OneDrive or SharePoint files which the Declarative Copilot can access.
.PARAMETER graphConnectorIds
    The IDs of the Graph Connectors which the Declarative Copilot can access.
.PARAMETER actionFiles
    The action (plugin) files which the Declarative Copilot can access.
.EXAMPLE
    New-DeclarativeCopilot -name "Product Copilot" -instructions "You are an experienced product manager, you help users to ideation, planning, and delivering great product from zero to one." -starterPrompts "Write PM spec, Please help me write spec about the idea below`n" -enableWebSearch -enableGraphicArt -enableCodeInterpreter
 
    This example creates a Declarative Copilot app package named "Product Copilot" with the instructions "You are an experienced product manager, you help users to ideation, planning, and delivering great product from zero to one." and a starter prompt "Write PM spec, Please help me write spec about the idea below". It enables the Web Search, Graphic Art, and Code Interpreter capabilities.
#>

function New-DeclarativeCopilot {
    [CmdletBinding()][Alias("ndc")]
    param (
        [string]$author,
        [Parameter(Mandatory = $true)]
        [string]$name,
        [string]$description,
        [Parameter(Mandatory = $true)]
        [string]$instructions,
        [string]$outlineIcon192x192,
        [string]$colorIcon32x32,
        [string[]]$starterPrompts,
        [switch]$enableWebSearch,
        [switch]$enableGraphicArt,
        [switch]$enableCodeInterpreter,
        [string[]]$onedriveOrSharePointUrls,
        [string[]]$graphConnectorIds,
        [string[]]$actionFiles
    )

    Send-AppInsightsTrace -Message "microsoft.copilot.toolkit" -Properties @{ "command" = "New-DeclarativeCopilot" } -ErrorAction SilentlyContinue
    
    # copy the content of private\assets\declarativecopilot to the temp folder
    $tempFolder = Join-Path $env:TEMP "microsoft.copilot.toolkit-$([Guid]::NewGuid().ToString())"

    $sourceFolder = Join-Path $PSScriptRoot -ChildPath "../private/assets/declarativecopilot"
    Copy-Item -Path $sourceFolder -Destination $tempFolder -Recurse -Force

    # update the manifest file
    $manifest = Get-Content (Join-Path $tempFolder "manifest.json") | ConvertFrom-Json
    $manifest.id = [Guid]::NewGuid().ToString()

    $manifest.name.short = $name
    $manifest.name.full = $name
    $manifest.description.short = "A Teams app inclduing a Declarative Copilot, $name"
    $manifest.description.full = "A Teams app inclduing a Declarative Copilot, $name, generated by the microsoft.copilot.toolkit module (https://www.powershellgallery.com/packages/microsoft.copilot.toolkit), created by Ares Chen."

    # save the updated manifest file to the same file
    $manifest | ConvertTo-Json -Depth 10 | Set-Content -Path (Join-Path $tempFolder "manifest.json") -Force -Encoding UTF8

    # update the outline icon
    if ($outlineIcon192x192 -and (Test-Path $outlineIcon192x192) -and ($outlineIcon192x192 -match "\.png$")) {
        # make sure it is a 192x192 png file
        $outlineIcon = Join-Path $tempFolder "outline.png"
        Copy-Item -Path $outlineIcon192x192 -Destination $outlineIcon -Force
    }

    # update the color icon
    if ($colorIcon32x32 -and (Test-Path $colorIcon32x32) -and ($colorIcon32x32 -match "\.png$")) {
        $colorIcon = Join-Path $tempFolder "color.png"
        Copy-Item -Path $colorIcon32x32 -Destination $colorIcon -Force
    }

    # update the content of the declarativecopilot.json
    $copilot = Get-Content (Join-Path $tempFolder "declarativecopilot.json") | ConvertFrom-Json
    $copilot.name = $name
    $copilot.instructions = $instructions

    # parse the starter prompts
    if ($starterPrompts -and $starterPrompts.Count -gt 0) {       
        $copilot | Add-Member -MemberType NoteProperty -Name "conversation_starters" -Value @(
            foreach ($starterPrompt in $starterPrompts) {
                $parts = $starterPrompt.Split(",")
                if ($parts.Count -eq 1) {
                    @{
                        "title" = $parts[0]
                        "text"  = $parts[0]
                    }
                }
                else {
                    @{
                        "title" = $parts[0]
                        "text"  = $parts[1]
                    }
                }
            }
        )
    }

    $capabilities = @()
    if ($enableWebSearch) {
        $capabilities += @{
            "name" = "WebSearch"
        }
    }

    if ($enableGraphicArt) {
        $capabilities += @{
            "name" = "GraphicArt"
        }
    }

    if ($enableCodeInterpreter) {
        $capabilities += @{
            "name" = "CodeInterpreter"
        }
    }

    if ($onedriveOrSharePointUrls -and $onedriveOrSharePointUrls.Count -gt 0) {
        $capabilities += @{
            "name"         = "OneDriveAndSharePoint"
            "items_by_url" = @(
                foreach ($url in $onedriveOrSharePointUrls) {
                    @{
                        "url" = $url
                    }
                }
            )
        }
    }

    if ($graphConnectorIds -and $graphConnectorIds.Count -gt 0) {
        $capabilities += @{
            "name"        = "GraphConnectors"
            "connections" = @(
                foreach ($id in $graphConnectorIds) {
                    @{
                        "connection_id" = $id
                    }
                }
            )
        }
    }

    # if any capibility is enabled, update the capabilities
    if ($capabilities.Count -gt 0) {
        $copilot | Add-Member -MemberType NoteProperty -Name "capabilities" -Value $capabilities
    }

    if ($actionFiles -and $actionFiles.Count -gt 0) {
        $actions = @(
            foreach ($actionFile in $actionFiles) {
                # copy the action file to the temp folder
                $actionFileName = Split-Path $actionFile -Leaf
                Copy-Item -Path $actionFile -Destination (Join-Path $tempFolder -ChildPath $actionFileName) -Force

                @{
                    "id"   = [Guid]::NewGuid().ToString()
                    "file" = $actionFileName
                }
            }
        )

        $copilot | Add-Member -MemberType NoteProperty -Name "actions" -Value $actions
    }

    # save the updated declarativecopilot.json to the same file
    $copilot | ConvertTo-Json -Depth 10 | Set-Content -Path (Join-Path $tempFolder "declarativecopilot.json") -Force -Encoding UTF8


    # create a zip file and save it in current folder, named as $name.zip
    $zipFile = "$name.zip"

    # compress the temp folder to a zip file
    Compress-Archive -Path "$tempFolder\\*" -DestinationPath $zipFile -Force


    # remove the temp folder
    Remove-Item -Path $tempFolder -Recurse -Force

    Write-Host "The Declarative Copilot app has been created successfully. The zip file is saved as $zipFile."

}
# SIG # Begin signature block
# MIIdKQYJKoZIhvcNAQcCoIIdGjCCHRYCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCC/eio0dtMDTgNg
# 2Vd58dRwe2NyxrcUm08Y15nYjZYgG6CCA0YwggNCMIICKqADAgECAhAdkYHz+qFO
# vkQjYqzHr3pKMA0GCSqGSIb3DQEBCwUAMDkxNzA1BgNVBAMMLkNvZGVTaWduaW5n
# IENlcnRpZmljYXRlIGZvciBQb3dlclNoZWxsIE1vZHVsZXMwHhcNMjQwNjEyMDUw
# ODAyWhcNMjUwNjEyMDUyODAyWjA5MTcwNQYDVQQDDC5Db2RlU2lnbmluZyBDZXJ0
# aWZpY2F0ZSBmb3IgUG93ZXJTaGVsbCBNb2R1bGVzMIIBIjANBgkqhkiG9w0BAQEF
# AAOCAQ8AMIIBCgKCAQEAwdSzTBb7ni0tRubblITxoGHzXlvwu8Y5ndoElOvIKaey
# AFW8+tYCPG5zATsoGGE3f8g6Wtv8JgEjH45ZOhRBjghEVpw/9Iszal5SmucjUlqB
# fMvts+M/x9G7h6GGAQFy65xgQqyCVJA10x2NDheb7cBRCRRZVkT+CUv1dbS41bsO
# BMKDUTumbU7vHk2FSJ5H6f31cj238qboI4g2GD2gIsWID+GhAfzxrmXMV6VgMKqW
# GNlK5g/X2tSM6Aygnx1itXrrV3LwDOYiAAs+j87jEsYhxe3CnFgtDsi4UtW/lFem
# eEiOh9Vd6LaTxNoleV/PGz3FU7t6nnZmIOsjOFWLHQIDAQABo0YwRDAOBgNVHQ8B
# Af8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFMTYcpJNvUO8
# TYpuvvHtzPkUUUmkMA0GCSqGSIb3DQEBCwUAA4IBAQAihkTQ6zo1SNboEZ2C5yXr
# Hf5FoMRFBij0o0drMYEwDbiVCNGXkk74nNqXnGm+CJ0jkPHkM35uC/JGGGyToyBF
# uC27hC6+WsTMlVlJZKr7N5WLaM97hwf5xtEWg1c1s0vLKx92AKSGgqJRU7rlRMaX
# 5oOROmFwLqMj15Oon73EhZNqpjfRsKgMxJJw03n6KwMNvzNTXlsiaS0mvAnFzKFp
# msuvtWJfp8fxHvEQckJzFr2EldNKKyTTZjbN5JfbQWZGIuxftYXZ0JKwXleZhNxZ
# MtkuHzjcpCoBgdIYI3FidWcZgUltoSLRZzM/iVLX6MAX2mjHQOBNWG/gOeZk28qo
# MYIZOTCCGTUCAQEwTTA5MTcwNQYDVQQDDC5Db2RlU2lnbmluZyBDZXJ0aWZpY2F0
# ZSBmb3IgUG93ZXJTaGVsbCBNb2R1bGVzAhAdkYHz+qFOvkQjYqzHr3pKMA0GCWCG
# SAFlAwQCAQUAoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisG
# AQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcN
# AQkEMSIEIMpeWS8+sJZ7UYlNM1Xn0b58CslKNebGdE2BwpOtvwByMA0GCSqGSIb3
# DQEBAQUABIIBAJ3QxKNu+xNBBBHkG6sKTAzkqUF+hD0HZkYwLU65w2rdZ0fI0rse
# LmDBgHyj6EZQcOCIzCZ0xwYyni0hYEzADCOHj+NcuxqVSoRFotCAGMvNffVWrVd9
# XSyzdDdWdOqYaSyyWmYd8PaZLz7bI8FmsUg4jZ4c4SqBdvNxip/s3f/W1vYnFIFB
# ynuxtVpAexvegzAnOAYDbIrSxn/nyq4tK1dAo8Khbb0qHHAkOnNSfSVEMF8vovHl
# 23EA2BqhRSJ/+4rZUtJ3W+7sr967ZiyXSiRpoPbmkPgsPKW5iGiI4VWRhdn1Rc49
# 37Pwd9tO93XcQtMO6KADvKZK6F0KP0vi/iOhghc/MIIXOwYKKwYBBAGCNwMDATGC
# FyswghcnBgkqhkiG9w0BBwKgghcYMIIXFAIBAzEPMA0GCWCGSAFlAwQCAQUAMHcG
# CyqGSIb3DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEF
# AAQgCBSkyu5jM0KyB9TXpWYlpXpQY75D23pIH13LugaWm6MCEARkvaAsR99iIfwg
# MktuRRYYDzIwMjQwOTExMjI0NDMyWqCCEwkwggbCMIIEqqADAgECAhAFRK/zlJ0I
# Oaa/2z9f5WEWMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQK
# Ew5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBS
# U0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjMwNzE0MDAwMDAwWhcN
# MzQxMDEzMjM1OTU5WjBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs
# IEluYy4xIDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIzMIICIjANBgkq
# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAo1NFhx2DjlusPlSzI+DPn9fl0uddoQ4J
# 3C9Io5d6OyqcZ9xiFVjBqZMRp82qsmrdECmKHmJjadNYnDVxvzqX65RQjxwg6sea
# Oy+WZuNp52n+W8PWKyAcwZeUtKVQgfLPywemMGjKg0La/H8JJJSkghraarrYO8pd
# 3hkYhftF6g1hbJ3+cV7EBpo88MUueQ8bZlLjyNY+X9pD04T10Mf2SC1eRXWWdf7d
# EKEbg8G45lKVtUfXeCk5a+B4WZfjRCtK1ZXO7wgX6oJkTf8j48qG7rSkIWRw69Xl
# oNpjsy7pBe6q9iT1HbybHLK3X9/w7nZ9MZllR1WdSiQvrCuXvp/k/XtzPjLuUjT7
# 1Lvr1KAsNJvj3m5kGQc3AZEPHLVRzapMZoOIaGK7vEEbeBlt5NkP4FhB+9ixLOFR
# r7StFQYU6mIIE9NpHnxkTZ0P387RXoyqq1AVybPKvNfEO2hEo6U7Qv1zfe7dCv95
# NBB+plwKWEwAPoVpdceDZNZ1zY8SdlalJPrXxGshuugfNJgvOuprAbD3+yqG7HtS
# OKmYCaFxsmxxrz64b5bV4RAT/mFHCoz+8LbH1cfebCTwv0KCyqBxPZySkwS0aXAn
# DU+3tTbRyV8IpHCj7ArxES5k4MsiK8rxKBMhSVF+BmbTO77665E42FEHypS34lCh
# 8zrTioPLQHsCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8E
# AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQC
# MAsGCWCGSAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAd
# BgNVHQ4EFgQUpbbvE+fvzdBkodVWqWUxo97V40kwWgYDVR0fBFMwUTBPoE2gS4ZJ
# aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5
# NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZM
# aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNB
# NDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEA
# gRrW3qCptZgXvHCNT4o8aJzYJf/LLOTN6l0ikuyMIgKpuM+AqNnn48XtJoKKcS8Y
# 3U623mzX4WCcK+3tPUiOuGu6fF29wmE3aEl3o+uQqhLXJ4Xzjh6S2sJAOJ9dyKAu
# JXglnSoFeoQpmLZXeY/bJlYrsPOnvTcM2Jh2T1a5UsK2nTipgedtQVyMadG5K8TG
# e8+c+njikxp2oml101DkRBK+IA2eqUTQ+OVJdwhaIcW0z5iVGlS6ubzBaRm6zxby
# gzc0brBBJt3eWpdPM43UjXd9dUWhpVgmagNF3tlQtVCMr1a9TMXhRsUo063nQwBw
# 3syYnhmJA+rUkTfvTVLzyWAhxFZH7doRS4wyw4jmWOK22z75X7BC1o/jF5HRqsBV
# 44a/rCcsQdCaM0qoNtS5cpZ+l3k4SF/Kwtw9Mt911jZnWon49qfH5U81PAC9vpwq
# bHkB3NpE5jreODsHXjlY9HxzMVWggBHLFAx+rrz+pOt5Zapo1iLKO+uagjVXKBbL
# afIymrLS2Dq4sUaGa7oX/cR3bBVsrquvczroSUa31X/MtjjA2Owc9bahuEMs305M
# fR5ocMB3CtQC4Fxguyj/OOVSWtasFyIjTvTs0xf7UGv/B3cfcZdEQcm4RtNsMnxY
# L2dHZeUbc7aZ+WssBkbvQR7w8F/g29mtkIBEr4AQQYowggauMIIElqADAgECAhAH
# Nje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUw
# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
# ITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAw
# MDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp
# Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2
# IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
# ggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGh
# RBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISK
# Ihjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdG
# AHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9
# zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKl
# SNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae
# 5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnz
# yqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/
# BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7T
# A4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbs
# q11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IB
# XTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3Mpdpov
# dYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P
# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC
# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v
# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEE
# AjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m
# 1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dt
# h/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+K
# LHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd
# 6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ
# 38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+
# k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3l
# NHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGY
# X/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFm
# ut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADN
# XcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kv
# RBVK5xMOHds3OBqhK/bt1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAY
# WjANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl
# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdp
# Q2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5
# MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw
# FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVz
# dGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBz
# aN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbr
# VsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTR
# EEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJ
# z82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyO
# j4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6R
# AXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k
# 98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJ
# tppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUa
# dmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZB
# dd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVf
# nSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0T
# AQH/BAUwAwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0j
# BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsG
# AQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
# MEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRBc3N1cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9j
# cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYD
# VR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3Qb
# PbYW1/e/Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5
# +KH38nLeJLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+n
# BgMTdydE1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc
# /RzY9HdaXFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVr
# zyerbHbObyMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o
# 4rmUMYIDdjCCA3ICAQEwdzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl
# cnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBT
# SEEyNTYgVGltZVN0YW1waW5nIENBAhAFRK/zlJ0IOaa/2z9f5WEWMA0GCWCGSAFl
# AwQCAQUAoIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0B
# CQUxDxcNMjQwOTExMjI0NDMyWjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBRm8Csy
# wsLJD4JdzqqKycZPGZzPQDAvBgkqhkiG9w0BCQQxIgQgtKoq6HadAFYi+xDRrm80
# sXXOLJHeZSf6g+rW/MlY394wNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQg0vbkbe10
# IszR1EBXaEE2b4KK2lWarjMWr00amtQMeCgwDQYJKoZIhvcNAQEBBQAEggIAL2dj
# AyKR5bS7cl8TCLEV/k6hReh+elKWQmMK+6wAiHlIAlrjKqgjjatZt/eu6BiXmr6L
# jLUnZPNlQMnEw/8zqvuuW8K5bJ2wRMdX6yB2ac+78fVHCYw80bCnwGiXCVQhFa22
# 2UI+4Tozs4PBDIw1IEutGVJQhztNXpgMFij0JMR3YwjfxMb5Qp7Nj2+g8YURE4l2
# wyHsOF2b0g7yk3LThghxu0PJPGYnA+4BHU6p6crrhSOIJcdEbCPCNsJDLkP87YA1
# 2KCisCbE/ASe41POF7Ag1CLIeTW5ZdeLbKINaykBwojaRfdgWQuRjt5jMk6Ti8Ne
# CssPe0NxA3EbdzB86Giudrz6EOPbR3Zw+EqLppDSTXK1o1NceO+T/rwUJK5ee3I3
# VxCGEpTcMm2skdQohHAbdU4Ulm1OmM3J6xFJxNxrpcS/r2wxYknIDQMKtQhqzEEx
# xNJ5Wch6888UqZkMwi9lmMXybYv19Txi2XXN4Blk5GLkQ6gligNX1tIj+lmhnYQt
# HzrZk0tSRJSS/9IumafgZuKmkUu64sqPQ56/zsjTP78j9bcMYhXRgZiSPxoGLahN
# JOpCyIfLTet9snB7MsTRmC8ANsffT7p4uf2utGmN4R12cWkw9KnIZVC92w0w4UhO
# AJcEG/FCPWFSy40lVpHHfCcnwupI0Hselgc6Yvc=
# SIG # End signature block