CTToolkit.psm1

Class CTReturnObject {
    [String] $Status
    [String] $ErrorMessage
    [System.Exception] $Exception
    [System.Collections.ArrayList] $Tracelog
    [System.Collections.ArrayList] $Input = ([Hashtable] $PSBoundParameters)
    [System.Collections.ArrayList] $Output = @()
}

#Not in use, because of issue with $PSBoundparameters as default value
Function Get-CTReturnObject {
    param(
        [String] $Status = "Unknown",
        [String] $ErrorMessage,
        [System.Collections.ArrayList] $Tracelog = $Script:Tracelog,
        [Hashtable] $InputParameters = ([Hashtable] $PSBoundParameters),
        [System.Collections.ArrayList] $Output = [System.Collections.ArrayList] @()
    )
    return [CTReturnObject] @{
        Status       = $Status
        ErrorMessage = $ErrorMessage
        Tracelog     = $Tracelog
        Input        = $InputParameters
        Output       = $Output
    }
}
Function Get-TraceLogMessage {
    <#
    .Synopsis
    Generates shorter strings from a long string.
    .DESCRIPTION
    Used to limit a tracelog file and split into multiple pieces, for use with a limited field, such as windows event log.
    #>

    param($RunbookName, $Message, $maxLength)
    $Message += "Runbook Name: $RunbookName`n"
    $Message += "Runas domain: $($env:userdomain)`n"
    #add last part of tracelog.
    $Message += "Last part of Trace Log:`n"

    # $maxLength = 30000
    $NumberOfMessages = [Math]::Ceiling(($Script:Tracelog.Length / $maxLength))

    For ($i = 0; $i -lt $NumberOfMessages; $i++) {
        $start = (0 + ($maxLength * $i))
        $end = $maxLength

        if ($end -gt $Script:Tracelog.Length - $start) { $end = $Script:Tracelog.Length - $start }


        $Message = $Script:Tracelog.Substring($start, $end)

        if ($Message.Length -eq $maxLength) {
            $Message = $Message + "`ncontinued.."
        }

        $Message 
    }
}
Function Write-EventLogTraceLog {
    <#
    .Synopsis
    Splits tracelog into multiple strings and then writes them to the windows event log
    .DESCRIPTION
    uses the Get-TraceLogMessages function to split the tracelog and write it to event log.
    #>

    param($LogName, $SourceName, $RunbookName, $EntryType, $EventId, $Message)
        
    $Messages = Get-TraceLogMessage -RunbookName $RunbookName -Message $Message -maxLength 30000

    #write event log
    if (!([System.Diagnostics.EventLog]::SourceExists($SourceName))) {
        New-EventLog -LogName $LogName -Source $SourceName
    }

    foreach ($message in $messages) {
        Write-EventLog -LogName $LogName -Source $SourceName -EntryType $EntryType -EventId $EventId -Message $Message
    }
}
Function Add-Tracelog {
    <#
    .Synopsis
    Adds a tracelog message to tracelog
    .DESCRIPTION
    Uses a script scope tracelog variable to have alle scopes write to a sinlg etracelog.
    Outputs each message to the Verbose stream.
    #>

    param($Message)

    if ([String]::IsNullOrEmpty($script:Tracelog)) {
        $script:TraceLogId = 0
        [System.Collections.ArrayList] $script:Tracelog = @()
    }

    $Message = "{0}: {1:yyyy-MM-dd HH:mm:ss.fff}: {2}`n" -f $script:TraceLogId,(get-date),$Message
    
    $script:TraceLogId++
    #$Message = "$(get-date) - $Message`n"
    Write-Verbose $Message
    
    $script:Tracelog.Add($Message.ToString())
}

