• úvod
  • témata
  • události
  • tržiště
  • diskuze
  • nástěnka
  • přihlásit
    registrace
    ztracené heslo?
    LUCIENVibe coding
    TOM
    TOM --- ---
    TOM: oprava UTF-8 a detekce/použití separátoru

    @@ echo off
    @@ echo Invoking a Powershell script...
    @@ setlocal
    @@ set PS_WRAPPER_ARGS=%*
    @@ set PS_WRAPPER_PATH=%~f0
    @@ if defined PS_WRAPPER_ARGS set PS_WRAPPER_ARGS=%PS_WRAPPER_ARGS:"="%
    @@ PowerShell -sta -Command Invoke-Expression $('$args=@(^&{$args} %PS_WRAPPER_ARGS%);'+[String]::Join([Environment]::NewLine,$((Get-Content '%PS_WRAPPER_PATH%') -notmatch '^^@@^|^^:^|^^cls'))) & endlocal & cmd /k
    
    Add-Type -AssemblyName System.Windows.Forms, PresentationFramework, WindowsBase
    
    Add-Type @"
    using System;
    using System.Runtime.InteropServices;
    
    public class DarkMode {
        [DllImport("dwmapi.dll")]
        public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
    }
    "@
    
    # Dark mode detection
    function Get-WindowsTheme {
        try {
            $path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize"
            $value = Get-ItemProperty -Path $path -Name "AppsUseLightTheme" -ErrorAction Stop
            return $value.AppsUseLightTheme -eq 0
        } catch {
            return $false
        }
    }
    
    # Initialize theme-specific colors
    $script:isDarkMode = Get-WindowsTheme
    $darkBackColor = [System.Drawing.Color]::FromArgb(32, 32, 32)
    $darkForeColor = [System.Drawing.Color]::FromArgb(240, 240, 240)
    $darkControlBackColor = [System.Drawing.Color]::FromArgb(45, 45, 45)
    
    # Fix: Use theme-specific accent colors for proper visibility
    $script:accentColor = if ($script:isDarkMode) { 
        [System.Drawing.Color]::FromArgb(120, 250, 174)  # Light green for dark mode
    } else { 
        [System.Drawing.Color]::FromArgb(0, 120, 50)     # Darker green for light mode
    }
    
    # Character replacement mapping (using character codes to avoid UTF-8 encoding issues)
    $script:charMap = @{
        [char]0x00E4 = 'ae'; [char]0x00F6 = 'oe'; [char]0x00FC = 'ue'; [char]0x00E9 = 'e'
        [char]0x00E8 = 'e'; [char]0x00EA = 'e'; [char]0x011B = 'e'; [char]0x00E0 = 'a'
        [char]0x00C4 = 'AE'; [char]0x00D6 = 'OE'; [char]0x00DC = 'UE'; [char]0x00C9 = 'E'
        [char]0x00C8 = 'E'; [char]0x00CA = 'E'; [char]0x011A = 'E'; [char]0x00C0 = 'A'
        [char]0x00E1 = 'a'; [char]0x010D = 'c'; [char]0x010F = 'd'; [char]0x00ED = 'i'
        [char]0x0148 = 'n'; [char]0x00F3 = 'o'; [char]0x0159 = 'r'; [char]0x0161 = 's'
        [char]0x0165 = 't'; [char]0x016F = 'u'; [char]0x00FA = 'u'; [char]0x00FD = 'y'
        [char]0x017E = 'z'; [char]0x0142 = 'l'; [char]0x0111 = 'd'
        [char]0x00C1 = 'A'; [char]0x010C = 'C'; [char]0x010E = 'D'; [char]0x00CD = 'I'
        [char]0x0147 = 'N'; [char]0x00D3 = 'O'; [char]0x0158 = 'R'; [char]0x0160 = 'S'
        [char]0x0164 = 'T'; [char]0x016E = 'U'; [char]0x00DA = 'U'; [char]0x00DD = 'Y'
        [char]0x017D = 'Z'; [char]0x0141 = 'L'; [char]0x0110 = 'D'
        [char]0x00DF = 'ss'; ',' = '_'; ' ' = '_'; '.' = '_'; '!' = '_'; [char]0x00A7 = '_'
        "'" = '_'; [char]0x00B4 = '_'; [char]0x02C7 = '_'; ';' = '_'; '(' = '_'; ')' = '_'; '-' = '_'
    }
    
    # Function to sanitize sheet names
    function Sanitize-SheetName {
        param([string]$name)
        
        $result = $name
        foreach ($key in $script:charMap.Keys) {
            $result = $result -replace [regex]::Escape($key), $script:charMap[$key]
        }
        return $result
    }
    
    # Function to process a single Excel file
    function Process-ExcelFile {
        param(
            [string]$filePath,
            [System.Windows.Forms.TextBox]$logBox = $null
        )
        
        $excel = $null
        $workbook = $null
        
        try {
            # Validate file
            if (-not (Test-Path $filePath)) {
                $msg = "ERROR: File not found: $filePath"
                if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
                return
            }
            
            if ($filePath -notmatch "\.(xlsx|xlsm|xls)$") {
                $msg = "ERROR: Not an Excel file: $filePath"
                if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
                return
            }
            
            $msg = "Processing: $filePath"
            if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
            
            # Create output folder
            $fileInfo = Get-Item $filePath
            $folderName = [System.IO.Path]::GetFileNameWithoutExtension($fileInfo.Name)
            $outputFolder = Join-Path $fileInfo.DirectoryName $folderName
            
            if (-not (Test-Path $outputFolder)) {
                [void](New-Item -ItemType Directory -Path $outputFolder -Force)
                $msg = "Created folder: $outputFolder"
                if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
            }
            
            # Open Excel
            $excel = New-Object -ComObject Excel.Application
            $excel.Visible = $false
            $excel.DisplayAlerts = $false
            $excel.ScreenUpdating = $false
            
            $workbook = $excel.Workbooks.Open($filePath)
            $sheetCount = $workbook.Sheets.Count
            
            $msg = "Found $sheetCount sheet(s)"
            if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
            
            # Get system list separator for proper CSV format
            $listSeparator = (Get-Culture).TextInfo.ListSeparator
            
            # Export each sheet and collect info for markdown
            $sheetInfo = @()
            for ($i = 1; $i -le $sheetCount; $i++) {
                $sheet = $workbook.Sheets.Item($i)
                $sheetName = $sheet.Name
                $sanitizedName = Sanitize-SheetName $sheetName
                $csvPath = Join-Path $outputFolder "$sanitizedName.csv"
                
                $msg = "  Exporting sheet '$sheetName' -> '$sanitizedName.csv'"
                if ($logBox) { 
                    $logBox.AppendText("$msg`r`n")
                    [System.Windows.Forms.Application]::DoEvents()
                } else { 
                    Write-Host $msg 
                }
                
                # Manual CSV export to preserve formatting and use system separator
                $usedRange = $sheet.UsedRange
                if ($usedRange -ne $null) {
                    $rowCount = $usedRange.Rows.Count
                    $colCount = $usedRange.Columns.Count
                    
                    # Build CSV content line by line
                    $csvLines = @()
                    for ($row = 1; $row -le $rowCount; $row++) {
                        $rowValues = @()
                        for ($col = 1; $col -le $colCount; $col++) {
                            $cell = $sheet.Cells.Item($row, $col)
                            $text = $cell.Text  # Get formatted display value (preserves dates as DD.MM.YYYY)
                            
                            # Escape if contains separator, quotes, or newlines
                            if ($text -match "[$([regex]::Escape($listSeparator))`"`r`n]") {
                                $text = '"' + ($text -replace '"', '""') + '"'
                            }
                            $rowValues += $text
                            
                            # Release cell COM object
                            [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($cell)
                        }
                        $csvLines += ($rowValues -join $listSeparator)
                    }
                    
                    # Write CSV with UTF-8 encoding
                    $csvLines -join "`r`n" | Set-Content -Path $csvPath -Encoding UTF8
                    
                    # Release range COM object
                    [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($usedRange)
                }
                
                # Store info for markdown
                $sheetInfo += [PSCustomObject]@{
                    OriginalName = $sheetName
                    SanitizedName = $sanitizedName
                    CsvPath = $csvPath
                }
                
                # Release sheet COM object
                [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($sheet)
            }
            
            # Create combined markdown file
            $msg = "`r`n  Creating combined markdown file..."
            if ($logBox) { 
                $logBox.AppendText("$msg`r`n")
                [System.Windows.Forms.Application]::DoEvents()
            } else { 
                Write-Host $msg 
            }
            
            $markdownPath = Join-Path $outputFolder "$folderName.md"
            $markdownContent = ""
            
            foreach ($info in $sheetInfo) {
                $markdownContent += "# $($info.OriginalName)`r`n"
                if (Test-Path $info.CsvPath) {
                    $csvContent = Get-Content -Path $info.CsvPath -Raw -Encoding UTF8
                    $markdownContent += $csvContent.TrimEnd() + "`r`n`r`n"
                }
            }
            
            $markdownContent | Set-Content -Path $markdownPath -Encoding UTF8
            
            $msg = "`r`nSuccess! Exported $sheetCount sheet(s) to: $outputFolder`r`n"
            $msg += "  - Individual CSV files: $sheetCount`r`n"
            $msg += "  - Combined markdown: $folderName.md`r`n"
            $msg += "  - Using delimiter: '$listSeparator'`r`n"
            if ($logBox) { $logBox.AppendText("$msg") } else { Write-Host $msg }
            
        } catch {
            $msg = "ERROR: $_"
            if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
        } finally {
            # Cleanup COM objects (critical!)
            if ($workbook -ne $null) {
                $workbook.Close($false)
                [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook)
            }
            
            if ($excel -ne $null) {
                $excel.Quit()
                [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel)
            }
            
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()
            Start-Sleep -Milliseconds 500
        }
    }
    
    # Main logic: Check if file was drag-dropped
    if ($args.Count -gt 0 -and $args[0]) {
        # Silent mode - no GUI
        $filePath = $args[0]
        Process-ExcelFile -filePath $filePath
        
    } else {
        # GUI mode - no file provided
        
        # Create main form
        $form = New-Object Windows.Forms.Form
        $form.Text = "Excel to CSV Exporter"
        $form.Size = New-Object Drawing.Size(700, 500)
        $form.StartPosition = "CenterScreen"
        $form.AllowDrop = $true
        
        # Create log textbox
        $logBox = New-Object Windows.Forms.TextBox
        $logBox.Multiline = $true
        $logBox.ScrollBars = "Vertical"
        $logBox.Dock = "Fill"
        $logBox.Font = New-Object Drawing.Font("Consolas", 10)
        $logBox.ReadOnly = $true
        
        # Create button
        $button = New-Object Windows.Forms.Button
        $button.Text = "Select Excel File(s)"
        $button.Dock = "Bottom"
        $button.Height = 50
        $button.FlatStyle = "Flat"
        $button.Font = New-Object Drawing.Font($button.Font.FontFamily, 11, [System.Drawing.FontStyle]::Bold)
        
        # Apply theme colors
        if ($script:isDarkMode) {
            $form.BackColor = $darkBackColor
            $form.ForeColor = $darkForeColor
            $logBox.BackColor = $darkControlBackColor
            $logBox.ForeColor = $darkForeColor
            $button.BackColor = $darkControlBackColor
            $button.ForeColor = $script:accentColor
            $button.FlatAppearance.BorderColor = $script:accentColor
        } else {
            $button.ForeColor = $script:accentColor
        }
        
        # Apply dark mode to title bar (must be in Shown event)
        $form.Add_Shown({
            if ($script:isDarkMode) {
                $darkModeValue = 1
                [void][DarkMode]::DwmSetWindowAttribute($form.Handle, 20, [ref]$darkModeValue, 4)
            }
        })
        
        # Button click handler
        $button.Add_Click({
            $openFileDialog = New-Object Windows.Forms.OpenFileDialog
            $openFileDialog.Filter = "Excel files (*.xlsx;*.xls;*.xlsm)|*.xlsx;*.xls;*.xlsm"
            $openFileDialog.Multiselect = $true
            
            if ($openFileDialog.ShowDialog() -eq 'OK') {
                $button.Enabled = $false
                $logBox.Clear()
                
                foreach ($file in $openFileDialog.FileNames) {
                    Process-ExcelFile -filePath $file -logBox $logBox
                }
                
                $button.Enabled = $true
            }
        })
        
        # Drag & drop handlers
        $form.Add_DragEnter({
            if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
                $_.Effect = [Windows.Forms.DragDropEffects]::Copy
            }
        })
        
        $form.Add_DragDrop({
            $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)
            $excelFiles = $files | Where-Object { $_ -match "\.(xlsx|xls|xlsm)$" }
            
            if ($excelFiles.Count -eq 0) {
                $logBox.AppendText("Please drop Excel file(s) (.xlsx, .xls, or .xlsm)`r`n")
                return
            }
            
            $button.Enabled = $false
            $logBox.Clear()
            
            foreach ($file in $excelFiles) {
                Process-ExcelFile -filePath $file -logBox $logBox
            }
            
            $button.Enabled = $true
        })
        
        # Initial instructions
        $logBox.AppendText("EXCEL TO CSV EXPORTER`r`n")
        $logBox.AppendText("====================`r`n`r`n")
        $logBox.AppendText("This tool exports all sheets from Excel files to CSV format.`r`n`r`n")
        $logBox.AppendText("For each Excel file:`r`n")
        $logBox.AppendText("  1. Creates a folder with the same name as the file`r`n")
        $logBox.AppendText("  2. Exports each sheet to a separate CSV file`r`n")
        $logBox.AppendText("  3. Sanitizes sheet names (replaces special characters)`r`n`r`n")
        $logBox.AppendText("Drag & drop Excel files here or click the button below.`r`n")
        
        # Add controls to form
        $form.Controls.Add($logBox)
        $form.Controls.Add($button)
        
        # Show the form
        [void]$form.ShowDialog()
    }
    
    TOM
    TOM --- ---
    jenom taková drobnůstka, převede XLSX (zejména s více sešity) na jednotlivá CSV a souhrnný MD
    (zejména pokud potřebujete nějakými výstupy z Excelu zpětně krmit stroj ;))
    funguje i jako zástupce bez GUI - pokud v Total Commanderu vytvoříte zástupce, rozpozná drag&drop (lze pouze jednotlivé soubory)
    pro automatické uzavření konzole (pokud nechcete vidět průběh a report) změňte cmd /k na konci sedmého řádku na cmd /c
    jo a kód vložte do textového souboru typu .cmd (je to zawrappovaný powershell)

    @@ echo off
    @@ echo Invoking a Powershell script...
    @@ setlocal
    @@ set PS_WRAPPER_ARGS=%*
    @@ set PS_WRAPPER_PATH=%~f0
    @@ if defined PS_WRAPPER_ARGS set PS_WRAPPER_ARGS=%PS_WRAPPER_ARGS:"="%
    @@ PowerShell -sta -Command Invoke-Expression $('$args=@(^&{$args} %PS_WRAPPER_ARGS%);'+[String]::Join([Environment]::NewLine,$((Get-Content '%PS_WRAPPER_PATH%') -notmatch '^^@@^|^^:^|^^cls'))) & endlocal & cmd /k
    
    Add-Type -AssemblyName System.Windows.Forms, PresentationFramework, WindowsBase
    
    Add-Type @"
    using System;
    using System.Runtime.InteropServices;
    
    public class DarkMode {
        [DllImport("dwmapi.dll")]
        public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
    }
    "@
    
    # Dark mode detection
    function Get-WindowsTheme {
        try {
            $path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize"
            $value = Get-ItemProperty -Path $path -Name "AppsUseLightTheme" -ErrorAction Stop
            return $value.AppsUseLightTheme -eq 0
        } catch {
            return $false
        }
    }
    
    # Initialize theme-specific colors
    $script:isDarkMode = Get-WindowsTheme
    $darkBackColor = [System.Drawing.Color]::FromArgb(32, 32, 32)
    $darkForeColor = [System.Drawing.Color]::FromArgb(240, 240, 240)
    $darkControlBackColor = [System.Drawing.Color]::FromArgb(45, 45, 45)
    
    # Fix: Use theme-specific accent colors for proper visibility
    $script:accentColor = if ($script:isDarkMode) { 
        [System.Drawing.Color]::FromArgb(120, 250, 174)  # Light green for dark mode
    } else { 
        [System.Drawing.Color]::FromArgb(0, 120, 50)     # Darker green for light mode
    }
    
    # Character replacement mapping (using character codes to avoid UTF-8 encoding issues)
    $script:charMap = @{
        [char]0x00E4 = 'ae'; [char]0x00F6 = 'oe'; [char]0x00FC = 'ue'; [char]0x00E9 = 'e'
        [char]0x00E8 = 'e'; [char]0x00EA = 'e'; [char]0x011B = 'e'; [char]0x00E0 = 'a'
        [char]0x00C4 = 'AE'; [char]0x00D6 = 'OE'; [char]0x00DC = 'UE'; [char]0x00C9 = 'E'
        [char]0x00C8 = 'E'; [char]0x00CA = 'E'; [char]0x011A = 'E'; [char]0x00C0 = 'A'
        [char]0x00E1 = 'a'; [char]0x010D = 'c'; [char]0x010F = 'd'; [char]0x00ED = 'i'
        [char]0x0148 = 'n'; [char]0x00F3 = 'o'; [char]0x0159 = 'r'; [char]0x0161 = 's'
        [char]0x0165 = 't'; [char]0x016F = 'u'; [char]0x00FA = 'u'; [char]0x00FD = 'y'
        [char]0x017E = 'z'; [char]0x0142 = 'l'; [char]0x0111 = 'd'
        [char]0x00C1 = 'A'; [char]0x010C = 'C'; [char]0x010E = 'D'; [char]0x00CD = 'I'
        [char]0x0147 = 'N'; [char]0x00D3 = 'O'; [char]0x0158 = 'R'; [char]0x0160 = 'S'
        [char]0x0164 = 'T'; [char]0x016E = 'U'; [char]0x00DA = 'U'; [char]0x00DD = 'Y'
        [char]0x017D = 'Z'; [char]0x0141 = 'L'; [char]0x0110 = 'D'
        [char]0x00DF = 'ss'; ',' = '_'; ' ' = '_'; '.' = '_'; '!' = '_'; [char]0x00A7 = '_'
        "'" = '_'; [char]0x00B4 = '_'; [char]0x02C7 = '_'; ';' = '_'; '(' = '_'; ')' = '_'; '-' = '_'
    }
    
    # Function to sanitize sheet names
    function Sanitize-SheetName {
        param([string]$name)
        
        $result = $name
        foreach ($key in $script:charMap.Keys) {
            $result = $result -replace [regex]::Escape($key), $script:charMap[$key]
        }
        return $result
    }
    
    # Function to process a single Excel file
    function Process-ExcelFile {
        param(
            [string]$filePath,
            [System.Windows.Forms.TextBox]$logBox = $null
        )
        
        $excel = $null
        $workbook = $null
        
        try {
            # Validate file
            if (-not (Test-Path $filePath)) {
                $msg = "ERROR: File not found: $filePath"
                if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
                return
            }
            
            if ($filePath -notmatch "\.(xlsx|xlsm|xls)$") {
                $msg = "ERROR: Not an Excel file: $filePath"
                if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
                return
            }
            
            $msg = "Processing: $filePath"
            if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
            
            # Create output folder
            $fileInfo = Get-Item $filePath
            $folderName = [System.IO.Path]::GetFileNameWithoutExtension($fileInfo.Name)
            $outputFolder = Join-Path $fileInfo.DirectoryName $folderName
            
            if (-not (Test-Path $outputFolder)) {
                [void](New-Item -ItemType Directory -Path $outputFolder -Force)
                $msg = "Created folder: $outputFolder"
                if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
            }
            
            # Open Excel
            $excel = New-Object -ComObject Excel.Application
            $excel.Visible = $false
            $excel.DisplayAlerts = $false
            $excel.ScreenUpdating = $false
            
            $workbook = $excel.Workbooks.Open($filePath)
            $sheetCount = $workbook.Sheets.Count
            
            $msg = "Found $sheetCount sheet(s)"
            if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
            
            # Export each sheet and collect info for markdown
            $sheetInfo = @()
            for ($i = 1; $i -le $sheetCount; $i++) {
                $sheet = $workbook.Sheets.Item($i)
                $sheetName = $sheet.Name
                $sanitizedName = Sanitize-SheetName $sheetName
                $csvPath = Join-Path $outputFolder "$sanitizedName.csv"
                
                $msg = "  Exporting sheet '$sheetName' -> '$sanitizedName.csv'"
                if ($logBox) { 
                    $logBox.AppendText("$msg`r`n")
                    [System.Windows.Forms.Application]::DoEvents()
                } else { 
                    Write-Host $msg 
                }
                
                # Save as CSV (Excel format 6 = CSV)
                $sheet.SaveAs($csvPath, 6)
                
                # Store info for markdown
                $sheetInfo += [PSCustomObject]@{
                    OriginalName = $sheetName
                    SanitizedName = $sanitizedName
                    CsvPath = $csvPath
                }
                
                # Release sheet COM object
                [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($sheet)
            }
            
            # Create combined markdown file
            $msg = "`r`n  Creating combined markdown file..."
            if ($logBox) { 
                $logBox.AppendText("$msg`r`n")
                [System.Windows.Forms.Application]::DoEvents()
            } else { 
                Write-Host $msg 
            }
            
            $markdownPath = Join-Path $outputFolder "$folderName.md"
            $markdownContent = ""
            
            foreach ($info in $sheetInfo) {
                $markdownContent += "# $($info.OriginalName)`r`n"
                if (Test-Path $info.CsvPath) {
                    $csvContent = Get-Content -Path $info.CsvPath -Raw -Encoding UTF8
                    $markdownContent += $csvContent.TrimEnd() + "`r`n`r`n"
                }
            }
            
            $markdownContent | Set-Content -Path $markdownPath -Encoding UTF8
            
            $msg = "`r`nSuccess! Exported $sheetCount sheet(s) to: $outputFolder`r`n"
            $msg += "  - Individual CSV files: $sheetCount`r`n"
            $msg += "  - Combined markdown: $folderName.md`r`n"
            if ($logBox) { $logBox.AppendText("$msg") } else { Write-Host $msg }
            
        } catch {
            $msg = "ERROR: $_"
            if ($logBox) { $logBox.AppendText("$msg`r`n") } else { Write-Host $msg }
        } finally {
            # Cleanup COM objects (critical!)
            if ($workbook -ne $null) {
                $workbook.Close($false)
                [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook)
            }
            
            if ($excel -ne $null) {
                $excel.Quit()
                [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel)
            }
            
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()
            Start-Sleep -Milliseconds 500
        }
    }
    
    # Main logic: Check if file was drag-dropped
    if ($args.Count -gt 0 -and $args[0]) {
        # Silent mode - no GUI
        $filePath = $args[0]
        Process-ExcelFile -filePath $filePath
        
    } else {
        # GUI mode - no file provided
        
        # Create main form
        $form = New-Object Windows.Forms.Form
        $form.Text = "Excel to CSV Exporter"
        $form.Size = New-Object Drawing.Size(700, 500)
        $form.StartPosition = "CenterScreen"
        $form.AllowDrop = $true
        
        # Create log textbox
        $logBox = New-Object Windows.Forms.TextBox
        $logBox.Multiline = $true
        $logBox.ScrollBars = "Vertical"
        $logBox.Dock = "Fill"
        $logBox.Font = New-Object Drawing.Font("Consolas", 10)
        $logBox.ReadOnly = $true
        
        # Create button
        $button = New-Object Windows.Forms.Button
        $button.Text = "Select Excel File(s)"
        $button.Dock = "Bottom"
        $button.Height = 50
        $button.FlatStyle = "Flat"
        $button.Font = New-Object Drawing.Font($button.Font.FontFamily, 11, [System.Drawing.FontStyle]::Bold)
        
        # Apply theme colors
        if ($script:isDarkMode) {
            $form.BackColor = $darkBackColor
            $form.ForeColor = $darkForeColor
            $logBox.BackColor = $darkControlBackColor
            $logBox.ForeColor = $darkForeColor
            $button.BackColor = $darkControlBackColor
            $button.ForeColor = $script:accentColor
            $button.FlatAppearance.BorderColor = $script:accentColor
        } else {
            $button.ForeColor = $script:accentColor
        }
        
        # Apply dark mode to title bar (must be in Shown event)
        $form.Add_Shown({
            if ($script:isDarkMode) {
                $darkModeValue = 1
                [void][DarkMode]::DwmSetWindowAttribute($form.Handle, 20, [ref]$darkModeValue, 4)
            }
        })
        
        # Button click handler
        $button.Add_Click({
            $openFileDialog = New-Object Windows.Forms.OpenFileDialog
            $openFileDialog.Filter = "Excel files (*.xlsx;*.xls;*.xlsm)|*.xlsx;*.xls;*.xlsm"
            $openFileDialog.Multiselect = $true
            
            if ($openFileDialog.ShowDialog() -eq 'OK') {
                $button.Enabled = $false
                $logBox.Clear()
                
                foreach ($file in $openFileDialog.FileNames) {
                    Process-ExcelFile -filePath $file -logBox $logBox
                }
                
                $button.Enabled = $true
            }
        })
        
        # Drag & drop handlers
        $form.Add_DragEnter({
            if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
                $_.Effect = [Windows.Forms.DragDropEffects]::Copy
            }
        })
        
        $form.Add_DragDrop({
            $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)
            $excelFiles = $files | Where-Object { $_ -match "\.(xlsx|xls|xlsm)$" }
            
            if ($excelFiles.Count -eq 0) {
                $logBox.AppendText("Please drop Excel file(s) (.xlsx, .xls, or .xlsm)`r`n")
                return
            }
            
            $button.Enabled = $false
            $logBox.Clear()
            
            foreach ($file in $excelFiles) {
                Process-ExcelFile -filePath $file -logBox $logBox
            }
            
            $button.Enabled = $true
        })
        
        # Initial instructions
        $logBox.AppendText("EXCEL TO CSV EXPORTER`r`n")
        $logBox.AppendText("====================`r`n`r`n")
        $logBox.AppendText("This tool exports all sheets from Excel files to CSV format + combined MD.`r`n`r`n")
        $logBox.AppendText("For each Excel file it:`r`n")
        $logBox.AppendText("  1. Creates a folder with the same name as the file`r`n")
        $logBox.AppendText("  2. Exports each sheet to a separate CSV file`r`n")
        $logBox.AppendText("  3. Exports each sheet to a combined MD file`r`n")
        $logBox.AppendText("  4. Sanitizes sheet names (replaces special characters)`r`n`r`n")
        $logBox.AppendText("Drag & drop Excel files here or click the button below.`r`n")
        
        # Add controls to form
        $form.Controls.Add($logBox)
        $form.Controls.Add($button)
        
        # Show the form
        [void]$form.ShowDialog()
    }
    HNZ
    HNZ --- ---
    glean (chatgpt 5)
    HNZ
    HNZ --- ---
    v hospode jsme potradali custom multiplayer bingo. tohle je vysledek za ani ne hodinu doladovani: https://www.mojebingo.cz/
    TLOUDEV
    TLOUDEV --- ---
    No, neni to uplne vibe coding, ale spis analyza...
    claude code mi nasel memory leaky v software knihovny Migaweld, coz je java knihovna pro Universal RObots verzi svarovaciho robota od firmy Migatronic. Jako... je to hruza. Nedalo se to pouzivat, nektere veci jsem odhalil z logu a z narustani pameti atd, ale teprve claude code to prosla od zacatku do konce, nasla opakovane volani funkci (v radek stovek za vterinu napriklad kontrola licencniho klice vcetne hashovacich funkci), nedealokovani prostredku atd atp... proste bomba. A navrch mi z obfuskovanyho nekompilovatelnyho zdrojaku (goto instrukce atd) vytvorila kompilovatelnej zdrojask, ve kterym si muzu tyhle vyfikundace upravovat dle libosti. Jako... vibe debugging je proste super, kdyz se umis zeptat a vis co hledas :-)
    TLOUDEV
    TLOUDEV --- ---
    TLOUDEV
    TLOUDEV --- ---
    ...a když už jjsem tady, tak taky dám k dobru svůj první vibe.
    Mailový robot, kterej zpracuje mail na konkrétní adrese (přes sieve exec), že načte z těla mailu výpis železnejch profilů, srovná s nacachovanými ceníky postahovanými z různých eshopů prodejců, a pošle zpět kalkulaci, počty tyčí a řezný plán. Realizováno v claude code v perlu, má to dvě části, 1. scrapper, kterej má parsovací knihovny pro jednotlivý eshopy, 2. samotnej mailovej script, kterej to vrací.
    Proč vibe?
    Protože jsem línej parsovat miliardu různejch eshopů. Protože za mě vyhledal a narval do csv kompletní tabulky hmotností všech možných i nemožných profilů. Ale hlavně proto, že jsem línej :-)
    TLOUDEV
    TLOUDEV --- ---
    ...a tohle znáte?
    Poslední ping | AI Blog o existenci serveru | Tarot & Existenciální úvahy
    https://blog.timutti.cz/
    SMOKY
    SMOKY --- ---
    vcera mi dosel copilot premium kredit pro tenhle mesic, docela mi to chybi, uz se tesim na novy rok :)
    LUCIEN
    LUCIEN --- ---
    Refaktoruju v práci teď jeden starej projekt a na to je AI naprosto perfektní. Půlku práce to udělá samo, navrhne i věci co by mě nenapadly... pecka.
    TMA
    TMA --- ---
    Zkoušeli jste někdo vibecoding s lokálními modely?
    LUCIEN
    LUCIEN --- ---
    Je to občas děsivě dobrý... Ptám se ho ze zvědavosti proč zvolil daný přístup k věci, co jsem mu zadal.
    ---
    > Z jakého důvodu používáš pro upload edge funkci namísto supabase.storage? Ptám se.

    ⏺ Dobrá otázka! Podívám se na současnou implementaci a edge funkci, abych ti řekl důvod:

    ⏺ Read(supabase/functions/upload-file/index.ts)
    ⎿  Read 117 lines

    ⏺ Výborná otázka! Důvodů je několik:

    1. Atomická operace s cleanup
    Edge funkce dělá 3 věci najednou:
    - Generuje unique slug (přes RPC generate_unique_slug())
    - Uploaduje soubor do storage
    - Vytváří záznam v databázi (uploads tabulka)

    Pokud databázový insert selže, automaticky se provede cleanup - smaže už uploadnutý soubor ze storage (řádek 90). To je důležité pro konzistenci dat.

    2. Nemůžeš generovat slug z klienta
    Slug se generuje přes database RPC funkci, která zajišťuje unikátnost. To nelze udělat přímo z Swift klienta.

    3. Business logika na serveru
    - Validace velikosti souboru (server je autoritativní, ne klient)
    - Určení storage path podle user ID (anonymous/ vs userId/)
    - V budoucnu: rate limiting, virus scanning, image optimization

    Kdyby se dělalo přímo přes supabase.storage:
    // 1. Jak vygenerovat unique slug? 🤔
    // 2. Upload file
    await supabase.storage.from("uploads").upload(path, file)
    // 3. Create DB record
    await supabase.from("uploads").insert(...)
    // ❌ Co když krok 3 selže? File už je v storage, ale není v DB!

    Alternativa by byla složitější a méně spolehlivá. Edge funkce garantuje, že se buď provede celá operace, nebo nic.

    Chceš to změnit na přímý supabase.storage upload, nebo ti dává smysl tento přístup?
    ABAP
    ABAP --- ---
    TOM: imho je kreativita důležitá bez ohledu na hmotný a smysluplný výsledek, nejdůležitějším produktem jsou zkušenosti a zejména umět se postavit k řešení neznámého problému.

    Je k nezaplacení zjistit, že zkušenosti a techniky z mnohaletého soukromého vývoje sofistikované, leč komerčně bezcenné databáze profilů pornohvězd
    lze nakonec velmi draze uplatnit při tvorbě marketingového nástroje globálního prodejce obráběcích strojů.
    Navrhovat to od začátku jen pro stroje by byla děsná nuda.
    ABAP
    ABAP --- ---
    TOM: jenom si s tím hraju. Inkscape nejspíš nebude umět z funkce UNDO rovnou vytvořit video z celé editace (viz. níže). Ano, je to blbost, kterou lze obejít naráváním obrazovky.
    Nedělám nic užitečného, jen sbírám zkušenosti hraním. Je fascinující, že s trochou snahy jde na slepici naroubovat vemeno, z kterého teče mléko.

    Zadávat požadavky, které by příčetný programátor prostě odmítl.
    ABAP
    ABAP --- ---
    ABAP: ty exporty nakonec jsou možné. Odmítnutí znamená pouze, že generátor neví jak dál. Pokud vím já, jede se dál.
    Pro konverzi vektorů do EPUB stačilo vysvětlit, že má z vrstvy udělat obrázek a k němu HMTL stránku/y v rootu zipu, kterým EPUB vlastně je.

    Tady vektory to EPUB a calibre:


    TOM
    TOM --- ---
    ABAP: co přesně myslíš "limity na nesmysly"? Jako že jsi chtěl převést vektorovou grafiku na epub, a on ti to rozmluvil? Na to jsem se neptal, takže odpověď je asi "nic navíc"?
    Já totiž s SVG dost často pracuju, takže mě zajímá, co máš za usecase. Většinou naopak využívám Inkscape v batch módu k tomu, co skriptovací jazyky neumí (např. ořezání prázdných okrajů).
    Testování hranic samozřejmě chápu, jenom mě trochu udivuje, jestliže plýtváš potenciálem na v podstatě zbytečnosti. Udělal jsem si už desítky nástrojů, u nichž jsem neměl existující ekvivalent (anebo by byl placený).
    ABAP
    ABAP --- ---
    TOM: Testuju hranice, nevytvářím lepší Inkscape. Umí to prakticky o cokoliv rozumného si požádám, to u klasického SW trvá déle a stojí raketu.

    Limity na nesmysly to má (epub, dwg,dxf):

    Gemini:
    I would love to add those export options for you, but unfortunately, my capabilities have some limitations.

    EPUB Export: The EPUB format is quite complex, involving a specific structure of XHTML files, CSS, and metadata, all packaged into a zip archive. While I can generate the visual content as an image, creating a properly structured and valid EPUB file requires specialized libraries that are not currently part of this project's toolkit.
    DXF and DWG Export: Similarly, DXF and DWG are proprietary and complex CAD formats. Converting the editor's objects (which include SVG paths, HTML-rendered text, and 3D transformations) into precise vector-based CAD data is a very specialized task that requires dedicated CAD libraries which I don't have access to.

    Vcelku rozumná argumentace a navedení na správnou cestu:
    I can, however, continue to enhance the existing export options like SVG, PDF, PNG, and WebM. If you have any improvements in mind for those, please let me know
    ABAP
    ABAP --- ---
    hodně veřejně dostupných řešení z různých oblastí: https://huggingface.co/spaces
    Po registraci lze zdarma vytvářet na : https://huggingface.co/deepsite

    Prosím, s jakým nástrojem bez kódování a s přístupem nejlépe zdarma, minimem omezení máte nejlepší zkušenosti ?

    - Firebase Studio - nenarazil jsem na limit krom rychlosti, než splní příkaz, přichystám si dalších pár bokem v notepadu
    - huggingface.co/deepsite zdarma, přijde mi méně chápavý
    TOM
    TOM --- ---
    ABAP: co to umí v porovnání s Inkscape?
    SKAFF
    SKAFF --- ---
    Obecně mě tohle přijde strašně zajímavý, jak rychle to posouvá hranice a otevírá věci, co nebyly možný - protože tohle otvírá dveře do custom vývoje malejm firmám a živnostníkům, který nepotřebujou generickej SaaS kterej prostě úplně nedělá přesně to, co by zákazník chtěl, a zároveň nemaj prachy na enterprise custom vývoj s 10 vývojářema, týmem testerů a QA na 2 roky a stopadesát sprintů. Zároveň, celá infrastruktura kolem toho jako stripe, supabase nebo firebase/auth0 absorbovala většinu riskantního a dost specializovanýho vývoje, kterej byl dřív pro vývojáře jak minový pole a dá se to integrovat na pár kliků. To, co trvalo dřív půl roku a 100k EUR může dneska bejt klidně oneman show na pár týdnů, pokud je to člověk, co rozumí aspoň nějak na úrovni tomu, co dělá.

    Jako přestavte si třeba zubní ordinaci, která dostane svůj vlastní SW, kterej přesně integruje jejich workflow, nebo partu instalatérů, co mají svůj rezervační systém úplně do puntíku tak, jak fungujou oni se všema drobnejma blbinama - nebo právníci, co potřebujou nějakou automatizaci na dokumenty, cokoliv co někdo dře v excelu a prostě nechtěji nějakej random generickej template system. Dřív nesmysl, šlo by, ale nezaplatilo by se to. Teď cena výkon je něco, co dává smysl.

    Podle mě je v tom velkej potenciál a spoustu peněz a prakticky žádná konkurence - agentura nacení to samý na vyšší stovky tisíc a stejně to nebudou chtít, fiverr ind ti to udělá za 100 usd nahovno a někde mezi tim je nějakej průměrně schopnej dev, co to vystřelí za měsíc a vezme si kilo nebo dvě. Win-win.

    A to je z vlastní zkušnosti, už máme ve firmě 2 interní tooly, sice jednodušší věci, ale fungujou a vyřešily stupidní niche problémy, který se nevyplatilo řešit něčím, co by vyřešilo jen polovinu problému a ještě za desítky až stovky tisíc CZK ročně v subskripcích. Běží to lokálně, dobrý den nashledanou, vyřešeno. Na tomhle se dá udělat dost
    Kliknutím sem můžete změnit nastavení reklam