PsEnbrea.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-EnbreaImport' cmdlet
 
 .Description
  This cmdlet will copy a template josn file to the target destination. You must adapt
  the configuration to your needs by opening the configuration file in a text editor.
   
 .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 ENBREA imports
  Initialize-EnbreaImport -ConfigFile MyImportConfig.json
 
 .Example
  # Adds a configuration template for ENBREA imports (short form)
  Initialize-EnbreaImport MyImportConfig.json
#>

function Initialize-EnbreaImport {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ConfigFile
    )
    process
    {
        try
        {
            $ConfigPath = GetFullConfigPath -ConfigFile $ConfigFile
            $ConfigTemplatePath = GetConfigTemplatePath -TemplateName "Import"

            if (-not (Test-Path -Path $ConfigPath))
            {
                Copy-Item $ConfigTemplatePath -Destination $ConfigPath
            }
            else 
            {
                throw ([string]::Format($stringTable.ErrorFileExists, $ConfigPath))
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Error $ErrorMessage
        }
    }
}

<#
 .Synopsis
  Creates a new JSON configuration template for the 'Start-EnbreaExport' cmdlet
 
 .Description
  This cmdlet will copy a template josn file to the target destination. You must adapt
  the configuration to your needs by opening the configuration file in a text editor.
   
 .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 ENBREA exports
  Initialize-EnbreaExport -ConfigFile MyExportConfig.json
 
 .Example
  # Adds a configuration template for ENBREA exports (short from)
  Initialize-EnbreaExport MyExportConfig.json
#>

function Initialize-EnbreaExport {
   param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ConfigFile
    )
    process
    {
        try
        {
            $ConfigPath = GetFullConfigPath -ConfigFile $ConfigFile
            $ConfigTemplatePath = GetConfigTemplatePath -TemplateName "Export"

            if (-not (Test-Path -Path $ConfigPath))
            {
                Copy-Item $ConfigTemplatePath -Destination $ConfigPath
            }
            else 
            {
                throw ([string]::Format($stringTable.ErrorFileExists, $ConfigPath))
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Error $ErrorMessage
        }
    }
}

<#
 .Synopsis
  Starts a new import from a supported source to ENBREA.
 
 .Description
  This cmdlet will start a new import from a supported source to ENBREA. This is a two step
  process. First data is exported from a source (e.g. DAVINCI) to ECF. After that ECF is
  imported to ENBREA. The target 'ecf' is an exception because only the second step is
  executed. The configuration for this import process will be read from a JSON configuration
  file.
 
 .Parameter Source
  The name of a supported import source. Currently supported are 'davinci', 'magellan',
  'untis', 'edoosys', 'schildnrw', 'bbsplanung', 'excel' and 'ecf'.
 
 .Parameter ConfigFile
  The file name of the JSON configuration file.
 
 .Parameter SkipEcfExport
  If true do not export ECF from source. This flag is for testing purpose.
 
 .Parameter SkipEcfImport
  If true do not import ECF to ENBREA. This flag is for testing purpose.
 
 .Example
  # Starts an import from DAVINCI to ENBREA
  Start-EnbreaImport -Source davinci -ConfigFile MyImportConfig.json
 
 .Example
  # Starts an import from DAVINCI to ENBREA (short form)
  Start-EnbreaImport davinci MyImportConfig.json
 
 .Example
  # Starts an import from plain ECF to ENBREA
  Start-EnbreaImport -Source ecf -ConfigFile MyImportConfig.json
#>

function Start-EnbreaImport {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ImportSource]
        $Source,
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ConfigFile,
        [switch]
        $SkipEcfExport,
        [switch]
        $SkipEcfImport
    )
    process
    {
        try
        {
        
            $ConfigPath = GetFullConfigPath -ConfigFile $ConfigFile
            $Config = GetConfig -Config $ConfigPath
            $Provider = $Source.ToString().ToLower()
            $FolderPath = GetEcfSourceFolderPath -Source $Source -Config $Config
        
            if (-not ($SkipEcfExport))
            {
                switch ($Source)
                {
                    ([ImportSource]::davinci)    { RunDavConsole -Command "export" -Config $Config }
                    ([ImportSource]::magellan)   { RunEcfTool -Tool ([EcfTool]::magellan) -Command "export" -Config $Config -ConfigPath $ConfigPath }
                    ([ImportSource]::untis)      { RunEcfTool -Tool ([EcfTool]::untis) -Command "export" -Config $Config -ConfigPath $ConfigPath }
                    ([ImportSource]::edoosys)    { RunEcfTool -Tool ([EcfTool]::edoosys) -Command "export" -Config $Config -ConfigPath $ConfigPath }
                    ([ImportSource]::schildnrw)  { RunEcfTool -Tool ([EcfTool]::schildnrw) -Command "export" -Config $Config -ConfigPath $ConfigPath }
                    ([ImportSource]::bbsplanung) { RunEcfTool -Tool ([EcfTool]::bbsplanung) -Command "export" -Config $Config -ConfigPath $ConfigPath }
                    ([ImportSource]::excel)      { RunEcfTool -Tool ([EcfTool]::excel) -Command "export" -Config $Config -ConfigPath $ConfigPath }
                }
            }

            if (-not ($SkipEcfImport))
            {
                RunEcfTool -Tool ([EcfTool]::enbrea) -Command "import" -Config $Config -ConfigPath $ConfigPath -Provider $Provider -FolderPath $FolderPath
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Error $ErrorMessage
        }
    }
}

