AnsiConsole.psm1
|
Set-StrictMode -Version 'Latest' #Requires -Version 5.1 ############################################# # Constants ############################################# New-Variable -Name escape -Value [char]0x001B -Option Constant New-Variable -Name csi -Value "$([char]0x001B)[" -Option Constant New-Variable -Name textColorBase -Value 30 -Option Constant New-Variable -Name backgroundColorBase -Value 40 -Option Constant ############################################# # State Variables ############################################# # Global setting which determines if ANSI graphics commands should be immediately # reset after processing. This ensures each line only has the specified formats. New-Variable -Name AnsiAutoReset -Value $true -Scope Script -Force ############################################# # Enumerations ############################################# enum AnsiColor { Black = 0 Red = 1 Green = 2 Yellow = 3 Blue = 4 Magenta = 5 Cyan = 6 White = 7 BrightBlack = 60 BrightRed = 61 BrightGreen = 62 BrightYellow = 63 BrightBlue = 64 BrightMagenta = 65 BrightCyan = 66 BrightWhite = 67 } enum AnsiClear { CursorToEnd = 0 CursorToStart = 1 All = 2 } ############################################# # Functions ############################################# function Set-AnsiCursorUp { <# .SYNOPSIS Generates the ANSI escape sequence for moving the cursor up by some amount. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [Parameter(Position = 0)] [byte] $Amount, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Move cursor up $Amount")) { return "${csi}${Amount}A" } } function Move-AnsiCursorDown { <# .SYNOPSIS Generates the ANSI escape sequence for moving the cursor down by some amount. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [Parameter(Position = 0)] [byte] $Amount, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Move cursor down $Amount")) { return "${csi}${Amount}B" } } function Move-AnsiCursorForward { <# .SYNOPSIS Generates the ANSI escape sequence for moving the cursor forward by some amount. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [Parameter(Position = 0)] [byte] $Amount, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Move cursor forward $Amount")) { return "${csi}${Amount}C" } } function Move-AnsiCursorBack { <# .SYNOPSIS Generates the ANSI escape sequence for moving the cursor backward by some amount. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [Parameter(Position = 0)] [byte] $Amount, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Move cursor backwards $Amount")) { return "${csi}${Amount}D" } } function Move-AnsiCursorNextLine { <# .SYNOPSIS Generates the ANSI escape sequence for moving the cursor down by a number of lines. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [Parameter(Position = 0)] [byte] $Amount, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Move cursor forward $Amount lines")) { return "${csi}${Amount}E" } } function Set-AnsiCursorPreviousLine { <# .SYNOPSIS Generates the ANSI escape sequence for moving the cursor up by a number of lines. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [Parameter(Position = 0)] [byte] $Amount, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Move cursor back $Amount lines")) { return "${csi}${Amount}F" } } function Move-AnsiCursorHorizontalAbsolute { <# .SYNOPSIS Generates the ANSI escape sequence for moving the cursor horizontally to an absolute position #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [Parameter(Position = 0)] [byte] $Column, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Set cursor to horizontal position $Column")) { return "${csi}${Column}G" } } function Move-AnsiCursorPosition { <# .SYNOPSIS Generates the ANSI escape sequence for absolutely positioning the cursor on the screen. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [byte] $Row, [byte] $Column, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Move cursor to ($Row, $Column)")) { return "${csi}${row};${column}H" } } function Move-AnsiScrollUp { <# .SYNOPSIS Generates the ANSI escape sequence for scrolling the screen up by a number of lines. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [Parameter(Position = 0)] [byte] $Amount, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Scroll up $Amount lines")) { return "${csi}${Amount}S" } } function Move-AnsiScrollDown { <# .SYNOPSIS Generates the ANSI escape sequence for scrolling the screen up by a number of lines. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [Parameter(Position = 0)] [byte] $Amount, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Scroll down $Amount lines")) { return "${csi}${Amount}T" } } function Save-AnsiCursor { <# .SYNOPSIS Generates the ANSI escape sequence for saving the current cursor position. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Save cursor position")) { return "${csi}s" } } function Restore-AnsiCursor { <# .SYNOPSIS Generates the ANSI escape sequence for restoring a saved cursor position. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Restore cursor position")) { return "${csi}u" } } function Clear-AnsiDisplay { <# .SYNOPSIS Generates the ANSI escape sequence to clear the display. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [AnsiClear] $Target, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess($Target, "Clear console")) { return "${csi}${Target}J" } } function Clear-AnsiLine { <# .SYNOPSIS Generates the ANSI escape sequence to clear a line. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [AnsiClear] $Target, [switch] $Force ) if ($Force -or $PSCmdlet.ShouldProcess($target, "Clear current line")) { return "${csi}${Target}K" } } function Set-AnsiConsole { <# .SYNOPSIS Generates the ANSI escape sequence to format the color and style of displayed text. #> [CmdletBinding(DefaultParameterSetName = "AnsiColor", SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [parameter(ParameterSetName = "AnsiColor")] [parameter(ParameterSetName = "RgbColor")] [string[]] $Text, [parameter(ParameterSetName = "AnsiColor")] [AnsiColor] $Foreground, [parameter(ParameterSetName = "AnsiColor")] [AnsiColor] $Background, [parameter(ParameterSetName = "RgbColor")] [string] $ForegroundRGB, [parameter(ParameterSetName = "RgbColor")] [string] $BackgroundRGB, [parameter(ParameterSetName = "AnsiColor")] [parameter(ParameterSetName = "RgbColor")] [switch] $Bold = $false, [parameter(ParameterSetName = "AnsiColor")] [parameter(ParameterSetName = "RgbColor")] [switch] $Underline = $false, [parameter(ParameterSetName = "AnsiColor")] [parameter(ParameterSetName = "RgbColor")] [switch] $Dim = $false, [parameter(ParameterSetName = "AnsiColor")] [parameter(ParameterSetName = "RgbColor")] [switch] $Italic = $false, [switch] $Force ) process { $content = "${csi}" $commands = New-Object System.Collections.ArrayList if ($Dim) { [void]$commands.Add("2") } if ($Bold) { [void]$commands.Add("1") } if ($Italic) { [void]$commands.Add("3") } if ($Underline) { [void]$commands.Add("4") } if ($PSCmdlet.ParameterSetName -eq 'AnsiColor') { if ($PSBoundParameters.ContainsKey('Foreground')) { $color = $textColorBase + $Foreground [void]$commands.Add($color) } if ($PSBoundParameters.ContainsKey('Background')) { $color = $backgroundColorBase + $Background [void]$commands.Add($color) } } elseif ($PSCmdlet.ParameterSetName -eq 'RgbColor') { if ($PSBoundParameters.ContainsKey('ForegroundRGB')) { [void]$commands.Add("38") [void]$commands.Add("2") [void]$commands.AddRange(($ForegroundRGB | Convert-ToRgbArray)) } if ($PSBoundParameters.ContainsKey('BackgroundRGB')) { [void]$commands.Add("48") [void]$commands.Add("2") [void]$commands.AddRange(($BackgroundRGB | Convert-ToRgbArray)) } } if ($Force -or $PSCmdlet.ShouldProcess("console", "Set output format for text")) { $content = $content + ($commands.ToArray() -Join ";") + "m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Set-AnsiTextColor { <# .SYNOPSIS Generates the ANSI escape sequence to set the text to one of the eight ANSI colors #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [parameter(Position = 0, Mandatory = $true)] [AnsiColor] $Color, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Set foreground text color to $Color")) { $content = "${csi}$($textColorBase + $Color)m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Set-AnsiBackgroundColor { <# .SYNOPSIS Generates the ANSI escape sequence to set the background for the text to a specific color. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [parameter(Position = 0, Mandatory = $true)] [AnsiColor] $Color, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Set background color to $Color")) { $content = "${csi}$($backgroundColorBase + $Color)m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Set-AnsiTextPaletteColor { <# .SYNOPSIS Generates the ANSI escape sequence to set the text to one of the 256 palette colors. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [Parameter(Position = 0)] [byte] $index, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Set text to palette color $index")) { $content = "${csi}38;5;${index}m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Set-AnsiBackgroundPaletteColor { <# .SYNOPSIS Generates the ANSI escape sequence to set the background to one of the 256 ANSI palette colors. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [Parameter(Position = 0)] [byte] $index, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Set background to palette color $index")) { $content = "${csi}48;5;${index}m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Set-AnsiTextRgbColor { <# .SYNOPSIS Generates the ANSI escape sequence to set the text to a specific RGB color. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [byte] $Red, [byte] $Green, [byte] $Blue, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Set text tp RGB ($Red, $Green, $Blue)")) { $content = "${csi}38;2;$Red;$Green;${Blue}m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Set-AnsiBackgroundRgbColor { <# .SYNOPSIS Generates the ANSI escape sequence to set the background to a specific RGB color. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [byte] $Red, [byte] $Green, [byte] $Blue, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Set background to RGB ($Red, $Green, $Blue)")) { $content = "${csi}48;2;$Red;$Green;${Blue}m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Reset-AnsiConsole { <# .SYNOPSIS Generates the ANSI escape sequence to reset the console formatting. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Reset all ANSI graphics states")) { return "${csi}0m" } } } function Set-AnsiBold { <# .SYNOPSIS Generates the ANSI escape sequence to format the text bold. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Enable bold")) { $content = "${csi}1m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Set-AnsiDim { <# .SYNOPSIS Generates the ANSI escape sequence to format the text dim. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Enable dim")) { $content = "${csi}2m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Set-AnsiItalic { <# .SYNOPSIS Generates the ANSI escape sequence to format the text in italics. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Enable italic")) { $content = "${csi}3m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Set-AnsiUnderline { <# .SYNOPSIS Generates the ANSI escape sequence to format the text with an underline. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("console", "Enable underline")) { $content = "${csi}4m" foreach ($item in $Text) { return ($content + $item) | Format-AutoReset } } } } function Reset-AnsiBold { <# .SYNOPSIS Generates the ANSI escape sequence to remove the bold formatting. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [switch]$Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Disable bold")) { return "${csi}22m" } } function Reset-AnsiDim { <# .SYNOPSIS Generates the ANSI escape sequence to remove the dim formatting. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [switch]$Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Disable dim")) { return "${csi}22m" } } function Reset-AnsiItalic { <# .SYNOPSIS Generates the ANSI escape sequence to remove the italic formatting. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [switch]$Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Disable italics")) { return "${csi}23m" } } function Reset-AnsiUnderline { <# .SYNOPSIS Generates the ANSI escape sequence to remove the underline formatting. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [switch]$Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Disable underline")) { return "${csi}24m" } } function Get-AnsiAutoReset { <# .SYNOPSIS Gets a value indicating whether piped strings automatically include an ANSI reset command at the end to restore the default formatting. #> [CmdletBinding()] [OutputType([string])] param ( ) $script:AnsiAutoReset } function Set-AnsiAutoReset { <# .SYNOPSIS Sets a value indicating whether piped strings automatically include an ANSI reset command at the end to restore the default formatting. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] [OutputType([string])] param ( [parameter(Position = 0, Mandatory = $true)] [bool] $Value, [switch]$Force ) if ($Force -or $PSCmdlet.ShouldProcess("console", "Disable automatic ANSI reset")) { $script:AnsiAutoReset = $Value } } ############################################# # Private Functions ############################################# function Convert-ToRgbArray { [CmdletBinding()] [OutputType([string[]])] param ( [parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [ValidateLength(6, 7)] [ValidatePattern('^#?[0-9A-Fa-f]{6}$')] [string] $Value ) process { $result = New-Object System.Collections.ArrayList $index = (0, 1)[$Value.Length -eq 7] [void]$result.Add([Convert]::ToByte($Value.Substring(0 + $index, 2), 16)) [void]$result.Add([Convert]::ToByte($Value.Substring(2 + $index, 2), 16)) [void]$result.Add([Convert]::ToByte($Value.Substring(4 + $index, 2), 16)) return $result.ToArray(); } } function Format-AutoReset { [CmdletBinding()] [OutputType([string])] param ( [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Text ) process { foreach ($item in $Text) { if (!$script:AnsiAutoReset) { return $item } else { return "${item}${csi}0m" } } } } ############################################# # Exports ############################################# Export-ModuleMember -Function @( "Clear-AnsiDisplay", "Clear-AnsiLine", "Get-AnsiAutoReset", "Move-AnsiCursorBack", "Move-AnsiCursorDown", "Move-AnsiCursorForward", "Move-AnsiCursorHorizontalAbsolute", "Move-AnsiCursorNextLine", "Move-AnsiCursorPosition", "Move-AnsiScrollDown", "Move-AnsiScrollUp", "Reset-AnsiBold", "Reset-AnsiConsole", "Reset-AnsiDim", "Reset-AnsiItalic", "Reset-AnsiUnderline", "Restore-AnsiCursor", "Save-AnsiCursor", "Set-AnsiAutoReset", "Set-AnsiBackgroundColor", "Set-AnsiBackgroundPaletteColor", "Set-AnsiBackgroundRgbColor", "Set-AnsiBold", "Set-AnsiConsole", "Set-AnsiCursorPreviousLine", "Set-AnsiCursorUp", "Set-AnsiDim", "Set-AnsiItalic", "Set-AnsiTextColor", "Set-AnsiTextPaletteColor", "Set-AnsiTextRgbColor", "Set-AnsiUnderline" ) # SIG # Begin signature block # MIIjdgYJKoZIhvcNAQcCoIIjZzCCI2MCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUGEYL+fOCfCmp9p2CIzP60WJW # tcWggh2UMIIFKzCCBBOgAwIBAgIQA92NH6Ao4oJnDDTTKeZ3HzANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE5MDkwOTAwMDAwMFoXDTIyMDkx # MjEyMDAwMFowaDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0dlb3JnaWExGTAXBgNV # BAcTEEF2b25kYWxlIEVzdGF0ZXMxFTATBgNVBAoTDEtlbm5ldGggTXVzZTEVMBMG # A1UEAxMMS2VubmV0aCBNdXNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC # AQEAsr5Lse8T47fphRV8/FhwMUgYR6h1FrGlf3YLe8nhl6ade5WHAtFZqlguZU+f # WyP/R5NHf9bKMbHg6IiIuedyBE2fEzCZH5CJwgC3J0Df5qrNf4qI5fBobsryV/mg # zSOzLBbunPfak1XNTNL0w4ak6jCz8OMAZ9Q+ThHgv5XIO5IhyTqkoMijkeLfg32x # 5hfYeSQsXDma0yzyd7tGDrhmN+ayhh0nuTYmXS3fjxq8oLztMZhzfRP8Qfvs3SrW # nZn+tCkGMPawOBc7M3GA5Zvc7yc9OiMprLOFN1BM8aNdGU+xRAQQ6lpO2vQOt8T4 # YaQApMxeI4UYF4iFT62OSDDfdQIDAQABo4IBxTCCAcEwHwYDVR0jBBgwFoAUWsS5 # eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYEFPy4/m56aqGve2X/EydtiYe2woZp # MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBu # MDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNz # LWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNz # dXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAwEwKjAoBggrBgEF # BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYQG # CCsGAQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu # Y29tME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln # aUNlcnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIw # ADANBgkqhkiG9w0BAQsFAAOCAQEA+MVLwwa9SEsrYO063xHRLZWuLYsKQ0nXySzt # kGoTnFwqHDBTTMkOtX2jLTZEnO0fpopEZzPoQJoO84njwxxqF6BQnYdu+x15ndXn # oUWQsFSreaWUJZK4M2mL0kOZH14gDZNz3Ok+1BqQQozpXVazd5YJMjdJFvEZN+xz # F0rwczzTnvhR1w+bKkb23YcCkF1S+VOhGZIpkUhftNdIx6pMfjg+pKxb8rOKwjAa # MEpTukSZXD7BhGCHAouurTYcIdeLfPz3w+e2amvi/MCo+YcjcDowFtfqAbL7HEea # k8nVTy9MPntNuxpOZQT8HalvGjH5KVjilkL+HXLc4nn1JMu/6DCCBTAwggQYoAMC # AQICEAQJGBtf1btmdVNDtW+VUAgwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMC # VVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0 # LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTEz # MTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcjELMAkGA1UEBhMCVVMxFTATBgNV # BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8G # A1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQTCC # ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPjTsxx/DhGvZ3cH0wsxSRnP # 0PtFmbE620T1f+Wondsy13Hqdp0FLreP+pJDwKX5idQ3Gde2qvCchqXYJawOeSg6 # funRZ9PG+yknx9N7I5TkkSOWkHeC+aGEI2YSVDNQdLEoJrskacLCUvIUZ4qJRdQt # oaPpiCwgla4cSocI3wz14k1gGL6qxLKucDFmM3E+rHCiq85/6XzLkqHlOzEcz+ry # CuRXu0q16XTmK/5sy350OTYNkO/ktU6kqepqCquE86xnTrXE94zRICUj6whkPlKW # wfIPEvTFjg/BougsUfdzvL2FsWKDc0GCB+Q4i2pzINAPZHM8np+mM6n9Gd8lk9EC # AwEAAaOCAc0wggHJMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGG # MBMGA1UdJQQMMAoGCCsGAQUFBwMDMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcw # AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8v # Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0 # MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGln # aUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsME8GA1UdIARIMEYw # OAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy # dC5jb20vQ1BTMAoGCGCGSAGG/WwDMB0GA1UdDgQWBBRaxLl7KgqjpepxA8Bg+S32 # ZXUOWDAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG9w0B # AQsFAAOCAQEAPuwNWiSz8yLRFcgsfCUpdqgdXRwtOhrE7zBh134LYP3DPQ/Er4v9 # 7yrfIFU3sOH20ZJ1D1G0bqWOWuJeJIFOEKTuP3GOYw4TS63XX0R58zYUBor3nEZO # XP+QsRsHDpEV+7qvtVHCjSSuJMbHJyqhKSgaOnEoAjwukaPAJRHinBRHoXpoaK+b # p1wgXNlxsQyPu6j4xRJon89Ay0BEpRPw5mQMJQhCMrI2iiQC/i9yfhzXSUWW6Fkd # 6fp0ZGuy62ZD2rOwjNXpDd32ASDOmTFjPQgaGLOBm0/GkxAG/AeB+ova+YJJ92Ju # oVP6EpQYhS6SkepobEQysmah5xikmmRR7zCCBbEwggSZoAMCAQICEAEkCvseOAuK # FvFLcZ3008AwDQYJKoZIhvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoT # DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UE # AxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTIyMDYwOTAwMDAwMFoX # DTMxMTEwOTIzNTk1OVowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0 # IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNl # cnQgVHJ1c3RlZCBSb290IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC # AgEAv+aQc2jeu+RdSjwwIjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQw # H/MbpDgW61bGl20dq7J58soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6 # dZlqczKU0RBEEC7fgvMHhOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXG # XuxbGrzryc/NrDRAX7F6Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXn # Mcvak17cjo+A2raRmECQecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy # 19sEcypukQF8IUzUvK4bA3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFY # F/ckXEaPZPfBaYh2mHY9WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+Skjqe # PdwA5EUlibaaRBkrfsCUtNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFg # qrFjGESVGnZifvaAsPvoZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJR # R3S+Jqy2QXXeeqxfjT/JvNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7Gr # hotPwtZFX50g/KEexcCPorF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCAV4wggFa # MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9P # MB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIB # hjATBgNVHSUEDDAKBggrBgEFBQcDCDB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUH # MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDov # L2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNy # dDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln # aUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsG # CWCGSAGG/WwHATANBgkqhkiG9w0BAQwFAAOCAQEAmhYCpQHvgfsNtFiyeK2oIxnZ # czfaYJ5R18v4L0C5ox98QE4zPpA854kBdYXoYnsdVuBxut5exje8eVxiAE34SXpR # TQYy88XSAConIOqJLhU54Cw++HV8LIJBYTUPI9DtNZXSiJUpQ8vgplgQfFOOn0XJ # IDcUwO0Zun53OdJUlsemEd80M/Z1UkJLHJ2NltWVbEcSFCRfJkH6Gka93rDlkUcD # rBgIy8vbZol/K5xlv743Tr4t851Kw8zMR17IlZWt0cu7KgYg+T9y6jbrRXKSeil7 # FAM8+03WSHF6EBGKCHTNbBsEXNKKlQN2UVBT1i73SkbDrhAscUywh7YnN0RgRDCC # Bq4wggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJKoZIhvcNAQELBQAwYjEL # MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 # LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0 # MB4XDTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVowYzELMAkGA1UEBhMCVVMx # FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVz # dGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTCCAiIwDQYJKoZI # hvcNAQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklRVcclA8TykTepl1Gh1tKD # 0Z5Mom2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54PMx9QEwsmc5Zt+FeoAn39 # Q7SE2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupRPfDWVtTnKC3r07G1decf # BmWNlCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvohGS0UvJ2R/dhgxndX7RU # CyFobjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV5huowWR0QKfAcsW6Th+x # tVhNef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYVVSZwmCZ/oBpHIEPjQ2OA # e3VuJyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6ic/rnH1pslPJSlRErWHRA # KKtzQ87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/CiPMpC3BhIfxQ0z9JMq++b # Pf4OuGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5K6jzRWC8I41Y99xh3pP+ # OcD5sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oiqMEmCPkUEBIDfV8ju2Tj # Y+Cm4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuldyF4wEr1GnrXTdrnSDmuZ # DNIztM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW # BBS6FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/ # 57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYI # KwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j # b20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp # Q2VydFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9j # cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1Ud # IAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEA # fVmOwJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvHUF3iSyn7cIoNqilp/GnB # zx0H6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0MCIKoFr2pVs8Vc40BIiXO # lWk/R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCKrOX9jLxkJodskr2dfNBw # CnzvqLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rAJ4JErpknG6skHibBt94q # 6/aesXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZxhOACcS2n82HhyS7T6NJ # uXdmkfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScsPT9rp/Fmw0HNT7ZAmyEh # QNC3EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1MrfvElXvtCl8zOYdBeHo4 # 6Zzh3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXseGYs2uJPU5vIXmVnKcPA3 # v5gA3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWYMbRiCQ8KvYHZE/6/pNHz # V9m8BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYphwlHK+Z/GqSFD/yYlvZV # VCsfgPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPwwggbGMIIErqADAgECAhAK # ekqInsmZQpAGYzhNhpedMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcw # FQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3Rl # ZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjIwMzI5MDAw # MDAwWhcNMzMwMzE0MjM1OTU5WjBMMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln # aUNlcnQsIEluYy4xJDAiBgNVBAMTG0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIyIC0g # MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALkqliOmXLxf1knwFYIY # 9DPuzFxs4+AlLtIx5DxArvurxON4XX5cNur1JY1Do4HrOGP5PIhp3jzSMFENMQe6 # Rm7po0tI6IlBfw2y1vmE8Zg+C78KhBJxbKFiJgHTzsNs/aw7ftwqHKm9MMYW2Nq8 # 67Lxg9GfzQnFuUFqRUIjQVr4YNNlLD5+Xr2Wp/D8sfT0KM9CeR87x5MHaGjlRDRS # Xw9Q3tRZLER0wDJHGVvimC6P0Mo//8ZnzzyTlU6E6XYYmJkRFMUrDKAz200kheiC # lOEvA+5/hQLJhuHVGBS3BEXz4Di9or16cZjsFef9LuzSmwCKrB2NO4Bo/tBZmCbO # 4O2ufyguwp7gC0vICNEyu4P6IzzZ/9KMu/dDI9/nw1oFYn5wLOUrsj1j6siugSBr # Q4nIfl+wGt0ZvZ90QQqvuY4J03ShL7BUdsGQT5TshmH/2xEvkgMwzjC3iw9dRLND # HSNQzZHXL537/M2xwafEDsTvQD4ZOgLUMalpoEn5deGb6GjkagyP6+SxIXuGZ1h+ # fx/oK+QUshbWgaHK2jCQa+5vdcCwNiayCDv/vb5/bBMY38ZtpHlJrYt/YYcFaPfU # cONCleieu5tLsuK2QT3nr6caKMmtYbCgQRgZTu1Hm2GV7T4LYVrqPnqYklHNP8lE # 54CLKUJy93my3YTqJ+7+fXprAgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4Aw # DAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAX # MAgGBmeBDAEEAjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3Mpdpov # dYxqII+eyG8wHQYDVR0OBBYEFI1kt4kh/lZYRIRhp+pvHDaP3a8NMFoGA1UdHwRT # MFEwT6BNoEuGSWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0 # ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEB # BIGDMIGAMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYI # KwYBBQUHMAKGTGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRy # dXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcN # AQELBQADggIBAA0tI3Sm0fX46kuZPwHk9gzkrxad2bOMl4IpnENvAS2rOLVwEb+E # GYs/XeWGT76TOt4qOVo5TtiEWaW8G5iq6Gzv0UhpGThbz4k5HXBw2U7fIyJs1d/2 # WcuhwupMdsqh3KErlribVakaa33R9QIJT4LWpXOIxJiA3+5JlbezzMWn7g7h7x44 # ip/vEckxSli23zh8y/pc9+RTv24KfH7X3pjVKWWJD6KcwGX0ASJlx+pedKZbNZJQ # fPQXpodkTz5GiRZjIGvL8nvQNeNKcEiptucdYL0EIhUlcAZyqUQ7aUcR0+7px6A+ # TxC5MDbk86ppCaiLfmSiZZQR+24y8fW7OK3NwJMR1TJ4Sks3KkzzXNy2hcC7cDBV # eNaY/lRtf3GpSBp43UZ3Lht6wDOK+EoojBKoc88t+dMj8p4Z4A2UKKDr2xpRoJWC # jihrpM6ddt6pc6pIallDrl/q+A8GQp3fBmiW/iqgdFtjZt5rLLh4qk1wbfAs8QcV # fjW05rUMopml1xVrNQ6F1uAszOAMJLh8UgsemXzvyMjFjFhpr6s94c/MfRWuFL+K # cd/Kl7HYR+ocheBFThIcFClYzG/Tf8u+wQ5KbyCcrtlzMlkI5y2SoRoR/jKYpl0r # l+CL05zMbbUNrkdjOEcXW28T2moQbh9Jt0RbtAgKh1pZBHYRoad3AhMcMYIFTDCC # BUgCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ # MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hB # MiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQQIQA92NH6Ao4oJnDDTTKeZ3HzAJ # BgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0B # CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAj # BgkqhkiG9w0BCQQxFgQUk6PD/WLWJLvW6ch3/xmOhDuXP4cwDQYJKoZIhvcNAQEB # BQAEggEAcgNGg/FQyd4JJJhujTuhgBsmz/iE362nFbSrKZC+T/+QtGLWovU5ywwM # dZ8OGC0xgQz/qFKUDynJZAKswugqthGW0++sHjaOOzzMKMRohC6KIHzv581qQe1f # 41WhLQ1lHhFvHS5qZHZOSp624zuKwkxCrgSb3DC9qqzZdzNh+ZnTHSFVDsZXXiGe # YQ8h9gczZGjsGJhQc0C8kf7nrmGBTcPbZiG5IWQggqT8l2B1Iw7uNyLmhuHibEfC # GDMeX5v3HxXbuW7Aq/rlU+CBOjLHjw/xlRJM8jjZ5EmAbw/CSVF477TU6JP6O/eS # rj893Jcd3A5h7bCLNjpVpTY8IcJ4d6GCAyAwggMcBgkqhkiG9w0BCQYxggMNMIID # CQIBATB3MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7 # MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1l # U3RhbXBpbmcgQ0ECEAp6SoieyZlCkAZjOE2Gl50wDQYJYIZIAWUDBAIBBQCgaTAY # BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMjA3MTEw # MTU5MzlaMC8GCSqGSIb3DQEJBDEiBCDWgYdRyzCckASLoQftwSkqHUDwYfPr8gqC # W3BG1nN0ujANBgkqhkiG9w0BAQEFAASCAgArGn1gx54RybN+vn+0wsmIdYG9WGL5 # 7ke5VLHA2c5UxmOTSLmPORnG30ZC5sOJFy9xbdvo1Th9LAq0uQajjCXPE0h/T+f5 # EelmOt+mNdCcOxhTiD7zuimwJ2TMdB/1/aQqIruRlW479J2wE5/yCyfh07cIgd64 # RzquFjJfyGj+jHqjKp+TJcG0MHhuc/09lKj0UhIxzYO1sSmdU1PIyquxENPsSKfP # J/r1YzDfFnSHHdGT+fJcZqckBEv29b+fjAIC/uA5R/5Qu4dUpC/Jasgans22kTvL # bSItYsQEMrsQVpRbfk3k8hPGpOuGZIKYL3pESA4/QrwKk5Y31dsZWjYXkJe90d5w # Wu858WLM98GMnxD/rCFdF0g2AXA3xmcNEqOHs8PHbHv2Q3757+ldZZUQrsbfjxuE # FL3VgroF6Y28ZcWTvL/wYPNedkentHSmDCNuZ7QY67ae/F25xnkVuZenUWtb/ROz # jiqbgrynY+TGtLBO0koKOiBXyL/eqTgEJY+vccHH1KENe4welaxeAZbmiHCWxCq9 # bSFhPRE++Iws/3KL6O15PBVptg56xYgXauDdJneAQgwXH6kNUtg7A83qf+smAMWS # HEcWaxv6MamMIeNmYLwX0gfZLDpI3SB5JNlSY+HaCxNDiu7VtyQQ0aHMOhFq5Lj+ # tjjlOmeqNadXHA== # SIG # End signature block |