UMN-SplunkRA.psm1

###
# Copyright 2017 University of Minnesota, Office of Information Technology

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with Foobar. If not, see <http://www.gnu.org/licenses/>.

# based off http://dev.splunk.com/restapi


#region Connect-Splunk
Function Connect-Splunk{
    <#
        .SYNOPSIS
            Connect to splunk server and header properly formatted
        
        .DESCRIPTION
            Connect to splunk server and header properly formatted
        
        .PARAMETER splunkCreds
            PS credential of user that has access

        .PARAMETER server
            FQDN for splunk server

        .PARAMETER SkipCertificateCheck
            Ignore bad SSL Certificates

        .PARAMETER port
            splunk server port to connect to, port 8089 is the default

        .EXAMPLE
            $header = Connect-Splunk -splunkCreds $cred -SkipCertificateCheck -server 'splunk.mydomain.com'

        .OUTPUTS
            System.Collections.Hashtable[]
            Header with Authentication information

        .NOTES
            # http://docs.splunk.com/Documentation/Splunk/latest/RESTUM/RESTusing#Authentication_and_authorization
            For legacy automation systems dealing with cookies -
            -UseBasicParsing is included on the InvokeWebRequest - needed parsing for Orchestrator
    #>


    [CmdletBinding()]
    param(

        [ValidateNotNullOrEmpty()]
        [System.Management.Automation.PSCredential]$splunkCreds,

        [parameter(Mandatory)]
        [string]$server,

        [switch]$SkipCertificateCheck,

        [string]$port = "8089"
    )
     
    Begin
    {
        if ($SkipCertificateCheck -and $PSVersionTable.PSVersion.Major -lt 6)
        {
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@

            [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
        }
}
    Process
    {    
        $uri = "https://$server`:$port/services/auth/login"
        $return = (Invoke-RestMethod -Uri $uri -UseBasicParsing -body "username=$($splunkCreds.UserName);password=$($splunkCreds.GetNetworkCredential().Password)" -Method Post -ContentType 'application/x-www-form-urlencoded').response
        $session = $return.sessionKey
        return (@{"Authorization"= "Splunk $session"})
    }
    End{}
}
#endregion

#region Invoke-SplunkBase
Function Invoke-SplunkBase{
    <#
        .SYNOPSIS
            Base function all other functions are built on

        .DESCRIPTION
            Base function all other functions are built on

        .PARAMETER header
            Header value (use Connect-splunk to get it)

        .PARAMETER server
            FQDN for splunk server

        .PARAMETER outPutmode
            csv,xml,json data return type for call

        .PARAMETER port
            splunk server port to connect to, port 8089 is the default

        .PARAMETER resourcePath
            Api resoure path.

        .EXAMPLE

        .NOTES
    #>


    [CmdletBinding()]
    param(

        [parameter(Mandatory)]
        [string]$server,

        [parameter(Mandatory)]
        [System.Collections.Hashtable]$header,

        [System.Collections.Hashtable]$body,

        [parameter(Mandatory)]
        [string]$resourcePath,

        ## Warning the convertfrom-json blows up a LOT, it does not like the way spunk sends back data
        [ValidateSet("json", "csv", "xml", "default")]
        [string]$outPutmode = "default",

        #[switch]$SkipCertificateCheck,

        [string]$port = "8089"
    )
    Begin{}
    Process
    {
        $uri = "https://$server`:$port/services/$resourcePath"
        if ($outPutmode -ne 'default'){$uri = $uri + "?output_mode=$outPutmode"}
        if ($body){$data = (Invoke-WebRequest -Uri $uri -Headers $header -Body $body -UseBasicParsing ).Content}
        else{$data = (Invoke-WebRequest -Uri $uri -Headers $header -UseBasicParsing ).Content}
        if ($outPutmode -eq 'csv'){ return ($data | ConvertFrom-Csv)}
        elseif ($outPutmode -eq 'json'){return ($data | ConvertFrom-Json)}
        else{return $data}
    }
    End{}
}
#endregion

#region Get-SplunkSearchExport
Function Get-SplunkSearchExport{
    <#
        .SYNOPSIS
            Get results for a search

        .DESCRIPTION
            Get results for a search

        .PARAMETER header
            Header value (use Connect-splunk to get it)

        .PARAMETER server
            FQDN for splunk server

        .PARAMETER outPutmode
            csv,xml,json data return type for call

        .PARAMETER port
            splunk server port to connect to, port 8089 is the default

        .PARAMETER search
            Realtime Search you want performed

    #>


    [CmdletBinding()]
    param(

        [parameter(Mandatory)]
        [string]$server,

        [parameter(Mandatory)]
        [System.Collections.Hashtable]$header,

        [parameter(Mandatory)]
        [string]$search,

        ## Warning the convertfrom-json blows up a LOT, it does not like the way spunk sends back data
        [ValidateSet("json", "csv", "xml", "default")]
        [string]$outPutmode = "default",

        #[switch]$SkipCertificateCheck,

        [string]$port = "8089"
    )
    
    Begin{}
    Process
    {
        $body = @{"search" = "search $search"}
        return (Invoke-SplunkBase -server $server -header $header -resourcePath 'search/jobs/export' -outPutmode $outPutmode -body $body -port $port)
    }
    End{}
}
#endregion

#region Get-SplunkListSavedSearches
function Get-SplunkListSavedSearches{
<#
    .SYNOPSIS
        Get list of saved searches

    .DESCRIPTION
        Get list of saved searches

    .PARAMETER header
        Header value (use Connect-splunk to get it)

    .PARAMETER server
        FQDN for splunk server

    .PARAMETER port
        splunk server port to connect to, port 8089 is the default

    .PARAMETER complete
       The default is to return a summary of search, use this switch to get all the details the system returns

    .EXAMPLE
        Get-SplunkListSavedSearches -server $server -header $header

    .NOTES
        
#>

    [CmdletBinding()]
    Param
    (
        [parameter(Mandatory)]
        [string]$server,

        [parameter(Mandatory)]
        [System.Collections.Hashtable]$header,

        [string]$port = "8089",

        [switch]$complete
    )

    Begin{}
    Process
    {
        if ($complete){return ((Invoke-SplunkBase -server $server -header $header -resourcePath 'saved/searches' -outPutmode json).entry)}
        else{return ((Invoke-SplunkBase -server $server -header $header -resourcePath 'saved/searches' -outPutmode json).entry | Select name,author,updated,id)}
    }
    End{}
}
#endregion

#region Get-SplunkSearchJobs
function Get-SplunkSearchJobs{
<#
    .SYNOPSIS
        Get list of jobs or details about a specific job

    .DESCRIPTION
        Get list of jobs or details about a specific job

    .PARAMETER header
        Header value (use Connect-splunk to get it)

    .PARAMETER server
        FQDN for splunk server

    .PARAMETER port
        splunk server port to connect to, port 8089 is the default

    .PARAMETER sid
       The default is to return a summary of jobs, this will also get the Search ID (sid) that you can feed back in to get more details about a job

    .EXAMPLE
        Get-SplunkListSavedSearches -server $server -header $header

    .NOTES
        
#>

    [CmdletBinding()]
    Param
    (
        [parameter(Mandatory)]
        [string]$server,

        [parameter(Mandatory)]
        [System.Collections.Hashtable]$header,

        [string]$port = "8089",

        [string]$sid
    )

    Begin{}
    Process
    {
        if ($sid){return (Invoke-SplunkBase -server $server -header $header -resourcePath "search/jobs/$sid" -outPutmode csv)}
        else{return (Invoke-SplunkBase -server $server -header $header -resourcePath 'search/jobs' -outPutmode csv | select label,user,sid | sort -Property label)}
    }
    End{}
}
#endregion

#region Get-SplunkSearchJobsResults
function Get-SplunkSearchJobsResults{
<#
    .SYNOPSIS
        Get Reults of a job

    .DESCRIPTION
        Get Reults of a job. It can return a lot of data, consider piping through Select to narrow it down.

    .PARAMETER header
        Header value (use Connect-splunk to get it)

    .PARAMETER server
        FQDN for splunk server

    .PARAMETER port
        splunk server port to connect to, port 8089 is the default

    .PARAMETER sid
       Search ID (sid), use Get-SplunkSearchJobs to get this

    .EXAMPLE
        

    .NOTES
        
#>

    [CmdletBinding()]
    Param
    (
        [parameter(Mandatory)]
        [string]$server,

        [parameter(Mandatory)]
        [System.Collections.Hashtable]$header,

        [string]$port = "8089",

        [parameter(Mandatory)]
        [string]$sid
    )

    Begin{}
    Process
    {
        return (Invoke-SplunkBase -server $server -header $header -resourcePath "search/jobs/$sid/results" -outPutmode csv)
    }
    End{}
}
#endregion
# SIG # Begin signature block
# MIIaxgYJKoZIhvcNAQcCoIIatzCCGrMCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUqRzWkTrdja28PbU/CoZwOFmj
# 4VKgghW3MIIEmTCCA4GgAwIBAgIPFojwOSVeY45pFDkH5jMLMA0GCSqGSIb3DQEB
# BQUAMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQg
# TGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNV
# BAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEdMBsGA1UEAxMUVVROLVVTRVJG
# aXJzdC1PYmplY3QwHhcNMTUxMjMxMDAwMDAwWhcNMTkwNzA5MTg0MDM2WjCBhDEL
# MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
# BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKjAoBgNVBAMT
# IUNPTU9ETyBTSEEtMSBUaW1lIFN0YW1waW5nIFNpZ25lcjCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBAOnpPd/XNwjJHjiyUlNCbSLxscQGBGue/YJ0UEN9
# xqC7H075AnEmse9D2IOMSPznD5d6muuc3qajDjscRBh1jnilF2n+SRik4rtcTv6O
# KlR6UPDV9syR55l51955lNeWM/4Og74iv2MWLKPdKBuvPavql9LxvwQQ5z1IRf0f
# aGXBf1mZacAiMQxibqdcZQEhsGPEIhgn7ub80gA9Ry6ouIZWXQTcExclbhzfRA8V
# zbfbpVd2Qm8AaIKZ0uPB3vCLlFdM7AiQIiHOIiuYDELmQpOUmJPv/QbZP7xbm1Q8
# ILHuatZHesWrgOkwmt7xpD9VTQoJNIp1KdJprZcPUL/4ygkCAwEAAaOB9DCB8TAf
# BgNVHSMEGDAWgBTa7WR0FJwUPKvdmam9WyhNizzJ2DAdBgNVHQ4EFgQUjmstM2v0
# M6eTsxOapeAK9xI1aogwDgYDVR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwFgYD
# VR0lAQH/BAwwCgYIKwYBBQUHAwgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny
# bC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDA1BggrBgEF
# BQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w
# DQYJKoZIhvcNAQEFBQADggEBALozJEBAjHzbWJ+zYJiy9cAx/usfblD2CuDk5oGt
# Joei3/2z2vRz8wD7KRuJGxU+22tSkyvErDmB1zxnV5o5NuAoCJrjOU+biQl/e8Vh
# f1mJMiUKaq4aPvCiJ6i2w7iH9xYESEE9XNjsn00gMQTZZaHtzWkHUxY93TYCCojr
# QOUGMAu4Fkvc77xVCf/GPhIudrPczkLv+XZX4bcKBUCYWJpdcRaTcYxlgepv84n3
# +3OttOe/2Y5vqgtPJfO44dXddZhogfiqwNGAwsTEOYnB9smebNd0+dmX+E/CmgrN
# Xo/4GengpZ/E8JIh5i15Jcki+cPwOoRXrToW9GOUEB1d0MYwggV3MIIEX6ADAgEC
# AhAT6ihwW/Ts7Qw2YwmAYUM2MA0GCSqGSIb3DQEBDAUAMG8xCzAJBgNVBAYTAlNF
# MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJu
# YWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJv
# b3QwHhcNMDAwNTMwMTA0ODM4WhcNMjAwNTMwMTA0ODM4WjCBiDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4w
# HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVz
# dCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzO
# iZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwW
# IJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YU
# VD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1da
# t//O+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+
# UzeQc0PzMsNT79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/z
# JSZrM233bkf6c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLa
# qUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxb
# gtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9A
# qURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
# eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwID
# AQABo4H0MIHxMB8GA1UdIwQYMBaAFK29mHo0tCb3+sQmVO8DveAky1QaMB0GA1Ud
# DgQWBBRTeb9aqitKz1SA4dibwJ3ysgNmyzAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T
# AQH/BAUwAwEB/zARBgNVHSAECjAIMAYGBFUdIAAwRAYDVR0fBD0wOzA5oDegNYYz
# aHR0cDovL2NybC51c2VydHJ1c3QuY29tL0FkZFRydXN0RXh0ZXJuYWxDQVJvb3Qu
# Y3JsMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNl
# cnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAQEAk2X2N4OVD17Dghwf1nfnPIrA
# qgnw6Qsm8eDCanWhx3nJuVJgyCkSDvCtA9YJxHbf5aaBladG2oJXqZWSxbaPAyJs
# M3fBezIXbgfOWhRBOgUkG/YUBjuoJSQOu8wqdd25cEE/fNBjNiEHH0b/YKSR4We8
# 3h9+GRTJY2eR6mcHa7SPi8BuQ33DoYBssh68U4V93JChpLwt70ZyVzUFv7tGu25t
# N5m2/yOSkcZuQPiPKVbqX9VfFFOs8E9h6vcizKdWC+K4NB8m2XsZBWg/ujzUOAai
# 0+aPDuO0cW1AQsWEtECVK/RloEh59h2BY5adT3Xg+HzkjqnR8q2Ks4zHIc3C7zCC
# BawwggSUoAMCAQICEHJNXiAT1cKRQFXzfFSJVHEwDQYJKoZIhvcNAQELBQAwfDEL
# MAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1JMRIwEAYDVQQHEwlBbm4gQXJib3IxEjAQ
# BgNVBAoTCUludGVybmV0MjERMA8GA1UECxMISW5Db21tb24xJTAjBgNVBAMTHElu
# Q29tbW9uIFJTQSBDb2RlIFNpZ25pbmcgQ0EwHhcNMTcxMjE0MDAwMDAwWhcNMjAx
# MjEzMjM1OTU5WjCByzELMAkGA1UEBhMCVVMxDjAMBgNVBBEMBTU1NDU1MRIwEAYD
# VQQIDAlNaW5uZXNvdGExFDASBgNVBAcMC01pbm5lYXBvbGlzMRgwFgYDVQQJDA8x
# MDAgVW5pb24gU3QgU0UxIDAeBgNVBAoMF1VuaXZlcnNpdHkgb2YgTWlubmVzb3Rh
# MSQwIgYDVQQLDBtDb21wdXRlciBhbmQgRGV2aWNlIFN1cHBvcnQxIDAeBgNVBAMM
# F1VuaXZlcnNpdHkgb2YgTWlubmVzb3RhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
# MIIBCgKCAQEAwk6kLE9u+tWv0JUkIJSn5pWfa09g6cqFLucCXomNj9NYj8t+JfPn
# a3gC6LHv3OQAUDHOoC5H+8N3ea7qVGYIiwPRHzXOGqG/tVaiU5s5hG3vBhfRX8W1
# /2g4/hpgeXUzrxYn/2c5SOGGy0MU1ZJyUSFEdsjXHEV7HXK4qmFGV9RJxtiLZH1q
# UldCglxcj7zw0QnUdG6oAxpwTCeVp057/WXbnIR8a0gPse+y/new5+CBUGTAvrw6
# K2BrJQVsdIIVn/q+BbcZxh9PpeZfTtsi6lgkvy0bUWtl5sSpd75+hvw4Sl3HAaWZ
# toWN7LPmbDbbVRO2Arv4doh4Chod4wJ5xQIDAQABo4IB2DCCAdQwHwYDVR0jBBgw
# FoAUrjUjF///Bj2cUOCMJGUzHnAQiKIwHQYDVR0OBBYEFF4LEhElVUvT8n5txOJS
# NAczooSAMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
# CCsGAQUFBwMDMBEGCWCGSAGG+EIBAQQEAwIEEDBmBgNVHSAEXzBdMFsGDCsGAQQB
# riMBBAMCATBLMEkGCCsGAQUFBwIBFj1odHRwczovL3d3dy5pbmNvbW1vbi5vcmcv
# Y2VydC9yZXBvc2l0b3J5L2Nwc19jb2RlX3NpZ25pbmcucGRmMEkGA1UdHwRCMEAw
# PqA8oDqGOGh0dHA6Ly9jcmwuaW5jb21tb24tcnNhLm9yZy9JbkNvbW1vblJTQUNv
# ZGVTaWduaW5nQ0EuY3JsMH4GCCsGAQUFBwEBBHIwcDBEBggrBgEFBQcwAoY4aHR0
# cDovL2NydC5pbmNvbW1vbi1yc2Eub3JnL0luQ29tbW9uUlNBQ29kZVNpZ25pbmdD
# QS5jcnQwKAYIKwYBBQUHMAGGHGh0dHA6Ly9vY3NwLmluY29tbW9uLXJzYS5vcmcw
# GQYDVR0RBBIwEIEOb2l0bXB0QHVtbi5lZHUwDQYJKoZIhvcNAQELBQADggEBAENR
# lesMKmBaZ0g68lttYEMtaPiz+DaNpOlXBs1gH66aghB1aP6iiRJcFVasGLUVFncd
# G1xbw503LTrBUc5PECMVDVF7KKCfHA1OeFV9vOWyvdVgbe3paDy1sj4CADO2D0gn
# xcGiZoFhEZiBkTvSsj4S3GXZEvoFHJxJLw2kvdLnzy0gH/b/b/yblwA1fKXw4loc
# UpDM6qTwM7SiKgkQ5W7/280EYu8BI6c8rpiJmqM1tZLcpswuavB00T52Y+ZZmz3t
# MMVgFHn9pFFltYr3s3bEek7I6pU8unISbiyQzxqhIUKaBi8hy8LgoY5UnGjX5jHs
# IvINzms+JX5Ity02sL0wggXrMIID06ADAgECAhBl4eLj1d5QRYXzJiSABeLUMA0G
# CSqGSIb3DQEBDQUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNl
# eTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1Qg
# TmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0aW9uIEF1
# dGhvcml0eTAeFw0xNDA5MTkwMDAwMDBaFw0yNDA5MTgyMzU5NTlaMHwxCzAJBgNV
# BAYTAlVTMQswCQYDVQQIEwJNSTESMBAGA1UEBxMJQW5uIEFyYm9yMRIwEAYDVQQK
# EwlJbnRlcm5ldDIxETAPBgNVBAsTCEluQ29tbW9uMSUwIwYDVQQDExxJbkNvbW1v
# biBSU0EgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
# CgKCAQEAwKAvix56u2p1rPg+3KO6OSLK86N25L99MCfmutOYMlYjXAaGlw2A6O2i
# gTXrC/Zefqk+aHP9ndRnec6q6mi3GdscdjpZh11emcehsriphHMMzKuHRhxqx+85
# Jb6n3dosNXA2HSIuIDvd4xwOPzSf5X3+VYBbBnyCV4RV8zj78gw2qblessWBRyN9
# EoGgwAEoPgP5OJejrQLyAmj91QGr9dVRTVDTFyJG5XMY4DrkN3dRyJ59UopPgNwm
# ucBMyvxR+hAJEXpXKnPE4CEqbMJUvRw+g/hbqSzx+tt4z9mJmm2j/w2nP35MViPW
# Cb7hpR2LB8W/499Yqu+kr4LLBfgKCQIDAQABo4IBWjCCAVYwHwYDVR0jBBgwFoAU
# U3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFK41Ixf//wY9nFDgjCRlMx5w
# EIiiMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBMGA1UdJQQM
# MAoGCCsGAQUFBwMDMBEGA1UdIAQKMAgwBgYEVR0gADBQBgNVHR8ESTBHMEWgQ6BB
# hj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNh
# dGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUFBzAChjNo
# dHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5j
# cnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI
# hvcNAQENBQADggIBAEYstn9qTiVmvZxqpqrQnr0Prk41/PA4J8HHnQTJgjTbhuET
# 98GWjTBEE9I17Xn3V1yTphJXbat5l8EmZN/JXMvDNqJtkyOh26owAmvquMCF1pKi
# QWyuDDllxR9MECp6xF4wnH1Mcs4WeLOrQPy+C5kWE5gg/7K6c9G1VNwLkl/po9OR
# PljxKKeFhPg9+Ti3JzHIxW7LdyljffccWiuNFR51/BJHAZIqUDw3LsrdYWzgg4x0
# 6tgMvOEf0nITelpFTxqVvMtJhnOfZbpdXZQ5o1TspxfTEVOQAsp05HUNCXyhznlV
# Lr0JaNkM7edgk59zmdTbSGdMq8Ztuu6VyrivOlMSPWmay5MjvwTzuNorbwBv0DL+
# 7cyZBp7NYZou+DoGd1lFZN0jU5IsQKgm3+00pnnJ67crdFwfz/8bq3MhTiKOWEb0
# 4FT3OZVp+jzvaChHWLQ8gbCORgClaZq1H3aqI7JeRkWEEEp6Tv4WAVsr/i7LoXU7
# 2gOb8CAzPFqwI4Excdrxp0I4OXbECHlDqU4sTInqwlMwofmxeO4u94196qIqJQl+
# 8Sykl06VktqMux84Iw3ZQLH08J8LaJ+WDUycc4OjY61I7FGxCDkbSQf3npXeRFm0
# IBn8GiW+TRDk6J2XJFLWEtVZmhboFlBLoUlqHUCKu0QOhU/+AEOqnY98j2zRMYIE
# eTCCBHUCAQEwgZAwfDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1JMRIwEAYDVQQH
# EwlBbm4gQXJib3IxEjAQBgNVBAoTCUludGVybmV0MjERMA8GA1UECxMISW5Db21t
# b24xJTAjBgNVBAMTHEluQ29tbW9uIFJTQSBDb2RlIFNpZ25pbmcgQ0ECEHJNXiAT
# 1cKRQFXzfFSJVHEwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKEC
# gAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwG
# CisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFMH7KRVliZ0DrJ6F40mE1zwvFuec
# MA0GCSqGSIb3DQEBAQUABIIBAJhAtIatsRTBRramRCOdFaNMYU26gwJXIuatDpev
# 1HycXTKPRcGZOVneQFD+ABnk8vF2iQHC59SksqFEwlOAhmME9L77tabBgtQBHUHW
# afcV6tIvRi1lnXWL9mvWKi7rhs+RZS3Gb+94msjFb0E1R6JqeUynqBfRLMF8cgLj
# Gq9G4F/Gv1CQ9w4iPMzlNrpKIcTw1BVxtAH3dnE7KtFFKF7SEHMR8ZWTk4k+7ppt
# GRkabUk3L2wQv3ITknNKAN6zdEPaF6oJ89tVVxk4tIsA32o+tBKhpB8r5XziHiaK
# 6YJNqRwFUahxNrgTP4dtl8ZJ/PlKjw7mNaRo9AWdy803Y2uhggJDMIICPwYJKoZI
# hvcNAQkGMYICMDCCAiwCAQEwgakwgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJV
# VDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJV
# U1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0w
# GwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdAIPFojwOSVeY45pFDkH5jMLMAkG
# BSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJ
# BTEPFw0xODAyMTUxOTU0MDdaMCMGCSqGSIb3DQEJBDEWBBQ+ZX8C3hM6q5F/R/7Q
# E1eO7wgRmTANBgkqhkiG9w0BAQEFAASCAQCjvH10f11XeGrkpLveFltqhRGL0Upu
# 5I1CAQDl4fommbGpF1fE8iE9sRfnhYwFQ+8rKWu6b/WuRiJ2G2GsJ8fFCTTdloGB
# cfQTEK+HXzj/+4Ve6fO4JCRJbEYXnbBc7fwF6qkQ3rUhbqWxKEEuXgpU8QAxmD2e
# Aacu9O18g0qYr4dCXQyh+yfNFlyugpSpsznvW8DYpvycYqmio3cAN2AaB/Q7888T
# IjdxsDR6K0vaTNcxfCz3QQAeTAfml+fnygyVNsH+ttOWJyG+Wg05T5nfBDEn7F8G
# bEicocwsy8xwxYBXQMVlXMyHFJkZmSPhXn79YPVwyOwMHh1joTzwlUzn
# SIG # End signature block