private async void Organizer_Load(object sender, EventArgs e)
        {
            source    = new DirectoryInfo(ConfigurationManager.AppSettings["sourceDir"]);
            target    = new DirectoryInfo(ConfigurationManager.AppSettings["outputDir"]);
            processed = new DirectoryInfo(ConfigurationManager.AppSettings["processedDir"]);
            var working = new DirectoryInfo(ConfigurationManager.AppSettings["workingDir"]);

            toolStripStatusLabelText.Text = "Loading...";
            var progress = new Progress <string>(s => toolStripStatusLabelText.Text = s);

            await LoadFolderAsync();

            ghostScriptPath = ConfigurationManager.AppSettings["gsPath"];

            processor = new OCRProcessor(new FileProcessorConfiguration()
            {
                SourceDir       = source.FullName,
                ProcessedDir    = processed.FullName,
                WorkingDir      = working.FullName,
                GhostScriptPath = ghostScriptPath,
                TesseractPath   = ConfigurationManager.AppSettings["tesseractPath"]
            },
                                         progress: new Progress <Tuple <int, string> >(statusUpdate =>
            {
                int runnerId      = statusUpdate.Item1;
                string updateText = statusUpdate.Item2;
                try
                {
                    Invoke((MethodInvoker) delegate
                    {
                        while (listViewStatus.Items.Count < runnerId)
                        {
                            listViewStatus.Items.Add("");
                        }
                        if (listViewStatus.Items.Count == runnerId)
                        {
                            listViewStatus.Items.Add(updateText);
                        }
                        else
                        {
                            listViewStatus.Items[runnerId].Text = updateText;
                        }
                        listViewStatus.Update();
                    });
                }
                catch { }
            }));

            processor.Start();
        }
        private async Task ProcessAsync()
        {
            if (selectedImages.Any())
            {
                var docsToProcess = selectedImages.Select(i => documents[i]).ToList();
                selectedImages.Clear();
                LoadPreviews();

                Task <string> processingTask = Task.Run(() =>
                {
                    if (docsToProcess.Count > 1)
                    {
                        //combine
                        var paths = docsToProcess.Select(doc => doc.ProcessedFile.FullName).ToList();
                        string inputFilesCommandLine = String.Join(" ", paths.Select(p => $"\"{p}\""));
                        var combinedFilePath         = Path.GetTempFileName();
                        OCRProcessor.RunSilentProcess(ghostScriptPath, processed.FullName, $"-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile=\"{combinedFilePath}\" {inputFilesCommandLine}");

                        return(combinedFilePath);
                    }
                    else
                    {
                        return(docsToProcess.First().ProcessedFile.FullName);
                    }
                });

                StringBuilder textBuilder = new StringBuilder();

                foreach (var doc in docsToProcess)
                {
                    string text = File.ReadAllText(doc.PreviewTextFile.FullName);
                    text = text.Replace("\n", "\r\n");
                    textBuilder.AppendLine(text);
                }

                var dlg1 = new FilterAndSaveDialog
                {
                    PdfText        = textBuilder.ToString(),
                    BaseTargetDir  = target.FullName,
                    OutputFilePath = Path.Combine(target.FullName, docsToProcess.First().ProcessedFile.Name)
                };

                var result = dlg1.ShowDialog(this);

                if (result == DialogResult.OK)
                {
                    try
                    {
                        var targetFile = new FileInfo(dlg1.OutputFilePath);
                        if (!targetFile.Directory.Exists)
                        {
                            targetFile.Directory.Create();
                        }
                        string sourceFilePath   = await processingTask;
                        string uniqueOutputPath = OCRProcessor.GetUniqueOutputFilePath(targetFile.FullName);
                        File.Move(sourceFilePath, uniqueOutputPath);

                        //cleanup
                        foreach (var doc in docsToProcess)
                        {
                            doc.Delete();
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }

                    await LoadFolderAsync();
                }
            }
        }