AI/Tasks/Use-TaskTemplate.ps1

#!/usr/bin/env pwsh
<#
.SYNOPSIS
    Lists available task templates and copies a chosen template into a
    destination file.
 
.DESCRIPTION
    Helps reuse prompt templates stored under AI/Tasks/Templates by listing them
    or copying one template into AI/Tasks/CurrentTask.txt or another destination
    path.
 
.PARAMETER Template
    File name of the template to copy, for example CSharp-BugFix-InPlace.txt.
 
.PARAMETER Destination
    Destination file path for the copied template. Defaults to
    AI/Tasks/CurrentTask.txt.
 
.PARAMETER List
    Lists available templates and exits.
 
.PARAMETER Show
    Writes the selected template content to the console.
 
.PARAMETER Open
    Opens the selected template file in VS Code when available, otherwise in the
    default associated application.
 
.PARAMETER Pick
    Presents an interactive numbered picker to choose a template.
 
.PARAMETER SelectionNumber
    Selects a template by its 1-based number in the picker list. Intended for
    automation or testing.
 
.PARAMETER Category
    Filters templates by category name before listing, picking, showing,
    opening, or copying.
 
.PARAMETER Force
    Overwrites an existing destination file without prompting.
 
.EXAMPLE
    .\AI\Tasks\Use-TaskTemplate.ps1 -List
 
    Lists the available task templates.
 
.EXAMPLE
    .\AI\Tasks\Use-TaskTemplate.ps1 -Template PowerShell-BugFix-InPlace.txt
 
    Copies the selected template into AI/Tasks/CurrentTask.txt.
 
.EXAMPLE
    .\AI\Tasks\Use-TaskTemplate.ps1 -Template CSharp-BugFix-InPlace -Show
 
    Prints the selected template to the console.
 
.EXAMPLE
    .\AI\Tasks\Use-TaskTemplate.ps1 -Template PowerShell-HelpAuthoring-Review -Open
 
    Opens the selected template file.
 
.EXAMPLE
    .\AI\Tasks\Use-TaskTemplate.ps1 -Pick
 
    Presents an interactive picker and copies the selected template into AI/Tasks/CurrentTask.txt.
 
.EXAMPLE
    .\AI\Tasks\Use-TaskTemplate.ps1 -Pick -Show
 
    Presents an interactive picker and prints the selected template to the console.
 
.EXAMPLE
    .\AI\Tasks\Use-TaskTemplate.ps1 -List -Category PowerShell
 
    Lists only PowerShell-related templates.
#>


[CmdletBinding()]
param(
    [string]$Template,
    [string]$Destination,
    [switch]$List,
    [switch]$Show,
    [switch]$Open,
    [switch]$Pick,
    [int]$SelectionNumber,
    [string]$Category,
    [switch]$Force
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

$moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
$taskRoot = Join-Path $moduleRoot 'AI\Tasks'

if ([string]::IsNullOrWhiteSpace($Destination)) {
    $Destination = Join-Path $taskRoot 'CurrentTask.txt'
}

$templateRoot = Join-Path $taskRoot 'Templates'

if (-not (Test-Path -LiteralPath $templateRoot)) {
    throw "Template directory not found: $templateRoot"
}

$templates = @(
    Get-ChildItem -LiteralPath $templateRoot -File -Filter '*.txt' | Sort-Object Name
)

$categoryMap = [ordered]@{
    'CSharp'     = @('CSharp-')
    'PowerShell' = @('PowerShell-')
    'General'    = @('General-')
    'Docs'       = @('Docs-')
    'Tests'      = @('Tests-')
    'Release'    = @('Release-')
    'CI'         = @('CI-')
    'Security'   = @('Security-')
}

$activeModes = @(@($List.IsPresent, $Show.IsPresent, $Open.IsPresent) | Where-Object { $_ })
if ($activeModes.Count -gt 1) {
    throw 'Specify only one of -List, -Show, or -Open.'
}

if ($Pick.IsPresent -and -not [string]::IsNullOrWhiteSpace($Template)) {
    throw 'Specify either -Template or -Pick, not both.'
}

if ($SelectionNumber -lt 0) {
    throw 'SelectionNumber must be zero or a positive integer.'
}

function Resolve-TemplatePath {
    param(
        [Parameter(Mandatory)]
        [string]$TemplateName,

        [Parameter(Mandatory)]
        [System.IO.FileInfo[]]$AvailableTemplates,

        [Parameter(Mandatory)]
        [string]$RootPath
    )

    $candidates = @($TemplateName)
    if ([System.IO.Path]::GetExtension($TemplateName) -eq [string]::Empty) {
        $candidates += "$TemplateName.txt"
    }

    foreach ($candidate in $candidates) {
        $match = $AvailableTemplates | Where-Object {
            $_.Name.Equals($candidate, [System.StringComparison]::OrdinalIgnoreCase)
        } | Select-Object -First 1

        if ($null -ne $match) {
            return $match.FullName
        }
    }

    return (Join-Path $RootPath $TemplateName)
}

function Get-AvailableCategoryNames {
    param(
        [Parameter(Mandatory)]
        [hashtable]$TemplateCategoryMap
    )

    return @($TemplateCategoryMap.Keys | Sort-Object)
}

function Get-TemplateCategory {
    param(
        [Parameter(Mandatory)]
        [string]$TemplateName,

        [Parameter(Mandatory)]
        [hashtable]$TemplateCategoryMap
    )

    foreach ($entry in $TemplateCategoryMap.GetEnumerator()) {
        foreach ($prefix in $entry.Value) {
            if ($TemplateName.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)) {
                return $entry.Key
            }
        }
    }

    return 'Other'
}