<#
 .Synopsis
  Starts a new export from ENBREA to a supported target.
 
 .Description
  This cmdlet will start a new export from ENBREA to a supported target. This is a two step
  process. First data is exported from ENBREA to ECF. After that ECF is imported to a target
  (e.g. MAGELLAN). The source 'ecf' is an exception because only the first step is executed.
  The configuration for this export process will be read from a JSON configuration
  file.
 
 .Parameter Source
  The name of a supported export target. Currently supported are 'davinci', 'magellan' and 'ecf'.
 
 .Parameter ConfigFile
  The file name of the JSON configuration file.
 
 .Parameter SkipEcfExport
  If true do not export ECF files from ENBREA. This flag is for testing purpose.
 
 .Parameter SkipEcfImport
  If true do not import ECF files to target. This flag is for testing purpose.
 
 .Example
  # Starts an export from ENBREA to DAVINCI
  Start-EnbreaExport -Target davinci -ConfigFile MyExportConfig.json
 
 .Example
  # Starts an export from ENBREA to DAVINCI (short form)
  Start-EnbreaExport davinci MyExportConfig.json
 
 .Example
  # Starts an export from ENBREA to plain ECF
  Start-EnbreaExport -Target ecf -ConfigFile MyExportConfig.json
#>

function Start-EnbreaExport {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ExportTarget]
        $Target,
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ConfigFile,
        [switch]
        $SkipEcfExport,
        [switch]
        $SkipEcfImport
    )
    process
    {
        try
        {
            $ConfigPath = GetFullConfigPath -ConfigFile $ConfigFile
            $Config = GetConfig -Config $ConfigPath
            $Provider = $Target.ToString().ToLower()
            $FolderPath = GetEcfTargetFolderPath -Target $Target -Config $Config

            if (-not ($SkipEcfExport))
            {
                RunEcfTool -Tool ([EcfTool]::enbrea) -Command "export" -Config $Config -ConfigPath $ConfigPath -Provider $Provider -FolderPath $FolderPath
            }

            if (-not ($SkipEcfImport))
            {
                switch ($Target)
                {
                    ([ExportTarget]::davinci)  { RunDavConsole -Command "import" -Config $Config }
                    ([ExportTarget]::magellan) { RunEcfTool -Tool ([EcfTool]::magellan) -Command "import" -Config $Config -ConfigPath $ConfigPath }
                }
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Error $ErrorMessage
        }
    }
}

<#
 .Synopsis
  Installs one or more ECF Tools
 
 .Description
  An ECF Tool is an command line processor for consuming and/or generating ECF files. This
  cmdlet will download and install the current versions from GitHub.
 
 .Parameter Tool
  An array of ECF Tool short names. Currently supported are 'enbrea', 'magellan', 'untis',
  'edoosys', 'schildnrw', 'bbsplanung' and 'excel'.
 
 .Parameter Version
  Version number of the ECF tool if not the current one.
 
 .Example
  # Installing ECF Tool for MAGELLAN
  Install-EcfTools -Tools magellan
 
 .Example
  # Installing ECF Tool for MAGELLAN and Excel
  Install-EcfTools -Tools magellan, excel
#>

function Install-EcfTools {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [EcfTool[]]
        $Tools,
        [string]
        $Version
    )
    process
    {
        try
        {   
            foreach($tool in $Tools)
            {
                SetupEcfTool -Tool $tool -Version $Version
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Error $ErrorMessage
        }
    }
}

<#
 .Synopsis
  Updates one or more ECF Tools
 
 .Description
  An ECF Tool is an command line processor for consuming and/or generating ECF files. This
  cmdlet searches for newer versions of allready installed ECF Tools on GitHub. If found they
  will be downloaded and installed.
 
 .Parameter Tool
  An array of ECF Tool short names. Currently supported are 'enbrea', 'magellan', 'untis',
  'edoosys', 'schildnrw', 'bbsplanung' and 'excel'. Skipping this parameter means updating
  all ECF Tools.
 
 .Parameter Tool
  An array of ECF Tool short names. Currently supported are 'enbrea', 'magellan', 'untis',
  'edoosys', 'schildnrw', 'bbsplanung' and 'excel'. Skipping this parameter means updating
  all ECF Tools.
 
 .Parameter Version
  Version number of the ECF tool if not the current one.
 
 .Example
  # Updating ECF Tool for MAGELLAN
  Update-EcfTools -Tools magellan
 
 .Example
  # Updating ECF Tools for MAGELLAN and Excel
  Update-EcfTools -Tools magellan, excel
 
 .Example
  # Updating all supported ECF Tools
  Update-EcfTools
#>

function Update-EcfTools {
    param(
        [EcfTool[]]
        $Tools,
        [string]
        $Version
    )
    process
    {
        try
        {   
            if ($Tools.Count -gt 0)
            {
                foreach($tool in $Tools)
                {
                    UpdateEcfTool -Tool $tool -Version $Version
                }
            }
            else 
            {
                foreach($tool in [enum]::GetValues([EcfTool]))
                {
                    UpdateEcfTool -Tool $tool -Version $Version
                }
            }
        }
        catch
        {
            $ErrorMessage = $_.Exception.Message
            Write-Host $ErrorMessage
        }
    }
}

