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