Function Get-TraceLog {
    [System.Collections.ArrayList] $script:TraceLog
}
Function Write-TextLog {
    <#
    .Synopsis
    Writes the tracelog to a text file.
    .DESCRIPTION
    Writes the tracelog to a text file.
    If the text file looks "weird" in notepad, it is becausenotepad cannot alway list the line breaks correctly.
    Use another editor to view the log.
    #>

    param($Message, $LogFolderPath, $LogName, $StartTime)    
    #Write to file
    $Message + "`n" + ($script:TraceLog -join "`n") | Out-file $LogFolderPath\$($LogName)_$($StartTime.ToString("yyyyMMddhhmmss")).log -Encoding ASCII
}
Function ConvertTo-IndexedTable {
    <#
    .Synopsis
    Converts an array of objects to a array of hashtables for performance
    .DESCRIPTION
    Converts an array of objects to a hashtable of hashtables for performance
    The hashtable has takes one field as index, for example name
    and the index field can be used to filter/sort much quicker than and array of objects.
    (see example for details)
    .Example
    Get-CMDevice -CollectionName "All Systems" -Fast | ConvertTo-IndexedTable Name
 
    Name Value
    ---- -----
    Object ...
    Name NCOP-CCMP-CCM01
 
    the index field is available directly, while the complete object is available in the object key of the hash table.
    #>

    param(
        [Parameter(Mandatory = $true,
            ValueFromPipelineByPropertyName = $false,
            Position = 0)]
        $IndexFieldName,
        [Parameter(Mandatory = $true,
            ValueFromPipelineByPropertyName = $true,
            ValueFromPipeline = $true,
            Position = 1)]
        [Object]$Object
    )

    #begin { $ReturnArray = @() } #New-Object System.Collections.ArrayList }
    process {
        @{ 
            $IndexFieldName = $Object.$IndexFieldName
            Object          = $Object
        }
    }
    #end { $ReturnArray }
}
Function Clear-Tracelog {
    <#
    .Synopsis
    Clears the tracelog
    .DESCRIPTION
    Clears the tracelog
    #>


    $script:Tracelog = [System.Collections.ArrayList]  @()

}

