PsDaVinci.psm1

# Copyright (c) STÜBER SYSTEMS GmbH. All rights reserved.
# Licensed under the MIT License.

Import-LocalizedData -BindingVariable stringTable

<#
 .Synopsis
  Creates a new JSON configuration template for the 'Start-DaVinciImport' cmdlet
 
 .Description
  This cmdlet will create a new JSON configuration file for an import source. If the JSON
  file exists already it will add the configuration to the file. You must adapt the
  configuration to your needs by opening the configuration file in a text editor.
 
 .Parameter Source
  The name of a supported import source. Currently supported is 'ecf'.
 
 .Parameter ConfigFile
  The file name of the JSON configuration file. If this file exists already this cmdlet
  will terminate with an error.
 
 .Example
  # Adds a configuration template for an ECF to DAVINCI import
  Initialize-DaVinciImport -Source ecf -ConfigFile MyImportConfig.json
 
 .Example
  # Adds a configuration template for an ECF to DAVINCI import (short form)
  Initialize-DaVinciImport ecf MyImportConfig.json
#>

function Initialize-DaVinciImport {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ImportSource]
        $Source,
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ConfigFile
    )
    process
    {
        try
        {
            $ConfigPath = GetFullConfigPath -ConfigFile $ConfigFile

            switch ($Source)
            {
                ([ImportSource]::ecf)   { CreateOrPopulateConfigFile -JsonProviderName "daVinci" -JsonConfigName "EcfImport" -ConfigTemplateName "import" -ConfigPath $ConfigPath }
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Error $ErrorMessage
        }
    }
}

<#
 .Synopsis
  Creates a new JSON configuration template for the 'Start-DaVinciExport' cmdlet
 
 .Description
  This cmdlet will create a new JSON configuration file for an export target. If the JSON
  file exists already it will add the configuration to the file. You must adapt the
  configuration to your needs by opening the configuration file in a text editor.
   
 .Parameter Target
  The name of a supported export target. Currently supported are 'sdui', 'iserv'
  and 'ecf'.
 
 .Parameter ConfigFile
  The file name of the JSON configuration file. If this file exists already this cmdlet
  will terminate with an error.
 
 .Example
  # Adds a configuration template for a DAVINCI to ECF export
  Initialize-DaVinciExport -Target ecf -ConfigFile MyExportConfig.json
 
 .Example
  # Adds a configuration template for a DAVINCI to ECF export (short from)
  Initialize-DaVinciExport ecf MyExportConfig.json
#>

function Initialize-DaVinciExport {
   param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ExportTarget]
        $Target,
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ConfigFile
    )
    process
    {
        try
        {
            $ConfigPath = GetFullConfigPath -ConfigFile $ConfigFile

            switch ($Target)
            {
                ([ExportTarget]::sdui)  { CreateOrPopulateConfigFile -JsonProviderName "daVinci" -JsonConfigName "SduiExport" -ConfigTemplateName "export" -ConfigPath $ConfigPath }
                ([ExportTarget]::iserv) { CreateOrPopulateConfigFile -JsonProviderName "daVinci" -JsonConfigName "IServExport" -ConfigTemplateName "export" -ConfigPath $ConfigPath }
                ([ExportTarget]::ecf)   { CreateOrPopulateConfigFile -JsonProviderName "daVinci" -JsonConfigName "EcfExport" -ConfigTemplateName "export" -ConfigPath $ConfigPath }
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Error $ErrorMessage
        }
    }
}

<#
 .Synopsis
  Starts a new import from a supported source to DAVINCI.
 
 .Description
  This cmdlet will start a new import from a supported source to DAVINCI.
 
 .Parameter Source
  The name of a supported import source. Currently supported is 'ecf'.
 
 .Parameter ConfigFile
  The file name of the JSON configuration file.
 
 .Example
  # Starts an import from ECF to DAVINCI
  Start-DaVinciImport -Source ecf -ConfigFile MyImportConfig.json
 
 .Example
  # Starts an import from ECF to DAVINCI (short form)
  Start-DaVinciImport ecf MyImportConfig.json