function SetupEcfTool {
    param(
        [EcfTool]
        $Tool,
        [string]
        $Version
    )
    process
    {
        $SetupFolder = GetEcfToolFolder -Tool $Tool
        $ShortName = GetEcfToolShortName -Tool $Tool
        $FriendlyName = GetEcfToolFriendlyName -Tool $Tool
        
        if ((-not ($SetupFolder)) -or (-not (Test-Path -Path $SetupFolder)))
        {
            Write-Verbose "Searching for latest version of $($FriendlyName)"

            if (-not (Test-Path -Path $SetupFolder -PathType Container))
            {
                $null = New-Item -Path $SetupFolder -ItemType Directory -Force
            }
            
            if ($Version)
            {
                $GitHubInfo = Invoke-RestMethod -Uri "https://api.github.com/repos/stuebersystems/$($ShortName)/releases/tags/v-$($Version)"
            }
            else
            {
                $GitHubInfo = Invoke-RestMethod -Uri "https://api.github.com/repos/stuebersystems/$($ShortName)/releases/latest"
            }
                
            if ($GitHubInfo.tag_name) 
            {
                $RemoteVersion = GetSemVersion $GitHubInfo.tag_name
                
                Write-Verbose "Remote version: $($RemoteVersion.ToString())"

                if ($GitHubInfo.assets.browser_download_url) 
                {
                    $TempZipArchive = "$($SetupFolder)\_download.zip"

                    $ProgressPreference = 'SilentlyContinue'    
                    try 
                    {
                        Invoke-WebRequest -Uri $GitHubInfo.assets.browser_download_url -OutFile $TempZipArchive 
                    }
                    finally 
                    {
                        $ProgressPreference = 'Continue'    
                    }

                    Expand-Archive $TempZipArchive -DestinationPath $SetupFolder -Force
                    
                    Remove-Item -Path $TempZipArchive -Force
                }

                Write-Host ([string]::Format($stringTable.EcfToolInstalled, $FriendlyName, $RemoteVersion.ToString()))
            }
        }
        else 
        {
            Write-Host ([string]::Format($stringTable.EcfToolAlreadyInstalled, $FriendlyName))
        }
    }
}

function UpdateEcfTool {
    param(
        [EcfTool]
        $Tool,
        [string]
        $Version
    )
    process
    {
        $ConsolePath = GetEcfToolBinaryPath -Tool $Tool
        $ShortName = GetEcfToolShortName -Tool $Tool
        $FriendlyName = GetEcfToolFriendlyName -Tool $Tool
        
        if (Test-Path -Path $ConsolePath -PathType Leaf)
        {
            Write-Verbose "Searching for update of $($FriendlyName)"

            if ($Version)
            {
                $GitHubInfo = Invoke-RestMethod -Uri "https://api.github.com/repos/stuebersystems/$($ShortName)/releases/tags/v-$($Version)"
            }
            else
            {
                $GitHubInfo = Invoke-RestMethod -Uri "https://api.github.com/repos/stuebersystems/$($ShortName)/releases/latest"
            }
                
            if ($GitHubInfo.tag_name) 
            {
                $RemoteVersion = GetSemVersion $GitHubInfo.tag_name
                $LocalVersion = GetSemVersion (GetFileVersion $ConsolePath)
                
                Write-Verbose "Remote version: $($RemoteVersion.ToString())"
                Write-Verbose "Local version: $($LocalVersion.ToString())"

                if ($Version) 
                {
                    if ($RemoteVersion -eq $LocalVersion)
                    {
                        Write-Host ([string]::Format($stringTable.EcfToolVersionAlreadyInstalled, $FriendlyName, $RemoteVersion.ToString()))
                        return
                    }
                }
                else
                {
                    if ($RemoteVersion -le $LocalVersion)
                    {
                        Write-Host ([string]::Format($stringTable.EcfToolUpToDate, $FriendlyName, $RemoteVersion.ToString()))
                        return
                    }
                }

                if ($GitHubInfo.assets.browser_download_url) 
                {
                    $ConsoleFolder = Split-Path -Path $ConsolePath
                    
                    $TempZipArchive = "$($ConsoleFolder)\_download.zip"

                    $ProgressPreference = 'SilentlyContinue'    
                    try 
                    {
                        Write-Verbose $GitHubInfo.assets.browser_download_url
                        Invoke-WebRequest -Uri $GitHubInfo.assets.browser_download_url -OutFile $TempZipArchive
                    }
                    finally 
                    {
                        $ProgressPreference = 'Continue'    
                    }

                    Expand-Archive $TempZipArchive -DestinationPath $ConsoleFolder -Force
                    
                    Remove-Item -Path $TempZipArchive -Force
                }

                Write-Host ([string]::Format($stringTable.EcfToolUpdated, $FriendlyName, $RemoteVersion.ToString()))
            }
        }
        else 
        {
            Write-Host ([string]::Format($stringTable.EcfToolNotInstalled, $FriendlyName))
        }
    }
}

