Public/New-DeclarativeCopilot.ps1
<#
.SYNOPSIS Create a Declarative Agent app package. .DESCRIPTION This cmdlet creates a Declarative Agent app package, which includes a Teams app with a Declarative Agent, you can sideload for yourself, or publish to your organization and share with more people. You can learn more about Declarative Agent here (https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/overview-declarative-copilot). .PARAMETER author The author of the Declarative Agent app. It is optional, if not specified, the author will be Ares Chen. .PARAMETER name The name of the Declarative Agent. .PARAMETER description The description of the Declarative Agent. .PARAMETER instructions The instructions of the Declarative Agent, this is very important to guide the user to use the Declarative Agent. Think this as the system prompt when you interact with the ChatGPT or other AI models. You can specify the instructions as a string, or a file path which contains the instructions. If it is a file path, the content of the file will be used as the instructions. The file should be a UTF-8 encoded text file. .PARAMETER outlineIcon192x192 The path of the outline icon of the Declarative Agent, 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 Agent, 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 Agent. Think this as templates of prompts you suggest to the user so that they can start the conversation easily. 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, so that the Declarative Agent can search the web (for example, query the weather or the recent news) for the user. .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 Agent can access. You can specify multiple URLs, the Url can be a SharePoint site, a SharePoint document library, or a OneDrive folder. For example, "https://contoso.sharepoint.com/sites/teamsite", "https://contoso-my.sharepoint.com/personal/user_contoso_com", "https://contoso-my.sharepoint.com/personal/user_contoso_com/Documents/Shared%20with%20Everyone". Please make sure the user who uses the Declarative Agent has the permission to access the files in the specified URLs. if you specify "all", it means the Declarative Agent can access all the files in the user's OneDrive or SharePoint sites you have permission to access. .PARAMETER graphConnectorIds The IDs of the Graph Connectors which the Declarative Agent can access. You can learn more about Graph Connectors here (https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/overview-graph-connector). if you specify "all", it means the Declarative Agent can access all the Graph Connectors you have permission to access. .PARAMETER helloworld If you specify this switch, the cmdlet will create a simplest agent, name is "Hello World", and instructions is "Hello, I am a Declarative Agent, I can help you with your daily work. You can ask me anything, I will try my best to help you.". .PARAMETER publish If you specify this switch, the cmdlet will publish the Declarative Agent app to your organization, and you can share the app to your organization by a link. Before you publish the app, you need to make sure you have logged in with your work or school account, and have the admin permission to publish the app. The cmdlet will use the MSAL.PS module to get the access token for you to publish the app, if the module is not installed, it will install it first. You can learn more about the MSAL.PS module here (https://www.powershellgallery.com/packages/MSAL.PS). .EXAMPLE New-DeclarativeAgent -helloworld This is the helloworld example, if will create a simplest agent, name is "Hello World", and instructions is "Hello, I am a Declarative Agent, I can help you with your daily work. You can ask me anything, I will try my best to help you.". .EXAMPLE New-DeclarativeAgent -name "Product Copilot" -instructions "You are an experienced product manager, you help users to ideation, planning, and delivering great product from zero to one." This is the simplest example, since only the name and instructions parameter are mandatory for this command. .EXAMPLE New-DeclarativeAgent -name "Product Copilot" -instructions "yourinstructions.txt" This example creates a Declarative Agent app package named "Product Copilot" with the instructions from the file "yourinstructions.txt". .EXAMPLE New-DeclarativeAgent -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" You can also specify the starter prompts parameter to provide a prompt for the user to start the conversation. It is up to 6 prompts, and the parameter is a string array. You can specifiy multiple prompts by using -starterPrompts "Prompt1", "Prompt2", "Prompt3". Each prompt can split by a camma to get the title and text. In this example, the starter prompt is "Write PM spec, Please help me write spec about the idea below", so the title is "Write PM spec" and the text is "Please help me write spec about the idea below". .EXAMPLE New-DeclarativeAgent -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 Agent 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 also enables the Web Search, Graphic Art, and Code Interpreter capabilities. .EXAMPLE New-DeclarativeAgent -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 -onedriveOrSharePointUrls "https://contoso.sharepoint.com/sites/teamsite", "https://contoso-my.sharepoint.com/personal/user_contoso_com", "https://contoso-my.sharepoint.com/personal/user_contoso_com/Documents/Shared%20with%20Everyone" This example creates a Declarative Agent 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 also enables the Web Search, Graphic Art, and Code Interpreter capabilities, and specifies the OneDrive or SharePoint URLs. .EXAMPLE New-DeclarativeAgent -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 -onedriveOrSharePointUrls "https://contoso.sharepoint.com/sites/teamsite", "https://contoso-my.sharepoint.com/personal/user_contoso_com", "https://contoso-my.sharepoint.com/personal/user_contoso_com/Documents/Shared%20with%20Everyone" -graphConnectorIds "12345678-abcd-1234-abcd-1234567890ab", "23456789-abcd-1234-abcd-1234567890ab" This example creates a Declarative Agent 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 also enables the Web Search, Graphic Art, and Code Interpreter capabilities, specifies the OneDrive or SharePoint URLs, and specifies the Graph Connector IDs. .EXAMPLE New-DeclarativeAgent -name "Product Copilot" -instructions "You are an experienced product manager, you help users to ideation, planning, and delivering great product from zero to one." -outlineIcon192x192 "C:\path\to\outline.png" -colorIcon32x32 "C:\path\to\color.png" -author "Your name" This example creates a Declarative Agent 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 specifies the outline icon, color icon, and author. .Link https://github.com/code365opensource/microsoft.copilot.toolkit #> function New-DeclarativeCopilot { [CmdletBinding()][Alias("ndc", "nda", "New-DeclarativeAgent")] param ( [Parameter(ParameterSetName = "default")] [string]$author, [Parameter(ParameterSetName = "default", Mandatory = $true)] [string]$name, [Parameter(ParameterSetName = "default")] [string]$description, [Parameter(ParameterSetName = "default", Mandatory = $true)] [string]$instructions, [Parameter(ParameterSetName = "default")] [string]$outlineIcon192x192, [Parameter(ParameterSetName = "default")] [string]$colorIcon32x32, [Parameter(ParameterSetName = "default")] [string[]]$starterPrompts, [Parameter(ParameterSetName = "default")] [switch]$enableWebSearch, [Parameter(ParameterSetName = "default")] [switch]$enableGraphicArt, [Parameter(ParameterSetName = "default")] [switch]$enableCodeInterpreter, [Parameter(ParameterSetName = "default")] [string[]]$onedriveOrSharePointUrls, [Parameter(ParameterSetName = "default")] [string[]]$graphConnectorIds, [Parameter(ParameterSetName = "quickstart", Mandatory = $true)] [switch]$helloworld, [Parameter(ParameterSetName = "default")] [Parameter(ParameterSetName = "quickstart")] [switch]$publish ) Send-AppInsightsTrace -Message "microsoft.copilot.toolkit" -Properties @{ "command" = "New-DeclarativeAgent" } -ErrorAction SilentlyContinue # if user specify the publish switch, then check if the "MSAL.ps" module is installed, if not, install it first, and then try to get the accesstoken for the user to publish the app, use the "Get-MSALToken" cmdlet to get the token if ($publish) { $msalModule = Get-Module -Name "MSAL.PS" -ListAvailable if (-not $msalModule) { Install-Module -Name "MSAL.PS" -Scope CurrentUser -Force } $accessToken = (Get-MsalToken -ClientId "52d52498-5bb2-45c5-9caf-3f01c326d9d0" -RedirectUri "msal52d52498-5bb2-45c5-9caf-3f01c326d9d0://auth" -Scopes "Directory.ReadWrite.All" -ErrorAction SilentlyContinue).AccessToken if (-not $accessToken) { Write-Error "Failed to get the access token, please make sure you have logged in with your work or school account, and have the admin permission to publish the app." return } } # 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 # if user specific the helloworld switch, then use the default values for instructions and name parameters if ($helloworld) { $instructions = "Hello, I am a Declarative Agent, I can help you with your daily work. You can ask me anything, I will try my best to help you." $name = "Hello World" } # 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 Agent, $name" $manifest.description.full = "A Teams app inclduing a Declarative Agent, $name, generated by the microsoft.copilot.toolkit module (https://www.powershellgallery.com/packages/microsoft.copilot.toolkit), created by Ares Chen." # update the author if ($author) { $manifest.developer.name = $author } # 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 "declarativeagent.json") | ConvertFrom-Json $copilot.name = $name # if instructions is a file, read the content of the file if ($instructions -and (Test-Path $instructions -PathType Leaf)) { $instructions = Get-Content $instructions -Raw -Encoding UTF8 } $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) { [ordered]@{ "title" = $starterPrompt "text" = $starterPrompt } } else { [ordered]@{ "title" = $parts[0] "text" = $starterPrompt.SubString($parts[0].Length + 1) } } } ) } $capabilities = @() if ($enableWebSearch) { $capabilities += @{ "name" = "WebSearch" } } if ($enableGraphicArt) { $capabilities += @{ "name" = "GraphicArt" } } if ($enableCodeInterpreter) { $capabilities += @{ "name" = "CodeInterpreter" } } if ($onedriveOrSharePointUrls -and $onedriveOrSharePointUrls.Count -gt 0) { # if $onedriveOrSharePointUrls contains "all", then add the capability "OneDriveAndSharePoint" without any url if ($onedriveOrSharePointUrls -contains "all") { $capabilities += @{ "name" = "OneDriveAndSharePoint" } } else { $capabilities += [ordered]@{ "name" = "OneDriveAndSharePoint" "items_by_url" = @( foreach ($url in $onedriveOrSharePointUrls) { @{ "url" = $url } } ) } } } if ($graphConnectorIds -and $graphConnectorIds.Count -gt 0) { # if $graphConnectorIds contains "all", then add the capability "GraphConnectors" without any id if ($graphConnectorIds -contains "all") { $capabilities += @{ "name" = "GraphConnectors" } } else { $capabilities += [ordered]@{ "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 # [ordered]@{ # "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 "declarativeagent.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 Agent app has been created successfully. The zip file is saved as $zipFile." if ($publish) { # publish the app $app = (Invoke-WebRequest -InFile $zipFile -Method Post -Uri "https://graph.microsoft.com/beta/appCatalogs/teamsApps" -ContentType "application/zip" -Headers @{ "Authorization" = "Bearer $accessToken" } -ErrorAction SilentlyContinue).Content | ConvertFrom-Json if ($app) { Write-Host "The Declarative Agent app has been published successfully. You can find it in the Teams admin center, or you can share the app to your organization by a link : https://teams.cloud.microsoft/l/app/$($app.id)" } else { Write-Error "Failed to publish the Declarative Agent app, please check the error message above." } } } # SIG # Begin signature block # MIIdJAYJKoZIhvcNAQcCoIIdFTCCHRECAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDKt7/plB/AmeJQ # z3zv6/Kb9xdWMPygfqXDqDfk4Tx8vaCCA0YwggNCMIICKqADAgECAhAdkYHz+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 # MYIZNDCCGTACAQEwTTA5MTcwNQYDVQQDDC5Db2RlU2lnbmluZyBDZXJ0aWZpY2F0 # ZSBmb3IgUG93ZXJTaGVsbCBNb2R1bGVzAhAdkYHz+qFOvkQjYqzHr3pKMA0GCWCG # SAFlAwQCAQUAoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisG # AQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcN # AQkEMSIEIDOsgPcjwy5zu4hVqBGJ6fS5sc8wI16cxnJYGnvOd65gMA0GCSqGSIb3 # DQEBAQUABIIBAEB2320KfUs7Ob3YKB+X8nwonvUqLP6dr1Dfopna4IBYog4joMW+ # gKGssWma1FWf9HF/ALNgILIIauEdJ0DOwO2EWm/J8SepZA7VD42X5FoPaIhAx6KJ # ELC/YF1adJQX5E6Txaomq8nROoWR1QSiV7JE+jQWfJ5XebtHl9q9f5ISLmtz38Pr # Hl2zVUeaKt5WTTId1qmZ7t593P83aSexflxv8HJb3GbvdLvDW/4SOHJcXEBesJjR # zTH6wQE8ryHsNEPpWhcIcJtWMNQkczNp58FiTJ8NPNgASAVxWFX1IVqgreBTV8Xe # bsvUXabA3M/MCK0LYHhmFTCUnJhBVYgy++Shghc6MIIXNgYKKwYBBAGCNwMDATGC # FyYwghciBgkqhkiG9w0BBwKgghcTMIIXDwIBAzEPMA0GCWCGSAFlAwQCAQUAMHgG # CyqGSIb3DQEJEAEEoGkEZzBlAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEF # AAQgxNXUnDSJQpZVZeQ66MtazpV+zCZsa0txwpC3CsHmngsCEQCR75YsoL1pl4FZ # 0caMkPGOGA8yMDI1MDExOTAyMTgyMVqgghMDMIIGvDCCBKSgAwIBAgIQC65mvFq6 # f5WHxvnpBOMzBDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UE # ChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQg # UlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTI0MDkyNjAwMDAwMFoX # DTM1MTEyNTIzNTk1OVowQjELMAkGA1UEBhMCVVMxETAPBgNVBAoTCERpZ2lDZXJ0 # MSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyNDCCAiIwDQYJKoZIhvcN # AQEBBQADggIPADCCAgoCggIBAL5qc5/2lSGrljC6W23mWaO16P2RHxjEiDtqmeOl # wf0KMCBDEr4IxHRGd7+L660x5XltSVhhK64zi9CeC9B6lUdXM0s71EOcRe8+CEJp # +3R2O8oo76EO7o5tLuslxdr9Qq82aKcpA9O//X6QE+AcaU/byaCagLD/GLoUb35S # fWHh43rOH3bpLEx7pZ7avVnpUVmPvkxT8c2a2yC0WMp8hMu60tZR0ChaV76Nhnj3 # 7DEYTX9ReNZ8hIOYe4jl7/r419CvEYVIrH6sN00yx49boUuumF9i2T8UuKGn9966 # fR5X6kgXj3o5WHhHVO+NBikDO0mlUh902wS/Eeh8F/UFaRp1z5SnROHwSJ+QQRZ1 # fisD8UTVDSupWJNstVkiqLq+ISTdEjJKGjVfIcsgA4l9cbk8Smlzddh4EfvFrpVN # nes4c16Jidj5XiPVdsn5n10jxmGpxoMc6iPkoaDhi6JjHd5ibfdp5uzIXp4P0wXk # gNs+CO/CacBqU0R4k+8h6gYldp4FCMgrXdKWfM4N0u25OEAuEa3JyidxW48jwBqI # JqImd93NRxvd1aepSeNeREXAu2xUDEW8aqzFQDYmr9ZONuc2MhTMizchNULpUEoA # 6Vva7b1XCB+1rxvbKmLqfY/M/SdV6mwWTyeVy5Z/JkvMFpnQy5wR14GJcv6dQ4aE # KOX5AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAW # BgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglg # hkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0O # BBYEFJ9XLAN3DigVkGalY17uT5IfdqBbMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6 # Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEy # NTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUF # BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6 # Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZT # SEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAD2tHh92 # mVvjOIQSR9lDkfYR25tOCB3RKE/P09x7gUsmXqt40ouRl3lj+8QioVYq3igpwrPv # BmZdrlWBb0HvqT00nFSXgmUrDKNSQqGTdpjHsPy+LaalTW0qVjvUBhcHzBMutB6H # zeledbDCzFzUy34VarPnvIWrqVogK0qM8gJhh/+qDEAIdO/KkYesLyTVOoJ4eTq7 # gj9UFAL1UruJKlTnCVaM2UeUUW/8z3fvjxhN6hdT98Vr2FYlCS7Mbb4Hv5swO+aA # XxWUm3WpByXtgVQxiBlTVYzqfLDbe9PpBKDBfk+rabTFDZXoUke7zPgtd7/fvWTl # Cs30VAGEsshJmLbJ6ZbQ/xll/HjO9JbNVekBv2Tgem+mLptR7yIrpaidRJXrI+Uz # B6vAlk/8a1u7cIqV0yef4uaZFORNekUgQHTqddmsPCEIYQP7xGxZBIhdmm4bhYsV # A6G2WgNFYagLDBzpmk9104WQzYuVNsxyoVLObhx3RugaEGru+SojW4dHPoWrUhft # NpFC5H7QEY7MhKRyrBe7ucykW7eaCuWBsBb4HOKRFVDcrZgdwaSIqMDiCLg4D+TP # VgKx2EgEdeoHNHT9l3ZDBD+XgbF+23/zBjeCtxz+dL/9NWR6P2eZRi7zcEO1xwcd # cqJsyz/JceENc2Sg8h3KeFUCS7tpFk7CrDqkMIIGrjCCBJagAwIBAgIQBzY3tyRU # fNhHrP0oZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UE # ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD # VQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIwMzIzMDAwMDAwWhcN # MzcwMzIyMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs # IEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEy # NTYgVGltZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEAxoY1BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCwzIP5WvYRoUQVQl+k # iPNo+n3znIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFzsbPuK4CEiiIY3+va # PcQXf6sZKz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ7Gnf2ZCHRgB720RB # idx8ald68Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7QKxfst5Kfc71ORJn # 7w6lY2zkpsUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/tePc5OsLDnipUjW8LAx # E6lXKZYnLvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCYOjgRs/b2nuY7W+yB # 3iIU2YIqx5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9KoRxrOMUp88qqlnNC # aJ+2RrOdOqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6dSgkQe1CvwWcZklS # UPRR8zZJTYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM1+mYSlg+0wOI/rOP # 015LdhJRk8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbCdLI/Hgl27KtdRnXi # YKNYCQEoAA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbECAwEAAaOCAV0wggFZ # MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1NhS9zKXaaL3WMaiCP # nshvMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQE # AwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYB # BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0 # cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5j # cnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJ # YIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7ZvmKlEIgF+ZtbYIULh # sBguEE0TzzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI2AvlXFvXbYf6hCAl # NDFnzbYSlm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/tydBTX/6tPiix6q4XN # Q1/tYLaqT5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVPulr3qRCyXen/KFSJ # 8NWKcXZl2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmBo1aGqwpFyd/EjaDn # mPv7pp1yr8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc6UsCUqc3fpNTrDsd # CEkPlM05et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3cHXg65J6t5TRxktcm # a+Q4c6umAU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0dKNPH+ejxmF/7K9h+ # 8kaddSweJywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZPJ/tgZxahZrrdVcA6 # KYawmKAr7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLeMt8EifAAzV3C+dAj # fwAL5HYCJtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDyDivl1vupL0QVSucT # Dh3bNzgaoSv27dZ8/DCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJ # KoZIhvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu # YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQg # QXNzdXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1 # OVowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE # CxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBS # b290IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+Rd # SjwwIjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20d # q7J58soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7f # gvMHhOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRA # X7F6Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raR # mECQecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzU # vK4bA3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2 # mHY9WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkr # fsCUtNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaA # sPvoZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxf # jT/JvNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEe # xcCPorF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQF # MAMBAf8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaA # FEXroq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcB # AQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggr # BgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNz # dXJlZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5k # aWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQK # MAgwBgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3 # v1cHvZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy # 3iS8UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cn # RNTnf+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3 # WlxUjG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2 # zm8jLfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDGC # A3YwggNyAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ # bmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2 # IFRpbWVTdGFtcGluZyBDQQIQC65mvFq6f5WHxvnpBOMzBDANBglghkgBZQMEAgEF # AKCB0TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8X # DTI1MDExOTAyMTgyMVowKwYLKoZIhvcNAQkQAgwxHDAaMBgwFgQU29OF7mLb0j57 # 5PZxSFCHJNWGW0UwLwYJKoZIhvcNAQkEMSIEIGyG5g93davSLQJT1EeNhVOwlaOb # 9J2CZcw+6UZ16o8wMDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEIHZ2n6jyYy8fQws6 # IzCu1lZ1/tdz2wXWZbkFk5hDj5rbMA0GCSqGSIb3DQEBAQUABIICAD9owpiSfhpr # viRzu/raPHOC308lo+P5RLtu/ckTUDpY1YtG29lXJcKSCE+IJ2OOr2IxQ+Q1ih3v # EcdihG8kCbEbg9rqwGt7A7HUXJbTRP9wT6GbyRoQdtoh7MuhEL6gLCHHTVt4hnLL # AhjSjD7yzer6PdX2rRpQeuua4SW81Rrs48az4AKQKIgCgUWfMMlHm7renoqYGo9/ # PzE5JLvk9aaMiB0TmYoDW/DwzFI2cB+yrw7zoTzJW+GLl2h8eMi17NHZl4iYOOjE # yrEKYk6uEky/rdEiWgr9eSchJukpWTzgB7yCc4DgmY9tfOCWP8110E3VowUVKVCV # ytJRNTBfRXswg+seQwtavky5aMOkfJB1IS/WWMR/eeobssqqxqLutCQrqwpYl0bd # 3mrjzk4RLJFQPJqcfV6tiFi9z7vi92mxWsTz338Xb18SqOvftzJ2YKJoVMdvWv7/ # SD/392d1C2iDj/G+lc4ROBNk6uMiZa6IThMt3P3AIWYDJ0V+bvxuGWR1V13hiRGK # UG0qlOsnmvSKrbv9zxBPBVaNl5EnPsIdIvP9QEjnSiEQd9tdN5wBhBWr7QcM+o8z # mXRdV/Bd+bNC9LqGIYnV27U+OaL+2RdlWvf6PSgrzeuwrfQc53gqinFH9OZhwd8p # AB083+zFAW9rbBh8mb6lpxJvxD5EaOQ7 # SIG # End signature block |