#>

function Start-DaVinciImport {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ImportSource]
        $Source,
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ConfigFile )
    process
    {
        try
        {
            $ConfigPath = GetFullConfigPath -ConfigFile $ConfigFile
            $Config = GetConfig -Config $ConfigPath
        
            switch ($Source)
            {
                ([ImportSource]::ecf) { RunDavConsole -Command "export" -Provider "ecf" -Config $Config }
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Error $ErrorMessage
        }
    }
}

<#
 .Synopsis
  Starts a new export from DAVINCI to a supported target.
 
 .Description
  This cmdlet will start a new export from DAVINCI to a supported target.
 
 .Parameter Target
  The name of a supported export target. Currently supported are 'sdui', 'iserv'
  and 'ecf'.
 
 .Parameter ConfigFile
  The file name of the JSON configuration file.
 
 .Example
  # Starts an export from DAVINCI to Ecf
  Start-DaVinciExport -Target ecf -ConfigFile MyExportConfig.json
 
 .Example
  # Starts an export from DAVINCI to Ecf (short form)
  Start-DaVinciExport ecf MyExportConfig.json
#>

function Start-DaVinciExport {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ExportTarget]
        $Target,
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ConfigFile
    )
    process
    {
        try
        {
            $ConfigPath = GetFullConfigPath -ConfigFile $ConfigFile
            $Config = GetConfig -Config $ConfigPath

            switch ($Target)
            {
                ([ExportTarget]::sdui)  { RunDavConsole -Command "export" -Provider "sdui" -Config $Config }
                ([ExportTarget]::iserv) { RunDavConsole -Command "export" -Provider "iserv" -Config $Config }
                ([ExportTarget]::ecf)   { RunDavConsole -Command "export" -Provider "ecf" -Config $Config }
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Error $ErrorMessage
        }
    }
}

function CreateOrPopulateConfigFile {
    param(
        [string]
        $ConfigPath,
        [string]
        $ConfigTemplateName,
        [string]
        $JsonProviderName,
        [string]
        $JsonConfigName
    )
    process
    {
        $ConfigTemplatePath = GetConfigTemplatePath -TemplateName $ConfigTemplateName
        $ConfigTemplate = Get-Content -Raw -Path $ConfigTemplatePath | ConvertFrom-Json

        foreach ($property in $ConfigTemplate.daVinci.PSObject.Properties)
        {
            if ($property.Name -ne $JsonConfigName)
            {
                $ConfigTemplate.daVinci.PSObject.Properties.Remove($property.Name)
            }
        }

        if (Test-Path -Path $ConfigPath)
        {
            $Config = Get-Content -Raw -Path $ConfigPath | ConvertFrom-Json
            
            if ($Config | Get-Member -Name $JsonProviderName -MemberType NoteProperty)
            {
                if ($null -ne $Config.daVinci)
                {
                    if (-not ($Config.daVinci | Get-Member -Name $JsonConfigName -MemberType NoteProperty))
                    {
                        $ConfigPropertyValue = $ConfigTemplate.daVinci | Select-Object -ExpandProperty $JsonConfigName
                        $Config.daVinci | Add-Member -MemberType NoteProperty -Name $JsonConfigName -Value $ConfigPropertyValue
                    }
                }
            }
            else
            {
                $Config | Add-Member -MemberType NoteProperty -Name $JsonProviderName -Value $ConfigTemplate.daVinci
            }
        }
        else 
        {
            $Config = $ConfigTemplate
        }

        $Config | ConvertTo-Json -depth 100 | Set-Content $ConfigPath
    }
}