function RunEcfTool{
    param(
        [EcfTool]
        $Tool,
        [string]
        $Command,
        [PSObject]
        $Config,
        [string]
        $ConfigPath,
        [string]
        $Provider,
        [string]
        $FolderPath
    )
    process
    {   
        Write-Host $stringTable.StartEcfTool -ForegroundColor $Host.PrivateData.VerboseForegroundColor

        $ConsolePath = GetEcfToolBinaryPath -Tool $Tool -Config $Config
        $FriendlyName = GetEcfToolFriendlyName -Tool $Tool
        
        if (($ConsolePath) -and (Test-Path -Path $ConsolePath -PathType Leaf))
        {
            $CurrentLocation = Get-Location
            Set-Location -Path (Split-Path -Path $ConfigPath)
            try 
            {
                if ($Tool -eq [EcfTool]::enbrea)
                {
                    dotnet "$($ConsolePath)" $($Command) -c "$($ConfigPath)" -p $($Provider) -f "$($FolderPath)"
                }
                else
                {
                    dotnet "$($ConsolePath)" $($Command) -c "$($ConfigPath)"
                }
            }
            finally 
            {
                Set-Location -Path $CurrentLocation
            }

            if ($LASTEXITCODE -ne 0)
            {
                $ErrorMessage = ([string]::Format($stringTable.ErrorEcfToolFailed, $FriendlyName))
                throw $ErrorMessage
            }
        }
        else
        {
            $ErrorMessage = ([string]::Format($stringTable.ErrorEcfToolNotFound, $FriendlyName))
            throw $ErrorMessage
        }
    }
}

function RunDavConsole{
    param(
        [string]
        $Command,
        [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) -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 "PsEnbrea.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.PSEnbrea.Tools.DaVinciConsole)
            {
                return $config.PSEnbrea.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
            }
        }
    
    }
}

function GetEcfSourceFolderPath {
    param(
        [ImportSource]
        $Source,
        [PsObject]
        $Config
    )
    process
    {
        $Provider = $Source.ToString()
        $ProviderConfig = $Config | Select-Object -ExpandProperty $Provider
        return $ProviderConfig.EcfExport.TargetFolderName
    }
}

function GetEcfTargetFolderPath {
    param(
        [ExportTarget]
        $Target,
        [PsObject]
        $Config
    )
    process
    {
        $Provider = $Target.ToString()
        $ProviderConfig = $Config | Select-Object -ExpandProperty $Provider
        return $ProviderConfig.EcfImport.SourceFolderName
    }
}

function GetEcfToolBinaryName {
    param(
        [EcfTool]
        $Tool
    )
    process
    {
        switch ($Tool)
        {
            ([EcfTool]::enbrea)     { return "ecf.enbrea.dll" }
            ([EcfTool]::magellan)   { return "ecf.magellan.dll" }
            ([EcfTool]::untis)      { return "ecf.untis.dll" }
            ([EcfTool]::bbsplanung) { return "ecf.bbsplanung.dll" }
            ([EcfTool]::edoosys)    { return "ecf.edoosys.dll" }
            ([EcfTool]::schildnrw)  { return "ecf.schildnrw.dll" }
            ([EcfTool]::excel)      { return "ecf.excel.dll" }
        }
    }
}

function GetEcfToolBinaryPath {
    param(
        [EcfTool]
        $Tool,
        [PSObject]
        $Config
    )
    process
    {
        if ($Config)
        {
            $ShortName = GetEcfToolShortName -Tool $Tool

            if (($Config.PSEnbrea.Tools) -and ($ShortName -in $Config.PSEnbrea.Tools.PSObject.Properties.Name))
            {
                return $Config.PSEnbrea.Tools | Select-Object -ExpandProperty $ShortName
            }
        }

        return Join-Path -Path (GetEcfToolFolder -Tool $Tool) -ChildPath (GetEcfToolBinaryName -Tool $Tool)
    }
}

function GetEcfToolFolder {
    param(
        [EcfTool]
        $Tool
    )
    process
    {
        $EcfToolInstallVariableName = "EcfToolsInstall"
        $EcfToolInstallPath = [Environment]::GetEnvironmentVariable($EcfToolInstallVariableName)
        
        if (($EcfToolInstallPath) -and (Test-Path -Path $EcfToolInstallPath))
        {
            return $EcfToolInstallPath  
        }
            
        return Join-Path -Path $Env:PROGRAMDATA -ChildPath (Join-Path -Path "Stueber Systems\Ecf-Tools" -ChildPath (GetEcfToolShortName -Tool $Tool))   
    }
}

function GetEcfToolFriendlyName {
    param(
        [EcfTool]
        $Tool
    )
    process
    {
        switch ($Tool)
        {
            ([EcfTool]::enbrea)     { return "ECF Tool for ENBREA" }
            ([EcfTool]::magellan)   { return "ECF Tool for MAGELLAN" }
            ([EcfTool]::untis)      { return "ECF Tool for Untis" }
            ([EcfTool]::bbsplanung) { return "ECF Tool for BBS-Planung" }
            ([EcfTool]::edoosys)    { return "ECF Tool for edoo.sys" }
            ([EcfTool]::schildnrw)  { return "ECF Tool for Schild-NRW" }
            ([EcfTool]::excel)      { return "ECF Tool for Excel" }
        }
    }
}

function GetEcfToolShortName {
    param(
        [EcfTool]
        $Tool
    )
    process
    {
        switch ($Tool)
        {
            ([EcfTool]::enbrea)     { return "ecf.enbrea" }
            ([EcfTool]::magellan)   { return "ecf.magellan" }
            ([EcfTool]::untis)      { return "ecf.untis" }
            ([EcfTool]::bbsplanung) { return "ecf.bbsplanung" }
            ([EcfTool]::edoosys)    { return "ecf.edoosys" }
            ([EcfTool]::schildnrw)  { return "ecf.schildnrw" }
            ([EcfTool]::excel)      { return "ecf.excel" }
        }
    }
}

