GitHubContents.ps1
@{ GitHubContentTypeName = 'GitHub.Content' }.GetEnumerator() | ForEach-Object { Set-Variable -Scope Script -Option ReadOnly -Name $_.Key -Value $_.Value } filter Get-GitHubContent { <# .SYNOPSIS Retrieve the contents of a file or directory in a repository on GitHub. .DESCRIPTION Retrieve content from files on GitHub. 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 Path The file path for which to retrieve contents .PARAMETER BranchName The branch, or defaults to the default branch of not specified. .PARAMETER MediaType The format in which the API will return the body of the issue. Object - Return a json object representation a file or folder. This is the default if you do not pass any specific media type. Raw - Return the raw contents of a file. Html - For markup files such as Markdown or AsciiDoc, you can retrieve the rendered HTML using the Html media type. .PARAMETER ResultAsString If this switch is specified and the MediaType is either Raw or Html then the resulting bytes will be decoded the result will be returned as a string instead of bytes. If the MediaType is Object, then an additional property on the object named 'contentAsString' will be included and its value will be the decoded base64 result as a string. .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. .INPUTS GitHub.Branch GitHub.Content GitHub.Event GitHub.Issue GitHub.IssueComment GitHub.Label GitHub.Milestone GitHub.PullRequest GitHub.Project GitHub.ProjectCard GitHub.ProjectColumn GitHub.Reaction GitHub.Release GitHub.ReleaseAsset GitHub.Repository .OUTPUTS [String] GitHub.Content .EXAMPLE Get-GitHubContent -OwnerName microsoft -RepositoryName PowerShellForGitHub -Path README.md -MediaType Html Get the Html output for the README.md file .EXAMPLE Get-GitHubContent -OwnerName microsoft -RepositoryName PowerShellForGitHub -Path LICENSE Get the Binary file output for the LICENSE file .EXAMPLE Get-GitHubContent -OwnerName microsoft -RepositoryName PowerShellForGitHub -Path Tests List the files within the "Tests" path of the repository .EXAMPLE $repo = Get-GitHubRepository -OwnerName microsoft -RepositoryName PowerShellForGitHub $repo | Get-GitHubContent -Path Tests List the files within the "Tests" path of the repository .NOTES Unable to specify Path as ValueFromPipeline because a Repository object may be incorrectly coerced into a string used for Path, thus confusing things. #> [CmdletBinding(DefaultParameterSetName = 'Elements')] [OutputType([String])] [OutputType({$script:GitHubContentTypeName})] param( [Parameter( Mandatory, ParameterSetName = 'Elements')] [string] $OwnerName, [Parameter( Mandatory, ParameterSetName = 'Elements')] [string] $RepositoryName, [Parameter( Mandatory, ValueFromPipelineByPropertyName, ParameterSetName='Uri')] [Alias('RepositoryUrl')] [string] $Uri, [string] $Path, [ValidateNotNullOrEmpty()] [string] $BranchName, [ValidateSet('Raw', 'Html', 'Object')] [string] $MediaType = 'Object', [switch] $ResultAsString, [string] $AccessToken ) Write-InvocationLog $elements = Resolve-RepositoryElements $OwnerName = $elements.ownerName $RepositoryName = $elements.repositoryName $telemetryProperties = @{ 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) } $description = [String]::Empty $uriFragment = "/repos/$OwnerName/$RepositoryName/contents" if ($PSBoundParameters.ContainsKey('Path')) { $Path = $Path.TrimStart("\", "/") $uriFragment += "/$Path" $description = "Getting content for $Path in $RepositoryName" } else { $description = "Getting all content for in $RepositoryName" } if ($PSBoundParameters.ContainsKey('BranchName')) { $uriFragment += "?ref=$BranchName" } $params = @{ 'UriFragment' = $uriFragment 'Description' = $description 'AcceptHeader' = (Get-MediaAcceptHeader -MediaType $MediaType) 'AccessToken' = $AccessToken 'TelemetryEventName' = $MyInvocation.MyCommand.Name 'TelemetryProperties' = $telemetryProperties } $result = Invoke-GHRestMethodMultipleResult @params if ($ResultAsString) { if ($MediaType -eq 'Raw' -or $MediaType -eq 'Html') { # Decode bytes to string $result = [System.Text.Encoding]::UTF8.GetString($result) } elseif ($MediaType -eq 'Object') { # Convert from base64 $decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($result.content)) Add-Member -InputObject $result -NotePropertyName "contentAsString" -NotePropertyValue $decoded } } if ($MediaType -eq 'Object') { $null = $result | Add-GitHubContentAdditionalProperties } return $result } filter Set-GitHubContent { <# .SYNOPSIS Sets the contents of a file or directory in a repository on GitHub. .DESCRIPTION Sets the contents of a file or directory in a repository on GitHub. 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 Path The file path for which to set contents. .PARAMETER CommitMessage The Git commit message. .PARAMETER Content The new file content. .PARAMETER Sha The SHA value of the current file if present. If this parameter is not provided, and the file currently exists in the specified branch of the repo, it will be read to obtain this value. .PARAMETER BranchName The branch, or defaults to the default branch if not specified. .PARAMETER CommitterName The name of the committer of the commit. Defaults to the name of the authenticated user if not specified. If specified, CommiterEmail must also be specified. .PARAMETER CommitterEmail The email of the committer of the commit. Defaults to the email of the authenticated user if not specified. If specified, CommitterName must also be specified. .PARAMETER AuthorName The name of the author of the commit. Defaults to the name of the authenticated user if not specified. If specified, AuthorEmail must also be specified. .PARAMETER AuthorEmail The email of the author of the commit. Defaults to the email of the authenticated user if not specified. If specified, AuthorName must also be specified. .PARAMETER PassThru Returns the updated GitHub Content. By default, this cmdlet does not generate any output. You can use "Set-GitHubConfiguration -DefaultPassThru" to control the default behavior of this switch. .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. .INPUTS GitHub.Branch GitHub.Content GitHub.Event GitHub.Issue GitHub.IssueComment GitHub.Label GitHub.Milestone GitHub.PullRequest GitHub.Project GitHub.ProjectCard GitHub.ProjectColumn GitHub.Release GitHub.Repository .OUTPUTS GitHub.Content .EXAMPLE Set-GitHubContent -OwnerName microsoft -RepositoryName PowerShellForGitHub -Path README.md -CommitMessage 'Adding README.md' -Content '# README' -BranchName master Sets the contents of the README.md file on the master branch of the PowerShellForGithub repository. #> [CmdletBinding( SupportsShouldProcess, PositionalBinding = $false)] [OutputType({$script:GitHubContentTypeName})] param( [Parameter( Mandatory, ParameterSetName = 'Elements')] [string] $OwnerName, [Parameter( Mandatory, ParameterSetName = 'Elements')] [string] $RepositoryName, [Parameter( Mandatory, ValueFromPipelineByPropertyName, Position = 1, ParameterSetName='Uri')] [Alias('RepositoryUrl')] [string] $Uri, [Parameter( Mandatory, ValueFromPipelineByPropertyName, Position = 2)] [string] $Path, [Parameter( Mandatory, Position = 3)] [string] $CommitMessage, [Parameter( Mandatory, Position = 4)] [string] $Content, [Parameter(ValueFromPipelineByPropertyName)] [string] $Sha, [Parameter(ValueFromPipelineByPropertyName)] [string] $BranchName, [string] $CommitterName, [string] $CommitterEmail, [string] $AuthorName, [string] $AuthorEmail, [switch] $PassThru, [string] $AccessToken ) Write-InvocationLog $elements = Resolve-RepositoryElements -DisableValidation $OwnerName = $elements.ownerName $RepositoryName = $elements.repositoryName $telemetryProperties = @{ 'OwnerName' = (Get-PiiSafeString -PlainText $OwnerName) 'RepositoryName' = (Get-PiiSafeString -PlainText $RepositoryName) } $uriFragment = "/repos/$OwnerName/$RepositoryName/contents/$Path" $encodedContent = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Content)) $hashBody = @{ message = $CommitMessage content = $encodedContent } if ($PSBoundParameters.ContainsKey('BranchName')) { $hashBody['branch'] = $BranchName } if ($PSBoundParameters.ContainsKey('CommitterName') -or $PSBoundParameters.ContainsKey('CommitterEmail')) { if (![System.String]::IsNullOrEmpty($CommitterName) -and ![System.String]::IsNullOrEmpty($CommitterEmail)) { $hashBody['committer'] = @{ name = $CommitterName email = $CommitterEmail } } else { $message = 'Both CommiterName and CommitterEmail need to be specified.' Write-Log -Message $message -Level Error throw $message } } if ($PSBoundParameters.ContainsKey('AuthorName') -or $PSBoundParameters.ContainsKey('AuthorEmail')) { if (![System.String]::IsNullOrEmpty($CommitterName) -and ![System.String]::IsNullOrEmpty($CommitterEmail)) { $hashBody['author'] = @{ name = $AuthorName email = $AuthorEmail } } else { $message = 'Both AuthorName and AuthorEmail need to be specified.' Write-Log -Message $message -Level Error throw $message } } if ($PSBoundParameters.ContainsKey('Sha')) { $hashBody['sha'] = $Sha } if (-not $PSCmdlet.ShouldProcess( "$BranchName branch of $RepositoryName", "Set GitHub Contents on $Path")) { return } $params = @{ UriFragment = $uriFragment Description = "Writing content for $Path in the $BranchName branch of $RepositoryName" Body = (ConvertTo-Json -InputObject $hashBody) Method = 'Put' AccessToken = $AccessToken TelemetryEventName = $MyInvocation.MyCommand.Name TelemetryProperties = $telemetryProperties } try { $result = (Invoke-GHRestMethod @params | Add-GitHubContentAdditionalProperties) if (Resolve-ParameterWithDefaultConfigurationValue -Name PassThru -ConfigValueName DefaultPassThru) { return $result } } catch { $overwriteShaRequired = $false # Temporary code to handle current differences in exception object between PS5 and PS7 if ($PSVersionTable.PSedition -eq 'Core') { $errorMessage = ($_.ErrorDetails.Message | ConvertFrom-Json).message -replace '\n',' ' -replace '\"','"' if (($_.Exception -is [Microsoft.PowerShell.Commands.HttpResponseException]) -and ($errorMessage -eq 'Invalid request. "sha" wasn''t supplied.')) { $overwriteShaRequired = $true } else { throw $_ } } else { $errorMessage = $_.Exception.Message -replace '\n',' ' -replace '\"','"' if ($errorMessage -like '*Invalid request. "sha" wasn''t supplied.*') { $overwriteShaRequired = $true } else { throw $_ } } if ($overwriteShaRequired) { # Get SHA from current file $getGitHubContentParms = @{ Path = $Path OwnerName = $OwnerName RepositoryName = $RepositoryName } if ($PSBoundParameters.ContainsKey('BranchName')) { $getGitHubContentParms['BranchName'] = $BranchName } if ($PSBoundParameters.ContainsKey('AccessToken')) { $getGitHubContentParms['AccessToken'] = $AccessToken } $object = Get-GitHubContent @getGitHubContentParms $hashBody['sha'] = $object.sha $params['body'] = ConvertTo-Json -InputObject $hashBody $message = 'Replacing the content of an existing file requires the current SHA ' + 'of that file. Retrieving the SHA now.' Write-Log -Level Verbose -Message $message $result = (Invoke-GHRestMethod @params | Add-GitHubContentAdditionalProperties) if (Resolve-ParameterWithDefaultConfigurationValue -Name PassThru -ConfigValueName DefaultPassThru) { return $result } } } } filter Add-GitHubContentAdditionalProperties { <# .SYNOPSIS Adds type name and additional properties to ease pipelining to GitHub Content objects. .PARAMETER InputObject The GitHub object to add additional properties to. .PARAMETER TypeName The type that should be assigned to the object. .INPUTS [PSCustomObject] .OUTPUTS GitHub.Content #> [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Internal helper that is definitely adding more than one property.")] param( [Parameter( Mandatory, ValueFromPipeline)] [AllowNull()] [AllowEmptyCollection()] [PSCustomObject[]] $InputObject, [ValidateNotNullOrEmpty()] [string] $TypeName = $script:GitHubContentTypeName ) foreach ($item in $InputObject) { $item.PSObject.TypeNames.Insert(0, $TypeName) if (-not (Get-GitHubConfiguration -Name DisablePipelineSupport)) { if ($item.html_url) { $uri = $item.html_url } else { $uri = $item.content.html_url } $elements = Split-GitHubUri -Uri $uri $repositoryUrl = Join-GitHubUri @elements Add-Member -InputObject $item -Name 'RepositoryUrl' -Value $repositoryUrl -MemberType NoteProperty -Force $hostName = $(Get-GitHubConfiguration -Name 'ApiHostName') if ($uri -match "^https?://(?:www\.|api\.|)$hostName/(?:[^/]+)/(?:[^/]+)/(?:blob|tree)/([^/]+)/([^#]*)?$") { $branchName = $Matches[1] $path = $Matches[2] } else { $branchName = [String]::Empty $path = [String]::Empty } Add-Member -InputObject $item -Name 'BranchName' -Value $branchName -MemberType NoteProperty -Force Add-Member -InputObject $item -Name 'Path' -Value $path -MemberType NoteProperty -Force } Write-Output $item } } # SIG # Begin signature block # MIIjjwYJKoZIhvcNAQcCoIIjgDCCI3wCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDwXzgKwexSjjAk # hJaLjI/7exwGSaVJu+o/ChjeBHeDRqCCDYEwggX/MIID56ADAgECAhMzAAABh3IX # chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ3WhcNMjEwMzAzMTgzOTQ3WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDOt8kLc7P3T7MKIhouYHewMFmnq8Ayu7FOhZCQabVwBp2VS4WyB2Qe4TQBT8aB # znANDEPjHKNdPT8Xz5cNali6XHefS8i/WXtF0vSsP8NEv6mBHuA2p1fw2wB/F0dH # sJ3GfZ5c0sPJjklsiYqPw59xJ54kM91IOgiO2OUzjNAljPibjCWfH7UzQ1TPHc4d # weils8GEIrbBRb7IWwiObL12jWT4Yh71NQgvJ9Fn6+UhD9x2uk3dLj84vwt1NuFQ # itKJxIV0fVsRNR3abQVOLqpDugbr0SzNL6o8xzOHL5OXiGGwg6ekiXA1/2XXY7yV # Fc39tledDtZjSjNbex1zzwSXAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhov4ZyO96axkJdMjpzu2zVXOJcsw # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDU4Mzg1MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAixmy # S6E6vprWD9KFNIB9G5zyMuIjZAOuUJ1EK/Vlg6Fb3ZHXjjUwATKIcXbFuFC6Wr4K # NrU4DY/sBVqmab5AC/je3bpUpjtxpEyqUqtPc30wEg/rO9vmKmqKoLPT37svc2NV # BmGNl+85qO4fV/w7Cx7J0Bbqk19KcRNdjt6eKoTnTPHBHlVHQIHZpMxacbFOAkJr # qAVkYZdz7ikNXTxV+GRb36tC4ByMNxE2DF7vFdvaiZP0CVZ5ByJ2gAhXMdK9+usx # zVk913qKde1OAuWdv+rndqkAIm8fUlRnr4saSCg7cIbUwCCf116wUJ7EuJDg0vHe # yhnCeHnBbyH3RZkHEi2ofmfgnFISJZDdMAeVZGVOh20Jp50XBzqokpPzeZ6zc1/g # yILNyiVgE+RPkjnUQshd1f1PMgn3tns2Cz7bJiVUaqEO3n9qRFgy5JuLae6UweGf # AeOo3dgLZxikKzYs3hDMaEtJq8IP71cX7QXe6lnMmXU/Hdfz2p897Zd+kU+vZvKI # 3cwLfuVQgK2RZ2z+Kc3K3dRPz2rXycK5XCuRZmvGab/WbrZiC7wJQapgBodltMI5 # GMdFrBg9IeF7/rP4EqVQXeKtevTlZXjpuNhhjuR+2DMt/dWufjXpiW91bo3aH6Ea # jOALXmoxgltCp1K7hrS6gmsvj94cLRf50QQ4U8Qwggd6MIIFYqADAgECAgphDpDS # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVZDCCFWACAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgbTQXEV01 # HV0G+dujkVoGpMTZ8bu5Zf+eBjmbsFKh+5kwQgYKKwYBBAGCNwIBDDE0MDKgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN # BgkqhkiG9w0BAQEFAASCAQCJrbca8sfec4Rg5plmveNZwmruimzszO62zgGeLFcs # 3rgPSEhQYeZOmT4GUFp0A4JVKjthzI5bbc4/um7pe49sYXKuq/QopNWRQMusjM5v # CG3mCADFqUN+70SReQ0lE4vyE/o3VtjN/0X9K2+oXB+0q8lE0OupAY6vfN9ek5UD # atxOsl0em1rLYI7nyNmDCny3Jqi6xWIRG9+zPyFC8tm5DxqXtuLWYhu/HCoNMg9X # 4lorjrBR61v2g0hBRzMuY1LVDyxeO7IgDynrPwXcFWlZ1klXsrQAeieA07L2hyrI # 1KtidCTgL7TZNdQdQwgJFxj/0UEyi9hYwITlf0/CGT69oYIS7jCCEuoGCisGAQQB # gjcDAwExghLaMIIS1gYJKoZIhvcNAQcCoIISxzCCEsMCAQMxDzANBglghkgBZQME # AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB # MDEwDQYJYIZIAWUDBAIBBQAEIIrI/Vu/nvgQJMsAvcuq3D1Xvppwwe3ZHWyvHinh # thzNAgZfO+RS8lgYEzIwMjAwOTA5MTU0MDQyLjI4MlowBIACAfSggdSkgdEwgc4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p # Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg # VFNTIEVTTjo2MEJDLUUzODMtMjYzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt # U3RhbXAgU2VydmljZaCCDkEwggT1MIID3aADAgECAhMzAAABJt+6SyK5goIHAAAA # AAEmMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw # MB4XDTE5MTIxOTAxMTQ1OVoXDTIxMDMxNzAxMTQ1OVowgc4xCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy # YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo2MEJD # LUUzODMtMjYzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj # ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ4wvoacTvMNlXQTtfF/ # Cx5Ol3X0fcjUNMvjLgTmO5+WHYJFbp725P3+qvFKDRQHWEI1Sz0gB24urVDIjXjB # h5NVNJVMQJI2tltv7M4/4IbhZJb3xzQW7LolEoZYUZanBTUuyly9osCg4o5joViT # 2GtmyxK+Fv5kC20l2opeaeptd/E7ceDAFRM87hiNCsK/KHyC+8+swnlg4gTOey6z # QqhzgNsG6HrjLBuDtDs9izAMwS2yWT0T52QA9h3Q+B1C9ps2fMKMe+DHpG+0c61D # 94Yh6cV2XHib4SBCnwIFZAeZE2UJ4qPANSYozI8PH+E5rCT3SVqYvHou97HsXvP2 # I3MCAwEAAaOCARswggEXMB0GA1UdDgQWBBRJq6wfF7B+mEKN0VimX8ajNA5hQTAf # BgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBH # hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNU # aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUF # BzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0 # YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG # AQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQBAlvudaOlv9Cfzv56bnX41czF6tLtH # LB46l6XUch+qNN45ZmOTFwLot3JjwSrn4oycQ9qTET1TFDYd1QND0LiXmKz9OqBX # ai6S8XdyCQEZvfL82jIAs9pwsAQ6XvV9jNybPStRgF/sOAM/Deyfmej9Tg9FcRwX # ank2qgzdZZNb8GoEze7f1orcTF0Q89IUXWIlmwEwQFYF1wjn87N4ZxL9Z/xA2m/R # 1zizFylWP/mpamCnVfZZLkafFLNUNVmcvc+9gM7vceJs37d3ydabk4wR6ObR34sW # aLppmyPlsI1Qq5Lu6bJCWoXzYuWpkoK6oEep1gML6SRC3HKVS3UscZhtMIIGcTCC # BFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJv # b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcN # MjUwNzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIw # DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0 # VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEw # RA/xYIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQe # dGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKx # Xf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4G # kbaICDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEA # AaOCAeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7 # fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC # AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX # zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v # cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI # KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0g # AQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYB # BQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUA # bQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOh # IW+z66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS # +7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlK # kVIArzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon # /VWvL/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOi # PPp/fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/ # fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCII # YdqwUB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0 # cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7a # KLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQ # cdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+ # NR4Iuto229Nfj950iEkSoYICzzCCAjgCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP # cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo2 # MEJDLUUzODMtMjYzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy # dmljZaIjCgEBMAcGBSsOAwIaAxUACmcyOWmZxErpq06B8dy6oMZ6//yggYMwgYCk # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF # AOMDYqswIhgPMjAyMDA5MDkxODE4MTlaGA8yMDIwMDkxMDE4MTgxOVowdDA6Bgor # BgEEAYRZCgQBMSwwKjAKAgUA4wNiqwIBADAHAgEAAgIUMTAHAgEAAgIRCTAKAgUA # 4wS0KwIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAID # B6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAF35Dqvm4D9uEoDASQqL # 9EdBF8mYmFRo/+ArFRUzLmDW1fTV0a4JPMJg+mPSzxd3yAGwGQIfXC8qsKudyQGw # Gr+wUXDF1rLLqADJkKM0RXo9vFn+4YkQtt8SzdnMVWQuHOhKjVU2W8xC2fVRE7aD # mxrZ41ozdKVdjP+iAzmFhVT1MYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt # U3RhbXAgUENBIDIwMTACEzMAAAEm37pLIrmCggcAAAAAASYwDQYJYIZIAWUDBAIB # BQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQx # IgQgaS2RVjY/n3d4s2PlOGLyC+yJh03Cf2LCvfQhbju8xE0wgfoGCyqGSIb3DQEJ # EAIvMYHqMIHnMIHkMIG9BCA2/c/vnr1ecAzvapOWZ2xGfAkzrkfpGcrvMW07CQl1 # DzCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABJt+6 # SyK5goIHAAAAAAEmMCIEIFS6Rd6vQMMD2UH0fzMeQCANX+D9cQukl40weweg2gQK # MA0GCSqGSIb3DQEBCwUABIIBAFP9ZHWj5v9SVoPdhiifJeHUtMdWizLKeJZhfHNT # CCdi99Vdmt7HvApxbU05geIwKpyuHUu3HJzicjNfM4s4KdRhXNBN9QL63pA6+kto # 8jhxnDe8ft/iPh4HOPmdEdVYNRThTO5ZndmT5oj7+/W0i0Fs2OdwAnFExGL5eNiB # 7qFO9Ju+IdNPn8Y9G9enFAK6GrfrmuA5OhSkLgbvvZjC92moC3GF9c/owUFs/Ihh # LXrabNst4dS8nW5XQ7grwx3/So3o8LD8lpAh1D+IAAQOCUOpEqjRRZrrggBE0lUk # 7iDR2o/z4VN19tetHDb/ILPtnrWzIeMAREqsfpAT8bJA0ng= # SIG # End signature block |