Function Write-CTError {
    param($PSError,$returnObject)
    #get error messa
    $CurrentError = $PSError
    $ErrorMessage = $CurrentError.Exception.Message + "`n $($CurrentError.InvocationInfo.PositionMessage)"
    Add-Tracelog -Message "Error in control runbook: $ErrorMessage"
    Write-Error -Message $ErrorMessage #-ErrorAction Continue #output error without stopping, for logging purposes.
}
# SIG # Begin signature block
# MIIm+AYJKoZIhvcNAQcCoIIm6TCCJuUCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCnXPX4pa+w99wW
# gCnWiwLwSyVeCR3zdRizb6Qkpo87HqCCH+QwggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M
# UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv
# ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5
# NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp
# BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G
# CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI
# ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV
# DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3
# 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw
# mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm
# +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe
# dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4
# 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM
# dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY
# MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU
# pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV
# HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG
# A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1
# YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG
# AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl
# U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0
# aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh
# w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd
# OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj
# cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc
# WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO
# hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs
# zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7
# 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J
# KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH
# j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2
# Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/
# L9Uo2bC5a4CH2RwwggZmMIIEzqADAgECAhEA4ikD7Bz5tV4p2sDA6k14ITANBgkq
# hkiG9w0BAQwFADBUMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1p
# dGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgQ0EgUjM2
# MB4XDTIyMDQxMTAwMDAwMFoXDTI1MDQxMDIzNTk1OVowUTELMAkGA1UEBhMCREsx
# FDASBgNVBAgMC0hvdmVkc3RhZGVuMRUwEwYDVQQKDAxDVEdsb2JhbCBBL1MxFTAT
# BgNVBAMMDENUR2xvYmFsIEEvUzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
# ggIBALo7Bkeh1fssdIJNGZ28+cH/K4trX84QLalEvjcu4UPFxS+gUy2djPuXqh1+
# Nr/PYDG047ZI08uQVF1onebKftvZC3BiEq7EwPUU6GBndD3mt3Q7V9BQfEPsZs+q
# rgdCrWS4frWx3cCyAODqG3/b5omtwaPFdUX8ro2Rf4i8T8ddmAYfA4+qwpBvKP8A
# ThfaVIOBpRfY0gvdqyXu4os5BJEbAvPyWCKlRWPrXLwcGsyN7HVlD1YjCyf4Paan
# 5UMwHA44YclgPCmz6NThWUCH1b/LGzM7j0emCbq3jO7Z1UAnBkt7NrGfe7wjHIes
# aSdNlIWhsfqUCSfO1xut7zjS+8goSYg4I2oyzF+QKP6fVWRAQDlOHpeXV1vk68vI
# V9/UeUBJIyl0OQqaUKjk4kpwW9XHNWPz7VX32Q7Pm9GhCbwNvF7WgG22Jw2/IuF9
# JoVim8tLGVIQ2SKrJagsLrkEDyt7IOV7TKuljqIMfhe75WeAaAdfdZ0wCxcAXGis
# rXWhY2TCx2Jfux80dt+isPvzRQH7pKvRMRnJlIJoICCb/9HR8SRfYOaDAfC62Nsb
# J2C8JPgXxMaL+TDyz84i9mVv5DjX6s4tRNSGnHX+7FIMsXNm+bFAR3ZAUYNXUjAF
# /Qzm+xwgtVl5sGQqtv9bmDmOSya1TLvq8GTldmKqdijV1EdJAgMBAAGjggG0MIIB
# sDAfBgNVHSMEGDAWgBQPKssghyi47G9IritUpimqF6TNDDAdBgNVHQ4EFgQUjd9u
# TSXhujdMkYFBibuhgRy3Rn8wDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAw
# EwYDVR0lBAwwCgYIKwYBBQUHAwMwSgYDVR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIw
# JTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQB
# MEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGln
# b1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYuY3JsMHkGCCsGAQUFBwEBBG0wazBEBggr
# BgEFBQcwAoY4aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29k
# ZVNpZ25pbmdDQVIzNi5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3Rp
# Z28uY29tMCkGA1UdEQQiMCCBHml0YWRtaW5ka0BjdGdsb2JhbHNlcnZpY2VzLmNv
# bTANBgkqhkiG9w0BAQwFAAOCAYEAeiTTMB3+8pbkqdiQFE7CJxlDUx3Yp44RjMGN
# IocltTEccGHf4sMzuoLuP7MUT82snXD3avaGUsxXYeKZgxoGZbtwYf4eSBhdx23g
# aNGA5t5VBTHYzpic2z5hYISGbYZXZoYjcpPL1gcZeCfPj0Vl+6w2UQ5ocseDHyOF
# DtXlSTDxkyLY/eo+11u+01BM4KEH77LIWxnpOsm0nN4RJLkLzmckrrSSeFKOtCaP
# 8i69Fy942+jURbuK2fgDLY8Bre8KhpCdKm5DMv6Z3iLswMvpVG7e38UeuAXl7T8i
# JCMozgr8EYGFxcFzRzBEJrvk12neEojFi9J6TWh9UJDwFDgYfJhDm/Qy5XkIWnPM
# 3vyl47ULFQlw6O5bBKwHmgi5+GSgBQXef0K0fImA4XT1CB8Vm5FUWsP9ZV07lBUX
# Gs5onrau8ULB4JjEcB/+6BPrwBBoibYbZHAPIfqMZAhF117gH8eYrGbT0zdy9vUF
# jWayEi/2vZRQgwSdeSI+v5cCpvTsMIIG7DCCBNSgAwIBAgIQMA9vrN1mmHR8qUY2
# p3gtuTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5l
# dyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNF
# UlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
# dGlvbiBBdXRob3JpdHkwHhcNMTkwNTAyMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjB9
# MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
# VQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxJTAjBgNVBAMT
# HFNlY3RpZ28gUlNBIFRpbWUgU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQDIGwGv2Sx+iJl9AZg/IJC9nIAhVJO5z6A+U++zWsB21hoE
# pc5Hg7XrxMxJNMvzRWW5+adkFiYJ+9UyUnkuyWPCE5u2hj8BBZJmbyGr1XEQeYf0
# RirNxFrJ29ddSU1yVg/cyeNTmDoqHvzOWEnTv/M5u7mkI0Ks0BXDf56iXNc48Ray
# cNOjxN+zxXKsLgp3/A2UUrf8H5VzJD0BKLwPDU+zkQGObp0ndVXRFzs0IXuXAZSv
# f4DP0REKV4TJf1bgvUacgr6Unb+0ILBgfrhN9Q0/29DqhYyKVnHRLZRMyIw80xSi
# nL0m/9NTIMdgaZtYClT0Bef9Maz5yIUXx7gpGaQpL0bj3duRX58/Nj4OMGcrRrc1
# r5a+2kxgzKi7nw0U1BjEMJh0giHPYla1IXMSHv2qyghYh3ekFesZVf/QOVQtJu5F
# GjpvzdeE8NfwKMVPZIMC1Pvi3vG8Aij0bdonigbSlofe6GsO8Ft96XZpkyAcSpcs
# dxkrk5WYnJee647BeFbGRCXfBhKaBi2fA179g6JTZ8qx+o2hZMmIklnLqEbAyfKm
# /31X2xJ2+opBJNQb/HKlFKLUrUMcpEmLQTkUAx4p+hulIq6lw02C0I3aa7fb9xhA
# V3PwcaP7Sn1FNsH3jYL6uckNU4B9+rY5WDLvbxhQiddPnTO9GrWdod6VQXqngwID
# AQABo4IBWjCCAVYwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYD
# VR0OBBYEFBqh+GEZIA/DQXdFKI7RNV8GEgRVMA4GA1UdDwEB/wQEAwIBhjASBgNV
# HRMBAf8ECDAGAQH/AgEAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBEGA1UdIAQKMAgw
# BgYEVR0gADBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5j
# b20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYB
# BQUHAQEEajBoMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20v
# VVNFUlRydXN0UlNBQWRkVHJ1c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9v
# Y3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAG1UgaUzXRbhtVOB
# kXXfA3oyCy0lhBGysNsqfSoF9bw7J/RaoLlJWZApbGHLtVDb4n35nwDvQMOt0+Lk
# VvlYQc/xQuUQff+wdB+PxlwJ+TNe6qAcJlhc87QRD9XVw+K81Vh4v0h24URnbY+w
# QxAPjeT5OGK/EwHFhaNMxcyyUzCVpNb0llYIuM1cfwGWvnJSajtCN3wWeDmTk5Sb
# sdyybUFtZ83Jb5A9f0VywRsj1sJVhGbks8VmBvbz1kteraMrQoohkv6ob1olcGKB
# c2NeoLvY3NdK0z2vgwY4Eh0khy3k/ALWPncEvAQ2ted3y5wujSMYuaPCRx3wXdah
# c1cFaJqnyTdlHb7qvNhCg0MFpYumCf/RoZSmTqo9CfUFbLfSZFrYKiLCS53xOV5M
# 3kg9mzSWmglfjv33sVKRzj+J9hyhtal1H3G/W0NdZT1QgW6r8NDT/LKzH7aZlib0
# PHmLXGTMze4nmuWgwAxyh8FuTVrTHurwROYybxzrF06Uw3hlIDsPQaof6aFBnf6x
# uKBlKjTg3qj5PObBMLvAoGMs/FwWAKjQxH/qEZ0eBsambTJdtDgJK0kHqv3sMNrx
# py/Pt/360KOE2See+wFmd7lWEOEgbsausfm2usg1XTN2jvF8IAwqd661ogKGuinu
# tFoAsYyr4/kKyVRd1LlqdJ69SK6YMIIG9TCCBN2gAwIBAgIQOUwl4XygbSeoZeI7
# 2R0i1DANBgkqhkiG9w0BAQwFADB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
# YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0
# aWdvIExpbWl0ZWQxJTAjBgNVBAMTHFNlY3RpZ28gUlNBIFRpbWUgU3RhbXBpbmcg
# Q0EwHhcNMjMwNTAzMDAwMDAwWhcNMzQwODAyMjM1OTU5WjBqMQswCQYDVQQGEwJH
# QjETMBEGA1UECBMKTWFuY2hlc3RlcjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVk
# MSwwKgYDVQQDDCNTZWN0aWdvIFJTQSBUaW1lIFN0YW1waW5nIFNpZ25lciAjNDCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKSTKFJLzyeHdqQpHJk4wOcO
# 1NEc7GjLAWTkis13sHFlgryf/Iu7u5WY+yURjlqICWYRFFiyuiJb5vYy8V0twHqi
# DuDgVmTtoeWBIHIgZEFsx8MI+vN9Xe8hmsJ+1yzDuhGYHvzTIAhCs1+/f4hYMqsw
# s9iMepZKGRNcrPznq+kcFi6wsDiVSs+FUKtnAyWhuzjpD2+pWpqRKBM1uR/zPeEk
# yGuxmegN77tN5T2MVAOR0Pwtz1UzOHoJHAfRIuBjhqe+/dKDcxIUm5pMCUa9NLzh
# S1B7cuBb/Rm7HzxqGXtuuy1EKr48TMysigSTxleGoHM2K4GX+hubfoiH2FJ5if5u
# dzfXu1Cf+hglTxPyXnypsSBaKaujQod34PRMAkjdWKVTpqOg7RmWZRUpxe0zMCXm
# loOBmvZgZpBYB4DNQnWs+7SR0MXdAUBqtqgQ7vaNereeda/TpUsYoQyfV7BeJUeR
# dM11EtGcb+ReDZvsdSbu/tP1ki9ShejaRFEqoswAyodmQ6MbAO+itZadYq0nC/Ib
# SsnDlEI3iCCEqIeuw7ojcnv4VO/4ayewhfWnQ4XYKzl021p3AtGk+vXNnD3MH65R
# 0Hts2B0tEUJTcXTC5TWqLVIS2SXP8NPQkUMS1zJ9mGzjd0HI/x8kVO9urcY+VXvx
# XIc6ZPFgSwVP77kv7AkTAgMBAAGjggGCMIIBfjAfBgNVHSMEGDAWgBQaofhhGSAP
# w0F3RSiO0TVfBhIEVTAdBgNVHQ4EFgQUAw8xyJEqk71j89FdTaQ0D9KVARgwDgYD
# VR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUH
# AwgwSgYDVR0gBEMwQTA1BgwrBgEEAbIxAQIBAwgwJTAjBggrBgEFBQcCARYXaHR0
# cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQCMEQGA1UdHwQ9MDswOaA3oDWG
# M2h0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1JTQVRpbWVTdGFtcGluZ0NB
# LmNybDB0BggrBgEFBQcBAQRoMGYwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQuc2Vj
# dGlnby5jb20vU2VjdGlnb1JTQVRpbWVTdGFtcGluZ0NBLmNydDAjBggrBgEFBQcw
# AYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggIBAEyb
# ZVj64HnP7xXDMm3eM5Hrd1ji673LSjx13n6UbcMixwSV32VpYRMM9gye9YkgXsGH
# xwMkysel8Cbf+PgxZQ3g621RV6aMhFIIRhwqwt7y2opF87739i7Efu347Wi/elZI
# 6WHlmjl3vL66kWSIdf9dhRY0J9Ipy//tLdr/vpMM7G2iDczD8W69IZEaIwBSrZfU
# YngqhHmo1z2sIY9wwyR5OpfxDaOjW1PYqwC6WPs1gE9fKHFsGV7Cg3KQruDG2PKZ
# ++q0kmV8B3w1RB2tWBhrYvvebMQKqWzTIUZw3C+NdUwjwkHQepY7w0vdzZImdHZc
# N6CaJJ5OX07Tjw/lE09ZRGVLQ2TPSPhnZ7lNv8wNsTow0KE9SK16ZeTs3+AB8LMq
# SjmswaT5qX010DJAoLEZKhghssh9BXEaSyc2quCYHIN158d+S4RDzUP7kJd2KhKs
# QMFwW5kKQPqAbZRhe8huuchnZyRcUI0BIN4H9wHU+C4RzZ2D5fjKJRxEPSflsIZH
# KgsbhHZ9e2hPjbf3E7TtoC3ucw/ZELqdmSx813UfjxDElOZ+JOWVSoiMJ9aFZh35
# rmR2kehI/shVCu0pwx/eOKbAFPsyPfipg2I2yMO+AIccq/pKQhyJA9z1XHxw2V14
# Tu6fXiDmCWp8KwijSPUV/ARP380hHHrl9Y4a1LlAMYIGajCCBmYCAQEwaTBUMQsw
# CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDEyJT
# ZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgQ0EgUjM2AhEA4ikD7Bz5tV4p2sDA
# 6k14ITANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAA
# MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgor
# BgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCB1hiobMbzwB6HqPgZfvueHCfC2dl3L
# ZNCI8CN/V3erBzANBgkqhkiG9w0BAQEFAASCAgAsdp0iDSzTZphDFfbmI4McFZaX
# X/HGK/W42uHwCexw9F9wW2o8TtLhrbNk3XXrVUWVVjrgeMcBlXd33Iuf0lwmgRv7
# Z5yfYkCerr4Rn7fW+1ONBW3LfD4bNNiLG36rW4kiIpWDcR+nZZ2A+pXLLkr5JD3y
# C20KFYoI032AVPuxvM6rCHnZqDX6wysYWbjcMi1AqmHpNHeSLEeid/IgtRMkCSOt
# ROFMOAouPAi4xJHh9MMaQPSnaBUJEFnCy7hAcPxszWuiqn+e/RIUZqZanqGJRZ3T
# W+vKG5qY9+JTRnFepguy+xOa+SV3+P6H2faV0UPObY2Tkw4bvRQUQk52csGr2yye
# 8WdfwHYlxvSC9Cxx9pqj9FtQ5LcG2hw7F5TICVNxX9WYGbevmj8jh/tOJc0WnwX3
# dUvO/W9Ca6DmOWVqRl3YShG0bPSm2mDyMTCQW5lCCDrz5024L7ur5tuVYlZZVo10
# GTCA0JSpy+qK3BHu55Ud1JuRcLvIk6D/HYTg940XIAdLz3FRzVurhShpRItNxBHC
# qIAYPbeZ/nUrw6/zr144SCIWH4Cn+RmwSbsAQCa/TcE0zFvKLP4PdxRPy0/Keqf0
# bICFCtDdAFb5AwL34SGbALxBwt/1KiFir4KgNR0nJhK695ZAMal4frovlBhwPVWG
# APsa0xVEe0IK+46QdaGCA0swggNHBgkqhkiG9w0BCQYxggM4MIIDNAIBATCBkTB9
# MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
# VQQHEwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxJTAjBgNVBAMT
# HFNlY3RpZ28gUlNBIFRpbWUgU3RhbXBpbmcgQ0ECEDlMJeF8oG0nqGXiO9kdItQw
# DQYJYIZIAWUDBAICBQCgeTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqG
# SIb3DQEJBTEPFw0yMzEwMDMwODU3MTBaMD8GCSqGSIb3DQEJBDEyBDA6xiOD5dBJ
# A+rYNZ5ujNZ1rGsydnUSfCQHQ6ffrpMOV5HVvS7p7/QjWit8bEgUgNswDQYJKoZI
# hvcNAQEBBQAEggIATCUBihH6kAQqg+7uDheIJWIY6nR7mBqeudpnSJM4TwWTfSEB
# /Xsfuu3CTsrr4M/72FhnMUeVYk+yBc7zMHkrqwCQzKZttH04wEjDe0OaKxlmOoF0
# dq4I1oyV9hJY8PSNujyUiAXj1XsyqN9RenVarwpd741j63dJJ6+1292azIgvsfWB
# Wpf95UQemlfRL46YfJKu758CSh/8ByHSHoOK6PGgyuwrmrS/U5kLoQ26vDBC6ST5
# 3B9xod2/E6r+XaisC04ENlgyk4v75LWwt6lXafUsReZdUp7kdY9F5rc2l8wwWUTM
# LjfsUkUkuxmmGaKEydhiSfQB9h5a2NoJdd92raEmNxrpczLapdINJ1SPPU+AXGwf
# dPSolLxCpd74mDs3YhcuIljZolXmhsUnORY7msaqowSGKU1/fDYUpbdd3Rwcaptc
# /WHEUZLDsvRX/zDDZgrgOhByecTeWBLaEJ3huZUzaf54tOmo2uJ4BsH7tQCgBXuY
# V4gfIirloahDO4XR+21EgQYnOC5GvfRYDrGgV7EZsjpfmWBU2vTji+OwZAR9d1h1
# zYVqh9S22d2JM9qLtEZJ3El6WKuKUHTwqlyxlqUJuP9OZNe1K9HIek10vYTarZ1d
# oF7nt2yRBQf7yah+5+cKcjjcxeegHOd28a0CDhpltpcymq+aG1a9hvFjZ0s=
# SIG # End signature block