public static async Task DownloadAsync(this HttpClient client, string requestUri, Stream destination,
                                               IDownloadable downloadable = null, CancellationToken cancellationToken = default)
        {
            // Get the http headers first to examine the content length
            using (HttpResponseMessage response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead))
            {
                long?contentLength = response.Content.Headers.ContentLength;

                using (Stream download = await response.Content.ReadAsStreamAsync())
                {
                    // Ignore progress reporting when no progress reporter was
                    // passed or when the content length is unknown
                    if (downloadable == null || !contentLength.HasValue)
                    {
                        await download.CopyToAsync(destination);

                        return;
                    }

                    // Convert absolute progress (bytes downloaded) into relative progress (0% - 100%)
                    Progress <long> relativeProgress = new Progress <long>(
                        totalBytes => downloadable.ReportProgress(totalBytes, contentLength.Value, totalBytes / (float)contentLength.Value * 100f)
                        );
                    // Use extension method to report progress while downloading
                    await download.CopyToAsync(destination, 81920, relativeProgress, cancellationToken);

                    downloadable.ReportProgress(contentLength.Value, contentLength.Value, 100f);
                }
            }
        }
        private async Task DeleteAppData(IDownloadable downloadable)
        {
            // Get all the files recursively as our total
            string directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Artemis");

            if (!Directory.Exists(directory))
            {
                downloadable.ReportProgress(0, 0, 100);
                return;
            }

            string source = Assembly.GetEntryAssembly().Location;

            string[] files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);

            // Delete all files
            await Task.Run(() =>
            {
                int index = 0;
                foreach (string file in files)
                {
                    if (file != source)
                    {
                        File.Delete(file);
                    }

                    index++;
                    downloadable.ReportProgress(index, files.Length, index / (float)files.Length * 100);
                }
            });

            downloadable.ReportProgress(0, 0, 100);
        }
        public async Task UninstallBinaries(IDownloadable downloadable, bool onlyDelete)
        {
            string source = Assembly.GetEntryAssembly().Location;

            if (Directory.Exists(InstallationDirectory))
            {
                // Get all the files recursively as our total
                string[] files = Directory.GetFiles(InstallationDirectory, "*", SearchOption.AllDirectories);
                // Delete all files except the installer
                await Task.Run(() =>
                {
                    int index = 0;
                    foreach (string file in files)
                    {
                        if (file != source)
                        {
                            File.Delete(file);
                        }

                        index++;
                        downloadable.ReportProgress(index, files.Length, index / (float)files.Length * 100);
                    }
                });
            }

            downloadable.ReportProgress(0, 0, 100);

            if (onlyDelete)
            {
                return;
            }

            // Delete the installer itself after it closes
            CleanUpOnShutdown = true;

            // If needed, repeat for app data
            if (RemoveAppData)
            {
                await DeleteAppData(downloadable);
            }

            // Clean up the start menu
            if (Directory.Exists(_artemisStartMenuDirectory))
            {
                Directory.Delete(_artemisStartMenuDirectory, true);
            }
        }
        public async Task InstallBinaries(string file, IDownloadable downloadable)
        {
            CleanUpOnShutdown = false;

            GeneralUtilities.CreateAccessibleDirectory(DataDirectory);
            GeneralUtilities.CreateAccessibleDirectory(InstallationDirectory);
            using (FileStream fileStream = new FileStream(file, FileMode.Open))
            {
                ZipArchive archive = new ZipArchive(fileStream);
                float      count   = 0;
                foreach (ZipArchiveEntry entry in archive.Entries)
                {
                    using (Stream unzippedEntryStream = entry.Open())
                    {
                        downloadable.ReportProgress(0, 0, count / archive.Entries.Count * 100f);
                        if (entry.Length > 0)
                        {
                            string path = Path.Combine(InstallationDirectory, entry.FullName);
                            CreateDirectoryForFile(path);
                            using (Stream extractStream = new FileStream(path, FileMode.OpenOrCreate))
                            {
                                await unzippedEntryStream.CopyToAsync(extractStream);
                            }
                        }
                    }

                    count++;
                }
            }

            downloadable.ReportProgress(0, 0, 100);

            // Copy installer
            string source = Assembly.GetEntryAssembly().Location;
            string target = Path.Combine(DataDirectory, "installer", "Artemis.Installer.exe");

            if (source != target)
            {
                CreateDirectoryForFile(target);
                File.Copy(source, target, true);
            }

            // Populate the start menu
            if (!Directory.Exists(_artemisStartMenuDirectory))
            {
                Directory.CreateDirectory(_artemisStartMenuDirectory);
            }

            ShortcutUtilities.Create(
                Path.Combine(_artemisStartMenuDirectory, "Artemis.lnk"),
                Path.Combine(InstallationDirectory, "Artemis.UI.exe"),
                "",
                InstallationDirectory,
                "Artemis",
                "",
                ""
                );
            ShortcutUtilities.Create(
                Path.Combine(_artemisStartMenuDirectory, "Uninstall Artemis.lnk"),
                Path.Combine(DataDirectory, "installer", "Artemis.Installer.exe"),
                "-uninstall",
                InstallationDirectory,
                "Uninstall Artemis",
                "",
                ""
                );
        }