diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj
index 5f9fa025..c054a04f 100644
--- a/FModel/FModel.csproj
+++ b/FModel/FModel.csproj
@@ -159,6 +159,7 @@
+
diff --git a/FModel/Forms/Settings.Designer.cs b/FModel/Forms/Settings.Designer.cs
index 4e7936a6..db836746 100644
--- a/FModel/Forms/Settings.Designer.cs
+++ b/FModel/Forms/Settings.Designer.cs
@@ -428,11 +428,11 @@ namespace FModel.Forms
//
this.label7.AutoSize = true;
this.label7.ForeColor = System.Drawing.Color.Red;
- this.label7.Location = new System.Drawing.Point(89, 113);
+ this.label7.Location = new System.Drawing.Point(106, 113);
this.label7.Name = "label7";
- this.label7.Size = new System.Drawing.Size(117, 13);
+ this.label7.Size = new System.Drawing.Size(86, 13);
this.label7.TabIndex = 33;
- this.label7.Text = "Banner Size: 1024x256";
+ this.label7.Text = "4:1 Aspect Ratio";
//
// button4
//
diff --git a/FModel/Forms/Settings.cs b/FModel/Forms/Settings.cs
index b3f59854..1c8be9e4 100644
--- a/FModel/Forms/Settings.cs
+++ b/FModel/Forms/Settings.cs
@@ -34,7 +34,7 @@ namespace FModel.Forms
textBox6.Text = Properties.Settings.Default.challengesWatermark;
if (string.IsNullOrWhiteSpace(textBox6.Text))
{
- textBox6.Text = "{Bundle_Name} Generated using FModel & JohnWickParse - {Date}";
+ textBox6.Text = "@UseTheWatermarkBecauseWhyNot - {Date}";
}
else { textBox6.Text = Properties.Settings.Default.challengesWatermark; }
@@ -291,7 +291,7 @@ namespace FModel.Forms
newForm.Size = pictureBox1.Image.Size;
newForm.Icon = Resources.FModel;
- newForm.Text = ThePak.CurrentUsedItem;
+ newForm.Text = "Challenges Design Template";
newForm.StartPosition = FormStartPosition.CenterScreen;
newForm.Controls.Add(pb);
newForm.Show();
diff --git a/FModel/MainWindow.Designer.cs b/FModel/MainWindow.Designer.cs
index 44f7c4f6..8ca9fc73 100644
--- a/FModel/MainWindow.Designer.cs
+++ b/FModel/MainWindow.Designer.cs
@@ -48,6 +48,7 @@ namespace FModel
this.searchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
this.saveAsJSONToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.autoSaveAsJSONToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
this.copySelectedFilePathToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator();
@@ -88,7 +89,8 @@ namespace FModel
this.saveAsJSONToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.contextMenuStrip2 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.extractFolderContentsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
- this.autoSaveAsJSONToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator();
+ this.downloadBackupsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.statusStrip1.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.panel1.SuspendLayout();
@@ -155,7 +157,9 @@ namespace FModel
this.loadOneToolStripMenuItem,
this.loadAllToolStripMenuItem,
this.toolStripSeparator1,
+ this.downloadBackupsToolStripMenuItem,
this.backupPAKsToolStripMenuItem,
+ this.toolStripSeparator8,
this.differenceModeToolStripMenuItem,
this.updateModeToolStripMenuItem,
this.toolStripSeparator2,
@@ -167,26 +171,26 @@ namespace FModel
// loadOneToolStripMenuItem
//
this.loadOneToolStripMenuItem.Name = "loadOneToolStripMenuItem";
- this.loadOneToolStripMenuItem.Size = new System.Drawing.Size(162, 22);
+ this.loadOneToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.loadOneToolStripMenuItem.Text = "Load One PAK";
this.loadOneToolStripMenuItem.DropDownItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.loadOneToolStripMenuItem_DropDownItemClicked);
//
// loadAllToolStripMenuItem
//
this.loadAllToolStripMenuItem.Name = "loadAllToolStripMenuItem";
- this.loadAllToolStripMenuItem.Size = new System.Drawing.Size(162, 22);
+ this.loadAllToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.loadAllToolStripMenuItem.Text = "Load All PAKs";
this.loadAllToolStripMenuItem.Click += new System.EventHandler(this.loadAllToolStripMenuItem_Click);
//
// toolStripSeparator1
//
this.toolStripSeparator1.Name = "toolStripSeparator1";
- this.toolStripSeparator1.Size = new System.Drawing.Size(159, 6);
+ this.toolStripSeparator1.Size = new System.Drawing.Size(217, 6);
//
// backupPAKsToolStripMenuItem
//
this.backupPAKsToolStripMenuItem.Name = "backupPAKsToolStripMenuItem";
- this.backupPAKsToolStripMenuItem.Size = new System.Drawing.Size(162, 22);
+ this.backupPAKsToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.backupPAKsToolStripMenuItem.Text = "Backup PAKs";
this.backupPAKsToolStripMenuItem.Click += new System.EventHandler(this.backupPAKsToolStripMenuItem_Click);
//
@@ -194,7 +198,7 @@ namespace FModel
//
this.differenceModeToolStripMenuItem.CheckOnClick = true;
this.differenceModeToolStripMenuItem.Name = "differenceModeToolStripMenuItem";
- this.differenceModeToolStripMenuItem.Size = new System.Drawing.Size(162, 22);
+ this.differenceModeToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.differenceModeToolStripMenuItem.Text = "Difference Mode";
this.differenceModeToolStripMenuItem.CheckedChanged += new System.EventHandler(this.differenceModeToolStripMenuItem_CheckedChanged);
//
@@ -203,21 +207,21 @@ namespace FModel
this.updateModeToolStripMenuItem.CheckOnClick = true;
this.updateModeToolStripMenuItem.Enabled = false;
this.updateModeToolStripMenuItem.Name = "updateModeToolStripMenuItem";
- this.updateModeToolStripMenuItem.Size = new System.Drawing.Size(162, 22);
+ this.updateModeToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.updateModeToolStripMenuItem.Text = "Update Mode";
this.updateModeToolStripMenuItem.CheckedChanged += new System.EventHandler(this.updateModeToolStripMenuItem_CheckedChanged);
//
// toolStripSeparator2
//
this.toolStripSeparator2.Name = "toolStripSeparator2";
- this.toolStripSeparator2.Size = new System.Drawing.Size(159, 6);
+ this.toolStripSeparator2.Size = new System.Drawing.Size(217, 6);
//
// settingsToolStripMenuItem
//
this.settingsToolStripMenuItem.Image = global::FModel.Properties.Resources.properties_16xLG;
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
this.settingsToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F1;
- this.settingsToolStripMenuItem.Size = new System.Drawing.Size(162, 22);
+ this.settingsToolStripMenuItem.Size = new System.Drawing.Size(220, 22);
this.settingsToolStripMenuItem.Text = "Settings";
this.settingsToolStripMenuItem.Click += new System.EventHandler(this.settingsToolStripMenuItem_Click);
//
@@ -257,6 +261,13 @@ namespace FModel
this.saveAsJSONToolStripMenuItem.Text = "Save as JSON";
this.saveAsJSONToolStripMenuItem.Click += new System.EventHandler(this.SaveAsJSONToolStripMenuItem_Click);
//
+ // autoSaveAsJSONToolStripMenuItem
+ //
+ this.autoSaveAsJSONToolStripMenuItem.CheckOnClick = true;
+ this.autoSaveAsJSONToolStripMenuItem.Name = "autoSaveAsJSONToolStripMenuItem";
+ this.autoSaveAsJSONToolStripMenuItem.Size = new System.Drawing.Size(197, 22);
+ this.autoSaveAsJSONToolStripMenuItem.Text = "Auto Save as JSON";
+ //
// toolStripSeparator5
//
this.toolStripSeparator5.Name = "toolStripSeparator5";
@@ -621,12 +632,17 @@ namespace FModel
this.extractFolderContentsToolStripMenuItem.Text = "Extract Folder Contents";
this.extractFolderContentsToolStripMenuItem.Click += new System.EventHandler(this.ExtractFolderContentsToolStripMenuItem_Click);
//
- // autoSaveAsJSONToolStripMenuItem
+ // toolStripSeparator8
//
- this.autoSaveAsJSONToolStripMenuItem.CheckOnClick = true;
- this.autoSaveAsJSONToolStripMenuItem.Name = "autoSaveAsJSONToolStripMenuItem";
- this.autoSaveAsJSONToolStripMenuItem.Size = new System.Drawing.Size(197, 22);
- this.autoSaveAsJSONToolStripMenuItem.Text = "Auto Save as JSON";
+ this.toolStripSeparator8.Name = "toolStripSeparator8";
+ this.toolStripSeparator8.Size = new System.Drawing.Size(217, 6);
+ //
+ // downloadBackupsToolStripMenuItem
+ //
+ this.downloadBackupsToolStripMenuItem.Name = "downloadBackupsToolStripMenuItem";
+ this.downloadBackupsToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.downloadBackupsToolStripMenuItem.Text = "Download Backups";
+ this.downloadBackupsToolStripMenuItem.DropDownItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.DownloadBackupsToolStripMenuItem_DropDownItemClicked);
//
// MainWindow
//
@@ -722,6 +738,8 @@ namespace FModel
private System.Windows.Forms.ToolStripMenuItem openExtractionFolderToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator7;
private System.Windows.Forms.ToolStripMenuItem autoSaveAsJSONToolStripMenuItem;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator8;
+ private System.Windows.Forms.ToolStripMenuItem downloadBackupsToolStripMenuItem;
}
}
diff --git a/FModel/MainWindow.cs b/FModel/MainWindow.cs
index f613520d..819cbed8 100644
--- a/FModel/MainWindow.cs
+++ b/FModel/MainWindow.cs
@@ -17,6 +17,7 @@ using FModel.Forms;
using FModel.Properties;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using RestSharp;
using Image = System.Drawing.Image;
using Settings = FModel.Properties.Settings;
@@ -102,6 +103,19 @@ namespace FModel
loadOneToolStripMenuItem.DropDownItems.Add(thePak);
}));
}
+ private void AddBackupFiles()
+ {
+ if (CreateBackup.backupFilesList != null && CreateBackup.backupFilesList.Count > 0)
+ {
+ foreach (var item in CreateBackup.backupFilesList)
+ {
+ Invoke(new Action(() =>
+ {
+ downloadBackupsToolStripMenuItem.DropDownItems.Add(item.bFileName);
+ }));
+ }
+ }
+ }
///
/// check if path exists
@@ -169,6 +183,8 @@ namespace FModel
FillWithPaKs();
AddToUI.checkAndAddDynamicKeys();
Utilities.colorMyPaks(loadOneToolStripMenuItem);
+ CreateBackup.GetFilesFromDropbox();
+ AddBackupFiles();
Utilities.SetFolderPermission(App.DefaultOutputPath);
Utilities.CreateDefaultFolders();
});
@@ -538,6 +554,35 @@ namespace FModel
CreateBackup.CreateBackupList();
});
}
+ private async void DownloadBackupsToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
+ {
+ await Task.Run(() => {
+ if (CreateBackup.backupFilesList != null && CreateBackup.backupFilesList.Count > 0)
+ {
+ string filename = CreateBackup.backupFilesList.Where(x => string.Equals(x.bFileName, e.ClickedItem.Text)).Select(x => x.bFileName).FirstOrDefault();
+ string downloadLink = CreateBackup.backupFilesList.Where(x => string.Equals(x.bFileName, e.ClickedItem.Text)).Select(x => x.bFileDownload).FirstOrDefault();
+ if (!string.IsNullOrEmpty(downloadLink))
+ {
+ new UpdateMyState("Downloading " + filename, "Waiting").ChangeProcessState();
+
+ RestClient EndpointClient = new RestClient(downloadLink);
+ RestRequest EndpointRequest = new RestRequest(Method.GET);
+ string content = EndpointClient.Execute(EndpointRequest).Content;
+
+ File.WriteAllText(App.DefaultOutputPath + "\\Backup\\" + filename, content);
+ if (new System.IO.FileInfo(App.DefaultOutputPath + "\\Backup\\" + filename).Length > 0)
+ {
+ new UpdateMyState("\\Backup\\" + filename + " successfully downloaded", "Success").ChangeProcessState();
+ }
+ else
+ {
+ File.Delete(App.DefaultOutputPath + "\\Backup\\" + filename);
+ new UpdateMyState("Can't download " + filename, "Error").ChangeProcessState();
+ }
+ }
+ }
+ });
+ }
//UPDATE MODE
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
diff --git a/FModel/MainWindow.resx b/FModel/MainWindow.resx
index 1e2e95b8..c08c9df4 100644
--- a/FModel/MainWindow.resx
+++ b/FModel/MainWindow.resx
@@ -131,7 +131,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABa
- CAAAAk1TRnQBSQFMAgEBAgEAAfABAQHwAQEBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
+ CAAAAk1TRnQBSQFMAgEBAgEAAfgBAQH4AQEBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
diff --git a/FModel/Methods/IconGenerator/ChallengeGenerator/BundleDesign.cs b/FModel/Methods/IconGenerator/ChallengeGenerator/BundleDesign.cs
index 4f27b004..9037debc 100644
--- a/FModel/Methods/IconGenerator/ChallengeGenerator/BundleDesign.cs
+++ b/FModel/Methods/IconGenerator/ChallengeGenerator/BundleDesign.cs
@@ -227,7 +227,9 @@ namespace FModel
JToken bundleCompletionRewards = myBundle["BundleCompletionRewards"];
if (bundleCompletionRewards != null)
{
+ new UpdateMyState("Drawing Completion Rewards...", "Waiting").ChangeProcessState();
theY += 35;
+
JArray bundleCompletionRewardsArray = bundleCompletionRewards.Value();
foreach (JToken token in bundleCompletionRewardsArray)
{
@@ -267,7 +269,7 @@ namespace FModel
{
string rewardId = Path.GetFileName(assetPathName.Value().Substring(0, assetPathName.Value().LastIndexOf(".", StringComparison.Ordinal)));
- if (!assetPathName.Value().Contains("/Game/Items/Tokens/") && !rewardId.Contains("Quest_BR_")) //no fortbyte for weekly challenges
+ if (!assetPathName.Value().Contains("/Game/Items/Tokens/") && !rewardId.Contains("Quest_BR_")) //no more fortbyte for weekly challenges
{
theY += 90;
drawCompletionText(myBitmap, compCount);
diff --git a/FModel/Methods/IconGenerator/ChallengeGenerator/BundleInfos.cs b/FModel/Methods/IconGenerator/ChallengeGenerator/BundleInfos.cs
index 6d3dd2e3..bb646e6f 100644
--- a/FModel/Methods/IconGenerator/ChallengeGenerator/BundleInfos.cs
+++ b/FModel/Methods/IconGenerator/ChallengeGenerator/BundleInfos.cs
@@ -181,14 +181,24 @@ namespace FModel
JToken description = token["Description"];
if (description != null)
{
- descriptionKey = description["key"].Value();
- descriptionSource = description["source_string"].Value();
+ JToken key = description["key"];
+ JToken sourceString = description["source_string"];
+ if (key != null && sourceString != null)
+ {
+ descriptionKey = key.Value();
+ descriptionSource = sourceString.Value();
+ }
}
JToken descriptionMain = AssetArray[0]["Description"];
if (descriptionMain != null)
{
- descriptionKey = descriptionMain["key"].Value();
- descriptionSource = descriptionMain["source_string"].Value();
+ JToken key = descriptionMain["key"];
+ JToken sourceString = descriptionMain["source_string"];
+ if (key != null && sourceString != null)
+ {
+ descriptionKey = key.Value();
+ descriptionSource = sourceString.Value();
+ }
}
}
diff --git a/FModel/Methods/IconGenerator/ChallengeGenerator/ChallengeInfoEntry.cs b/FModel/Methods/IconGenerator/ChallengeGenerator/ChallengeInfoEntry.cs
index 24d20350..3e8be47d 100644
--- a/FModel/Methods/IconGenerator/ChallengeGenerator/ChallengeInfoEntry.cs
+++ b/FModel/Methods/IconGenerator/ChallengeGenerator/ChallengeInfoEntry.cs
@@ -1,8 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace FModel
{
diff --git a/FModel/Methods/PakHelper/BackupFilesEntry.cs b/FModel/Methods/PakHelper/BackupFilesEntry.cs
new file mode 100644
index 00000000..f164c12b
--- /dev/null
+++ b/FModel/Methods/PakHelper/BackupFilesEntry.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace FModel
+{
+ public struct BackupFilesEntry : IEquatable
+ {
+ internal BackupFilesEntry(string fileName, string fileDownload)
+ {
+ bFileName = fileName;
+ bFileDownload = fileDownload;
+ }
+ public string bFileName { get; set; }
+ public string bFileDownload { get; set; }
+
+ bool IEquatable.Equals(BackupFilesEntry other)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/FModel/Methods/PakHelper/CreateBackup.cs b/FModel/Methods/PakHelper/CreateBackup.cs
index 1509548f..f30e6975 100644
--- a/FModel/Methods/PakHelper/CreateBackup.cs
+++ b/FModel/Methods/PakHelper/CreateBackup.cs
@@ -1,6 +1,8 @@
using csharp_wick;
using FModel.Properties;
+using Newtonsoft.Json.Linq;
using System;
+using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
@@ -10,6 +12,8 @@ namespace FModel
{
static class CreateBackup
{
+ public static List backupFilesList { get; set; }
+
public static void CreateBackupList()
{
PakExtractor extractor = null;
@@ -79,7 +83,7 @@ namespace FModel
}
File.WriteAllText(App.DefaultOutputPath + "\\Backup" + Checking.BackupFileName, sb.ToString()); //File will always exist so we check the file size instead
- if (new System.IO.FileInfo(App.DefaultOutputPath + "\\Backup" + Checking.BackupFileName).Length > 0)
+ if (new FileInfo(App.DefaultOutputPath + "\\Backup" + Checking.BackupFileName).Length > 0)
{
new UpdateMyState("\\Backup" + Checking.BackupFileName + " successfully created", "Success").ChangeProcessState();
}
@@ -89,5 +93,34 @@ namespace FModel
new UpdateMyState("Can't create " + Checking.BackupFileName.Substring(1), "Error").ChangeProcessState();
}
}
+
+ public static void GetFilesFromDropbox()
+ {
+ try
+ {
+ if (DLLImport.IsInternetAvailable())
+ {
+ string backupFiles = Keychain.GetEndpoint("https://dl.dropbox.com/s/lngkoq2ucd9di2n/FModel_Backups.json?dl=0");
+ backupFilesList = new List();
+
+ if (!string.IsNullOrEmpty(backupFiles))
+ {
+ JArray array = JArray.Parse(backupFiles);
+ foreach (JProperty prop in array.Children().Properties())
+ {
+ backupFilesList.Add(new BackupFilesEntry(prop.Name, prop.Value.Value()));
+ }
+ }
+ }
+ else
+ {
+ new UpdateMyConsole("Your internet connection is currently unavailable, can't check for backup files at the moment.", Color.Red, true).AppendToConsole();
+ }
+ }
+ catch (Exception)
+ {
+ new UpdateMyConsole("[FModel] Error while checking for backup files", Color.Red, true).AppendToConsole();
+ }
+ }
}
}
diff --git a/FModel/Methods/PakHelper/PakHelper.cs b/FModel/Methods/PakHelper/PakHelper.cs
index 5b0429da..c40e0e45 100644
--- a/FModel/Methods/PakHelper/PakHelper.cs
+++ b/FModel/Methods/PakHelper/PakHelper.cs
@@ -70,9 +70,11 @@ namespace FModel
{
theExtractor = new PakExtractor(Settings.Default.PAKsPath + "\\" + pakName, pakKey);
}
- catch (Exception)
+ catch (Exception ex)
{
- new UpdateMyConsole("0x" + pakKey + " doesn't work with " + ThePak.dynamicPaksList[i].thePak, Color.Red, true).AppendToConsole();
+ if (string.Equals(ex.Message, "Extraction failed")) { new UpdateMyConsole("0x" + pakKey + " doesn't work with " + ThePak.dynamicPaksList[i].thePak, Color.Red, true).AppendToConsole(); }
+ else { new UpdateMyConsole("Message: " + ex.Message + "\nSource: " + ex.Source + "\nTarget: " + ex.TargetSite, Color.Red, true).AppendToConsole(); }
+
if (theExtractor != null) { theExtractor.Dispose(); }
continue;
}
diff --git a/README.md b/README.md
index 461fe62b..baddb21b 100644
--- a/README.md
+++ b/README.md
@@ -75,6 +75,7 @@ Also if you find this project useful, feel free to give it a :star: thank you :k
- [ScintillaNET](https://www.nuget.org/packages/jacobslusser.ScintillaNET)
- [Find & Replace for ScintillaNET](https://www.nuget.org/packages/snt.ScintillaNet.FindReplaceDialog/)
- [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json)
+ - [Cyotek ColorPicker](https://github.com/cyotek/Cyotek.Windows.Forms.ColorPicker)
### Contributors