GitHubLabels.ps1
# Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. function Get-GitHubLabel { <# .SYNOPSIS Retrieve label(s) of a given GitHub repository. .DESCRIPTION Retrieve label(s) of a given GitHub repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub .PARAMETER OwnerName Owner of the repository. If not supplied here, the DefaultOwnerName configuration property value will be used. .PARAMETER RepositoryName Name of the repository. If not supplied here, the DefaultRepositoryName configuration property value will be used. .PARAMETER Uri Uri for the repository. The OwnerName and RepositoryName will be extracted from here instead of needing to provide them individually. .PARAMETER Name Name of the specific label to be retieved. If not supplied, all labels will be retrieved. Emoji and codes are supported. For more information, see here: https://www.webpagefx.com/tools/emoji-cheat-sheet/ .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. .PARAMETER NoStatus If this switch is specified, long-running commands will run on the main thread with no commandline status update. When not specified, those commands run in the background, enabling the command prompt to provide status information. If not supplied here, the DefaultNoStatus configuration property value will be used. .EXAMPLE Get-GitHubLabel -OwnerName Powershell -RepositoryName PowerShellForGitHub Gets the information for every label from the PowerShell\PowerShellForGitHub project. .EXAMPLE Get-GitHubLabel -OwnerName Powershell -RepositoryName PowerShellForGitHub -LabelName TestLabel Gets the information for the label named "TestLabel" from the PowerShell\PowerShellForGitHub project. #> [CmdletBinding( SupportsShouldProcess, DefaultParametersetName='Elements')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] param( [Parameter(ParameterSetName='Elements')] [string] $OwnerName, [Parameter(ParameterSetName='Elements')] [string] $RepositoryName, [Parameter( Mandatory, ParameterSetName='Uri')] [string] $Uri, [Alias('LabelName')] [string] $Name, [string] $AccessToken, [switch] $NoStatus ) Write-InvocationLog $elements = Resolve-RepositoryElements $OwnerName = $elements.ownerName $RepositoryName = $elements.repositoryName $telemetryProperties = @{ 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) } $params = @{ 'UriFragment' = "repos/$OwnerName/$RepositoryName/labels/$Name" 'Description' = "Getting all labels for $RepositoryName" 'AcceptHeader' = 'application/vnd.github.symmetra-preview+json' 'AccessToken' = $AccessToken 'TelemetryEventName' = $MyInvocation.MyCommand.Name 'TelemetryProperties' = $telemetryProperties 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) } if (-not [String]::IsNullOrWhiteSpace($Name)) { $params["Description"] = "Getting label $Name for $RepositoryName" } return Invoke-GHRestMethodMultipleResult @params } function New-GitHubLabel { <# .SYNOPSIS Create a new label on a given GitHub repository. .DESCRIPTION Create a new label on a given GitHub repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub .PARAMETER OwnerName Owner of the repository. If not supplied here, the DefaultOwnerName configuration property value will be used. .PARAMETER RepositoryName Name of the repository. If not supplied here, the DefaultRepositoryName configuration property value will be used. .PARAMETER Uri Uri for the repository. The OwnerName and RepositoryName will be extracted from here instead of needing to provide them individually. .PARAMETER Name Name of the label to be created. Emoji and codes are supported. For more information, see here: https://www.webpagefx.com/tools/emoji-cheat-sheet/ .PARAMETER Color Color (in HEX) for the new label, without the leading # sign. .PARAMETER Description A short description of the label. .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. .PARAMETER NoStatus If this switch is specified, long-running commands will run on the main thread with no commandline status update. When not specified, those commands run in the background, enabling the command prompt to provide status information. If not supplied here, the DefaultNoStatus configuration property value will be used. .EXAMPLE New-GitHubLabel -OwnerName PowerShell -RepositoryName PowerShellForGitHub -Name TestLabel -Color BBBBBB Creates a new, grey-colored label called "TestLabel" in the PowerShellForGitHub project. #> [CmdletBinding( SupportsShouldProcess, DefaultParametersetName='Elements')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] param( [Parameter(ParameterSetName='Elements')] [string] $OwnerName, [Parameter(ParameterSetName='Elements')] [string] $RepositoryName, [Parameter( Mandatory, ParameterSetName='Uri')] [string] $Uri, [Parameter(Mandatory)] [Alias('LabelName')] [string] $Name, [Parameter(Mandatory)] [Alias('LabelColor')] [ValidateScript({if ($_ -match '^#?[ABCDEF0-9]{6}$') { $true } else { throw "Color must be provided in hex." }})] [string] $Color = "EEEEEE", [string] $Description, [string] $AccessToken, [switch] $NoStatus ) Write-InvocationLog $elements = Resolve-RepositoryElements $OwnerName = $elements.ownerName $RepositoryName = $elements.repositoryName $telemetryProperties = @{ 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) } # Be robust to users who choose to provide a color in hex by specifying the leading # sign # (by just stripping it out). if ($Color.StartsWith('#')) { $Color = $Color.Substring(1) } $hashBody = @{ 'name' = $Name 'color' = $Color 'description' = $Description } $params = @{ 'UriFragment' = "repos/$OwnerName/$RepositoryName/labels" 'Body' = (ConvertTo-Json -InputObject $hashBody) 'Method' = 'Post' 'Description' = "Creating label $Name in $RepositoryName" 'AcceptHeader' = 'application/vnd.github.symmetra-preview+json' 'AccessToken' = $AccessToken 'TelemetryEventName' = $MyInvocation.MyCommand.Name 'TelemetryProperties' = $telemetryProperties 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) } return Invoke-GHRestMethod @params } function Remove-GitHubLabel { <# .SYNOPSIS Deletes a label from a given GitHub repository. .DESCRIPTION Deletes a label from a given GitHub repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub .PARAMETER OwnerName Owner of the repository. If not supplied here, the DefaultOwnerName configuration property value will be used. .PARAMETER RepositoryName Name of the repository. If not supplied here, the DefaultRepositoryName configuration property value will be used. .PARAMETER Uri Uri for the repository. The OwnerName and RepositoryName will be extracted from here instead of needing to provide them individually. .PARAMETER Name Name of the label to be deleted. Emoji and codes are supported. For more information, see here: https://www.webpagefx.com/tools/emoji-cheat-sheet/ .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. .PARAMETER NoStatus If this switch is specified, long-running commands will run on the main thread with no commandline status update. When not specified, those commands run in the background, enabling the command prompt to provide status information. If not supplied here, the DefaultNoStatus configuration property value will be used. .EXAMPLE Remove-GitHubLabel -OwnerName PowerShell -RepositoryName PowerShellForGitHub -Name TestLabel Removes the label called "TestLabel" from the PowerShellForGitHub project. #> [CmdletBinding( SupportsShouldProcess, DefaultParametersetName='Elements')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] [Alias('Delete-GitHubLabel')] param( [Parameter(ParameterSetName='Elements')] [string] $OwnerName, [Parameter(ParameterSetName='Elements')] [string] $RepositoryName, [Parameter( Mandatory, ParameterSetName='Uri')] [string] $Uri, [Parameter(Mandatory)] [Alias('LabelName')] [string] $Name, [string] $AccessToken, [switch] $NoStatus ) Write-InvocationLog $elements = Resolve-RepositoryElements $OwnerName = $elements.ownerName $RepositoryName = $elements.repositoryName $telemetryProperties = @{ 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) } $params = @{ 'UriFragment' = "repos/$OwnerName/$RepositoryName/labels/$Name" 'Method' = 'Delete' 'Description' = "Deleting label $Name from $RepositoryName" 'AcceptHeader' = 'application/vnd.github.symmetra-preview+json' 'AccessToken' = $AccessToken 'TelemetryEventName' = $MyInvocation.MyCommand.Name 'TelemetryProperties' = $telemetryProperties 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) } return Invoke-GHRestMethod @params } function Update-GitHubLabel { <# .SYNOPSIS Updates an existing label on a given GitHub repository. .DESCRIPTION Updates an existing label on a given GitHub repository. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub .PARAMETER OwnerName Owner of the repository. If not supplied here, the DefaultOwnerName configuration property value will be used. .PARAMETER RepositoryName Name of the repository. If not supplied here, the DefaultRepositoryName configuration property value will be used. .PARAMETER Uri Uri for the repository. The OwnerName and RepositoryName will be extracted from here instead of needing to provide them individually. .PARAMETER Name Current name of the label to be updated. Emoji and codes are supported. For more information, see here: https://www.webpagefx.com/tools/emoji-cheat-sheet/ .PARAMETER NewName New name for the label being updated. Emoji and codes are supported. For more information, see here: https://www.webpagefx.com/tools/emoji-cheat-sheet/ .PARAMETER Color Color (in HEX) for the new label, without the leading # sign. .PARAMETER Description A short description of the label. .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. .PARAMETER NoStatus If this switch is specified, long-running commands will run on the main thread with no commandline status update. When not specified, those commands run in the background, enabling the command prompt to provide status information. If not supplied here, the DefaultNoStatus configuration property value will be used. .EXAMPLE Update-GitHubLabel -OwnerName Powershell -RepositoryName PowerShellForGitHub -Name TestLabel -NewName NewTestLabel -LabelColor BBBB00 Updates the existing label called TestLabel in the PowerShellForGitHub project to be called 'NewTestLabel' and be colored yellow. #> [CmdletBinding( SupportsShouldProcess, DefaultParametersetName='Elements')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] param( [Parameter(ParameterSetName='Elements')] [string] $OwnerName, [Parameter(ParameterSetName='Elements')] [string] $RepositoryName, [Parameter( Mandatory, ParameterSetName='Uri')] [string] $Uri, [Parameter(Mandatory)] [Alias('LabelName')] [string] $Name, [Parameter(Mandatory)] [Alias('NewLabelName')] [string] $NewName, [Parameter(Mandatory)] [Alias('LabelColor')] [ValidateScript({if ($_ -match '^#?[ABCDEF0-9]{6}$') { $true } else { throw "Color must be provided in hex." }})] [string] $Color = "EEEEEE", [string] $Description, [string] $AccessToken, [switch] $NoStatus ) Write-InvocationLog $elements = Resolve-RepositoryElements $OwnerName = $elements.ownerName $RepositoryName = $elements.repositoryName $telemetryProperties = @{ 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) } $hashBody = @{} if ($PSBoundParameters.ContainsKey('NewName')) { $hashBody['name'] = $NewName } if ($PSBoundParameters.ContainsKey('Color')) { $hashBody['color'] = $Color } if ($PSBoundParameters.ContainsKey('Description')) { $hashBody['description'] = $Description } $params = @{ 'UriFragment' = "repos/$OwnerName/$RepositoryName/labels/$Name" 'Body' = (ConvertTo-Json -InputObject $hashBody) 'Method' = 'Patch' 'Description' = "Updating label $Name" 'AcceptHeader' = 'application/vnd.github.symmetra-preview+json' 'AccessToken' = $AccessToken 'TelemetryEventName' = $MyInvocation.MyCommand.Name 'TelemetryProperties' = $telemetryProperties 'NoStatus' = (Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus) } return Invoke-GHRestMethod @params } function Set-GitHubLabel { <# .SYNOPSIS Sets the entire set of Labels on the given GitHub repository to match the provided list of Labels. .DESCRIPTION Sets the entire set of Labels on the given GitHub repository to match the provided list of Labels. Will update the color/description for any Labels already in the repository that match the name of a Label in the provided list. All other existing Labels will be removed, and then new Labels will be created to match the others in the Label list. The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub .PARAMETER OwnerName Owner of the repository. If not supplied here, the DefaultOwnerName configuration property value will be used. .PARAMETER RepositoryName Name of the repository. If not supplied here, the DefaultRepositoryName configuration property value will be used. .PARAMETER Uri Uri for the repository. The OwnerName and RepositoryName will be extracted from here instead of needing to provide them individually. .PARAMETER Label The array of Labels (name, color, description) that the repository should be aligning to. A default list of labels will be used if no Labels are provided. .PARAMETER AccessToken If provided, this will be used as the AccessToken for authentication with the REST Api. Otherwise, will attempt to use the configured value or will run unauthenticated. .PARAMETER NoStatus If this switch is specified, long-running commands will run on the main thread with no commandline status update. When not specified, those commands run in the background, enabling the command prompt to provide status information. If not supplied here, the DefaultNoStatus configuration property value will be used. .NOTES This method does not rename any existing labels, as it doesn't have any context regarding which Issue the new name is for. Therefore, it is possible that by running this function on a repository with Issues that have already been assigned Labels, you may experience data loss as a minor correction to you (maye fixing a typo) will result in the old Label being removed (and thus unassigned from existing Issues) and then the new one created. .EXAMPLE Set-GitHubLabel -OwnerName Powershell -RepositoryName PowerShellForGitHub -Label @(@{'name' = 'TestLabel'; 'color' = 'EEEEEE'}, @{'name' = 'critical'; 'color' = 'FF000000'; 'description' = 'Needs immediate attention'}) Removes any labels not in this Label array, ensure the current assigned color and descriptions match what's in the array for the labels that do already exist, and then creates new labels for any remaining ones in the Label list. #> [CmdletBinding( SupportsShouldProcess, DefaultParametersetName='Elements')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification="Methods called within here make use of PSShouldProcess, and the switch is passed on to them inherently.")] param( [Parameter(ParameterSetName='Elements')] [string] $OwnerName, [Parameter(ParameterSetName='Elements')] [string] $RepositoryName, [Parameter( Mandatory, ParameterSetName='Uri')] [string] $Uri, [object[]] $Label, [string] $AccessToken, [switch] $NoStatus ) if (($null -eq $Label) -or ($Label.Count -eq 0)) { $Label = $script:defaultGitHubLabels } $elements = Resolve-RepositoryElements $OwnerName = $elements.ownerName $RepositoryName = $elements.repositoryName $NoStatus = Resolve-ParameterWithDefaultConfigurationValue -Name NoStatus -ConfigValueName DefaultNoStatus $commonParams = @{ 'OwnerName' = $OwnerName 'RepositoryName' = $RepositoryName 'AccessToken' = $AccessToken 'NoStatus' = $NoStatus } $labelNames = $Label.name $existingLabels = Get-GitHubLabel @commonParams $existingLabelNames = $existingLabels.name foreach ($labelToConfigure in $Label) { if ($labelToConfigure.name -notin $existingLabelNames) { # Create label if it doesn't exist $null = New-GitHubLabel -Name $labelToConfigure.name -Color $labelToConfigure.color @commonParams } else { # Update label's color if it already exists $null = Update-GitHubLabel -Name $labelToConfigure.name -NewName $labelToConfigure.name -Color $labelToConfigure.color @commonParams } } foreach ($labelName in $existingLabelNames) { if ($labelName -notin $labelNames) { # Remove label if it exists but is not in desired label list $null = Remove-GitHubLabel -Name $labelName @commonParams } } } # A set of labels that a project might want to initially populate their repository with # Used by Set-GitHubLabel when no Label list is provided by the user. # This list exists to support v0.1.0 users. $script:defaultGitHubLabels = @( @{ 'name' = 'pri:lowest' 'color' = '4285F4' }, @{ 'name' = 'pri:low' 'color' = '4285F4' }, @{ 'name' = 'pri:medium' 'color' = '4285F4' }, @{ 'name' = 'pri:high' 'color' = '4285F4' }, @{ 'name' = 'pri:highest' 'color' = '4285F4' }, @{ 'name' = 'bug' 'color' = 'fc2929' }, @{ 'name' = 'duplicate' 'color' = 'cccccc' }, @{ 'name' = 'enhancement' 'color' = '121459' }, @{ 'name' = 'up for grabs' 'color' = '159818' }, @{ 'name' = 'question' 'color' = 'cc317c' }, @{ 'name' = 'discussion' 'color' = 'fe9a3d' }, @{ 'name' = 'wontfix' 'color' = 'dcb39c' }, @{ 'name' = 'in progress' 'color' = 'f0d218' }, @{ 'name' = 'ready' 'color' = '145912' } ) # SIG # Begin signature block # MIIdjgYJKoZIhvcNAQcCoIIdfzCCHXsCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUd5BZMMHgwdhEOEE6cCjicpKD # Tn+gghhqMIIE2jCCA8KgAwIBAgITMwAAAO87PT5gr0llIAAAAAAA7zANBgkqhkiG # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTgwODIzMjAxOTQ0 # WhcNMTkxMTIzMjAxOTQ0WjCByjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEm # MCQGA1UECxMdVGhhbGVzIFRTUyBFU046RDIzNi0zN0RBLTk3NjExJTAjBgNVBAMT # HE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQDKAoM+JZXt2QHAW0fzq1A+Eo16GzOcOwaU0Md9QcQgH4vF # A7R5Xec8Y0+rH89t/hcWGC9zFc900QCAia3VZgM7i6bRFRL5A0YUMv6F7UPWTqpp # irccYGjVrs7RiJtGbPUKaKCKhhTZ1NA1FC6QwsWmyo+a/R1gFtcoHdCN6xn0RMvh # 4RcIGSIiDr6VmtdW3N0qDDo8/TXxDS1roCh5bOTIFjSlNAFbqYnp7L8zPYwdizWy # /URm75I+dxfNhngTgGj7KyJhksgIlSzko0XdKRnyaF22PL806UaXylklK5SDdTDk # 05GaAyV8e+tIsMdVQ0hwgh05BGExE0R06NHjnxUrAgMBAAGjggEJMIIBBTAdBgNV # HQ4EFgQUlB6M3h0tMwUDjaUAKcF+hH9WAQUwHwYDVR0jBBgwFoAUIzT42VJGcArt # QPt2+7MrsMM1sw8wVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5taWNyb3Nv # ZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljcm9zb2Z0VGltZVN0YW1wUENBLmNy # bDBYBggrBgEFBQcBAQRMMEowSAYIKwYBBQUHMAKGPGh0dHA6Ly93d3cubWljcm9z # b2Z0LmNvbS9wa2kvY2VydHMvTWljcm9zb2Z0VGltZVN0YW1wUENBLmNydDATBgNV # HSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAOyvqWaVgRVzte8SC # JjkB4tn6LHoWT+a3vrtOckmUgC4Lmz0dxCRsixSVnz4RXwM3Y9i3Yry65S570jHb # UM2Cw2ZN9Z86wjSwn7S4XGgFPSh+Q1l0fyqpDm7pHKk+B1maKEeqfQxFVIcrGmaV # fRm/l0OWSplyxZ70Z2EfK6nVruSbELs/2HMPJh5pcc+w7xKGGWpnIVwYHj6ahacD # bIyD72HqpFqHkRv4ufWFbAzgoW+2eXXDSi5Eg54PYjXzRGTkj3d1MGlLJaRiwsf5 # ZHty2uZlComeJ/bNoCCWuyBmxY/1mmWo6hGvFcOoxxjauDui4lOJYhgXue6OUzSn # H1vdLTCCBf8wggPnoAMCAQICEzMAAAEDXiUcmR+jHrgAAAAAAQMwDQYJKoZIhvcN # AQELBQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV # BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYG # A1UEAxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMTAeFw0xODA3MTIy # MDA4NDhaFw0xOTA3MjYyMDA4NDhaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xHjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIw # DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANGUdjbmhqs2/mn5RnyLiFDLkHB/ # sFWpJB1+OecFnw+se5eyznMK+9SbJFwWtTndG34zbBH8OybzmKpdU2uqw+wTuNLv # z1d/zGXLr00uMrFWK040B4n+aSG9PkT73hKdhb98doZ9crF2m2HmimRMRs621TqM # d5N3ZyGctloGXkeG9TzRCcoNPc2y6aFQeNGEiOIBPCL8r5YIzF2ZwO3rpVqYkvXI # QE5qc6/e43R6019Gl7ziZyh3mazBDjEWjwAPAf5LXlQPysRlPwrjo0bb9iwDOhm+ # aAUWnOZ/NL+nh41lOSbJY9Tvxd29Jf79KPQ0hnmsKtVfMJE75BRq67HKBCMCAwEA # AaOCAX4wggF6MB8GA1UdJQQYMBYGCisGAQQBgjdMCAEGCCsGAQUFBwMDMB0GA1Ud # DgQWBBRHvsDL4aY//WXWOPIDXbevd/dA/zBQBgNVHREESTBHpEUwQzEpMCcGA1UE # CxMgTWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xFjAUBgNVBAUTDTIz # MDAxMis0Mzc5NjUwHwYDVR0jBBgwFoAUSG5k5VAF04KqFzc3IrVtqMp1ApUwVAYD # VR0fBE0wSzBJoEegRYZDaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j # cmwvTWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNybDBhBggrBgEFBQcBAQRV # MFMwUQYIKwYBBQUHMAKGRWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv # Y2VydHMvTWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNydDAMBgNVHRMBAf8E # AjAAMA0GCSqGSIb3DQEBCwUAA4ICAQCf9clTDT8NJuyiRNgN0Z9jlgZLPx5cxTOj # pMNsrx/AAbrrZeyeMxAPp6xb1L2QYRfnMefDJrSs9SfTSJOGiP4SNZFkItFrLTuo # LBWUKdI3luY1/wzOyAYWFp4kseI5+W4OeNgMG7YpYCd2NCSb3bmXdcsBO62CEhYi # gIkVhLuYUCCwFyaGSa/OfUUVQzSWz4FcGCzUk/Jnq+JzyD2jzfwyHmAc6bAbMPss # uwculoSTRShUXM2W/aDbgdi2MMpDsfNIwLJGHF1edipYn9Tu8vT6SEy1YYuwjEHp # qridkPT/akIPuT7pDuyU/I2Au3jjI6d4W7JtH/lZwX220TnJeeCDHGAK2j2w0e02 # v0UH6Rs2buU9OwUDp9SnJRKP5najE7NFWkMxgtrYhK65sB919fYdfVERNyfotTWE # cfdXqq76iXHJmNKeWmR2vozDfRVqkfEU9PLZNTG423L6tHXIiJtqv5hFx2ay1//O # kpB15OvmhtLIG9snwFuVb0lvWF1pKt5TS/joynv2bBX5AxkPEYWqT5q/qlfdYMb1 # cSD0UaiayunR6zRHPXX6IuxVP2oZOWsQ6Vo/jvQjeDCy8qY4yzWNqphZJEC4Omek # B1+g/tg7SRP7DOHtC22DUM7wfz7g2QjojCFKQcLe645b7gPDHW5u5lQ1ZmdyfBrq # UvYixHI/rjCCBgcwggPvoAMCAQICCmEWaDQAAAAAABwwDQYJKoZIhvcNAQEFBQAw # XzETMBEGCgmSJomT8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29m # dDEtMCsGA1UEAxMkTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # MB4XDTA3MDQwMzEyNTMwOVoXDTIxMDQwMzEzMDMwOVowdzELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWljcm9zb2Z0IFRpbWUt # U3RhbXAgUENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn6Fssd/b # SJIqfGsuGeG94uPFmVEjUK3O3RhOJA/u0afRTK10MCAR6wfVVJUVSZQbQpKumFww # JtoAa+h7veyJBw/3DgSY8InMH8szJIed8vRnHCz8e+eIHernTqOhwSNTyo36Rc8J # 0F6v0LBCBKL5pmyTZ9co3EZTsIbQ5ShGLieshk9VUgzkAyz7apCQMG6H81kwnfp+ # 1pez6CGXfvjSE/MIt1NtUrRFkJ9IAEpHZhEnKWaol+TTBoFKovmEpxFHFAmCn4Tt # VXj+AZodUAiFABAwRu233iNGu8QtVJ+vHnhBMXfMm987g5OhYQK1HQ2x/PebsgHO # IktU//kFw8IgCwIDAQABo4IBqzCCAacwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E # FgQUIzT42VJGcArtQPt2+7MrsMM1sw8wCwYDVR0PBAQDAgGGMBAGCSsGAQQBgjcV # AQQDAgEAMIGYBgNVHSMEgZAwgY2AFA6sgmBAVieX5SUT/CrhClOVWeSkoWOkYTBf # MRMwEQYKCZImiZPyLGQBGRYDY29tMRkwFwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0 # MS0wKwYDVQQDEyRNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmC # EHmtFqFKoKWtTHNY9AcTLmUwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5t # aWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvbWljcm9zb2Z0cm9vdGNlcnQu # Y3JsMFQGCCsGAQUFBwEBBEgwRjBEBggrBgEFBQcwAoY4aHR0cDovL3d3dy5taWNy # b3NvZnQuY29tL3BraS9jZXJ0cy9NaWNyb3NvZnRSb290Q2VydC5jcnQwEwYDVR0l # BAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQEFBQADggIBABCXisNcA0Q23em0rXfb # znlRTQGxLnRxW20ME6vOvnuPuC7UEqKMbWK4VwLLTiATUJndekDiV7uvWJoc4R0B # hqy7ePKL0Ow7Ae7ivo8KBciNSOLwUxXdT6uS5OeNatWAweaU8gYvhQPpkSokInD7 # 9vzkeJkuDfcH4nC8GE6djmsKcpW4oTmcZy3FUQ7qYlw/FpiLID/iBxoy+cwxSnYx # PStyC8jqcD3/hQoT38IKYY7w17gX606Lf8U1K16jv+u8fQtCe9RTciHuMMq7eGVc # WwEXChQO0toUmPU8uWZYsy0v5/mFhsxRVuidcJRsrDlM1PZ5v6oYemIp76KbKTQG # dxpiyT0ebR+C8AvHLLvPQ7Pl+ex9teOkqHQ1uE7FcSMSJnYLPFKMcVpGQxS8s7Ow # TWfIn0L/gHkhgJ4VMGboQhJeGsieIiHQQ+kr6bv0SMws1NgygEwmKkgkX1rqVu+m # 3pmdyjpvvYEndAYR7nYhv5uCwSdUtrFqPYmhdmG0bqETpr+qR/ASb/2KMmyy/t9R # yIwjyWa9nR2HEmQCPS2vWY+45CHltbDKY7R4VAXUQS5QrJSwpXirs6CWdRrZkocT # dSIvMqgIbqBbjCW/oO+EyiHW6x5PyZruSeD3AWVviQt9yGnI5m7qp5fOMSn/DsVb # XNhNG6HY+i+ePy5VFmvJE6P9MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg # Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03 # a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr # rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg # OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy # 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9 # sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh # dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k # A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB # w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn # Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90 # lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w # ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o # ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa # BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG # AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV # HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG # AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl # AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb # C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l # hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6 # I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0 # wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560 # STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam # ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa # J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah # XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA # 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt # Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr # /Xmfwb1tbWrJUnMTDXpQzTGCBI4wggSKAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAAEDXiUcmR+jHrgAAAAAAQMwCQYFKw4DAhoFAKCB # ojAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYK # KwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUVq0k8q8uiQKu5PjuT3XAV6Wqp8sw # QgYKKwYBBAGCNwIBDDE0MDKgFIASAE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6 # Ly93d3cubWljcm9zb2Z0LmNvbTANBgkqhkiG9w0BAQEFAASCAQB4GuiFiAFriDsS # VAvh9EfrivFl5JHBD5u3LrEYiO2Di5QuB9EmEPgd9q7epKAQT94eKDfmL6wH0Dka # Rqc/6Vm5UjkEjUq+AQHe2RqOPA5OxHH5UpJ0Wa5YAvnLLN/1Buxz11uFABIetKkv # jkGxipZU852s+Cv0DxviPyWbnEEPP7p+6A/LF3xQR/DKRIFDfErbhERwCLqW3pfI # CncruJuxLqJI4uk3ST+TF4dKSyFXxEXyKkkOHu/dDBxhrdLRu9dCd3IZUuuIVUtl # NeUKrQRBL7IBn2UP0cKdWNL4L/6oQhuKF+jy2vIew4fRHGhhAIBLBOOiBNQN6jOd # YezeiznMoYICKDCCAiQGCSqGSIb3DQEJBjGCAhUwggIRAgEBMIGOMHcxCzAJBgNV # BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w # HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xITAfBgNVBAMTGE1pY3Jvc29m # dCBUaW1lLVN0YW1wIFBDQQITMwAAAO87PT5gr0llIAAAAAAA7zAJBgUrDgMCGgUA # oF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTgx # MjAxMDEwOTQ1WjAjBgkqhkiG9w0BCQQxFgQUb1bieKVrnKVteuXFC/DD7jhpJjww # DQYJKoZIhvcNAQEFBQAEggEAqYoJpqOWkDSXrd8njmyoGwYhNKXKLS+4b/JkI/21 # nfkNCDRSds5RauRnBxbQ/PEgrd0uWj+2u4w8N4E0WXb31AhZLQsXqTFTEJltRHwC # Eqow/Y0gOkQVmKF/cxbGa6rFD/I2bjnKi8LdyaVfeJiTo6aDxwsVJZVStXe9s6/G # ABGBwb2Wg8bTJg87onI8efBmMflVt9CLOPEQ9v6AMVhiWENt2/0iGyvjgDX6Vnz5 # +Xa12s86RpSUkNvHIzydXfbI6yDYmcVwMEjtqxc5UZCJTOYRQEsW8uJyVc3+kKsp # ZFaN2zUvQ/0sFGqDWnZIXt1B9njvBxMZm1izjxGyOi0KwA== # SIG # End signature block |