function GetFileVersion {
    param(
        [string]
        $Path
    )
    process
    {
        return (Get-Command $Path).FileVersionInfo.ProductVersion
    }
}

function GetSemVersion {
    param(
        [string]
        $TagName
    )
    process
    {
        $Version = $null
        $TagName = $TagName -replace "v-", ""

        if ([NuGet.Versioning.SemanticVersion]::TryParse($TagName, [ref]$Version))
        {
            return $Version
        }
        else
        {
            $ErrorMessage = ([string]::Format($stringTable.ErrorTagNameParsing, $TagName))
            throw $ErrorMessage
        }
    }
}

# List of supported ecf tools
Enum EcfTool {
    enbrea
    magellan
    untis
    bbsplanung
    edoosys
    schildnrw
    excel
}

# List of supported import sources
Enum ImportSource {
    davinci
    magellan
    untis
    bbsplanung
    edoosys
    schildnrw
    excel
    ecf
}

# List of supported export targets
Enum ExportTarget {
    davinci
    magellan
    ecf
}

Export-ModuleMember -Function Initialize-EnbreaImport
Export-ModuleMember -Function Initialize-EnbreaExport
Export-ModuleMember -Function Install-EcfTools
Export-ModuleMember -Function Start-EnbreaImport
Export-ModuleMember -Function Start-EnbreaExport
Export-ModuleMember -Function Update-EcfTools