function Filter-TemplatesByCategory {
    param(
        [Parameter(Mandatory)]
        [System.IO.FileInfo[]]$AvailableTemplates,

        [string]$RequestedCategory,

        [Parameter(Mandatory)]
        [hashtable]$TemplateCategoryMap
    )

    if ([string]::IsNullOrWhiteSpace($RequestedCategory)) {
        return $AvailableTemplates
    }

    $matchedCategory = Get-AvailableCategoryNames -TemplateCategoryMap $TemplateCategoryMap |
    Where-Object { $_.Equals($RequestedCategory, [System.StringComparison]::OrdinalIgnoreCase) } |
    Select-Object -First 1

    if ($null -eq $matchedCategory) {
        $availableCategories = (Get-AvailableCategoryNames -TemplateCategoryMap $TemplateCategoryMap) -join ', '
        throw "Unknown category '$RequestedCategory'. Available categories: $availableCategories"
    }

    return @(
        $AvailableTemplates | Where-Object {
            (Get-TemplateCategory -TemplateName $_.Name -TemplateCategoryMap $TemplateCategoryMap).Equals(
                $matchedCategory,
                [System.StringComparison]::OrdinalIgnoreCase
            )
        }
    )
}

$templates = Filter-TemplatesByCategory -AvailableTemplates $templates -RequestedCategory $Category -TemplateCategoryMap $categoryMap

function Select-TemplateFile {
    param(
        [Parameter(Mandatory)]
        [System.IO.FileInfo[]]$AvailableTemplates,

        [int]$PreselectedNumber = 0
    )

    if ($AvailableTemplates.Count -eq 0) {
        throw 'No task templates found.'
    }

    Write-Host 'Available task templates:' -ForegroundColor Cyan
    for ($index = 0; $index -lt $AvailableTemplates.Count; $index++) {
        Write-Host ('[{0}] {1}' -f ($index + 1), $AvailableTemplates[$index].Name)
    }

    $selectedIndex = -1
    while ($selectedIndex -lt 0) {
        $rawChoice = if ($PreselectedNumber -gt 0) {
            [string]$PreselectedNumber
        }
        else {
            Read-Host 'Enter template number'
        }

        if (-not [int]::TryParse($rawChoice, [ref]$selectedIndex)) {
            $selectedIndex = -1
            if ($PreselectedNumber -gt 0) {
                throw "SelectionNumber '$PreselectedNumber' is not valid."
            }

            Write-Warning 'Enter a valid number from the list.'
            continue
        }

        $selectedIndex--
        if ($selectedIndex -lt 0 -or $selectedIndex -ge $AvailableTemplates.Count) {
            $selectedIndex = -1
            if ($PreselectedNumber -gt 0) {
                throw "SelectionNumber '$PreselectedNumber' is out of range."
            }

            Write-Warning 'Enter a number that matches one of the listed templates.'
        }
    }

    return $AvailableTemplates[$selectedIndex].FullName
}

if ($List.IsPresent) {
    if ($templates.Count -eq 0) {
        if ([string]::IsNullOrWhiteSpace($Category)) {
            Write-Host 'No task templates found.'
        }
        else {
            Write-Host ("No task templates found for category '{0}'." -f $Category)
        }
        return
    }

    if ([string]::IsNullOrWhiteSpace($Category)) {
        Write-Host 'Available task templates:' -ForegroundColor Cyan
    }
    else {
        Write-Host ("Available task templates for category '{0}':" -f $Category) -ForegroundColor Cyan
    }
    foreach ($item in $templates) {
        $templateCategory = Get-TemplateCategory -TemplateName $item.Name -TemplateCategoryMap $categoryMap
        Write-Host ("- {0} [{1}]" -f $item.Name, $templateCategory)
    }

    return
}

