[
  {
    "path": ".github/workflows/dotnet.yml",
    "content": "name: .NET\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build:\n    strategy:\n      matrix:\n        platform: [ubuntu-latest, windows-latest, macos-latest]\n    runs-on: ${{ matrix.platform }}\n    steps:\n    - uses: actions/checkout@v2\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v1\n      with:\n        dotnet-version: 5.0.x\n    #- name: Show Working Directory # does not work on windows as we are not in a powershell\n    #  run: ls -lah\n    - name: Restore dependencies\n      run: dotnet restore --configfile NuGet.Config ChiaPlotStatus.sln\n    - name: Build\n      run: dotnet build --no-restore --configuration .\\ChiaPlotStatus.sln /p:Configuration=Release /p:Platform=\"Any CPU\"\n    - name: Test\n      run: dotnet test --no-build --verbosity normal --configuration .\\ChiaPlotStatus.sln /p:Configuration=Release /p:Platform=\"Any CPU\"\n    #- name: tree\n    #  run: tree\n#    - uses: actions/upload-artifact@v2\n#      with:\n#        name: binaries-${{ matrix.platform }}\n#        path: bin/Release/net5.0\n"
  },
  {
    "path": ".gitignore",
    "content": ".vs\nChiaPlotStatus.csproj.user\nobj\nChiaPlotStatusLib/obj\nChiaPlotStatusLib/bin\nChiaPlotStatusLib/.vs\nChiaPlotStatusGUI/obj\nChiaPlotStatusGUI/bin\nChiaPlotStatusGUI/.vs\nChiaPlotStatusCli/obj\nChiaPlotStatusCli/bin\nChiaPlotStatusCli/.vs\nrelease\nNotes.txt\nwebsite\nPackaging\nProperties/PlotProgress.cs\n"
  },
  {
    "path": "ChiaPlotStatus.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Library</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <RuntimeIdentifiers>win7-x64;ubuntu.16.10-x64;linux-x64</RuntimeIdentifiers>\n    <Nullable>enable</Nullable>\n    <SignAssembly>false</SignAssembly>\n    <AssemblyOriginatorKeyFile>grayfallstown.pfx</AssemblyOriginatorKeyFile>\n    <DelaySign>false</DelaySign>\n    <ApplicationIcon></ApplicationIcon>\n    <StartupObject></StartupObject>\n    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>\n    <Authors>grayfallstown</Authors>\n    <Company>none</Company>\n    <Version>0.11.11</Version>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <WarningLevel>5</WarningLevel>\n  </PropertyGroup>\n  <ItemGroup>\n    <AvaloniaResource Include=\"ChiaPlotStatusGUI\\GUI\\Assets\\**\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Remove=\"Assets\\en - Kopieren.yaml\" />\n    <None Remove=\"Assets\\en.yaml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <AvaloniaResource Update=\"Assets\\en - Kopieren.yaml\">\n      <SubType>Component</SubType>\n    </AvaloniaResource>\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Update=\"Properties\\Resources.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n  <ItemGroup>\n    <EmbeddedResource Update=\"Properties\\Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "ChiaPlotStatus.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31129.286\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ChiaPlotStatusCli\", \"ChiaPlotStatusCli\\ChiaPlotStatusCli.csproj\", \"{677D6D3F-3693-4EA7-9FE0-AE64167BE82E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ChiaPlotStatusGUI\", \"ChiaPlotStatusGUI\\ChiaPlotStatusGUI.csproj\", \"{38F6EA6C-7E72-439B-B548-AFB5591DCEE3}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"ChiaPlotStatusLib\", \"ChiaPlotStatusLib\\ChiaPlotStatusLib.csproj\", \"{1CD172CB-184B-4C41-BB7A-4F68B61E80DE}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{677D6D3F-3693-4EA7-9FE0-AE64167BE82E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{677D6D3F-3693-4EA7-9FE0-AE64167BE82E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{677D6D3F-3693-4EA7-9FE0-AE64167BE82E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{677D6D3F-3693-4EA7-9FE0-AE64167BE82E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{38F6EA6C-7E72-439B-B548-AFB5591DCEE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{38F6EA6C-7E72-439B-B548-AFB5591DCEE3}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{38F6EA6C-7E72-439B-B548-AFB5591DCEE3}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{38F6EA6C-7E72-439B-B548-AFB5591DCEE3}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{1CD172CB-184B-4C41-BB7A-4F68B61E80DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1CD172CB-184B-4C41-BB7A-4F68B61E80DE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1CD172CB-184B-4C41-BB7A-4F68B61E80DE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1CD172CB-184B-4C41-BB7A-4F68B61E80DE}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{91BD97DE-BA91-4BED-97C6-1AC8B306FFA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{91BD97DE-BA91-4BED-97C6-1AC8B306FFA1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{91BD97DE-BA91-4BED-97C6-1AC8B306FFA1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{91BD97DE-BA91-4BED-97C6-1AC8B306FFA1}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {75F20C1E-B71F-4C68-9945-E3C53E1C74D1}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "ChiaPlotStatusCli/CLI/CLI.cs",
    "content": "﻿using ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatus.Logic.Utils;\nusing CommandLine;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.CLI\n{\n    public class ChiaPlotStatusCLI\n    {\n        public static void Main(string[] args)\n        {\n            Parser parser = new((parserSettings) => {\n                parserSettings.CaseSensitive = false;\n                parserSettings.AutoVersion = false;\n                parserSettings.AutoHelp = true;\n                parserSettings.HelpWriter = Console.Out;\n            });\n            parser.ParseArguments<CliOptions>(args)\n                   .WithParsed<CliOptions>(options =>\n                   {\n                       do\n                       {\n                           GenerateReport(options);\n                           Console.Out.WriteLine(\"File '\" + options.File + \"' written\");\n                           if (options.KeepUpdating)\n                           {\n                               int seconds = 10;\n                               Console.Out.WriteLine(\"Updating file in \" + seconds + \" seconds...\");\n                               Thread.Sleep(seconds * 1000);\n                           }\n                       }\n                       while (options.KeepUpdating);\n                   });\n        }\n\n        public static void GenerateReport(CliOptions options)\n        {\n            ChiaPlotStatus PlotManager = SetupChiaPlotStatus(options);\n            Filter filter = SetupFilter(options);\n            string sortProperty = options.SortProperty;\n            if (string.IsNullOrEmpty(sortProperty))\n                sortProperty = PlotManager.Settings.SortProperty;\n            Console.Out.WriteLine(\"Sorting by \" + sortProperty);\n            List<(PlotLog, PlotLogReadable)> plotLogs = PlotManager.PollPlotLogs(options.SortProperty, options.SortAsc, options.Search, filter);\n            ExportToFile(options, plotLogs);\n        }\n\n        private static ChiaPlotStatus SetupChiaPlotStatus(CliOptions options)\n        {\n            var configFolder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Path.DirectorySeparatorChar;\n            Settings Settings = new Settings(configFolder + \"ChiaPlotStatu.config.json\");\n            Settings.Load();\n            ChiaPlotStatus PlotManager = new(Settings);\n            List<string> folders = options.LogFolders.ToList();\n            if (folders.Count() == 0)\n            {\n                if (PlotManager.Settings.LogDirectories.Count == 0)\n                    PlotManager.AddDefaultLogFolders();\n            }\n            else\n            {\n                // override LogFolders from settings file\n                PlotManager.Settings.LogDirectories.Clear();\n                foreach (var folder in folders)\n                    PlotManager.AddLogFolder(folder);\n            }\n\n            return PlotManager;\n        }\n\n        private static Filter SetupFilter(CliOptions options)\n        {\n            Filter filter = new();\n            filter.HideHealthy = options.HideHealthy;\n            filter.HideFinished = options.HideFinished;\n            filter.HidePossiblyDead = options.HidePossiblyDead;\n            filter.HideConfirmedDead = options.HideConfirmedDead;\n            return filter;\n        }\n\n        private static void ExportToFile(CliOptions options, List<(PlotLog, PlotLogReadable)> plotLogs)\n        {\n            Exporter exporter = new Exporter(plotLogs);\n            try\n            {\n                switch (options.Format.ToLower())\n                {\n                    case \"json\":\n                        exporter.ToJson(options.File, options.Raw);\n                        break;\n                    case \"yaml\":\n                        exporter.ToYaml(options.File, options.Raw);\n                        break;\n                    case \"csv\":\n                        exporter.ToCsv(options.File, options.Raw);\n                        break;\n                    default:\n                        throw new NotImplementedException(\"File format '\" + options.Format + \"' not supported\");\n                }\n            }\n            catch (Exception e)\n            {\n                Console.Error.WriteLine(\"Could not write file '\" + options.File + \"': \" + e.Message);\n                Console.Error.WriteLine(e.StackTrace);\n                System.Environment.Exit(1);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusCli/CLI/CliOptions.cs",
    "content": "﻿using CommandLine;\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.CLI\n{\n    public class CliOptions\n    {\n        [Option('o', \"outfile\", Required = true, HelpText = \"The file to write to\")]\n        public string File { get; set; }\n\n        [Option('f', \"format\", Required = true, HelpText = \"The format to use while writing the file. Valid values are json, yaml and csv\")]\n        public string Format { get; set; }\n\n        [Option('r', \"raw\", Required = false, HelpText = \"Write raw, unformatted values instead of human readable ones.\")]\n        public bool Raw { get; set; }\n\n        [Option('l', \"log-folders\", Required = false, Separator = ',', HelpText = \"The folders where logs can be found, comma separated. Uses default folder when empty\")]\n        public IEnumerable<string> LogFolders { get; set; }\n\n        [Option('s', \"sort-property\", Required = false, HelpText = \"The property you want the plotlogs sorted by\")]\n        public string SortProperty { get; set; }\n\n        [Option('a', \"sort-asc\", Required = false, HelpText = \"Sort ascending\")]\n        public bool SortAsc { get; set; }\n\n        [Option(\"search\", Required = false, HelpText = \"Filter plotlogs by this search terms. You filter for your temp1 folder for example.\")]\n        public string Search { get; set; }\n\n        [Option(\"hide-finished\", Required = false, HelpText = \"Hide finished plots\")]\n        public bool HideFinished { get; set; }\n\n        [Option(\"hide-possibly-dead\", Required = false, HelpText = \"Hide possibly dead plots\")]\n        public bool HidePossiblyDead { get; set; }\n\n        [Option(\"hide-confirmed-dead\", Required = false, HelpText = \"Hide confirmed dead plots\")]\n        public bool HideConfirmedDead { get; set; }\n\n        [Option(\"hide-healthy\", Required = false, HelpText = \"Hide healthy plots\")]\n        public bool HideHealthy { get; set; }\n\n        [Option(\"keep-updating\", Required = false, HelpText = \"Keep updating the file every 10 seconds\")]\n        public bool KeepUpdating { get; set; }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusCli/ChiaPlotStatusCli.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <RuntimeIdentifiers>win7-x64;ubuntu.16.10-x64;linux-x64</RuntimeIdentifiers>\n    <StartupObject>ChiaPlotStatus.CLI.ChiaPlotStatusCLI</StartupObject>\n    <ApplicationIcon>Icon - Color changed.ico</ApplicationIcon>\n    <Authors>grayfallstown</Authors>\n    <Company>grayfallstown</Company>\n    <Version>0.11.11</Version>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageReference Include=\"CommandLineParser\" Version=\"2.8.0\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ChiaPlotStatusLib\\ChiaPlotStatusLib.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "ChiaPlotStatusGUI/ChiaPlotStatusGUI.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>WinExe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <RuntimeIdentifiers>win7-x64;ubuntu.16.10-x64;linux-x64</RuntimeIdentifiers>\n    <Nullable>enable</Nullable>\n    <StartupObject>ChiaPlotStatus.Program</StartupObject>\n    <AssemblyName>ChiaPlotStatus</AssemblyName>\n    <PackageId>ChiaPlotStatusGUI</PackageId>\n    <Company>grayfallstown</Company>\n    <Authors>grayfallstown</Authors>\n    <ApplicationIcon>Icon - Color changed.ico</ApplicationIcon>\n    <Version>0.11.11</Version>\n  </PropertyGroup>\n  <ItemGroup>\n    <AvaloniaResource Include=\"GUI\\Assets\\**\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"chia-plot-status.desktop\" CopyToPublishDirectory=\"Always\" LinuxFileMode=\"0755\">\n      <LinuxPath>/usr/share/applications/chia-plot-status.desktop</LinuxPath>\n    </Content>\n  </ItemGroup>\n  <ItemGroup>\n    <DebDotNetDependencies Include=\"libc4 | libc5 | libc6 | libc7 | libc8 | libc9 | libc10 | libc11 | libc12 | libc13\" />\n    <DebDotNetDependencies Include=\"libgcc1 | libgcc2 | libgcc3 | libgcc4 | libgcc5 | libgcc6 | libgcc7 | libgcc8 | libgcc9\" />\n    <DebDotNetDependencies Include=\"libgssapi-krb5-2\" />\n    <DebDotNetDependencies Include=\"libstdc++12 | libstdc++11 | libstdc++10 | libstdc++9 | libstdc++9 | libstdc++7 | libstdc++6\" />\n    <DebDotNetDependencies Include=\"zlib1g\" />\n    <DebDotNetDependencies Include=\"libssl1.3 | libssl1.1.1 | libssl1.2 | libssl1.1 | libssl1.0.2 | libssl1.0.1 | libssl1.0.0 | libssl0.9.8\" />\n    <DebDotNetDependencies Include=\"libicu74 | libicu73 | libicu72 | libicu71 | libicu70 | libicu69 | libicu68 | libicu67 |libicu66 | libicu65 | libicu64 | libicu63 | libicu62 | libicu61 | libicu60 | libicu59 | libicu58 | libicu57 | libicu56 | libicu55 | libicu54 | libicu53 | libicu52\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"chia-plot-status.png\" CopyToPublishDirectory=\"Always\" LinuxFileMode=\"0755\">\n      <LinuxPath>/usr/share/pixmaps/chia-plot-status.png</LinuxPath>\n    </Content>\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Avalonia\" Version=\"0.10.5\" />\n    <PackageReference Include=\"Avalonia.Controls.DataGrid\" Version=\"0.10.5\" />\n    <PackageReference Include=\"Avalonia.Desktop\" Version=\"0.10.5\" />\n    <PackageReference Include=\"Avalonia.Diagnostics\" Version=\"0.10.5\" />\n    <PackageReference Include=\"Avalonia.ReactiveUI\" Version=\"0.10.5\" />\n    <PackageReference Include=\"Octokit\" Version=\"0.50.0\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\ChiaPlotStatusLib\\ChiaPlotStatusLib.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Update=\"GUI\\App.axaml.cs\">\n      <DependentUpon>%(Filename)</DependentUpon>\n    </Compile>\n    <Compile Update=\"GUI\\Views\\DonationDialog.axaml.cs\">\n      <DependentUpon>%(Filename)</DependentUpon>\n    </Compile>\n    <Compile Update=\"GUI\\Views\\MainWindow.axaml.cs\">\n      <DependentUpon>%(Filename)</DependentUpon>\n    </Compile>\n    <Compile Update=\"GUI\\Views\\HarvestDialog.axaml.cs\">\n      <DependentUpon>HarvestDialog.axaml</DependentUpon>\n    </Compile>\n    <Compile Update=\"GUI\\Views\\NoteDialog.axaml.cs\">\n      <DependentUpon>NoteDialog.axaml</DependentUpon>\n    </Compile>\n    <Compile Update=\"GUI\\Views\\ChiaPlotterDialog.axaml.cs\">\n      <DependentUpon>ChiaPlotterDialog.axaml</DependentUpon>\n    </Compile>\n    <Compile Update=\"GUI\\Views\\StatisticsDialog.axaml.cs\">\n      <DependentUpon>StatisticsDialog.axaml</DependentUpon>\n    </Compile>\n    <Compile Update=\"GUI\\Views\\MarkOfDeathDialog.axaml.cs\">\n      <DependentUpon>%(Filename)</DependentUpon>\n    </Compile>\n    <Compile Update=\"GUI\\Views\\UpdateDialog.axaml.cs\">\n      <DependentUpon>%(Filename)</DependentUpon>\n    </Compile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "ChiaPlotStatusGUI/ChiaPlotStatusGUI.csproj.user",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup />\n</Project>"
  },
  {
    "path": "ChiaPlotStatusGUI/Directory.Build.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <PackageReference Include=\"Packaging.Targets\">\n      <Version>0.1.189-*</Version>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/App.axaml",
    "content": "<Application xmlns=\"https://github.com/avaloniaui\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n             xmlns:local=\"using:ChiaPlotStatus\"\n             x:Class=\"ChiaPlotStatus.App\">\n    <Application.DataTemplates>\n        <local:ViewLocator/>\n    </Application.DataTemplates>\n\n    <Application.Styles>\n\t\t<StyleInclude Source=\"avares://Avalonia.Themes.Default/Accents/BaseLight.xaml\"/>\n\t\t<StyleInclude Source=\"avares://Avalonia.Themes.Default/DefaultTheme.xaml\"/>\n\t\t<StyleInclude Source=\"avares://Avalonia.Controls.DataGrid/Themes/Default.xaml\"/>\n\t\t<!--\n\t\t<FluentTheme Mode=\"Light\"/>\n\t\t<StyleInclude Source=\"avares://Avalonia.Themes.Default/Accents/BaseLight.xaml\"/>\n\t\t<StyleInclude Source=\"avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml\"/>\n\t\t-->\n    </Application.Styles>\n</Application>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/App.axaml.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls.ApplicationLifetimes;\nusing Avalonia.Markup.Xaml;\nusing ChiaPlotStatus.ViewModels;\nusing ChiaPlotStatus.Views;\n\nnamespace ChiaPlotStatus\n{\n    public class App : Application\n    {\n        public override void Initialize()\n        {\n            AvaloniaXamlLoader.Load(this);\n        }\n\n        public override void OnFrameworkInitializationCompleted()\n        {\n            if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)\n            {\n                desktop.MainWindow = new MainWindow\n                {\n                    DataContext = new MainWindowViewModel(),\n                };\n            }\n\n            base.OnFrameworkInitializationCompleted();\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Assets/en.yaml",
    "content": "﻿Name: English\n\n\nFields:\n    Search: \"Search\"\n    Light: \"Light\"\n    Dark: \"Dark\"\n    LogFolder: \"Log Folders\"\n    RawExport: \"Raw Export\"\n    HideHealthy: \"Hide healthy\"\n    HideFinished: \"Hide finished\"\n    HidePossiblyDead: \"Hide possibly Dead\"\n    HideConfirmedDead: \"Hide confirmed Dead\"\n\nButtons:\n    Add: \"Add\"\n    Remove: \"Remove\"\n    Json: \"Json\"\n    Yaml: \"Yaml\"\n    CSV: \"CSV\"\n    MarkAsDead: \"Mark as dead\"\n    SelectAllConcerningCommand: \"Select concerning\"\n    SelectAllPossiblyDeadCommand: \"Selected possibly dead\"\n    MarkSelectionAsDead: \"Mark selected logs as dead\"\n    UnmarkAsDead: \"Unmark as dead\"\n    Abort: \"Cancel\"\n    Copy: \"Copy\"\n    Save: \"Save\"\n\nColumns:\n    RuntimeMinutes: \"Time Frame Minutes\"\n    PoolPuzzleHash: \"Pool Puzzle / Address\"\n    Tmp1Drive: \"Tmp1\"\n    Tmp2Drive: \"Tmp2\"\n    DestDrive: \"Destination\"\n    Errors: \"Errors\"\n    PID: \"PID\"\n    Progress: \"Progress\"\n    TimeRemaining: \"Remaining 🕐\"\n    RunTimeSeconds: \"Runtime 🕐\"\n    ETA: \"ETA\"\n    CurrentTable: \"Cur. Table\"\n    CurrentBucket: \"Cur. Bucket\"\n    CurrentPhase: \"Cur. Phase\"\n    Phase1Cpu: \"P1 CPU\"\n    Phase2Cpu: \"P2 CPU\"\n    Phase3Cpu: \"P3 CPU\"\n    Phase4Cpu: \"P4 CPU\"\n    Phase1Seconds: \"Phase 1 🕐\"\n    Phase2Seconds: \"Phase 2 🕐\"\n    Phase3Seconds: \"Phase 3 🕐\"\n    Phase4Seconds: \"Phase 4 🕐\"\n    CopyTimeSeconds: \"Copy 🕐\"\n    TotalSeconds: \"Total 🕐\"\n    PlotSize: \"K-Size\"\n    Threads: \"Threads\"\n    Buffer: \"Buffer\"\n    Buckets: \"Buckets\"\n    StartDate: \"Started\"\n    FinishDate: \"Finished\"\n    PlotName: \"Plot Name\"\n    LogFolder: \"Log Folder\"\n    LogFile: \"Log File\"\n    ApproximateWorkingSpace: \"Workingspace\"\n    FinalFileSize: \"Final Size\"\n    Health: \"Health\"\n    LastLogLine: \"Last Log Line\"\n    PlaceInLogFile: \"Nr\"\n    Phase1AvgTimeNeed: \"Phase 1 avg 🕐\"\n    Phase2AvgTimeNeed: \"Phase 2 avg 🕐\"\n    Phase3AvgTimeNeed: \"Phase 3 avg 🕐\"\n    Phase4AvgTimeNeed: \"Phase 4 avg 🕐\"\n    CopyTimeAvgTimeNeed: \"Copy avg 🕐\"\n    TotalAvgTimeNeed: \"Total avg 🕐\"\n    Phase1Completed: \"Sample Size\"\n    Note: \"Note/Tags\"\n    TotalEligiblePlots: \"Eligible Plots\"\n    FoundProofs: \"Found Proofs\"\n    BestLookupTime: \"Best Lookup Time\"\n    WorstLookupTime: \"Worst Lookup Time\"\n    AvgLookupTime: \"Avg Lookup Time\"\n    FilterRatio: \"Filter Ratio\"\n    TotalPlots: \"Total Plots\"\n    ChallengesPerMinute: \"Challenges per Minute\"\n    AvgHeat: \"Avg Heat\"\n    MaxHeat: \"Max Heat\"\n    MinHeat: \"Min Heat\"\n    AvgEligiblePlots: \"Avg eligible Plots\"\n\n\nTooltips:\n    RuntimeMinutes: \"This statistic uses the last n minutes from the log for its calculations\"\n    PoolPuzzleHash: \"The Pool Puzzle Hash if you plot with madmax and the pool address if you still use chiapos.\"\n    JsonExport: \"Export shown data to Json. Check <Raw Export> if you want plain unformatted numbers.\"\n    YamlExport: \"Export shown data to Yaml. Check <Raw Export> if you want plain unformatted numbers.\"\n    CsvExport: \"Export shown data to Csv. Check <Raw Export> if you want plain unformatted numbers.\"\n    RawExport: \"Export shown data as plain unformatted numbers.\"\n    Tmp1Drive: null\n    Tmp2Drive: null\n    DestDrive: \"Directory where the plot file was/will be written to.\"\n    Errors: >\n        Errors that occured in the plotting process while reading from or writing data to disk.\n        The chia plotter will retry in case of such an error after a short Seconds. One is not that bad.\n        If you use external harddrives or network attached Storage this usally means the connection\n        dropped. Reattach the device and chia will continue. If the error count keeps rising you need to troubleshoot.\n    PID: >\n        Process ID if the running plotter process. You can use this nr to find and kill the process if it misbehaves.\n    Progress: >\n        Shows the progression defined by the number of steps done vs the number of steps left to completion.\n        The number of steps tells you nothing about how long the process will take to completion.\n    TimeRemaining: >\n        An estimate on how long it will take for the plot to complete. It is based on the plots progress and all\n        the data extracted from your finished plots. It will try to use the data of those plots that match the\n        configuration of that plot most closely to make a better prediction if you mix hard disks, ssd, internal\n        and external drives and even network attached storage.\n    RunTimeSeconds: >\n        \"How long the process is running already\"\n    ETA: >\n        An estimate on when the plotting process completes formatted MM/dd HH:mm. It is based on the plots\n        progress and all the data extracted from your finished plots. It will try to use the data of those plots\n        that match the configuration of that plot most closely to make a better prediction if you mix hard disks,\n        ssd, internal and external drives and even network attached storage.\n    CurrentTable: >\n        The table number currently worked on. On phase 1 and 3 it will start with table 1 and work its way up to 7. In\n        Phase 2 it will start with table 7 and work its way back to table 1. An arrow shows in which way it currently\n        progresses.\n    CurrentBucket: >\n        The Chia plotter will work through each table in the phases 1 and 3 and will process each bucket in each table.\n        This shows which bucket in the current table is currently worked on.\n    CurrentPhase: >\n        Shows in which of the four phases the plotting process is. It does not go back to a previous phase.\n    Phase1Cpu: >\n        \"CPU Usage during phase 1.\"\n    Phase2Cpu: >\n        \"CPU Usage during phase 2.\"\n    Phase3Cpu: >\n        \"CPU Usage during phase 3.\"\n    Phase4Cpu: >\n        \"CPU Usage during phase 4.\"\n    Phase1Seconds: >\n        The time this plot process took to complete phase 1.\n        This is the only phase with multithreading enabled and the only one you can optimize with the threads option.\n    Phase2Seconds: >\n        The time this plot process took to complete phase 2\n    Phase3Seconds: >\n        The time this plot process took to complete phase 3\n    Phase4Seconds: >\n        The time this plot process took to complete phase 4\n    CopyTimeSeconds: >\n        Unofficial phase 5.\n        The time this plot process took to copy the final file to the destination.\n        It gets copied from temp folder 2 to destination unless temp folder 2 and the destination are identical.\n        If you are using a remote destination you can optimize this process by using a local ssd or even just a\n        hdd as destination and then moving the plot to its remote destination by other means.\n        This way your plotting process is completed before the plot slowly gets moved to its final destination\n        and the plotter can already begin the next plot.\n        Google \"windows task scheduler\" or \"linux chron jobs\" to see how to set up automatic jobs that move the\n        files for you.\n    TotalSeconds: >\n        The time this plot process took to fully complete\n    PlotSize: >\n        The k-size of the plot. Usally 32, which produces a 100GB plot file. Apparently there is very little\n        reason to use a larger k-size for now.\n    Threads: >\n        The number of threads used to complete phase 1. As of now the other phases are not multithreaded\n        and will only use one cpu core, tweaking this only affects phase 1\n    Buffer: >\n        This buffer size the plotter uses. It is used to sort the data within the buckets in memory.\n        It will resort to a different sort algorithm which is slower on most tables. Too small buffer\n        sizes will slow down the plotter, too large ones will bring no additional benefit, but lower\n        the number on plotting processes you can run in parallel with the ram installed in your\n        system.\n    Buckets: >\n        The number of parts a table will be split into. Each bucket is sorted individually. Each bucket\n        gets written in its own file.\n    StartDate: >\n        When the plotting process was started.\n    FinishDate: >\n        When the plotting process finished.\n    PlotName: >\n        Name of the final plot file.\n    LogFolder: >\n        The folder in which this log file in stored. If you have multiple log folder for multiple rigs,\n        this tells you which rig it is from.\n    LogFile: >\n        The name of the logfile.\n    ApproximateWorkingSpace: >\n        An estimate on how much temporary space was used during the creation of the plot.\n    FinalFileSize: >\n        The size of the finished plot file. Varies little over the same k-size.\n    Health: >\n        Read catefully! Don't be rushed into making a decision here!\n        This feature requires existing logs of finished plots from the same log directory\n        to run correctly or it uses default warning thresholds that are pretty much diced at the moment!\n        If your system does not update \"last modfied at\" on files (some deactivate it on SSDs) ignore\n        the warnings with time in it. Chia Plot Status doesn't know any better.\n\n\n        An Estimate on the processes health. In some cases it is not clear if the process is still running,\n        this can happen especially in phase 4.\n\n\n        \"⚠ Temp Errors\": Usually not so serious, but you need to take action.\n        It means the last line in the logfile is a read or write error (look at Errors column).\n        You might be out of disk space for temp1, temp2 or the destination, so free up some space.\n        Another reason could be your external hard disk / network attached storage is detached or the\n        connection is flaky.\n        The plotter retries every 5 minutes, so it continues once you fixed the error.\n\n\n        \"⚠ Slow 20m/15m\": Usually not serious, just have an eye on it.\n        It means last update to the logfile was 20 minutes ago, but Chia Plot Status expected a new log line\n        within 15 minutes.\n        Process is likely still running.\n        Maybe you gave your temp drives more IO than they can handle this time?\n        If you only have finished plots that ran on SSDs and this one is on a HDD now, it is expected to be\n        slower and throw that warning.\n        Chia Plot Status will learn that this drive is slower once this plot is done.\n\n\n        \"⚠ Dead? 40m/10m\": This is scary. It means last update to the logFile was way too long ago.\n        Process might be still running!\n        If your system is not really slow/overtaxed at the moment the process could be dead (check to be sure).\n        Chia Plot Status considers it possibly dead until it logs something again.\n\n\n        \"✗ Dead (m)\": You manually marked this process as dead.\n\n\n        \"✗ Dead\": Ouch. The chia plotter produced a fatal error. There will be something like \"Caught plotting\n        error\" in your logfile or it means the processes is not done and a new process appeared in the same logfile.\n        If your logging is not messed up and logging multiple processes in parallel to the same file this means\n        the process is dead.\n    LastLogLine: >\n        Last line in this plots log file\n    PlaceInLogFile: >\n        When using --num 20 to plot 20 plots in a row this shows you the current plot nr on the left and the\n        size of the queue on the right\n    Note: >\n        Here you can add notes and tags to group plot logs and compare performance.\n\n    TotalEligiblePlots: >\n        Plots that could have provided proofs for the challanges (for a reward).\n        1/512 chance per plot, per challenge.\n        Maybe they did actually contain a proof, maybe not.\n        Even if, this does not mean you earned Chia as the best proof provided by anyone gets rewarded, not everyone who delivers a proof.\n    AvgEligiblePlots: >\n        Average number of plots that can provide proofs for the challanges (for a reward) given in the timeframe from begin to end of your logfiles.\n        1/512 chance per plot, therefor should be somewhere around 0.001953125 times the nr of total plots.\n        If the number is higher, lucky you.\n        If it is a lot lower, well something is wrong unless you do not have many plots, like less than 50 or so or if you do not have a lot of data.\n        if you have just set the log level to INFO, this means practically nothing.\n        Wait a few hours to see any relevant value.\n        The less plots you have, the longer it takes for this value to become relevant.\n        Do you have a thousand plots? This value could become meaningfull after one to three hours.\n        Do you have less than 100 plots? Wait at least a day, maybe a week.\n    FoundProofs: >\n        Number of Proofs found.\n        A found proof does not necessarily mean you won chia, as the best submitted proof is picked.\n    BestLookupTime: >\n        Lookup time increases when a plot does actually contain proofs.\n        Best lookup time does therefor not tell you much unless it is high.\n    WorstLookupTime: >\n        Lookup time increases when a plot does actually contain proofs.\n        You have 30 seconds to submit a proof once a challenge is started.\n        Keep in mind that the proof needs to be transfered to a lot of nodes to be successfull.\n        Because of this the worst lookup time should not be larger that 5 seconds.\n    AvgLookupTime: >\n        Lookup time increases when a plot does actually contain proofs.\n        You have 30 seconds to submit a proof once a challenge is started.\n        Keep in mind that the proof needs to be transfered to a lot of nodes to be successfull.\n        Because of this the avg lookup time should not be larger that ~2 seconds.\n    FilterRatio: >\n        Number of elgible plots divided by the total nr of plots.\n        Shout be somewhere around 1/512 (0.001953125).\n        Higher is better, way lower means something is seriously wrong.\n    TotalPlots: >\n        Total nr of plots that harvester uses to harvest.\n    ChallengesPerMinute: >\n        Number of challenges this harvester handled per minute\n    AvgHeat: >\n        The nearer this gets to 5 (or even above 5) the worse your harvester works.\n        NAS does not work well with chia.\n    MaxHeat: >\n        The nearer this gets to 5 (or even above 5) the worse your harvester works, but Avg Heat is more important.\n        NAS does not work well with chia.\n    MinHeat: >\n        Should be as low as possible.\n        The nearer this gets to 5 (or even above 5) the worse your harvester works, but Avg and Max Heat are more important.\n        NAS does not work well with chia.\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Models/HighlightedText.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.GUI.Models\n{\n    public class HighlightedText\n    {\n        public string Text { get; set; }\n        public bool Level0 { get; set; }\n        public bool Level1 { get; set; }\n        public bool Level2 { get; set; }\n        public bool Level3 { get; set; }\n        public bool Level4 { get; set; }\n        public bool Level5 { get; set; }\n\n        public HighlightedText(string Text, int level)\n        {\n            this.Text = Text;\n            this.Level0 = level == 0;\n            this.Level1 = level == 1;\n            this.Level2 = level == 2;\n            this.Level3 = level == 3;\n            this.Level4 = level == 4;\n            this.Level5 = level == 5;\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Models/PlotCounts.cs",
    "content": "﻿using ChiaPlotStatus;\nusing ChiaPlotStatus.Logic.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusGUI.GUI.Models\n{\n    public class PlotCounts\n    {\n        public int PlotsInPhase1 { get; set; } = 0;\n        public int PlotsInPhase2 { get; set; } = 0;\n        public int PlotsInPhase3 { get; set; } = 0;\n        public int PlotsInPhase4 { get; set; } = 0;\n        public int PlotsInPhase5 { get; set; } = 0;\n        public int Finished { get; set; } = 0;\n        public int Running { get; set; } = 0;\n        public int Concerning { get; set; } = 0;\n        public int Failed { get; set; } = 0;\n\n        public PlotCounts() { }\n\n        public PlotCounts(List<(PlotLog, PlotLogReadable)> plotLogs)\n        {\n            foreach (var tuple in plotLogs)\n            {\n                var plotLog = tuple.Item1;\n                var done = tuple.Item1.CurrentPhase == 6;\n                switch (plotLog.Health)\n                {\n                    case Healthy:\n                        if (done)\n                            Finished++;\n                        else\n                            handlePhase(plotLog);\n                        break;\n                    case TempError:\n                    case Concerning c:\n                        Concerning++;\n                        handlePhase(plotLog);\n                        break;\n                    case PossiblyDead p:\n                        Concerning++;\n                        Failed++;\n                        handlePhase(plotLog);\n                        break;\n                    case ConfirmedDead c:\n                        Failed++;\n                        break;\n                }\n            }\n        }\n\n        private void handlePhase(PlotLog plotLog)\n        {\n            Running++;\n            switch (plotLog.CurrentPhase)\n            {\n                case 1:\n                    PlotsInPhase1++;\n                    break;\n                case 2:\n                    PlotsInPhase2++;\n                    break;\n                case 3:\n                    PlotsInPhase3++;\n                    break;\n                case 4:\n                    PlotsInPhase4++;\n                    break;\n                case 5:\n                    PlotsInPhase5++;\n                    break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Models/Translation.cs",
    "content": "﻿using Avalonia;\nusing Avalonia.Platform;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing YamlDotNet.Serialization;\n\nnamespace ChiaPlotStatus.GUI.Models\n{\n    public static class Translation\n    {\n        public static Dictionary<string, Language> LoadLanguages()\n        {\n            var deserializer = new DeserializerBuilder().Build();\n            Dictionary<string, Language> langs = new();\n            var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();\n            foreach (var lang2 in new string[] { \"en\" })\n            {\n                System.IO.Stream filestream = assets.Open(new Uri(\"avares://ChiaPlotStatus/GUI/Assets/\" + lang2 + \".yaml\"));\n                StreamReader reader = new StreamReader(filestream);\n                string yaml = reader.ReadToEnd();\n                var lang = deserializer.Deserialize<Language>(yaml);\n                langs.Add(lang.Name, lang);\n            }\n            return langs;\n        }\n\n    }\n\n\n    public class Language\n    {\n        public string Name { get; set; }\n        public Tooltips Tooltips { get; set; }\n        public Columns Columns { get; set; }\n        public Fields Fields { get; set; }\n        public Buttons Buttons { get; set; }\n    }\n\n\n    public class Fields\n    {\n        public string Search { get; set; } = \"\";\n        public string Light { get; set; } = \"\";\n        public string Dark { get; set; } = \"\";\n        public string LogFolder { get; set; } = \"\";\n        public string RawExport { get; set; } = \"\";\n        public string HideHealthy { get; set; } = \"\";\n        public string HideFinished { get; set; } = \"\";\n        public string HidePossiblyDead { get; set; } = \"\";\n        public string HideConfirmedDead { get; set; } = \"\";\n    }\n\n\n    public class Buttons\n    {\n        public string Add { get; set; } = \"\";\n        public string Remove { get; set; } = \"\";\n        public string Json { get; set; } = \"\";\n        public string Yaml { get; set; } = \"\";\n        public string CSV { get; set; } = \"\";\n        public string MarkAsDead { get; set; } = \"\";\n        public string SelectAllConcerningCommand { get; set; } = \"\";\n        public string SelectAllPossiblyDeadCommand { get; set; } = \"\";\n        public string MarkSelectionAsDead { get; set; } = \"\";\n        public string UnmarkAsDead { get; set; } = \"\";\n        public string Abort { get; set; } = \"\";\n        public string Copy { get; set; } = \"\";\n        public string Save { get; set; } = \"\";\n    }\n\n    public class Tooltips\n    {\n        public string JsonExport { get; set; } = \"\";\n        public string YamlExport { get; set; } = \"\";\n        public string CsvExport { get; set; } = \"\";\n        public string RawExport { get; set; } = \"\";\n        public string Tmp1Drive { get; set; } = \"\";\n        public string Tmp2Drive { get; set; } = \"\";\n        public string DestDrive { get; set; } = \"\";\n        public string Errors { get; set; } = \"\";\n        public string PID { get; set; } = \"\";\n        public string Progress { get; set; } = \"\";\n        public string TimeRemaining { get; set; } = \"\";\n        public string RunTimeSeconds { get; set; } = \"\";\n        public string ETA { get; set; } = \"\";\n        public string CurrentTable { get; set; } = \"\";\n        public string CurrentBucket { get; set; } = \"\";\n        public string CurrentPhase { get; set; } = \"\";\n        public string Phase1Cpu { get; set; } = \"\";\n        public string Phase2Cpu { get; set; } = \"\";\n        public string Phase3Cpu { get; set; } = \"\";\n        public string Phase4Cpu { get; set; } = \"\";\n        public string Phase1Seconds { get; set; } = \"\";\n        public string Phase2Seconds { get; set; } = \"\";\n        public string Phase3Seconds { get; set; } = \"\";\n        public string Phase4Seconds { get; set; } = \"\";\n        public string CopyTimeSeconds { get; set; } = \"\";\n        public string TotalSeconds { get; set; } = \"\";\n        public string PlotSize { get; set; } = \"\";\n        public string Threads { get; set; } = \"\";\n        public string Buffer { get; set; } = \"\";\n        public string Buckets { get; set; } = \"\";\n        public string StartDate { get; set; } = \"\";\n        public string FinishDate { get; set; } = \"\";\n        public string PlotName { get; set; } = \"\";\n        public string LogFolder { get; set; } = \"\";\n        public string LogFile { get; set; } = \"\";\n        public string ApproximateWorkingSpace { get; set; } = \"\";\n        public string FinalFileSize { get; set; } = \"\";\n        public string Health { get; set; } = \"\";\n        public string LastLogLine { get; set; } = \"\";\n        public string PlaceInLogFile { get; set; } = \"\";\n        public string Note { get; set; } = \"\";\n        public string TotalEligiblePlots { get; set; } = \"\";\n        public string AvgEligiblePlots { get; set; } = \"\";\n        public string FoundProofs { get; set; } = \"\";\n        public string BestLookupTime { get; set; } = \"\";\n        public string WorstLookupTime { get; set; } = \"\";\n        public string AvgLookupTime { get; set; } = \"\";\n        public string FilterRatio { get; set; } = \"\";\n        public string TotalPlots { get; set; } = \"\";\n        public string ChallengesPerMinute { get; set; } = \"\";\n        public string AvgHeat { get; set; } = \"\";\n        public string MaxHeat { get; set; } = \"\";\n        public string MinHeat { get; set; } = \"\";\n        public string PoolPuzzleHash { get; set; } = \"\";\n        public string RuntimeMinutes { get; set; } = \"\";\n    }\n\n    public class Columns\n    {\n        public string Tmp1Drive { get; set; } = \"\";\n        public string Tmp2Drive { get; set; } = \"\";\n        public string DestDrive { get; set; } = \"\";\n        public string Errors { get; set; } = \"\";\n        public string PID { get; set; } = \"\";\n        public string Progress { get; set; } = \"\";\n        public string TimeRemaining { get; set; } = \"\";\n        public string RunTimeSeconds { get; set; } = \"\";\n        public string ETA { get; set; } = \"\";\n        public string CurrentTable { get; set; } = \"\";\n        public string CurrentBucket { get; set; } = \"\";\n        public string CurrentPhase { get; set; } = \"\";\n        public string Phase1Cpu { get; set; } = \"\";\n        public string Phase2Cpu { get; set; } = \"\";\n        public string Phase3Cpu { get; set; } = \"\";\n        public string Phase4Cpu { get; set; } = \"\";\n        public string Phase1Seconds { get; set; } = \"\";\n        public string Phase2Seconds { get; set; } = \"\";\n        public string Phase3Seconds { get; set; } = \"\";\n        public string Phase4Seconds { get; set; } = \"\";\n        public string CopyTimeSeconds { get; set; } = \"\";\n        public string TotalSeconds { get; set; } = \"\";\n        public string PlotSize { get; set; } = \"\";\n        public string Threads { get; set; } = \"\";\n        public string Buffer { get; set; } = \"\";\n        public string Buckets { get; set; } = \"\";\n        public string StartDate { get; set; } = \"\";\n        public string FinishDate { get; set; } = \"\";\n        public string PlotName { get; set; } = \"\";\n        public string LogFolder { get; set; } = \"\";\n        public string LogFile { get; set; } = \"\";\n        public string ApproximateWorkingSpace { get; set; } = \"\";\n        public string FinalFileSize { get; set; } = \"\";\n        public string Health { get; set; } = \"\";\n        public string LastLogLine { get; set; } = \"\";\n        public string PlaceInLogFile { get; set; } = \"\";\n        public string Phase1AvgTimeNeed { get; set; } = \"\";\n        public string Phase2AvgTimeNeed { get; set; } = \"\";\n        public string Phase3AvgTimeNeed { get; set; } = \"\";\n        public string Phase4AvgTimeNeed { get; set; } = \"\";\n        public string CopyTimeAvgTimeNeed { get; set; } = \"\";\n        public string TotalAvgTimeNeed { get; set; } = \"\";\n        public string Phase1Completed { get; set; } = \"\";\n        public string Note { get; set; } = \"\";\n        public string TotalEligiblePlots { get; set; } = \"\";\n        public string AvgEligiblePlots { get; set; } = \"\";\n        public string FoundProofs { get; set; } = \"\";\n        public string BestLookupTime { get; set; } = \"\";\n        public string WorstLookupTime { get; set; } = \"\";\n        public string AvgLookupTime { get; set; } = \"\";\n        public string FilterRatio { get; set; } = \"\";\n        public string TotalPlots { get; set; } = \"\";\n        public string ChallengesPerMinute { get; set; } = \"\";\n        public string AvgHeat { get; set; } = \"\";\n        public string MaxHeat { get; set; } = \"\";\n        public string MinHeat { get; set; } = \"\";\n        public string PoolPuzzleHash { get; set; } = \"\";\n        public string RuntimeMinutes { get; set; } = \"\";\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Program.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls.ApplicationLifetimes;\nusing Avalonia.ReactiveUI;\nusing System;\n\nnamespace ChiaPlotStatus\n{\n    class Program\n    {\n        // Initialization code. Don't use any Avalonia, third-party APIs or any\n        // SynchronizationContext-reliant code before AppMain is called: things aren't initialized\n        // yet and stuff might break.\n        public static void Main(string[] args) => BuildAvaloniaApp()\n            .StartWithClassicDesktopLifetime(args);\n\n        // Avalonia configuration, don't remove; also used by visual designer.\n        public static AppBuilder BuildAvaloniaApp()\n            => AppBuilder.Configure<App>()\n                .UsePlatformDetect()\n                .LogToTrace()\n                .UseReactiveUI();\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Utils/Utils.cs",
    "content": "﻿using Avalonia.Controls;\nusing Avalonia.Markup.Xaml.Styling;\nusing ChiaPlotStatus.Views;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusGUI.GUI.Utils\n{\n    public class Utils\n    {\n        /**\n         * Open URL in default browser\n         */\n        public static void OpenUrl(string url)\n        {\n            try\n            {\n                Process.Start(url);\n            }\n            catch\n            {\n                // workaround because of this: https://github.com/dotnet/corefx/issues/10361\n                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                {\n                    url = url.Replace(\"&\", \"^&\");\n                    Process.Start(new ProcessStartInfo(\"cmd\", $\"/c start {url}\") { CreateNoWindow = true });\n                }\n                else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\n                {\n                    Process.Start(\"xdg-open\", url);\n                }\n                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n                {\n                    Process.Start(\"open\", url);\n                }\n                else\n                {\n                    throw;\n                }\n            }\n        }\n\n\n        public static void OpenLogFile(string url)\n        {\n            try\n            {\n                Process.Start(url);\n            }\n            catch\n            {\n                // hack because of this: https://github.com/dotnet/corefx/issues/10361\n                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                {\n                    url = url.Replace(\"&\", \"^&\");\n                    // force notepad or it will not open log files of running plots\n                    Process.Start(new ProcessStartInfo(\"cmd\", $\"/c start notepad {url}\") { CreateNoWindow = true });\n                }\n                else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\n                {\n                    Process.Start(\"xdg-open\", url);\n                }\n                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n                {\n                    Process.Start(\"open\", url);\n                }\n                else\n                {\n                    throw;\n                }\n            }\n        }\n\n\n\n\n        public static void SetTheme(Window window, string theme)\n        {\n            var light = new StyleInclude(new Uri(\"resm:Styles?assembly=ControlCatalog\"))\n            {\n                Source = new Uri(\"resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default\")\n            };\n            var dark = new StyleInclude(new Uri(\"resm:Styles?assembly=ControlCatalog\"))\n            {\n                Source = new Uri(\"resm:Avalonia.Themes.Default.Accents.BaseDark.xaml?assembly=Avalonia.Themes.Default\")\n            };\n            switch (theme)\n            {\n                case \"Dark\":\n                    window.Styles[0] = dark;\n                    break;\n                default:\n                    window.Styles[0] = light;\n                    break;\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/ViewLocator.cs",
    "content": "using Avalonia.Controls;\nusing Avalonia.Controls.Templates;\nusing ChiaPlotStatus.ViewModels;\nusing System;\n\nnamespace ChiaPlotStatus\n{\n    public class ViewLocator : IDataTemplate\n    {\n        public bool SupportsRecycling => false;\n\n        public IControl Build(object data)\n        {\n            var name = data.GetType().FullName!.Replace(\"ViewModel\", \"View\");\n            var type = Type.GetType(name);\n\n            if (type != null)\n            {\n                return (Control)Activator.CreateInstance(type)!;\n            }\n            else\n            {\n                return new TextBlock { Text = \"Not Found: \" + name };\n            }\n        }\n\n        public bool Match(object data)\n        {\n            return data is ViewModelBase;\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/ViewModels/MainWindowViewModel.cs",
    "content": "﻿using Avalonia.Controls;\nusing Avalonia.Interactivity;\nusing Avalonia.Markup.Xaml.Styling;\nusing Avalonia.Threading;\nusing ChiaPlotStatus;\nusing ChiaPlotStatus.Logic.Utils;\nusing ChiaPlotStatus.GUI.Models;\nusing ChiaPlotStatus.Views;\nusing ReactiveUI;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.IO;\nusing System.Reactive;\nusing System.Text;\nusing System.Threading.Tasks;\nusing ChiaPlotStatus.Logic.Models;\nusing Avalonia;\nusing System.Runtime.InteropServices;\nusing ChiaPlotStatusGUI.GUI.Models;\nusing ChiaPlotStatusGUI.GUI.Utils;\nusing System.ComponentModel;\n\nnamespace ChiaPlotStatus.ViewModels\n{\n    public class MainWindowViewModel : ViewModelBase\n    {\n        public ChiaPlotStatus PlotManager { get; internal set; }\n\n        public ObservableCollection<PlotLogReadable> PlotLogs { get; set; } = new();\n        public List<(PlotLog, PlotLogReadable)> PlotLogTuples { get; set; } = new();\n        public PlotCounts PlotCounts { get; set; }\n\n        public string? Search { get; set; } = null;\n\n        public ObservableCollection<string> SortProperties = new();\n\n        public Language Language { get; set; }\n        public Dictionary<string, Language> Languages { get; set; }\n\n        public ReactiveCommand<Unit, Unit> ExportJsonCommand { get; set; }\n        public bool RawExport { get; set; } = false;\n        public ReactiveCommand<Unit, Unit> ExportYamlCommand { get; set; }\n        public ReactiveCommand<Unit, Unit> ExportCsvCommand { get; set; }\n        public ReactiveCommand<Unit, Unit> AddFolderCommand { get; set; }\n        public ReactiveCommand<string, Unit> RemoveFolderCommand { get; set; }\n        public ReactiveCommand<Unit, Unit> IncreaseFontSizeCommand { get; set; }\n        public ReactiveCommand<Unit, Unit> DecreaseFontSizeCommand { get; set; }\n        public ReactiveCommand<PlotLogReadable, Unit> MarkAsDeadCommand { get; set; }\n        public ReactiveCommand<PlotLogReadable, Unit> NoteCommand { get; set; }\n        public ReactiveCommand<Unit, Unit> MarkSelectionAsDeadCommand { get; set; }\n        public ReactiveCommand<Unit, Unit> SelectAllPossiblyDeadCommand { get; set; }\n        public ReactiveCommand<Unit, Unit> SelectAllConcerningCommand { get; set; }\n        public DispatcherTimer RefreshTimer { get; set; }\n\n        public MainWindowViewModel()\n        {\n            if (MainWindow.Instance.Find<Button>(\"RefreshPauseButton\") == null)\n            {\n                // TODO: rewrite in proper MVVM or similar pattern to get rid of this\n                return;\n            }\n\n            // cleanup installation files after update\n            UpdateDialog.DeleteUpdateTempDirectory();\n\n            foreach (var property in typeof(PlotLogReadable).GetProperties())\n                SortProperties.Add(property.Name);\n            Languages = Translation.LoadLanguages();\n            Language = Languages[\"English\"];\n            InitializeChiaPlotStatus();\n            InitializeButtons();\n            InitializeSearchBox();\n            KeepGridScrollbarOnScreen();\n            InitializeThemeSwitcher();\n            InitializeRefreshInterval();\n            InitializeRefreshPauseButton();\n            InitializeSelection();\n            InitializeFilterUpdates();\n            SortColumns();\n            HandleColumnWidths();\n\n            RegisterOnCloseHandler();\n        }\n\n        private void HandleFinishDateVisibility()\n        {\n            var logDataGrid = MainWindow.Instance.Find<DataGrid>(\"LogDataGrid\");\n            foreach (var col in logDataGrid.Columns)\n            {\n                if (col.SortMemberPath == \"FinishDate\") {\n                    col.IsVisible = !PlotManager.Settings.Filter.HideFinished;\n                    break;\n                }\n            }\n        }\n\n        private void SortColumns()\n        {\n            var logDataGrid = MainWindow.Instance.Find<DataGrid>(\"LogDataGrid\");\n            List<DataGridColumn> columns = new();\n            foreach (var col in logDataGrid.Columns)\n                columns.Add(col);\n\n            logDataGrid.Columns.Clear();\n\n            columns.Sort((a, b) =>\n            {\n                return PlotManager.Settings.Columns.IndexOf(a.SortMemberPath).CompareTo(\n                    PlotManager.Settings.Columns.IndexOf(b.SortMemberPath));\n            });\n\n            for (int i = 0; i < columns.Count; i++)\n            {\n                columns[i].DisplayIndex = i;\n                logDataGrid.Columns.Add(columns[i]);\n            }\n        }\n\n        private void HandleColumnWidths()\n        {\n            var logDataGrid = MainWindow.Instance.Find<DataGrid>(\"LogDataGrid\");\n            foreach (var column in logDataGrid.Columns)\n            {\n                string name = column.SortMemberPath;\n                if (this.PlotManager.Settings.Columns.Widths.ContainsKey(name))\n                {\n                    column.Width = new DataGridLength(this.PlotManager.Settings.Columns.Widths[name]);\n                    //column.Width = new DataGridLength(3333);\n                }\n                /*\n                column.WhenAnyValue(x => x.ActualWidth).Subscribe(x => {\n                    this.PlotManager.Settings.Columns.Widths.Add(name, x);\n                    this.PlotManager.Settings.Persist();\n                });\n                */\n            }\n\n            MainWindow.Instance.Closing += (sender, e) =>\n            {\n                foreach (var column in logDataGrid.Columns)\n                {\n                    string name = column.SortMemberPath;\n                    this.PlotManager.Settings.Columns.Widths[name] = (int) column.ActualWidth;\n                }\n                this.PlotManager.Settings.Persist();\n            };\n        }\n\n        private void InitializeRefreshPauseButton()\n        {\n            var button = MainWindow.Instance.Find<Button>(\"RefreshPauseButton\");\n            if (button != null)\n            {\n                button.Click += (sender, e) => SetPauseRefreshState(null);\n            }\n        }\n\n        private void SetPauseRefreshState(bool? pause)\n        {\n            if (pause == null)\n            {\n                pause = RefreshTimer.IsEnabled;\n            }\n            var button = MainWindow.Instance.Find<Button>(\"RefreshPauseButton\");\n            if (pause == true)\n            {\n                Debug.WriteLine(\"pausing refresh\");\n                button.Content = \"Refresh ■\";\n                RefreshTimer.Stop();\n            } else {\n                Debug.WriteLine(\"continuing refresh\");\n                button.Content = \"Refresh ▶\";\n                RefreshTimer.Start();\n                LoadPlotLogs();\n            }\n        }\n\n        private void InitializeSelection()\n        {\n            MainWindow.Instance.SelectionChangedAction = () => SetPauseRefreshState(true);\n            this.SelectAllPossiblyDeadCommand = ReactiveCommand.Create(() => Select(true, false));\n            this.SelectAllConcerningCommand = ReactiveCommand.Create(() => Select(false, true));\n\n            void Select(bool possiblyDead, bool concerning)\n            {\n                foreach (var plotLogReadable in PlotLogs)\n                {\n                    plotLogReadable.IsSelected = false;\n                    var plotLog = getPlotLogByReadable(plotLogReadable);\n                    switch (plotLog.Health)\n                    {\n                        case PossiblyDead pd:\n                            if (possiblyDead)\n                                plotLogReadable.IsSelected = true;\n                            break;\n                        case Concerning c:\n                            if (concerning)\n                                plotLogReadable.IsSelected = true;\n                            break;\n                        default:\n                            break;\n                    }\n                }\n\n                // work around avalonia datagrid not updating the checkbox even\n                // with TwoWay Binding as I refuse to re-implement plotLog and\n                // plotLogReadable as ReactiveObjects and copy the data from\n                // plotLog/plotLogReadable to its reactive counterparts (thats\n                // not dry!) or even worse, make plotLog itself reactive and\n                // thereby adding gui code and dependencies to the non-gui\n                // library and cli\n                ObservableCollection<PlotLogReadable> plotLogsTemp = new();\n                foreach (var plotLogReadable in PlotLogs)\n                    plotLogsTemp.Add(plotLogReadable);\n                PlotLogs = plotLogsTemp;\n                this.RaisePropertyChanged(\"PlotLogs\");\n\n                MainWindow.Instance.SelectionChangedAction();\n            }\n\n            this.MarkSelectionAsDeadCommand = ReactiveCommand.Create(() =>\n            {\n                foreach (var plotLog in PlotLogs)\n                {\n                    if (plotLog.IsSelected)\n                    {\n                        var mark = new MarkOfDeath(plotLog);\n                        if (!PlotManager.Settings.MarksOfDeath.Contains(mark))\n                            PlotManager.Settings.MarksOfDeath.Add(mark);\n                    }\n                }\n                PlotManager.Settings.Persist();\n                SetPauseRefreshState(false);\n            });\n        }\n\n        private PlotLog getPlotLogByReadable(PlotLogReadable plotLogReadable)\n        {\n            foreach (var tuple in PlotLogTuples)\n                if (tuple.Item2 == plotLogReadable)\n                    return tuple.Item1;\n            throw new Exception(\"getPlotLogByReadable did not find the match\");\n        }\n\n        private void InitializeThemeSwitcher()\n        {\n            MainWindow.Instance.ThemeSwitchWorkaround = (theme) =>\n            {\n                PlotManager.Settings.Theme = theme;\n                PlotManager.Settings.Persist();\n                Utils.SetTheme(MainWindow.Instance, theme);\n                switch (theme)\n                {\n                    case \"Dark\":\n                        MainWindow.Instance.Find<ComboBox>(\"Themes\").SelectedIndex = 1;\n                        MainWindow.Instance.Find<TextBox>(\"SearchBox\").Foreground = Avalonia.Media.Brushes.LightGray;\n                        MainWindow.Instance.Find<ComboBox>(\"Themes\").Foreground = Avalonia.Media.Brushes.LightGray;\n                        break;\n                    default:\n                        MainWindow.Instance.Find<ComboBox>(\"Themes\").SelectedIndex = 0;\n                        MainWindow.Instance.Find<TextBox>(\"SearchBox\").Foreground = Avalonia.Media.Brushes.Black;\n                        MainWindow.Instance.Find<ComboBox>(\"Themes\").Foreground = Avalonia.Media.Brushes.Black;\n                        break;\n                }\n                return true;\n            };\n            Dispatcher.UIThread.InvokeAsync(() =>\n            {\n               MainWindow.Instance.ThemeSwitchWorkaround(PlotManager.Settings.Theme);\n           });\n        }\n\n        private void KeepGridScrollbarOnScreen()\n        {\n            MainWindow.Instance.WhenAnyValue(x => x.Height)\n                .Subscribe(x =>\n                {\n                    var dataGrid = MainWindow.Instance.Find<DataGrid>(\"LogDataGrid\");\n                    if (dataGrid != null)\n                        dataGrid.Height = x - 150;\n                });\n        }\n\n        public void InitializeChiaPlotStatus()\n        {\n            var folder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Path.DirectorySeparatorChar;\n            Settings Settings = new Settings(folder + \"ChiaPlotStatu.config.json\");\n            Settings.Load();\n            PlotManager = new(Settings);\n            if (PlotManager.Settings.LogDirectories.Count == 0)\n                PlotManager.AddDefaultLogFolders();\n            LoadPlotLogs();\n        }\n\n        public void LoadPlotLogs()\n        {\n            MainWindow.Instance.Find<DataGrid>(\"LogDataGrid\").BeginBatchUpdate();\n            PlotLogs.Clear();\n            PlotLogTuples = new();\n            foreach (var plotLog in PlotManager.PollPlotLogs(PlotManager.Settings.SortProperty, (bool)PlotManager.Settings.SortAsc, Search, PlotManager.Settings.Filter))\n            {\n                PlotLogs.Add(plotLog.Item2);\n                PlotLogTuples.Add(plotLog);\n            }\n            PlotCounts = new(PlotLogTuples);\n            HandleFinishDateVisibility();\n            MainWindow.Instance.Find<DataGrid>(\"LogDataGrid\").EndBatchUpdate();\n            this.RaisePropertyChanged(\"PlotCounts\");\n        }\n\n\n        public void InitializeButtons()\n        {\n            AddFolderCommand = ReactiveCommand.Create(AddFolder);\n            RemoveFolderCommand = ReactiveCommand.Create<string>(RemoveFolder);\n            MainWindow.Instance.BtnClickWorkaround = (folder) =>\n            {\n                RemoveFolder(folder);\n                return true;\n            };\n\n            MainWindow.Instance.SortChangeWorkaround = (headerText) =>\n            {\n                var oldSortProperty = PlotManager.Settings.SortProperty;\n                foreach (var property in typeof(Columns).GetProperties())\n                {\n                    string translation = (string)property.GetValue(Language.Columns);\n                    if (string.Equals(headerText, translation))\n                    {\n                        PlotManager.Settings.SortProperty = property.Name;\n                        break;\n                    }\n                }\n                if (string.Equals(PlotManager.Settings.SortProperty, oldSortProperty))\n                    PlotManager.Settings.SortAsc = !PlotManager.Settings.SortAsc;\n                // Debug.WriteLine(\"SearchProperty: \" + SortProperty + \", ASC: \" + SortAsc);\n                LoadPlotLogs();\n                PlotManager.Settings.Persist();\n                return true;\n            };\n\n            IncreaseFontSizeCommand = ReactiveCommand.Create(() =>\n            {\n                this.PlotManager.Settings.FontSize += 0.3;\n                this.PlotManager.Settings.Persist();\n            });\n\n            DecreaseFontSizeCommand = ReactiveCommand.Create(() =>\n            {\n                this.PlotManager.Settings.FontSize -= 0.3;\n                this.PlotManager.Settings.Persist();\n            });\n\n            ExportJsonCommand = ReactiveCommand.Create(() =>\n            {\n                Exporter exporter = new Exporter(PlotLogTuples);\n                SaveFileDialog picker = new SaveFileDialog();\n                picker.Title = \"Save as Json\";\n                if (RawExport)\n                    picker.InitialFileName = \"ChiaPlotStatus-raw.json\";\n                else\n                    picker.InitialFileName = \"ChiaPlotStatus.json\";\n                picker.Filters = new List<FileDialogFilter>\n                {\n                    new FileDialogFilter\n                    {\n                        Name = \"Json (.json)\", Extensions = new List<string> {\"json\"}\n                    },\n                    new FileDialogFilter\n                    {\n                        Name = \"All files\",\n                        Extensions = new List<string> {\"*\"}\n                    }\n                };\n                Task.Run(async () =>\n                {\n                    var result = await picker.ShowAsync(MainWindow.Instance);\n                    if (result != null)\n                        exporter.ToJson(result, RawExport);\n                });\n            });\n\n            ExportYamlCommand = ReactiveCommand.Create(() =>\n            {\n                Exporter exporter = new Exporter(PlotLogTuples);\n                SaveFileDialog picker = new SaveFileDialog();\n                picker.Title = \"Save as Yaml\";\n                if (RawExport)\n                    picker.InitialFileName = \"ChiaPlotStatus-raw.yaml\";\n                else\n                    picker.InitialFileName = \"ChiaPlotStatus.yaml\";\n                picker.Filters = new List<FileDialogFilter>\n                {\n                    new FileDialogFilter\n                    {\n                        Name = \"Yaml (.yaml)\", Extensions = new List<string> {\"yaml\"}\n                    },\n                    new FileDialogFilter\n                    {\n                        Name = \"All files\",\n                        Extensions = new List<string> {\"*\"}\n                    }\n                };\n                Task.Run(async () =>\n                {\n                    var result = await picker.ShowAsync(MainWindow.Instance);\n                    if (result != null)\n                        exporter.ToYaml(result, RawExport);\n                });\n            });\n\n            ExportCsvCommand = ReactiveCommand.Create(() =>\n            {\n                Exporter exporter = new Exporter(PlotLogTuples);\n                SaveFileDialog picker = new SaveFileDialog();\n                picker.Title = \"Save as Csv\";\n                if (RawExport)\n                    picker.InitialFileName = \"ChiaPlotStatus-raw.csv\";\n                else\n                    picker.InitialFileName = \"ChiaPlotStatus.csv\";\n                picker.Filters = new List<FileDialogFilter>\n                {\n                    new FileDialogFilter\n                    {\n                        Name = \"Yaml (.csv)\", Extensions = new List<string> {\"csv\"}\n                    },\n                    new FileDialogFilter\n                    {\n                        Name = \"All files\",\n                        Extensions = new List<string> {\"*\"}\n                    }\n                };\n                Task.Run(async () =>\n                {\n                    var result = await picker.ShowAsync(MainWindow.Instance);\n                    if (result != null)\n                        exporter.ToCsv(result, RawExport);\n                });\n            });\n\n            MarkAsDeadCommand = ReactiveCommand.Create<PlotLogReadable>((plotLogReadable) =>\n            {\n                var dialog = new MarkOfDeathDialog(plotLogReadable, this.Language, this.PlotManager.Settings, this.PlotManager.Settings.Theme, LoadPlotLogs);\n                dialog.Show();\n            });\n\n            NoteCommand = ReactiveCommand.Create<PlotLogReadable>((plotLogReadable) =>\n            {\n                var dialog = new NoteDialog(plotLogReadable, this.Language, this.PlotManager.Settings, this.PlotManager.Settings.Theme, LoadPlotLogs);\n                dialog.Show();\n            });\n\n            var updateButton = MainWindow.Instance.Find<MenuItem>(\"UpdateButton\");\n            if (updateButton != null)\n                updateButton.Command = ReactiveCommand.Create(() =>\n                {\n                    var dialog = new UpdateDialog(this.Language, this.PlotManager.Settings.Theme);\n                    dialog.Show();\n                });\n\n            var donateButton = MainWindow.Instance.Find<MenuItem>(\"DonateButton\");\n            if (donateButton != null)\n                donateButton.Command = ReactiveCommand.Create(() =>\n                {\n                    var dialog = new DonationDialog(this.Language, this.PlotManager.Settings.Theme);\n                    dialog.Show();\n                });\n\n            var statisticsButton = MainWindow.Instance.Find<MenuItem>(\"StatisticsButton\");\n            if (statisticsButton != null)\n                statisticsButton.Command = ReactiveCommand.Create(() =>\n                {\n                    var dialog = new StatisticsDialog(this.PlotManager, this.Language, this.PlotManager.Settings.Theme);\n                    dialog.Show();\n                });\n\n            var harvestersButton = MainWindow.Instance.Find<MenuItem>(\"HarvestersButton\");\n            if (harvestersButton != null)\n                harvestersButton.Command = ReactiveCommand.Create(() =>\n                {\n                    var dialog = new HarvestDialog(this.Language, this.PlotManager.Settings, this.PlotManager.Settings.Theme);\n                    dialog.Show();\n                });\n\n            var chiaPlotterButton = MainWindow.Instance.Find<MenuItem>(\"ChiaPlotterButton\");\n            if (chiaPlotterButton != null)\n                chiaPlotterButton.Command = ReactiveCommand.Create(() =>\n                {\n                    var dialog = new ChiaPlotterDialog(this.PlotManager, this.Language, this.PlotManager.Settings.Theme);\n                    dialog.Show();\n                });\n\n        }\n\n        public void InitializeSearchBox()\n        {\n            MainWindow.Instance.TextChangeWorkaround = (text) =>\n            {\n                Search = text;\n                LoadPlotLogs();\n                return true;\n            };\n        }\n\n        public async void AddFolder()\n        {\n            OpenFolderDialog picker = new OpenFolderDialog();\n            var result = await picker.ShowAsync(MainWindow.Instance);\n            AddFolder(result);\n        }\n\n        public void AddFolder(string folder)\n        {\n            if (!PlotManager.Settings.LogDirectories.Contains(folder))\n            {\n                PlotManager.AddLogFolder(folder);\n                PlotManager.Settings.Persist();\n                LoadPlotLogs();\n            }\n        }\n\n        public void RemoveFolder(string folder)\n        {\n            PlotManager.RemoveLogFolder(folder);\n            PlotManager.Settings.Persist();\n            LoadPlotLogs();\n        }\n\n\n        public void InitializeRefreshInterval()\n        {\n            RefreshTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(30) };\n            RefreshTimer.Tick += (sender, e) =>\n            {\n                // Somehow this ticks twice\n                Debug.WriteLine(\"Refresh \" + DateTime.Now);\n                LoadPlotLogs();\n            };\n            RefreshTimer.Start();\n        }\n\n\n        public void InitializeFilterUpdates()\n        {\n            /*\n            this.WhenAnyValue(x => x.Filter.HideHealthy)\n                .Subscribe((x) => LoadPlotLogs());\n            this.WhenAnyValue(x => x.Filter.HidePossiblyDead)\n                .Subscribe((x) => LoadPlotLogs());\n            this.WhenAnyValue(x => x.Filter.HideConfirmedDead)\n                .Subscribe((x) => LoadPlotLogs());\n            */\n            var checkBox = MainWindow.Instance.Find<CheckBox>(\"HideConfirmedDead\");\n            if (checkBox != null)\n            {\n                void update()\n                {\n                    PlotManager.Settings.Persist();\n                    LoadPlotLogs();\n                }\n\n                checkBox.WhenAnyValue(x => x.IsChecked)\n                    .Subscribe((x) => update());\n                MainWindow.Instance.Find<CheckBox>(\"HidePossiblyDead\").WhenAnyValue(x => x.IsChecked)\n                    .Subscribe((x) => update());\n                MainWindow.Instance.Find<CheckBox>(\"HideHealthy\").WhenAnyValue(x => x.IsChecked)\n                    .Subscribe((x) => update());\n                MainWindow.Instance.Find<CheckBox>(\"HideFinished\").WhenAnyValue(x => x.IsChecked)\n                    .Subscribe((x) => update());\n            }\n        }\n\n        public void RegisterOnCloseHandler()\n        {\n            MainWindow.Instance.Closing += (sender, e) =>\n            {\n                PlotManager.Persist();\n            };\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/ViewModels/ViewModelBase.cs",
    "content": "using ReactiveUI;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace ChiaPlotStatus.ViewModels\n{\n    public class ViewModelBase : ReactiveObject\n    {\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/ChiaPlotterDialog.axaml",
    "content": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:oxy=\"clr-namespace:OxyPlot.Avalonia;assembly=OxyPlot.Avalonia\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\" d:DesignWidth=\"400\" d:DesignHeight=\"100\"\n        Width=\"1000\" Height=\"600\"\n        x:Class=\"ChiaPlotStatus.Views.ChiaPlotterDialog\"\n        Icon=\"/GUI/Assets/Logo.png\"\n        TransparencyLevelHint=\"Transparent\"\n        ExtendClientAreaToDecorationsHint=\"False\"\n        Title=\"Chia-Plotter Monitoring\">\n\n  <!--\n\t<Window.DataContext>\n\t\t<vm:MainWindowViewModel/>\n\t</Window.DataContext>\n  -->\n\t<Window.Styles>\n    <Style Selector=\"DataGridRow\">\n      <Setter Property=\"Margin\" Value=\"2\" />\n    </Style>\n    <Style Selector=\"TextBlock\">\n      <Setter Property=\"FontSize\" Value=\"10\"/>\n    </Style>\n    <Style Selector=\"DataGrid TextBlock\">\n      <Setter Property=\"Margin\" Value=\"4, 1\"/>\n      <Setter Property=\"FontSize\" Value=\"12\"/>\n    </Style>\n    <Style Selector=\"ToolTip\">\n      <Setter Property=\"MaxWidth\" Value=\"600\"/>\n      <Setter Property=\"MaxHeight\" Value=\"600\"/>\n    </Style>\n    <Style Selector=\"ToolTip TextBlock\">\n      <Setter Property=\"MaxWidth\" Value=\"600\"/>\n      <Setter Property=\"MaxHeight\" Value=\"600\"/>\n      <Setter Property=\"FontSize\" Value=\"10.3\"/>\n      <Setter Property=\"TextWrapping\" Value=\"Wrap\"/>\n    </Style>\n    <Style Selector=\"TextBox\">\n      <!-- <Setter Property=\"FontFamily\" Value=\"Ubuntu\" /> -->\n      <Setter Property=\"BorderThickness\" Value=\"1\" />\n      <Setter Property=\"Foreground\" Value=\"{DynamicResource ThemeForegroundBrush}\" />\n      <Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n      <Setter Property=\"Padding\" Value=\"6\" />\n      <Setter Property=\"Margin\" Value=\"0 2\" />\n      <Setter Property=\"FontSize\" Value=\"12\" />\n    </Style>\n    <Style Selector=\"TextBox TextBlock\">\n      <Setter Property=\"FontSize\" Value=\"12\" />\n    </Style>\n    <Style Selector=\"TextBox /template/ Border\">\n      <Setter Property=\"CornerRadius\" Value=\"5\" />\n    </Style>\n    <Style Selector=\"TextBox:pointerover /template/ Border\">\n      <Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n    </Style>\n    <Style Selector=\"TextBox:focus /template/ Border\">\n      <Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n    </Style>\n    <Style Selector=\"Button.Compact\">\n      <Setter Property=\"Margin\" Value=\"0\" />\n      <Setter Property=\"Padding\" Value=\"0\" />\n      <Setter Property=\"BorderThickness\" Value=\"0\" />\n    </Style>\n    <Style Selector=\"DataGrid Button\">\n      <Setter Property=\"BorderThickness\" Value=\"0\" />\n    </Style>\n  </Window.Styles>\n\n\n  <ScrollViewer Name=\"WindowContext\">\n    <StackPanel>\n\n      <DataGrid Name=\"LogDataGrid\" Items=\"{Binding PlotLogs}\" IsReadOnly=\"true\" MinHeight=\"80\" CanUserSortColumns=\"false\" CanUserResizeColumns=\"true\">\n        <DataGrid.Columns>\n          <DataGridTemplateColumn SortMemberPath=\"Selection\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Selection}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <CheckBox IsChecked=\"{Binding IsSelected, Mode=TwoWay}\" Checked=\"OnSelectionChanged\"></CheckBox>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Note\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Note}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <Button Content=\"{Binding Note}\" HorizontalAlignment=\"Left\" Classes=\"Compact\" Command=\"{Binding ElementName=WindowContext, Path=DataContext.NoteCommand}\" CommandParameter=\"{Binding}\"\n                    ></Button>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Tmp1Drive\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Tmp1Drive}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Tmp1Drive}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Tmp2Drive\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Tmp2Drive}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Tmp2Drive}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <!--\n\t\t\t\t\t<DataGridTemplateColumn SortMemberPath=\"DestDrive\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.DestDrive}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate>\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.DestDrive}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding DestDrive}\" HorizontalAlignment=\"Left\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n\t\t\t\t\t-->\n          <DataGridTemplateColumn SortMemberPath=\"StartDate\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.StartDate}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.StartDate}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding StartDate}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <!--\n          <DataGridTemplateColumn SortMemberPath=\"FinishDate\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.FinishDate}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.FinishDate}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding FinishDate}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          -->\n          <DataGridTemplateColumn SortMemberPath=\"Health\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Health}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Health}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <Button Content=\"{Binding Health}\" HorizontalAlignment=\"Left\" Classes=\"Compact\" Command=\"{Binding ElementName=WindowContext, Path=DataContext.MarkAsDeadCommand}\" CommandParameter=\"{Binding}\"\n                    ></Button>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <!--\n          <DataGridTemplateColumn SortMemberPath=\"Errors\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Errors}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Errors}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Errors}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          -->\n          <DataGridTemplateColumn SortMemberPath=\"Progress\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Progress}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Progress}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Progress}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"ETA\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.ETA}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.ETA}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding ETA}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn >\n          <DataGridTemplateColumn SortMemberPath=\"TimeRemaining\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.TimeRemaining}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.TimeRemaining}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding TimeRemaining}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn >\n          <DataGridTemplateColumn SortMemberPath=\"RunTimeSeconds\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.RunTimeSeconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.RunTimeSeconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding RunTimeSeconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"CurrentPhase\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.CurrentPhase}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CurrentPhase}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding CurrentPhase}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"CurrentTable\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.CurrentTable}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CurrentTable}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding CurrentTable}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"CurrentPhasePart\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.CurrentPhasePart}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CurrentPhasePart}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding CurrentPhasePart}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn >\n          <DataGridTemplateColumn SortMemberPath=\"Phase1Seconds\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase1Seconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase1Seconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding P1}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase2Seconds\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase2Seconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase2Seconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding P2}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase3Seconds\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase3Seconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase3Seconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding P3}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase4Seconds\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase4Seconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase4Seconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase4Seconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <!--\n          <DataGridTemplateColumn SortMemberPath=\"CopyTimeSeconds\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.CopyTimeSeconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CopyTimeSeconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding CopyTimeSeconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          -->\n          <DataGridTemplateColumn SortMemberPath=\"TotalSeconds\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.TotalSeconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.TotalSeconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Total}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <!--\n          <DataGridTemplateColumn SortMemberPath=\"Buffer\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Buffer}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Buffer}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Buffer}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          -->\n          <DataGridTemplateColumn SortMemberPath=\"Buckets\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Buckets}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Buckets}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Buckets}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Threads\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Threads}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Threads}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Threads}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"LogFolder\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.LogFolder}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.LogFolder}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding LogFolder}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"LogFile\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.LogFile}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.LogFile}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <Button Classes=\"Compact\" Content=\"{Binding LogFile}\" HorizontalAlignment=\"Left\" Click=\"OpenLogViewerWindow\" Tag=\"{Binding}\"></Button>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn >\n          <DataGridTemplateColumn SortMemberPath=\"FinalFileSize\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.FinalFileSize}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.FinalFileSize}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding FinalFileSize}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"LastLogLine\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.LastLogLine}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.LastLogLine}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding LastLogLine}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n        </DataGrid.Columns>\n      </DataGrid>\n    </StackPanel>\n  </ScrollViewer>\n</Window>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/ChiaPlotterDialog.axaml.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Interactivity;\nusing Avalonia.Layout;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Markup.Xaml.Styling;\nusing ChiaPlotStatus.GUI.Models;\nusing ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatus.Logic.Utils;\nusing ChiaPlotStatusGUI.GUI.Utils;\nusing ChiaPlotStatusGUI.GUI.ViewModels;\nusing ChiaPlotStatusLib.Logic.Models;\nusing ReactiveUI;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.IO;\nusing System.Reactive;\nusing System.Text.RegularExpressions;\n\nnamespace ChiaPlotStatus.Views\n{\n    public class ChiaPlotterDialog : Window\n    {\n        public Language Language { get; set; }\n        public List<(CPPlotLog, CPPlotLogReadable)> PlotLogTuples { get; set; }\n        public ObservableCollection<CPPlotLogReadable> PlotLogs { get; set; } = new();\n        public ChiaPlotStatus PlotManager { get; set; }\n        public string SortProperty { get; set; } = \"Tmp1Drive\";\n        public string Search { get; set; } = \"\";\n        public bool SortAsc { get; set; } = true;\n\n\n        public ChiaPlotterDialog()\n        {\n        }\n\n        public ChiaPlotterDialog(ChiaPlotStatus plotManager, Language language, string theme)\n        {\n            this.DataContext = this;\n            this.Language = language;\n            this.PlotManager = plotManager;\n            InitializeComponent();\n#if DEBUG\n            this.AttachDevTools();\n#endif\n            KeepGridScrollbarOnScreen();\n            LoadData();\n            this.WindowState = WindowState.Maximized;\n            Utils.SetTheme(this, theme);\n            this.Focus();\n        }\n\n        private void LoadData()\n        {\n            this.Find<DataGrid>(\"LogDataGrid\").BeginBatchUpdate();\n            PlotLogs.Clear();\n            PlotLogTuples = new();\n            foreach (var plotLog in PlotManager.PollCPPlotLogs(PlotManager.Settings.SortProperty, (bool)PlotManager.Settings.SortAsc, Search, PlotManager.Settings.Filter))\n            {\n                PlotLogs.Add(plotLog.Item2);\n                PlotLogTuples.Add(plotLog);\n            }\n            // PlotCounts = new(PlotLogTuples);\n            // HandleFinishDateVisibility();\n            this.Find<DataGrid>(\"LogDataGrid\").EndBatchUpdate();\n            //this.RaisePropertyChanged(\"PlotCounts\");\n        }\n\n        private void InitializeComponent()\n        {\n            AvaloniaXamlLoader.Load(this);\n        }\n\n\n        public void OnSelectionChanged(object sender, RoutedEventArgs e)\n        {\n            // TODO: SelectionChangedAction();\n        }\n\n        public void OpenLogViewerWindow(object sender, RoutedEventArgs e)\n        {\n            var plotLogReadable = (PlotLogReadable)((Button)sender).Tag;\n            var path = plotLogReadable.LogFolder + Path.DirectorySeparatorChar + plotLogReadable.LogFile;\n            Utils.OpenLogFile(path);\n        }\n\n        public void LogDataGridHeaderClick(object sender, RoutedEventArgs e)\n        {\n            Button header = ((Button)sender);\n            string headerText = (string)header.Content;\n            var oldSortProperty = SortProperty;\n            foreach (var property in typeof(GUI.Models.Columns).GetProperties())\n            {\n                string translation = (string)property.GetValue(Language.Columns);\n                if (string.Equals(headerText, translation))\n                {\n                    SortProperty = property.Name;\n                    break;\n                }\n            }\n            if (string.Equals(SortProperty, oldSortProperty))\n                SortAsc = !SortAsc;\n            Sorter.Sort(SortProperty, SortAsc, PlotLogTuples);\n            PlotLogs.Clear();\n            foreach (var tuple in PlotLogTuples)\n                PlotLogs.Add(tuple.Item2);\n            // Debug.WriteLine(\"SearchProperty: \" + SortProperty + \", ASC: \" + SortAsc);\n        }\n\n        private void KeepGridScrollbarOnScreen()\n        {\n            this.WhenAnyValue(x => x.Height)\n                .Subscribe(x =>\n                {\n                    var logDataGrid = this.Find<DataGrid>(\"LogDataGrid\");\n                    logDataGrid.Height = x - 145;\n                });\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/DonationDialog.axaml",
    "content": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\" d:DesignWidth=\"500\" d:DesignHeight=\"130\"\n        Width=\"500\" Height=\"130\"\n        x:Class=\"ChiaPlotStatus.Views.DonationDialog\"\n        Icon=\"/GUI/Assets/Logo.png\"\n        TransparencyLevelHint=\"Transparent\"\n        ExtendClientAreaToDecorationsHint=\"False\"\n        Title=\"Donation to the Chia Plot Status developer\">\n\n  <!--\n\t<Window.DataContext>\n\t\t<vm:MainWindowViewModel/>\n\t</Window.DataContext>\n  -->\n\t<Window.Styles>\n    <Style Selector=\"Button.Compact\">\n      <Setter Property=\"Margin\" Value=\"3\" />\n      <Setter Property=\"Padding\" Value=\"2\" />\n      <Setter Property=\"BorderThickness\" Value=\"0\" />\n    </Style>\n    <Style Selector=\"TextBlock.Margin\">\n      <Setter Property=\"Margin\" Value=\"3\" />\n      <Setter Property=\"Padding\" Value=\"2\" />\n    </Style>\n    <Style Selector=\"Button.Margin\">\n      <Setter Property=\"Margin\" Value=\"3\" />\n      <Setter Property=\"Padding\" Value=\"2\" />\n    </Style>\n  </Window.Styles>\n\n  <Panel Name=\"WindowContext\">\n\t\t<StackPanel Margin=\"20\">\n      <Panel>\n\t\t\t  <ExperimentalAcrylicBorder IsHitTestVisible=\"False\">\n\t\t\t\t  <ExperimentalAcrylicBorder.Material>\n\t\t\t\t\t  <ExperimentalAcrylicMaterial\n\t\t\t\t\t\t  BackgroundSource=\"Digger\"\n\t\t\t\t\t\t  TintColor=\"Black\"\n\t\t\t\t\t\t  TintOpacity=\"0.2\"\n\t\t\t\t\t\t  MaterialOpacity=\"0.25\" />\n\t\t\t\t  </ExperimentalAcrylicBorder.Material>\n\t\t\t  </ExperimentalAcrylicBorder>\n\t\t  </Panel>\n\n      <TextBlock FontWeight=\"Bold\" Text=\"Buy the Chia Plot Status developer a beer, some coffee or another Terabyte\"></TextBlock>\n      <TextBlock Text=\" \"></TextBlock>\n      <StackPanel Orientation=\"Horizontal\">\n        <TextBlock Text=\"Chia:\" FontWeight=\"Bold\" Classes=\"Margin\"></TextBlock>\n        <Border>\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock Text=\"{Binding ChiaAddress}\" Classes=\"Margin\"></TextBlock>\n            <Button Content=\"{Binding Language.Buttons.Copy}\" Classes=\"Margin\" Click=\"CopyToClipboard\" Tag=\"{Binding ChiaAddress}\"></Button>\n          </StackPanel>\n        </Border>\n      </StackPanel>\n      <StackPanel Orientation=\"Horizontal\">\n        <Border>\n          <StackPanel Orientation=\"Horizontal\">\n            <Button Content=\"Paypal\" Classes=\"Margin\" Click=\"OpenLink\" Tag=\"{Binding PaypalURL}\"></Button>\n            <Button Content=\"Liberapay\" Classes=\"Margin\" Click=\"OpenLink\" Tag=\"{Binding LiberapayURL}\"></Button>\n          </StackPanel>\n        </Border>\n      </StackPanel>\n\n      <TextBlock Text=\"Thank you and cheers!\" FontWeight=\"Bold\" Name=\"Thx\" Classes=\"Margin\"></TextBlock>\n    </StackPanel>\n\t</Panel>\n</Window>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/DonationDialog.axaml.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Input.Platform;\nusing Avalonia.Interactivity;\nusing Avalonia.Layout;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Markup.Xaml.Styling;\nusing ChiaPlotStatus.GUI.Models;\nusing ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusGUI.GUI.Utils;\nusing ReactiveUI;\nusing System;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.Reactive;\nusing System.Runtime.InteropServices;\nusing System.Text.RegularExpressions;\n\nnamespace ChiaPlotStatus.Views\n{\n    public class DonationDialog : Window\n    {\n        public Language Language { get; set; }\n        public string ChiaAddress { get; set; } = \"xch15p8swrrdt5ujv0dxy4hwjrvpjseyvuquwtfwnrjhxqt6ws9uf90qzq4axl\";\n        public string PaypalURL { get; set; } = \"https://www.paypal.com/donate?hosted_button_id=PDLLVF5XVMJPC\";\n        public string LiberapayURL { get; set; } = \"https://liberapay.com/grayfallstown/donate\";\n\n        public DonationDialog() { }\n\n        public DonationDialog(Language language, string theme)\n        {\n            this.DataContext = this;\n            this.Language = language;\n            InitializeComponent();\n#if DEBUG\n            this.AttachDevTools();\n#endif\n            this.Find<TextBlock>(\"Thx\").IsVisible = false;\n            Utils.SetTheme(this, theme);\n            this.Focus();\n        }\n\n        private void InitializeComponent()\n        {\n            AvaloniaXamlLoader.Load(this);\n        }\n\n        public void CopyToClipboard(object sender, RoutedEventArgs e)\n        {\n            string text = (string)(((Button)sender).Tag);\n            Application.Current.Clipboard.SetTextAsync(text);\n            this.Find<TextBlock>(\"Thx\").IsVisible = true;\n        }\n\n        public void OpenLink(object sender, RoutedEventArgs e)\n        {\n            string url = (string)(((Button)sender).Tag);\n            Utils.OpenUrl(url);\n            this.Find<TextBlock>(\"Thx\").IsVisible = true;\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/HarvestDialog.axaml",
    "content": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\" d:DesignWidth=\"400\" d:DesignHeight=\"100\"\n        Width=\"800\" Height=\"600\"\n        x:Class=\"ChiaPlotStatus.Views.HarvestDialog\"\n        Icon=\"/GUI/Assets/Logo.png\"\n        TransparencyLevelHint=\"Transparent\"\n        ExtendClientAreaToDecorationsHint=\"False\"\n        Title=\"Overview over your harvesters health\">\n\n  <!--\n\t<Window.DataContext>\n\t\t<vm:MainWindowViewModel/>\n\t</Window.DataContext>\n  -->\n\t<Window.Styles>\n    <Style>\n      <!-- will be replaced with dark theme-->\n    </Style>\n    <Style Selector=\"DataGridRow\">\n      <Setter Property=\"Margin\" Value=\"2\" />\n    </Style>\n    <Style Selector=\"TextBlock\">\n      <Setter Property=\"FontSize\" Value=\"10\"/>\n    </Style>\n    <Style Selector=\"DataGrid TextBlock\">\n      <Setter Property=\"Margin\" Value=\"4, 1\"/>\n      <Setter Property=\"FontSize\" Value=\"12\"/>\n    </Style>\n    <Style Selector=\"ToolTip\">\n      <Setter Property=\"MaxWidth\" Value=\"600\"/>\n      <Setter Property=\"MaxHeight\" Value=\"600\"/>\n    </Style>\n    <Style Selector=\"ToolTip TextBlock\">\n      <Setter Property=\"MaxWidth\" Value=\"600\"/>\n      <Setter Property=\"MaxHeight\" Value=\"600\"/>\n      <Setter Property=\"FontSize\" Value=\"10.3\"/>\n      <Setter Property=\"TextWrapping\" Value=\"Wrap\"/>\n    </Style>\n    <Style Selector=\"TextBox\">\n      <!-- <Setter Property=\"FontFamily\" Value=\"Ubuntu\" /> -->\n      <Setter Property=\"BorderThickness\" Value=\"1\" />\n      <Setter Property=\"Foreground\" Value=\"{DynamicResource ThemeForegroundBrush}\" />\n      <Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n      <Setter Property=\"Padding\" Value=\"6\" />\n      <Setter Property=\"Margin\" Value=\"0 2\" />\n      <Setter Property=\"FontSize\" Value=\"12\" />\n    </Style>\n    <Style Selector=\"TextBox TextBlock\">\n      <Setter Property=\"FontSize\" Value=\"12\" />\n    </Style>\n    <Style Selector=\"TextBox /template/ Border\">\n      <Setter Property=\"CornerRadius\" Value=\"5\" />\n    </Style>\n    <Style Selector=\"TextBox:pointerover /template/ Border\">\n      <Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n    </Style>\n    <Style Selector=\"TextBox:focus /template/ Border\">\n      <Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n    </Style>\n    <Style Selector=\"Button.Compact\">\n      <Setter Property=\"Margin\" Value=\"0\" />\n      <Setter Property=\"Padding\" Value=\"0\" />\n      <Setter Property=\"BorderThickness\" Value=\"0\" />\n    </Style>\n    <Style Selector=\"DataGrid Button\">\n      <Setter Property=\"BorderThickness\" Value=\"0\" />\n    </Style>\n  </Window.Styles>\n\n  <Panel Name=\"WindowContext\">\n\t\t<StackPanel Margin=\"20\">\n      <Panel>\n\t\t\t  <ExperimentalAcrylicBorder IsHitTestVisible=\"False\">\n\t\t\t\t  <ExperimentalAcrylicBorder.Material>\n\t\t\t\t\t  <ExperimentalAcrylicMaterial\n\t\t\t\t\t\t  BackgroundSource=\"Digger\"\n\t\t\t\t\t\t  TintColor=\"Black\"\n\t\t\t\t\t\t  TintOpacity=\"0.2\"\n\t\t\t\t\t\t  MaterialOpacity=\"0.25\" />\n\t\t\t\t  </ExperimentalAcrylicBorder.Material>\n\t\t\t  </ExperimentalAcrylicBorder>\n\t\t  </Panel>\n\n      <StackPanel Orientation=\"Horizontal\">\n\t\t\t\t\t<DataGrid Name=\"FolderGrid\" Height=\"100\" MaxHeight=\"100\" Items=\"{Binding Settings.HarvesterLogDirectories}\" Classes=\"folders\">\n\t\t\t\t\t\t<DataGrid.Columns>\n\t\t\t\t\t\t\t<DataGridTemplateColumn Width=\"60\">\n\t\t\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t\t\t<Button Width=\"60\" Name=\"AddFolderButton\" Click=\"AddFolder\" Content=\"Add\"></Button>\n\t\t\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t\t\t<Button Name=\"RemoveFolderButton\" Content=\"Remove\" Tag=\"{Binding}\" Click=\"RemoveFolder\"></Button>\n\t\t\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t</DataGridTemplateColumn>\n\t\t\t\t\t\t\t<DataGridTextColumn Header=\"Log Folders\" Binding=\"{Binding}\" Width=\"400\" />\n\t\t\t\t\t\t</DataGrid.Columns>\n\t\t\t\t\t</DataGrid>\n      </StackPanel>\n\n\n      <StackPanel Name=\"Loading\" Orientation=\"Horizontal\">\n        <TextBlock Text=\"Parsing log data. This takes a while!\"></TextBlock>\n      </StackPanel>\n\n      <StackPanel Name=\"Loaded\" IsVisible=\"False\" Orientation=\"Horizontal\">\n\n        <DataGrid Name=\"SummeriesDataGrid\" Items=\"{Binding Summaries}\" CanUserResizeColumns=\"true\" CanUserReorderColumns=\"false\" CanUserSortColumns=\"false\">\n          <DataGrid.Columns>\n            <DataGridTemplateColumn SortMemberPath=\"LogFolder\">\n              <DataGridTemplateColumn.Header>\n                 <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.LogFolder}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate >\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.LogFolder}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding LogFolder}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n            <DataGridTemplateColumn SortMemberPath=\"RuntimeMinutes\">\n              <DataGridTemplateColumn.Header>\n                <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.RuntimeMinutes}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate>\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.RuntimeMinutes}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding RuntimeMinutes}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n            <DataGridTemplateColumn SortMemberPath=\"AvgLookupTime\">\n              <DataGridTemplateColumn.Header>\n                <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.AvgLookupTime}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate>\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.AvgLookupTime}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding AvgLookupTime}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n            <DataGridTemplateColumn SortMemberPath=\"WorstLookupTime\">\n              <DataGridTemplateColumn.Header>\n                <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.WorstLookupTime}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate>\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.WorstLookupTime}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding WorstLookupTime}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n            <DataGridTemplateColumn SortMemberPath=\"BestLookupTime\">\n              <DataGridTemplateColumn.Header>\n                <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.BestLookupTime}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate>\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.BestLookupTime}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding BestLookupTime}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n            <DataGridTemplateColumn SortMemberPath=\"ChallengesPerMinute\">\n              <DataGridTemplateColumn.Header>\n                <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.ChallengesPerMinute}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate>\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.ChallengesPerMinute}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding ChallengesPerMinute}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n            <DataGridTemplateColumn SortMemberPath=\"FilterRatio\">\n              <DataGridTemplateColumn.Header>\n                <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.FilterRatio}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate>\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.FilterRatio}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding FilterRatio}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n            <DataGridTemplateColumn SortMemberPath=\"FoundProofs\">\n              <DataGridTemplateColumn.Header>\n                <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.FoundProofs}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate>\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.FoundProofs}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding FoundProofs}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n            <DataGridTemplateColumn SortMemberPath=\"AvgEligiblePlots\">\n              <DataGridTemplateColumn.Header>\n                <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.AvgEligiblePlots}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate>\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.AvgEligiblePlots}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding AvgEligiblePlots}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n            <DataGridTemplateColumn SortMemberPath=\"TotalPlots\">\n              <DataGridTemplateColumn.Header>\n                <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.TotalPlots}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n              </DataGridTemplateColumn.Header>\n              <DataGridTemplateColumn.CellTemplate>\n                <DataTemplate>\n                  <StackPanel>\n                    <ToolTip.Tip>\n                      <StackPanel>\n                        <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.TotalPlots}\"></TextBlock>\n                      </StackPanel>\n                    </ToolTip.Tip>\n                    <TextBlock Text=\"{Binding TotalPlots}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                  </StackPanel>\n                </DataTemplate>\n              </DataGridTemplateColumn.CellTemplate>\n            </DataGridTemplateColumn>\n          </DataGrid.Columns>\n        </DataGrid>\n      </StackPanel>\n    </StackPanel>\n\t</Panel>\n</Window>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/HarvestDialog.axaml.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Interactivity;\nusing Avalonia.Layout;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Markup.Xaml.Styling;\nusing Avalonia.Threading;\nusing ChiaPlotStatus.GUI.Models;\nusing ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusGUI.GUI.Utils;\nusing ChiaPlotStatusLib.Logic.Models;\nusing ChiaPlotStatusLib.Logic.Statistics.Harvest;\nusing ReactiveUI;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.IO;\nusing System.Reactive;\nusing System.Text.RegularExpressions;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.Views\n{\n\n    /**\n     * TODO:\n     * - FolderList\n     * - AddFolder\n     * - RemoveFolder\n     * - Summary List\n     * - Heatmaps in Details (either tabs or sub-dialogs)\n     */\n    public class HarvestDialog : Window\n    {\n        public Settings Settings { get; set; }\n        public Language Language { get; set; }\n        public List<Tuple<string, HarvestSummary, List<Harvest>>?> Results { get; set; }\n        public ObservableCollection<HarvestSummeryReadable> Summaries { get; set; } = new();\n        public ObservableCollection<string> PathsWithoutResults { get; set; } = new();\n\n        public HarvestDialog()\n        {\n        }\n\n        public HarvestDialog(Language language, Settings settings, string theme)\n        {\n            this.DataContext = this;\n            this.Language = language;\n            this.Settings = settings;\n            foreach (var path in HarvestParser.DefaultPaths())\n                 this.Settings.HarvesterLogDirectories.Add(path);\n            InitializeComponent();\n            KeepGridScrollbarOnScreen();\n#if DEBUG\n            this.AttachDevTools();\n#endif\n            Utils.SetTheme(this, theme);\n\n\n            //Task.Run(async () =>\n            //{\n                LoadData();\n                Dispatcher.UIThread.InvokeAsync(() =>\n                {\n                    this.Find<StackPanel>(\"Loading\").IsVisible = false;\n                    this.Find<StackPanel>(\"Loaded\").IsVisible = true;\n                });\n            //});\n\n            this.WindowState = WindowState.Maximized;\n            this.Focus();\n        }\n\n\n        public void AddFolder(string folder)\n        {\n            if (!Settings.HarvesterLogDirectories.Contains(folder))\n            {\n                Settings.HarvesterLogDirectories.Add(folder);\n                Settings.Persist();\n                LoadData();\n            }\n        }\n\n        public void AddFolder(object sender, RoutedEventArgs e)\n        {\n            Task.Run(async () =>\n            {\n                OpenFolderDialog picker = new OpenFolderDialog();\n                var result = await picker.ShowAsync(this);\n                Dispatcher.UIThread.InvokeAsync(() => AddFolder(result));\n            });\n        }\n\n        public void RemoveFolder (object sender, RoutedEventArgs e) {\n            string folder = (string)((Button)sender).Tag;\n            Settings.HarvesterLogDirectories.Remove(folder);\n            Settings.Persist();\n            LoadData();\n        }\n\n        private void LoadData()\n        {\n            Summaries.Clear();\n            PathsWithoutResults.Clear();\n\n            Results = new HarvestParser().ParseLogs(new List<string>(this.Settings.HarvesterLogDirectories),\n                (double)this.Settings.MaxHarvestLookupSeconds, 500);\n\n            // assume all are missing until a result is found\n            foreach (var path in this.Settings.HarvesterLogDirectories)\n                PathsWithoutResults.Add(path);\n\n            foreach (var triplet in Results)\n            {\n                if (triplet != null)\n                {\n                    Summaries.Add(new HarvestSummeryReadable(triplet.Item2));\n                    PathsWithoutResults.Remove(triplet.Item1);\n                }\n            }\n        }\n\n        private void KeepGridScrollbarOnScreen()\n        {\n            this.WhenAnyValue(x => x.Height)\n                .Subscribe(x =>\n                {\n                    var summeriesDataGrid = this.Find<DataGrid>(\"SummeriesDataGrid\");\n                    summeriesDataGrid.Height = x - 100;\n                });\n        }\n\n        public void DataGridHeaderClick(object sender, RoutedEventArgs e)\n        {\n\n        }\n\n        private void InitializeComponent()\n        {\n            AvaloniaXamlLoader.Load(this);\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/MainWindow.axaml",
    "content": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:vm=\"using:ChiaPlotStatus.ViewModels\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\" d:DesignWidth=\"1000\" d:DesignHeight=\"700\"\n        x:Class=\"ChiaPlotStatus.Views.MainWindow\"\n        Icon=\"/GUI/Assets/Logo.png\"\n        TransparencyLevelHint=\"Transparent\"\n        ExtendClientAreaToDecorationsHint=\"False\"\n        Title=\"Chia Plot Status\">\n\n\t<Window.DataContext>\n\t\t<vm:MainWindowViewModel/>\n\t</Window.DataContext>\n\t<Window.Styles>\n\t\t<Style Selector=\"DataGridColumnHeader > Button\">\n\t\t\t<Setter Property=\"BorderThickness\" Value=\"0\" />\n\t\t</Style>\n\t\t<Style Selector=\"StackPanel.Export > Border, StackPanel.Selection > Border\">\n\t\t\t<Setter Property=\"Margin\" Value=\"0\" />\n\t\t\t<Setter Property=\"Padding\" Value=\"2\" />\n\t\t</Style>\n\t\t<Style Selector=\"StackPanel.Export Button, StackPanel.Selection Button\">\n\t\t\t<Setter Property=\"Height\" Value=\"25\" />\n\t\t\t<Setter Property=\"Margin\" Value=\"0\" />\n\t\t\t<Setter Property=\"Padding\" Value=\"2\" />\n\t\t</Style>\n\t\t<Style Selector=\"DataGridRow\">\n            <Setter Property=\"Margin\" Value=\"2\" />\n        </Style>\n        <Style Selector=\"ToolTip TextBlock\">\n        </Style>\n\t\t<Style Selector=\"TextBlock\">\n\t\t\t<!-- <Setter Property=\"FontSize\" Value=\"{Binding ElementName=WindowContext, Path=DataContext.PlotManager.Settings.FontSize, Mode=TwoWay}\"/> -->\n\t\t\t<Setter Property=\"FontSize\" Value=\"10\"/>\n\t\t</Style>\n\t\t<Style Selector=\"DataGrid.folders\">\n\t\t</Style>\n\t\t<Style Selector=\"DataGrid.folders TextBlock\">\n\t\t</Style>\n\t\t<Style Selector=\"DataGrid.folders Button\">\n\t\t</Style>\n\t\t<Style Selector=\"DataGrid TextBlock\">\n\t\t\t<Setter Property=\"Margin\" Value=\"4, 1\"/>\n\t\t\t<Setter Property=\"FontSize\" Value=\"12\"/>\n\t\t</Style>\n\t\t<Style Selector=\"ToolTip\">\n\t\t\t<Setter Property=\"MaxWidth\" Value=\"600\"/>\n\t\t\t<Setter Property=\"MaxHeight\" Value=\"600\"/>\n\t\t</Style>\n\t\t<Style Selector=\"ToolTip TextBlock\">\n\t\t\t<Setter Property=\"MaxWidth\" Value=\"600\"/>\n\t\t\t<Setter Property=\"MaxHeight\" Value=\"600\"/>\n\t\t\t<Setter Property=\"FontSize\" Value=\"10.3\"/>\n\t\t\t<Setter Property=\"TextWrapping\" Value=\"Wrap\"/>\n\t\t</Style>\n\t\t<Style Selector=\"ComboBox\">\n\t\t\t<Setter Property=\"BorderThickness\" Value=\"1\" />\n\t\t\t<Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n\t\t\t<Setter Property=\"Padding\" Value=\"6\" />\n\t\t\t<Setter Property=\"FontSize\" Value=\"12\" />\n\t\t</Style>\n\t\t<Style Selector=\"ComboBox /template/ Border\">\n\t\t\t<Setter Property=\"CornerRadius\" Value=\"5\" />\n\t\t</Style>\n\t\t<Style Selector=\"ComboBox:pointerover /template/ Border\">\n\t\t\t<Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n\t\t</Style>\n\t\t<Style Selector=\"ComboBox:pointerover:focus /template/ Border\">\n\t\t\t<Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n\t\t</Style>\n\n\t\t<Style Selector=\"ComboBoxItem\">\n\t\t\t<Setter Property=\"Padding\" Value=\"5\" />\n\t\t</Style>\n\t\t<Style Selector=\"ComboBoxItem:selected > TextBlock\">\n\t\t\t<Setter Property=\"Foreground\" Value=\"{DynamicResource HighlightForegroundBrush}\" />\n\t\t</Style>\n\t\t<Style Selector=\"TextBox\">\n\t\t\t<!-- <Setter Property=\"FontFamily\" Value=\"Ubuntu\" /> -->\n\t\t\t<Setter Property=\"BorderThickness\" Value=\"1\" />\n\t\t\t<Setter Property=\"Foreground\" Value=\"{DynamicResource ThemeForegroundBrush}\" />\n\t\t\t<Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n\t\t\t<Setter Property=\"Padding\" Value=\"6\" />\n\t\t\t<Setter Property=\"Margin\" Value=\"0 2\" />\n\t\t\t<Setter Property=\"FontSize\" Value=\"12\" />\n\t\t</Style>\n\t\t<Style Selector=\"TextBox TextBlock\">\n\t\t\t<Setter Property=\"FontSize\" Value=\"12\" />\n\t\t</Style>\n\t\t<Style Selector=\"TextBox /template/ Border\">\n\t\t\t<Setter Property=\"CornerRadius\" Value=\"5\" />\n\t\t</Style>\n\t\t<Style Selector=\"TextBox:pointerover /template/ Border\">\n\t\t\t<Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n\t\t</Style>\n\t\t<Style Selector=\"TextBox:focus /template/ Border\">\n\t\t\t<Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n\t\t</Style>\n\t\t<Style Selector=\"CheckBox\">\n\t\t\t<Setter Property=\"BorderThickness\" Value=\"1\" />\n\t\t\t<Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n\t\t</Style>\n\t\t<Style Selector=\"CheckBox /template/ Border\">\n\t\t\t<Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n\t\t</Style>\n\t\t<Style Selector=\"CheckBox:pointerover\">\n\t\t\t<Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n\t\t</Style>\n\n    <Style Selector=\"StackPanel.Filters > Border\">\n      <Setter Property=\"Margin\" Value=\"2\" />\n      <Setter Property=\"Padding\" Value=\"2\" />\n    </Style>\n    <Style Selector=\"Button.Compact\">\n      <Setter Property=\"Margin\" Value=\"0\" />\n      <Setter Property=\"Padding\" Value=\"0\" />\n      <Setter Property=\"BorderThickness\" Value=\"0\" />\n    </Style>\n\n\n    <Style Selector=\"StackPanel.PlotCounts\">\n      <Setter Property=\"Margin\" Value=\"6 2\" />\n    </Style>\n    <Style Selector=\"StackPanel.PlotCounts TextBlock\">\n      <Setter Property=\"Margin\" Value=\"2\" />\n      <Setter Property=\"FontSize\" Value=\"12\" />\n    </Style>\n  </Window.Styles>\n\n\n\t<ScrollViewer Name=\"WindowContext\">\n\t\t<StackPanel>\n      <!--\n      <StackPanel Classes=\"LogLines\" Orientation=\"Vertical\">\n        <StackPanel Classes=\"Line\" Orientation=\"Horizontal\">\n          <TextBlock Classes=\"\">sort time =  2374.087 seconds. CPU (41.570%) Sun May  2 04:49:41 2021</TextBlock>\n        </StackPanel>\n        <StackPanel Classes=\"Line\" Orientation=\"Horizontal\">\n          Tooltips\n\t\t\t\t<TextBlock Classes=\"Level1\">Time for phase 1 = </TextBlock>\n          <TextBlock Classes=\"Level2\">41645.190</TextBlock>\n          <TextBlock Classes=\"Level1\"> seconds. CPU (</TextBlock>\n          <TextBlock Classes=\"Level2\">80.080%</TextBlock>\n          <TextBlock Classes=\"Level1\">) Sat May  1 23:38:19 2021</TextBlock>\n        </StackPanel>\n      </StackPanel>\n-->\n\n      <Panel>\n\t\t\t<ExperimentalAcrylicBorder IsHitTestVisible=\"False\">\n\t\t\t\t<ExperimentalAcrylicBorder.Material>\n\t\t\t\t\t<ExperimentalAcrylicMaterial\n\t\t\t\t\t\tBackgroundSource=\"Digger\"\n\t\t\t\t\t\tTintColor=\"Black\"\n\t\t\t\t\t\tTintOpacity=\"0.2\"\n\t\t\t\t\t\tMaterialOpacity=\"0.25\" />\n\t\t\t\t</ExperimentalAcrylicBorder.Material>\n\t\t\t</ExperimentalAcrylicBorder>\n\t\t</Panel>\n\n      <DockPanel>\n        <Menu DockPanel.Dock=\"Top\">\n          <MenuItem Header=\"Update\" Name=\"UpdateButton\" />\n          <MenuItem Header=\"Donate\" Name=\"DonateButton\" />\n          <MenuItem Header=\"Statistics\" Name=\"StatisticsButton\" />\n          <MenuItem Header=\"Harvesters\" Name=\"HarvestersButton\" />\n          <!--\n          <MenuItem Header=\"Chia-Plotter\" Name=\"ChiaPlotterButton\" />\n          -->\n        </Menu>\n      </DockPanel>\n\t\t\t<StackPanel Orientation=\"Horizontal\">\n\t\t\t\t<Image Source=\"/GUI/Assets/Logo.png\" Width=\"100\" Height=\"100\" Grid.Row=\"0\" Grid.Column=\"0\" Grid.RowSpan=\"2\" />\n\t\t\t\t<StackPanel Grid.Row=\"0\" Grid.Column=\"1\" Grid.RowSpan=\"2\">\n\t\t\t\t\t<DataGrid Name=\"FolderGrid\" Height=\"100\" MaxHeight=\"100\" Items=\"{Binding PlotManager.Settings.LogDirectories}\" Classes=\"folders\">\n\t\t\t\t\t\t<DataGrid.Columns>\n\t\t\t\t\t\t\t<DataGridTemplateColumn Width=\"60\">\n\t\t\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t\t\t<Button Width=\"60\" Command=\"{Binding AddFolderCommand}\" Content=\"Add\"></Button>\n\t\t\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t\t\t<Button Command=\"{Binding RemoveFolderCommand}\"\n\t\t\t\t\t\t\t\t\t\t\t\tCommandParameter=\"{Binding}\" Click=\"RemoveFolderWorkaround\" Tag=\"{Binding RemoveFolderCommand}\"\n\t\t\t\t\t\t\t\t\t\t\t\tContent=\"Remove\"></Button>\n\t\t\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t</DataGridTemplateColumn>\n\t\t\t\t\t\t\t<DataGridTextColumn Header=\"Log Folders\" Binding=\"{Binding}\" Width=\"400\" />\n\t\t\t\t\t\t</DataGrid.Columns>\n\t\t\t\t\t</DataGrid>\n\t\t\t\t</StackPanel>\n\t\t\t\t<!--\n\t\t\t\t<StackPanel Grid.Row=\"1\" Grid.Column=\"2\">\n\t\t\t\t\t<TextBlock Text=\"font size\"></TextBlock>\n\t\t\t\t</StackPanel>\n\t\t\t\t<StackPanel Grid.Row=\"2\" Grid.Column=\"2\">\n\t\t\t\t\t<Button Content=\"+\" Command=\"{Binding IncreaseFontSizeCommand}\"></Button>\n\t\t\t\t\t<Button Content=\"-\" Command=\"{Binding DecreaseFontSizeCommand}\"></Button>\n\t\t\t\t</StackPanel>\n\t\t\t\t-->\n\t\t\t\t<StackPanel Orientation=\"Vertical\">\n\t\t\t\t\t<TextBox Name=\"SearchBox\" Width=\"300\" Watermark=\"Search\" Text=\"{Binding Search, Mode=TwoWay}\" KeyUp=\"OnKeyPressUp\" />\n\t\t\t\t\t<ComboBox Name=\"Themes\">\n\t\t\t\t\t\t<ComboBoxItem Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Fields.Light}\"></ComboBoxItem>\n            <ComboBoxItem Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Fields.Dark}\"></ComboBoxItem>\n\t\t\t\t\t</ComboBox>\n\t\t\t\t\t<StackPanel Classes=\"Export\" Orientation=\"Horizontal\">\n\t\t\t\t\t\t<Border>\n\t\t\t\t\t\t\t<Button Content=\"Json\" Command=\"{Binding ExportJsonCommand}\">\n\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.JsonExport}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</Border>\n\t\t\t\t\t\t<Border>\n\t\t\t\t\t\t\t<Button Content=\"Yaml\" Command=\"{Binding ExportYamlCommand}\">\n\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.YamlExport}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</Border>\n\t\t\t\t\t\t<Border>\n\t\t\t\t\t\t\t<Button Content=\"CSV\" Command=\"{Binding ExportCsvCommand}\">\n\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CsvExport}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</Border>\n\t\t\t\t\t\t<Border>\n\t\t\t\t\t\t\t<CheckBox Content=\"Raw Export\" IsChecked=\"{Binding RawExport}\">\n\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.RawExport}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t</CheckBox>\n\t\t\t\t\t\t</Border>\n\t\t\t\t\t</StackPanel>\n\t\t\t\t</StackPanel>\n        <StackPanel Name=\"Filters\" Classes=\"Filters\" Orientation=\"Vertical\">\n          <Border>\n            <CheckBox Name=\"HideConfirmedDead\" Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Fields.HideConfirmedDead}\" IsChecked=\"{Binding ElementName=WindowContext, Path=DataContext.PlotManager.Settings.Filter.HideConfirmedDead}\">\n              <ToolTip.Tip>\n                <StackPanel>\n                  <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.HideConfirmedDead}\"></TextBlock>\n                </StackPanel>\n              </ToolTip.Tip>\n            </CheckBox>\n          </Border>\n          <Border>\n            <CheckBox Name=\"HidePossiblyDead\" Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Fields.HidePossiblyDead}\" IsChecked=\"{Binding ElementName=WindowContext, Path=DataContext.PlotManager.Settings.Filter.HidePossiblyDead}\">\n              <ToolTip.Tip>\n                <StackPanel>\n                  <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.HidePossiblyDead}\"></TextBlock>\n                </StackPanel>\n              </ToolTip.Tip>\n            </CheckBox>\n          </Border>\n          <Border>\n            <CheckBox Name=\"HideHealthy\" Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Fields.HideHealthy}\" IsChecked=\"{Binding ElementName=WindowContext, Path=DataContext.PlotManager.Settings.Filter.HideHealthy}\">\n              <ToolTip.Tip>\n                <StackPanel>\n                  <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.HideHealthy}\"></TextBlock>\n                </StackPanel>\n              </ToolTip.Tip>\n            </CheckBox>\n          </Border>\n          <Border>\n            <CheckBox Name=\"HideFinished\" Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Fields.HideFinished}\" IsChecked=\"{Binding ElementName=WindowContext, Path=DataContext.PlotManager.Settings.Filter.HideFinished}\">\n              <ToolTip.Tip>\n                <StackPanel>\n                  <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.HideFinished}\"></TextBlock>\n                </StackPanel>\n              </ToolTip.Tip>\n            </CheckBox>\n          </Border>\n        </StackPanel>\n        <StackPanel Orientation=\"Vertical\" Classes=\"PlotCounts\">\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock>\n              Running:\n            </TextBlock>\n            <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.PlotCounts.Running, Mode=TwoWay}\"/>\n          </StackPanel>\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock>\n              Finished:\n            </TextBlock>\n            <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.PlotCounts.Finished, Mode=TwoWay}\"/>\n          </StackPanel>\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock>\n              Concerning:\n            </TextBlock>\n            <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.PlotCounts.Concerning, Mode=TwoWay}\"/>\n          </StackPanel>\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock>\n              Failed:\n            </TextBlock>\n            <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.PlotCounts.Failed, Mode=TwoWay}\"/>\n          </StackPanel>\n        </StackPanel>\n        <StackPanel Orientation=\"Vertical\" Classes=\"PlotCounts\">\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock>\n              Phase 1:\n            </TextBlock>\n            <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.PlotCounts.PlotsInPhase1, Mode=TwoWay}\"/>\n          </StackPanel>\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock>\n              Phase 2:\n            </TextBlock>\n            <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.PlotCounts.PlotsInPhase2, Mode=TwoWay}\"/>\n          </StackPanel>\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock>\n              Phase 3:\n            </TextBlock>\n            <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.PlotCounts.PlotsInPhase3, Mode=TwoWay}\"/>\n          </StackPanel>\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock>\n              Phase 4:\n            </TextBlock>\n            <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.PlotCounts.PlotsInPhase4, Mode=TwoWay}\"/>\n          </StackPanel>\n          <StackPanel Orientation=\"Horizontal\">\n            <TextBlock>\n              Phase 5:\n            </TextBlock>\n            <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.PlotCounts.PlotsInPhase5, Mode=TwoWay}\"/>\n          </StackPanel>\n        </StackPanel>\n\n        <StackPanel Orientation=\"Vertical\" Classes=\"Selection\">\n          <Border>\n            <Button Name=\"RefreshPauseButton\" Content=\"Refresh ▶\"></Button>\n          </Border>\n          <Border>\n            <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Buttons.SelectAllConcerningCommand}\" Command=\"{Binding ElementName=WindowContext, Path=DataContext.SelectAllConcerningCommand}\"></Button>\n          </Border>\n          <Border>\n            <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Buttons.SelectAllPossiblyDeadCommand}\" Command=\"{Binding ElementName=WindowContext, Path=DataContext.SelectAllPossiblyDeadCommand}\"></Button>\n          </Border>\n          <Border>\n            <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Buttons.MarkSelectionAsDead}\" Command=\"{Binding ElementName=WindowContext, Path=DataContext.MarkSelectionAsDeadCommand}\"></Button>\n          </Border>\n        </StackPanel>\n\t\t\t</StackPanel>\n\n      <DataGrid Name=\"LogDataGrid\" Items=\"{Binding PlotLogs}\" IsReadOnly=\"true\" MinHeight=\"80\" CanUserSortColumns=\"false\" CanUserResizeColumns=\"true\">\n        <DataGrid.Columns>\n          <DataGridTemplateColumn SortMemberPath=\"Selection\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Selection}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <CheckBox IsChecked=\"{Binding IsSelected, Mode=TwoWay}\" Checked=\"OnSelectionChanged\"></CheckBox>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Note\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Note}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <Button Content=\"{Binding Note}\" HorizontalAlignment=\"Left\" Classes=\"Compact\" Command=\"{Binding ElementName=WindowContext, Path=DataContext.NoteCommand}\" CommandParameter=\"{Binding}\"\n                    ></Button>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Tmp1Drive\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Tmp1Drive}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate>\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding Tmp1Drive}\" HorizontalAlignment=\"Left\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Tmp2Drive\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Tmp2Drive}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate>\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding Tmp2Drive}\" HorizontalAlignment=\"Left\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n\t\t\t\t\t<DataGridTemplateColumn SortMemberPath=\"DestDrive\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.DestDrive}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate>\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.DestDrive}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding DestDrive}\" HorizontalAlignment=\"Left\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"StartDate\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.StartDate}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate>\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.StartDate}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding StartDate}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n\t\t\t\t\t<DataGridTemplateColumn SortMemberPath=\"FinishDate\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.FinishDate}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate>\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.FinishDate}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding FinishDate}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Health\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Health}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Health}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <Button Content=\"{Binding Health}\" HorizontalAlignment=\"Left\" Classes=\"Compact\" Command=\"{Binding ElementName=WindowContext, Path=DataContext.MarkAsDeadCommand}\" CommandParameter=\"{Binding}\"\n                    ></Button>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Errors\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Errors}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Errors}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Errors}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"PID\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.PID}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.PID}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding PID}\" HorizontalAlignment=\"Right\"></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Progress\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Progress}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Progress}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding Progress}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"ETA\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.ETA}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.ETA}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ETA}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn >\n          <DataGridTemplateColumn SortMemberPath=\"TimeRemaining\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.TimeRemaining}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.TimeRemaining}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding TimeRemaining}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn >\n          <DataGridTemplateColumn SortMemberPath=\"RunTimeSeconds\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.RunTimeSeconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.RunTimeSeconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding RunTimeSeconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"CurrentPhase\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.CurrentPhase}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CurrentPhase}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding CurrentPhase}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"CurrentTable\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.CurrentTable}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CurrentTable}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding CurrentTable}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"CurrentBucket\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.CurrentBucket}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CurrentBucket}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding CurrentBucket}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn >\n          <DataGridTemplateColumn SortMemberPath=\"Phase1Seconds\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase1Seconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase1Seconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase1Seconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase1Cpu\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase1Cpu}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase1Cpu}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase1Cpu}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase2Seconds\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase2Seconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase2Seconds}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding Phase2Seconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase2Cpu\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase2Cpu}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase2Cpu}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase2Cpu}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase3Seconds\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase3Seconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase3Seconds}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding Phase3Seconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase3Cpu\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase3Cpu}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase3Cpu}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase3Cpu}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase4Seconds\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase4Seconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase4Seconds}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding Phase4Seconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase4Cpu\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase4Cpu}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase4Cpu}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase4Cpu}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"CopyTimeSeconds\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.CopyTimeSeconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate>\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CopyTimeSeconds}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding CopyTimeSeconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"TotalSeconds\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.TotalSeconds}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.TotalSeconds}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding TotalSeconds}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Buffer\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Buffer}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Buffer}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding Buffer}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Buckets\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Buckets}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Buckets}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding Buckets}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Threads\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Threads}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate>\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Threads}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding Threads}\" HorizontalAlignment=\"Right\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"LogFolder\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.LogFolder}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.LogFolder}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding LogFolder}\" HorizontalAlignment=\"Left\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"LogFile\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.LogFile}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate >\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.LogFile}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<Button Classes=\"Compact\" Content=\"{Binding LogFile}\" HorizontalAlignment=\"Left\" Click=\"OpenLogViewerWindow\" Tag=\"{Binding}\"></Button>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn >\n          <DataGridTemplateColumn SortMemberPath=\"PlaceInLogFile\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.PlaceInLogFile}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.PlaceInLogFile}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding PlaceInLogFile}\" HorizontalAlignment=\"Left\"></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn >\n          <DataGridTemplateColumn SortMemberPath=\"ApproximateWorkingSpace\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.ApproximateWorkingSpace}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.ApproximateWorkingSpace}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding ApproximateWorkingSpace}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"FinalFileSize\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.FinalFileSize}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.FinalFileSize}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding FinalFileSize}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"PoolPuzzleHash\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.PoolPuzzleHash}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.PoolPuzzleHash}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding PoolPuzzleHash}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"LastLogLine\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.LastLogLine}\" HorizontalAlignment=\"Left\" Click=\"LogDataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.LastLogLine}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding LastLogLine}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n\t\t\t\t</DataGrid.Columns>\n\t\t\t</DataGrid>\n\t\t\t<TextBlock>\n\t\t\t\tLogo made by charlie on freeicons.io under License Creative Commons(Attribution 3.0 unported)\n\t\t\t</TextBlock>\n\t    </StackPanel>\n\t</ScrollViewer>\n</Window>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/MainWindow.axaml.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Interactivity;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Markup.Xaml.Styling;\nusing ChiaPlotStatusGUI.GUI.Utils;\nusing ReactiveUI;\nusing System;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.IO;\nusing System.Reactive;\nusing System.Runtime.InteropServices;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.Views\n{\n    public class MainWindow : Window\n    {\n        public static MainWindow? Instance { get; private set; }\n        public Func<string, bool> BtnClickWorkaround { get; set; }\n        public Func<string, bool> TextChangeWorkaround { get; set; }\n        public Func<string, bool> SortChangeWorkaround { get; set; }\n        public Func<string, bool> ThemeSwitchWorkaround { get; set; }\n        public Action SelectionChangedAction { get; set; }\n\n        public MainWindow()\n        {\n            Instance = this;\n            InitializeComponent();\n#if DEBUG\n            this.AttachDevTools();\n#endif\n            ThemeSwitcher();\n            this.WindowState = WindowState.Maximized;\n        }\n\n        private void InitializeComponent()\n        {\n            AvaloniaXamlLoader.Load(this);\n        }\n\n\n\n        // FIXME: RemoveFolderCommand does not trigger. Why is button.Command null?\n        public void RemoveFolderWorkaround(object sender, RoutedEventArgs e)\n        {\n            Button button = (Button)sender;\n            string folder = (string)button.CommandParameter;\n            ReactiveCommand<string, Unit> command = (ReactiveCommand<string, Unit>)button.Command;\n            if (command == null)\n            {\n                command = (ReactiveCommand<string, Unit>)button.Tag;\n            }\n            // button.Command.Execute(folder);\n            BtnClickWorkaround.Invoke(folder);\n        }\n\n\n        // FIXME: apparently avalonia cannot tell me when a textbox text changes in my MainWindowViewModel\n        public void OnKeyPressUp(object sender, KeyEventArgs e)\n        {\n            TextChangeWorkaround(((TextBox)sender).Text);\n        }\n\n        public void LogDataGridHeaderClick(object sender, RoutedEventArgs e)\n        {\n            Button header = ((Button)sender);\n            string headerText = (string) header.Content;\n            SortChangeWorkaround(headerText);\n        }\n\n        public void ThemeSwitcher()\n        {\n            var themes = this.Find<ComboBox>(\"Themes\");\n            themes.SelectionChanged += (sender, e) =>\n            {\n                switch (themes.SelectedIndex)\n                {\n                    case 1:\n                        ThemeSwitchWorkaround(\"Dark\");\n                        break;\n                    default:\n                        ThemeSwitchWorkaround(\"Light\");\n                        break;\n                }\n            };\n        }\n\n\n        public void OnSelectionChanged(object sender, RoutedEventArgs e)\n        {\n            SelectionChangedAction();\n        }\n\n        public void OpenLogViewerWindow(object sender, RoutedEventArgs e)\n        {\n            var plotLogReadable = (PlotLogReadable)((Button)sender).Tag;\n            var path = plotLogReadable.LogFolder + Path.DirectorySeparatorChar + plotLogReadable.LogFile;\n            Utils.OpenLogFile(path);\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/MarkOfDeathDialog.axaml",
    "content": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\" d:DesignWidth=\"400\" d:DesignHeight=\"100\"\n        Width=\"400\" Height=\"100\"\n        x:Class=\"ChiaPlotStatus.Views.MarkOfDeathDialog\"\n        Icon=\"/GUI/Assets/Logo.png\"\n        TransparencyLevelHint=\"Transparent\"\n        ExtendClientAreaToDecorationsHint=\"False\"\n        Title=\"Mark this Plotting Process as Dead?\">\n\n  <!--\n\t<Window.DataContext>\n\t\t<vm:MainWindowViewModel/>\n\t</Window.DataContext>\n  -->\n\t<Window.Styles>\n    <Style>\n      <!-- will be replaced with dark theme-->\n    </Style>\n    <Style Selector=\"Button\">\n      <Setter Property=\"Margin\" Value=\"4\" />\n    </Style>\n\t</Window.Styles>\n\n  <Panel Name=\"WindowContext\">\n\t\t<StackPanel Margin=\"20\">\n      <Panel>\n\t\t\t  <ExperimentalAcrylicBorder IsHitTestVisible=\"False\">\n\t\t\t\t  <ExperimentalAcrylicBorder.Material>\n\t\t\t\t\t  <ExperimentalAcrylicMaterial\n\t\t\t\t\t\t  BackgroundSource=\"Digger\"\n\t\t\t\t\t\t  TintColor=\"Black\"\n\t\t\t\t\t\t  TintOpacity=\"0.2\"\n\t\t\t\t\t\t  MaterialOpacity=\"0.25\" />\n\t\t\t\t  </ExperimentalAcrylicBorder.Material>\n\t\t\t  </ExperimentalAcrylicBorder>\n\t\t  </Panel>\n\n      <TextBlock Text=\"Mark this Plotting Process as Dead?\"></TextBlock>\n      <TextBlock Text=\" \"></TextBlock>\n\n      <StackPanel Orientation=\"Horizontal\">\n        <Button Name=\"MarkAsDead\" Click=\"MarkAsDead\">\n          <TextBlock Text=\"{Binding Language.Buttons.MarkAsDead }\"></TextBlock>\n        </Button>\n        <Button Name=\"UnmarkAsDead\" Click=\"UnmarkAsDead\">\n          <TextBlock Text=\"{Binding Language.Buttons.UnmarkAsDead }\"></TextBlock>\n        </Button>\n        <Button Name=\"Abort\" Click=\"Abort\">\n          <TextBlock Text=\"{Binding Language.Buttons.Abort }\"></TextBlock>\n        </Button>\n      </StackPanel>\n    </StackPanel>\n\t</Panel>\n</Window>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/MarkOfDeathDialog.axaml.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Interactivity;\nusing Avalonia.Layout;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Markup.Xaml.Styling;\nusing ChiaPlotStatus.GUI.Models;\nusing ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusGUI.GUI.Utils;\nusing ReactiveUI;\nusing System;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.Reactive;\nusing System.Text.RegularExpressions;\n\nnamespace ChiaPlotStatus.Views\n{\n    public class MarkOfDeathDialog : Window\n    {\n        public Settings Settings { get; set; }\n        public Language Language { get; set; }\n        public Action OnUpdate { get; set; }\n        public bool IsDead { get; set; }\n        public bool IsAlive { get; set; }\n        public PlotLogReadable plotLogReadable { get; }\n\n        public MarkOfDeathDialog()\n        {\n        }\n\n        public MarkOfDeathDialog(PlotLogReadable plotLogReadable, Language language, Settings settings, string theme, Action onUpdate)\n        {\n            this.DataContext = this;\n            this.Language = language;\n            this.Settings = settings;\n            this.plotLogReadable = plotLogReadable;\n            this.OnUpdate = onUpdate;\n            InitializeComponent();\n#if DEBUG\n            this.AttachDevTools();\n#endif\n            foreach (var markOfDeath in Settings.MarksOfDeath)\n                if (markOfDeath.IsMatch(plotLogReadable))\n                    this.IsDead = true;\n            this.IsAlive = !this.IsDead;\n            Utils.SetTheme(this, theme);\n            this.Focus();\n        }\n\n        private void InitializeComponent()\n        {\n            AvaloniaXamlLoader.Load(this);\n        }\n\n        public void MarkAsDead(object sender, RoutedEventArgs e)\n        {\n            var mark = new MarkOfDeath(this.plotLogReadable);\n            if (!this.Settings.MarksOfDeath.Contains(mark))\n            {\n                this.Settings.MarksOfDeath.Add(mark);\n                this.Settings.Persist();\n                this.OnUpdate();\n            }\n            this.Close();\n        }\n\n        public void UnmarkAsDead(object sender, RoutedEventArgs e)\n        {\n            var mark = new MarkOfDeath(this.plotLogReadable);\n            if (this.Settings.MarksOfDeath.Contains(mark))\n            {\n                this.Settings.MarksOfDeath.Remove(mark);\n                this.Settings.Persist();\n                this.OnUpdate();\n            }\n            this.Close();\n        }\n\n        public void Abort(object sender, RoutedEventArgs e)\n        {\n            this.Close();\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/NoteDialog.axaml",
    "content": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\" d:DesignWidth=\"400\" d:DesignHeight=\"100\"\n        Width=\"400\" Height=\"100\"\n        x:Class=\"ChiaPlotStatus.Views.NoteDialog\"\n        Icon=\"/GUI/Assets/Logo.png\"\n        TransparencyLevelHint=\"Transparent\"\n        ExtendClientAreaToDecorationsHint=\"False\"\n        Title=\"Mark this Plotting Process as Dead?\">\n\n  <!--\n\t<Window.DataContext>\n\t\t<vm:MainWindowViewModel/>\n\t</Window.DataContext>\n  -->\n\t<Window.Styles>\n    <Style>\n      <!-- will be replaced with dark theme-->\n    </Style>\n    <Style Selector=\"Button\">\n      <Setter Property=\"Margin\" Value=\"4\" />\n    </Style>\n\t</Window.Styles>\n\n  <Panel Name=\"WindowContext\">\n\t\t<StackPanel Margin=\"20\">\n      <Panel>\n\t\t\t  <ExperimentalAcrylicBorder IsHitTestVisible=\"False\">\n\t\t\t\t  <ExperimentalAcrylicBorder.Material>\n\t\t\t\t\t  <ExperimentalAcrylicMaterial\n\t\t\t\t\t\t  BackgroundSource=\"Digger\"\n\t\t\t\t\t\t  TintColor=\"Black\"\n\t\t\t\t\t\t  TintOpacity=\"0.2\"\n\t\t\t\t\t\t  MaterialOpacity=\"0.25\" />\n\t\t\t\t  </ExperimentalAcrylicBorder.Material>\n\t\t\t  </ExperimentalAcrylicBorder>\n\t\t  </Panel>\n\n      <TextBox Text=\"{Binding Note, Mode=TwoWay}\" Name=\"Input\"></TextBox>\n\n      <StackPanel Orientation=\"Horizontal\">\n        <Button Name=\"Save\" Click=\"Save\" IsDefault=\"True\">\n          <TextBlock Text=\"{Binding Language.Buttons.Save}\"></TextBlock>\n        </Button>\n        <Button Name=\"Abort\" Click=\"Abort\">\n          <TextBlock Text=\"{Binding Language.Buttons.Abort }\"></TextBlock>\n        </Button>\n      </StackPanel>\n    </StackPanel>\n\t</Panel>\n</Window>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/NoteDialog.axaml.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Interactivity;\nusing Avalonia.Layout;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Markup.Xaml.Styling;\nusing ChiaPlotStatus.GUI.Models;\nusing ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusGUI.GUI.Utils;\nusing ChiaPlotStatusLib.Logic.Models;\nusing ReactiveUI;\nusing System;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.Reactive;\nusing System.Text.RegularExpressions;\n\nnamespace ChiaPlotStatus.Views\n{\n    public class NoteDialog : Window\n    {\n        public Settings Settings { get; set; }\n        public Language Language { get; set; }\n        public Action OnUpdate { get; set; }\n        public PlotLogReadable plotLogReadable { get; }\n        public string Note { get; set; }\n\n        public NoteDialog()\n        {\n        }\n\n        public NoteDialog(PlotLogReadable plotLogReadable, Language language, Settings settings, string theme, Action onUpdate)\n        {\n            this.DataContext = this;\n            this.Language = language;\n            this.Settings = settings;\n            this.plotLogReadable = plotLogReadable;\n            this.OnUpdate = onUpdate;\n            this.Note = plotLogReadable.Note;\n            InitializeComponent();\n#if DEBUG\n            this.AttachDevTools();\n#endif\n            Utils.SetTheme(this, theme);\n            this.Focus();\n            // does not work for some reason:\n            this.Find<TextBox>(\"Input\").SelectionStart = 0;\n            this.Find<TextBox>(\"Input\").SelectionEnd = plotLogReadable.Note.Length;\n            this.Find<TextBox>(\"Input\").Focus();\n        }\n\n        private void InitializeComponent()\n        {\n            AvaloniaXamlLoader.Load(this);\n        }\n\n        public void Save(object sender, RoutedEventArgs e)\n        {\n            var note = new Note(this.plotLogReadable);\n            note.text = this.Note;\n            if (this.Settings.Notes.Contains(note))\n                this.Settings.Notes.Remove(note);\n            this.Settings.Notes.Add(note);\n            this.Settings.Persist();\n            this.OnUpdate();\n            this.Close();\n        }\n\n        public void Abort(object sender, RoutedEventArgs e)\n        {\n            this.Close();\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/StatisticsDialog.axaml",
    "content": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:oxy=\"clr-namespace:OxyPlot.Avalonia;assembly=OxyPlot.Avalonia\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\" d:DesignWidth=\"400\" d:DesignHeight=\"100\"\n        Width=\"1000\" Height=\"600\"\n        x:Class=\"ChiaPlotStatus.Views.StatisticsDialog\"\n        Icon=\"/GUI/Assets/Logo.png\"\n        TransparencyLevelHint=\"Transparent\"\n        ExtendClientAreaToDecorationsHint=\"False\"\n        Title=\"Statistics\">\n\n  <!--\n\t<Window.DataContext>\n\t\t<vm:MainWindowViewModel/>\n\t</Window.DataContext>\n  -->\n\t<Window.Styles>\n    <Style Selector=\"DataGridRow\">\n      <Setter Property=\"Margin\" Value=\"2\" />\n    </Style>\n    <Style Selector=\"TextBlock\">\n      <Setter Property=\"FontSize\" Value=\"10\"/>\n    </Style>\n    <Style Selector=\"DataGrid TextBlock\">\n      <Setter Property=\"Margin\" Value=\"4, 1\"/>\n      <Setter Property=\"FontSize\" Value=\"12\"/>\n    </Style>\n    <Style Selector=\"ToolTip\">\n      <Setter Property=\"MaxWidth\" Value=\"600\"/>\n      <Setter Property=\"MaxHeight\" Value=\"600\"/>\n    </Style>\n    <Style Selector=\"ToolTip TextBlock\">\n      <Setter Property=\"MaxWidth\" Value=\"600\"/>\n      <Setter Property=\"MaxHeight\" Value=\"600\"/>\n      <Setter Property=\"FontSize\" Value=\"10.3\"/>\n      <Setter Property=\"TextWrapping\" Value=\"Wrap\"/>\n    </Style>\n    <Style Selector=\"TextBox\">\n      <!-- <Setter Property=\"FontFamily\" Value=\"Ubuntu\" /> -->\n      <Setter Property=\"BorderThickness\" Value=\"1\" />\n      <Setter Property=\"Foreground\" Value=\"{DynamicResource ThemeForegroundBrush}\" />\n      <Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n      <Setter Property=\"Padding\" Value=\"6\" />\n      <Setter Property=\"Margin\" Value=\"0 2\" />\n      <Setter Property=\"FontSize\" Value=\"12\" />\n    </Style>\n    <Style Selector=\"TextBox TextBlock\">\n      <Setter Property=\"FontSize\" Value=\"12\" />\n    </Style>\n    <Style Selector=\"TextBox /template/ Border\">\n      <Setter Property=\"CornerRadius\" Value=\"5\" />\n    </Style>\n    <Style Selector=\"TextBox:pointerover /template/ Border\">\n      <Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n    </Style>\n    <Style Selector=\"TextBox:focus /template/ Border\">\n      <Setter Property=\"Background\" Value=\"{DynamicResource ThemeBackgroundBrush}\" />\n    </Style>\n    <Style Selector=\"Button.Compact\">\n      <Setter Property=\"Margin\" Value=\"0\" />\n      <Setter Property=\"Padding\" Value=\"0\" />\n      <Setter Property=\"BorderThickness\" Value=\"0\" />\n    </Style>\n    <Style Selector=\"DataGrid Button\">\n      <Setter Property=\"BorderThickness\" Value=\"0\" />\n    </Style>\n  </Window.Styles>\n\n\n  <ScrollViewer Name=\"WindowContext\">\n    <StackPanel>\n\n      <DataGrid Name=\"DailyStatsDataGrid\" Items=\"{Binding DailyStats}\" CanUserResizeColumns=\"true\" CanUserReorderColumns=\"false\" CanUserSortColumns=\"false\">\n        <DataGrid.Columns>\n          <DataGridTemplateColumn SortMemberPath=\"Day\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"Day\" HorizontalAlignment=\"Left\" ></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Day}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Finished\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"Finished\" HorizontalAlignment=\"Left\" ></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Finished}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Died\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"Died\" HorizontalAlignment=\"Left\" ></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Died}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase1\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"Phase1\" HorizontalAlignment=\"Left\" ></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Phase1}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase2\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"Phase2\" HorizontalAlignment=\"Left\" ></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Phase2}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase3\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"Phase3\" HorizontalAlignment=\"Left\" ></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Phase3}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase4\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"Phase4\" HorizontalAlignment=\"Left\" ></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Phase4}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase5\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"Phase5\" HorizontalAlignment=\"Left\" ></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Phase5}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n        </DataGrid.Columns>\n      </DataGrid>\n\n\n\n      <DataGrid Name=\"StatsDataGrid\" Items=\"{Binding Stats}\" IsReadOnly=\"true\" MinHeight=\"80\" CanUserSortColumns=\"false\" CanUserResizeColumns=\"true\">\n        <DataGrid.Columns>\n          <DataGridTemplateColumn SortMemberPath=\"LogFolder\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.LogFolder}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.LogFolder}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding LogFolder}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Tmp1Drive\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Tmp1Drive}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Tmp1Drive}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Tmp2Drive\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Tmp2Drive}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Tmp2Drive}\" HorizontalAlignment=\"Left\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <!--\n\t\t\t\t\t<DataGridTemplateColumn SortMemberPath=\"DestDrive\">\n\t\t\t\t\t\t<DataGridTemplateColumn.Header>\n\t\t\t\t\t\t\t<Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.DestDrive}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n\t\t\t\t\t\t</DataGridTemplateColumn.Header>\n\t\t\t\t\t\t<DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t\t\t<DataTemplate>\n\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t<ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t\t<StackPanel>\n\t\t\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.DestDrive}\"></TextBlock>\n\t\t\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t\t\t</ToolTip.Tip>\n\t\t\t\t\t\t\t\t\t<TextBlock Text=\"{Binding DestDrive}\" HorizontalAlignment=\"Left\" ></TextBlock>\n\t\t\t\t\t\t\t\t</StackPanel>\n\t\t\t\t\t\t\t</DataTemplate>\n\t\t\t\t\t\t</DataGridTemplateColumn.CellTemplate>\n\t\t\t\t\t</DataGridTemplateColumn>\n\t\t\t\t\t-->\n\n          <DataGridTemplateColumn SortMemberPath=\"Buffer\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Buffer}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Buffer}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Buffer}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Buckets\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Buckets}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Buckets}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Buckets}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Threads\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Threads}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate>\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Threads}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Threads}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase1AvgTimeNeed\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase1AvgTimeNeed}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase1Seconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase1AvgTimeNeed}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase2AvgTimeNeed\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase2AvgTimeNeed}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase2Seconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase2AvgTimeNeed}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase3AvgTimeNeed\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase3AvgTimeNeed}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase3Seconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase3AvgTimeNeed}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase4AvgTimeNeed\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase4AvgTimeNeed}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.Phase4Seconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding Phase4AvgTimeNeed}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"CopyTimeAvgTimeNeed\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.CopyTimeAvgTimeNeed}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.CopyTimeSeconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding CopyTimeAvgTimeNeed}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"TotalAvgTimeNeed\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.TotalAvgTimeNeed}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <ToolTip.Tip>\n                    <StackPanel>\n                      <TextBlock Text=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Tooltips.TotalTimeSeconds}\"></TextBlock>\n                    </StackPanel>\n                  </ToolTip.Tip>\n                  <TextBlock Text=\"{Binding TotalAvgTimeNeed}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n          <DataGridTemplateColumn SortMemberPath=\"Phase1Completed\">\n            <DataGridTemplateColumn.Header>\n              <Button Content=\"{Binding ElementName=WindowContext, Path=DataContext.Language.Columns.Phase1Completed}\" HorizontalAlignment=\"Left\" Click=\"DataGridHeaderClick\"></Button>\n            </DataGridTemplateColumn.Header>\n            <DataGridTemplateColumn.CellTemplate>\n              <DataTemplate >\n                <StackPanel>\n                  <TextBlock Text=\"{Binding Phase1Completed}\" HorizontalAlignment=\"Right\" ></TextBlock>\n                </StackPanel>\n              </DataTemplate>\n            </DataGridTemplateColumn.CellTemplate>\n          </DataGridTemplateColumn>\n        </DataGrid.Columns>\n      </DataGrid>\n    </StackPanel>\n  </ScrollViewer>\n</Window>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/StatisticsDialog.axaml.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Interactivity;\nusing Avalonia.Layout;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Markup.Xaml.Styling;\nusing ChiaPlotStatus.GUI.Models;\nusing ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatus.Logic.Utils;\nusing ChiaPlotStatusGUI.GUI.Utils;\nusing ChiaPlotStatusGUI.GUI.ViewModels;\nusing ReactiveUI;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.Reactive;\nusing System.Text.RegularExpressions;\n\nnamespace ChiaPlotStatus.Views\n{\n    public class StatisticsDialog : Window\n    {\n        public Language Language { get; set; }\n        public List<(PlottingStatisticsFull, PlottingStatisticsFullReadable)> StatsTuples { get; set; }\n        public ObservableCollection<PlottingStatisticsFullReadable> Stats { get; set; } = new();\n        public List<PlottingStatisticsDayReadable> DailyStats { get; set; }\n        public ChiaPlotStatus PlotManager { get; set; }\n        public string SortProperty { get; set; } = \"Tmp1Drive\";\n        public bool SortAsc { get; set; } = true;\n\n\n        public StatisticsDialog()\n        {\n        }\n\n        public StatisticsDialog(ChiaPlotStatus plotManager, Language language, string theme)\n        {\n            this.DataContext = this;\n            this.Language = language;\n            this.PlotManager = plotManager;\n            LoadData();\n            InitDailyStatsTable();\n            InitializeComponent();\n#if DEBUG\n            this.AttachDevTools();\n#endif\n            KeepGridScrollbarOnScreen();\n            this.WindowState = WindowState.Maximized;\n            Utils.SetTheme(this, theme);\n            this.Focus();\n        }\n\n        private void LoadData()\n        {\n            this.StatsTuples = PlotManager.Statistics.AllStatistics();\n            Sorter.Sort(SortProperty, SortAsc, StatsTuples);\n            Stats.Clear();\n            foreach (var tuple in this.StatsTuples)\n                Stats.Add(tuple.Item2);\n        }\n\n        private void InitializeComponent()\n        {\n            AvaloniaXamlLoader.Load(this);\n        }\n\n        public void DataGridHeaderClick(object sender, RoutedEventArgs e)\n        {\n            Button header = ((Button)sender);\n            string headerText = (string)header.Content;\n            var oldSortProperty = SortProperty;\n            foreach (var property in typeof(Columns).GetProperties())\n            {\n                string translation = (string)property.GetValue(Language.Columns);\n                if (string.Equals(headerText, translation))\n                {\n                    SortProperty = property.Name;\n                    break;\n                }\n            }\n            if (string.Equals(SortProperty, oldSortProperty))\n                SortAsc = !SortAsc;\n            Sorter.Sort(SortProperty, SortAsc, StatsTuples);\n            Stats.Clear();\n            foreach (var tuple in StatsTuples)\n                Stats.Add(tuple.Item2);\n            // Debug.WriteLine(\"SearchProperty: \" + SortProperty + \", ASC: \" + SortAsc);\n        }\n\n        private void KeepGridScrollbarOnScreen()\n        {\n            this.WhenAnyValue(x => x.Height)\n                .Subscribe(x =>\n                {\n                    var statsDataGrid = this.Find<DataGrid>(\"StatsDataGrid\");\n                    var dailyStatsDataGrid = this.Find<DataGrid>(\"DailyStatsDataGrid\");\n                    statsDataGrid.Height = x / 2;\n                    dailyStatsDataGrid.Height = x / 2;\n                });\n        }\n\n        public void InitDailyStatsTable()\n        {\n            Dictionary<DateTime, PlottingStatisticsDay> dailyStats = PlotManager.Statistics.GetDailyStats();\n            List<PlottingStatisticsDay> days = new(dailyStats.Values);\n            days.Sort((a, b) => -1 * a.Day.CompareTo(b.Day));\n            DailyStats = new();\n            foreach (var stat in days)\n                DailyStats.Add(new(stat));\n        }\n\n        /*\n        private void BuildPlotModel()\n        {\n            Dictionary<DateTime, PlottingStatisticsDay> dailyStats = PlotManager.Statistics.GetDailyStats();\n\n            Dictionary<string, LineSeries> lineSeries = new();\n\n            LineSeries getLineSeries(string name)\n            {\n                if (!lineSeries.ContainsKey(name))\n                    lineSeries.Add(name, new LineSeries());\n                return lineSeries[name];\n            }\n\n\n            var plotModel = new PlotModel\n            {\n                Title = \"test1\",\n                TitleToolTip = \"test2\"\n            };\n\n            DateTime twoWeeksAgo = DateTime.Now.AddDays(-14);\n            plotModel.Axes.Add(new DateTimeAxis {\n                Position = AxisPosition.Bottom,\n                Minimum = DateTimeAxis.ToDouble(twoWeeksAgo),\n                Maximum = DateTimeAxis.ToDouble(DateTime.Now),\n                StringFormat = \"MMM dd\" });\n\n            List<PlottingStatisticsDay> stats = new(dailyStats.Values);\n            stats.Sort((a, b)=> a.Day.CompareTo(b.Day));\n            foreach (var stat in stats)\n            {\n                getLineSeries(\"Phase1\").Points.Add(new DataPoint(DateTimeAxis.ToDouble(stat.Day), stat.Phase1));\n                getLineSeries(\"Phase2\").Points.Add(new DataPoint(DateTimeAxis.ToDouble(stat.Day), stat.Phase2));\n                getLineSeries(\"Phase3\").Points.Add(new DataPoint(DateTimeAxis.ToDouble(stat.Day), stat.Phase3));\n                getLineSeries(\"Phase4\").Points.Add(new DataPoint(DateTimeAxis.ToDouble(stat.Day), stat.Phase4));\n                getLineSeries(\"Phase5\").Points.Add(new DataPoint(DateTimeAxis.ToDouble(stat.Day), stat.Phase5));\n                getLineSeries(\"Finished\").Points.Add(new DataPoint(DateTimeAxis.ToDouble(stat.Day), stat.Finished));\n                getLineSeries(\"Died\").Points.Add(new DataPoint(DateTimeAxis.ToDouble(stat.Day), stat.Died));\n            }\n\n            foreach (var series in lineSeries.Values)\n                plotModel.Series.Add(series);\n\n            this.PlotModel = plotModel;\n        }\n        */\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/UpdateDialog.axaml",
    "content": "<Window xmlns=\"https://github.com/avaloniaui\"\n        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\"\n        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n        mc:Ignorable=\"d\" d:DesignWidth=\"300\" d:DesignHeight=\"100\"\n        Width=\"300\" Height=\"100\"\n        x:Class=\"ChiaPlotStatus.Views.UpdateDialog\"\n        Icon=\"/GUI/Assets/Logo.png\"\n        TransparencyLevelHint=\"Transparent\"\n        ExtendClientAreaToDecorationsHint=\"False\"\n        Title=\"Checking for updates\">\n\n  <!--\n\t<Window.DataContext>\n\t\t<vm:MainWindowViewModel/>\n\t</Window.DataContext>\n  -->\n\t<Window.Styles>\n    <Style Selector=\"TextBlock\">\n      <Setter Property=\"Margin\" Value=\"3\" />\n    </Style>\n  </Window.Styles>\n\n  <Panel Name=\"WindowContext\">\n\t\t<StackPanel Margin=\"20\">\n      <Panel>\n\t\t\t  <ExperimentalAcrylicBorder IsHitTestVisible=\"False\">\n\t\t\t\t  <ExperimentalAcrylicBorder.Material>\n\t\t\t\t\t  <ExperimentalAcrylicMaterial\n\t\t\t\t\t\t  BackgroundSource=\"Digger\"\n\t\t\t\t\t\t  TintColor=\"Black\"\n\t\t\t\t\t\t  TintOpacity=\"0.2\"\n\t\t\t\t\t\t  MaterialOpacity=\"0.25\" />\n\t\t\t\t  </ExperimentalAcrylicBorder.Material>\n\t\t\t  </ExperimentalAcrylicBorder>\n\t\t  </Panel>\n\n      <StackPanel Orientation=\"Horizontal\">\n        <TextBlock Text=\"Latest Release:\" FontWeight=\"Bold\"></TextBlock>\n        <TextBlock Text=\"{Binding Latest.TagName}\"></TextBlock>\n      </StackPanel>\n\n      <StackPanel Orientation=\"Horizontal\">\n        <TextBlock Text=\"Currently installed:\" FontWeight=\"Bold\"></TextBlock>\n        <TextBlock Text=\"{Binding Current}\"></TextBlock>\n      </StackPanel>\n\n\n      <TextBlock Text=\"You are up to date!\" Name=\"UpToDate\"></TextBlock>\n      <StackPanel Name=\"DownloadButtons\" Orientation=\"Horizontal\">\n        <Button Content=\"Windows\" Click=\"DownloadWindows\" />\n        <Button Content=\"Linux Deb\" Click=\"DownloadDeb\" />\n        <Button Content=\"Linux RPM\" Click=\"DownloadRpm\" />\n        <!--\n        <Button Content=\"MacOS\" Click=\"DownloadMac\" />\n        -->\n      </StackPanel>\n      <StackPanel Name=\"DownloadNotice\" Orientation=\"Vertical\" IsVisible=\"False\">\n        <TextBlock Text=\"Downloading installation file...\"></TextBlock>\n        <TextBlock Text=\"Installation will be started as soon\"></TextBlock>\n        <TextBlock Text=\"as the download finished.\"></TextBlock>\n        <TextBlock Text=\"Chia Plot Status will be closed\"></TextBlock>\n        <TextBlock Text=\"automatically when the installation starts.\"></TextBlock>\n      </StackPanel>\n    </StackPanel>\n\t</Panel>\n</Window>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/Views/UpdateDialog.axaml.cs",
    "content": "using Avalonia;\nusing Avalonia.Controls;\nusing Avalonia.Input;\nusing Avalonia.Input.Platform;\nusing Avalonia.Interactivity;\nusing Avalonia.Layout;\nusing Avalonia.Markup.Xaml;\nusing Avalonia.Markup.Xaml.Styling;\nusing Avalonia.Platform;\nusing Avalonia.Threading;\nusing ChiaPlotStatus.GUI.Models;\nusing ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusGUI.GUI.Utils;\nusing Octokit;\nusing ReactiveUI;\nusing System;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.IO;\nusing System.Net;\nusing System.Reactive;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Text.RegularExpressions;\nusing System.Threading.Tasks;\nusing YamlDotNet.Serialization;\n\nnamespace ChiaPlotStatus.Views\n{\n    public enum InstallationPackageType\n    {\n        EXE,\n        DEB,\n        RPM,\n        PKG\n    }\n\n    public class UpdateDialog : Window\n    {\n        public GUI.Models.Language Language { get; set; }\n        public Release Latest { get; set; }\n        public string Current { get; set; }\n        public string current { get; set; }\n\n        public UpdateDialog() { }\n\n        public UpdateDialog(GUI.Models.Language language, string theme)\n        {\n            this.DataContext = this;\n            this.Language = language;\n            this.Current = LoadCurrentRelease();\n            this.Latest = LoadLatestRelease();\n            InitializeComponent();\n#if DEBUG\n            this.AttachDevTools();\n#endif\n            this.Find<TextBlock>(\"UpToDate\").IsVisible = string.Equals(this.Latest.TagName, this.Current);\n            this.Find<StackPanel>(\"DownloadButtons\").IsVisible = !string.Equals(this.Latest.TagName, this.Current);\n            Utils.SetTheme(this, theme);\n            this.Focus();\n        }\n\n        private void InitializeComponent()\n        {\n            AvaloniaXamlLoader.Load(this);\n        }\n\n\n        private Release LoadLatestRelease()\n        {\n            var client = new GitHubClient(new ProductHeaderValue(\"Chia-Plot-Status\"));\n            Release? latest = null;\n            var task = Task.Run(async () =>\n            {\n                var result = await client.Repository.Release.GetAll(\"grayfallstown\", \"Chia-Plot-Status\");\n                latest = result[0];\n            });\n            task.Wait();\n            return latest;\n        }\n\n        private string LoadCurrentRelease()\n        {\n            return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(3);\n        }\n\n        public void DownloadWindows(object sender, RoutedEventArgs e)\n        {\n            Update(InstallationPackageType.EXE);\n        }\n\n        public void DownloadDeb(object sender, RoutedEventArgs e)\n        {\n            Update(InstallationPackageType.DEB);\n        }\n\n        public void DownloadRpm(object sender, RoutedEventArgs e)\n        {\n            Update(InstallationPackageType.RPM);\n        }\n\n\n\n        /**\n         * It was requested to rename Setup.exe in something that contains the name of the application.\n         * Problem is the download url and therefor the file name is hardcoded to Setup.exe.\n         * Old applications would no longer be able to find the update if the name was changed.\n         * Solving this by using a fallback name now and once a few updates passed I can change\n         * the name without breaking too many installations.\n         */\n        public static (string, string?) GetInstallationPackageName(InstallationPackageType type)\n        {\n            switch (type)\n            {\n                case InstallationPackageType.EXE:\n                    return (\"ChiaPlotStatus.windows-Setup.exe\", \"Setup.exe\");\n                case InstallationPackageType.DEB:\n                    return (\"ChiaPlotStatus.linux-x64.deb\", null);\n                case InstallationPackageType.RPM:\n                    return (\"ChiaPlotStatus.linux-x64.rpm\", null);\n                case InstallationPackageType.PKG:\n                    return (\"ChiaPlotStatus.mac.pkg\", null);\n                default:\n                    throw new NotImplementedException(\"unknown InstallationPackageType \" + type);\n            }\n        }\n\n        public void Update(InstallationPackageType type)\n        {\n            this.Find<StackPanel>(\"DownloadButtons\").IsVisible = false;\n            this.Find<StackPanel>(\"DownloadNotice\").IsVisible = true;\n            var fileName = GetInstallationPackageName(type);\n            Task.Run(async () =>\n            {\n                if (DownloadInstallationPackage(fileName))\n                {\n                    void StartInstallationAndExit(string installerPath)\n                    {\n                        // starts a detached process that does not get terminated\n                        // when we close Chia Plot Status, as we need to close\n                        // it to update the files (on windows and maybe on mac too)\n                        var startInfo = new ProcessStartInfo(installerPath);\n                        startInfo.UseShellExecute = true;\n                        Process.Start(startInfo);\n                        Environment.Exit(0);\n                    }\n\n                    var paths = GetFullInstallationPackagePath(type);\n                    if (File.Exists(paths.Item1))\n                    {\n                        StartInstallationAndExit(paths.Item1);\n                        return;\n                    }\n                    if (paths.Item2 != null && File.Exists(paths.Item2))\n                    {\n                        StartInstallationAndExit(paths.Item2);\n                        return;\n                    }\n                    else\n                        Debug.WriteLine(\"Both installation package paths lead nowhere, falling back to manual installation\");\n                }\n                else\n                    Debug.WriteLine(\"Download of installation package failed, falling back to manual installation\");\n\n                // fallback to manual download via browser\n                Utils.OpenUrl(\"https://github.com/grayfallstown/Chia-Plot-Status/releases/latest/\");\n\n            });\n        }\n\n        public bool DownloadInstallationPackage((string, string?) fileName)\n        {\n            using (var client = new WebClient())\n            {\n                try\n                {\n                    string baseUrl = \"https://github.com/grayfallstown/Chia-Plot-Status/releases/latest/download/\";\n                    string updateDir = EnsureUpdateTempDirectoryExists(); ;\n                    client.DownloadFile(baseUrl + fileName.Item1, updateDir + fileName.Item1);\n                    return true;\n                }\n                catch (System.Net.WebException e)\n                {\n                    Debug.WriteLine(\"download of update file \" + fileName + \" failed \" + e);\n                    if (fileName.Item2 != null)\n                        return DownloadInstallationPackage((fileName.Item2, null));\n                }\n            }\n            return false;\n        }\n\n        public static string GetUpdateTempDirectory()\n        {\n            return Path.GetTempPath() + \"ChiaPlotStatusUpdate\" + Path.DirectorySeparatorChar;\n        }\n\n        public static (string, string?) GetFullInstallationPackagePath(InstallationPackageType type)\n        {\n            (string, string?) packageName = GetInstallationPackageName(type);\n            string basePath = GetUpdateTempDirectory() + Path.DirectorySeparatorChar;\n            if (packageName.Item2 == null)\n                return (basePath + packageName.Item1, null);\n            else\n                return (basePath + packageName.Item1, basePath + packageName.Item2);\n        }\n\n        public static string EnsureUpdateTempDirectoryExists()\n        {\n            var dir = GetUpdateTempDirectory();\n            if (!Directory.Exists(dir))\n                Directory.CreateDirectory(dir);\n            return dir;\n        }\n\n        public static void DeleteUpdateTempDirectory()\n        {\n            try\n            {\n                var dir = GetUpdateTempDirectory();\n                if (Directory.Exists(dir))\n                    Directory.Delete(dir, true);\n            } catch (Exception e)\n            {\n                Debug.WriteLine(\"DeleteUpdateTempDirectory failed: \" + e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusGUI/GUI/nuget.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- \n  To use the Avalonia CI feed to get unstable packages, move this file to the root of your solution.\n-->\n\n<configuration>\n  <packageSources>\n    <add key=\"AvaloniaCI\" value=\"https://www.myget.org/F/avalonia-ci/api/v2\" />\n  </packageSources>\n</configuration>\n"
  },
  {
    "path": "ChiaPlotStatusGUI/chia-plot-status.desktop",
    "content": "[Desktop Entry]\nName=Chia Plot Status\nComment=Tool to Monitor and Analyse Chia Plotting log files, show health and progress of running plots and estimated time to completion\nGenericName=Chia Plot Status\nExec=/usr/local/bin/ChiaPlotStatus %U\nIcon=chia-plot-status\nType=Application\nStartupNotify=true\nCategories=GNOME;GTK;Utility;"
  },
  {
    "path": "ChiaPlotStatusLib/ChiaPlotStatusLib.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net5.0</TargetFramework>\n    <RuntimeIdentifiers>win7-x64;ubuntu.16.10-x64;linux-x64</RuntimeIdentifiers>\n    <Company>grayfallstown</Company>\n    <Authors>grayfallstown</Authors>\n    <Product>ChiaPlotStatusLib</Product>\n    <Version>0.11.11</Version>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageReference Include=\"CsvHelper\" Version=\"27.0.2\" />\n    <PackageReference Include=\"YamlDotNet\" Version=\"11.1.1\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/ChiaPlotStatus.cs",
    "content": "﻿using ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatus.Logic.Utils;\nusing ChiaPlotStatusLib.Logic;\nusing ChiaPlotStatusLib.Logic.Models;\nusing ChiaPlotStatusLib.Logic.Parser;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n    /**\n     * Core Object of this tool.\n     * Knows everything, does everything.\n     */\n    public class ChiaPlotStatus\n    {\n        public Settings Settings { get; }\n        private PlotParserCache cache;\n        private Dictionary<string, PlotLogFileParser> PlotLogFiles { get; } = new();\n        private Dictionary<string, CPPlotLogFileParser> CPPlotLogFiles { get; } = new();\n        public PlottingStatisticsHolder Statistics { get; set; }\n\n        public ChiaPlotStatus(Settings settings) {\n            this.Settings = settings;\n            Statistics = new PlottingStatisticsHolder(new List<PlotLog>(), Settings.Weigths, new List<MarkOfDeath>());\n\n            string cachePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Path.DirectorySeparatorChar +\n                \"ChiaPlotStatus.cache.json\";\n            cache = new PlotParserCache(cachePath);\n        }\n\n        public void AddDefaultLogFolders()\n        {\n            void add(string blockchain)\n            {\n                string path = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)\n                         + Path.DirectorySeparatorChar + \".\" + blockchain + Path.DirectorySeparatorChar + \"mainnet\" +\n                         Path.DirectorySeparatorChar + \"plotter\";\n                AddLogFolder(path);\n            }\n            add(\"chia\");\n            add(\"flax\");\n            add(\"chaingreen\");\n            add(\"seno2\");\n            add(\"chiarose\");\n            add(\"goji-blockchain\");\n            add(\"spare-blockchain\");\n        }\n\n        public void AddLogFolder(string path)\n        {\n            Settings.LogDirectories.Add(path);\n        }\n\n        public void RemoveLogFolder(string path)\n        {\n            Settings.LogDirectories.Remove(path);\n            // drop plotlogs from that folder\n            foreach (var plotLogFile in PlotLogFiles.Values)\n            {\n                var folder = plotLogFile.LogFolder;\n                if (string.Equals(folder, path))\n                   PlotLogFiles.Remove(plotLogFile.LogFile);\n                folder = folder + \"\\\\\";\n                if (string.Equals(folder, path))\n                    PlotLogFiles.Remove(plotLogFile.LogFile);\n            }\n            foreach (var plotLogFile in CPPlotLogFiles.Values)\n            {\n                var folder = plotLogFile.LogFolder;\n                if (string.Equals(folder, path))\n                    CPPlotLogFiles.Remove(plotLogFile.LogFile);\n                folder = folder + \"\\\\\";\n                if (string.Equals(folder, path))\n                    CPPlotLogFiles.Remove(plotLogFile.LogFile);\n            }\n        }\n\n        public List<(PlotLog, PlotLogReadable)> PollPlotLogs(string sortPropertyName, bool sortAsc, string? searchString, Filter filter)\n        {\n            SearchForNewLogFiles();\n            ConcurrentBag<PlotLog> plotLogs = ParseTheLogs();\n            foreach (var cpPlotLog in ParseTheCPLogs())\n                plotLogs.Add(cpPlotLog);\n            if (Settings.AlwaysDoFullRead == true) // nullable, so == true\n                PlotLogFiles.Clear();\n            HandleStatistics(plotLogs.ToList());\n            List<(PlotLog, PlotLogReadable)> plusReadable = new();\n            foreach (var plotLog in plotLogs)\n            {\n                foreach (var markOfDeath in Settings.MarksOfDeath)\n                    if (markOfDeath.IsMatch(plotLog))\n                        plotLog.Health = new ConfirmedDead(true);\n                foreach (var note in Settings.Notes)\n                    if (note.IsMatch(plotLog))\n                        plotLog.Note = note.text;\n                if (!plotLog.IsRunning())\n                    plotLog.RunTimeSeconds = 0;\n                else if (plotLog.StartDate != null)\n                    plotLog.RunTimeSeconds = (int)((TimeSpan)(DateTime.Now - plotLog.StartDate)).TotalSeconds;\n                if (typeof(CPPlotLog) == plotLog.GetType())\n                    plusReadable.Add((plotLog, new CPPlotLogReadable((CPPlotLog)plotLog)));\n                else\n                    plusReadable.Add((plotLog, new PlotLogReadable(plotLog)));\n            }\n            List<(PlotLog, PlotLogReadable)> result = Filter(searchString, filter, plusReadable);\n            SortPlotLogs(sortPropertyName, sortAsc, result);\n            return result;\n        }\n\n        public List<(CPPlotLog, CPPlotLogReadable)> PollCPPlotLogs(string sortPropertyName, bool sortAsc, string? searchString, Filter filter)\n        {\n            SearchForNewLogFiles();\n            ConcurrentBag<CPPlotLog> cpPlotLogs = ParseTheCPLogs();\n            if (Settings.AlwaysDoFullRead == true) // nullable, so == true\n                CPPlotLogFiles.Clear();\n            HandleStatistics(new(cpPlotLogs.ToArray()));\n            List<(CPPlotLog, CPPlotLogReadable)> plusReadable = new();\n            foreach (var cpPlotLog in cpPlotLogs)\n            {\n                foreach (var markOfDeath in Settings.MarksOfDeath)\n                    if (markOfDeath.IsMatch(cpPlotLog))\n                        cpPlotLog.Health = new ConfirmedDead(true);\n                foreach (var note in Settings.Notes)\n                    if (note.IsMatch(cpPlotLog))\n                        cpPlotLog.Note = note.text;\n                if (!cpPlotLog.IsRunning())\n                    cpPlotLog.RunTimeSeconds = 0;\n                else if (cpPlotLog.StartDate != null)\n                    cpPlotLog.RunTimeSeconds = (int)((TimeSpan)(DateTime.Now - cpPlotLog.StartDate)).TotalSeconds;\n                plusReadable.Add((cpPlotLog, new CPPlotLogReadable(cpPlotLog)));\n            }\n            List<(CPPlotLog, CPPlotLogReadable)> result = Filter(searchString, filter, plusReadable);\n            SortPlotLogs(sortPropertyName, sortAsc, result);\n            return result;\n        }\n\n        private void SearchForNewLogFiles()\n        {\n            foreach (var directory in Settings.LogDirectories)\n            {\n                // when a logfolder gets deleted that was added to Settings Chia Plot Status failed to start\n                if (Directory.Exists(directory))\n                {\n                    foreach (var filePath in Directory.GetFiles(directory))\n                    {\n                        if (!PlotLogFiles.ContainsKey(filePath) && LooksLikeAPlotLog(filePath))\n                        {\n                            PlotLogFiles[filePath] = new PlotLogFileParser(filePath, Settings.AlwaysDoFullRead == true, ref cache);\n                        }\n                        else if (!CPPlotLogFiles.ContainsKey(filePath) && LooksLikeACPPlotLog(filePath))\n                        {\n                            CPPlotLogFiles[filePath] = new CPPlotLogFileParser(filePath, Settings.AlwaysDoFullRead == true);\n                        }\n                    }\n                }\n            }\n        }\n\n        private ConcurrentBag<PlotLog> ParseTheLogs()\n        {\n            ConcurrentBag<PlotLog> plotLogs = new ConcurrentBag<PlotLog>();\n            Parallel.ForEach(PlotLogFiles.Values, (plotLogFile) =>\n            {\n                foreach (var plotLog in plotLogFile.ParsePlotLog())\n                    plotLogs.Add(plotLog);\n            });\n            return plotLogs;\n        }\n\n        private ConcurrentBag<CPPlotLog> ParseTheCPLogs()\n        {\n            ConcurrentBag<CPPlotLog> cpPlotLogs = new ConcurrentBag<CPPlotLog>();\n            Parallel.ForEach(CPPlotLogFiles.Values, (cpPlotLogFile) => {\n                foreach (var cpPlotLog in cpPlotLogFile.ParseCPPlotLog())\n                    cpPlotLogs.Add(cpPlotLog);\n            });\n            return cpPlotLogs;\n        }\n\n        private List<(A, B)> Filter<A, B> (string? searchString, Filter filter, List<(A, B)> plotLogs) where A : PlotLog\n        {\n            List<(A, B)> searchResults = SearchFilter.Search<A, B>(searchString, plotLogs);\n            List<(A, B)> filterResults = new();\n            foreach (var tuple in searchResults)\n            {\n                if (filter.HideFinished && tuple.Item1.CurrentPhase == 6)\n                    continue;\n                switch (tuple.Item1.Health)\n                {\n                    case Healthy:\n                        if (!filter.HideHealthy || (tuple.Item1.CurrentPhase == 6 && !filter.HideFinished)) filterResults.Add(tuple);\n                        break;\n                    case TempError:\n                        // well, you have to take action here.\n                        filterResults.Add(tuple);\n                        break;\n                    case Concerning:\n                        // would one want to hide those?\n                        filterResults.Add(tuple);\n                        break;\n                    case PossiblyDead:\n                        if (!filter.HidePossiblyDead) filterResults.Add(tuple);\n                        break;\n                    case ConfirmedDead:\n                        if (!filter.HideConfirmedDead) filterResults.Add(tuple);\n                        break;\n                }\n            }\n            return filterResults;\n        }\n\n        private static void SortPlotLogs(string propertyName, bool sortAsc, List<(PlotLog, PlotLogReadable)> plotLogs)\n        {\n            Sorter.Sort(propertyName, sortAsc, plotLogs);\n        }\n\n        private static void SortPlotLogs(string propertyName, bool sortAsc, List<(CPPlotLog, CPPlotLogReadable)> plotLogs)\n        {\n            Sorter.Sort(propertyName, sortAsc, plotLogs);\n        }\n\n        private void HandleStatistics(List<PlotLog> plotLogs)\n        {\n            Statistics = new PlottingStatisticsHolder(plotLogs, Settings.Weigths, Settings.MarksOfDeath);\n            foreach (var plotLog in plotLogs)\n            {\n                PlottingStatistics stats = Statistics.GetMostRelevantStatistics(plotLog);\n                plotLog.UpdateEta(stats);\n                plotLog.UpdateHealth(stats);\n            }\n        }\n\n        private bool LooksLikeAPlotLog(string file)\n        {\n            byte[] buffer = new byte[4096];\n            try\n            {\n                using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))\n                {\n                    var bytes_read = fs.Read(buffer, 0, buffer.Length);\n                    fs.Close();\n                    if (bytes_read > 63)\n                    {\n                        string asString = GetEncoding(file).GetString(buffer);\n                        bool hasNewLine = asString.Contains(\"\\n\");\n                        bool hasStartingSentence = asString.Contains(\"Starting plotting progress into temporary dirs\");\n                        bool hasHarvesterDuplicateWarning = asString.Contains(\"already exists for harvester, please remove it manually\");\n                        if (hasNewLine && (hasStartingSentence || hasHarvesterDuplicateWarning))\n                            return true;\n                    }\n                }\n            } catch (Exception e)\n            {\n                Debug.WriteLine(e);\n                return false;\n            }\n            // Debug.WriteLine(\"File \" + file + \" was detected as a non plotlog file and will not be parsed as such\");\n            return false;\n        }\n\n        private bool LooksLikeACPPlotLog(string file)\n        {\n            byte[] buffer = new byte[4096];\n            try\n            {\n                using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))\n                {\n                    var bytes_read = fs.Read(buffer, 0, buffer.Length);\n                    fs.Close();\n                    if (bytes_read > 63)\n                    {\n                        string asString = GetEncoding(file).GetString(buffer);\n                        bool hasNewLine = asString.Contains(\"\\n\");\n                        bool hasPlotterName = asString.Contains(\"Multi-threaded pipelined Chia k32 plotter\");\n                        bool hasFinalDirectory = asString.Contains(\"Final Directory: \");\n                        bool hasThreads = asString.Contains(\"Number of Threads: \");\n                        bool hasBuckets = asString.Contains(\"Number of Sort Buckets: \");\n                        bool hasDirectory = asString.Contains(\"Working Directory:\");\n                        bool hasStartingSentence = asString.Contains(\"Number of Threads: \");\n                        if (hasNewLine && (hasPlotterName || hasThreads || hasBuckets || hasDirectory || hasFinalDirectory))\n                            return true;\n                    }\n                }\n            }\n            catch (Exception e)\n            {\n                Debug.WriteLine(e);\n                return false;\n            }\n           // Debug.WriteLine(\"File \" + file + \" was detected as a non cpPlotlog file and will not be parsed as such\");\n            return false;\n        }\n\n        private static Encoding GetEncoding(string filename)\n        {\n            // Read the BOM\n            var bom = new byte[4];\n            using (var file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))\n            {\n                file.Read(bom, 0, 4);\n            }\n\n            // Analyze the BOM\n            // if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7;\n            if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8;\n            if (bom[0] == 0xff && bom[1] == 0xfe && bom[2] == 0 && bom[3] == 0) return Encoding.UTF32; //UTF-32LE\n            if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE\n            if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE\n            if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return new UTF32Encoding(true, true);  //UTF-32BE\n\n            // We actually have no idea what the encoding is if we reach this point, so\n            // you may wish to return null instead of defaulting to ASCII\n            return Encoding.ASCII;\n        }\n\n        public void Persist()\n        {\n            this.Settings.Persist();\n            this.cache.Persist();\n        }\n    }\n\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/CPPlotLog.cs",
    "content": "﻿using ChiaPlotStatus;\nusing ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusLib.Logic.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json.Serialization;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Models\n{\n    public class CPPlotLog: PlotLog\n    {\n        public static int P1PARTS = 12;\n        public static int P2PARTS = 15;\n        public static int P3PARTS = 14;\n        public static int P4PARTS = 6;\n\n\n        public int CurrentPhasePart { get; set; } = 1;\n\n        public float P1 { get; set; } = 0.0f;\n        public float P2 { get; set; } = 0.0f;\n        public float P3 { get; set; } = 0.0f;\n        public long P3Entries { get; set; } = 0L;\n        public float P4 { get; set; } = 0.0f;\n\n        public float P1Table1 { get; set; } = 0.0f;\n        public long P1Table1Found { get; set; } = 0L;\n        public long P1Table1Lost { get; set; } = 0L;\n        public float P1Table2 { get; set; } = 0.0f;\n        public long P1Table2Found { get; set; } = 0L;\n        public long P1Table2Lost { get; set; } = 0L;\n        public float P1Table3 { get; set; } = 0.0f;\n        public long P1Table3Found { get; set; } = 0L;\n        public long P1Table3Lost { get; set; } = 0L;\n        public float P1Table4 { get; set; } = 0.0f;\n        public long P1Table4Found { get; set; } = 0L;\n        public long P1Table4Lost { get; set; } = 0L;\n        public float P1Table5 { get; set; } = 0.0f;\n        public long P1Table5Found { get; set; } = 0L;\n        public long P1Table5Lost { get; set; } = 0L;\n        public float P1Table6 { get; set; } = 0.0f;\n        public long P1Table6Found { get; set; } = 0L;\n        public long P1Table6Lost { get; set; } = 0L;\n        public float P1Table7 { get; set; } = 0.0f;\n        public long P1Table7Found { get; set; } = 0L;\n        public long P1Table7Lost { get; set; } = 0L;\n\n        public long P2MaxTableSize { get; set; } = 0L;\n\n        public float P2Table1Scan { get; set; } = 0.0f;\n        public float P2Table2Scan { get; set; } = 0.0f;\n        public float P2Table3Scan { get; set; } = 0.0f;\n        public float P2Table4Scan { get; set; } = 0.0f;\n        public float P2Table5Scan { get; set; } = 0.0f;\n        public float P2Table6Scan { get; set; } = 0.0f;\n        public float P2Table7Scan { get; set; } = 0.0f;\n\n        public float P2Table1Rewrite { get; set; } = 0.0f;\n        public float P2Table2Rewrite { get; set; } = 0.0f;\n        public float P2Table3Rewrite { get; set; } = 0.0f;\n        public float P2Table4Rewrite { get; set; } = 0.0f;\n        public float P2Table5Rewrite { get; set; } = 0.0f;\n        public float P2Table6Rewrite { get; set; } = 0.0f;\n        public float P2Table7Rewrite { get; set; } = 0.0f;\n\n        public long P2Table1Lost { get; set; } = 0L;\n        public long P2Table2Lost { get; set; } = 0L;\n        public long P2Table3Lost { get; set; } = 0L;\n        public long P2Table4Lost { get; set; } = 0L;\n        public long P2Table5Lost { get; set; } = 0L;\n        public long P2Table6Lost { get; set; } = 0L;\n        public long P2Table7Lost { get; set; } = 0L;\n\n        public float P31Table2 { get; set; } = 0.0f;\n        public long P31Table2Entries { get; set; } = 0L;\n        public float P31Table3 { get; set; } = 0.0f;\n        public long P31Table3Entries { get; set; } = 0L;\n        public float P31Table4 { get; set; } = 0.0f;\n        public long P31Table4Entries { get; set; } = 0L;\n        public float P31Table5 { get; set; } = 0.0f;\n        public long P31Table5Entries { get; set; } = 0L;\n        public float P31Table6 { get; set; } = 0.0f;\n        public long P31Table6Entries { get; set; } = 0L;\n        public float P31Table7 { get; set; } = 0.0f;\n        public long P31Table7Entries { get; set; } = 0L;\n\n        public float P32Table1 { get; set; } = 0.0f;\n        public long P32Table1Entries { get; set; } = 0L;\n        public float P32Table2 { get; set; } = 0.0f;\n        public long P32Table2Entries { get; set; } = 0L;\n        public float P32Table3 { get; set; } = 0.0f;\n        public long P32Table3Entries { get; set; } = 0L;\n        public float P32Table4 { get; set; } = 0.0f;\n        public long P32Table4Entries { get; set; } = 0L;\n        public float P32Table5 { get; set; } = 0.0f;\n        public long P32Table5Entries { get; set; } = 0L;\n        public float P32Table6 { get; set; } = 0.0f;\n        public long P32Table6Entries { get; set; } = 0L;\n        public float P32Table7 { get; set; } = 0.0f;\n        public long P32Table7Entries { get; set; } = 0L;\n\n\n        public CPPlotLog()\n        {\n            UsedPlotter = \"chia-plotter\";\n        }\n\n        public void EnterPhase(int phase)\n        {\n            //Debug.WriteLine(\"XXXXXX \" + this.CurrentPhase + \": \" + this.CurrentPhasePart);\n            this.CurrentPhase = phase;\n            this.CurrentPhasePart = 0;\n        }\n\n        public void NextPhasePart()\n        {\n            this.CurrentPhasePart++;\n        }\n\n\n        public override void UpdateProgress()\n        {\n            float part = 0;\n\n            switch (CurrentPhase)\n            {\n                case 6:\n                    part = 1 + CPPlotLog.P4PARTS + CPPlotLog.P3PARTS + CPPlotLog.P2PARTS + CPPlotLog.P1PARTS;\n                    break;\n                case 5:\n                    part = CPPlotLog.P4PARTS + CPPlotLog.P3PARTS + CPPlotLog.P2PARTS + CPPlotLog.P1PARTS;\n                    break;\n                case 4:\n                    part = part = CPPlotLog.P3PARTS + CPPlotLog.P2PARTS + CPPlotLog.P1PARTS;\n                    break;\n                case 3:\n                    int totalTablesIn3 = 7;\n                    part = part = CPPlotLog.P2PARTS + CPPlotLog.P1PARTS;\n                    break;\n                case 2:\n                    part = part = CPPlotLog.P1PARTS;\n                    break;\n                case 1:\n                    part = 0;\n                    break;\n            }\n            Progress = (part + CurrentPhasePart) / (1 + CPPlotLog.P4PARTS + CPPlotLog.P3PARTS + CPPlotLog.P2PARTS + CPPlotLog.P1PARTS) * 100;\n            if (Double.IsNaN(Progress))\n                Progress = 0;\n        }\n\n\n        public override void UpdateEta(PlottingStatistics stats)\n        {\n            this.TimeRemaining = 0;\n            if (CurrentPhase == 6)\n            {\n                this.TimeRemaining = 0;\n            }\n            if (CurrentPhase <= 5)\n            {\n                float factor = 1;\n                if (CurrentPhase == 5)\n                {\n                    // TODO: if more can be known\n\n                }\n                this.TimeRemaining += (int)(factor * (float)stats.CopyTimeAvgTimeNeed);\n            }\n            if (CurrentPhase <= 4)\n            {\n                float factor = 1;\n                if (CurrentPhase == 4)\n                    factor = (float)this.CurrentPhasePart / CPPlotLog.P4PARTS;\n                this.TimeRemaining += (int)(factor * stats.Phase4AvgTimeNeed);\n            }\n            if (CurrentPhase <= 3)\n            {\n                float factor = 1;\n                if (CurrentPhase == 3)\n                    factor = (float)this.CurrentPhasePart / CPPlotLog.P3PARTS;\n                this.TimeRemaining += (int)(factor * stats.Phase3AvgTimeNeed);\n            }\n            if (CurrentPhase <= 2)\n            {\n                float factor = 1;\n                if (CurrentPhase == 2)\n                    factor = (float)this.CurrentPhasePart / CPPlotLog.P2PARTS;\n                this.TimeRemaining += (int)(factor * stats.Phase2AvgTimeNeed);\n            }\n            if (CurrentPhase == 1)\n            {\n                var factor = (float)this.CurrentPhasePart / CPPlotLog.P1PARTS;\n                this.TimeRemaining += (int)(factor * stats.Phase2AvgTimeNeed);\n            }\n            if (this.TimeRemaining > 0)\n            {\n                DateTime dt = DateTime.Now;\n                dt = dt.AddSeconds(this.TimeRemaining);\n                this.ETA = dt;\n            }\n            else\n                this.ETA = null;\n        }\n\n        public override void UpdateHealth(PlottingStatistics stats)\n        {\n            // TODO\n            base.UpdateHealth(stats);\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/CPPlotLogReadable.cs",
    "content": "﻿using ChiaPlotStatus;\nusing ChiaPlotStatusLib.Logic.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Models\n{\n    public class CPPlotLogReadable: PlotLogReadable\n    {\n        public string CurrentPhasePart { get; set; } = \"\";\n\n        public string P3Entries { get; set; } = \"\";\n\n        public string P1Table1 { get; set; } = \"\";\n        public string P1Table1Found { get; set; } = \"\";\n        public string P1Table1Lost { get; set; } = \"\";\n        public string P1Table2 { get; set; } = \"\";\n        public string P1Table2Found { get; set; } = \"\";\n        public string P1Table2Lost { get; set; } = \"\";\n        public string P1Table3 { get; set; } = \"\";\n        public string P1Table3Found { get; set; } = \"\";\n        public string P1Table3Lost { get; set; } = \"\";\n        public string P1Table4 { get; set; } = \"\";\n        public string P1Table4Found { get; set; } = \"\";\n        public string P1Table4Lost { get; set; } = \"\";\n        public string P1Table5 { get; set; } = \"\";\n        public string P1Table5Found { get; set; } = \"\";\n        public string P1Table5Lost { get; set; } = \"\";\n        public string P1Table6 { get; set; } = \"\";\n        public string P1Table6Found { get; set; } = \"\";\n        public string P1Table6Lost { get; set; } = \"\";\n        public string P1Table7 { get; set; } = \"\";\n        public string P1Table7Found { get; set; } = \"\";\n        public string P1Table7Lost { get; set; } = \"\";\n\n        public string P2MaxTableSize { get; set; } = \"\";\n\n        public string P2Table1Scan { get; set; } = \"\";\n        public string P2Table2Scan { get; set; } = \"\";\n        public string P2Table3Scan { get; set; } = \"\";\n        public string P2Table4Scan { get; set; } = \"\";\n        public string P2Table5Scan { get; set; } = \"\";\n        public string P2Table6Scan { get; set; } = \"\";\n        public string P2Table7Scan { get; set; } = \"\";\n\n        public string P2Table1Rewrite { get; set; } = \"\";\n        public string P2Table2Rewrite { get; set; } = \"\";\n        public string P2Table3Rewrite { get; set; } = \"\";\n        public string P2Table4Rewrite { get; set; } = \"\";\n        public string P2Table5Rewrite { get; set; } = \"\";\n        public string P2Table6Rewrite { get; set; } = \"\";\n        public string P2Table7Rewrite { get; set; } = \"\";\n\n        public string P2Table1Lost { get; set; } = \"\";\n        public string P2Table2Lost { get; set; } = \"\";\n        public string P2Table3Lost { get; set; } = \"\";\n        public string P2Table4Lost { get; set; } = \"\";\n        public string P2Table5Lost { get; set; } = \"\";\n        public string P2Table6Lost { get; set; } = \"\";\n        public string P2Table7Lost { get; set; } = \"\";\n\n        public string P31Table2 { get; set; } = \"\";\n        public string P31Table2Entries { get; set; } = \"\";\n        public string P31Table3 { get; set; } = \"\";\n        public string P31Table3Entries { get; set; } = \"\";\n        public string P31Table4 { get; set; } = \"\";\n        public string P31Table4Entries { get; set; } = \"\";\n        public string P31Table5 { get; set; } = \"\";\n        public string P31Table5Entries { get; set; } = \"\";\n        public string P31Table6 { get; set; } = \"\";\n        public string P31Table6Entries { get; set; } = \"\";\n        public string P31Table7 { get; set; } = \"\";\n        public string P31Table7Entries { get; set; } = \"\";\n\n        public string P32Table1 { get; set; } = \"\";\n        public string P32Table1Entries { get; set; } = \"\";\n        public string P32Table2 { get; set; } = \"\";\n        public string P32Table2Entries { get; set; } = \"\";\n        public string P32Table3 { get; set; } = \"\";\n        public string P32Table3Entries { get; set; } = \"\";\n        public string P32Table4 { get; set; } = \"\";\n        public string P32Table4Entries { get; set; } = \"\";\n        public string P32Table5 { get; set; } = \"\";\n        public string P32Table5Entries { get; set; } = \"\";\n        public string P32Table6 { get; set; } = \"\";\n        public string P32Table6Entries { get; set; } = \"\";\n        public string P32Table7 { get; set; } = \"\";\n        public string P32Table7Entries { get; set; } = \"\";\n\n\n        public CPPlotLogReadable(CPPlotLog cpPlotLog): base(cpPlotLog)\n        {\n            this.CurrentBucket = \"\";\n            if (cpPlotLog.CurrentTable == 0)\n                this.CurrentTable = \"\";\n            else\n                this.CurrentTable = cpPlotLog.CurrentTable + \"/7\";\n\n            switch (cpPlotLog.CurrentPhase)\n            {\n                case 1:\n                    this.CurrentPhase = \"1/5\";\n                    this.CurrentPhasePart = cpPlotLog.CurrentPhasePart + \"/\" + CPPlotLog.P1PARTS;\n                    break;\n                case 2:\n                    this.CurrentPhase = \"2/5\";\n                    this.CurrentPhasePart = cpPlotLog.CurrentPhasePart + \"/\" + CPPlotLog.P2PARTS;\n                    break;\n                case 3:\n                    this.CurrentPhase = \"3/5\";\n                    this.CurrentPhasePart = cpPlotLog.CurrentPhasePart + \"/\" + CPPlotLog.P3PARTS;\n                    break;\n                case 4:\n                    this.CurrentPhase = \"4/5\";\n                    this.CurrentPhasePart = cpPlotLog.CurrentPhasePart + \"/\" + CPPlotLog.P4PARTS;\n                    break;\n                case 5:\n                    this.CurrentPhase = \"5/5\";\n                    this.CurrentPhasePart = \"\";\n                    break;\n                case 6:\n                    this.CurrentPhase = \"\";\n                    this.CurrentPhasePart = \"\";\n                    break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/Columns.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json.Serialization;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Models\n{\n    /**\n     * This is code for the GUI, but needs to here to be part of Settings.\n     * Well, it could be used to render an ascii table / cli ui, too.\n     */\n    public class Columns\n    {\n        public List<string> Order { get; set; } = new();\n        public Dictionary<string, int> Widths { get; set; } = new();\n\n        public Columns() {  }\n\n        public int IndexOf(string columnName)\n        {\n            for (int i = 0; i < Order.Count; i++)\n                if (columnName == Order[i])\n                    return i;\n            return -1;\n        }\n\n        public void FixAddedAndRemovedColumns() {\n            var defaultColumns = Default();\n            // add columns that are new in this release\n            foreach (var defaultCol in defaultColumns.Order)\n                if (!this.Order.Contains(defaultCol))\n                    this.Order.Add(defaultCol);\n\n            // remove saved columns that were removed in this release\n            List<string> colsToRemove = new();\n            foreach (var col in this.Order)\n                if (!defaultColumns.Order.Contains(col))\n                    colsToRemove.Add(col);\n            foreach (var col in colsToRemove)\n                this.Order.Remove(col);\n        }\n\n        public static Columns Default()\n        {\n            Columns columns = new();\n\n            columns.Order.Add(\"Note\");\n            columns.Order.Add(\"Tmp1Drive\");\n            columns.Order.Add(\"Tmp2Drive\");\n            columns.Order.Add(\"DestDrive\");\n            columns.Order.Add(\"StartDate\");\n            columns.Order.Add(\"FinishDate\");\n            columns.Order.Add(\"Health\");\n            columns.Order.Add(\"Errors\");\n            columns.Order.Add(\"Progress\");\n            columns.Order.Add(\"ETA\");\n            columns.Order.Add(\"TimeRemaining\");\n            columns.Order.Add(\"RunTimeSeconds\");\n            columns.Order.Add(\"CurrentPhase\");\n            columns.Order.Add(\"CurrentTable\");\n            columns.Order.Add(\"CurrentBucket\");\n            columns.Order.Add(\"Phase1Seconds\");\n            columns.Order.Add(\"Phase1Cpu\");\n            columns.Order.Add(\"Phase2Seconds\");\n            columns.Order.Add(\"Phase2Cpu\");\n            columns.Order.Add(\"Phase3Seconds\");\n            columns.Order.Add(\"Phase3Cpu\");\n            columns.Order.Add(\"Phase4Seconds\");\n            columns.Order.Add(\"Phase4Cpu\");\n            columns.Order.Add(\"CopyTimeSeconds\");\n            columns.Order.Add(\"TotalSeconds\");\n            columns.Order.Add(\"Buffer\");\n            columns.Order.Add(\"Buckets\");\n            columns.Order.Add(\"Threads\");\n            columns.Order.Add(\"LogFolder\");\n            columns.Order.Add(\"LogFile\");\n            columns.Order.Add(\"PlaceInLogFile\");\n            columns.Order.Add(\"PID\");\n            columns.Order.Add(\"ApproximateWorkingSpace\");\n            columns.Order.Add(\"FinalFileSize\");\n            columns.Order.Add(\"LastLogLine\");\n            columns.Order.Add(\"PoolPuzzleHash\");\n\n            return columns;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/Filter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.Logic.Models\n{\n    public class Filter\n    {\n        public bool HideFinished { get; set; } = false;\n        public bool HidePossiblyDead { get; set; } = false;\n        public bool HideConfirmedDead { get; set; } = false;\n        public bool HideHealthy { get; set; } = false;\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/Health.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.Logic.Models\n{\n    public interface HealthIndicator\n    {\n        public string Name { get; }\n        public int SortIndex { get; }\n    }\n\n    public class Healthy : HealthIndicator\n    {\n        public string Name { get; } = \"Healthy\";\n        public int SortIndex { get; } = 1;\n        private Healthy() { }\n        public static Healthy Instance = new();\n    }\n\n    public class TempError : HealthIndicator\n    {\n        public string Name { get; } = \"TempError\";\n        public int SortIndex { get; } = 2;\n        private TempError() { }\n        public static TempError Instance = new();\n    }\n\n    public class Concerning : HealthIndicator\n    {\n        public string Name { get; } = \"Concerning\";\n        public int SortIndex { get; } = 3;\n        public float Minutes { get; set; }\n        public float ExpectedMinutes { get; set; }\n\n        public Concerning(float minutes, float expectedMinutes) {\n            this.Minutes = minutes;\n            this.ExpectedMinutes = expectedMinutes;\n        }\n    }\n\n    public class PossiblyDead : HealthIndicator\n    {\n        public string Name { get; } = \"PossiblyDead\";\n        public int SortIndex { get; } = 4;\n        public float Minutes { get; set; }\n        public float ExpectedMinutes { get; set; }\n\n        public PossiblyDead(float minutes, float expectedMinutes)\n        {\n            this.Minutes = minutes;\n            this.ExpectedMinutes = expectedMinutes;\n        }\n    }\n\n    public class ConfirmedDead : HealthIndicator\n    {\n        public string Name { get; } = \"ConfirmedDead\";\n        public int SortIndex { get; } = 5;\n        public bool Manual { get; set; }\n        public ConfirmedDead(bool manual)\n        {\n            this.Manual = manual;\n        }\n    }\n\n\n\n    /**\n     * // apparently csharp cannot do this? Which lang did tho? Scala?\n     * public enum Health\n        {\n            HEALTHY,\n            TEMP_ERROR,\n            CONCERNING(float minutes),\n            POSSIBLY_DEAD(float minutes),\n            CONFIRMED_DEAD(bool manual)\n        }\n*/\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/MarkOfDeath.cs",
    "content": "﻿using ChiaPlotStatusLib.Logic.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.Logic.Models\n{\n    /**\n     * Manually marks a PlogLog as dead so it can be hidden\n     */\n    public class MarkOfDeath\n    {\n        public string LogFolder { get; set; }\n        public string LogFile { get; set; }\n        public int PlaceInLogFile { get; set; }\n        public DateTime? DiedAt { get; set; }\n\n        public MarkOfDeath() { }\n\n        public MarkOfDeath(PlotLogReadable plotLogReadable) {\n            this.LogFolder = plotLogReadable.LogFolder;\n            this.LogFile = plotLogReadable.LogFile;\n            this.PlaceInLogFile = int.Parse(plotLogReadable.PlaceInLogFile.Split(\"/\")[0]);\n            // here and not in field definition to stay compatible to pre DiedAt versions\n            this.DiedAt = DateTime.Now;\n        }\n\n        public MarkOfDeath(CPPlotLogReadable plotLogReadable)\n        {\n            this.LogFolder = plotLogReadable.LogFolder;\n            this.LogFile = plotLogReadable.LogFile;\n            this.PlaceInLogFile = 1;\n            this.DiedAt = DateTime.Now;\n        }\n\n        public bool IsMatch(PlotLog plotLog)\n        {\n            if (!string.Equals(this.LogFolder, plotLog.LogFolder)) return false;\n            string logFileName = plotLog.LogFile.Substring(plotLog.LogFile.LastIndexOf(Path.DirectorySeparatorChar) + 1);\n            if (!string.Equals(this.LogFile, logFileName)) return false;\n            if (this.PlaceInLogFile != plotLog.PlaceInLogFile) return false;\n            return true;\n        }\n\n        public bool IsMatch(PlotLogReadable plotLog)\n        {\n            if (!string.Equals(this.LogFolder, plotLog.LogFolder)) return false;\n            if (!string.Equals(this.LogFile, plotLog.LogFile)) return false;\n            if (!string.Equals(this.PlaceInLogFile, plotLog.PlaceInLogFile)) return false;\n            return true;\n        }\n\n        public bool IsMatch(CPPlotLog plotLog)\n        {\n            if (!string.Equals(this.LogFolder, plotLog.LogFolder)) return false;\n            string logFileName = plotLog.LogFile.Substring(plotLog.LogFile.LastIndexOf(Path.DirectorySeparatorChar) + 1);\n            if (!string.Equals(this.LogFile, logFileName)) return false;\n            return true;\n        }\n\n        public bool IsMatch(CPPlotLogReadable plotLog)\n        {\n            if (!string.Equals(this.LogFolder, plotLog.LogFolder)) return false;\n            if (!string.Equals(this.LogFile, plotLog.LogFile)) return false;\n            return true;\n        }\n\n        public override bool Equals(object? obj)\n        {\n            return obj is MarkOfDeath death &&\n                   LogFolder == death.LogFolder &&\n                   LogFile == death.LogFile &&\n                   PlaceInLogFile == death.PlaceInLogFile;\n        }\n\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(LogFolder, LogFile, PlaceInLogFile);\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/Note.cs",
    "content": "﻿using ChiaPlotStatus;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Models\n{\n    /**\n     * A little notice or a collection of tags you can attach to a plot log <file>\n     * It affects all plot logs in the same log file, which allows to add the\n     * GUI Plotter Queue Name to Chia Plot Status.\n     */\n    public class Note\n    {\n        public string LogFolder { get; set; }\n        public string LogFile { get; set; }\n        public string text { get; set; }\n\n        public Note() { }\n\n        public Note(PlotLogReadable plotLogReadable)\n        {\n            this.LogFolder = plotLogReadable.LogFolder;\n            this.LogFile = plotLogReadable.LogFile;\n            this.text = plotLogReadable.Note;\n        }\n\n\n        public bool IsMatch(PlotLog plotLog)\n        {\n            if (!string.Equals(this.LogFolder, plotLog.LogFolder)) return false;\n            string logFileName = plotLog.LogFile.Substring(plotLog.LogFile.LastIndexOf(Path.DirectorySeparatorChar) + 1);\n            if (!string.Equals(this.LogFile, logFileName)) return false;\n            return true;\n        }\n\n        public bool IsMatch(PlotLogReadable plotLog)\n        {\n            if (!string.Equals(this.LogFolder, plotLog.LogFolder)) return false;\n            if (!string.Equals(this.LogFile, plotLog.LogFile)) return false;\n            return true;\n        }\n\n        public bool IsMatch(CPPlotLog plotLog)\n        {\n            if (!string.Equals(this.LogFolder, plotLog.LogFolder)) return false;\n            string logFileName = plotLog.LogFile.Substring(plotLog.LogFile.LastIndexOf(Path.DirectorySeparatorChar) + 1);\n            if (!string.Equals(this.LogFile, logFileName)) return false;\n            return true;\n        }\n\n        public bool IsMatch(CPPlotLogReadable plotLog)\n        {\n            if (!string.Equals(this.LogFolder, plotLog.LogFolder)) return false;\n            if (!string.Equals(this.LogFile, plotLog.LogFile)) return false;\n            return true;\n        }\n\n        public override bool Equals(object obj)\n        {\n            return obj is Note note &&\n                   LogFolder == note.LogFolder &&\n                   LogFile == note.LogFile;\n        }\n\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(LogFolder, LogFile);\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/PlotLog.cs",
    "content": "﻿using ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusLib.Logic.Models;\nusing System;\nusing System.Diagnostics;\nusing System.Text.Json.Serialization;\n\nnamespace ChiaPlotStatus\n{\n    /**\n     * Stores informations about a plotting process.\n     * This is the object shown in the ui table.\n     */\n    public class PlotLog\n    {\n        public string UsedPlotter { get; set; } = \"chiapos\";\n        public string? Tmp1Drive { get; set; }\n        public string? Tmp2Drive { get; set; }\n        public string? DestDrive { get; set; }\n        public int Errors { get; set; } = 0;\n        public int PID { get; set; } = 0;\n        public float Progress { get; set; } = 0;\n        public int TimeRemaining { get; set; } = 0;\n        public DateTime? ETA { get; set; }\n        public int CurrentTable { get; set; } = 0;\n        // Phase 6 is done\n        public int CurrentPhase { get; set; } = 0;\n        public int CurrentBucket { get; set; } = 0;\n        public int Phase1Table { get; set; } = 0;\n        public int Phase2Table { get; set; } = 0;\n        public int Phase3Table { get; set; } = 0;\n        public int Phase1Seconds { get; set; } = 0;\n        public int Phase2Seconds { get; set; } = 0;\n        public int Phase3Seconds { get; set; } = 0;\n        public int Phase4Seconds { get; set; } = 0;\n        public double Phase1Cpu { get; set; } = 0;\n        public double Phase2Cpu { get; set; } = 0;\n        public double Phase3Cpu { get; set; } = 0;\n        public double Phase4Cpu { get; set; } = 0;\n        public int CopyTimeSeconds { get; set; } = 0;\n        public int TotalSeconds { get; set; } = 0;\n        public int PlotSize { get; set; } = 0;\n        public int Threads { get; set; } = 0;\n        public int Buffer { get; set; } = 0;\n        public int Buckets { get; set; } = 0;\n        public DateTime? StartDate { get; set; }\n        public DateTime? FinishDate { get; set; }\n        public string PlotName { get; set; } = \"\";\n        public string LogFolder { get; set; } = \"\";\n        public string LogFile { get; set; } = \"\";\n        public string ApproximateWorkingSpace { get; set; } = \"\";\n        public string FinalFileSize { get; set; } = \"\";\n        public DateTime? FileLastWritten { get; set; }\n        [JsonIgnore]\n        public HealthIndicator Health { get; set; } = Healthy.Instance;\n        public bool IsLastInLogFile { get; set; } = true;\n        public bool IsLastLineTempError { get; set; } = false;\n        public int QueueSize { get; set; } = 1;\n        public int PlaceInLogFile { get; set; } = 1;\n        public int RunTimeSeconds { get; set; } = 0;\n        public bool CaughtPlottingError { get; set; } = false;\n        public string LastLogLine { get; set; } = \"\";\n        public string Note { get; set; } = \"Notice / Tags\";\n        public string PoolPuzzleHash { get; set; } = \"\";\n\n        public virtual void UpdateProgress()\n        {\n            float part = 0;\n            // 22 parts total:\n            // 7 tables in phase 1\n            // 7 tables in phase 2\n            // 7 tables in phase 3\n            // 1 phase 4\n            // 1 phase 5\n            float subpart = 0;\n\n            switch(CurrentPhase)\n            {\n                case 6:\n                    part = 23;\n                    break;\n                case 5:\n                    part = 22;\n                    break;\n                case 4:\n                    part = 20;\n                    subpart = (float)this.CurrentBucket / this.Buckets;\n                    break;\n                case 3:\n                    int totalTablesIn3 = 7;\n                    part = 20 - (totalTablesIn3 - Phase3Table);\n                    subpart = (float)CurrentBucket / Buckets;\n                    break;\n                case 2:\n                    part = 14 - Phase2Table;\n                    subpart = (float)CurrentBucket / Buckets;\n                    break;\n                case 1:\n                    int totalTablesIn1 = 7;\n                    part = 7 - (totalTablesIn1 - Phase1Table) - 1;\n                    subpart = (float)CurrentBucket / Buckets;\n                    break;\n            }\n            Progress = (part + subpart) / 23 * 100;\n            if (Double.IsNaN(Progress))\n                Progress = 0;\n        }\n\n        /**\n         * Run UpdateHealth before calling\n         */\n        public virtual bool IsRunning()\n        {\n            switch (Health)\n            {\n                case Healthy:\n                case Concerning:\n                case TempError:\n                case PossiblyDead:\n                    return CurrentPhase != 6;\n                default:\n                    return false;\n            }\n        }\n\n        public virtual void UpdateEta(PlottingStatistics stats)\n        {\n            this.TimeRemaining = 0;\n            if (this.Buckets == 0)\n            {\n                // log too short to know anything yet\n                this.ETA = null;\n                this.TimeRemaining = 0;\n                return;\n            }\n            if (CurrentPhase == 6)\n            {\n                this.TimeRemaining = 0;\n            }\n            if (CurrentPhase <= 5)\n            {\n                float factor = 1;\n                if (CurrentPhase == 5)\n                {\n                    DateTime copyStart = ((DateTime)this.StartDate)\n                        .AddSeconds(this.Phase1Seconds)\n                        .AddSeconds(this.Phase2Seconds)\n                        .AddSeconds(this.Phase3Seconds)\n                        .AddSeconds(this.Phase4Seconds);\n                    int elapsed = (int)(DateTime.Now - copyStart).TotalSeconds;\n                    factor = (float)1 - (float)((float)elapsed / stats.CopyTimeAvgTimeNeed);\n                    if (factor < 0.01f)\n                        factor = 0.01f;\n                }\n                this.TimeRemaining += (int)(factor * (float)stats.CopyTimeAvgTimeNeed);\n            }\n            if (CurrentPhase <= 4)\n            {\n                float factor = 1;\n                if (CurrentPhase == 4)\n                {\n                    factor = (float)1 - ((float)((float)this.CurrentBucket / this.Buckets));\n                }\n                this.TimeRemaining += (int)(factor * stats.Phase4AvgTimeNeed);\n            }\n            if (CurrentPhase <= 3)\n            {\n                float factor = 1;\n                if (CurrentPhase == 3)\n                {\n                    factor = (float)1 - ((float)(((float)this.Phase3Table - 1) + ((float)this.CurrentBucket / this.Buckets)) / 7);\n                }\n                this.TimeRemaining += (int)(factor * stats.Phase3AvgTimeNeed);\n            }\n            if (CurrentPhase <= 2)\n            {\n                float factor = 1;\n                if (CurrentPhase == 2)\n                {\n                    factor = (float)1 - ((float)((float) 7 - this.Phase2Table) / 7);\n                }\n                this.TimeRemaining += (int)(factor * stats.Phase2AvgTimeNeed);\n            }\n            if (CurrentPhase == 1)\n            {\n                var factor = (float)1 - ((float)(((float)this.Phase3Table - 1) + ((float)this.CurrentBucket / this.Buckets)) / 7);\n                this.TimeRemaining += (int)(factor * stats.Phase2AvgTimeNeed);\n            }\n            if (this.TimeRemaining > 0)\n            {\n                DateTime dt = DateTime.Now;\n                dt = dt.AddSeconds(this.TimeRemaining);\n                this.ETA = dt;\n            }\n            else\n                this.ETA = null;\n        }\n\n        public virtual void UpdateHealth(PlottingStatistics stats)\n        {\n            int lastModifiedAtWarningThreashold = 0;\n            int lastModifiedAtErrorThreashold = 0;\n\n            switch (this.CurrentPhase)\n            {\n                case 1:\n                    if (this.CurrentTable == 1)\n                        lastModifiedAtWarningThreashold = (int)(((float)stats.Phase1AvgTimeNeed / 60 / 7) * 3);\n                    else\n                        lastModifiedAtWarningThreashold = (int)(((float)stats.Phase1AvgTimeNeed / 60 / 7 / this.Buckets) * 3);\n                    if (lastModifiedAtWarningThreashold == 0)\n                        lastModifiedAtWarningThreashold = 15;\n                    break;\n                case 2:\n                    lastModifiedAtWarningThreashold = (int)((float)stats.Phase2AvgTimeNeed / 60 / 7 * 3);\n                    if (lastModifiedAtWarningThreashold == 0)\n                        lastModifiedAtWarningThreashold = 10;\n                    break;\n                case 3:\n                    lastModifiedAtWarningThreashold = (int)(((float)stats.Phase3AvgTimeNeed / 60 / 7 / this.Buckets) * 3);\n                    if (lastModifiedAtWarningThreashold == 0)\n                        lastModifiedAtWarningThreashold = 15;\n                    break;\n                case 4:\n                    lastModifiedAtWarningThreashold = (int)(((float)stats.Phase3AvgTimeNeed / 60 / this.Buckets) * 3);\n                    if (lastModifiedAtWarningThreashold == 0)\n                        lastModifiedAtWarningThreashold = 15;\n                    if (this.CurrentBucket == this.Buckets)\n                        lastModifiedAtWarningThreashold = 20;\n                    break;\n                case 5:\n                case 6:\n                    Health = Healthy.Instance;\n                    return;\n            }\n            if (lastModifiedAtWarningThreashold < 10)\n                lastModifiedAtWarningThreashold = 10;\n            lastModifiedAtWarningThreashold = (int)((float)lastModifiedAtWarningThreashold * 1.2f);\n            lastModifiedAtErrorThreashold = lastModifiedAtWarningThreashold * 4;\n            // Debug.WriteLine(\"lastModifiedAtWarningThreashold: \" + lastModifiedAtWarningThreashold);\n            // Debug.WriteLine(\"lastModifiedAtErrorThreashold: \" + lastModifiedAtErrorThreashold);\n\n            bool notLastAndNotDone = this.Progress < 100d && !this.IsLastInLogFile;\n            bool lastModfiedAtWarning = false;\n            bool lastModfiedAtError = false;\n            bool lastLineError = this.IsLastLineTempError;\n            TimeSpan? fileLastWrittenAge = null;\n            int lastWriteMinutesAgo = 0;\n            if (this.FileLastWritten != null)\n            {\n                fileLastWrittenAge = DateTime.Now - ((DateTime)this.FileLastWritten);\n                if (((TimeSpan)fileLastWrittenAge).TotalMinutes > (lastModifiedAtWarningThreashold + 1))\n                    lastModfiedAtWarning = true;\n                if (((TimeSpan)fileLastWrittenAge).TotalMinutes > (lastModifiedAtErrorThreashold + 1))\n                    lastModfiedAtError = true;\n                lastWriteMinutesAgo = (int)((TimeSpan)fileLastWrittenAge).TotalMinutes;\n            }\n\n            // manual is set to false for now, it will be overwritten in ChiaPlotStatus.cs if necessary\n            bool manual = false;\n            if (notLastAndNotDone || this.CaughtPlottingError)\n                this.Health = new ConfirmedDead(manual);\n            else if (lastModfiedAtError)\n                this.Health = new PossiblyDead(lastWriteMinutesAgo, lastModifiedAtWarningThreashold);\n            else if (lastModfiedAtWarning)\n                this.Health = new Concerning(lastWriteMinutesAgo, lastModifiedAtWarningThreashold);\n            else if (lastLineError)\n                this.Health = TempError.Instance;\n            else\n                this.Health = Healthy.Instance;\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/PlotLogReadable.cs",
    "content": "﻿using ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusLib.Logic.Models;\nusing ChiaPlotStatusLib.Logic.Utils;\nusing System;\nusing System.Diagnostics;\nusing System.IO;\n\nnamespace ChiaPlotStatus\n{\n    /**\n     * Stores readable informations about a plotting process.\n     * This is the object shown in the ui table.\n     */\n    public class PlotLogReadable\n    {\n        public string Tmp1Drive { get; set; } = \"\";\n        public string Tmp2Drive { get; set; } = \"\";\n        public string DestDrive { get; set; }\n        public string Errors { get; set; } = \"\";\n        public string PID { get; set; } = \"\";\n        public string Progress { get; set; } = \"\";\n        public string TimeRemaining { get; set; } = \"\";\n        public string ETA { get; set; } = \"\";\n        public string CurrentTable { get; set; } = \"\";\n        public string CurrentBucket { get; set; } = \"\";\n        public string CurrentPhase { get; set; } = \"\";\n        public string Phase1Cpu { get; set; } = \"\";\n        public string Phase2Cpu { get; set; } = \"\";\n        public string Phase3Cpu { get; set; } = \"\";\n        public string Phase4Cpu { get; set; } = \"\";\n        public string Phase1Seconds { get; set; } = \"\";\n        public string Phase2Seconds { get; set; } = \"\";\n        public string Phase3Seconds { get; set; } = \"\";\n        public string Phase4Seconds { get; set; } = \"\";\n        public string CopyTimeSeconds { get; set; } = \"\";\n        public string TotalSeconds { get; set; } = \"\";\n        public string PlotSize { get; set; } = \"\";\n        public string Threads { get; set; } = \"\";\n        public string Buffer { get; set; } = \"\";\n        public string Buckets { get; set; } = \"\";\n        public string StartDate { get; set; } = \"\";\n        public string FinishDate { get; set; } = \"\";\n        public string PlotName { get; set; } = \"\";\n        public string LogFolder { get; set; } = \"\";\n        public string LogFile { get; set; } = \"\";\n        public string ApproximateWorkingSpace { get; set; } = \"\";\n        public string FinalFileSize { get; set; } = \"\";\n        public string Health { get; set; } = \"\";\n        public string PlaceInLogFile { get; set; } = \"\";\n        public string RunTimeSeconds { get; set; } = \"\";\n        public string LastLogLine { get; set; } = \"\";\n        public bool IsSelected { get; set; } = false;\n        public string Note { get; set; } = \"\";\n        public string PoolPuzzleHash { get; set; } = \"\";\n\n\n        public PlotLogReadable(PlotLog plotLog)\n        {\n            this.Tmp1Drive = plotLog.Tmp1Drive;\n            this.Tmp2Drive = plotLog.Tmp2Drive;\n            if (plotLog.Errors > 0)\n                this.Errors = plotLog.Errors.ToString();\n            this.Progress = string.Format(\"{0:0.00}\", plotLog.Progress) + \"%\";\n            if (string.Equals(this.Progress, \"NaN%\")) this.Progress = \"\";\n            switch(plotLog.CurrentPhase)\n            {\n                case 1:\n                    this.CurrentPhase = \"1/5\";\n                    this.CurrentTable = plotLog.Phase1Table + \"/7 ↑\";\n                    break;\n                case 2:\n                    this.CurrentPhase = \"2/5\";\n                    this.CurrentTable = plotLog.Phase2Table + \"/7 ↓\";\n                    break;\n                case 3:\n                    this.CurrentPhase = \"3/5\";\n                    this.CurrentTable = plotLog.Phase3Table + \"/7 ↑\";\n                    break;\n                case 4:\n                    this.CurrentPhase = \"4/5\";\n                    this.CurrentTable = \"1/1\";\n                    break;\n                case 5:\n                    this.CurrentPhase = \"5/5\";\n                    this.CurrentTable = \"\";\n                    break;\n                case 6: // done\n                    this.CurrentPhase = \"\";\n                    this.CurrentTable = \"\";\n                    break;\n            }\n            this.ETA = Formatter.formatDateTime(plotLog.ETA);\n            this.StartDate = Formatter.formatDateTime(plotLog.StartDate);\n            this.FinishDate = Formatter.formatDateTime(plotLog.FinishDate);\n            this.TimeRemaining = Formatter.formatSeconds(plotLog.TimeRemaining, true);\n            this.Phase1Cpu = Formatter.formatCpuUsage(plotLog.Phase1Cpu);\n            this.Phase2Cpu = Formatter.formatCpuUsage(plotLog.Phase2Cpu);\n            this.Phase3Cpu = Formatter.formatCpuUsage(plotLog.Phase3Cpu);\n            this.Phase4Cpu = Formatter.formatCpuUsage(plotLog.Phase4Cpu);\n            this.Phase1Seconds = Formatter.formatSeconds(plotLog.Phase1Seconds, true);\n            this.Phase2Seconds = Formatter.formatSeconds(plotLog.Phase2Seconds, true);\n            this.Phase3Seconds = Formatter.formatSeconds(plotLog.Phase3Seconds, true);\n            this.Phase4Seconds = Formatter.formatSeconds(plotLog.Phase4Seconds, false);\n            this.CopyTimeSeconds = Formatter.formatSeconds(plotLog.CopyTimeSeconds, false);\n            this.TotalSeconds = Formatter.formatSeconds(plotLog.TotalSeconds, true);\n            this.RunTimeSeconds = Formatter.formatSeconds(plotLog.RunTimeSeconds, true);\n            this.ApproximateWorkingSpace = plotLog.ApproximateWorkingSpace;\n            this.DestDrive = plotLog.DestDrive;\n            this.FinalFileSize = plotLog.FinalFileSize;\n            this.Buckets = plotLog.Buckets.ToString();\n            this.Threads = plotLog.Threads.ToString();\n            this.Buffer = plotLog.Buffer + \" MB\";\n            this.PoolPuzzleHash = plotLog.PoolPuzzleHash;\n            this.LastLogLine = plotLog.LastLogLine;\n            if (plotLog.PID != 0)\n                this.PID = \"\" + plotLog.PID;\n            switch (plotLog.CurrentPhase)\n            {\n                case 1:\n                case 3:\n                case 4:\n                    this.CurrentBucket = plotLog.CurrentBucket + \"/\" + plotLog.Buckets;\n                    break;\n                case 2:\n                case 5:\n                case 6:\n                    this.CurrentBucket = \"\";\n                    break;\n            }\n            this.PlotName = plotLog.PlotName;\n            this.LogFolder = plotLog.LogFolder;\n            this.LogFile = plotLog.LogFile.Substring(plotLog.LogFile.LastIndexOf(Path.DirectorySeparatorChar) + 1);\n            this.Health = Formatter.formatHealth(plotLog.Health);\n            this.PlaceInLogFile = plotLog.PlaceInLogFile + \"/\" + plotLog.QueueSize;\n            this.Note = plotLog.Note;\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Models/Settings.cs",
    "content": "﻿using ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusLib.Logic.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.Logic.Models\n{\n    public class Settings\n    {\n        private string SettingsFile;\n        public bool? AlwaysDoFullRead { get; set; } = false;\n        public string? Theme { get; set; } = \"Light\";\n        public ObservableCollection<string> LogDirectories { get; set; } = new();\n        public double? MaxHarvestLookupSeconds { get; set; } = 5d;\n        public ObservableCollection<string> HarvesterLogDirectories { get; set; } = new();\n        public Columns Columns { get; set; } = Columns.Default();\n        public PlottingStatisticsIdRelevanceWeights Weigths { get; set; } = new();\n        public Filter Filter { get; set; } = new();\n        public string? SortProperty { get; set; } = \"Progress\";\n        public bool? SortAsc { get; set; } = true;\n        public List<Note>? Notes { get; set; } = new();\n        public List<MarkOfDeath>? MarksOfDeath { get; set; } = new();\n        // no longer supported, but needs to stay or JsonDeserializer is not happy with old config files\n        public double? FontSize { get; set; } = null;\n\n        public Settings()\n        {\n            this.SettingsFile = \"ChiaPlotStatusSettings\";\n        }\n\n        public Settings(string settingsFile)\n        {\n            this.SettingsFile = settingsFile;\n        }\n\n        public bool Load()\n        {\n            if (File.Exists(this.SettingsFile))\n            {\n                string json = File.ReadAllText(this.SettingsFile);\n                Settings? fromFile = JsonSerializer.Deserialize<Settings>(json);\n                if (fromFile != null)\n                {\n                    if (fromFile.LogDirectories != null)\n                        this.LogDirectories = fromFile.LogDirectories;\n                    if (fromFile.FontSize != null && fromFile.FontSize > 6)\n                        this.FontSize = fromFile.FontSize;\n                    if (fromFile.Theme != null)\n                        this.Theme = fromFile.Theme;\n                    if (fromFile.MarksOfDeath != null)\n                        this.MarksOfDeath = fromFile.MarksOfDeath;\n                    if (fromFile.AlwaysDoFullRead != null)\n                        this.AlwaysDoFullRead = fromFile.AlwaysDoFullRead;\n                    if (fromFile.Filter != null)\n                        this.Filter = fromFile.Filter;\n                    if (fromFile.SortProperty != null)\n                        this.SortProperty = fromFile.SortProperty;\n                    if (fromFile.SortAsc != null)\n                        this.SortAsc = fromFile.SortAsc;\n                    if (fromFile.Weigths != null)\n                        this.Weigths = fromFile.Weigths;\n                    if (fromFile.Notes != null)\n                        this.Notes = fromFile.Notes;\n                    if (fromFile.HarvesterLogDirectories != null)\n                        this.HarvesterLogDirectories = fromFile.HarvesterLogDirectories;\n                    if (fromFile.MaxHarvestLookupSeconds != null)\n                        this.MaxHarvestLookupSeconds = fromFile.MaxHarvestLookupSeconds;\n                    if (fromFile.Columns != null)\n                    {\n                        this.Columns = fromFile.Columns;\n                        this.Columns.FixAddedAndRemovedColumns();\n                    }\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        public void Persist()\n        {\n            JsonSerializerOptions options = new JsonSerializerOptions();\n            options.AllowTrailingCommas = true;\n            options.MaxDepth = 9999999;\n            options.DefaultBufferSize = 64 * 1024;\n            options.WriteIndented = true;\n            string json = JsonSerializer.Serialize(this, options);\n            File.WriteAllText(SettingsFile, json);\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Parser/CPPlotLogFileParser.cs",
    "content": "﻿using ChiaPlotStatus;\nusing ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusLib.Logic.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Parser\n{\n    class CPPlotLogFileParser\n    {\n        private TailLineEmitter TailLineEmitter { get; }\n        protected List<CPPlotLog> PlotLogs { get; } = new();\n        public string LogFile;\n        public string LogFolder;\n        public bool closed = false;\n        public bool firstRead = false;\n        public bool lineRead = false;\n        public DateTime? lastGrown;\n\n        public CPPlotLogFileParser(string path, bool closeOnEndOfFile)\n        {\n            this.LogFile = path;\n            this.LogFolder = path.Substring(0, path.LastIndexOf(Path.DirectorySeparatorChar));\n            CurrentPlotLog().StartDate = File.GetCreationTime(path);\n            CurrentPlotLog().LogFile = this.LogFile;\n            CurrentPlotLog().LogFolder = this.LogFolder;\n            CurrentPlotLog().CurrentPhase = 1;\n            this.TailLineEmitter = new TailLineEmitter(path, closeOnEndOfFile, (line) =>\n            {\n                lineRead = true;\n                CurrentPlotLog().LastLogLine = line.Trim();\n                if (CurrentPlotLog().CurrentTable == 0)\n                    CurrentPlotLog().CurrentTable = 1;\n                if (!firstRead)\n                    lastGrown = DateTime.Now;\n                MatchCollection matches;\n                switch (line)\n                {\n                    case var _ when copyTimeRG.IsMatch(line):\n                        matches = copyTimeRG.Matches(line);\n                        CurrentPlotLog().CopyTimeSeconds = int.Parse(matches[0].Groups[1].Value);\n                        break;\n                    case var _ when poolPuzzleHashRg.IsMatch(line):\n                        matches = poolPuzzleHashRg.Matches(line);\n                        CurrentPlotLog().PoolPuzzleHash = matches[0].Groups[1].Value;\n                        break;\n                    case var _ when threadsRg.IsMatch(line):\n                        matches = threadsRg.Matches(line);\n                        if (CurrentPlotLog().Threads != 0)\n                            NextPlotLog();\n                        CurrentPlotLog().Threads = int.Parse(matches[0].Groups[1].Value);\n                        CurrentPlotLog().EnterPhase(1);\n                        break;\n                    case var _ when bucketsRg.IsMatch(line):\n                        matches = bucketsRg.Matches(line);\n                        CurrentPlotLog().Buckets = int.Parse(matches[0].Groups[1].Value);\n                        break;\n                    case var _ when buckets2Rg.IsMatch(line):\n                        matches = buckets2Rg.Matches(line);\n                        CurrentPlotLog().Buckets = int.Parse(matches[0].Groups[1].Value);\n                        break;\n                    case var _ when plotNameRg.IsMatch(line):\n                        matches = plotNameRg.Matches(line);\n                        CurrentPlotLog().PlotName = matches[0].Groups[1].Value;\n                        break;\n                    case var _ when tmp1Rg.IsMatch(line):\n                        matches = tmp1Rg.Matches(line);\n                        CurrentPlotLog().Tmp1Drive = matches[0].Groups[1].Value;\n                        break;\n                    case var _ when tmp2Rg.IsMatch(line):\n                        matches = tmp2Rg.Matches(line);\n                        CurrentPlotLog().Tmp2Drive = matches[0].Groups[1].Value;\n                        break;\n                    case var _ when destRg.IsMatch(line):\n                        matches = destRg.Matches(line);\n                        CurrentPlotLog().DestDrive = matches[0].Groups[1].Value;\n                        break;\n                    case var _ when pidRg.IsMatch(line):\n                        matches = pidRg.Matches(line);\n                        CurrentPlotLog().PID = int.Parse(matches[0].Groups[1].Value);\n                        break;\n                    case var _ when lossRg.IsMatch(line):\n                        matches = lossRg.Matches(line);\n                        long lost = long.Parse(matches[0].Groups[1].Value);\n                        switch (CurrentPlotLog().CurrentTable)\n                        {\n                            case 1:\n                                CurrentPlotLog().P1Table1Lost = lost;\n                                break;\n                            case 2:\n                                CurrentPlotLog().P1Table2Lost = lost;\n                                break;\n                            case 3:\n                                CurrentPlotLog().P1Table3Lost = lost;\n                                break;\n                            case 4:\n                                CurrentPlotLog().P1Table4Lost = lost;\n                                break;\n                            case 5:\n                                CurrentPlotLog().P1Table5Lost = lost;\n                                break;\n                            case 6:\n                                CurrentPlotLog().P1Table6Lost = lost;\n                                break;\n                            case 7:\n                                CurrentPlotLog().P1Table7Lost = lost;\n                                break;\n                        }\n                        if (CurrentPlotLog().P1Table1Lost == 0)\n                            CurrentPlotLog().P1Table1Lost = lost;\n                        else if (CurrentPlotLog().P1Table2Lost == 0)\n                            CurrentPlotLog().P1Table2Lost = lost;\n                        else if (CurrentPlotLog().P1Table3Lost == 0)\n                            CurrentPlotLog().P1Table3Lost = lost;\n                        else if (CurrentPlotLog().P1Table4Lost == 0)\n                            CurrentPlotLog().P1Table4Lost = lost;\n                        else if (CurrentPlotLog().P1Table5Lost == 0)\n                            CurrentPlotLog().P1Table5Lost = lost;\n                        else if (CurrentPlotLog().P1Table6Lost == 0)\n                            CurrentPlotLog().P1Table6Lost = lost;\n                        else if (CurrentPlotLog().P1Table7Lost == 0)\n                            CurrentPlotLog().P1Table7Lost = lost;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p1table1Rg.IsMatch(line):\n                        matches = p1table1Rg.Matches(line);\n                        CurrentPlotLog().P1Table1 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentTable = 2;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p1table2Rg.IsMatch(line):\n                        matches = p1table2Rg.Matches(line);\n                        CurrentPlotLog().P1Table2 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P1Table2Found = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 3;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p1table3Rg.IsMatch(line):\n                        matches = p1table3Rg.Matches(line);\n                        CurrentPlotLog().P1Table3 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P1Table3Found = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 4;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p1table4Rg.IsMatch(line):\n                        matches = p1table4Rg.Matches(line);\n                        CurrentPlotLog().P1Table4 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P1Table4Found = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 5;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p1table5Rg.IsMatch(line):\n                        matches = p1table5Rg.Matches(line);\n                        CurrentPlotLog().P1Table5 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P1Table5Found = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 6;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p1table6Rg.IsMatch(line):\n                        matches = p1table6Rg.Matches(line);\n                        CurrentPlotLog().P1Table6 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P1Table6Found = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 7;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p1table7Rg.IsMatch(line):\n                        matches = p1table7Rg.Matches(line);\n                        CurrentPlotLog().P1Table7 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P1Table7Found = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p1timeRg.IsMatch(line):\n                        matches = p1timeRg.Matches(line);\n                        CurrentPlotLog().P1 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().Phase1Seconds = (int)float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().EnterPhase(2);\n                        break;\n                    case var _ when p2timeRg.IsMatch(line):\n                        matches = p2timeRg.Matches(line);\n                        CurrentPlotLog().P2 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().Phase2Seconds = (int)float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().EnterPhase(3);\n                        break;\n                    case var _ when p3timeRg.IsMatch(line):\n                        matches = p3timeRg.Matches(line);\n                        CurrentPlotLog().P3 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().Phase3Seconds = (int)float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P3Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().EnterPhase(4);\n                        break;\n                    case var _ when p4timeRg.IsMatch(line):\n                        matches = p4timeRg.Matches(line);\n                        CurrentPlotLog().P4 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().Phase4Seconds = (int)float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().FinalFileSize = (long.Parse(matches[0].Groups[2].Value) / 1024 / 1024) + \" MB\";\n                        CurrentPlotLog().EnterPhase(5);\n                        break;\n                    case var _ when totaltimeRg.IsMatch(line):\n                        matches = totaltimeRg.Matches(line);\n                        CurrentPlotLog().TotalSeconds = (int)float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().FinishDate = CurrentPlotLog().StartDate.Value.AddSeconds(CurrentPlotLog().TotalSeconds);\n                        if (CurrentPlotLog().FinishDate > DateTime.Now)\n                        {\n                            using (var file = File.AppendText(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + Path.DirectorySeparatorChar +\n                                \"ChiaPlotStatus.chia-plotter-finishdate.log\"))\n                            {\n                                file.WriteLine((DateTime.Now - CurrentPlotLog().FinishDate.Value).TotalSeconds + \"\\n\");\n                            }\n                            CurrentPlotLog().FinishDate = DateTime.Now;\n                        }\n                        CurrentPlotLog().EnterPhase(6);\n                        // TODO:\n                        //if (CurrentPlotLog().QueueSize == 1 || CurrentPlotLog().QueueSize == 0)\n                        //    this.Close();\n                        break;\n\n                    // phase 2\n                    case var _ when p2MaxTableSize.IsMatch(line):\n                        matches = p2MaxTableSize.Matches(line);\n                        CurrentPlotLog().P2MaxTableSize = long.Parse(matches[0].Groups[1].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table1scanRg.IsMatch(line):\n                        matches = p2table1scanRg.Matches(line);\n                        CurrentPlotLog().P2Table1Scan = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentTable = 1;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table1rewriteRg.IsMatch(line):\n                        matches = p2table1rewriteRg.Matches(line);\n                        CurrentPlotLog().P2Table1Rewrite = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P2Table2Lost = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 1;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table2scanRg.IsMatch(line):\n                        matches = p2table2scanRg.Matches(line);\n                        CurrentPlotLog().P2Table2Scan = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentTable = 2;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table2rewriteRg.IsMatch(line):\n                        matches = p2table2rewriteRg.Matches(line);\n                        CurrentPlotLog().P2Table2Rewrite = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P2Table2Lost = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 1;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table3scanRg.IsMatch(line):\n                        matches = p2table3scanRg.Matches(line);\n                        CurrentPlotLog().P2Table3Scan = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentTable = 3;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table3rewriteRg.IsMatch(line):\n                        matches = p2table3rewriteRg.Matches(line);\n                        CurrentPlotLog().P2Table3Rewrite = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P2Table3Lost = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 2;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table4scanRg.IsMatch(line):\n                        matches = p2table4scanRg.Matches(line);\n                        CurrentPlotLog().P2Table4Scan = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentTable = 4;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table4rewriteRg.IsMatch(line):\n                        matches = p2table4rewriteRg.Matches(line);\n                        CurrentPlotLog().P2Table4Rewrite = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P2Table4Lost = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 3;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table5scanRg.IsMatch(line):\n                        matches = p2table5scanRg.Matches(line);\n                        CurrentPlotLog().P2Table5Scan = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentTable = 5;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table5rewriteRg.IsMatch(line):\n                        matches = p2table5rewriteRg.Matches(line);\n                        CurrentPlotLog().P2Table5Rewrite = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P2Table5Lost = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 4;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table6scanRg.IsMatch(line):\n                        matches = p2table6scanRg.Matches(line);\n                        CurrentPlotLog().P2Table6Scan = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentTable = 6;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table6rewriteRg.IsMatch(line):\n                        matches = p2table6rewriteRg.Matches(line);\n                        CurrentPlotLog().P2Table6Rewrite = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P2Table6Lost = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 5;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table7scanRg.IsMatch(line):\n                        matches = p2table7scanRg.Matches(line);\n                        CurrentPlotLog().P2Table7Scan = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentTable = 7;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p2table7rewriteRg.IsMatch(line):\n                        matches = p2table7rewriteRg.Matches(line);\n                        CurrentPlotLog().P2Table7Rewrite = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P2Table7Lost = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().CurrentTable = 6;\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n\n\n                    // phase 3\n                    case var _ when p31table2Rg.IsMatch(line):\n                        matches = p31table2Rg.Matches(line);\n                        CurrentPlotLog().P31Table2 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P31Table2Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 3;\n                        break;\n                    case var _ when p31table3Rg.IsMatch(line):\n                        matches = p31table3Rg.Matches(line);\n                        CurrentPlotLog().P31Table3 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P31Table3Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 4;\n                        break;\n                    case var _ when p31table4Rg.IsMatch(line):\n                        matches = p31table4Rg.Matches(line);\n                        CurrentPlotLog().P31Table4 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P31Table4Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 5;\n                        break;\n                    case var _ when p31table5Rg.IsMatch(line):\n                        matches = p31table5Rg.Matches(line);\n                        CurrentPlotLog().P31Table5 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P31Table5Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 6;\n                        break;\n                    case var _ when p31table6Rg.IsMatch(line):\n                        matches = p31table6Rg.Matches(line);\n                        CurrentPlotLog().P31Table6 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P31Table6Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 7;\n                        break;\n                    case var _ when p31table7Rg.IsMatch(line):\n                        matches = p31table7Rg.Matches(line);\n                        CurrentPlotLog().P31Table7 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P31Table7Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 1;\n                        break;\n                    case var _ when p31table2Rg.IsMatch(line):\n                        matches = p31table2Rg.Matches(line);\n                        CurrentPlotLog().P31Table2 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P31Table2Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p32table2Rg.IsMatch(line):\n                        matches = p32table2Rg.Matches(line);\n                        CurrentPlotLog().P32Table2 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P32Table2Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p32table3Rg.IsMatch(line):\n                        matches = p32table3Rg.Matches(line);\n                        CurrentPlotLog().P32Table3 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P32Table3Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p32table4Rg.IsMatch(line):\n                        matches = p32table4Rg.Matches(line);\n                        CurrentPlotLog().P32Table4 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P32Table4Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p32table5Rg.IsMatch(line):\n                        matches = p32table5Rg.Matches(line);\n                        CurrentPlotLog().P32Table5 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P32Table5Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p32table6Rg.IsMatch(line):\n                        matches = p32table6Rg.Matches(line);\n                        CurrentPlotLog().P32Table6 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P32Table6Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        break;\n                    case var _ when p32table7Rg.IsMatch(line):\n                        matches = p32table7Rg.Matches(line);\n                        CurrentPlotLog().P32Table7 = float.Parse(matches[0].Groups[1].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().P32Table7Entries = long.Parse(matches[0].Groups[2].Value);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 1;\n                        break;\n                    case var _ when p4start1Rg.IsMatch(line):\n                        matches = p4start1Rg.Matches(line);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 1;\n                        break;\n                    case var _ when p4finish1Rg.IsMatch(line):\n                        matches = p4finish1Rg.Matches(line);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 2;\n                        break;\n                    case var _ when p4start2Rg.IsMatch(line):\n                        matches = p4start2Rg.Matches(line);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 2;\n                        break;\n                    case var _ when p4finish2Rg.IsMatch(line):\n                        matches = p4finish2Rg.Matches(line);\n                        CurrentPlotLog().NextPhasePart();\n                        CurrentPlotLog().CurrentTable = 1;\n                        break;\n\n                    // errors\n                    case var _ when segFaultRg.IsMatch(line):\n                    case var _ when coreDumpRg.IsMatch(line):\n                    case var _ when catchExceptionRg.IsMatch(line):\n                    case var _ when invalidArgumentRg.IsMatch(line):\n                    case var _ when terminateRg.IsMatch(line):\n                    case var _ when failedRg.IsMatch(line):\n                        CurrentPlotLog().CaughtPlottingError = true;\n                        CurrentPlotLog().Health = new ConfirmedDead(false);\n                        break;\n                }\n                CurrentPlotLog().UpdateProgress();\n            });\n        }\n\n\n        /**\n         * Can be called as often as needed as it does not reparse what was already processed.\n         */\n        public List<CPPlotLog> ParseCPPlotLog()\n        {\n            if (closed)\n                return PlotLogs;\n            lineRead = false;\n            this.TailLineEmitter.ReadMore();\n            CurrentPlotLog().FileLastWritten = File.GetLastWriteTime(this.LogFile);\n            if (CurrentPlotLog().FileLastWritten != null && ((DateTime.Now - (DateTime)CurrentPlotLog().FileLastWritten).TotalDays > 1d))\n                Close();\n            if (lineRead && !firstRead)\n                lastGrown = DateTime.Now;\n            if (lastGrown != null)\n                CurrentPlotLog().FileLastWritten = lastGrown;\n            firstRead = false;\n\n            return PlotLogs;\n        }\n\n\n        private CPPlotLog CurrentPlotLog()\n        {\n            if (PlotLogs.Count == 0)\n                PlotLogs.Add(new());\n            return PlotLogs[PlotLogs.Count - 1];\n        }\n\n        private CPPlotLog NextPlotLog()\n        {\n            var oldPlotLog = CurrentPlotLog();\n            oldPlotLog.IsLastInLogFile = false;\n            var newPlotLog = new CPPlotLog();\n            // when plot create --num n is used parameters stay the same\n            newPlotLog.Buckets = oldPlotLog.Buckets;\n            newPlotLog.Threads = oldPlotLog.Threads;\n            newPlotLog.Buffer = oldPlotLog.Buffer;\n            newPlotLog.Tmp1Drive = oldPlotLog.Tmp1Drive;\n            newPlotLog.Tmp2Drive = oldPlotLog.Tmp2Drive;\n            newPlotLog.DestDrive = oldPlotLog.DestDrive;\n            newPlotLog.LogFile = oldPlotLog.LogFile;\n            newPlotLog.LogFolder = oldPlotLog.LogFolder;\n            newPlotLog.PlaceInLogFile = oldPlotLog.PlaceInLogFile + 1;\n            newPlotLog.QueueSize = oldPlotLog.QueueSize;\n            newPlotLog.StartDate = oldPlotLog.FinishDate;\n            PlotLogs.Add(newPlotLog);\n            return newPlotLog;\n        }\n\n\n        private void Close()\n        {\n            if (closed)\n                return;\n            Debug.WriteLine(\"CPPlotLog \" + LogFile + \" has not been updated for more than a day. Closing file.\");\n            this.TailLineEmitter.Close();\n            closed = true;\n        }\n\n        static Regex copyTimeRG = new Regex(\"Copy to .* finished, took (\\\\d+).?\\\\d* sec,\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex poolPuzzleHashRg = new Regex(\"Pool Puzzle Hash:\\\\s+(.+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex threadsRg = new Regex(\"Number of Threads: (\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex bucketsRg = new Regex(\"Number of Sort Buckets: 2\\\\^\\\\d+ \\\\((\\\\d+)\\\\)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex buckets2Rg = new Regex(\"Number of Buckets P1:\\\\s*2\\\\^\\\\d+ \\\\((\\\\d+)\\\\)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex plotNameRg = new Regex(\"Plot Name: (.*)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex tmp1Rg = new Regex(\"Working Directory:\\\\s+(.*)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex tmp2Rg = new Regex(\"Working Directory 2:\\\\s+(.*)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex destRg = new Regex(\"Final Directory:\\\\s+(.*)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex pidRg = new Regex(\"Process ID:\\\\s+(\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p1table1Rg = new Regex(\"\\\\[P1\\\\] Table 1 took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p1table2Rg = new Regex(\"\\\\[P1\\\\] Table 2 took ([0-9.]+) sec, found (\\\\d+) matches\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p1table3Rg = new Regex(\"\\\\[P1\\\\] Table 3 took ([0-9.]+) sec, found (\\\\d+) matches\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p1table4Rg = new Regex(\"\\\\[P1\\\\] Table 4 took ([0-9.]+) sec, found (\\\\d+) matches\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p1table5Rg = new Regex(\"\\\\[P1\\\\] Table 5 took ([0-9.]+) sec, found (\\\\d+) matches\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p1table6Rg = new Regex(\"\\\\[P1\\\\] Table 6 took ([0-9.]+) sec, found (\\\\d+) matches\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p1table7Rg = new Regex(\"\\\\[P1\\\\] Table 7 took ([0-9.]+) sec, found (\\\\d+) matches\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex lossRg = new Regex(\"\\\\[P1\\\\] Lost (\\\\d+) matches due to 32-bit overflow.\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p1timeRg = new Regex(\"Phase 1 took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2timeRg = new Regex(\"Phase 2 took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p3timeRg = new Regex(\"Phase 3 took ([0-9.]+) sec, wrote (\\\\d+) entries to final plot\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p4timeRg = new Regex(\"Phase 4 took ([0-9.]+) sec, final plot size is (\\\\d+) bytes\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex totaltimeRg = new Regex(\"Total plot creation time was ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2MaxTableSize = new Regex(\"\\\\[P2\\\\] max_table_size = (\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table1scanRg = new Regex(\"\\\\[P2\\\\] Table 1 scan took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table2scanRg = new Regex(\"\\\\[P2\\\\] Table 2 scan took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table3scanRg = new Regex(\"\\\\[P2\\\\] Table 3 scan took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table4scanRg = new Regex(\"\\\\[P2\\\\] Table 4 scan took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table5scanRg = new Regex(\"\\\\[P2\\\\] Table 5 scan took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table6scanRg = new Regex(\"\\\\[P2\\\\] Table 6 scan took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table7scanRg = new Regex(\"\\\\[P2\\\\] Table 7 scan took ([0-9.]+) sec\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table1rewriteRg = new Regex(\"\\\\[P2\\\\] Table 1 rewrite took ([0-9.]+) sec, dropped (\\\\d+) entries \\\\(([0-9.]+) %\\\\)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table2rewriteRg = new Regex(\"\\\\[P2\\\\] Table 2 rewrite took ([0-9.]+) sec, dropped (\\\\d+) entries \\\\(([0-9.]+) %\\\\)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table3rewriteRg = new Regex(\"\\\\[P2\\\\] Table 3 rewrite took ([0-9.]+) sec, dropped (\\\\d+) entries \\\\(([0-9.]+) %\\\\)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table4rewriteRg = new Regex(\"\\\\[P2\\\\] Table 4 rewrite took ([0-9.]+) sec, dropped (\\\\d+) entries \\\\(([0-9.]+) %\\\\)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table5rewriteRg = new Regex(\"\\\\[P2\\\\] Table 5 rewrite took ([0-9.]+) sec, dropped (\\\\d+) entries \\\\(([0-9.]+) %\\\\)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table6rewriteRg = new Regex(\"\\\\[P2\\\\] Table 6 rewrite took ([0-9.]+) sec, dropped (\\\\d+) entries \\\\(([0-9.]+) %\\\\)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p2table7rewriteRg = new Regex(\"\\\\[P2\\\\] Table 7 rewrite took ([0-9.]+) sec, dropped (\\\\d+) entries \\\\(([0-9.]+) %\\\\)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p31table2Rg = new Regex(\"\\\\[P3-1\\\\] Table 2 took ([0-9.]+) sec, wrote (\\\\d+) right entries\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p31table3Rg = new Regex(\"\\\\[P3-1\\\\] Table 3 took ([0-9.]+) sec, wrote (\\\\d+) right entries\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p31table4Rg = new Regex(\"\\\\[P3-1\\\\] Table 4 took ([0-9.]+) sec, wrote (\\\\d+) right entries\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p31table5Rg = new Regex(\"\\\\[P3-1\\\\] Table 5 took ([0-9.]+) sec, wrote (\\\\d+) right entries\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p31table6Rg = new Regex(\"\\\\[P3-1\\\\] Table 6 took ([0-9.]+) sec, wrote (\\\\d+) right entries\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p31table7Rg = new Regex(\"\\\\[P3-1\\\\] Table 7 took ([0-9.]+) sec, wrote (\\\\d+) right entries\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p32table2Rg = new Regex(\"\\\\[P3-2\\\\] Table 2 took ([0-9.]+) sec, wrote (\\\\d+) left entries, (\\\\d+) final\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p32table3Rg = new Regex(\"\\\\[P3-2\\\\] Table 3 took ([0-9.]+) sec, wrote (\\\\d+) left entries, (\\\\d+) final\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p32table4Rg = new Regex(\"\\\\[P3-2\\\\] Table 4 took ([0-9.]+) sec, wrote (\\\\d+) left entries, (\\\\d+) final\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p32table5Rg = new Regex(\"\\\\[P3-2\\\\] Table 5 took ([0-9.]+) sec, wrote (\\\\d+) left entries, (\\\\d+) final\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p32table6Rg = new Regex(\"\\\\[P3-2\\\\] Table 6 took ([0-9.]+) sec, wrote (\\\\d+) left entries, (\\\\d+) final\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p32table7Rg = new Regex(\"\\\\[P3-2\\\\] Table 7 took ([0-9.]+) sec, wrote (\\\\d+) left entries, (\\\\d+) final\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p4start1Rg = new Regex(\"\\\\[P4\\\\] Starting to write C1 and C3 tables\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p4finish1Rg = new Regex(\"\\\\[P4\\\\] Finished to write C1 and C3 tables\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p4start2Rg = new Regex(\"\\\\[P4\\\\] Starting to write C2 tables\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex p4finish2Rg = new Regex(\"\\\\[P4\\\\] Finished to write C2 tables\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n\n        // errors\n        static Regex segFaultRg = new Regex(\"(Segmentation fault|SIGSEGV|segfault)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex coreDumpRg = new Regex(\"(core dumped|coredump)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex catchExceptionRg = new Regex(\"Error\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex invalidArgumentRg = new Regex(\"Invalid\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex terminateRg = new Regex(\"terminat\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        static Regex failedRg = new Regex(\"failed\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Parser/PlotLogFileParser.cs",
    "content": "﻿using ChiaPlotStatusLib.Logic;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n    /**\n     * Parses a log file and generates PlotLogs for each plotting process in the log file\n     * (multiple PlotLogs per file if plot create --num n is used)\n     * Tails the log file if it is still being written. Call Parse() before each access\n     */\n    public class PlotLogFileParser\n    {\n        private TailLineEmitter TailLineEmitter { get; }\n        protected List<PlotLog> PlotLogs { get; } = new List<PlotLog>();\n        public string LogFile;\n        public string LogFolder;\n        public bool firstRead = true;\n        public bool lineRead = true;\n        public bool closed = false;\n        public PlotParserCache cache;\n        public DateTime? lastGrown;\n\n        public PlotLogFileParser(string path, bool closeOnEndOfFile, ref PlotParserCache cache)\n        {\n            this.cache = cache;\n            this.LogFile = path;\n            this.LogFolder = path.Substring(0, path.LastIndexOf(Path.DirectorySeparatorChar));\n            this.TailLineEmitter = new TailLineEmitter(path, closeOnEndOfFile, (line) =>\n            {\n                CurrentPlotLog().IsLastLineTempError = false;\n                CurrentPlotLog().LastLogLine = line.Trim();\n                switch (line)\n                {\n                    case var _ when plotSizeRg.IsMatch(line):\n                        CurrentPlotLog().PlotSize = int.Parse(plotSizeRg.Matches(line)[0].Groups[1].Value);\n                        break;\n                    case var _ when poolPuzzleHashRg.IsMatch(line):\n                        CurrentPlotLog().PoolPuzzleHash = poolPuzzleHashRg.Matches(line)[0].Groups[1].Value;\n                        break;\n                    case var _ when bufferSizeRg.IsMatch(line):\n                        CurrentPlotLog().Buffer = int.Parse(bufferSizeRg.Matches(line)[0].Groups[1].Value);\n                        break;\n                    case var _ when bucketsRg.IsMatch(line):\n                        CurrentPlotLog().Buckets = int.Parse(bucketsRg.Matches(line)[0].Groups[1].Value);\n                        break;\n                    case var _ when currentBucketRg.IsMatch(line):\n                        CurrentPlotLog().CurrentBucket = 1 + int.Parse(currentBucketRg.Matches(line)[0].Groups[1].Value);\n                        break;\n                    case var _ when threadsRg.IsMatch(line):\n                        CurrentPlotLog().Threads = int.Parse(threadsRg.Matches(line)[0].Groups[1].Value);\n                        break;\n                    case var _ when pidRG.IsMatch(line):\n                        CurrentPlotLog().PID = int.Parse(pidRG.Matches(line)[0].Groups[1].Value);\n                        break;\n                    case var _ when startDateRg.IsMatch(line):\n                        var dateTimeStr = startDateRg.Matches(line)[0].Groups[1].Value;\n                        CurrentPlotLog().StartDate = DateTime.ParseExact(dateTimeStr, \"ddd MMM d HH:mm:ss yyyy\", new System.Globalization.CultureInfo(\"en-US\"), DateTimeStyles.AllowWhiteSpaces);\n                        break;\n                    case var _ when plotNameRg.IsMatch(line):\n                        CurrentPlotLog().PlotName = plotNameRg.Matches(line)[0].Groups[1].Value;\n                        break;\n                    case var _ when phase1Rg.IsMatch(line):\n                        CurrentPlotLog().Phase1Seconds = int.Parse(phase1Rg.Matches(line)[0].Groups[1].Value);\n                        CurrentPlotLog().Phase1Cpu = double.Parse(phase1Rg.Matches(line)[0].Groups[2].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentBucket = 0;\n                        break;\n                    case var _ when phase1Table.IsMatch(line):\n                        CurrentPlotLog().Phase1Table = int.Parse(phase1Table.Matches(line)[0].Groups[1].Value);\n                        CurrentPlotLog().CurrentTable = CurrentPlotLog().Phase1Table;\n                        CurrentPlotLog().CurrentPhase = 1;\n                        break;\n                    case var _ when phase2Rg.IsMatch(line):\n                        CurrentPlotLog().Phase2Seconds = int.Parse(phase2Rg.Matches(line)[0].Groups[1].Value);\n                        CurrentPlotLog().Phase2Cpu = double.Parse(phase2Rg.Matches(line)[0].Groups[2].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentBucket = 0;\n                        break;\n                    case var _ when phase2Table.IsMatch(line):\n                        CurrentPlotLog().Phase2Table = int.Parse(phase2Table.Matches(line)[0].Groups[1].Value);\n                        CurrentPlotLog().CurrentTable = CurrentPlotLog().Phase2Table;\n                        CurrentPlotLog().CurrentPhase = 2;\n\n                        break;\n                    case var _ when phase3Rg.IsMatch(line):\n                        CurrentPlotLog().Phase3Seconds = int.Parse(phase3Rg.Matches(line)[0].Groups[1].Value);\n                        CurrentPlotLog().Phase3Cpu = double.Parse(phase3Rg.Matches(line)[0].Groups[2].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentBucket = 0;\n                        CurrentPlotLog().CurrentPhase = 4;\n                        break;\n                    case var _ when phase3Table.IsMatch(line):\n                        CurrentPlotLog().Phase3Table = int.Parse(phase3Table.Matches(line)[0].Groups[1].Value);\n                        CurrentPlotLog().CurrentTable = CurrentPlotLog().Phase3Table;\n                        CurrentPlotLog().CurrentPhase = 3;\n                        break;\n                    case var _ when phase4Rg.IsMatch(line):\n                        CurrentPlotLog().Phase4Seconds = int.Parse(phase4Rg.Matches(line)[0].Groups[1].Value);\n                        CurrentPlotLog().Phase4Cpu = double.Parse(phase4Rg.Matches(line)[0].Groups[2].Value, CultureInfo.InvariantCulture);\n                        CurrentPlotLog().CurrentBucket = 0;\n                        CurrentPlotLog().CurrentPhase = 5;\n                        break;\n                    case var _ when copyTime.IsMatch(line):\n                        CurrentPlotLog().CopyTimeSeconds = int.Parse(copyTime.Matches(line)[0].Groups[1].Value);\n                        break;\n                    case var _ when totalTimeRg.IsMatch(line):\n                        var curPlot = CurrentPlotLog();\n                        curPlot.TotalSeconds = int.Parse(totalTimeRg.Matches(line)[0].Groups[1].Value);\n                        curPlot.CurrentPhase = 6;\n                        if (curPlot.StartDate != null)\n                            curPlot.FinishDate = ((DateTime)curPlot.StartDate).AddSeconds(curPlot.TotalSeconds);\n                        break;\n                    case var _ when approximateWorkingSpace.IsMatch(line):\n                        CurrentPlotLog().ApproximateWorkingSpace = approximateWorkingSpace.Matches(line)[0].Groups[1].Value;\n                        break;\n                    case var _ when destinationDirectory.IsMatch(line):\n                        CurrentPlotLog().DestDrive = destinationDirectory.Matches(line)[0].Groups[1].Value;\n                        break;\n                    case var _ when finalFileSize.IsMatch(line):\n                        CurrentPlotLog().FinalFileSize = finalFileSize.Matches(line)[0].Groups[1].Value;\n                        break;\n                    case var _ when queueSize.IsMatch(line):\n                        CurrentPlotLog().QueueSize = int.Parse(queueSize.Matches(line)[0].Groups[1].Value);\n                        break;\n                    case var _ when writePloblemRg.IsMatch(line):\n                    case var _ when readPloblemRg.IsMatch(line):\n                    case var _ when copyPloblemRg.IsMatch(line):\n                    case var _ when couldNotOpenFile.IsMatch(line):\n                        CurrentPlotLog().IsLastLineTempError = true;\n                        CurrentPlotLog().Errors++;\n                        break;\n                    case var _ when caughtPlottingError.IsMatch(line):\n                        CurrentPlotLog().CaughtPlottingError = true;\n                        break;\n                    case var _ when tmpFolders.IsMatch(line):\n                        var match = tmpFolders.Matches(line)[0];\n                        var plotLog = CurrentPlotLog();\n                        if (plotLog.Tmp1Drive != null) // this is a new plot in the same logfile (--num n used)\n                        {\n                            plotLog = NextPlotLog();\n                        }\n                        plotLog.Tmp1Drive = match.Groups[1].Value;\n                        plotLog.Tmp2Drive = match.Groups[2].Value;\n                        break;\n                    default:\n                        break;\n                }\n                var cPlotLog = CurrentPlotLog();\n                cPlotLog.LogFile = this.LogFile;\n                cPlotLog.LogFolder = this.LogFolder;\n                cPlotLog.UpdateProgress();\n                lineRead = true;\n            });\n        }\n\n        /**\n         * Can be called as often as needed as it does not reparse what was already processed.\n         */\n        public List<PlotLog> ParsePlotLog()\n        {\n            if (closed)\n                return PlotLogs;\n            var fromCache = cache.Get(this);\n            if (fromCache != null)\n            {\n                Debug.WriteLine(\"Plotlog was already in cache. Not reading again.\");\n                firstRead = false;\n                Close();\n                foreach (var plotLog in fromCache)\n                    PlotLogs.Add(plotLog);\n                return PlotLogs;\n            }\n            lineRead = false;\n            this.TailLineEmitter.ReadMore();\n            CurrentPlotLog().FileLastWritten = File.GetLastWriteTime(this.LogFile);\n            if (CurrentPlotLog().FileLastWritten != null && ((DateTime.Now - (DateTime)CurrentPlotLog().FileLastWritten).TotalDays > 1d))\n            {\n                cache.Add(this, PlotLogs);\n                Close();\n            }\n            if (lineRead && !firstRead)\n                lastGrown = DateTime.Now;\n            if (lastGrown != null)\n                CurrentPlotLog().FileLastWritten = lastGrown;\n            firstRead = false;\n\n            return PlotLogs;\n        }\n\n        private void Close()\n        {\n            if (closed)\n                return;\n            Debug.WriteLine(\"PlotLog \" + LogFile + \" has not been updated for more than a day. Closing file.\");\n            this.TailLineEmitter.Close();\n            closed = true;\n        }\n\n        private PlotLog CurrentPlotLog()\n        {\n            if (PlotLogs.Count == 0)\n                PlotLogs.Add(new PlotLog());\n            return PlotLogs[PlotLogs.Count - 1];\n        }\n\n        private PlotLog NextPlotLog()\n        {\n            var oldPlotLog = CurrentPlotLog();\n            oldPlotLog.IsLastInLogFile = false;\n            var newPlotLog = new PlotLog();\n            // when plot create --num n is used parameters stay the same\n            newPlotLog.Buckets = oldPlotLog.Buckets;\n            newPlotLog.Threads = oldPlotLog.Threads;\n            newPlotLog.Buffer = oldPlotLog.Buffer;\n            newPlotLog.Tmp1Drive = oldPlotLog.Tmp1Drive;\n            newPlotLog.Tmp2Drive = oldPlotLog.Tmp2Drive;\n            newPlotLog.DestDrive = oldPlotLog.DestDrive;\n            newPlotLog.LogFile = oldPlotLog.LogFile;\n            newPlotLog.LogFolder = oldPlotLog.LogFolder;\n            newPlotLog.PlaceInLogFile = oldPlotLog.PlaceInLogFile + 1;\n            newPlotLog.QueueSize = oldPlotLog.QueueSize;\n            PlotLogs.Add(newPlotLog);\n            return newPlotLog;\n        }\n\n        // interesting data from logfiles as regex\n        public static Regex poolPuzzleHashRg = new Regex(\"pool contract address:\\\\s+([a-z0-9]+)\\\\s+\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex plotSizeRg = new Regex(\"^Plot size is: (\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex bufferSizeRg = new Regex(\"^Buffer size is: (\\\\d+)MiB\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex bucketsRg = new Regex(\"^Using (\\\\d+) buckets\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex threadsRg = new Regex(\"^Using (\\\\d+) threads of stripe size (\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex pidRG = new Regex(\"^Process ID is: (\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex startDateRg = new Regex(\"^Starting phase 1/4: Forward Propagation into tmp files\\\\.\\\\.\\\\. (.+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex phase1Rg = new Regex(\"^Time for phase 1 = (\\\\d+)\\\\.\\\\d+ seconds. CPU \\\\((\\\\d+\\\\.\\\\d+)%\\\\) \", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex phase2Rg = new Regex(\"^Time for phase 2 = (\\\\d+)\\\\.\\\\d+ seconds. CPU \\\\((\\\\d+\\\\.\\\\d+)%\\\\) \", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex phase3Rg = new Regex(\"^Time for phase 3 = (\\\\d+)\\\\.\\\\d+ seconds. CPU \\\\((\\\\d+\\\\.\\\\d+)%\\\\) \", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex phase4Rg = new Regex(\"^Time for phase 4 = (\\\\d+)\\\\.\\\\d+ seconds. CPU \\\\((\\\\d+\\\\.\\\\d+)%\\\\) \", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex copyTime = new Regex(\"^Copy time = (\\\\d+)\\\\.\\\\d+ seconds\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex totalTimeRg = new Regex(\"^Total time = (\\\\d+)\\\\.\\\\d+ seconds\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex plotNameRg = new Regex(\"^Renamed final file from \\\".+\\\" to (\\\".+\\\")\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex currentBucketRg = new Regex(\"^\\\\tBucket (\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex phase1Table = new Regex(\"^Computing table (\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex phase2Table = new Regex(\"^Backpropagating on table (\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex phase3Table = new Regex(\"^Compressing tables (\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex tmpFolders = new Regex(\"^Starting plotting progress into temporary dirs: (.*) and (.*)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex writePloblemRg = new Regex(\"^Only wrote \\\\d+ of \\\\d+ bytes at\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex couldNotOpenFile = new Regex(\"^Could not open\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex readPloblemRg = new Regex(\"^Only read \\\\d+ of \\\\d+ bytes at\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex copyPloblemRg = new Regex(\"^Could not copy \", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex approximateWorkingSpace = new Regex(\"^Approximate working space used \\\\(without final file\\\\): (\\\\d+\\\\.\\\\d+ .*)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex finalFileSize = new Regex(\"^Final File size: (\\\\d+\\\\.\\\\d+ .*)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex destinationDirectory = new Regex(\"^Final Directory is: (.*)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex caughtPlottingError = new Regex(\"^Caught plotting error: .*\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n        public static Regex queueSize = new Regex(\"Starting plot \\\\d+.(\\\\d+)\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Parser/PlotParserCache.cs",
    "content": "﻿using ChiaPlotStatus;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic\n{\n\n    public class PlotParserCache\n    {\n        public Dictionary<string, List<PlotLog>> CachedPlots { get; set; } = new();\n        private readonly object lockObject = new object();\n        private string path;\n\n\n        public PlotParserCache(string path)\n        {\n            this.path = path;\n            try\n            {\n                Debug.WriteLine(\"Trying to read cache\");\n                if (File.Exists(path))\n                    CachedPlots = JsonSerializer.Deserialize<Dictionary<string, List<PlotLog>>>(File.ReadAllText(path));\n                Debug.WriteLine(\"Loaded \" + CachedPlots.Count + \" entries from cache\");\n            } catch (Exception e)\n            {\n                Debug.WriteLine(\"Could not load PlotParserCache: \" + e);\n            }\n        }\n\n        private string GetKey(PlotLogFileParser parser)\n        {\n            return parser.LogFolder + \" # \" + parser.LogFile;\n        }\n\n        public void Add(PlotLogFileParser parser, List<PlotLog> plotLogs)\n        {\n            lock(lockObject)\n            {\n                CachedPlots[GetKey(parser)] = plotLogs;\n            }\n        }\n\n        public List<PlotLog>? Get(PlotLogFileParser parser)\n        {\n            lock (lockObject)\n            {\n                List<PlotLog> result;\n                if (CachedPlots.TryGetValue(GetKey(parser), out result))\n                    return result;\n                return null;\n            }\n        }\n\n        public void Persist()\n        {\n            lock (lockObject)\n            {\n                try\n                {\n                    Debug.WriteLine(\"Persisting Cache\");\n                    string json = JsonSerializer.Serialize(CachedPlots);\n                    File.WriteAllText(path, json);\n                }\n                catch (Exception e)\n                {\n                    Debug.WriteLine(\"Could not persist PlotParserCache: \" + e);\n                }\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Parser/TailLineEmitter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n    public delegate void TailLineEmitterCallback(string line);\n\n    /**\n     * Opens a given File for read even if it is currently written by a different process and\n     * emits each line to the given TailLineEmitterCallback in correct order. When the end of\n     * the file is reached it pauses until ReadMore() is called again and it tries to continues\n     * reading from the spot it paused at.\n     */\n    public class TailLineEmitter\n    {\n        StreamReader StreamReader { get; set; }\n        TailLineEmitterCallback Callback { get; set; }\n        private string file;\n        private bool closeOnEndOfFile;\n        private bool firstRead = true;\n        private bool initialized = false;\n        private bool closed = false;\n\n        public TailLineEmitter(string file, bool closeOnEndOfFile, TailLineEmitterCallback callback)\n        {\n            this.file = file;\n            this.Callback = callback;\n            this.closeOnEndOfFile = closeOnEndOfFile;\n        }\n\n        ~TailLineEmitter()\n        {\n            Close();\n        }\n\n        public void Close()\n        {\n            if (!closed)\n            {\n                closed = true;\n                if (this.StreamReader != null)\n                    this.StreamReader.Close();\n            }\n        }\n\n        /**\n         * Read and emit each line from last read point on until current end of file is reached\n         */\n        public void ReadMore()\n        {\n            if (!initialized)\n            {\n                var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);\n                var bufferedFs = new BufferedStream(fs, 128 * 1024);\n                this.StreamReader = new StreamReader(bufferedFs);\n                initialized = true;\n            }\n            if (!closeOnEndOfFile ||firstRead)\n            {\n                firstRead = false;\n                try\n                {\n                    string? line = \"\";\n                    do\n                    {\n                        line = this.StreamReader.ReadLine();\n                        if (line != null)\n                        {\n                            this.Callback(line);\n                        }\n                    } while (line != null && !closed);\n                }\n                catch (Exception e)\n                {\n                    Debug.WriteLine(e);\n                }\n                if (closeOnEndOfFile)\n                    Close();\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/CPPlottingStatistics.cs",
    "content": "﻿using ChiaPlotStatusLib.Logic.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n\n    /**\n     * Collects Statistics on plotting processes such as avarage time spend on phases.\n     * Used for ETA.\n     */\n    public class CPPlottingStatistics: PlottingStatistics\n    {\n\n        public CPPlottingStatistics(List<PlotLog> plotLogs): base(plotLogs)\n        {\n            // TODO: implement details like table times\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/Harvest/Harvest.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Statistics.Harvest\n{\n    public class Harvest\n    {\n        public string LogFolder { get; set; }\n        public DateTime DateTime { get; set; }\n        public int ElgiblePlots { get; set; }\n        public int FoundProofs { get; set; }\n        public double LookupTime { get; set; }\n        public double FilterRatio { get; set; }\n        public int TotalPlots { get; set; }\n        public double Heat { get; set; }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/Harvest/HarvestParser.cs",
    "content": "﻿using ChiaPlotStatus;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Statistics.Harvest\n{\n\n    // partially ported from https://github.com/MrPig91/PSChiaPlotter/blob/main/PSChiaPlotter/Public/Get-ChiaHarvesterActivity.ps1\n    public class HarvestParser\n    {\n       // public static string DefaultPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)\n       //              + Path.DirectorySeparatorChar + \".chia\" + Path.DirectorySeparatorChar + \"mainnet\" +\n       ///              Path.DirectorySeparatorChar + \"log\";\n       ///              \n\n        public static List<string> DefaultPaths()\n        {\n            List<string> result = new();\n\n            void add(string blockchain)\n            {\n                result.Add(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)\n                     + Path.DirectorySeparatorChar + \".\" + blockchain + Path.DirectorySeparatorChar + \"mainnet\" +\n                              Path.DirectorySeparatorChar + \"log\");\n            }\n            add(\"chia\");\n            add(\"flax\");\n            add(\"chaingreen\");\n            add(\"seno2\");\n            add(\"chiarose\");\n            add(\"goji-blockchain\");\n            add(\"spare-blockchain\");\n\n            return result;\n        }\n\n        public List<Tuple<string, HarvestSummary, List<Harvest>>?> ParseLogs(List<string> paths, double maxAllowedLookupTime, int nrOfRecentEntries)\n        {\n            ConcurrentBag<Tuple<string, HarvestSummary, List<Harvest>>?> results = new();\n            Parallel.ForEach(paths, (path) => results.Add(ParseLogs(path, maxAllowedLookupTime, nrOfRecentEntries)));\n            return results.ToList();\n        }\n\n        public Tuple<string, HarvestSummary, List<Harvest>>? ParseLogs(string path, double maxAllowedLookupTime, int nrOfRecentEntries)\n        {\n            string[] debugLogFiles = { };\n            if (Directory.Exists(path))\n                debugLogFiles = Directory.GetFiles(path, \"debug.log*\");\n\n            var regex = new Regex(\"([0-9:.\\\\-T]*) harvester .*.harvester.harvester: INFO\\\\s*([0-9]*) \" +\n                 \"plots were eligible for farming ([a-z0-9.]*) Found ([0-9]*) proofs. \" +\n                 \"Time: ([0-9.]*) s. Total ([0-9]*) plots\", RegexOptions.Compiled | RegexOptions.IgnoreCase);\n            ConcurrentBag<Harvest> harvestsBag = new();\n\n            Parallel.ForEach(debugLogFiles, (file) =>\n            {\n                try\n                {\n                    // for now close after each read as I am not sure how wallets / harvesters\n                    // react if they run or get restarted while we keep a shared lock on those files\n                    new TailLineEmitter(file, true, (line) =>\n                    {\n                        if (regex.IsMatch(line))\n                        {\n                            var matches = regex.Matches(line)[0];\n                            var harvest = new Harvest\n                            {\n                                LogFolder = path,\n                                DateTime = DateTime.Parse(matches.Groups[1].Value),\n                                ElgiblePlots = int.Parse(matches.Groups[2].Value, CultureInfo.InvariantCulture),\n                                FoundProofs = int.Parse(matches.Groups[4].Value, CultureInfo.InvariantCulture),\n                                LookupTime = double.Parse(matches.Groups[5].Value, CultureInfo.InvariantCulture),\n                                TotalPlots = int.Parse(matches.Groups[6].Value, CultureInfo.InvariantCulture),\n                                FilterRatio = double.Parse(matches.Groups[2].Value) / int.Parse(matches.Groups[6].Value, CultureInfo.InvariantCulture),\n                                Heat = double.Parse(matches.Groups[5].Value, CultureInfo.InvariantCulture) == 0 ? 0 :\n                                    (double.Parse(matches.Groups[5].Value, CultureInfo.InvariantCulture) / maxAllowedLookupTime),\n                            };\n                            harvestsBag.Add(harvest);\n                        }\n                    }).ReadMore();\n                } catch (Exception e)\n                {\n                    Debug.WriteLine(\"ERROR: parsing harvester log \" + path + \" failed. skipping it\");\n                }\n            });\n\n            List<Harvest> harvests = harvestsBag.ToList();\n            if (harvests.Count == 0)\n            {\n                Debug.WriteLine(\"No harvests found! Set log level at least to info!\");\n                return null;\n            }\n            else if (harvests.Count == 1)\n            {\n                Debug.WriteLine(\"Only found a single harvest! Need at least two!\");\n                return null;\n            }\n            harvests.Sort((a, b) => a.DateTime.CompareTo(b.DateTime));\n            harvests = new(harvests.Skip(Math.Max(0, harvests.Count() - nrOfRecentEntries)));\n            var first = harvests[0];\n            var last = harvests[harvests.Count - 1];\n            var runtimeMinutes = (last.DateTime - first.DateTime).TotalMinutes;\n\n            var summary = new HarvestSummary\n            {\n                LogFolder = path,\n                WorstLookupTime = harvests.Aggregate((a, b) => a.LookupTime > b.LookupTime ? a : b).LookupTime,\n                BestLookupTime = harvests.Aggregate((a, b) => a.LookupTime < b.LookupTime ? a : b).LookupTime,\n                AvgLookupTime = harvests.Average(a => a.LookupTime),\n                AvgEligiblePlots = harvests.Average(a => a.ElgiblePlots),\n                TotalPlots = last.TotalPlots,\n                FoundProofs = (int)harvests.Sum(a => a.FoundProofs),\n                FilterRatio = harvests.Average(a => a.FilterRatio),\n                ChallengesPerMinute = harvests.Count / runtimeMinutes,\n                AvgHeat = harvests.Average(a => a.Heat),\n                MaxHeat = harvests.Aggregate((a, b) => a.LookupTime > b.LookupTime ? a : b).LookupTime,\n                MinHeat = harvests.Aggregate((a, b) => a.LookupTime < b.LookupTime ? a : b).LookupTime,\n                RuntimeMinutes = runtimeMinutes,\n            };\n\n            return new(path, summary, harvests);\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/Harvest/HarvestSummary.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Statistics.Harvest\n{\n    public class HarvestSummary\n    {\n        public string LogFolder { get; set; }\n        public double AvgEligiblePlots { get; set; }\n        public int FoundProofs { get; set; }\n        public double BestLookupTime { get; set; }\n        public double WorstLookupTime { get; set; }\n        public double AvgLookupTime { get; set; }\n        public double FilterRatio { get; set; }\n        public int TotalPlots { get; set; }\n        public double ChallengesPerMinute { get; set; }\n        public double AvgHeat { get; set; }\n        public double MaxHeat { get; set; }\n        public double MinHeat { get; set; }\n        public double RuntimeMinutes { get; set; }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/Harvest/HarvestSummeryReadable.cs",
    "content": "﻿using ChiaPlotStatusLib.Logic.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Statistics.Harvest\n{\n    public class HarvestSummeryReadable\n    {\n        public string LogFolder { get; set; }\n        public string AvgEligiblePlots { get; set; }\n        public int FoundProofs { get; set; }\n        public string BestLookupTime { get; set; }\n        public string WorstLookupTime { get; set; }\n        public string AvgLookupTime { get; set; }\n        public string FilterRatio { get; set; }\n        public int TotalPlots { get; set; }\n        public string ChallengesPerMinute { get; set; }\n        public string AvgHeat { get; set; }\n        public string MaxHeat { get; set; }\n        public string MinHeat { get; set; }\n        public string RuntimeMinutes { get; set; }\n\n        public HarvestSummeryReadable(HarvestSummary summery)\n        {\n            this.LogFolder = summery.LogFolder;\n            this.AvgEligiblePlots = Formatter.formatDouble(summery.AvgEligiblePlots, 5, null);\n            this.FoundProofs = summery.FoundProofs;\n            this.BestLookupTime = Formatter.formatDouble(summery.BestLookupTime, 5, \"s\");\n            this.WorstLookupTime = Formatter.formatDouble(summery.WorstLookupTime, 5, \"s\");\n            this.AvgLookupTime = Formatter.formatDouble(summery.AvgLookupTime, 5, \"s\");\n            this.FilterRatio = Formatter.formatDouble(summery.FilterRatio, 5, null);\n            this.TotalPlots = summery.TotalPlots;\n            this.ChallengesPerMinute = Formatter.formatDouble(summery.ChallengesPerMinute, 5, null);\n            this.AvgHeat = Formatter.formatDouble(summery.AvgHeat, 5, null);\n            this.MaxHeat = Formatter.formatDouble(summery.MaxHeat, 5, null);\n            this.MinHeat = Formatter.formatDouble(summery.MinHeat, 5, null);\n            this.RuntimeMinutes = Formatter.formatDouble(summery.RuntimeMinutes, 2, null);\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/PlottingStatistics.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n\n    /**\n     * Collects Statistics on plotting processes such as avarage time spend on phases.\n     * Used for ETA.\n     */\n    public class PlottingStatistics\n    {\n        private List<PlotLog> plotLogs;\n\n        // in seconds\n        public int Phase1AvgTimeNeed { get; set; }\n        public int Phase1Completed { get; set; }\n        public int Phase2AvgTimeNeed { get; set; }\n        public int Phase2Completed { get; set; }\n        public int Phase3AvgTimeNeed { get; set; }\n        public int Phase3Completed { get; set; }\n        public int Phase4AvgTimeNeed { get; set; }\n        public int Phase4Completed { get; set; }\n        public int CopyTimeAvgTimeNeed { get; set; }\n        public int CopyTimeCompleted { get; set; }\n\n        public PlottingStatistics(List<PlotLog> plotLogs)\n        {\n            this.plotLogs = plotLogs;\n            foreach (var plotLog in plotLogs)\n            {\n                if (plotLog.Phase1Seconds != 0)\n                {\n                    Phase1Completed++;\n                    Phase1AvgTimeNeed += plotLog.Phase1Seconds;\n                }\n                if (plotLog.Phase2Seconds != 0)\n                {\n                    Phase2Completed++;\n                    Phase2AvgTimeNeed += plotLog.Phase2Seconds;\n                }\n                if (plotLog.Phase3Seconds != 0)\n                {\n                    Phase3Completed++;\n                    Phase3AvgTimeNeed += plotLog.Phase3Seconds;\n                }\n                if (plotLog.Phase4Seconds != 0)\n                {\n                    Phase4Completed++;\n                    Phase4AvgTimeNeed += plotLog.Phase4Seconds;\n                }\n                if (plotLog.CopyTimeSeconds != 0)\n                {\n                    CopyTimeCompleted++;\n                    CopyTimeAvgTimeNeed += plotLog.CopyTimeSeconds;\n                }\n            }\n            if (Phase1Completed > 0) Phase1AvgTimeNeed /= Phase1Completed;\n            if (Phase2Completed > 0) Phase2AvgTimeNeed /= Phase2Completed;\n            if (Phase3Completed > 0) Phase3AvgTimeNeed /= Phase3Completed;\n            if (Phase4Completed > 0) Phase4AvgTimeNeed /= Phase4Completed;\n            if (CopyTimeCompleted > 0) CopyTimeAvgTimeNeed /= CopyTimeCompleted;\n        }\n\n        public override bool Equals(object obj)\n        {\n            return obj is PlottingStatistics statistics &&\n                   Phase1AvgTimeNeed == statistics.Phase1AvgTimeNeed &&\n                   Phase1Completed == statistics.Phase1Completed &&\n                   Phase2AvgTimeNeed == statistics.Phase2AvgTimeNeed &&\n                   Phase2Completed == statistics.Phase2Completed &&\n                   Phase3AvgTimeNeed == statistics.Phase3AvgTimeNeed &&\n                   Phase3Completed == statistics.Phase3Completed &&\n                   Phase4AvgTimeNeed == statistics.Phase4AvgTimeNeed &&\n                   Phase4Completed == statistics.Phase4Completed &&\n                   CopyTimeAvgTimeNeed == statistics.CopyTimeAvgTimeNeed &&\n                   CopyTimeCompleted == statistics.CopyTimeCompleted;\n        }\n\n        public override int GetHashCode()\n        {\n            HashCode hash = new HashCode();\n            hash.Add(Phase1AvgTimeNeed);\n            hash.Add(Phase1Completed);\n            hash.Add(Phase2AvgTimeNeed);\n            hash.Add(Phase2Completed);\n            hash.Add(Phase3AvgTimeNeed);\n            hash.Add(Phase3Completed);\n            hash.Add(Phase4AvgTimeNeed);\n            hash.Add(Phase4Completed);\n            hash.Add(CopyTimeAvgTimeNeed);\n            hash.Add(CopyTimeCompleted);\n            return hash.ToHashCode();\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/PlottingStatisticsDay.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n    public class PlottingStatisticsDay\n    {\n        public DateTime Day { get; set; }\n        public int Phase1 { get; set; } = 0;\n        public int Phase2 { get; set; } = 0;\n        public int Phase3 { get; set; } = 0;\n        public int Phase4 { get; set; } = 0;\n        public int Phase5 { get; set; } = 0;\n        public int Finished { get; set; } = 0;\n        public int Died { get; set; } = 0;\n\n        public PlottingStatisticsDay(DateTime day)\n        {\n            this.Day = day;\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/PlottingStatisticsDayReadable.cs",
    "content": "﻿using ChiaPlotStatusLib.Logic.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n    public class PlottingStatisticsDayReadable\n    {\n        public string Day { get; set; }\n        public int Phase1 { get; set; } = 0;\n        public int Phase2 { get; set; } = 0;\n        public int Phase3 { get; set; } = 0;\n        public int Phase4 { get; set; } = 0;\n        public int Phase5 { get; set; } = 0;\n        public int Finished { get; set; } = 0;\n        public int Died { get; set; } = 0;\n\n        public PlottingStatisticsDayReadable(PlottingStatisticsDay psd)\n        {\n            this.Day = Formatter.formatDate(psd.Day);\n            this.Phase1 = psd.Phase1;\n            this.Phase2 = psd.Phase2;\n            this.Phase3 = psd.Phase3;\n            this.Phase4 = psd.Phase4;\n            this.Phase5 = psd.Phase5;\n            this.Finished = psd.Finished;\n            this.Died = psd.Died;\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/PlottingStatisticsFull.cs",
    "content": "﻿using ChiaPlotStatus;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusGUI.GUI.ViewModels\n{\n    public class PlottingStatisticsFull\n    {\n        public string LogFolder { get; set; }\n        public string Tmp1Drive { get; set; }\n        public string Tmp2Drive { get; set; }\n        public int PlotSize { get; set; }\n        public int Threads { get; set; }\n        public int Buffer { get; set; }\n        public int Buckets { get; set; }\n\n        public int Phase1AvgTimeNeed { get; set; }\n        public int Phase1Completed { get; set; }\n        public int Phase2AvgTimeNeed { get; set; }\n        public int Phase2Completed { get; set; }\n        public int Phase3AvgTimeNeed { get; set; }\n        public int Phase3Completed { get; set; }\n        public int Phase4AvgTimeNeed { get; set; }\n        public int Phase4Completed { get; set; }\n        public int CopyTimeAvgTimeNeed { get; set; }\n        public int CopyTimeCompleted { get; set; }\n        public int TotalAvgTimeNeed { get; set; }\n\n        public PlottingStatisticsFull(PlottingStatisticsID id, PlottingStatistics stats)\n        {\n            this.LogFolder = id.LogFolder;\n            this.Tmp1Drive = id.Tmp1Drive;\n            this.Tmp2Drive = id.Tmp2Drive;\n            this.PlotSize = id.PlotSize;\n            this.Threads = id.Threads;\n            this.Buffer = id.Buffer;\n            this.Buckets = id.Buckets;\n            this.Phase1AvgTimeNeed = stats.Phase1AvgTimeNeed;\n            this.Phase1Completed = stats.Phase1Completed;\n            this.Phase2AvgTimeNeed = stats.Phase2AvgTimeNeed;\n            this.Phase2Completed = stats.Phase2Completed;\n            this.Phase3AvgTimeNeed = stats.Phase3AvgTimeNeed;\n            this.Phase3Completed = stats.Phase3Completed;\n            this.Phase4AvgTimeNeed = stats.Phase4AvgTimeNeed;\n            this.Phase4Completed = stats.Phase4Completed;\n            this.CopyTimeAvgTimeNeed = stats.CopyTimeAvgTimeNeed;\n            this.CopyTimeCompleted = stats.CopyTimeCompleted;\n            this.TotalAvgTimeNeed = stats.Phase1AvgTimeNeed + stats.Phase2AvgTimeNeed +\n                stats.Phase3AvgTimeNeed + stats.Phase4AvgTimeNeed + stats.CopyTimeAvgTimeNeed;\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/PlottingStatisticsFullReadable.cs",
    "content": "﻿using ChiaPlotStatus;\nusing ChiaPlotStatusLib.Logic.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusGUI.GUI.ViewModels\n{\n    public class PlottingStatisticsFullReadable\n    {\n        public string LogFolder { get; set; }\n        public string Tmp1Drive { get; set; }\n        public string Tmp2Drive { get; set; }\n        public int PlotSize { get; set; }\n        public int Threads { get; set; }\n        public string Buffer { get; set; }\n        public int Buckets { get; set; }\n\n        public string Phase1AvgTimeNeed { get; set; }\n        public int Phase1Completed { get; set; }\n        public string Phase2AvgTimeNeed { get; set; }\n        public int Phase2Completed { get; set; }\n        public string Phase3AvgTimeNeed { get; set; }\n        public int Phase3Completed { get; set; }\n        public string Phase4AvgTimeNeed { get; set; }\n        public int Phase4Completed { get; set; }\n        public string CopyTimeAvgTimeNeed { get; set; }\n        public int CopyTimeCompleted { get; set; }\n        public string TotalAvgTimeNeed { get; set; }\n\n        public PlottingStatisticsFullReadable(PlottingStatisticsFull stats)\n        {\n            this.LogFolder = stats.LogFolder;\n            this.Tmp1Drive = stats.Tmp1Drive;\n            this.Tmp2Drive = stats.Tmp2Drive;\n            this.PlotSize = stats.PlotSize;\n            this.Threads = stats.Threads;\n            this.Buffer = stats.Buffer + \"MB\";\n            this.Buckets = stats.Buckets;\n            this.Phase1AvgTimeNeed = Formatter.formatSeconds(stats.Phase1AvgTimeNeed, true);\n            this.Phase1Completed = stats.Phase1Completed;\n            this.Phase2AvgTimeNeed = Formatter.formatSeconds(stats.Phase2AvgTimeNeed, true);\n            this.Phase2Completed = stats.Phase2Completed;\n            this.Phase3AvgTimeNeed = Formatter.formatSeconds(stats.Phase3AvgTimeNeed, true);\n            this.Phase3Completed = stats.Phase3Completed;\n            this.Phase4AvgTimeNeed = Formatter.formatSeconds(stats.Phase4AvgTimeNeed, false);\n            this.Phase4Completed = stats.Phase4Completed;\n            this.CopyTimeAvgTimeNeed = Formatter.formatSeconds(stats.CopyTimeAvgTimeNeed, false);\n            this.CopyTimeCompleted = stats.CopyTimeCompleted;\n            this.TotalAvgTimeNeed = Formatter.formatSeconds(stats.TotalAvgTimeNeed, true);\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/PlottingStatisticsHolder.cs",
    "content": "﻿using ChiaPlotStatus.Logic.Models;\nusing ChiaPlotStatusGUI.GUI.ViewModels;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n\n    /**\n     * Collects Statistics on plotting processes and can give you a statistic most\n     * relevant to your PlogLog\n     */\n    public class PlottingStatisticsHolder\n    {\n        private readonly ConcurrentBag<PlotLog> FinishedPlotLogs = new ConcurrentBag<PlotLog>();\n        private readonly PlottingStatisticsIdRelevanceWeights weights;\n        private readonly Dictionary<DateTime, PlottingStatisticsDay> Days = new();\n\n        public PlottingStatisticsHolder(List<PlotLog> plotLogs, PlottingStatisticsIdRelevanceWeights weights, List<MarkOfDeath> markOfDeaths)\n        {\n            this.weights = weights;\n\n            PlottingStatisticsDay GetOrCreatePlottingStatisticsDay(DateTime? dateTime)\n            {\n                if (dateTime == null)\n                    // silently give them an instance that gets thrown away\n                    return new PlottingStatisticsDay(DateTime.Now.Date);\n                DateTime day = ((DateTime)dateTime).Date;\n                if (!Days.ContainsKey(day))\n                    Days.Add(day, new PlottingStatisticsDay(day));\n                return Days[day];\n            }\n\n            foreach (var plotLog in plotLogs)\n            {\n                GetOrCreatePlottingStatisticsDay(plotLog.StartDate).Phase1++;\n                GetOrCreatePlottingStatisticsDay(plotLog.FinishDate).Finished++;\n                // max reached moment the process was likely still running. Not very precise when --num is used.\n                // could use currentTable + currentBucket and ETA-like Calculation to improve estimate in that case.\n                // Should be a noticable improvement on HDDs\n                DateTime? max = plotLog.StartDate;\n                if (plotLog.Phase1Seconds != 0)\n                {\n                    var phase2 = plotLog.StartDate.Value.AddSeconds(plotLog.Phase1Seconds);\n                    max = phase2;\n                    GetOrCreatePlottingStatisticsDay(phase2).Phase2++;\n                    if (plotLog.Phase2Seconds != 0)\n                    {\n                        var phase3 = phase2.AddSeconds(plotLog.Phase2Seconds);\n                        max = phase3;\n                        GetOrCreatePlottingStatisticsDay(phase3).Phase3++;\n                        if (plotLog.Phase3Seconds != 0)\n                        {\n                            var phase4 = phase3.AddSeconds(plotLog.Phase3Seconds);\n                            max = phase4;\n                            GetOrCreatePlottingStatisticsDay(phase4).Phase4++;\n                            if (plotLog.Phase4Seconds != 0)\n                            {\n                                var phase5 = phase4.AddSeconds(plotLog.Phase4Seconds);\n                                max = phase5;\n                                GetOrCreatePlottingStatisticsDay(phase5).Phase5++;\n                            }\n                        }\n                    }\n                }\n\n                foreach (var mark in markOfDeaths)\n                {\n                    if (mark.IsMatch(plotLog) && mark.DiedAt != null)\n                    {\n                        max = mark.DiedAt.Value;\n                        break;\n                    }\n                }\n                if (plotLog.Health is ConfirmedDead)\n                {\n                    // if --num is not used then lastModifiedAt property on the log file should be very\n                    // near our time of death.\n                    // if --num is used we can only assume the above if this was the last plot in queue\n                    // plotLog.PlaceInLogFile == plotLog.QueueSize catches both cases\n                    if (plotLog.PlaceInLogFile == plotLog.QueueSize)\n                    {\n                        max = File.GetLastWriteTime(plotLog.LogFile);\n                    }\n                    GetOrCreatePlottingStatisticsDay(max).Died++;\n                }\n\n                if (plotLog.TotalSeconds > 0)\n                    FinishedPlotLogs.Add(plotLog);\n            }\n        }\n\n        public PlottingStatistics GetMostRelevantStatistics(PlotLog plotLog)\n        {\n            PlottingStatisticsID id = new PlottingStatisticsID(plotLog);\n            return GetMostRelevantStatistics(id);\n        }\n\n        public PlottingStatistics GetMostRelevantStatistics(PlottingStatisticsID id)\n        {\n            Dictionary<int, List<PlotLog>> byRelevance = new Dictionary<int, List<PlotLog>>();\n            foreach (var fromAll in FinishedPlotLogs)\n            {\n                int relevance = id.CalcRelevance(new PlottingStatisticsID(fromAll), weights);\n                // Debug.WriteLine(relevance);\n                if (!byRelevance.ContainsKey(relevance))\n                    byRelevance.Add(relevance, new List<PlotLog>());\n                byRelevance[relevance].Add(fromAll);\n            }\n\n            int highestRelevance = -1;\n            foreach (var relevance in byRelevance.Keys)\n                if (relevance > highestRelevance)\n                    highestRelevance = relevance;\n\n            if (highestRelevance > -1)\n            {\n                List<PlotLog> plotLogs = byRelevance[highestRelevance];\n                if (id.UsedPlotter == \"chia-plotter\")\n                    return new CPPlottingStatistics(plotLogs.ToList());\n                else\n                    return new PlottingStatistics(plotLogs.ToList());\n            }\n            if (FinishedPlotLogs.Count > 0)\n                if (id.UsedPlotter == \"chia-plotter\")\n                    return new CPPlottingStatistics(FinishedPlotLogs.ToList());\n                else\n                    return new PlottingStatistics(FinishedPlotLogs.ToList());\n            else\n                return MagicNumbers(id.UsedPlotter);\n        }\n\n        /**\n         * An average over some plotlogs I had on my drive.\n         * This way we can display ETA and Time Remaining even\n         * when the user does not have finished plotlogs (will\n         * be imprecise tho).\n         * That way we get better warning and error thresholds\n         * from the beginning too, as they were diced before.\n         * See Issue #23\n         */\n        private PlottingStatistics MagicNumbers(string usedPlotter)\n        {\n            List<PlotLog> plotLogs = new List<PlotLog>();\n            var magicPlotLog = new PlotLog();\n            if (usedPlotter == \"chiapos\")\n            {\n                magicPlotLog.Phase1Seconds = 31573;\n                magicPlotLog.Phase2Seconds = 12298;\n                magicPlotLog.Phase3Seconds = 34925;\n                magicPlotLog.Phase4Seconds = 3024;\n                magicPlotLog.CopyTimeSeconds = 934;\n            }\n            else\n            {\n                // from chia-plotter readme times 3 as most people will use ssds and not ramdisk\n                magicPlotLog.Phase1Seconds = 1143 * 3;\n                magicPlotLog.Phase2Seconds = 635 * 3;\n                magicPlotLog.Phase3Seconds = 946 * 3;\n                magicPlotLog.Phase4Seconds = 80 * 3;\n                magicPlotLog.CopyTimeSeconds = 2804 * 3;\n            }\n            plotLogs.Add(magicPlotLog);\n            return new PlottingStatistics(plotLogs);\n        }\n\n        public List<(PlottingStatisticsFull, PlottingStatisticsFullReadable)> AllStatistics()\n        {\n            Dictionary<PlottingStatisticsID, PlottingStatistics> statsDict = new();\n            foreach (var plotLog in FinishedPlotLogs)\n            {\n                var id = new PlottingStatisticsID(plotLog);\n                if (!statsDict.ContainsKey(id))\n                    statsDict.Add(id, this.GetMostRelevantStatistics(plotLog));\n            }\n            List<(PlottingStatisticsFull, PlottingStatisticsFullReadable)> statsFull = new();\n            foreach (var entry in statsDict) {\n                var stat = new PlottingStatisticsFull(entry.Key, entry.Value);\n                statsFull.Add((stat, new PlottingStatisticsFullReadable(stat)));\n            }\n            return statsFull;\n        }\n\n        public Dictionary<DateTime, PlottingStatisticsDay> GetDailyStats()\n        {\n            return new(Days);\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/PlottingStatisticsID.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n\n    /**\n     * Key used to determine best matches / relevance on finished plotting processes for a given PlotLog\n     * Relevance is calculated by summing up weigths assigned to the Properties that are equal between\n     * PlotLogs represented by this PlottingStatisticsID\n     */\n    public class PlottingStatisticsID\n    {\n        public string UsedPlotter { get; set; }\n        public string LogFolder { get; set; }\n        public string Tmp1Drive { get; set; }\n        public string Tmp2Drive { get; set; }\n        public int PlotSize { get; set; }\n        public int Threads { get; set; }\n        public int Buffer { get; set; }\n        public int Buckets { get; set; }\n\n        public PlottingStatisticsID(PlotLog plotLog)\n        {\n            UsedPlotter = plotLog.UsedPlotter;\n            LogFolder = plotLog.LogFolder;\n            Tmp1Drive = plotLog.Tmp1Drive;\n            Tmp2Drive = plotLog.Tmp2Drive;\n            PlotSize = plotLog.PlotSize;\n            Threads = plotLog.Threads;\n            Buffer = plotLog.Buffer;\n            Tmp2Drive = plotLog.Tmp2Drive;\n            Buckets = plotLog.Buckets;\n        }\n\n        public int CalcRelevance(PlottingStatisticsID other, PlottingStatisticsIdRelevanceWeights weights)\n        {\n            var relevance = 0;\n            relevance += UsedPlotterRelevance(other) * (weights.TmpDir + weights.ComputeConfiguration) * 10;\n            relevance += PlotSizeRelevance(other) * weights.PlotSize;\n            relevance += LogFolderRelevance(other) * weights.LogFolder;\n            relevance += TmpDirRelevance(other) * weights.TmpDir;\n            relevance += ComputeConfiguration(other) * weights.ComputeConfiguration;\n            return relevance;\n        }\n\n        private int UsedPlotterRelevance(PlottingStatisticsID other)\n        {\n            if (this.UsedPlotter == other.UsedPlotter)\n                return 1;\n            return 0;\n        }\n\n        private int PlotSizeRelevance(PlottingStatisticsID other)\n        {\n            if (this.PlotSize == other.PlotSize)\n                return 1;\n            return 0;\n        }\n\n        private int LogFolderRelevance(PlottingStatisticsID other)\n        {\n            if (string.Equals(this.LogFolder, other.LogFolder))\n                return 1;\n            return 0;\n        }\n\n        private int TmpDirRelevance(PlottingStatisticsID other)\n        {\n            bool tmp1Equal = string.Equals(this.Tmp1Drive, other.Tmp1Drive);\n            bool tmp2Equal = string.Equals(this.Tmp2Drive, other.Tmp2Drive);\n            if (tmp1Equal && tmp2Equal)\n                return 2;\n            if (!tmp1Equal && !tmp2Equal)\n                return 0;\n            return 1;\n        }\n\n        private int ComputeConfiguration(PlottingStatisticsID other)\n        {\n            int relevance = 0;\n            if (this.Threads == other.Threads) relevance++;\n            if (this.Buckets == other.Buckets) relevance++;\n            if (this.Buffer == other.Buffer) relevance++;\n            return relevance;\n        }\n\n        public override bool Equals(object obj)\n        {\n            return obj is PlottingStatisticsID iD &&\n                   LogFolder == iD.LogFolder &&\n                   Tmp1Drive == iD.Tmp1Drive &&\n                   Tmp2Drive == iD.Tmp2Drive &&\n                   PlotSize == iD.PlotSize &&\n                   Threads == iD.Threads &&\n                   Buffer == iD.Buffer &&\n                   Buckets == iD.Buckets;\n        }\n\n        public override int GetHashCode()\n        {\n            return HashCode.Combine(LogFolder, Tmp1Drive, Tmp2Drive, PlotSize, Threads, Buffer, Buckets);\n        }\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Statistics/PlottingStatisticsIdRelevanceWeights.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus\n{\n    /**\n     * When trying to find the best matched finished PlotLogs for a given\n     * PlotLog this is used to define relevance.\n     */\n    public class PlottingStatisticsIdRelevanceWeights\n    {\n        /**\n         * k32, k33, k34...\n         */\n        public int PlotSize { get; set; } = 10000;\n\n        /**\n         * from which folder the PlogLogs originate\n         */\n        public int LogFolder { get; set; } = 1000;\n\n        /**\n         * Partially or exact match on tmp1 and tmp2 dirs\n         */\n        public int TmpDir { get; set; } = 200;\n\n        /**\n         * Similarity on Threads, Buffer, Buckets\n         */\n        public int ComputeConfiguration { get; set; } = 100;\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Utils/Exporter.cs",
    "content": "﻿using CsvHelper;\nusing System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.Json;\nusing System.Threading.Tasks;\nusing YamlDotNet.Serialization;\n\nnamespace ChiaPlotStatus.Logic.Utils\n{\n    public class Exporter\n    {\n        private List<(PlotLog, PlotLogReadable)> plotLogTuples = new();\n        private List<PlotLog> plotLogs = new();\n        private List<PlotLogReadable> plotLogReadables = new();\n\n        public Exporter(IEnumerable<(PlotLog, PlotLogReadable)> plotLogs)\n        {\n            foreach (var tuple in plotLogs)\n            {\n                this.plotLogTuples.Add(tuple);\n                this.plotLogs.Add(tuple.Item1);\n                this.plotLogReadables.Add(tuple.Item2);\n            }\n        }\n\n        public void ToJson(string file, bool raw)\n        {\n            JsonSerializerOptions options = new JsonSerializerOptions();\n            options.WriteIndented = true;\n            string? json = null;\n            try {\n                if (raw)\n                    json = JsonSerializer.Serialize(this.plotLogs, options);\n                else\n                    json = JsonSerializer.Serialize(this.plotLogReadables, options);\n                File.WriteAllText(file, json);\n            } catch (Exception e)\n            {\n                Debug.WriteLine(e);\n            }\n        }\n\n        public void ToYaml(string file, bool raw)\n        {\n            var serializer = new SerializerBuilder().Build();\n            string? yaml = null;\n            if (raw)\n                yaml = serializer.Serialize(this.plotLogs);\n            else\n                yaml = serializer.Serialize(this.plotLogReadables);\n            File.WriteAllText(file, yaml);\n        }\n\n        public void ToCsv(string file, bool raw)\n        {\n            using (var writer = new StreamWriter(file))\n            using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))\n            if (raw)\n                csv.WriteRecords(this.plotLogs);\n            else\n                csv.WriteRecords(this.plotLogReadables);\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Utils/Formatter.cs",
    "content": "﻿using ChiaPlotStatus.Logic.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatusLib.Logic.Utils\n{\n    public class Formatter\n    {\n\n        public static string formatCpuUsage(double usage)\n        {\n            if (usage < 0.01d)\n                return \"\";\n            else\n                return usage.ToString(\"0.0 '%'\");\n        }\n\n        public static string formatSeconds(int seconds, bool hideSeconds)\n        {\n            var secondsPart = \"\\\\ ss\\\\s\";\n            if (hideSeconds)\n                secondsPart = \"\";\n\n            if (seconds == 0)\n                return \"\";\n            else if (seconds > 24 * 60 * 60)\n                return TimeSpan.FromSeconds(seconds).ToString(@\"dd\\d\\ hh\\h\\ mm\\m\" + secondsPart);\n            else if (seconds > 60 * 60)\n                return TimeSpan.FromSeconds(seconds).ToString(@\"hh\\h\\ mm\\m\" + secondsPart);\n            else if (seconds > 60)\n                return TimeSpan.FromSeconds(seconds).ToString(@\"mm\\m\" + secondsPart);\n            else\n                return TimeSpan.FromSeconds(seconds).ToString(@\"ss\\s\");\n        }\n\n        public static string formatDouble(double value, int decimalPlaces, string? suffix)\n        {\n            var format = \"0\";\n            if (decimalPlaces > 0)\n                format += \".\";\n            for (int i = 0; i < decimalPlaces; i++) format += \"0\";\n            var val = value.ToString(format, CultureInfo.CurrentCulture);\n            if (suffix == null)\n                return val;\n            else return val + suffix;\n        }\n\n        public static string formatDateTime(DateTime? dateTime)\n        {\n            if (dateTime == null)\n                return \"\";\n            else {\n                CultureInfo culture = CultureInfo.CurrentCulture;\n                // forced to cast it to a non nullable or it does not find ToString(format)\n                return ((DateTime)dateTime).ToString(\"m\", culture) + \" \" + ((DateTime)dateTime).ToString(\"t\", culture);\n            }\n        }\n\n        public static string formatDate(DateTime? dateTime)\n        {\n            if (dateTime == null)\n                return \"\";\n            else\n            {\n                CultureInfo culture = CultureInfo.CurrentCulture;\n                // forced to cast it to a non nullable or it does not find ToString(format)\n                return ((DateTime)dateTime).ToString(\"m\", culture);\n            }\n        }\n\n        public static string formatHealth(HealthIndicator health)\n        {\n            switch (health)\n            {\n                case Healthy:\n                    return \"✓\";\n                case TempError:\n                    return \"⚠ Temp Errors\";\n                case Concerning c:\n                    return \"⚠ Slow \" + c.Minutes + \" / \" + c.ExpectedMinutes + \"m\";\n                case PossiblyDead p:\n                    return \"⚠ Dead? \" + p.Minutes + \" / \" + p.ExpectedMinutes + \"m\";\n                case ConfirmedDead c:\n                    return \"✗ Dead\" + (c.Manual ? \" (m)\" : \"\");\n                default:\n                    throw new NotImplementedException(\"formatHealth (HealthIndicator \" + health + \")\");\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Utils/SearchFilter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.Logic.Utils\n{\n    public static class SearchFilter\n    {\n\n        /**\n         * Splits searchString into keywords and each keyword must be contained in at least one\n         * property of an item for the item to be included in the return list.\n         * Uses Reflection, which is more than fast enough for our usecase.\n         */\n        public static List<T> Search<T>(string? searchString, List<T> items)\n        {\n            if (items.Count == 0 || string.IsNullOrEmpty(searchString))\n            {\n                return items;\n            }\n\n            List<T> result = new();\n            string[] keywords = searchString.ToLower().Split(\" \");\n            PropertyInfo[] properties = typeof(T).GetProperties();\n            foreach (var item in items)\n            {\n                bool match = true;\n                foreach (var keyword in keywords)\n                {\n                    bool keywordMatch = false;\n                    foreach (PropertyInfo property in properties)\n                    {\n                        object? value = property.GetValue(item);\n                        if (value != null)\n                        {\n                            string? valueStr = value.ToString().ToLower();\n                            if (!string.IsNullOrEmpty(valueStr) && valueStr.Contains(keyword))\n                            {\n                                keywordMatch = true;\n                                break;\n                            }\n                        }\n                    }\n                    if (!keywordMatch)\n                    {\n                        match = false;\n                        break;\n                    }\n                }\n                if (match)\n                    result.Add(item);\n            }\n            return result;\n        }\n\n\n        public static List<(A, B)> Search<A, B>(string? searchString, List<(A, B)> items)\n        {\n            if (items.Count == 0 || string.IsNullOrEmpty(searchString))\n            {\n                return items;\n            }\n            List<A> itemsA = new();\n            List<B> itemsB = new();\n            foreach (var item in items)\n            {\n                itemsA.Add(item.Item1);\n                itemsB.Add(item.Item2);\n            }\n            itemsA = Search(searchString, itemsA);\n            itemsB = Search(searchString, itemsB);\n            List<(A, B)> result = new();\n            foreach (var item in items)\n                if (itemsA.Contains(item.Item1) || itemsB.Contains(item.Item2))\n                    result.Add(item);\n            return result;\n        }\n\n    }\n}\n"
  },
  {
    "path": "ChiaPlotStatusLib/Logic/Utils/Sorter.cs",
    "content": "﻿using ChiaPlotStatus.Logic.Models;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Threading.Tasks;\n\nnamespace ChiaPlotStatus.Logic.Utils\n{\n    public static class Sorter\n    {\n\n        public static void Sort<A, B>(string propertyName, bool sortAsc, List<(A, B)> items)\n        {\n            PropertyInfo[] propertiesA = typeof(A).GetProperties();\n            PropertyInfo[] propertiesB = typeof(B).GetProperties();\n            PropertyInfo? propertyA = null;\n            PropertyInfo? propertyB = null;\n            foreach (var prop in propertiesA)\n                if (string.Equals(propertyName, prop.Name))\n                    propertyA = prop;\n            foreach (var prop in propertiesB)\n                if (string.Equals(propertyName, prop.Name))\n                    propertyB = prop;\n\n            PropertyInfo? property = propertyA;\n            bool sortOverLeftTupleItem = true;\n            if (property == null)\n            {\n                property = propertyB;\n                sortOverLeftTupleItem = false;\n            }\n            items.Sort((a, b) =>\n            {\n                int sortIndex = 0;\n                object? valueA = null;\n                object? valueB = null;\n                if (sortOverLeftTupleItem)\n                {\n                    // property not found, sort by first property on A whatever it is\n                    if (property == null)\n                        property = propertiesA[0];\n                    valueA = property.GetValue(a.Item1);\n                    valueB = property.GetValue(b.Item1);\n                }\n                else\n                {\n                    // property not found, sort by first property on A whatever it is\n                    if (property == null)\n                        property = propertiesB[0];\n                    valueA = property.GetValue(a.Item2);\n                    valueB = property.GetValue(b.Item2);\n                }\n                string valueAStr = \"\";\n                string valueBStr = \"\";\n                TypeCode typeCode = Type.GetTypeCode(property.PropertyType);\n                switch (typeCode)\n                {\n                    case TypeCode.Int32:\n                        sortIndex = compare((int?)valueA, (int?)valueB);\n                        break;\n                    case TypeCode.Single:\n                        sortIndex = compare((Single?)valueA, (Single?)valueB);\n                        break;\n                    case TypeCode.Double:\n                        sortIndex = compare((Double?)valueA, (Double?)valueB);\n                        break;\n                    case TypeCode.Decimal:\n                        sortIndex = compare((Decimal?)valueA, (Decimal?)valueB);\n                        break;\n                    case TypeCode.DateTime:\n                    case TypeCode.Object:\n                        if (valueA is HealthIndicator)\n                            sortIndex = ((HealthIndicator)valueA).SortIndex.CompareTo(((HealthIndicator)valueB).SortIndex);\n                        else\n                            sortIndex = compare((DateTime?)valueA, (DateTime?)valueB);\n                        break;\n                    case TypeCode.String:\n                        valueAStr = \"\";\n                        valueBStr = \"\";\n                        if (valueA != null)\n                            valueAStr = valueA.ToString().ToLower();\n                        if (valueB != null)\n                            valueBStr = valueB.ToString().ToLower();\n                        sortIndex = string.Compare(valueAStr, valueBStr);\n                        break;\n                    default:\n                        Debug.WriteLine(\"TypeCode \" + typeCode);\n                        break;\n                }\n\n                // keep empty values on the bottom of the table\n                if (propertyB != null)\n                {\n                    // we sort over plotLog first but might hide useless information in plotLogReadable\n                    // the sorting does not see this values as empty as it looks into plotLogs first since\n                    // the data there is more easily sortable\n                    // but on the table we stil see empty values on top of the table as they are hidden.\n                    // That is why we sort on propertyB (plotLogReadable/item2) here\n                    var valueAPropB = propertyB.GetValue(a.Item2);\n                    var valueBPropB = propertyB.GetValue(b.Item2);\n                    var valueAProbANullOrEmpty = valueA == null || string.IsNullOrEmpty(\"\" + valueA);\n                    var valueBProbANullOrEmpty = valueB == null || string.IsNullOrEmpty(\"\" + valueB);\n                    var valueAProbBNullOrEmpty = valueAPropB == null || string.IsNullOrEmpty(\"\" + valueAPropB);\n                    var valueBProbBNullOrEmpty = valueBPropB == null || string.IsNullOrEmpty(\"\" + valueBPropB);\n\n                    if ((!valueAProbANullOrEmpty && valueAProbBNullOrEmpty) || (!valueBProbANullOrEmpty && valueBProbBNullOrEmpty))\n                    {\n                        // this is to sort by propb when values are null in plotlogreadable but not in plotlog\n                        if (valueAProbBNullOrEmpty && !valueBProbBNullOrEmpty)\n                        {\n                            if (sortAsc)\n                                sortIndex = 1;\n                            else\n                                sortIndex = -1;\n                        }\n                        if (!valueAProbBNullOrEmpty && valueBProbBNullOrEmpty)\n                        {\n                            if (sortAsc)\n                                sortIndex = -1;\n                            else\n                                sortIndex = 1;\n                        }\n                    }\n                    else\n                    {\n                        // this is to sort by propa when values are null in plotlog\n                        if (valueAProbANullOrEmpty && !valueBProbANullOrEmpty)\n                        {\n                            if (sortAsc)\n                                sortIndex = 1;\n                            else\n                                sortIndex = -1;\n                        }\n                        if (!valueAProbANullOrEmpty && valueBProbANullOrEmpty)\n                        {\n                            if (sortAsc)\n                                sortIndex = -1;\n                            else\n                                sortIndex = 1;\n                        }\n                    }\n                }\n\n\n                // stabilize sorting so a refresh or sort does not put plot logs with equal values at random\n                // positions causing visual \"jumping\" of table entries.\n                // this way sorting stays consistent on equal values across the runtime of the program\n                if (sortIndex == 0)\n                {\n                    sortIndex = a.Item1.GetHashCode().CompareTo(b.Item1.GetHashCode());\n                }\n\n\n                if (!sortAsc)\n                {\n                    sortIndex *= -1;\n                }\n                return sortIndex;\n            });\n        }\n\n        private static int compare(Single? a, Single? b)\n        {\n            if (a == null && b != null)\n                return +1;\n            if (a != null && b == null)\n                return -1;\n            if (a == null && b == null)\n                return 0;\n            if (a > b)\n                return +1;\n            if (a < b)\n                return -1;\n            return 0;\n        }\n\n        private static int compare(Double? a, Double? b)\n        {\n            if (a == null && b != null)\n                return +1;\n            if (a != null && b == null)\n                return -1;\n            if (a == null && b == null)\n                return 0;\n            if (a > b)\n                return +1;\n            if (a < b)\n                return -1;\n            return 0;\n        }\n\n        private static int compare(Decimal? a, Decimal? b)\n        {\n            if (a == null && b != null)\n                return +1;\n            if (a != null && b == null)\n                return -1;\n            if (a == null && b == null)\n                return 0;\n            if (a > b)\n                return +1;\n            if (a < b)\n                return -1;\n            return 0;\n        }\n\n        private static int compare(int? a, int? b)\n        {\n            if (a == null && b != null)\n                return +1;\n            if (a != null && b == null)\n                return -1;\n            if (a == null && b == null)\n                return 0;\n            if (a > b)\n                return +1;\n            if (a < b)\n                return -1;\n            return 0;\n        }\n\n        private static int compare(DateTime? a, DateTime? b)\n        {\n            if (a == null && b != null)\n                return +1;\n            if (a != null && b == null)\n                return -1;\n            if (a == null && b == null)\n                return 0;\n            if (a > b)\n                return +1;\n            if (a < b)\n                return -1;\n            return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "Directory.Build.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <PackageReference Include=\"Packaging.Targets\">\n      <Version>0.1.189-*</Version>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 grayfallstown\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Logo/Icon - Readme.txt",
    "content": "Image downloaded from https://freeicons.io/plant-icon-set/leaf-leaves-green-fall-spring-nature-tree-icon-41188\nArtist Charlie https://www.tanhuiyingdesign.com/ https://freeicons.io/profile/740\nLicense Creative Commons(Attribution 3.0 unported)\nColor was changed\n"
  },
  {
    "path": "NuGet.Config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <add key=\"nuget.org\" value=\"https://api.nuget.org/v3/index.json\" protocolVersion=\"3\" />\n  </packageSources>\n</configuration>"
  },
  {
    "path": "Properties/PublishProfiles/FolderProfile.pubxml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nhttps://go.microsoft.com/fwlink/?LinkID=208121. \n-->\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <Platform>Any CPU</Platform>\n    <PublishDir>bin\\Release\\net5.0\\publish\\</PublishDir>\n    <PublishProtocol>FileSystem</PublishProtocol>\n    <TargetFramework>net5.0</TargetFramework>\n    <RuntimeIdentifier>win-x86</RuntimeIdentifier>\n    <SelfContained>true</SelfContained>\n    <PublishSingleFile>False</PublishSingleFile>\n    <PublishReadyToRun>False</PublishReadyToRun>\n    <PublishTrimmed>False</PublishTrimmed>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Properties/PublishProfiles/FolderProfile.pubxml.user",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nhttps://go.microsoft.com/fwlink/?LinkID=208121. \n-->\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <History>True|2021-05-02T17:58:29.8523802Z;True|2021-05-02T19:49:14.6691365+02:00;</History>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "Properties/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     Dieser Code wurde von einem Tool generiert.\n//     Laufzeitversion:4.0.30319.42000\n//\n//     Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn\n//     der Code erneut generiert wird.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace ChiaPlotStatus.Properties {\n    using System;\n    \n    \n    /// <summary>\n    ///   Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.\n    /// </summary>\n    // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert\n    // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.\n    // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen\n    // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"16.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"ChiaPlotStatus.Properties.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle\n        ///   Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Properties/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n\t<!-- \n\t\tMicrosoft ResX Schema\n\n\t\tVersion 1.3\n\n\t\tThe primary goals of this format is to allow a simple XML format \n\t\tthat is mostly human readable. The generation and parsing of the \n\t\tvarious data types are done through the TypeConverter classes \n\t\tassociated with the data types.\n\n\t\tExample:\n\n\t\t... ado.net/XML headers & schema ...\n\t\t<resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n\t\t<resheader name=\"version\">1.3</resheader>\n\t\t<resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n\t\t<resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n\t\t<data name=\"Name1\">this is my long string</data>\n\t\t<data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n\t\t<data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n\t\t\t[base64 mime encoded serialized .NET Framework object]\n\t\t</data>\n\t\t<data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n\t\t\t[base64 mime encoded string representing a byte array form of the .NET Framework object]\n\t\t</data>\n\n\t\tThere are any number of \"resheader\" rows that contain simple \n\t\tname/value pairs.\n\n\t\tEach data row contains a name, and value. The row also contains a \n\t\ttype or mimetype. Type corresponds to a .NET class that support \n\t\ttext/value conversion through the TypeConverter architecture. \n\t\tClasses that don't support this are serialized and stored with the \n\t\tmimetype set.\n\n\t\tThe mimetype is used for serialized objects, and tells the \n\t\tResXResourceReader how to depersist the object. This is currently not \n\t\textensible. For a given mimetype the value must be set accordingly:\n\n\t\tNote - application/x-microsoft.net.object.binary.base64 is the format \n\t\tthat the ResXResourceWriter will generate, however the reader can \n\t\tread any of the formats listed below.\n\n\t\tmimetype: application/x-microsoft.net.object.binary.base64\n\t\tvalue   : The object must be serialized with \n\t\t\t: System.Serialization.Formatters.Binary.BinaryFormatter\n\t\t\t: and then encoded with base64 encoding.\n\n\t\tmimetype: application/x-microsoft.net.object.soap.base64\n\t\tvalue   : The object must be serialized with \n\t\t\t: System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n\t\t\t: and then encoded with base64 encoding.\n\n\t\tmimetype: application/x-microsoft.net.object.bytearray.base64\n\t\tvalue   : The object must be serialized into a byte array \n\t\t\t: using a System.ComponentModel.TypeConverter\n\t\t\t: and then encoded with base64 encoding.\n\t-->\n\t\n\t<xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n\t\t<xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n\t\t\t<xsd:complexType>\n\t\t\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t\t\t<xsd:element name=\"data\">\n\t\t\t\t\t\t<xsd:complexType>\n\t\t\t\t\t\t\t<xsd:sequence>\n\t\t\t\t\t\t\t\t<xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n\t\t\t\t\t\t\t\t<xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n\t\t\t\t\t\t\t</xsd:sequence>\n\t\t\t\t\t\t\t<xsd:attribute name=\"name\" type=\"xsd:string\" msdata:Ordinal=\"1\" />\n\t\t\t\t\t\t\t<xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n\t\t\t\t\t\t\t<xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n\t\t\t\t\t\t</xsd:complexType>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element name=\"resheader\">\n\t\t\t\t\t\t<xsd:complexType>\n\t\t\t\t\t\t\t<xsd:sequence>\n\t\t\t\t\t\t\t\t<xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n\t\t\t\t\t\t\t</xsd:sequence>\n\t\t\t\t\t\t\t<xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n\t\t\t\t\t\t</xsd:complexType>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:complexType>\n\t\t</xsd:element>\n\t</xsd:schema>\n\t<resheader name=\"resmimetype\">\n\t\t<value>text/microsoft-resx</value>\n\t</resheader>\n\t<resheader name=\"version\">\n\t\t<value>1.3</value>\n\t</resheader>\n\t<resheader name=\"reader\">\n\t\t<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n\t</resheader>\n\t<resheader name=\"writer\">\n\t\t<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n\t</resheader>\n</root>"
  },
  {
    "path": "README.md",
    "content": "![GitHub all releases](https://img.shields.io/github/downloads/grayfallstown/Chia-Plot-Status/total)\n![GitHub](https://img.shields.io/github/license/grayfallstown/Chia-Plot-Status)\n![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/grayfallstown/Chia-Plot-Status?color=green&include_prereleases)\n![GitHub last commit](https://img.shields.io/github/last-commit/grayfallstown/Chia-Plot-Status)\n[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/donate?hosted_button_id=PDLLVF5XVMJPC)\n\n\n<p align=\"center\">\n  <img width=\"200\" alt=\"Chia Plot Status Log\" src=\"./Logo/Icon%20-%20Color%20changed.svg\">\n</p>\n\n# [Chia Plot Status](https://grayfallstown.github.io/Chia-Plot-Status/)\n\nGUI Tool for beginners and experts to Monitor and Analyse Chia Plotting log files, show health and progress of running plots and estimated time to completion. No setup, configuration or installation of python or whatever required. Just install and enjoy.\n\n![Screenshot](./Screenshots/Screenshot.jpg)\n![Screenshot](./Screenshots/Screenshot-Dark.jpg)\n\n## Features\n\n - Support for Chia, Flax, Spare and ChainGreen\n - Monitor Progress of running plots\n - Show estimated time to completion based on your already finished plots best matching your current plot config\n - Monitor Health of plotting processes\n - Already compatible with madMAx43v3r/chia-plotter (currently getting improved)\n - Compatible with all plotters and plotting managers that use or are based on the official chia plotter (see Troubleshooting if something does not work from the get go)\n - Show important information from log file in easy to read table\n - Multiple folders with log files supported (multiple plotting rigs, anyone?)\n - Multiple plots per log file supported (plot create --num n)\n - Export of readable or raw data to Json, Yaml and CSV\n\n\n## See Chia Plot Status in action:\n\n### On Upside Down Crypto (YouTube):\n\n<a href=\"http://www.youtube.com/watch?feature=player_embedded&v=lK0o3KyGFW8\" target=\"_blank\">\n <img src=\"http://img.youtube.com/vi/lK0o3KyGFW8/hqdefault.jpg\" alt=\"Watch the video\" />\n</a>\n\n\n### On Patro TV (YouTube):\n\n<a href=\"http://www.youtube.com/watch?feature=player_embedded&v=JLVhG86-4UI\" target=\"_blank\">\n <img src=\"http://img.youtube.com/vi/JLVhG86-4UI/hqdefault.jpg\" alt=\"Watch the video\" />\n</a>\n\n## How it works\n\nChia Plot Status observes the log folders you give it to monitor which can be local or connected via network. By this it supports monitoring multiple plotting rigs as you can access them on your desktop even if your plotting rigs are headless. It regulary checks for new Log files in those folders and analyses them.\n\nOn basis of finished plots it builds a local statistic (on your machine, no data is send anywhere or pulled from any cloud) and uses them to calculate ETA / time remaining and warning thresholds for the Health of your plotting processes.\n\n\n## Working with many distributed plotting rigs\n\n**Recommended way:** Use sshfs (with [sshfs-win](https://github.com/billziss-gh/sshfs-win) for Windows) to securely mount the log dirs of your plotting rigs on your desktop via highly encrypted network connection, where it is your desktop that initiates the mount. This can be set up so that the desktop can only access the log dirs and only has read access. Even if you use remote plotting rigs that you access over the internet this is the most secure way and you most likely access your remote servers via ssh already.\n\nOther Options: Mount the log folders of all rigs as network shares (via samba on linux) if all your plotting rigs are in the local network or connected via VPN. Another way would be to make a cronjob on your plotting rigs that uses scp or rsync in append mode to copy the log dir to your desktop where you run Chia Plot Status, but if you can manage to set this up you should set up sshfs instead. Last, least preferred option: collect them with cloud apps like Google Drive (Chia Plot Status does not talk to any cloud services for you, you have to install those apps and mount your log folders in them yourself if you want to use them).\n\n\n**Best Practice:**\n- Only delete log files of finished plots if your hardware or the way you plot has significantly changed. Chia Plot Status uses finished plots to calculate ETA/Time Remaining as well as warning/error thresholds. If you delete finished log files the quality of those values decreases significantly.\n- Use SSHFS to access the log directories of your plotting rigs\n- Each plotting rig should have its own log folder, so they don't mix and mess up estimates and warning thresholds for each other.\n- Always log locally. If you log directly to a network share / NAS your plotting processes will crash if the connection becomes flaky. Prefer connecting your host machine (which runs Chia Plot Status) to networkshares on the plotting rigs, not the other way around.\n\n\n## Security / Trustworthiness\n\nSee [a reddit comment made by the Chia Plot Status Core Developer, summarized in the following:](https://www.reddit.com/r/chia/comments/nlmwk7/safety_of_chiabot_from_joaquimguimaraes_on_github/gzn4xu3/?utm_source=reddit&utm_medium=web2x&context=3)\n\n### There are multiple attack vectors to consider:\n\n##### 1. The possibility that the core developer (me) is or becomes malicious\n\nThere is a saying: Where is a money trail, there is a way to sue/prosecute someone.\n\nChia Plot Status has buttons to donate via paypal both in the application itself and on the website.\n\nShould the core developer (me) turn malicious, people could easily sue the core developer (me) and by that get the necessary details as in full name, address and day of birth, IBAN/Bic, everything from paypal.\n\nIf the core developer (me) becomes malicious this would be basically a how to get imprisoned speedrun (any %)\n\nEven if you think you would not sue the core developer as he (me) might sit in a different country (germany), someone will as the Chia Plot Status Github Repository has between 2k to 4k visits daily and currently 24k downloads.\n\nThis should be more than enough to deter the core developer (me) from doing anything malicious.\n\n#### 2. The core developer (me) merges a pull request (code changes made by someone else) which contains malicious code without noticing\n\nAs seen on [https://github.com/grayfallstown/Chia-Plot-Status/graphs/contributors](https://github.com/grayfallstown/Chia-Plot-Status/graphs/contributors) there is only one other person who contributed a pull request so far and that wasn't code but a documentation change.\n\nThe core developer (me) will check each pull request before merging as he (me) would have to run the code himself to check if the application works properly after merging that pull request and by that he (I) would get attacked by any malicious code that was contained in that pull request.\n\n#### 3. External Dependencies (as in libraries / code written by someone else) the application uses to do certain things (like to create the graphical user interface) become malicious.\n\nWell, this is a tough one as even the core developer (me) has very little means to check external binaries for malicious code. The core developer (me) and every other developer using those libraries will get attacked by any malicious code in those libraries before they (we) distribute a new version of their (our) software containing that library to the users of their (our) softwares, as they (we) generally test their (our) applications before each release.\n\nThe core developer (me) takes the following precautions to mitigate that risk:\n\n- External dependencies are kept at a minimum to reduce this attack vector (chia-blockchain devs do the same)\n\n- Every release build is build on the same system and previously downloaded dependencies are never deleted/redownloaded. This prevents pulling in malicious code if the external dependency version used gets replaced with malicious code. But it also prevents  reproducible builds that everyone can follow and reproduce step by step on their system, if the external dependency version actually does get changed. Well, this should raise concern anyway and in any case.\n\n- Updating Dependencies (external libraries / code written by someone else) is delayed (possibly indefinitely) until an update is required to implement a feature or to fix a bug. This gives anti virus providers time to determine if that library version is malicious, which would prevent an update.\n\n\n## Installation / Download\n\n![GitHub all releases](https://img.shields.io/github/downloads/grayfallstown/Chia-Plot-Status/total)\n\nWindows: [Download latest version](https://github.com/grayfallstown/Chia-Plot-Status/releases/latest/download/Setup.exe)\nYou will get a blue warning saying this was published by an unknown developer.\n\nLinux: First install [dotnet 5.0 SDK](https://dotnet.microsoft.com/download/dotnet/5.0), then either the Chia Plot Status [deb](https://github.com/grayfallstown/Chia-Plot-Status/releases/latest/download/ChiaPlotStatus.linux-x64.deb) or [rpm](https://github.com/grayfallstown/Chia-Plot-Status/releases/latest/download/ChiaPlotStatus.linux-x64.rpm) package depending on your linux distribution (deb for ubuntu)\n\nFor Mac you currently have to [build it](#Build-it-).\n\n## Getting Log Files from PowerShell\n\n```\n$Temp1=\"D:\\PlotTemp\"\n$Temp2=\"D:\\PlotTemp\"\n...\n\nchia.exe plots create --tmp_dir \"$TEMP1\" --tmp2_dir \"$TEMP2\" [and so on] 2>&1 | % ToString | Tee-Object -FilePath \"C:\\Users\\$USERNAME\\.chia\\mainnet\\plotter\\$([GUID]::NewGUID().ToString('D')).log\"\n```\n\nThe last part with `2>&1 | % ToString | Tee-Object` writes the log to the PowerShell and to a file with a unique name for each plotting process.\n\nYou can download a [full example script with Tee-Object](https://gist.github.com/grayfallstown/8530acb84eb131d3dae074e4be23badb) as well.\n\n\n## Getting Log Files from madMAx43v3r/chia-plotter\n\nOn Windows without WSL:\n\nTake the same command you are currently using and just add ` 2>&1 | % ToString | Tee-Object -FilePath \"C:\\Users\\$env:UserName\\.chia\\mainnet\\plotter\\$([GUID]::NewGUID().ToString('D')).log\"` at the end and run it in PowerShell, not CMD.\nNote: there must be a whitespace between your command and this and there is nothing to be replaced in this line. Just leave it as it is.\n\nOn Windows with WSL:\n\n```\n# make sure you have got uuid installed (sudo apt install uuid -y)\n# use 'chia keys show' to get this keys:\nexport POOLKEY=\"replace-me\"; \\\nexport FARMERKEY=\"replace-me\"; \\\nexport WINDOWS_USERNAME=\"replace-me\" \\\nexport THREADS=\"$(expr $(nproc) / 2)\"; \\\n/home/mk/chia-plotter/build2/chia_plot \\\n--poolkey=$POOLKEY \\\n--farmerkey=$FARMERKEY \\\n--tmpdir2=replace-me \\\n--tmpdir=replace-me \\\n--finaldir=replace-me/ \\\n--count=-1 \\\n--threads=$THREADS \\\n--buckets=7 \\\n 2>&1  | tee /mnt/c/Users/$WINDOWS_USERNAME/.chia/mainnet/plotter/chia-plotter-$(uuid).log\n```\nNote: There is nothing to be replaced in the last line. Just leave it as it is.\n\n\nOn Linux directly:\n\n```\n# make sure you have got uuid installed (sudo apt install uuid -y)\n# use 'chia keys show' to get this keys:\nexport POOLKEY=\"replace-me\"; \\\nexport FARMERKEY=\"replace-me\"; \\\nexport THREADS=\"$(expr $(nproc) / 2)\"; \\\n/home/mk/chia-plotter/build2/chia_plot \\\n--poolkey=$POOLKEY \\\n--farmerkey=$FARMERKEY \\\n--tmpdir2=replace-me \\\n--tmpdir=replace-me \\\n--finaldir=replace-me/ \\\n--count=-1 \\\n--threads=$THREADS \\\n--buckets=7 \\\n 2>&1 | tee /home/$(whoami)/.chia/mainnet/plotter/chia-plotter-$(uuid).log;\n```\n\nNote: There is nothing to be replaced in the last line. Just leave it as it is.\n\n\n## Need the columns in a different order?\n\nSee https://github.com/grayfallstown/Chia-Plot-Status/issues/36#issuecomment-843351280\n\n\n## Troubleshooting\n\nIf you use Cloud Sync Services, rsync/scp cronjobs or tools like Syncthing to collect your log files you might run into an issue with the files not properly syncing. Sonething like `The process cannot access the file because it is being used by another process.`. See [Issue #40](https://github.com/grayfallstown/Chia-Plot-Status/issues/40#issuecomment-841025993) for how to fix that, or even better, use sshfs instead.\n\nThe same works if you use harry plotter as plotting manager.\n\nIf Chia Plot Status does no longer start, try renaming `ChiaPlotStatu.config.json` to `ChiaPlotStatu.config.json.backup`. The file is located in your home directory at `C:\\Users\\<your username>\\ChiaPlotStatu.config.json` on windows, `/home/<your username>/ChiaPlotStatu.config.json` on linux and `<your user profile directory>/ChiaPlotStatu.config.json` on mac.\n\n## Custom tools / Home automation\n\nYou can export plot logs to json, yaml or csv both via the gui or the console for automation:\n\n```\n\"C:\\Program Files (x86)\\ChiaPlotStatus\\ChiaPlotStatus\\ChiaPlotStatusCli.exe\" --help\nCopyright (C) 2021 grayfallstown\n\n  -o, --outfile            Required. The file to write to\n\n  -f, --format             Required. The format to use while writing the file. Valid values are json, yaml and csv\n\n  -l, --log-folders        The folders where logs can be found, comma separated. Uses default folder when empty\n\n  -s, --sort-property      The property you want the plotlogs sorted by\n\n  -a, --sort-asc           Sort ascending\n\n  --search                 Filter plotlogs by this search terms. You filter for your temp1 folder for example.\n\n  --hide-finished          Hide finished plots\n\n  --hide-possibly-dead     Hide possibly dead plots\n\n  --hide-confirmed-dead    Hide confirmed dead plots\n\n  --hide-healthy           Hide healthy plots\n\n  --keep-updating          Keep updating the file every 10 seconds\n\n  --help                   Display this help screen.\n\n\n\n\"C:\\Program Files (x86)\\ChiaPlotStatus\\ChiaPlotStatus\\ChiaPlotStatusCli.exe\" -o test.json -f json\nSorting by Progress\nFile 'test.json' written\n```\n\nNote: Write your tools or home automation in a way that new fields/properties/columns added to the exported files do not crash it.\n\n\n## Open Source\n\nMIT opensource licence, free to keep or change.\n\n\n## Build it yourself\n\nThis **should** work on x86_64bit, x86_32bit, ARM 64bit and ARM 32 bit Systems. If not, open an [Issue](https://github.com/grayfallstown/Chia-Plot-Status/issues/new) to tell me whats wrong.\n\nDownload and install [dotnet 5.0 SDK](https://dotnet.microsoft.com/download/dotnet/5.0) and [git](https://git-scm.com/).\n\nOn the console, clone/download this repository:\n\n`git clone https://github.com/grayfallstown/Chia-Plot-Status.git`\n\nBuild it:\n\n`cd Chia-Plot-Status`\n\n`dotnet build --configuration .\\ChiaPlotStatus.sln /p:Configuration=Release /p:Platform=\"Any CPU\"`\n\nChia-Plot-Status can now be started with \n\nwindows: `.\\ChiaPlotStatusGUI\\bin\\Release\\net5.0\\ChiaPlotStatus.exe` \n\nlinux: `./ChiaPlotStatusGUI/bin/Release/net5.0/ChiaPlotStatus`\n\nmacOS: `dotnet ./ChiaPlotStatusGUI/bin/Release/net5.0/ChiaPlotStatus.dll` (thanks @mahdi-ninja)\n\nalternatively try `dotnet run --build`.\n\n\n## Donations\n\nPayPal: https://www.paypal.com/donate?hosted_button_id=PDLLVF5XVMJPC\n\nBitcoin/BTC bc1qy2fvr0js9xunlcgndlz9m9yu2qrydtlnlh4fgm\n\nEtherium/ETH 0x0e07b5A73F571a98bAf19Fc42EBDE15d6B1664f0\n\nChia/XCH xch15p8swrrdt5ujv0dxy4hwjrvpjseyvuquwtfwnrjhxqt6ws9uf90qzq4axl\n\nTether/USDT 0x0e07b5A73F571a98bAf19Fc42EBDE15d6B1664f0\n\nBinance Coin/BNB bnb1pes46l2jkw8dd9tw6j7sc4r9muzv5kuepnal0r\n\nCardano/ADA addr1q86sat0hpuvg5mp85qwke5kk6rjf6yntvr7epaz8j3k2g784p6klwrcc3fkz0gqadnfdd58yn5fxkc8ajr6y09rv53uqzjzv2r\n\nXRP r9Wrpa2JsHh74nKqmcjJduy9GXDgmX44ic\n\nUSD Coin/USDC 0x0e07b5A73F571a98bAf19Fc42EBDE15d6B1664f0\n\nPolkadot/DOT 16Mp3siK7qFJ9567R6ynPMNf3W9SYcumgUMXacMkH9UC7817\n\nUniswap/UNI 0x0e07b5A73F571a98bAf19Fc42EBDE15d6B1664f0\n\nLitecoin/LTC LdbWCtQu7L9J9sYeDcp3M1qTWyA6Acck28\n\nBitcoin Cash/BCH qrxfzf3dact3crqu8l8uvxdp639scekw9qn20akrdc\n\nChainlink/LINK 0x0e07b5A73F571a98bAf19Fc42EBDE15d6B1664f0\n\nStellar/XLM GAIEQ6N7V77WLDYNFBESCGONNURKGCQZ2GS6THEENOWUSBVHQBBFL4XJ\n\nVeChain/VET 0xBf8AC5799333a8B14A51228Be9E02629e034A039\n\nTron/TRX TKMnrH4P2L4PigJVNijZz9BQiSewrABosc\n\nDai/DAI 0x0e07b5A73F571a98bAf19Fc42EBDE15d6B1664f0\n\nNeo/NEO ANZiysMZZS3PgzKpqTs8jATRcrpujZTBsB\n\nTezos/XTZ tz1XhtmaVr6RnqbTGPmPvD1XgsK7kHt8rUuH\n\nCosmos/ATOM cosmos1mu89q07xv9m8furg06f7tsw3u32da553wh0uv2\n\nNEM/XEM NDM7SU2CVAN6CNOEFRMPPOIZSXQVYHIQ3BVJGH7T\n\n0x/ZRX 0x0e07b5A73F571a98bAf19Fc42EBDE15d6B1664f0\n\nMonero/XMR 43RbqKt37UUgY62ow4N3ptTT263zK1sfC88szAhThihU6bQKeURF3TrYLDumSak5gkX8Bj2FNzeWiduoEcPjLppHHSoBQi5\n\nEtherium Classic/ETC 0x9347727443e8808c14062A7Fb95625B0284F2F8d\n\nFlax/XFX xfx1622u30na4n83rya7nxkn5rpm78f4988e7cscl47ypct7wgnd7wus747nmk\n\nChainGreen/CGN cgn1zsfna95ju03juzpfcgyrfg4ljj2tq4ydpsdfxaegxx5dd6k3rjlqjgu9rr\n\n\n\n## Special Thanks\n\n- [@charlie](https://freeicons.io/profile/740) on [freeicons.io](https://freeicons.io) for the Logo [(details)](https://github.com/grayfallstown/Chia-Plot-Status/blob/main/Logo/Icon%20-%20Readme.txt)\n- @ใครๆก็ทําได้ DiY\n- @Alpha One\n- @Çağlar\n- @Cuello\n- @DazEB2\n- @DjMuffin_top\n- @Dujapan\n- @Gridjump\n- @@getchiaplot\n- @Hellfall1\n- @Jazeon\n- @Jonesyj83\n- @JoseAngelB\n- @KJP Gaming\n- @Lucky_Length2676\n- @Lyushen\n- @Manic!\n- @Mr pq\n- @Ok-Studio5311\n- @Oguzhan Oda\n- @Patro TV\n- @R3htribution\n- @RaySmalley\n- @RedxLus\n- @SERVAK\n- @TormodSan\n- @Upside Down Crypto\n- @Waloumi\n- @WeAreNotAngels\n- @Worldly-Mind3108\n- @Zubon102\n- @aDilly\n- @badi95\n- @bathrobehero\n- @bestq8.com\n- @blood5322\n- @buettgenbach\n- @c-pool\n- @carfnann\n- @chefsas\n- @chiaxch\n- @cyperbg\n- @darkfriend77\n- @djdookie81\n- @dorofino\n- @douwebusschops\n- @dvlzgrmz\n- @j.spracher\n- @jcmarco\n- @jimshank\n- @johnamtl\n- @jonnnny\n- @kata32\n- @littleneko\n- @magallanesrafa\n- @magnusmyklebost\n- @massimo de rovere\n- @mmoingame\n- @ouoam\n- @ozulu\n- @puperinoo\n- @raf-cr\n- @revlisoft\n- @rsegrest77\n- @rul3s\n- @sirdeekay\n- @tajchert\n- @tiberiu puscas\n- @toddouimet\n- @whitetechnologies\n- @Vera Toro\n- @whoismos3s\n- @wild9\n- @wizbowes\n- @z.ostroff\n- @zeroarst\n- @The Malware Analysts of Microsoft and Malwarebytes for checking Chia Plot Status after every false positive\n\nFor contributing to Chia Plot Status either by [donating](https://www.paypal.com/donate?hosted_button_id=PDLLVF5XVMJPC) or otherwise.\n"
  },
  {
    "path": "next-minor.ps1",
    "content": "dotnet version --no-git --minor\ncd ChiaPlotStatusGUI\ndotnet version --no-git --minor\ncd ..\\ChiaPlotStatusCli\ndotnet version --no-git --minor\ncd ..\\ChiaPlotStatusLib\ndotnet version --no-git --minor\ncd ..\n"
  },
  {
    "path": "next-patch.ps1",
    "content": "dotnet version --no-git --patch\ncd ChiaPlotStatusGUI\ndotnet version --no-git --patch\ncd ..\\ChiaPlotStatusCli\ndotnet version --no-git --patch\ncd ..\\ChiaPlotStatusLib\ndotnet version --no-git --patch\ncd .."
  },
  {
    "path": "release.ps1",
    "content": "Echo \"Set Version!\"\nEcho \".\\next-patch.ps1\"\nEcho \".\\next-minor.ps1\"\n\npause\n\nEcho \"Killing running ChiaPlotStatus.exe\"\ntaskkill /IM \"ChiaPlotStatus.exe\" /F\ntaskkill /IM \"ChiaPlotStatus.exe\" /F\n\nEcho \"Cleaning release folder\"\nrm -r release\\\nmkdir release\\\nmkdir release\\ChiaPlotStatus\\\n\nrm -r ChiaPlotStatusGUI\\bin\nrm -r ChiaPlotStatusCLI\\bin\nrm -r ChiaPlotStatusLIB\\bin\n\nEcho \"Building linux deb and rpm packages\"\ncd ChiaPlotStatusGUI\ndotnet deb -r linux-x64 -f net5.0 -c Release\ndotnet rpm -r linux-x64 -f net5.0 -c Release\n# dotnet publish -c Release -f net5.0 -r ubuntu.16.04-x64\n# cd ..\\ChiaPlotStatusGUI\n# dotnet deb -r ubuntu.16.04-x64 -f net5.0 -c Release\n# cp ..\\ChiaPlotStatusCLI\\bin\\Release\\net5.0\\linux-x64\\publish\\ChiaPlotStatusCLI* .\\bin\\Release\\net5.0\\ubuntu.16.04-x64\\publish\\\n# dotnet rpm -r ubuntu.16.04-x64 -f net5.0 -c Release\n# cp bin\\Release\\net5.0\\ubuntu.16.04-x64\\ChiaPlotStatus.*.ubuntu.16.04-x64.rpm ..\\release\\ChiaPlotStatus.linux-x64.rpm\n# dotnet deb -r ubuntu.16.04-x64 -f net5.0 -c Release\n# dotnet deb -c Release\n# cp bin\\Release\\net5.0\\ChiaPlotStatus.*.deb ..\\release\\ChiaPlotStatus.linux-x64.deb\ncp bin\\Release\\net5.0\\linux-x64\\ChiaPlotStatus*.deb ..\\release\\ChiaPlotStatus.linux-x64.deb\ncp bin\\Release\\net5.0\\linux-x64\\ChiaPlotStatus*.rpm ..\\release\\ChiaPlotStatus.linux-x64.rpm\ncd ..\n\n\n# Echo \"Building for MacOS\"\n# dotnet publish -r osx-x64 --configuration .\\ChiaPlotStatus.sln /p:Configuration=Release /p:Platform=\"Any CPU\"\n# dotnet pkg -r osx-x64 -f net5.0 -c Release\n\n\nEcho \"Building for Windows\"\ndotnet publish -r win-x64 --configuration .\\ChiaPlotStatus.sln /p:Configuration=Release /p:Platform=\"Any CPU\"\n\n\nEcho \"\"\nEcho \"The warnings are normal. Only formal flaws in the code\"\nEcho \"\"\n\n\nEcho \"Copying Windows build to release folder\"\nxcopy /sy C:\\Users\\mk\\IdeaProjects\\ChiaPlotStatus\\ChiaPlotStatusLib\\bin\\Release\\net5.0\\win-x64\\publish\\* release\\ChiaPlotStatus\\\nxcopy /sy C:\\Users\\mk\\IdeaProjects\\ChiaPlotStatus\\ChiaPlotStatusGUI\\bin\\Release\\net5.0\\win-x64\\publish\\* release\\ChiaPlotStatus\\\nxcopy /sy C:\\Users\\mk\\IdeaProjects\\ChiaPlotStatus\\ChiaPlotStatusCli\\bin\\Release\\net5.0\\win-x64\\publish\\* release\\ChiaPlotStatus\\\n\nEcho \"Now open and build setup using InstallForge and InstallerConfig.ifp as config\"\n"
  }
]