function RunDavConsole{
    param(
        [string]
        $Command,
        [string]
        $Provider,
        [PSObject]
        $Config
    )
    process
    {
        Write-Host $stringTable.StartDaVinciConsole -ForegroundColor $Host.PrivateData.VerboseForegroundColor

        $ConsolePath = GetDavConsolePath -Config $Config

        if (($ConsolePath) -and (Test-Path -Path $ConsolePath -PathType Leaf))
        {
            $CurrentLocation = Get-Location
            Set-Location -Path (Split-Path -Path $ConfigPath)
            try
            {   
                Invoke-Expression "& ""$($consolePath)"" $($Command) -p ""$($Provider)"" -c ""$($ConfigPath)"""
            }
            finally 
            {
                Set-Location -Path $CurrentLocation
            }

            if ($LASTEXITCODE -ne 0)
            {
                $ErrorMessage = $stringTable.ErrorDaVinciConsoleFailed
                throw $ErrorMessage
            }
        }
        else
        {
            $ErrorMessage = ([string]::Format($stringTable.ErrorDaVinciConsoleNotFound, $ConsolePath)) 
            throw $ErrorMessage
        }
    }
}

function GetConfig {
    param(
        [string]
        $ConfigPath
    )
    process
    {
        if (($ConfigPath) -and (Test-Path -Path $ConfigPath -PathType leaf))
        {
            return Get-Content -Path $ConfigPath -Raw | ConvertFrom-Json
        }
        else
        {
            return "{}" | ConvertFrom-Json
        }
    }
}

function GetConfigTemplatePath {
    param(
        [string]
        $TemplateName
    )
    process
    {
        return Join-Path -Path $PSScriptRoot -ChildPath "PsDaVinci.Template.$($TemplateName).json"
    }
}

function GetFullConfigPath {
    param(
        [string]
        $ConfigFile
    )
    process
    {
        $ConfigPath = $ConfigFile
        
        if ((Split-Path -Path $ConfigPath -Leaf) -eq $ConfigPath)
        {
            $ConfigPath = Join-Path -Path (Get-Location) -ChildPath $ConfigPath
        }

        if (-not (Test-Path -Path $ConfigPath -PathType Leaf))
        {
            if (-not ([IO.Path]::HasExtension($ConfigPath)))
            {
                $ConfigPath = [IO.Path]::ChangeExtension($ConfigPath, "json")
            }
        }

        return $ConfigPath
    }
}

function GetDavConsolePath {
    param(
        [PSObject]
        $Config
    )
    process
    {
        if ($Config)
        {
            if ($Config.PsDaVinci.Tools.DaVinciConsole)
            {
                return $config.PsDaVinci.Tools.DaVinciConsole
            }
        }
        
        $RegKey64 = "HKLM:\SOFTWARE\WOW6432Node\Stueber Systems\daVinci 6\Main"
        $RegKey32 = "HKLM:\SOFTWARE\Stueber Systems\daVinci 6\Main"

        if ([Environment]::Is64BitProcess)
        {
            if (Test-Path -Path $RegKey64)
            {
                $RegKey = Get-ItemProperty -Path $RegKey64 -Name BinFolder
                return Join-Path -Path $RegKey.BinFolder -ChildPath "daVinciConsole.exe"
            }
            else
            {
                return $null
            }
        }
        else
        {
            if (Test-Path -Path $RegKey32)
            {
                $RegKey = Get-ItemProperty -Path $RegKey32 -Name BinFolder
                return Join-Path -Path $RegKey.BinFolder -ChildPath "daVinciConsole.exe"
            }
            else
            {
                return $null
            }
        }
    
    }
}

# List of supported import sources
Enum ImportSource {
    ecf
}

# List of supported export targets
Enum ExportTarget {
    sdui
    iserv
    ecf
}

Export-ModuleMember -Function Initialize-DaVinciImport
Export-ModuleMember -Function Initialize-DaVinciExport
Export-ModuleMember -Function Start-DaVinciImport
Export-ModuleMember -Function Start-DaVinciExport

