OZOStrings.psm1

Function Get-OZODelimiterSubString {
    <#
        .SYNOPSIS
        See description.
        .DESCRIPTION
        Returns a list of strings found between Start and End delimiters. The delimiters may be characters or strings, and may be identical or different. If only the Start or End delimiter is found in the input string, the resulting list will contain a single substring (see parameters below for more detail). If neither delimiter is found in the input string, the returned list will contain the original unaltered string.
        .PARAMETER String
        The string to process. Accepts pipeline input.
        .PARAMETER Start
        The start delimiter string. When "Start" is provided and "End" is not provided, the string following "Start" is returned; and if the input string does not contain "Start", the original string is returned. When "Start" is used with "End" and the input string does not contain "Start", the string leading up to "End" is returned.
        .PARAMETER End
        The end delimiter string. When "End" is provided and "Start" is not provided, the string leading up to "End" is returned; and if the input string does not contain "End", the original string is returned. When "End" is used with "Start" and the input string does not contain "End", the string following "Start" is returned.
        .EXAMPLE
        $subStringsList = Get-OZODelimiterSubString -String "2023-06-20T14:18:09-05:00{226da830-da5c-42af-83fd-37467b753ec6}" -Start "{" -End "}"
        $subStringsList[0]
        226da830-da5c-42af-83fd-37467b753ec6
        .EXAMPLE
        Get-OZODelimiterSubString -String "2023-06-20T14:18:09-05:00{226da830-da5c-42af-83fd-37467b753ec6}" -Start "{" -End "}" | Select-Object -First 1
        226da830-da5c-42af-83fd-37467b753ec6
        .EXAMPLE
        $subStringsList = Get-OZODelimiterSubString -String "2023-06-20T14:18:09-05:00{226da830-da5c-42af-83fd-37467b753ec6}" -Start ":" -End ":"
        $subStringsList[0]
        18
        $subStringsList[1]
        09-05
        .EXAMPLE
        (Get-OZODelimiterSubString -String "alievertz@onezeroone.dev" -Start "@" -End ".dev")[0]
        onezeroone
        .OUTPUTS
        System.Collections.Generic.List[String]
        .NOTES
        Thanks to this Stack Overflow post (https://stackoverflow.com/questions/67626879/system-collections-generic-liststring-as-return-value that helped me understand how to write a function that consistently returns a List.
        .LINK
        https://github.com/onezeroone-dev/OZO-PowerShell-Module/blob/main/Documentation/Get-OZODelimiterSubstring.md
    #>

    # Parameters
    [CmdLetBinding()] Param (
        [Parameter(Mandatory=$true,HelpMessage="The string to parse",ValueFromPipeline=$true)][String]$String,
        [Parameter(Mandatory=$false,HelpMessage="The starting delimiter string")][Char]$Start,
        [Parameter(Mandatory=$false,HelpMessage="The ending delimiter string")][Char]$End
    )
    # Variables
    [System.Collections.Generic.List[String]]$Results = @()
    # Determine if we have Start and not have End
    If ([String]::IsNullOrEmpty($Start) -eq $false -And [String]::IsNullOrEmpty($End) -eq $true) {
        # We have Start and not have End; determine if String contains Start
        If ($String -Like ("*" + $Start + "*")) {
            # String contains Start; return the substring following Start
            $Results.Add($String.Substring($String.IndexOf($Start) + 1))
        } Else {
            # String does not contain Start; return the original unaltered string
            $Results.Add($String)
        }
    # Determine if we not have Start and have End
    } ElseIf ([String]::IsNullOrEmpty($Start) -eq $true -And [String]::IsNullOrEmpty($End) -eq $false) {
        # We have End and not have Start; determine if String contains End
        If ($String -Like ("*" + $End + "*")) {
            # String contains End; return the substring leading up to End
            $Results.Add($String.Split($EndFern)[0])
        } Else {
            # String does not contain End; return the original unaltered string
            $Results.Add($String)
        }
    # We have Start and End
    } Else {
        # Determine if Start and End are identical, and appears at least twice in the input string
        If ($Start -eq $End -And $String.Split($Start).Count -ge 3) {
            # Start and End are identical and appears at least twice in the string; perform a simple split and return the middle set
            [System.Collections.Generic.List[String]] $tempResults = $String.Split($Start)
            For ($Count = 1; $Count -lt ($tempResults.Count - 1)) {
                $Results.Add($tempResults[$Count])
            }
            #ForEach ($Result in $String.Split($StartFern)[1..-2]) { $Results.Add($Result) }
        # Determine if the string contains Start and End
        } ElseIf ($String -Like ("*" + $Start + "*") -And $String -Like ("*" + $End + "*")) {
            # String contains Start and End; add each of the results to the List
            ForEach ($Result in [Regex]::Matches($String,"(?<=\$Start).+?(?=\$End)").Value) { $Results.Add($Result) }
        # Determine if String contains only Start
        } ElseIf ($String -Like ("*" + $Start + "*")) {
            # String contains only Start; add the string following the first instance of Start to the list
            $Results.Add([Regex]::Matches($String,"(?<=\$Start).*").Value)
        # Determine if String contains only End
        } ElseIf ($String -Like ("*" + $End + "*")) {
            # String contains only End; add the string leading up to End to the list
            $Results.Add([Regex]::Matches($String,".*(?=\$End)").Value)
        # None of the above apply
        } Else {
            # Neither Start or End appear in String; return the original unaltered string
            $Results.Add($String)
        }
    }    
    # Return
    $PSCmdlet.WriteObject($Results)
}

Function Get-OZOEndSubString {
    <#
        .SYNOPSIS
        See description.
        .DESCRIPTION
        Returns the last "Length" characters of a string. If Length is longer than String, the original string is returned.
        .PARAMETER String
        The string to parse. Accepts pipeline input.
        .PARAMETER Length
        The number of characters to return.
        .EXAMPLE
        Get-OZOEndSubString -String "The quick brown fox jumps over the lazy dog." -Length 8
        azy dog.
        .EXAMPLE
        "The quick brown fox jumps over the lazy dog." | Get-OZOEndSubString -Length 8
        azy dog.
        .OUTPUTS
        System.String
        .LINK
        https://github.com/onezeroone-dev/OZO-PowerShell-Module/blob/main/Documentation/Get-OZOEndSubString.md
    #>

    # Parameters
    param (
        [Parameter(Mandatory=$true,HelpMessage="The string to parse",ValueFromPipeline=$true)][String]$String,
        [Parameter(Mandatory=$true,HelpMessage="The number of characters to return")][Int32]$Length
    )
    # Determine if Length is shorter than or equal to String length
    If ($First -le $String.Length) { 
        # Length is shorter than or equal to String length; return the desired substring
        return $String.Substring($String.Length - $Length)
    } Else {
        # Length is *not* shorter than or equal to String length
        return $String
    }
}

Function Get-OZOIndexSubString {
    <#
        .SYNOPSIS
        See description.
        .DESCRIPTION
        Returns the inner part of a string based on a starting index and length. If the length between the start index and the end of the string is longer than Length, the string trailing the start index is returned. If Length is longer than String, the original string is returned.
        .PARAMETER String
        The string to process. Accepts pipeline input.
        .PARAMETER Index
        The starting character index.
        .PARAMETER Length
        The number of characters to return.
        .EXAMPLE
        Get-OZOIndexSubString -String "The quick brown fox jumps over the lazy dog." -Index 8 -Length 4
        ck b
        .EXAMPLE
        "The quick brown fox jumps over the lazy dog." | Get-OZOIndexSubString -Index 8 -Length 4
        ck b
        .LINK
        https://github.com/onezeroone-dev/OZO-PowerShell-Module/blob/main/Documentation/Get-OZOIndexSubString.md
    #>

    # Parameters
    param (
        [Parameter(Mandatory=$true,HelpMessage="The string to parse",ValueFromPipeline=$true)][String]$String,
        [Parameter(Mandatory=$true,HelpMessage="The starting character number")][Int32]$Index,
        [Parameter(Mandatory=$true,HelpMessage="The number of characters to return")][Int32]$Length

    )
    # Determine if Start = or Start = 1
    If ($Index -eq 0 -Or $Index -eq 1) {
        # Start is 0 or 1; call Get-OZOStartSubString
        return (Get-OZOStartSubString -String $String -Length $Length)
    } ElseIf ($Index -eq $String.Length) {
        # Start character is equal to the length of String; return the last character
        return $String.Substring($String.Length - 1)
    } ElseIf ($Index -lt $String.Length) {
        # Shift Start to be inclusive
        $Index = $Index - 1
        # Determine that the start character is shorter than String length
        If ($Index -lt $String.Length) {
            # Start character shorter than String length; determine that the difference length is less than or equal to Length
            If ($Length -le ($String.Length - $Index)) {
                # Difference length is less than or equal to Length; return the desired substring
                return $String.Substring($Index,$Length)
            } Else {
                # Difference length is *not* less than or equal to Length; return the substring starting at StartCharacter
                return $String.Substring($String.Length - ($String.Length - $Index))
            }

        } Else {
            # Start character is *not* less than the length of the string; return the original String
            return $String
        }
    }
}

Function Get-OZOReverseString {
    <#
        .SYNOPSIS
        See description.
        .DESCRIPTION
        Returns the reverse of a given string.
        .PARAMETER String
        The string to reverse
        .EXAMPLE
        Get-OZOReverseString -String "Hello, world"
        dlrow ,olleH
        .EXAMPLE
        "Hello, world" | Get-OZOReverseString
        dlrow ,olleH
        .LINK
        https://github.com/onezeroone-dev/OZO-PowerShell-Module/blob/main/Documentation/Get-OZOReverseString.md
    #>

    Param(
        [Parameter(Mandatory=$true,HelpMessage="The string to reverse",ValueFromPipeline=$true)][String]$String
    )
    # Convert the string to a character array
    [Array]$Gnirts = $String.ToCharArray()
    # Reverse the character array
    [Array]::Reverse($Gnirts)
    # return the joined elements of the character array
    return -Join $Gnirts
}

Function Get-OZOStartSubString {
    <#
        .SYNOPSIS
        See description.
        .DESCRIPTION
        Returns the first "Length" characters of a string. If Length is longer than String, the original string is returned.
        .PARAMETER String
        The string to parse. Accepts pipeline input.
        .PARAMETER Length
        The number of characters to return.
        .EXAMPLE
        Get-OZOStartSubString -String "The quick brown fox jumps over the lazy dog." -Length 8
        The quic
        .EXAMPLE
        "The quick brown fox jumps over the lazy dog." | Get-OZOStartSubString -Length 8
        The quic
        .LINK
        https://github.com/onezeroone-dev/OZO-PowerShell-Module/blob/main/Documentation/Get-OZOStartSubString.md
    #>

    # Parameters
    param (
        [Parameter(Mandatory=$true,HelpMessage="The string to parse",ValueFromPipeline=$true)][String]$String,
        [Parameter(Mandatory=$true,HelpMessage="The number of characters to return")][Int32]$Length
    )
    # Determine if Length shorter than or or equal to String length
    If ($Length -le $String.Length) {
        # Length is shorter than or equal to String length; return the desired substring
        return $String.Substring(0,$Length)
    } Else {
        # Length is *not* shorter tahn equal to String length; return String
        return $String
    }
}

Export-ModuleMember -Function Get-OZODelimiterSubString,Get-OZOEndSubString,Get-OZOIndexSubString,Get-OZOReverseString,Get-OZOStartSubString

# SIG # Begin signature block
# MIIfcwYJKoZIhvcNAQcCoIIfZDCCH2ACAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA6NL50MMDbsir2
# HRguY38UdVUxT3CSkg+zCU9RpxF1CKCCDPgwggZyMIIEWqADAgECAghkM1HTxzif
# CDANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
# EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8G
# A1UEAwwoU1NMLmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAe
# Fw0xNjA2MjQyMDQ0MzBaFw0zMTA2MjQyMDQ0MzBaMHgxCzAJBgNVBAYTAlVTMQ4w
# DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENv
# cnAxNDAyBgNVBAMMK1NTTC5jb20gQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBD
# QSBSU0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCfgxNzqrDG
# bSHL24t6h3TQcdyOl3Ka5LuINLTdgAPGL0WkdJq/Hg9Q6p5tePOf+lEmqT2d0bKU
# Vz77OYkbkStW72fL5gvjDjmMxjX0jD3dJekBrBdCfVgWQNz51ShEHZVkMGE6ZPKX
# 13NMfXsjAm3zdetVPW+qLcSvvnSsXf5qtvzqXHnpD0OctVIFD+8+sbGP0EmtpuNC
# GVQ/8y8Ooct8/hP5IznaJRy4PgBKOm8yMDdkHseudQfYVdIYyQ6KvKNc8HwKp4WB
# wg6vj5lc02AlvINaaRwlE81y9eucgJvcLGfE3ckJmNVz68Qho+Uyjj4vUpjGYDdk
# jLJvSlRyGMwnh/rNdaJjIUy1PWT9K6abVa8mTGC0uVz+q0O9rdATZlAfC9KJpv/X
# gAbxwxECMzNhF/dWH44vO2jnFfF3VkopngPawismYTJboFblSSmNNqf1x1KiVgMg
# Lzh4gL32Bq5BNMuURb2bx4kYHwu6/6muakCZE93vUN8BuvIE1tAx3zQ4XldbyDge
# VtSsSKbt//m4wTvtwiS+RGCnd83VPZhZtEPqqmB9zcLlL/Hr9dQg1Zc0bl0EawUR
# 0tOSjAknRO1PNTFGfnQZBWLsiePqI3CY5NEv1IoTGEaTZeVYc9NMPSd6Ij/D+KNV
# t/nmh4LsRR7Fbjp8sU65q2j3m2PVkUG8qQIDAQABo4H7MIH4MA8GA1UdEwEB/wQF
# MAMBAf8wHwYDVR0jBBgwFoAU3QQJB6L1en1SUxKSle44gCUNplkwMAYIKwYBBQUH
# AQEEJDAiMCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTARBgNVHSAE
# CjAIMAYGBFUdIAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwOwYDVR0fBDQwMjAwoC6g
# LIYqaHR0cDovL2NybHMuc3NsLmNvbS9zc2wuY29tLXJzYS1Sb290Q0EuY3JsMB0G
# A1UdDgQWBBRUwv4QlQCTzWr158DX2bJLuI8M4zAOBgNVHQ8BAf8EBAMCAYYwDQYJ
# KoZIhvcNAQELBQADggIBAPUPJodwr5miyvXWyfCNZj05gtOII9iCv49UhCe204MH
# 154niU2EjlTRIO5gQ9tXQjzHsJX2vszqoz2OTwbGK1mGf+tzG8rlQCbgPW/M9r1x
# xs19DiBAOdYF0q+UCL9/wlG3K7V7gyHwY9rlnOFpLnUdTsthHvWlM98CnRXZ7WmT
# V7pGRS6AvGW+5xI+3kf/kJwQrfZWsqTU+tb8LryXIbN2g9KR+gZQ0bGAKID+260P
# Z+34fdzZcFt6umi1s0pmF4/n8OdX3Wn+vF7h1YyfE7uVmhX7eSuF1W0+Z0duGwdc
# +1RFDxYRLhHDsLy1bhwzV5Qe/kI0Ro4xUE7bM1eV+jjk5hLbq1guRbfZIsr0WkdJ
# LCjoT4xCPGRo6eZDrBmRqccTgl/8cQo3t51Qezxd96JSgjXktefTCm9r/o35pNfV
# HUvnfWII+NnXrJlJ27WEQRQu9i5gl1NLmv7xiHp0up516eDap8nMLDt7TAp4z5T3
# NmC2gzyKVMtODWgqlBF1JhTqIDfM63kXdlV4cW3iSTgzN9vkbFnHI2LmvM4uVEv9
# XgMqyN0eS3FE0HU+MWJliymm7STheh2ENH+kF3y0rH0/NVjLw78a3Z9UVm1F5VPz
# iIorMaPKPlDRADTsJwjDZ8Zc6Gi/zy4WZbg8Zv87spWrmo2dzJTw7XhQf+xkR6Od
# MIIGfjCCBGagAwIBAgIQZ2iSsNbwOsjnLExSAX6F6DANBgkqhkiG9w0BAQsFADB4
# MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x
# ETAPBgNVBAoMCFNTTCBDb3JwMTQwMgYDVQQDDCtTU0wuY29tIENvZGUgU2lnbmlu
# ZyBJbnRlcm1lZGlhdGUgQ0EgUlNBIFIxMB4XDTI0MTExNjEwMzUyOFoXDTI1MTEx
# NjEwMzUyOFowZTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCENvbG9yYWRvMQ8wDQYD
# VQQHDAZEZW52ZXIxGDAWBgNVBAoMD0FuZHJldyBMaWV2ZXJ0ejEYMBYGA1UEAwwP
# QW5kcmV3IExpZXZlcnR6MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA
# vIBAQzK0aahepOrPmvCEqfd6dMZC4GvV7kflKwrn4QPJGfqhFmUtadP1e3ange8O
# QZ3/w7UjOTAUNUHfhjbSgUBlKjbS6EWQKZuRFzI3SNkMJkcjTX4uS2P4QsnwM+SW
# IE5me3CTssdjtgue+Iiy53TMgW8JpoxiULVxmm3bhCRUAgxWeT6tzjytR1UyGcMc
# cm/YE6TOgsCHiZoo4X4HJD9iHDrNldArq04Jl6FsADxEswttKyfqpIRJLoAysVl1
# f8CEDBwhszJrEXBnAlWViJFfNY+dKP4jhf7lLqSvPCuADqP2jvM0Ym5I8qDGMz9j
# XPSMLF58MFB4vM4viS7nLRFJ8S1Q98vQvB8W4kk0WPuiZbZTHsROzohE1VSbLnIY
# ag5dDOWI8L6yutAsfdZFYFmSTKcMSiOj5VbK4LhAJUL2G8vPwpTGFgr+cEp0p62F
# P0WXK+/cRfGqodI5S+bg+9rQTD9zf829DwraSRAt5P5zrQk4WPst3JW/vIKNx7cV
# AgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFFTC/hCVAJPN
# avXnwNfZsku4jwzjMHoGCCsGAQUFBwEBBG4wbDBIBggrBgEFBQcwAoY8aHR0cDov
# L2NlcnQuc3NsLmNvbS9TU0xjb20tU3ViQ0EtQ29kZVNpZ25pbmctUlNBLTQwOTYt
# UjEuY2VyMCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTBRBgNVHSAE
# SjBIMAgGBmeBDAEEATA8BgwrBgEEAYKpMAEDAwEwLDAqBggrBgEFBQcCARYeaHR0
# cHM6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5MBMGA1UdJQQMMAoGCCsGAQUFBwMD
# ME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9jcmxzLnNzbC5jb20vU1NMY29tLVN1
# YkNBLUNvZGVTaWduaW5nLVJTQS00MDk2LVIxLmNybDAdBgNVHQ4EFgQUSj8HrSK7
# f/j+Dz31jJFhOF7rJUMwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4IC
# AQBf4lcc6FUJ1W/opNz8yjS9qLUy9cQt0s35BhasB5QoTbDaW4jv9xnFGhQVg6n+
# jhL0i94Vsywd/MRBb8lYGpuBZnS/7LHuRZu7qUuud+IMDyRHIyBK6koN5bfyA5VY
# c7bFbNpbe1s1hMWke8di4qgMLZKDfyG/RtA0swf5t4UgQLPP0h+koZ8X8V5+P0V0
# 1HsdXyXd+ojo38EoZyCKfQL2aAwMPwzZfCbmI5SRXNOc6K8oqXzQcendhlKSfVBo
# Zgpi+1updqbD4jmJfYdK5AYPxJ3YH6td6ETtr8owL+bmX8lQjlXPOwVnC11rVlNB
# VjqtaJRUClLtiNiYSTKVfjdmGVJ4+sNov0dWhHc0A9o5NX/05VVYTlImuJpnG5Og
# o7w6kWRdsgE8gM58jWf7XfI6aQS0Np/z2B+ZBj0K93khEHBX7cvvORa92LCHiVeP
# km+zEAMXgxIPs/e8cmcc/o3CORgzEwxlH9Z3UOWCuXSHD3P2RPNDAY+WPdjSHm9f
# JFlGq+f9iKyedxYa/NNjNag/5EbZ+Z2NldtSMNeFdsejGJ/TJHF1PyJd4aXx9J1i
# B/IZBOoJYyh9xpQ3ljZUKE/4otPi7INpuDFwgWiUHZZJVvrGTWwxH1Yhf8P+VpFf
# aNqsBuvklUcUDs3RNE0f1qlgFfcnAepFF+RiBRqmsj29fjGCEdEwghHNAgEBMIGM
# MHgxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3Rv
# bjERMA8GA1UECgwIU1NMIENvcnAxNDAyBgNVBAMMK1NTTC5jb20gQ29kZSBTaWdu
# aW5nIEludGVybWVkaWF0ZSBDQSBSU0EgUjECEGdokrDW8DrI5yxMUgF+hegwDQYJ
# YIZIAWUDBAIBBQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYK
# KwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG
# 9w0BCQQxIgQgy+QMIwTjsqLnn7wxL0cPydLEJ392bfZtHrdd5JXbhqUwDQYJKoZI
# hvcNAQEBBQAEggGAJH5OdMVjRwztuMWDrNiN0ffy9U2EZeJHl6K8Ve4Y+5IBDQav
# Xr7jhsnUfajqQI2uiHsxdpTauevtL8oATujp8Ze+XUrzVZJTk5QdRY3E4pyTlqBS
# CrZc2ydzJSbnmdIZYn8YaOaPJNI5vv4zvAlpvEUYP8dz+PnMXpvgqzSmrNfmjo8z
# 9gTtKUcYMyTfWQk/v4fl11Dbuk604A6tvmz1/2/JEnR9mL4mxDvONTr6dKGfVLws
# MbmWz5RZAl7YwJEvYrPlghyUpBt5Pa0eeNIx7yI9JNQ3HikK/O7qC1Ly9UbMgtOF
# 3pFCh8Q4i56GeptvKta9/kEAK5BSbpb2fUoTK0eangV/VR/3+vlhuX//OtEz0qsp
# AXibGxlaD8CjK/ULXizgsuh9ZCPH2JFBxtP9zKcQOQ7S9SHB4tYICcYh2b057uf6
# wV9R2znM5p9pk+wTJ/JkJsM+R058UK90Dg8xESQ2lsDPMgbKwcEeDHOJFl7o5wQ8
# 4zZNlGSqH2mCHKdboYIPFzCCDxMGCisGAQQBgjcDAwExgg8DMIIO/wYJKoZIhvcN
# AQcCoIIO8DCCDuwCAQMxDTALBglghkgBZQMEAgEwdwYLKoZIhvcNAQkQAQSgaARm
# MGQCAQEGDCsGAQQBgqkwAQMGATAxMA0GCWCGSAFlAwQCAQUABCABqUeEnLK4EUxP
# elIZOjZfoYmCepLVfLuWg9XnxBeEvwIIXm3t3EvpPsEYDzIwMjUwNjA1MTg0NjM2
# WjADAgEBoIIMADCCBPwwggLkoAMCAQICEFparOgaNW60YoaNV33gPccwDQYJKoZI
# hvcNAQELBQAwczELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQH
# DAdIb3VzdG9uMREwDwYDVQQKDAhTU0wgQ29ycDEvMC0GA1UEAwwmU1NMLmNvbSBU
# aW1lc3RhbXBpbmcgSXNzdWluZyBSU0EgQ0EgUjEwHhcNMjQwMjE5MTYxODE5WhcN
# MzQwMjE2MTYxODE4WjBuMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO
# BgNVBAcMB0hvdXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMSowKAYDVQQDDCFTU0wu
# Y29tIFRpbWVzdGFtcGluZyBVbml0IDIwMjQgRTEwWTATBgcqhkjOPQIBBggqhkjO
# PQMBBwNCAASnYXL1MOl6xIMUlgVC49zonduUbdkyb0piy2i8t3JlQEwA74cjK8g9
# mRC8GH1cAAVMIr8M2HdZpVgkV1LXBLB8o4IBWjCCAVYwHwYDVR0jBBgwFoAUDJ0Q
# JY6apxuZh0PPCH7hvYGQ9M8wUQYIKwYBBQUHAQEERTBDMEEGCCsGAQUFBzAChjVo
# dHRwOi8vY2VydC5zc2wuY29tL1NTTC5jb20tdGltZVN0YW1waW5nLUktUlNBLVIx
# LmNlcjBRBgNVHSAESjBIMDwGDCsGAQQBgqkwAQMGATAsMCoGCCsGAQUFBwIBFh5o
# dHRwczovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkwCAYGZ4EMAQQCMBYGA1UdJQEB
# /wQMMAoGCCsGAQUFBwMIMEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmxzLnNz
# bC5jb20vU1NMLmNvbS10aW1lU3RhbXBpbmctSS1SU0EtUjEuY3JsMB0GA1UdDgQW
# BBRQTySs77U+YxMjCZIm7Lo6luRdIjAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcN
# AQELBQADggIBAJigjwMAkbyrxGRBf0Ih4r+rbCB57lTuwViC6nH2fZSciMogpqSz
# rSeVZ2eIb5vhj9rT7jqWXZn02Fncs4YTrA1QyxJW36yjC4jl5/bsFCaWuXzGXt2Y
# 6Ifp//A3Z0sNTMWTTBobmceM3sqnovdX9ToRFP+29r5yQnPcgRTI2PvrVSqLxY9E
# yk9/0cviM3W29YBl080ENblRcu3Y8RsfzRtVT/2snuDocRxvRYmd0TPaMgIj2xII
# 651QnPp1hiq9xU0AyovLzbsi5wlR5Ip4i/i8+x+HwYJNety5cYtdWJ7uQP6YaZtW
# /jNoHp76qNftq/IlSx6xEYBRjFBxHSq2fzhUQ5oBawk2OsZ2j0wOf7q7AqjCt6t/
# +fbmWjrAWYWZGj/RLjltqdFPBpIKqdhjVIxaGgzVhaE/xHKBg4k4DfFZkBYJ9BWu
# P93Tm+paWBDwXI7Fg3alGsboErWPWlvwMAmpeJUjeKLZY26JPLt9ZWceTVWuIyuj
# erqb5IMmeqLJm5iFq/Qy4YPGyPiolw5w1k9OeO4ErmS2FKvk1ejvw4SWR+S1VyWn
# ktY442WaoStxBCCVWZdMWFeB+EpL8uoQNq1MhSt/sIUjUudkyZLIbMVQjj7b6gPX
# nD6mS8FgWiCAhuM1a/hgA+6o1sJWizHdmcpYDhyNzorf9KVRE6iR7rcmMIIG/DCC
# BOSgAwIBAgIQbVIYcIfoI02FYADQgI+TVjANBgkqhkiG9w0BAQsFADB8MQswCQYD
# VQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAWBgNV
# BAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290IENlcnRp
# ZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTExMTMxODUwMDVaFw0zNDExMTIx
# ODUwMDVaMHMxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwH
# SG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxLzAtBgNVBAMMJlNTTC5jb20gVGlt
# ZXN0YW1waW5nIElzc3VpbmcgUlNBIENBIFIxMIICIjANBgkqhkiG9w0BAQEFAAOC
# Ag8AMIICCgKCAgEArlEQE9L5PCCgIIXeyVAcZMnh/cXpNP8KfzFI6HJaxV6oYf3x
# h/dRXPu35tDBwhOwPsJjoqgY/Tg6yQGBqt65t94wpx0rAgTVgEGMqGri6vCI6rEt
# SZVy9vagzTDHcGfFDc0Eu71mTAyeNCUhjaYTBkyANqp9m6IRrYEXOKdd/eREsqVD
# mhryd7dBTS9wbipm+mHLTHEFBdrKqKDM3fPYdBOro3bwQ6OmcDZ1qMY+2Jn1o0l4
# N9wORrmPcpuEGTOThFYKPHm8/wfoMocgizTYYeDG/+MbwkwjFZjWKwb4hoHT2WK8
# pvGW/OE0Apkrl9CZSy2ulitWjuqpcCEm2/W1RofOunpCm5Qv10T9tIALtQo73GHI
# lIDU6xhYPH/ACYEDzgnNfwgnWiUmMISaUnYXijp0IBEoDZmGT4RTguiCmjAFF5OV
# NbY03BQoBb7wK17SuGswFlDjtWN33ZXSAS+i45My1AmCTZBV6obAVXDzLgdJ1A1r
# yyXz4prLYyfJReEuhAsVp5VouzhJVcE57dRrUanmPcnb7xi57VPhXnCuw26hw1Hd
# +ulK3jJEgbc3rwHPWqqGT541TI7xaldaWDo85k4lR2bQHPNGwHxXuSy3yczyOg57
# TcqqG6cE3r0KR6jwzfaqjTvN695GsPAPY/h2YksNgF+XBnUD9JBtL4c34AcCAwEA
# AaOCAYEwggF9MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU3QQJB6L1
# en1SUxKSle44gCUNplkwgYMGCCsGAQUFBwEBBHcwdTBRBggrBgEFBQcwAoZFaHR0
# cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29tUm9vdENlcnRpZmljYXRp
# b25BdXRob3JpdHlSU0EuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3Ns
# LmNvbTA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cHM6Ly93
# d3cuc3NsLmNvbS9yZXBvc2l0b3J5MBMGA1UdJQQMMAoGCCsGAQUFBwMIMDsGA1Ud
# HwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmxzLnNzbC5jb20vc3NsLmNvbS1yc2EtUm9v
# dENBLmNybDAdBgNVHQ4EFgQUDJ0QJY6apxuZh0PPCH7hvYGQ9M8wDgYDVR0PAQH/
# BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQCSGXUNplpCzxkH2fL8lPrAm/AV6USW
# Wi9xM91Q5RN7mZN3D8T7cm1Xy7qmnItFukgdtiUzLbQokDJyFTrF1pyLgGw/2hU3
# FJEywSN8crPsBGo812lyWFgAg0uOwUYw7WJQ1teICycX/Fug0KB94xwxhsvJBiRT
# pQyhu/2Kyu1Bnx7QQBA1XupcmfhbQrK5O3Q/yIi//kN0OkhQEiS0NlyPPYoRboHW
# C++wogzV6yNjBbKUBrMFxABqR7mkA0x1Kfy3Ud08qyLC5Z86C7JFBrMBfyhfPpKV
# lIiiTQuKz1rTa8ZW12ERoHRHcfEjI1EwwpZXXK5J5RcW6h7FZq/cZE9kLRZhvnRK
# tb+X7CCtLx2h61ozDJmifYvuKhiUg9LLWH0Or9D3XU+xKRsRnfOuwHWuhWch8G7k
# EmnTG9CtD9Dgtq+68KgVHtAWjKk2ui1s1iLYAYxnDm13jMZm0KpRM9mLQHBK5Gb4
# dFgAQwxOFPBslf99hXWgLyYE33vTIi9p0gYqGHv4OZh1ElgGsvyKdUUJkAr5hfbD
# X6pYScJI8v9VNYm1JEyFAV9x4MpskL6kE2Sy8rOqS9rQnVnIyPWLi8N9K4GZvPit
# /Oy+8nFL6q5kN2SZbox5d69YYFe+rN1sDD4CpNWwBBTI/q0V4pkgvhL99IV2Xasj
# HZf4peSrHdL4RjGCAlkwggJVAgEBMIGHMHMxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI
# DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxLzAt
# BgNVBAMMJlNTTC5jb20gVGltZXN0YW1waW5nIElzc3VpbmcgUlNBIENBIFIxAhBa
# WqzoGjVutGKGjVd94D3HMAsGCWCGSAFlAwQCAaCCAWEwGgYJKoZIhvcNAQkDMQ0G
# CyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNTA2MDUxODQ2MzZaMCgGCSqG
# SIb3DQEJNDEbMBkwCwYJYIZIAWUDBAIBoQoGCCqGSM49BAMCMC8GCSqGSIb3DQEJ
# BDEiBCDR8FUQle2q1gAafEYDQtWwvCOrwAIkEQ6f57D+NLg4KTCByQYLKoZIhvcN
# AQkQAi8xgbkwgbYwgbMwgbAEIJ1xf43CN2Wqzl5KsOH1ddeaF9Qc7tj9r+8D/T29
# iUfnMIGLMHekdTBzMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNV
# BAcMB0hvdXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMS8wLQYDVQQDDCZTU0wuY29t
# IFRpbWVzdGFtcGluZyBJc3N1aW5nIFJTQSBDQSBSMQIQWlqs6Bo1brRiho1XfeA9
# xzAKBggqhkjOPQQDAgRIMEYCIQDBvrce4l9lWyowpZRP14VeFMzMbc3R1co3ve4L
# VBhUoQIhAJc8bNVj83oMi7yxaCXMkSt0uLzo6hk+mwMRHWtDywlP
# SIG # End signature block