if ([string]::IsNullOrWhiteSpace($Template)) {
    if (-not $Pick.IsPresent) {
        throw 'Specify -Template <FileName>, use -Pick, or use -List to see available templates.'
    }
}

$sourcePath = if ($Pick.IsPresent) {
    Select-TemplateFile -AvailableTemplates $templates -PreselectedNumber $SelectionNumber
}
else {
    Resolve-TemplatePath -TemplateName $Template -AvailableTemplates $templates -RootPath $templateRoot
}
if (-not (Test-Path -LiteralPath $sourcePath)) {
    $available = if ($templates.Count -gt 0) {
        ($templates.Name -join ', ')
    }
    else {
        '(none)'
    }

    throw "Template not found: $Template. Available templates: $available"
}

$resolvedTemplateName = Split-Path -Leaf $sourcePath

if ($Show.IsPresent) {
    Get-Content -LiteralPath $sourcePath -Raw | Write-Output
    return
}

if ($Open.IsPresent) {
    $codeCommand = Get-Command code -ErrorAction SilentlyContinue
    if ($null -ne $codeCommand) {
        & $codeCommand.Source --reuse-window $sourcePath | Out-Null
    }
    else {
        Invoke-Item -LiteralPath $sourcePath
    }

    Write-Host ("Opened template '{0}'." -f $resolvedTemplateName) -ForegroundColor Green
    return
}

$destinationDirectory = Split-Path -Parent $Destination
if (-not [string]::IsNullOrWhiteSpace($destinationDirectory) -and -not (Test-Path -LiteralPath $destinationDirectory)) {
    New-Item -ItemType Directory -Path $destinationDirectory -Force | Out-Null
}

if ((Test-Path -LiteralPath $Destination) -and -not $Force.IsPresent) {
    Write-Warning "Overwriting existing destination: $Destination"
}

$content = Get-Content -LiteralPath $sourcePath -Raw
Set-Content -LiteralPath $Destination -Value $content -NoNewline

Write-Host ("Copied template '{0}' to '{1}'." -f $resolvedTemplateName, $Destination) -ForegroundColor Green