# SIG # Begin signature block
# MIIZbAYJKoZIhvcNAQcCoIIZXTCCGVkCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUWNp1xWtFSk3662NiZC1rSm+m
# vymgghRtMIIE1TCCA72gAwIBAgIQLv6kF6bmtV9boNbBVSrC5TANBgkqhkiG9w0B
# AQsFADB/MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRp
# b24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxMDAuBgNVBAMTJ1N5
# bWFudGVjIENsYXNzIDMgU0hBMjU2IENvZGUgU2lnbmluZyBDQTAeFw0xOTA4MDYw
# MDAwMDBaFw0yMTEwMTUyMzU5NTlaMG0xCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZC
# ZXJsaW4xDzANBgNVBAcMBkJlcmxpbjEdMBsGA1UECgwUU1RVRUJFUiBTWVNURU1T
# IEdtYkgxHTAbBgNVBAMMFFNUVUVCRVIgU1lTVEVNUyBHbWJIMIIBIjANBgkqhkiG
# 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaRIVaSkAMSQj+/zPkMRDRo7TwC80M3tt/nX
# uuPnfQNEilBRgRUj5lJ6AAxam4ayXCf38v371FOQ/IJpFSEU++H+LhCIpiCrjlY2
# m36N34SLUqgxjuFjBPj3gDUN8tATX3Svg0VGe8giXXo2aUYpPESSPfWblr3wmDU4
# eQ/Y6G6QqCAd3O9cqJo5Asp4x04mbo15nkaV0hyD0Bch/I5d6Wgirkirr5K/sC4q
# ZQPH5BDnQ4p3JlnOqL76sCqjgiToMn7KRMNblYcqAbRvDjTucq4dwGbthOEfWjGQ
# qJcgr8hbZgXxHKhoQwDjuB4KStbsAELIE0Ul2cYkXH93e/PzIQIDAQABo4IBXTCC
# AVkwCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCB4AwKwYDVR0fBCQwIjAgoB6gHIYa
# aHR0cDovL3N2LnN5bWNiLmNvbS9zdi5jcmwwYQYDVR0gBFowWDBWBgZngQwBBAEw
# TDAjBggrBgEFBQcCARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUH
# AgIwGQwXaHR0cHM6Ly9kLnN5bWNiLmNvbS9ycGEwEwYDVR0lBAwwCgYIKwYBBQUH
# AwMwVwYIKwYBBQUHAQEESzBJMB8GCCsGAQUFBzABhhNodHRwOi8vc3Yuc3ltY2Qu
# Y29tMCYGCCsGAQUFBzAChhpodHRwOi8vc3Yuc3ltY2IuY29tL3N2LmNydDAfBgNV
# HSMEGDAWgBSWO1PweTOXr32D7y4rzMq3hh5yZjAdBgNVHQ4EFgQUYz6hg49VBlOi
# YvOJKjgcMVfwTbkwDQYJKoZIhvcNAQELBQADggEBAJN+Vhe4Abpf8Wh//vApKk1o
# BxJP5cp92phKg9lYyVpxf2aw1oiEp7X9z1Ihgdc6zkR2pP8fYrFU/fYu0aXapGMR
# qf/3RwjYuBKGxB5U0jGAxHMtV+owcchQZcd12Td7BTwm0o848i0zGZu6+48bIfeZ
# Ot+qoxldwQQrYQyn1+4PE7IfP03KkCX7+wJ4aOyWXvN8wUINvSswuecnVFi/MKSS
# fhE4OydQcY93fYIhLGimh3TAVdTTfWN8OSfy+TOVAvC4FoHBM54sWzfU1Nr35EK+
# RuJbgcNIFaRBC2MkBH42Nh5g7PQDUo8aXMP9s00sY1oSOmhbXLbkQNxjMI8MDPsw
# ggT+MIID5qADAgECAhANQkrgvjqI/2BAIc4UAPDdMA0GCSqGSIb3DQEBCwUAMHIx
# CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
# dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJ
# RCBUaW1lc3RhbXBpbmcgQ0EwHhcNMjEwMTAxMDAwMDAwWhcNMzEwMTA2MDAwMDAw
# WjBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xIDAeBgNV
# BAMTF0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOC
# AQ8AMIIBCgKCAQEAwuZhhGfFivUNCKRFymNrUdc6EUK9CnV1TZS0DFC1JhD+Hchv
# kWsMlucaXEjvROW/m2HNFZFiWrj/ZwucY/02aoH6KfjdK3CF3gIY83htvH35x20J
# Pb5qdofpir34hF0edsnkxnZ2OlPR0dNaNo/Go+EvGzq3YdZz7E5tM4p8XUUtS7FQ
# 5kE6N1aG3JMjjfdQJehk5t3Tjy9XtYcg6w6OLNUj2vRNeEbjA4MxKUpcDDGKSoyI
# xfcwWvkUrxVfbENJCf0mI1P2jWPoGqtbsR0wwptpgrTb/FZUvB+hh6u+elsKIC9L
# CcmVp42y+tZji06lchzun3oBc/gZ1v4NSYS9AQIDAQABo4IBuDCCAbQwDgYDVR0P
# AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgw
# QQYDVR0gBDowODA2BglghkgBhv1sBwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3
# dy5kaWdpY2VydC5jb20vQ1BTMB8GA1UdIwQYMBaAFPS24SAd/imu0uRhpbKiJbLI
# FzVuMB0GA1UdDgQWBBQ2RIaOpLqwZr68KC0dRDbd42p6vDBxBgNVHR8EajBoMDKg
# MKAuhixodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNy
# bDAyoDCgLoYsaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10
# cy5jcmwwgYUGCCsGAQUFBwEBBHkwdzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
# ZGlnaWNlcnQuY29tME8GCCsGAQUFBzAChkNodHRwOi8vY2FjZXJ0cy5kaWdpY2Vy
# dC5jb20vRGlnaUNlcnRTSEEyQXNzdXJlZElEVGltZXN0YW1waW5nQ0EuY3J0MA0G
# CSqGSIb3DQEBCwUAA4IBAQBIHNy16ZojvOca5yAOjmdG/UJyUXQKI0ejq5LSJcRw
# Wb4UoOUngaVNFBUZB3nw0QTDhtk7vf5EAmZN7WmkD/a4cM9i6PVRSnh5Nnont/Pn
# Up+Tp+1DnnvntN1BIon7h6JGA0789P63ZHdjXyNSaYOC+hpT7ZDMjaEXcw3082U5
# cEvznNZ6e9oMvD0y0BvL9WH8dQgAdryBDvjA4VzPxBFy5xtkSdgimnUVQvUtMjiB
# 2vRgorq0Uvtc4GEkJU+y38kpqHNDUdq9Y9YfW5v3LhtPEx33Sg1xfpe39D+E68Hj
# o0mh+s6nv1bPull2YYlffqe0jmd4+TaY4cso2luHpoovMIIFMTCCBBmgAwIBAgIQ
# CqEl1tYyG35B5AXaNpfCFTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEV
# MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t
# MSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTYwMTA3
# MTIwMDAwWhcNMzEwMTA3MTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM
# RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD
# EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBMIIBIjAN
# BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvdAy7kvNj3/dqbqCmcU5VChXtiNK
# xA4HRTNREH3Q+X1NaH7ntqD0jbOI5Je/YyGQmL8TvFfTw+F+CNZqFAA49y4eO+7M
# pvYyWf5fZT/gm+vjRkcGGlV+Cyd+wKL1oODeIj8O/36V+/OjuiI+GKwR5PCZA207
# hXwJ0+5dyJoLVOOoCXFr4M8iEA91z3FyTgqt30A6XLdR4aF5FMZNJCMwXbzsPGBq
# rC8HzP3w6kfZiFBe/WZuVmEnKYmEUeaC50ZQ/ZQqLKfkdT66mA+Ef58xFNat1fJk
# y3seBdCEGXIX8RcG7z3N1k3vBkL9olMqT4UdxB08r8/arBD13ays6Vb/kwIDAQAB
# o4IBzjCCAcowHQYDVR0OBBYEFPS24SAd/imu0uRhpbKiJbLIFzVuMB8GA1UdIwQY
# MBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD
# VR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHkGCCsGAQUFBwEBBG0w
# azAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUF
# BzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVk
# SURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRw
# Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3Js
# MFAGA1UdIARJMEcwOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczov
# L3d3dy5kaWdpY2VydC5jb20vQ1BTMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsF
# AAOCAQEAcZUS6VGHVmnN793afKpjerN4zwY3QITvS4S/ys8DAv3Fp8MOIEIsr3fz
# Kx8MIVoqtwU0HWqumfgnoma/Capg33akOpMP+LLR2HwZYuhegiUexLoceywh4tZb
# LBQ1QwRostt1AuByx5jWPGTlH0gQGF+JOGFNYkYkh2OMkVIsrymJ5Xgf1gsUpYDX
# Ekdws3XVk4WTfraSZ/tTYYmo9WuWwPRYaQ18yAGxuSh1t5ljhSKMYcp5lH5Z/IwP
# 42+1ASa2bKXuh1Eh5Fhgm7oMLSttosR+u8QlK0cCCHxJrhO24XxCQijGGFbPQTS2
# Zl22dHv1VjMiLyI2skuiSpXY9aaOUjCCBVkwggRBoAMCAQICED141/l2SWCyYX30
# 8B7KhiowDQYJKoZIhvcNAQELBQAwgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5W
# ZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6
# MDgGA1UECxMxKGMpIDIwMDYgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXpl
# ZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMyBQdWJsaWMgUHJp
# bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc1MB4XDTEzMTIxMDAwMDAw
# MFoXDTIzMTIwOTIzNTk1OVowfzELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFu
# dGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3Jr
# MTAwLgYDVQQDEydTeW1hbnRlYyBDbGFzcyAzIFNIQTI1NiBDb2RlIFNpZ25pbmcg
# Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCXgx4AFq8ssdIIxNdo
# k1FgHnH24ke021hNI2JqtL9aG1H3ow0Yd2i72DarLyFQ2p7z518nTgvCl8gJcJOp
# 2lwNTqQNkaC07BTOkXJULs6j20TpUhs/QTzKSuSqwOg5q1PMIdDMz3+b5sLMWGqC
# Fe49Ns8cxZcHJI7xe74xLT1u3LWZQp9LYZVfHHDuF33bi+VhiXjHaBuvEXgamK7E
# VUdT2bMy1qEORkDFl5KK0VOnmVuFNVfT6pNiYSAKxzB3JBFNYoO2untogjHuZcrf
# +dWNsjXcjCtvanJcYISc8gyUXsBWUgBIzNP4pX3eL9cT5DiohNVGuBOGwhud6lo4
# 3ZvbAgMBAAGjggGDMIIBfzAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0
# dHA6Ly9zMi5zeW1jYi5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADBsBgNVHSAEZTBj
# MGEGC2CGSAGG+EUBBxcDMFIwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuc3ltYXV0
# aC5jb20vY3BzMCgGCCsGAQUFBwICMBwaGmh0dHA6Ly93d3cuc3ltYXV0aC5jb20v
# cnBhMDAGA1UdHwQpMCcwJaAjoCGGH2h0dHA6Ly9zMS5zeW1jYi5jb20vcGNhMy1n
# NS5jcmwwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMDMA4GA1UdDwEB/wQE
# AwIBBjApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRU3ltYW50ZWNQS0ktMS01Njcw
# HQYDVR0OBBYEFJY7U/B5M5evfYPvLivMyreGHnJmMB8GA1UdIwQYMBaAFH/TZafC
# 3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3DQEBCwUAA4IBAQAThRoeaak396C9pK9+
# HWFT/p2MXgymdR54FyPd/ewaA1U5+3GVx2Vap44w0kRaYdtwb9ohBcIuc7pJ8dGT
# /l3JzV4D4ImeP3Qe1/c4i6nWz7s1LzNYqJJW0chNO4LmeYQW/CiwsUfzHaI+7ofZ
# pn+kVqU/rYQuKd58vKiqoz0EAeq6k6IOUCIpF0yH5DoRX9akJYmbBWsvtMkBTCd7
# C6wZBSKgYBU/2sn7TUyP+3Jnd/0nlMe6NQ6ISf6N/SivShK9DbOXBd5EDBX6NisD
# 3MFQAfGhEV0U5eK9J0tUviuEXg+mw3QFCu+Xw4kisR93873NQ9TxTKk/tYuEr2Ty
# 0BQhMYIEaTCCBGUCAQEwgZMwfzELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFu
# dGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3Jr
# MTAwLgYDVQQDEydTeW1hbnRlYyBDbGFzcyAzIFNIQTI1NiBDb2RlIFNpZ25pbmcg
# Q0ECEC7+pBem5rVfW6DWwVUqwuUwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwx
# CjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGC
# NwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFCTU4An38FFz34Qf
# oTGgMIfSKnAAMA0GCSqGSIb3DQEBAQUABIIBACXObqgXuVMiYnU6vQWDVXst2ctO
# augKsiJ8s5dQN0c0p231f0MfeV3QlA1dyPeWGm3AtT44WRRdngx9Mp86p/XCrKr7
# pQ0L9WBHC+FN1mDJLJ5n12/YWyGsSdQh3asH7kr++b15HFEFcvbbdQBXxNyvh7r3
# BILUFNbbagu/kyU0rrvcF0PV5juwDGOTSntAMIpxhrHX0zIQoIyojYosxSu/XgaX
# q9hU9CCO/ZyQ4/GgHR8JHErBSWfyJu/bngvUH73APEPoksDY29ttt7rO7iBaUL4H
# sl5vt9dwyO6X9HZIAMYSnCcWOkHxwkrWMjQddIrg62enT/pt4nlUB96a9dahggIw
# MIICLAYJKoZIhvcNAQkGMYICHTCCAhkCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTAT
# BgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEx
# MC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBD
# QQIQDUJK4L46iP9gQCHOFADw3TANBglghkgBZQMEAgEFAKBpMBgGCSqGSIb3DQEJ
# AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIxMDQyMDExMzIzM1owLwYJ
# KoZIhvcNAQkEMSIEIDItOFxB+4JlE5as8mbaNG4KPsWIkzm2zY797ka7gcO5MA0G
# CSqGSIb3DQEBAQUABIIBAADJBcGyLmanl3cxv5IabD36OZlLgPWoxcaqmc2jfnyg
# +VkL4IV3ltSLZl2zjZhvNw+QSBJ93JfuQPs7IoD5n2xKZWqyjK0TOG8R4Z2/du+q
# mg1iLJxHSVZU5zW0jAE8/eToQX14emmzxAsWG9n24eGOZTkdSOqVOrjItWKrCtc6
# oIRrvqHU+ppba6XIGwbMOJenT9HLwOA7Zm8l3diRvMs60Wk+WU5GrRpM/dDahUlH
# 7WhHPd2KpVhiXH80VQ6LkuGKRrSJlgWLcz8Zb2ZrASTokrUFAQoojabcbPjeThZi
# kGOuS4Yibk80lX8tu0/KPTU205ico74JR75hD0ruHiY=
# SIG # End signature block