# SIG # Begin signature block
# MIIn7gYJKoZIhvcNAQcCoIIn3zCCJ9sCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU/zB1fmPtdtJmO7AIcldom7kT
# u86ggiEWMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B
# AQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk
# IElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQsw
# CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
# ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw
# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz
# 7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS
# 5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7
# bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfI
# SKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jH
# trHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14
# Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2
# h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt
# 6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPR
# iQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ER
# ElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4K
# Jpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAd
# BgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SS
# y4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAC
# hjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS
# b290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRV
# HSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyh
# hyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO
# 0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo
# 8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++h
# UD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5x
# aiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMIIGrjCCBJag
# AwIBAgIQBzY3tyRUfNhHrP0oZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQG
# EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
# cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIw
# MzIzMDAwMDAwWhcNMzcwMzIyMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UE
# ChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQg
# UlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEF
# AAOCAg8AMIICCgKCAgEAxoY1BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCw
# zIP5WvYRoUQVQl+kiPNo+n3znIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFz
# sbPuK4CEiiIY3+vaPcQXf6sZKz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ
# 7Gnf2ZCHRgB720RBidx8ald68Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7
# QKxfst5Kfc71ORJn7w6lY2zkpsUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/teP
# c5OsLDnipUjW8LAxE6lXKZYnLvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCY
# OjgRs/b2nuY7W+yB3iIU2YIqx5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9K
# oRxrOMUp88qqlnNCaJ+2RrOdOqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6
# dSgkQe1CvwWcZklSUPRR8zZJTYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM
# 1+mYSlg+0wOI/rOP015LdhJRk8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbC
# dLI/Hgl27KtdRnXiYKNYCQEoAA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbEC
# AwEAAaOCAV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1N
# hS9zKXaaL3WMaiCPnshvMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9P
# MA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcB
# AQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggr
# BgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1
# c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAI
# BgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7Zv
# mKlEIgF+ZtbYIULhsBguEE0TzzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI
# 2AvlXFvXbYf6hCAlNDFnzbYSlm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/ty
# dBTX/6tPiix6q4XNQ1/tYLaqT5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVP
# ulr3qRCyXen/KFSJ8NWKcXZl2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmB
# o1aGqwpFyd/EjaDnmPv7pp1yr8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc
# 6UsCUqc3fpNTrDsdCEkPlM05et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3c
# HXg65J6t5TRxktcma+Q4c6umAU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0d
# KNPH+ejxmF/7K9h+8kaddSweJywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZP
# J/tgZxahZrrdVcA6KYawmKAr7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLe
# Mt8EifAAzV3C+dAjfwAL5HYCJtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDy
# Divl1vupL0QVSucTDh3bNzgaoSv27dZ8/DCCBrAwggSYoAMCAQICEAitQLJg0pxM
# n17Nqb2TrtkwDQYJKoZIhvcNAQEMBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoT
# DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UE
# AxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTIxMDQyOTAwMDAwMFoXDTM2
# MDQyODIzNTk1OVowaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
# bmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBS
# U0E0MDk2IFNIQTM4NCAyMDIxIENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBANW0L0LQKK14t13VOVkbsYhC9TOM6z2Bl3DFu8SFJjCfpI5o2Fz16zQk
# B+FLT9N4Q/QX1x7a+dLVZxpSTw6hV/yImcGRzIEDPk1wJGSzjeIIfTR9TIBXEmtD
# mpnyxTsf8u/LR1oTpkyzASAl8xDTi7L7CPCK4J0JwGWn+piASTWHPVEZ6JAheEUu
# oZ8s4RjCGszF7pNJcEIyj/vG6hzzZWiRok1MghFIUmjeEL0UV13oGBNlxX+yT4Us
# SKRWhDXW+S6cqgAV0Tf+GgaUwnzI6hsy5srC9KejAw50pa85tqtgEuPo1rn3MeHc
# reQYoNjBI0dHs6EPbqOrbZgGgxu3amct0r1EGpIQgY+wOwnXx5syWsL/amBUi0nB
# k+3htFzgb+sm+YzVsvk4EObqzpH1vtP7b5NhNFy8k0UogzYqZihfsHPOiyYlBrKD
# 1Fz2FRlM7WLgXjPy6OjsCqewAyuRsjZ5vvetCB51pmXMu+NIUPN3kRr+21CiRshh
# WJj1fAIWPIMorTmG7NS3DVPQ+EfmdTCN7DCTdhSmW0tddGFNPxKRdt6/WMtyEClB
# 8NXFbSZ2aBFBE1ia3CYrAfSJTVnbeM+BSj5AR1/JgVBzhRAjIVlgimRUwcwhGug4
# GXxmHM14OEUwmU//Y09Mu6oNCFNBfFg9R7P6tuyMMgkCzGw8DFYRAgMBAAGjggFZ
# MIIBVTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRoN+Drtjv4XxGG+/5h
# ewiIZfROQjAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8B
# Af8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYIKwYBBQUHAQEEazBpMCQG
# CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKG
# NWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290
# RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMBwGA1UdIAQVMBMwBwYFZ4EMAQMw
# CAYGZ4EMAQQBMA0GCSqGSIb3DQEBDAUAA4ICAQA6I0Q9jQh27o+8OpnTVuACGqX4
# SDTzLLbmdGb3lHKxAMqvbDAnExKekESfS/2eo3wm1Te8Ol1IbZXVP0n0J7sWgUVQ
# /Zy9toXgdn43ccsi91qqkM/1k2rj6yDR1VB5iJqKisG2vaFIGH7c2IAaERkYzWGZ
# gVb2yeN258TkG19D+D6U/3Y5PZ7Umc9K3SjrXyahlVhI1Rr+1yc//ZDRdobdHLBg
# XPMNqO7giaG9OeE4Ttpuuzad++UhU1rDyulq8aI+20O4M8hPOBSSmfXdzlRt2V0C
# FB9AM3wD4pWywiF1c1LLRtjENByipUuNzW92NyyFPxrOJukYvpAHsEN/lYgggnDw
# zMrv/Sk1XB+JOFX3N4qLCaHLC+kxGv8uGVw5ceG+nKcKBtYmZ7eS5k5f3nqsSc8u
# pHSSrds8pJyGH+PBVhsrI/+PteqIe3Br5qC6/To/RabE6BaRUotBwEiES5ZNq0RA
# 443wFSjO7fEYVgcqLxDEDAhkPDOPriiMPMuPiAsNvzv0zh57ju+168u38HcT5uco
# P6wSrqUvImxB+YJcFWbMbA7KxYbD9iYzDAdLoNMHAmpqQDBISzSoUSC7rRuFCOJZ
# DW3KBVAr6kocnqX9oKcfBnTn8tZSkP2vhUgh+Vc7tJwD7YZF9LRhbr9o4iZghurI
# r6n+lB3nYxs6hlZ4TjCCBsAwggSooAMCAQICEAxNaXJLlPo8Kko9KQeAPVowDQYJ
# KoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
# bmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2
# IFRpbWVTdGFtcGluZyBDQTAeFw0yMjA5MjEwMDAwMDBaFw0zMzExMjEyMzU5NTla
# MEYxCzAJBgNVBAYTAlVTMREwDwYDVQQKEwhEaWdpQ2VydDEkMCIGA1UEAxMbRGln
# aUNlcnQgVGltZXN0YW1wIDIwMjIgLSAyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
# MIICCgKCAgEAz+ylJjrGqfJru43BDZrboegUhXQzGias0BxVHh42bbySVQxh9J0J
# dz0Vlggva2Sk/QaDFteRkjgcMQKW+3KxlzpVrzPsYYrppijbkGNcvYlT4DotjIdC
# riak5Lt4eLl6FuFWxsC6ZFO7KhbnUEi7iGkMiMbxvuAvfTuxylONQIMe58tySSge
# TIAehVbnhe3yYbyqOgd99qtu5Wbd4lz1L+2N1E2VhGjjgMtqedHSEJFGKes+JvK0
# jM1MuWbIu6pQOA3ljJRdGVq/9XtAbm8WqJqclUeGhXk+DF5mjBoKJL6cqtKctvdP
# bnjEKD+jHA9QBje6CNk1prUe2nhYHTno+EyREJZ+TeHdwq2lfvgtGx/sK0YYoxn2
# Off1wU9xLokDEaJLu5i/+k/kezbvBkTkVf826uV8MefzwlLE5hZ7Wn6lJXPbwGqZ
# IS1j5Vn1TS+QHye30qsU5Thmh1EIa/tTQznQZPpWz+D0CuYUbWR4u5j9lMNzIfMv
# wi4g14Gs0/EH1OG92V1LbjGUKYvmQaRllMBY5eUuKZCmt2Fk+tkgbBhRYLqmgQ8J
# JVPxvzvpqwcOagc5YhnJ1oV/E9mNec9ixezhe7nMZxMHmsF47caIyLBuMnnHC1mD
# jcbu9Sx8e47LZInxscS451NeX1XSfRkpWQNO+l3qRXMchH7XzuLUOncCAwEAAaOC
# AYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM
# MAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAf
# BgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4EFgQUYore0GH8
# jzEU7ZcLzT0qlBTfUpwwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybDMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFt
# cGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUHMAGGGGh0dHA6
# Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDovL2NhY2VydHMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVT
# dGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAVaoqGvNG83hXNzD8deNP
# 1oUj8fz5lTmbJeb3coqYw3fUZPwV+zbCSVEseIhjVQlGOQD8adTKmyn7oz/AyQCb
# Ex2wmIncePLNfIXNU52vYuJhZqMUKkWHSphCK1D8G7WeCDAJ+uQt1wmJefkJ5ojO
# fRu4aqKbwVNgCeijuJ3XrR8cuOyYQfD2DoD75P/fnRCn6wC6X0qPGjpStOq/CUkV
# NTZZmg9U0rIbf35eCa12VIp0bcrSBWcrduv/mLImlTgZiEQU5QpZomvnIj5EIdI/
# HMCb7XxIstiSDJFPPGaUr10CU+ue4p7k0x+GAWScAMLpWnR1DT3heYi/HAGXyRkj
# gNc2Wl+WFrFjDMZGQDvOXTXUWT5Dmhiuw8nLw/ubE19qtcfg8wXDWd8nYiveQclT
# uf80EGf2JjKYe/5cQpSBlIKdrAqLxksVStOYkEVgM4DgI974A6T2RUflzrgDQkfo
# QTZxd639ouiXdE4u2h4djFrIHprVwvDGIqhPm73YHJpRxC+a9l+nJ5e6li6FV8Bg
# 53hWf2rvwpWaSxECyIKcyRoFfLpxtU56mWz06J7UWpjIn7+NuxhcQ/XQKujiYu54
# BNu90ftbCqhwfvCXhHjjCANdRyxjqCU4lwHSPzra5eX25pvcfizM/xdMTQCi2NYB
# DriL7ubgclWJLCcZYfZ3AYwwggdXMIIFP6ADAgECAhAPckT3cO3dV6VYGwywjOEd
# MA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy
# dCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25p
# bmcgUlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjIwNTI4MDAwMDAwWhcNMjMw
# ODE4MjM1OTU5WjBcMQswCQYDVQQGEwJERTEPMA0GA1UEBxMGQmVybGluMR0wGwYD
# VQQKDBRTVMOcQkVSIFNZU1RFTVMgR21iSDEdMBsGA1UEAwwUU1TDnEJFUiBTWVNU
# RU1TIEdtYkgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDCW7g9PYnG
# yTqDVjET6+PkgJCFXyA0B5Se0NmjbQhup9zGo7z3xi4f/pThhxIlidglVCRNl0mR
# tHTqRkEeJBFDSDi/tA5sFM2w+M/+tEz0Q5UxgWsLrpHUgfmdDhfcNbDkFoJLVg9x
# x8aviK1JZQoJszgYiGX4SJKtoIqpLa+DXn1SLSIkKJWkjAJV5Jw0NDZGuSJDhPYr
# 0WYdFIcGOEaAE2xPb6CwxsNgq7m3OnH0YLG4vm7NxVWP8myPROPkX3fWVUFhQDct
# jiG3G4nvLUoskrrVW0y8kU9W/2cew2PqNJ69+OKknMipXdz8CgZ6ukwsp72yr7Xy
# p+3SPOilNrfaxGUR1A5jMEv5irPJuI7LNMNK4RuMogtrcrWRf399sUG+0ubduJL/
# X/V5iRoMB660kY6XVcgaylPHlQwby2SVkDWEnn7Zed+W62sz69bRFYWuB/CrISGe
# mnQ6YaPLwBW8BVsbu4oN992KQgv7iPpK0dPsjry/zklxFCyaE6vZFcRiD296Rxk/
# it6MVLgO90bvtT2z/bGCFnrki/tj2mj4hJM5smhFyzehtrL9hkdljAOIAoC0S0iG
# 1im0YtCU2dmejRRJCObn9AyKy+1i9mchdMa/ppY3gRJIXQZvcCDRH6oZ7wwPeghO
# Yk4/xw1MiY1qNXCbeFh40zuHjTJchpSSvQIDAQABo4ICBjCCAgIwHwYDVR0jBBgw
# FoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFDKT6fB5tVCJiERKwktP
# /Z0jrQF5MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzCBtQYD
# VR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDBT
# oFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0
# Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwPgYDVR0gBDcwNTAz
# BgZngQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20v
# Q1BTMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
# ZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2Vy
# dC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQy
# MDIxQ0ExLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQCLikA+
# PIM3C1TWEQLwpLnm7yIP2eatSNwUewWw5uCo9lLn8loPdynwN+4tn73MXmUV4yec
# nvDwFXcVsQIVYJmmlTLs1MWXZRnCi1wlccl65yN4fgugk7uTfR2HNI4ie45dEuhJ
# 4GJXRbQp6d8JK6/dtIce5Qs889OZMXGuehppsrn3FnrrRdGtVPxK6Cn+EjPG9Py0
# xRc9+PFgQffyVKRcMtKw36NcYX5PaXO/xGnP18n8UvNqfnz7yMI9ckM551SR+kin
# CN3WOilzmARROZ/a+P8AFGifybyYAcsFS3YHNUg3L8uhovO37uH0+3I2yoh+mfcZ
# E+7N+f4s/k3pDidZTtr6SzBPoSVkee03iYkZumiH0v1tI92C3ovBv1FgCvR8nwAG
# cbTXj2NkXj/H6n0rcbXKQj6ZaWXshsIYLiLtFNQ7sjvYNJDarWqjxq/9VnuJwqiG
# +kLDt4RAE8Uim6+k+a3E85WUxLGr56sutfAOgD3tG+ugkuHdjGSQNmVxrORlsIP5
# +Z1TyZTvZ11jbdJ7IAO80HhSt2+ywm5kp4hnsYP5G9CDUa06KcYw8NlUAhAhQJ+l
# cZPlpr2YJOxVd6yEna6fTUZIiwmY8xNEhGPdI+gMxPjrGI6JB4ElUzQ/00+1Ry4U
# 6g5AqlxtcLlXugomLm0ygnh5uBtNR3Pyfa+4KjGCBkIwggY+AgEBMH0waTELMAkG
# A1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdp
# Q2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIx
# IENBMQIQD3JE93Dt3VelWBsMsIzhHTAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIB
# DDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEE
# AYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUXEhwdC7/h6je
# r3IQTaoNfan3NZMwDQYJKoZIhvcNAQEBBQAEggIAg1nqiR5H809tYOArCsjyu+qr
# h1Jk2AK931OZdDFjdq9iL8Il67fZrrNwYzZagFxoLh4lbswhjCjLtmgKBB5Ey0AS
# viB4WQSJz0bGwZ2D/YFf94f2HA+oVb/rSnsy6LTpN2rjcgC+8bXVQvI6tGZEXtvJ
# lIzO6yNHrmRQ0YDQU8Ea2BS7bbHRt6Z/IWSdIzWLlZqKEcSmNqcCbnOI/MVp9V8r
# 0OkZ/ApApZiWlKwBAynwqLpWWdjKoczVPJbXvx3OBo+sb6V6J6b77qF8lwQAMqIJ
# moI3sAlq8T9OTBn/XJP+iHgvo5pvTDc5UEJXRGno72XOHiZFO9EUAHVh4JielmVi
# jMAG6OtiL/6m9gGg94DybZHU9drnxdoSMcq66FDV0f81CsDCcx0ZbRcM6wHt1Q+Y
# Ik4bL9OM83tXNgNwqmfYSOd63Ew/Afv6+hF2QJOWquPYXAaL8jA7XESzkuqNiytt
# bl+UGsERltkNxnvzUmUEQqZcEChLZszXY7PAZCVwsoR31DaUHujfj8OmXg9D0Bpu
# QOl62C5RbspYjfpJ2mlpV1Fe+32Kpau18M6z5XzIAnQsTr3c/GNyqtGUGAYmHw+t
# 3LRRgW//Bczy8+2bxB/p/DUs3Y3LW8ijgu2D3DKWd9P6Dg2CeWe5AWaOePZX9KPY
# eXWIpfm1RXjacEbej/mhggMgMIIDHAYJKoZIhvcNAQkGMYIDDTCCAwkCAQEwdzBj
# MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMT
# MkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5n
# IENBAhAMTWlyS5T6PCpKPSkHgD1aMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcN
# AQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjMwMzIwMTU1NTMwWjAv
# BgkqhkiG9w0BCQQxIgQgYptk4Tmwb541FMCX67QZDXXdxUsO02eUS5EMsALz1aAw
# DQYJKoZIhvcNAQEBBQAEggIAXSrVD8IDQeF/QoFKB3aMt5onkrE2FME78nSpqq6r
# mii76D9g8Dlr+BF0Znhz3HCUvJyfUDps1o00esG0jGt+LH8lLBOz/5N1jh+WczLF
# DbY2c8XkO+se4mlilRR4v9y/VeedxshrHApGisJolQZICEIKz/I6gmIZZgIS1VbO
# 2huFlxhQuJZt2F9hJrpg8sfFn14ZkqGnXjg7ZZnqVTWPSlnWcLvzJ67yLBkADyEj
# wBDB7l0laUNKrMnCePPyv5HUmHz8epzVQxNoTQ9pZvvIWY3MpsUkOeW7wxmwbiTR
# bI1sgPC2//SCyrlksnWIKyjS617MzpS+lIxDO32Jb0YN8HAhf8BpOHxmXFmEdoAE
# a5DCpdCRBzscSc49iNv58MbmHGLDFotnndDMJbRvMaGPhBkYXnabAYJrlRoOS0Lf
# nf1BAIMNCJdcjAFWDUluAd+CaTHVD/Jpt+MbADsbYcjhIhbNFVwfeitkFx1FXsTm
# vBQ0ws1l37bBIwvFkTCxHCIchyCUFxn2Y5H/sXRVRWUkCD0zq63axVde1gzvWD+n
# Eo1bqZlkO17eSX9X452tEN4hfYEaI2pivhb7IOiJtRmc0L12LG4tQXNKGNi2heAd
# YoIgurHhhcZHvavvhVAiRv8iE3er7locMHEwxEP2DyIJiJbXpmAXOFO453iimPim
# 2MY=
# SIG # End signature block