# SIG # Begin signature block
# MIIfAgYJKoZIhvcNAQcCoIIe8zCCHu8CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDLyY3Mu1/BDI1W
# JxoZpWnLMi3LYfv7bKrcjnWnlDHwsKCCGEowggUMMIIC9KADAgECAhAR+U4xG7FH
# qkyqS9NIt7l5MA0GCSqGSIb3DQEBCwUAMB4xHDAaBgNVBAMME1ZBRFRFSyBDb2Rl
# IFNpZ25pbmcwHhcNMjUxMjE5MTk1NDIxWhcNMjYxMjE5MjAwNDIxWjAeMRwwGgYD
# VQQDDBNWQURURUsgQ29kZSBTaWduaW5nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
# MIICCgKCAgEA3pzzZIUEY92GDldMWuzvbLeivHOuMupgpwbezoG5v90KeuN03S5d
# nM/eom/PcIz08+fGZF04ueuCS6b48q1qFnylwg/C/TkcVRo0WFcKoFGT8yGxdfXi
# caHtapZfbSRh73r7qR7w0CioVveNBVgfMsTgE0WKcuwxemvIe/ptmkfzwAiw/IAC
# Ib0E0BjiX4PySbwWy/QKy/qMXYY19xpRItVTKNBtXzADUtzPzUcFqJU83vM2gZFs
# Or0MhPvM7xEVkOWZFBAWAubbMCJ3rmwyVv9keVDJChhCeLSz2XR11VGDOEA2OO90
# Y30WfY9aOI2sCfQcKMeJ9ypkHl0xORdhUwZ3Wz48d3yJDXGkduPm2vl05RvnA4T6
# 29HVZTmMdvP2475/8nLxCte9IB7TobAOGl6P1NuwplAMKM8qyZh62Br23vcx1fXZ
# TJlKCxBFx1nTa6VlIJk+UbM4ZPm954peB/fIqEacm8LkZ0cPwmLE5ckW7hfK4Trs
# o+RaudU1sKeA+FvpOWgsPccVRWcEYyGkwbyTB3xrIBXA+YckbANZ0XL7fv7x29hn
# gXbZipGu3DnTISiFB43V4MhNDKZYfbWdxze0SwLe8KzIaKnwlwRgvXDMwXgk99Mi
# EbYa3DvA/5ZWikLW9PxBFD7Vdr8ZiG/tRC9I2Y6fnb+PVoZKc/2xsW0CAwEAAaNG
# MEQwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQW
# BBRfYLVE8caSc990rnrIHUjoB7X/KjANBgkqhkiG9w0BAQsFAAOCAgEAiGB2Wmk3
# QBtd1LcynmxHzmu+X4Y5DIpMMNC2ahsqZtPUVcGqmb5IFbVuAdQphL6PSrDjaAR8
# 1S8uTfUnMa119LmIb7di7TlH2F5K3530h5x8JMj5EErl0xmZyJtSg7BTiBA/UrMz
# 6WCf8wWIG2/4NbV6aAyFwIojfAcKoO8ng44Dal/oLGzLO3FDE5AWhcda/FbqVjSJ
# 1zMfiW8odd4LgbmoyEI024KkwOkkPyJQ2Ugn6HMqlFLazAmBBpyS7wxdaAGrl18n
# 6bS7QuAwCd9hitdMMitG8YyWL6tKeRSbuTP5E+ASbu0Ga8/fxRO5ZSQhO6/5ro1j
# PGe1/Kr49Uyuf9VSCZdNIZAyjjeVAoxmV0IfxQLKz6VOG0kGDYkFGskvllIpQbQg
# WLuPLJxoskJsoJllk7MjZJwrpr08+3FQnLkRuisjDOc3l4VxFUsUe4fnJhMUONXT
# Sk7vdspgxirNbLmXU4yYWdsizz3nMUR0zebUW29A+HYme16hzrMPOeyoQjy4I5XX
# 3wXAFdworfPEr/ozDFrdXKgbLwZopymKbBwv6wtT7+1zVhJXr+jGVQ1TWr6R+8ea
# tIOFnY7HqGaxe5XB7HzOwJKdj+bpHAfXft1vUoiKr16VajLigcYCG8MdwC3sngO3
# JDyv2V+YMfsYBmItMGBwvizlQ6557NbK95EwggWNMIIEdaADAgECAhAOmxiO+dAt
# 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa
# Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD
# ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
# ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E
# MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy
# unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF
# xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1
# 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB
# MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR
# WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6
# nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB
# YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S
# UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x
# q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB
# NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP
# TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC
# AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
# Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0
# aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB
# LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc
# Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov
# Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy
# oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW
# juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF
# mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z
# twGpn1eqXijiuZQwgga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0GCSqG
# SIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx
# GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy
# dXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTlaMGkx
# CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4
# RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYg
# MjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHTCphB
# cr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPhof6p
# vF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mAxAHe
# HYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBvMgEd
# gkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps0wjU
# jsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF83bR
# VFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXiUOeS
# LsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOMCZIV
# NSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydPpOjL
# 6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrUG2Zd
# SoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+sdFU
# eEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0TAQH/
# BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYDVR0j
# BBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1Ud
# JQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0
# cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0
# cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8E
# PDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz
# dGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEw
# DQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WIGjB/
# T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+IQhQ
# E7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8Myb9r
# EVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2th9y
# 1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjajV/gx
# dEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2Lr3t
# y9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFzeGxcy
# tL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG7uEB
# YTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+NJpud
# /v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckTetiS
# uEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszWkPZP
# ubdcMIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG9w0BAQsF
# ADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNV
# BAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hB
# MjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1OVowYzEL
# MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJE
# aWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVyIDIwMjUg
# MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q6q5gVrMr
# V7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPnZ8ZN+vo8
# dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSssp3qome7M
# rxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09ldQ//nBZ
# ZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98oksouTMYFO
# nHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+3qU8DD+n
# igNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsnqcnpJeIt
# K/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQPdP51ho1
# zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbSLZ49kPmk
# 8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojTdS5PWPsW
# eupWs7NpChUk555K096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoKRR7YufAk
# prxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAAMB0G
# A1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTvb1NK6eQG
# fHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYB
# BQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
# cC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRzLmRpZ2lj
# ZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZTSEEy
# NTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2U0hB
# MjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcB
# MA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk9iJP2zWL
# pQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tshgb4O6Lgj
# g8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9mzskgiC3Q
# YIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQBHMUBaB5
# bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+YkDFkxUG
# tMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0cKsb+zJNE
# suEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY7T/lwd6U
# Arb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcbojBcxlRcGG
# 0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05oxYy2zRWV
# FjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskKPIJgbaP5
# t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjdNXOCIUjs
# arfNZzGCBg4wggYKAgEBMDIwHjEcMBoGA1UEAwwTVkFEVEVLIENvZGUgU2lnbmlu
# ZwIQEflOMRuxR6pMqkvTSLe5eTANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3
# AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisG
# AQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCAAiuZofVIf
# ZOCzcfMFMRpoJ0gaM5pPOLIcK4G4XIzxujANBgkqhkiG9w0BAQEFAASCAgCg3rf7
# oLNLgUIRw/41mGtWrW6h3qJXOaeF2v13h8o20nr9Z6DdQxZqcitDicOAR8j2Asf8
# co8obDjxO0BX126C15myXgLAmUk+alKwcwAvL2Mu7XhEPq5zrXJpie6PBq/YFX1D
# pJX6VVr9AapaHXpwaOZFkqxcZUXN7eQDK3X+nj4+PJFUMKqtyDNHBtGd9nDxd6kM
# 4VO7SNLxhFgzeTWAlcLroox1RSRmNg4/4G1c9tnj5qjyOwJOOhcpqp8w/+s4F3IU
# RpVpfh5efCAOCqsjEoH1ObmyelievlfAr7j9GY6F9GvDUJUwFYnkKqSalgOfiO1C
# oBn60pwICsb54PARjbV1qA8QvAFnMciOYhd3pbEHmYjjDMoMiRlN2sK1PE9X9fQR
# Yoc11xEZU9AL546eRAarrCDdPZ3wGbNYz8mI8ld3g9eebhYZjn2DhaDI/6zHXHP2
# ozu0tAyVeLvdNLZ6gbg30VjTvb4tuosLFI0gKagoVWYUEwsIaRe3kwYYs2TQem20
# bVJhqLUKw8VN7AGQLilGNDri8rJpxnMAihaRAiHxzsS20SOX0tJdbTyUalpmve8R
# 5ACVACdFPtfdbWJVPlpOr2o3dnK6oy9zRhMY2VXzWEBpFb0IWkJgEklxoV6GyXll
# BnWY1sIgsQi5S/njDwX2ZNZwvo588lpqAc05OKGCAyYwggMiBgkqhkiG9w0BCQYx
# ggMTMIIDDwIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcg
# UlNBNDA5NiBTSEEyNTYgMjAyNSBDQTECEAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZI
# AWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJ
# BTEPFw0yNjA3MTUwMzQ2MzNaMC8GCSqGSIb3DQEJBDEiBCBPq4Zo/3uXW23D0kPg
# yVcOFyQI8f5EIyOaotxA2U54VDANBgkqhkiG9w0BAQEFAASCAgAf807+H27y4Tps
# b2O/HgtdbROYgntgRMOXUD/RFrmpld9V1yqiVN6sU94h19VO0QvhZMlfLwVDScXp
# OF/KEFDuDiBo8nC8NpPHXH2WkwoqPcokcbzjmq+mgILt30vD0N64qreC9TuW9spB
# l5eP9X5RzgI+oR/LY0LTR2jRVah1S21ssqpqNawJRx+5GYOfAbAZPPtiG9h8j9vB
# tXdBFXmuxAbJ8e4QzK5TgY3EH4mYrK5KI5pxHpkoWBXu2tlDTTHScHLY2hsKKwsu
# KKNvDtCvwzu+PXzo/MvHCe4ptdQRpVZilRZChHIwI1nJbopPI6QbjnIAPAOINfVt
# 1brqN+Y8IVgbI3jzpcIeplbCEXkL3sLP0EJQZ7YQ5V/ktRq8Nos4qLSZAZWWxBNq
# VDihgnRK5Xe466aCNNqAi2IbNtMBFG5Ttbr/Chl1udTTy9yKVa6VpnBJBbdd87o2
# ibgnxyffExgKKbDW35GlRKiYx9TXXPeayOMKguBInDN5onLhWlB3T1Wgw5ROfI/h
# 5rqV+Pxijb6UCIiTS4G8otvLRBOjL0tAuqztxxw36bmYAllWrKtI/lUYkpI5bWdi
# OCyJY5amTW3z9bDMOq5pqgRYB2jzL/rPJ4q0VzejAR+28N/TGE5gCwMaPeco6L0O
# TfE8b+k8iqgopAaGHZBfcRSmTDgBTg==
# SIG # End signature block