diff --git a/bin/Vinesauce ROM Corruptor v1.2.0 (Beta).zip b/bin/Vinesauce ROM Corruptor v1.2.0 (Beta).zip new file mode 100644 index 0000000..52950a4 Binary files /dev/null and b/bin/Vinesauce ROM Corruptor v1.2.0 (Beta).zip differ diff --git a/src/Vinesauce ROM Corruptor/Corruption.cs b/src/Vinesauce ROM Corruptor/Corruption.cs new file mode 100644 index 0000000..0f1ab13 --- /dev/null +++ b/src/Vinesauce ROM Corruptor/Corruption.cs @@ -0,0 +1,535 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace Vinesauce_ROM_Corruptor +{ + static class Corruption + { + public enum ByteCorruptionOptions + { + AddXToByte, + ShiftRightXBytes, + ReplaceByteXwithY + } + + static private List NESCPUJamProtection_Avoid = new List() { 0x48, 0x08, 0x68, 0x28, 0x78, 0x00, 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x92, 0xB2, 0xD2, 0xF2 }; + static private List NESCPUJamProtection_Protect_1 = new List() { 0x48, 0x08, 0x68, 0x28, 0x78, 0x40, 0x60, 0x00, 0x90, 0xB0, 0xF0, 0x30, 0xD0, 0x10, 0x50, 0x70, 0x4C, 0x6C, 0x20 }; + static private List NESCPUJamProtection_Protect_2 = new List() { 0x90, 0xB0, 0xF0, 0x30, 0xD0, 0x10, 0x50, 0x70, 0x4C, 0x6C, 0x20 }; + static private List NESCPUJamProtection_Protect_3 = new List() { 0x4C, 0x6C, 0x20 }; + + public static byte[] Run + (byte[] ROM, bool ByteCorruptionEnable, long StartByte, long EndByte, ByteCorruptionOptions ByteCorruptionOption, + uint EveryNthByte, int AddXtoByte, int ShiftRightXBytes, byte ReplaceByteXwithYByteX, byte ReplaceByteXwithYByteY, bool EnableNESCPUJamProtection, + bool TextReplacementEnable, bool TextUseByteCorruptionRange, string RawTextToReplace, string RawReplaceWith, string RawAnchorWords, + bool ColorReplacementEnable, bool ColorUseByteCorruptionRange, string RawColorsToReplace, string RawReplaceWithColors) + { + // Areas to not corrupt. + List ProtectedRegions = new List(); + + // Delimeter for text sections. + char[] Delimeter = new char[1] { '|' }; + + // Do text replacement if desired. + if (TextReplacementEnable) + { + // Translation dictionary. + Dictionary TranslationDictionary = new Dictionary(); + + // Read in the text and its replacement. + string[] TextToReplace = RawTextToReplace.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); + string[] ReplaceWith = RawReplaceWith.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); + + // Make sure they have equal length. + if (TextToReplace.Length != ReplaceWith.Length) + { + MessageBox.Show("Number of text sections to replace does not match number of replacements.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + + // Create relative offset arrays of the anchors. + string[] Anchors = RawAnchorWords.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); + int[][] RelativeAnchors = new int[Anchors.Length][]; + for (int i = 0; i < Anchors.Length; i++) + { + RelativeAnchors[i] = new int[Anchors[i].Length]; + for (int j = 0; j < Anchors[i].Length; j++) + { + RelativeAnchors[i][j] = Anchors[i][j] - Anchors[i][0]; + } + } + + // Look for the anchors. + for (int i = 0; i < RelativeAnchors.Length; i++) + { + // Position in ROM. + long j = 0; + + // Scan the entire ROM. + while (j < ROM.LongLength) + { + // If a match has been found. + bool Match = true; + + // Look for the relative values. + for (int k = 0; k < RelativeAnchors[i].Length; k++) + { + // Make sure its in range. + if (j + k < ROM.LongLength) + { + // Ignore non-letter characters for matching purposes. + if (!Char.IsLetter(Anchors[i][k])) + { + continue; + } + + // Check if the relative value doesn't match. + if ((ROM[j + k] - ROM[j]) != RelativeAnchors[i][k]) + { + // It doesn't, break. + Match = false; + break; + } + } + else + { + // Out of range before matching. + Match = false; + break; + } + } + + // If a match was found, update the dictionary. + if (Match) + { + int k = 0; + for (k = 0; k < Anchors[i].Length; k++) + { + if (!TranslationDictionary.ContainsKey(Anchors[i][k])) + { + TranslationDictionary.Add(Anchors[i][k], ROM[j + k]); + } + } + + // Move ahead to the correct location in the ROM. + j = j + k + 1; + } + else + { + // Move ahead one byte. + j = j + 1; + } + } + } + + // Calculate the offset to translate unknown text, assuming ASCII structure. + int ASCIIOffset = 0; + if (TranslationDictionary.Count > 0) + { + ASCIIOffset = TranslationDictionary.First().Value - TranslationDictionary.First().Key; + } + + // Create arrays of the text to be replaced in ROM format. + byte[][] ByteTextToReplace = new byte[TextToReplace.Length][]; + for (int i = 0; i < TextToReplace.Length; i++) + { + ByteTextToReplace[i] = new byte[TextToReplace[i].Length]; + for (int j = 0; j < TextToReplace[i].Length; j++) + { + if (TranslationDictionary.ContainsKey(TextToReplace[i][j])) + { + ByteTextToReplace[i][j] = TranslationDictionary[TextToReplace[i][j]]; + } + else + { + int ASCIITranslated = TextToReplace[i][j] + ASCIIOffset; + if (ASCIITranslated >= Byte.MinValue && ASCIITranslated <= Byte.MaxValue) + { + ByteTextToReplace[i][j] = (byte)(ASCIITranslated); + } + else + { + // Could not translate. + ByteTextToReplace[i][j] = (byte)(TextToReplace[i][j]); + } + } + } + } + + // Create arrays of the replacement text in ROM format. + byte[][] ByteReplaceWith = new byte[ReplaceWith.Length][]; + for (int i = 0; i < ReplaceWith.Length; i++) + { + ByteReplaceWith[i] = new byte[ReplaceWith[i].Length]; + for (int j = 0; j < ReplaceWith[i].Length; j++) + { + if (TranslationDictionary.ContainsKey(ReplaceWith[i][j])) + { + ByteReplaceWith[i][j] = TranslationDictionary[ReplaceWith[i][j]]; + } + else + { + int ASCIITranslated = ReplaceWith[i][j] + ASCIIOffset; + if (ASCIITranslated >= Byte.MinValue && ASCIITranslated <= Byte.MaxValue) + { + ByteReplaceWith[i][j] = (byte)(ASCIITranslated); + } + else + { + // Could not translate. + ByteReplaceWith[i][j] = (byte)(ReplaceWith[i][j]); + } + } + } + } + + // Area of ROM to consider. + long TextReplacementStartByte = 0; + long TextReplacementEndByte = ROM.LongLength - 1; + + // Change area if using the byte corruption range. + if (TextUseByteCorruptionRange) + { + TextReplacementStartByte = StartByte; + TextReplacementEndByte = EndByte; + } + + // Look for the text to replace. + for (int i = 0; i < ByteTextToReplace.Length; i++) + { + // Position in ROM. + long j = TextReplacementStartByte; + + // Scan the entire ROM. + while (j <= TextReplacementEndByte) + { + // If a match has been found. + bool Match = true; + + // Look for the text. + for (int k = 0; k < ByteTextToReplace[i].Length; k++) + { + // Make sure its in range. + if (j + k <= TextReplacementEndByte) + { + // Ignore non-letter characters for matching purposes. + if (!Char.IsLetter(TextToReplace[i][k])) + { + continue; + } + + // Check if the relative value doesn't match. + if (ROM[j + k] != ByteTextToReplace[i][k]) + { + // It doesn't, break. + Match = false; + break; + } + } + else + { + // Out of range before matching. + Match = false; + break; + } + } + + // If the entire string matched, replace it. + if (Match) + { + // If the area is protected. + bool Protected = false; + + // Length of the replacement. + int k = ByteReplaceWith[i].Length - 1; + + // Check if the area is protected. + foreach (long[] ProtectedRegion in ProtectedRegions) + { + if ((j >= ProtectedRegion[0] && j <= ProtectedRegion[1]) || (j + k >= ProtectedRegion[0] && j + k <= ProtectedRegion[1]) || (j < ProtectedRegion[0] && j + k > ProtectedRegion[1])) + { + // Yes, its protected. + Protected = true; + break; + } + } + + // If not protected, replace the text. + if (!Protected) + { + for (k = 0; k < ByteReplaceWith[i].Length; k++) + { + ROM[j + k] = ByteReplaceWith[i][k]; + } + + // Protect the inserted text. + ProtectedRegions.Add(new long[2] { j, j + k }); + } + + // Move ahead to the correct location in the ROM. + j = j + k + 1; + } + else + { + // Move ahead one byte. + j = j + 1; + } + } + } + } + + // Do color replacement if desired. + if (ColorReplacementEnable) + { + // Read in the text and its replacement. + string[] ColorsToReplace = RawColorsToReplace.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); + string[] ColorsReplaceWith = RawReplaceWithColors.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); + + // Make sure they have equal length. + if (ColorsToReplace.Length != ColorsReplaceWith.Length) + { + MessageBox.Show("Number of colors to replace does not match number of replacements.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + + // Convert the strings. + byte[] ColorsToReplaceBytes = new byte[ColorsToReplace.Length]; + byte[] ColorsReplaceWithBytes = new byte[ColorsReplaceWith.Length]; + for (int i = 0; i < ColorsToReplace.Length; i++) + { + try + { + byte Converted = Convert.ToByte(ColorsToReplace[i], 16); + ColorsToReplaceBytes[i] = Converted; + } + catch + { + MessageBox.Show("Invalid color to replace.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + } + for (int i = 0; i < ColorsReplaceWithBytes.Length; i++) + { + try + { + byte Converted = Convert.ToByte(ColorsReplaceWith[i], 16); + ColorsReplaceWithBytes[i] = Converted; + } + catch + { + MessageBox.Show("Invalid color replacement.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + } + + // Area of ROM to consider. + long ColorReplacementStartByte = 0; + long ColorReplacementEndByte = ROM.LongLength - 1; + + // Change area if using the byte corruption range. + if (ColorUseByteCorruptionRange) + { + ColorReplacementStartByte = StartByte; + ColorReplacementEndByte = EndByte; + } + + // Position in ROM. + long j = ColorReplacementStartByte; + + // Scan the entire ROM. + while (j <= ColorReplacementEndByte) + { + // If a palette has been found. + bool Palette = true; + + // Look for a palette. + for (int k = 0; k < 4; k++) + { + // Make sure its in range. + if (j + k <= ColorReplacementEndByte) + { + // Check if value exceeds the maximum valid color value. + if (ROM[j + k] > 0x3F) + { + // It does, break. + Palette = false; + break; + } + } + else + { + // Out of range before matching. + Palette = false; + break; + } + } + + // If a possible palette was found, do color replacement. + if (Palette) + { + for (int i = 0; i < ColorsToReplaceBytes.Length; i++) + { + for (int k = 0; k < 4; k++) + { + if (ROM[j + k] == ColorsToReplaceBytes[i]) + { + // If the byte is protected. + bool Protected = false; + + // Check if the byte is protected. + foreach (long[] ProtectedRegion in ProtectedRegions) + { + if (j + k >= ProtectedRegion[0] && j + k <= ProtectedRegion[1]) + { + // Yes, its protected. + Protected = true; + break; + } + } + + // If its not protected, do the replacement. + if (!Protected) + { + ROM[j + k] = ColorsReplaceWithBytes[i]; + ProtectedRegions.Add(new long[2] { j + k, j + k }); + } + } + } + } + + // Move ahead to the correct location in the ROM. + j = j + 4; + } + else + { + // Move ahead one byte. + j = j + 1; + } + } + } + + // Do byte corruption if desired. + if (ByteCorruptionEnable) + { + if (ByteCorruptionOption == ByteCorruptionOptions.AddXToByte && AddXtoByte != 0) + { + for (long i = StartByte + EveryNthByte; i <= EndByte; i = i + EveryNthByte) + { + // If the byte is protected. + bool Protected = false; + + // Check if the byte is protected. + foreach (long[] ProtectedRegion in ProtectedRegions) + { + if (i >= ProtectedRegion[0] && i <= ProtectedRegion[1]) + { + // Yes, its protected. + Protected = true; + break; + } + } + + // Do NES CPU jam protection if desired. + if (EnableNESCPUJamProtection) + { + if (!Protected && i >= 2) + { + if (NESCPUJamProtection_Avoid.Contains((byte)((ROM[i] + AddXtoByte) % (Byte.MaxValue + 1))) + || NESCPUJamProtection_Protect_1.Contains(ROM[i]) + || NESCPUJamProtection_Protect_2.Contains(ROM[i - 1]) + || NESCPUJamProtection_Protect_3.Contains(ROM[i - 2])) + { + Protected = true; + } + } + } + + // If the byte is not protected, corrupt it. + if (!Protected) + { + int NewValue = (ROM[i] + AddXtoByte) % (Byte.MaxValue + 1); + ROM[i] = (byte)NewValue; + } + } + } + else if (ByteCorruptionOption == ByteCorruptionOptions.ShiftRightXBytes && ShiftRightXBytes != 0) + { + for (long i = StartByte + EveryNthByte; i <= EndByte; i = i + EveryNthByte) + { + long j = i + ShiftRightXBytes; + + if (j >= StartByte && j <= EndByte) + { + // If the byte is protected. + bool Protected = false; + + // Check if the byte is protected. + foreach (long[] ProtectedRegion in ProtectedRegions) + { + if (j >= ProtectedRegion[0] && j <= ProtectedRegion[1]) + { + // Yes, its protected. + Protected = true; + break; + } + } + + // Do NES CPU jam protection if desired. + if (EnableNESCPUJamProtection) + { + if (!Protected && j >= 2) + { + if (NESCPUJamProtection_Avoid.Contains(ROM[i]) + || NESCPUJamProtection_Protect_1.Contains(ROM[j]) + || NESCPUJamProtection_Protect_2.Contains(ROM[j - 1]) + || NESCPUJamProtection_Protect_3.Contains(ROM[j - 2])) + { + Protected = true; + } + } + } + + // If the byte is not protected, corrupt it. + if (!Protected) + { + ROM[j] = ROM[i]; + } + } + } + } + else if (ByteCorruptionOption == ByteCorruptionOptions.ReplaceByteXwithY && ReplaceByteXwithYByteX != ReplaceByteXwithYByteY) + { + for (long i = StartByte + EveryNthByte; i <= EndByte; i = i + EveryNthByte) + { + if (ROM[i] == ReplaceByteXwithYByteX) + { + // If the byte is protected. + bool Protected = false; + + // Check if the byte is protected. + foreach (long[] ProtectedRegion in ProtectedRegions) + { + if (i >= ProtectedRegion[0] && i <= ProtectedRegion[1]) + { + // Yes, its protected. + Protected = true; + break; + } + } + + // If the byte is not protected, corrupt it. + if (!Protected) + { + ROM[i] = ReplaceByteXwithYByteY; + } + } + } + } + } + + return ROM; + } + } +} diff --git a/src/Vinesauce ROM Corruptor/MainForm.Designer.cs b/src/Vinesauce ROM Corruptor/MainForm.Designer.cs index 74ba706..c1893f7 100644 --- a/src/Vinesauce ROM Corruptor/MainForm.Designer.cs +++ b/src/Vinesauce ROM Corruptor/MainForm.Designer.cs @@ -136,6 +136,11 @@ namespace Vinesauce_ROM_Corruptor this.checkBox_HotkeyEnable = new System.Windows.Forms.CheckBox(); this.button_HotkeySet = new System.Windows.Forms.Button(); this.button_HotkeyHelp = new System.Windows.Forms.Button(); + this.groupBox_Queue = new System.Windows.Forms.GroupBox(); + this.button_QueueHelp = new System.Windows.Forms.Button(); + this.checkBox_QueueEnable = new System.Windows.Forms.CheckBox(); + this.button_QueueManage = new System.Windows.Forms.Button(); + this.button_QueueAdd = new System.Windows.Forms.Button(); this.groupBox_FileSelection.SuspendLayout(); this.groupBox_EmulatorSelection.SuspendLayout(); this.groupBox_TextReplace.SuspendLayout(); @@ -144,6 +149,7 @@ namespace Vinesauce_ROM_Corruptor this.groupBox_NESPalette.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox_NESPalette)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.groupBox_Queue.SuspendLayout(); this.SuspendLayout(); // // button_RomDirectoryBrowse @@ -247,7 +253,7 @@ namespace Vinesauce_ROM_Corruptor this.listView_Files.Margin = new System.Windows.Forms.Padding(2); this.listView_Files.MultiSelect = false; this.listView_Files.Name = "listView_Files"; - this.listView_Files.Size = new System.Drawing.Size(344, 188); + this.listView_Files.Size = new System.Drawing.Size(344, 183); this.listView_Files.TabIndex = 47; this.listView_Files.UseCompatibleStateImageBehavior = false; this.listView_Files.View = System.Windows.Forms.View.Details; @@ -256,7 +262,7 @@ namespace Vinesauce_ROM_Corruptor // listViewC_fileName // this.listViewC_fileName.Text = "File Name"; - this.listViewC_fileName.Width = 344; + this.listViewC_fileName.Width = 340; // // groupBox_EmulatorSelection // @@ -928,9 +934,9 @@ namespace Vinesauce_ROM_Corruptor this.groupBox_ColorReplacement.Controls.Add(this.label_ColorsToReplace); this.groupBox_ColorReplacement.Controls.Add(this.checkBox_ColorReplacementEnable); this.groupBox_ColorReplacement.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.groupBox_ColorReplacement.Location = new System.Drawing.Point(10, 583); + this.groupBox_ColorReplacement.Location = new System.Drawing.Point(10, 580); this.groupBox_ColorReplacement.Name = "groupBox_ColorReplacement"; - this.groupBox_ColorReplacement.Size = new System.Drawing.Size(359, 169); + this.groupBox_ColorReplacement.Size = new System.Drawing.Size(359, 172); this.groupBox_ColorReplacement.TabIndex = 16; this.groupBox_ColorReplacement.TabStop = false; this.groupBox_ColorReplacement.Text = "Color Replacement"; @@ -1091,7 +1097,7 @@ namespace Vinesauce_ROM_Corruptor this.pictureBox1.Image = global::Vinesauce_ROM_Corruptor.Properties.Resources.Vinesauce_Mushroom; this.pictureBox1.Location = new System.Drawing.Point(376, 11); this.pictureBox1.Name = "pictureBox1"; - this.pictureBox1.Size = new System.Drawing.Size(358, 307); + this.pictureBox1.Size = new System.Drawing.Size(358, 233); this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; this.pictureBox1.TabIndex = 39; this.pictureBox1.TabStop = false; @@ -1153,12 +1159,71 @@ namespace Vinesauce_ROM_Corruptor this.button_HotkeyHelp.UseVisualStyleBackColor = true; this.button_HotkeyHelp.Click += new System.EventHandler(this.button_HotkeyHelp_Click); // + // groupBox_Queue + // + this.groupBox_Queue.Controls.Add(this.button_QueueHelp); + this.groupBox_Queue.Controls.Add(this.checkBox_QueueEnable); + this.groupBox_Queue.Controls.Add(this.button_QueueManage); + this.groupBox_Queue.Controls.Add(this.button_QueueAdd); + this.groupBox_Queue.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.groupBox_Queue.Location = new System.Drawing.Point(376, 250); + this.groupBox_Queue.Name = "groupBox_Queue"; + this.groupBox_Queue.Size = new System.Drawing.Size(358, 68); + this.groupBox_Queue.TabIndex = 46; + this.groupBox_Queue.TabStop = false; + this.groupBox_Queue.Text = "Queue"; + // + // button_QueueHelp + // + this.button_QueueHelp.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.button_QueueHelp.Location = new System.Drawing.Point(236, 16); + this.button_QueueHelp.Name = "button_QueueHelp"; + this.button_QueueHelp.Size = new System.Drawing.Size(26, 23); + this.button_QueueHelp.TabIndex = 45; + this.button_QueueHelp.Text = "?"; + this.button_QueueHelp.UseVisualStyleBackColor = true; + this.button_QueueHelp.Click += new System.EventHandler(this.button_QueueHelp_Click); + // + // checkBox_QueueEnable + // + this.checkBox_QueueEnable.AutoSize = true; + this.checkBox_QueueEnable.Location = new System.Drawing.Point(6, 20); + this.checkBox_QueueEnable.Name = "checkBox_QueueEnable"; + this.checkBox_QueueEnable.Size = new System.Drawing.Size(65, 17); + this.checkBox_QueueEnable.TabIndex = 2; + this.checkBox_QueueEnable.Text = "Enable"; + this.checkBox_QueueEnable.UseVisualStyleBackColor = true; + this.checkBox_QueueEnable.CheckedChanged += new System.EventHandler(this.checkBox_QueueEnable_CheckedChanged); + // + // button_QueueManage + // + this.button_QueueManage.Enabled = false; + this.button_QueueManage.Location = new System.Drawing.Point(155, 16); + this.button_QueueManage.Name = "button_QueueManage"; + this.button_QueueManage.Size = new System.Drawing.Size(75, 23); + this.button_QueueManage.TabIndex = 1; + this.button_QueueManage.Text = "Manage"; + this.button_QueueManage.UseVisualStyleBackColor = true; + this.button_QueueManage.Click += new System.EventHandler(this.button_QueueManage_Click); + // + // button_QueueAdd + // + this.button_QueueAdd.Enabled = false; + this.button_QueueAdd.Location = new System.Drawing.Point(74, 16); + this.button_QueueAdd.Name = "button_QueueAdd"; + this.button_QueueAdd.Size = new System.Drawing.Size(75, 23); + this.button_QueueAdd.TabIndex = 0; + this.button_QueueAdd.Text = "Add"; + this.button_QueueAdd.UseVisualStyleBackColor = true; + this.button_QueueAdd.Click += new System.EventHandler(this.button_QueueAdd_Click); + // // MainForm // this.AcceptButton = this.button_Run; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(742, 791); + this.Controls.Add(this.groupBox_Queue); this.Controls.Add(this.button_HotkeyHelp); this.Controls.Add(this.button_HotkeySet); this.Controls.Add(this.checkBox_HotkeyEnable); @@ -1193,6 +1258,8 @@ namespace Vinesauce_ROM_Corruptor this.groupBox_NESPalette.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.pictureBox_NESPalette)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.groupBox_Queue.ResumeLayout(false); + this.groupBox_Queue.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -1287,6 +1354,11 @@ namespace Vinesauce_ROM_Corruptor private System.Windows.Forms.Button button_HotkeyHelp; private System.Windows.Forms.ListView listView_Files; private System.Windows.Forms.ColumnHeader listViewC_fileName; + private System.Windows.Forms.GroupBox groupBox_Queue; + private System.Windows.Forms.Button button_QueueHelp; + private System.Windows.Forms.CheckBox checkBox_QueueEnable; + private System.Windows.Forms.Button button_QueueManage; + private System.Windows.Forms.Button button_QueueAdd; } } diff --git a/src/Vinesauce ROM Corruptor/MainForm.cs b/src/Vinesauce ROM Corruptor/MainForm.cs index d97129a..4288685 100644 --- a/src/Vinesauce ROM Corruptor/MainForm.cs +++ b/src/Vinesauce ROM Corruptor/MainForm.cs @@ -264,595 +264,31 @@ namespace Vinesauce_ROM_Corruptor return; } - // Read in all of the text boxes. - long StartByte; - try + if (checkBox_QueueEnable.Checked) { - StartByte = Convert.ToInt64(textBox_StartByte.Text, 16); - } - catch - { - MessageBox.Show("Invalid start byte.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - long EndByte; - try - { - EndByte = Convert.ToInt64(textBox_EndByte.Text, 16); - } - catch - { - MessageBox.Show("Invalid end byte.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - uint EveryNthByte; - try - { - EveryNthByte = Convert.ToUInt32(textBox_EveryNBytes.Text); - } - catch - { - MessageBox.Show("Invalid byte corruption interval.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - if (EveryNthByte == 0) - { - MessageBox.Show("Invalid byte corruption interval.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - int AddXtoByte; - try - { - AddXtoByte = Convert.ToInt32(textBox_AddXToByte.Text); - } - catch - { - MessageBox.Show("Invalid byte addition value.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - int ShiftRightXBytes; - try - { - ShiftRightXBytes = Convert.ToInt32(textBox_ShiftRightXBytes.Text); - } - catch - { - MessageBox.Show("Invalid right shift value.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - byte ReplaceByteXwithYByteX; - try - { - ReplaceByteXwithYByteX = Convert.ToByte(textBox_ReplaceByteXwithYByteX.Text, 16); - } - catch - { - MessageBox.Show("Invalid byte to match.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - byte ReplaceByteXwithYByteY; - try - { - ReplaceByteXwithYByteY = Convert.ToByte(textBox_ReplaceByteXwithYByteY.Text, 16); - } - catch - { - MessageBox.Show("Invalid byte replacement.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - // Limit the end byte. - if (EndByte > (ROM.LongLength - 1)) - { - EndByte = ROM.LongLength - 1; - } - - // Areas to not corrupt. - List ProtectedRegions = new List(); - - // Delimeter for text sections. - char[] Delimeter = new char[1] { '|' }; - - // Do text replacement if desired. - if (checkBox_TextReplacementEnable.Checked) - { - // Translation dictionary. - Dictionary TranslationDictionary = new Dictionary(); - - // Read in the text and its replacement. - string[] TextToReplace = textBox_TextToReplace.Text.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); - string[] ReplaceWith = textBox_ReplaceWith.Text.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); - - // Make sure they have equal length. - if (TextToReplace.Length != ReplaceWith.Length) + QueueForm.CorruptionQueue.Add(new string[] { "Current", CorruptionSettingsToString() }); + foreach (string[] Entry in QueueForm.CorruptionQueue) { - MessageBox.Show("Number of text sections to replace does not match number of replacements.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - // Create relative offset arrays of the anchors. - string[] Anchors = textBox_AnchorWords.Text.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); - int[][] RelativeAnchors = new int[Anchors.Length][]; - for (int i = 0; i < Anchors.Length; i++) - { - RelativeAnchors[i] = new int[Anchors[i].Length]; - for (int j = 0; j < Anchors[i].Length; j++) + StringToCorruptionSettings(Entry[1]); + ROM = Corrupt(ROM); + if (ROM == null) { - RelativeAnchors[i][j] = Anchors[i][j] - Anchors[i][0]; - } - } - - // Look for the anchors. - for (int i = 0; i < RelativeAnchors.Length; i++) - { - // Position in ROM. - long j = 0; - - // Scan the entire ROM. - while (j < ROM.LongLength) - { - // If a match has been found. - bool Match = true; - - // Look for the relative values. - for (int k = 0; k < RelativeAnchors[i].Length; k++) - { - // Make sure its in range. - if (j + k < ROM.LongLength) - { - // Ignore non-letter characters for matching purposes. - if (!Char.IsLetter(Anchors[i][k])) - { - continue; - } - - // Check if the relative value doesn't match. - if ((ROM[j + k] - ROM[j]) != RelativeAnchors[i][k]) - { - // It doesn't, break. - Match = false; - break; - } - } - else - { - // Out of range before matching. - Match = false; - break; - } - } - - // If a match was found, update the dictionary. - if (Match) - { - int k = 0; - for (k = 0; k < Anchors[i].Length; k++) - { - if (!TranslationDictionary.ContainsKey(Anchors[i][k])) - { - TranslationDictionary.Add(Anchors[i][k], ROM[j + k]); - } - } - - // Move ahead to the correct location in the ROM. - j = j + k + 1; - } - else - { - // Move ahead one byte. - j = j + 1; - } - } - } - - // Calculate the offset to translate unknown text, assuming ASCII structure. - int ASCIIOffset = 0; - if (TranslationDictionary.Count > 0) - { - ASCIIOffset = TranslationDictionary.First().Value - TranslationDictionary.First().Key; - } - - // Create arrays of the text to be replaced in ROM format. - byte[][] ByteTextToReplace = new byte[TextToReplace.Length][]; - for (int i = 0; i < TextToReplace.Length; i++) - { - ByteTextToReplace[i] = new byte[TextToReplace[i].Length]; - for (int j = 0; j < TextToReplace[i].Length; j++) - { - if (TranslationDictionary.ContainsKey(TextToReplace[i][j])) - { - ByteTextToReplace[i][j] = TranslationDictionary[TextToReplace[i][j]]; - } - else - { - int ASCIITranslated = TextToReplace[i][j] + ASCIIOffset; - if (ASCIITranslated >= Byte.MinValue && ASCIITranslated <= Byte.MaxValue) - { - ByteTextToReplace[i][j] = (byte)(ASCIITranslated); - } - else - { - // Could not translate. - ByteTextToReplace[i][j] = (byte)(TextToReplace[i][j]); - } - } - } - } - - // Create arrays of the replacement text in ROM format. - byte[][] ByteReplaceWith = new byte[ReplaceWith.Length][]; - for (int i = 0; i < ReplaceWith.Length; i++) - { - ByteReplaceWith[i] = new byte[ReplaceWith[i].Length]; - for (int j = 0; j < ReplaceWith[i].Length; j++) - { - if (TranslationDictionary.ContainsKey(ReplaceWith[i][j])) - { - ByteReplaceWith[i][j] = TranslationDictionary[ReplaceWith[i][j]]; - } - else - { - int ASCIITranslated = ReplaceWith[i][j] + ASCIIOffset; - if (ASCIITranslated >= Byte.MinValue && ASCIITranslated <= Byte.MaxValue) - { - ByteReplaceWith[i][j] = (byte)(ASCIITranslated); - } - else - { - // Could not translate. - ByteReplaceWith[i][j] = (byte)(ReplaceWith[i][j]); - } - } - } - } - - // Area of ROM to consider. - long TextReplacementStartByte = 0; - long TextReplacementEndByte = ROM.LongLength - 1; - - // Change area if using the byte corruption range. - if (checkBox_TextUseByteCorruptionRange.Checked) - { - TextReplacementStartByte = StartByte; - TextReplacementEndByte = EndByte; - } - - // Look for the text to replace. - for (int i = 0; i < ByteTextToReplace.Length; i++) - { - // Position in ROM. - long j = TextReplacementStartByte; - - // Scan the entire ROM. - while (j <= TextReplacementEndByte) - { - // If a match has been found. - bool Match = true; - - // Look for the text. - for (int k = 0; k < ByteTextToReplace[i].Length; k++) - { - // Make sure its in range. - if (j + k <= TextReplacementEndByte) - { - // Ignore non-letter characters for matching purposes. - if (!Char.IsLetter(TextToReplace[i][k])) - { - continue; - } - - // Check if the relative value doesn't match. - if (ROM[j + k] != ByteTextToReplace[i][k]) - { - // It doesn't, break. - Match = false; - break; - } - } - else - { - // Out of range before matching. - Match = false; - break; - } - } - - // If the entire string matched, replace it. - if (Match) - { - // If the area is protected. - bool Protected = false; - - // Length of the replacement. - int k = ByteReplaceWith[i].Length - 1; - - // Check if the area is protected. - foreach (long[] ProtectedRegion in ProtectedRegions) - { - if ((j >= ProtectedRegion[0] && j <= ProtectedRegion[1]) || (j + k >= ProtectedRegion[0] && j + k <= ProtectedRegion[1]) || (j < ProtectedRegion[0] && j + k > ProtectedRegion[1])) - { - // Yes, its protected. - Protected = true; - break; - } - } - - // If not protected, replace the text. - if (!Protected) - { - for (k = 0; k < ByteReplaceWith[i].Length; k++) - { - ROM[j + k] = ByteReplaceWith[i][k]; - } - - // Protect the inserted text. - ProtectedRegions.Add(new long[2] { j, j + k }); - } - - // Move ahead to the correct location in the ROM. - j = j + k + 1; - } - else - { - // Move ahead one byte. - j = j + 1; - } - } - } - } - - // Do color replacement if desired. - if (checkBox_ColorReplacementEnable.Checked) - { - // Read in the text and its replacement. - string[] ColorsToReplace = textBox_ColorsToReplace.Text.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); - string[] ColorsReplaceWith = textBox_ReplaceWithColors.Text.Split(Delimeter, StringSplitOptions.RemoveEmptyEntries); - - // Make sure they have equal length. - if (ColorsToReplace.Length != ColorsReplaceWith.Length) - { - MessageBox.Show("Number of colors to replace does not match number of replacements.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - // Convert the strings. - byte[] ColorsToReplaceBytes = new byte[ColorsToReplace.Length]; - byte[] ColorsReplaceWithBytes = new byte[ColorsReplaceWith.Length]; - for (int i = 0; i < ColorsToReplace.Length; i++) - { - try - { - byte Converted = Convert.ToByte(ColorsToReplace[i], 16); - ColorsToReplaceBytes[i] = Converted; - } - catch - { - MessageBox.Show("Invalid color to replace.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Previous error encountered corrupting using \"" + Entry[0] + "\" corruption settings in queue.", + "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + StringToCorruptionSettings(Enumerable.Last(QueueForm.CorruptionQueue)[1]); + QueueForm.CorruptionQueue.RemoveAt(QueueForm.CorruptionQueue.Count - 1); return; } } - for (int i = 0; i < ColorsReplaceWithBytes.Length; i++) - { - try - { - byte Converted = Convert.ToByte(ColorsReplaceWith[i], 16); - ColorsReplaceWithBytes[i] = Converted; - } - catch - { - MessageBox.Show("Invalid color replacement.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - } - - // Area of ROM to consider. - long ColorReplacementStartByte = 0; - long ColorReplacementEndByte = ROM.LongLength - 1; - - // Change area if using the byte corruption range. - if (checkBox_ColorUseByteCorruptionRange.Checked) - { - ColorReplacementStartByte = StartByte; - ColorReplacementEndByte = EndByte; - } - - // Position in ROM. - long j = ColorReplacementStartByte; - - // Scan the entire ROM. - while (j <= ColorReplacementEndByte) - { - // If a palette has been found. - bool Palette = true; - - // Look for a palette. - for (int k = 0; k < 4; k++) - { - // Make sure its in range. - if (j + k <= ColorReplacementEndByte) - { - // Check if value exceeds the maximum valid color value. - if (ROM[j + k] > 0x3F) - { - // It does, break. - Palette = false; - break; - } - } - else - { - // Out of range before matching. - Palette = false; - break; - } - } - - // If a possible palette was found, do color replacement. - if (Palette) - { - for (int i = 0; i < ColorsToReplaceBytes.Length; i++) - { - for (int k = 0; k < 4; k++) - { - if (ROM[j + k] == ColorsToReplaceBytes[i]) - { - // If the byte is protected. - bool Protected = false; - - // Check if the byte is protected. - foreach (long[] ProtectedRegion in ProtectedRegions) - { - if (j + k >= ProtectedRegion[0] && j + k <= ProtectedRegion[1]) - { - // Yes, its protected. - Protected = true; - break; - } - } - - // If its not protected, do the replacement. - if (!Protected) - { - ROM[j + k] = ColorsReplaceWithBytes[i]; - ProtectedRegions.Add(new long[2] { j + k, j + k }); - } - } - } - } - - // Move ahead to the correct location in the ROM. - j = j + 4; - } - else - { - // Move ahead one byte. - j = j + 1; - } - } + StringToCorruptionSettings(Enumerable.Last(QueueForm.CorruptionQueue)[1]); + QueueForm.CorruptionQueue.RemoveAt(QueueForm.CorruptionQueue.Count - 1); } - - // Do byte corruption if desired. - if (checkBox_ByteCorruptionEnable.Checked) + else { - if (radioButton_AddXToByte.Checked && AddXtoByte != 0) + ROM = Corrupt(ROM); + if (ROM == null) { - for (long i = StartByte + EveryNthByte; i <= EndByte; i = i + EveryNthByte) - { - // If the byte is protected. - bool Protected = false; - - // Check if the byte is protected. - foreach (long[] ProtectedRegion in ProtectedRegions) - { - if (i >= ProtectedRegion[0] && i <= ProtectedRegion[1]) - { - // Yes, its protected. - Protected = true; - break; - } - } - - // Do NES CPU jam protection if desired. - if (checkBox_EnableNESCPUJamProtection.Checked) - { - if (!Protected && i >= 2) - { - if (NESCPUJamProtection_Avoid.Contains((byte)((ROM[i] + AddXtoByte) % (Byte.MaxValue + 1))) - || NESCPUJamProtection_Protect_1.Contains(ROM[i]) - || NESCPUJamProtection_Protect_2.Contains(ROM[i - 1]) - || NESCPUJamProtection_Protect_3.Contains(ROM[i - 2])) - { - Protected = true; - } - } - } - - // If the byte is not protected, corrupt it. - if (!Protected) - { - int NewValue = (ROM[i] + AddXtoByte) % (Byte.MaxValue + 1); - ROM[i] = (byte)NewValue; - } - } - } - else if (radioButton_ShiftRightXBytes.Checked && ShiftRightXBytes != 0) - { - for (long i = StartByte + EveryNthByte; i <= EndByte; i = i + EveryNthByte) - { - long j = i + ShiftRightXBytes; - - if (j >= StartByte && j <= EndByte) - { - // If the byte is protected. - bool Protected = false; - - // Check if the byte is protected. - foreach (long[] ProtectedRegion in ProtectedRegions) - { - if (j >= ProtectedRegion[0] && j <= ProtectedRegion[1]) - { - // Yes, its protected. - Protected = true; - break; - } - } - - // Do NES CPU jam protection if desired. - if (checkBox_EnableNESCPUJamProtection.Checked) - { - if (!Protected && j >= 2) - { - if (NESCPUJamProtection_Avoid.Contains(ROM[i]) - || NESCPUJamProtection_Protect_1.Contains(ROM[j]) - || NESCPUJamProtection_Protect_2.Contains(ROM[j - 1]) - || NESCPUJamProtection_Protect_3.Contains(ROM[j - 2])) - { - Protected = true; - } - } - } - - // If the byte is not protected, corrupt it. - if (!Protected) - { - ROM[j] = ROM[i]; - } - } - } - } - else if (radioButton_ReplaceByteXwithY.Checked && ReplaceByteXwithYByteX != ReplaceByteXwithYByteY) - { - for (long i = StartByte + EveryNthByte; i <= EndByte; i = i + EveryNthByte) - { - if (ROM[i] == ReplaceByteXwithYByteX) - { - // If the byte is protected. - bool Protected = false; - - // Check if the byte is protected. - foreach (long[] ProtectedRegion in ProtectedRegions) - { - if (i >= ProtectedRegion[0] && i <= ProtectedRegion[1]) - { - // Yes, its protected. - Protected = true; - break; - } - } - - // If the byte is not protected, corrupt it. - if (!Protected) - { - ROM[i] = ReplaceByteXwithYByteY; - } - } - } + return; } } @@ -1365,7 +801,7 @@ namespace Vinesauce_ROM_Corruptor UriBuilder ub = new UriBuilder(); ub.Host = "tinyurl.com"; ub.Path = "/api-create.php"; - ub.Query = "url=" + SettingsToString(); + ub.Query = "url=" + FileSettingsToString() + CorruptionSettingsToString() + QueueSettingsToString(); response = wc.DownloadString(ub.Uri); } catch @@ -1424,7 +860,7 @@ namespace Vinesauce_ROM_Corruptor StreamWriter sw = new StreamWriter(fDialog.FileName); // Write the settings to the file. - sw.Write(SettingsToString()); + sw.Write(FileSettingsToString() + CorruptionSettingsToString() + QueueSettingsToString()); // Close the file. sw.Close(); @@ -1476,7 +912,9 @@ namespace Vinesauce_ROM_Corruptor text = Uri.UnescapeDataString(text); // Load the settings. - StringToSettings(text); + StringToFileSettings(text); + StringToCorruptionSettings(text); + StringToQueueSettings(text); EnforceAutoEnd(); } catch @@ -1499,7 +937,10 @@ namespace Vinesauce_ROM_Corruptor try { // Load the settings from the file. - StringToSettings(File.ReadAllText(fDialog.FileName)); + string text = File.ReadAllText(fDialog.FileName); + StringToFileSettings(text); + StringToCorruptionSettings(text); + StringToQueueSettings(text); EnforceAutoEnd(); } catch @@ -1534,7 +975,7 @@ namespace Vinesauce_ROM_Corruptor "Replace Byte X with Y Help"); } - private string SettingsToString() + private string FileSettingsToString() { StringBuilder sb = new StringBuilder(); @@ -1544,6 +985,13 @@ namespace Vinesauce_ROM_Corruptor sb.AppendLine("ROM.FileLength=" + String.Format("{0:X}", SelectedROM.FileLength)); sb.AppendLine("ROM.Hash=" + SelectedROM.HashStringBase64); + return sb.ToString(); + } + + private string CorruptionSettingsToString() + { + StringBuilder sb = new StringBuilder(); + // General settings. sb.AppendLine("checkBox_EnableNESCPUJamProtection.Checked=" + checkBox_EnableNESCPUJamProtection.Checked.ToString()); @@ -1578,9 +1026,26 @@ namespace Vinesauce_ROM_Corruptor return sb.ToString(); } - private void StringToSettings(string text) + private string QueueSettingsToString() { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("checkBox_QueueEnable.Checked=" + checkBox_QueueEnable.Checked.ToString()); + + foreach (string[] Entry in QueueForm.CorruptionQueue) + { + + sb.AppendLine("Queue_Entry_Start"); + sb.AppendLine("Identifier=" + Entry[0]); + sb.Append(Entry[1]); + sb.AppendLine("Queue_Entry_End"); + } + + return sb.ToString(); + } + + private void StringToFileSettings(string text) + { // ROM to corrupt. string TargetROMFileName = ""; long TargetROMFileLength = 0; @@ -1631,10 +1096,13 @@ namespace Vinesauce_ROM_Corruptor "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } + } + public void StringToCorruptionSettings(string text) + { // Enable checkboxes. // Text replacement. - m = Regex.Match(text, "(?<=checkBox_TextReplacementEnable\\.Checked=).*?(?=\r)"); + Match m = Regex.Match(text, "(?<=checkBox_TextReplacementEnable\\.Checked=).*?(?=\r)"); if (m.Success) { if (m.Groups[0].Value == "True") @@ -1854,6 +1322,38 @@ namespace Vinesauce_ROM_Corruptor } } + public void StringToQueueSettings(string text) + { + Match m = Regex.Match(text, "(?<=checkBox_QueueEnable\\.Checked=).*?(?=\r)"); + if (m.Success) + { + if (m.Groups[0].Value == "True") + { + checkBox_QueueEnable.Checked = true; + } + else + { + checkBox_QueueEnable.Checked = false; + } + } + + QueueForm.CorruptionQueue.Clear(); + MatchCollection entries = Regex.Matches(text, "(?<=Queue_Entry_Start\r\n).*?(?=Queue_Entry_End\r\n)", RegexOptions.Singleline); + foreach (Match entry in entries) + { + if (entry.Success) + { + string id = ""; + m = Regex.Match(entry.Groups[0].Value, "(?<=Identifier=).*?(?=\r)"); + if (m.Success) + { + id = m.Groups[0].Value; + } + QueueForm.CorruptionQueue.Add(new string[] { id, entry.Groups[0].Value }); + } + } + } + private void button_UseTinyURLHelp_Click(object sender, EventArgs e) { button_Run.Focus(); @@ -1967,7 +1467,7 @@ namespace Vinesauce_ROM_Corruptor listView_Files.Focus(); if (item.Index >= 4) { - listView_Files.TopItem = listView_Files.Items[item.Index-4]; + listView_Files.TopItem = listView_Files.Items[item.Index - 4]; } item.Selected = true; break; @@ -2006,5 +1506,148 @@ namespace Vinesauce_ROM_Corruptor EnforceAutoEnd(); } } + + private void button_QueueHelp_Click(object sender, EventArgs e) + { + button_Run.Focus(); + MessageBox.Show("Checking this box enables queue mode, which allows for multiple corruptions to be executed on the file sequentially. This allows corruption of multiple byte ranges among other things. " + + "When the \"Add\" button is clicked, the current corruption settings will be saved to the queue and you will be asked for an identifier for these settings. " + + "When the \"Manage\" button is clicked a new window will appear which will allow you to move corruption settings up and down in the queue, remove corruption settings from the queue, " + + "or overwrite the current settings with a set of queued settings. The corruption settings at the top of the queue list will be executed first, and the current corruption settings will be executed last. " + + "For example, one item in the queue means the ROM is corrupted twice, first using the queued settings and then using the current settings." + , "Queue Help"); + } + + private void button_QueueAdd_Click(object sender, EventArgs e) + { + // Get an identifier of the corruption settings from the user. + string name = Interaction.InputBox("Please enter a brief description of these corruption settings below.", "Add to Queue", ""); + if (name == "") + { + MessageBox.Show("No description entered, addition to queue aborted.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + QueueForm.CorruptionQueue.Add(new string[] { name, CorruptionSettingsToString() }); + } + + private void checkBox_QueueEnable_CheckedChanged(object sender, EventArgs e) + { + button_QueueAdd.Enabled = checkBox_QueueEnable.Checked; + button_QueueManage.Enabled = checkBox_QueueEnable.Checked; + } + + private void button_QueueManage_Click(object sender, EventArgs e) + { + QueueForm form = new QueueForm(this); + form.StartPosition = FormStartPosition.CenterParent; + form.ShowDialog(); + while (form.Visible == true) + this.Enabled = false; + } + + private byte[] Corrupt(byte[] ROM) + { + // Read in all of the text boxes. + long StartByte; + try + { + StartByte = Convert.ToInt64(textBox_StartByte.Text, 16); + } + catch + { + MessageBox.Show("Invalid start byte.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + + long EndByte; + try + { + EndByte = Convert.ToInt64(textBox_EndByte.Text, 16); + } + catch + { + MessageBox.Show("Invalid end byte.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + + uint EveryNthByte; + try + { + EveryNthByte = Convert.ToUInt32(textBox_EveryNBytes.Text); + } + catch + { + MessageBox.Show("Invalid byte corruption interval.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + if (EveryNthByte == 0) + { + MessageBox.Show("Invalid byte corruption interval.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + + int AddXtoByte; + try + { + AddXtoByte = Convert.ToInt32(textBox_AddXToByte.Text); + } + catch + { + MessageBox.Show("Invalid byte addition value.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + + int ShiftRightXBytes; + try + { + ShiftRightXBytes = Convert.ToInt32(textBox_ShiftRightXBytes.Text); + } + catch + { + MessageBox.Show("Invalid right shift value.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + + byte ReplaceByteXwithYByteX; + try + { + ReplaceByteXwithYByteX = Convert.ToByte(textBox_ReplaceByteXwithYByteX.Text, 16); + } + catch + { + MessageBox.Show("Invalid byte to match.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + + byte ReplaceByteXwithYByteY; + try + { + ReplaceByteXwithYByteY = Convert.ToByte(textBox_ReplaceByteXwithYByteY.Text, 16); + } + catch + { + MessageBox.Show("Invalid byte replacement.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + + // Limit the end byte. + if (EndByte > (ROM.LongLength - 1)) + { + EndByte = ROM.LongLength - 1; + } + + // Set byte corruption option. + Corruption.ByteCorruptionOptions ByteCorruptionOption = Corruption.ByteCorruptionOptions.AddXToByte; + if (radioButton_ShiftRightXBytes.Checked) ByteCorruptionOption = Corruption.ByteCorruptionOptions.ShiftRightXBytes; + else if (radioButton_ReplaceByteXwithY.Checked) ByteCorruptionOption = Corruption.ByteCorruptionOptions.ReplaceByteXwithY; + + // Corrupt. + ROM = Corruption.Run(ROM, checkBox_ByteCorruptionEnable.Checked, StartByte, EndByte, ByteCorruptionOption, + EveryNthByte, AddXtoByte, ShiftRightXBytes, ReplaceByteXwithYByteX, ReplaceByteXwithYByteY, checkBox_EnableNESCPUJamProtection.Checked, + checkBox_TextReplacementEnable.Checked, checkBox_TextUseByteCorruptionRange.Checked, textBox_TextToReplace.Text, textBox_ReplaceWith.Text, textBox_AnchorWords.Text, + checkBox_ColorReplacementEnable.Checked, checkBox_ColorUseByteCorruptionRange.Checked, textBox_ColorsToReplace.Text, textBox_ReplaceWithColors.Text); + + return ROM; + } } } diff --git a/src/Vinesauce ROM Corruptor/QueueForm.Designer.cs b/src/Vinesauce ROM Corruptor/QueueForm.Designer.cs new file mode 100644 index 0000000..eb8e1bc --- /dev/null +++ b/src/Vinesauce ROM Corruptor/QueueForm.Designer.cs @@ -0,0 +1,147 @@ +namespace Vinesauce_ROM_Corruptor +{ + partial class QueueForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(QueueForm)); + this.listView_Queue = new System.Windows.Forms.ListView(); + this.listViewC_Identifier = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.button_Up = new System.Windows.Forms.Button(); + this.button_Down = new System.Windows.Forms.Button(); + this.button_Remove = new System.Windows.Forms.Button(); + this.button_Overwrite = new System.Windows.Forms.Button(); + this.button_Close = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // listView_Queue + // + this.listView_Queue.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.listViewC_Identifier}); + this.listView_Queue.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.listView_Queue.FullRowSelect = true; + this.listView_Queue.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.listView_Queue.HideSelection = false; + this.listView_Queue.Location = new System.Drawing.Point(12, 74); + this.listView_Queue.Margin = new System.Windows.Forms.Padding(2); + this.listView_Queue.MultiSelect = false; + this.listView_Queue.Name = "listView_Queue"; + this.listView_Queue.Size = new System.Drawing.Size(258, 183); + this.listView_Queue.TabIndex = 48; + this.listView_Queue.UseCompatibleStateImageBehavior = false; + this.listView_Queue.View = System.Windows.Forms.View.Details; + // + // listViewC_Identifier + // + this.listViewC_Identifier.Text = "Identifier"; + this.listViewC_Identifier.Width = 254; + // + // button_Up + // + this.button_Up.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.button_Up.Location = new System.Drawing.Point(12, 42); + this.button_Up.Name = "button_Up"; + this.button_Up.Size = new System.Drawing.Size(75, 23); + this.button_Up.TabIndex = 49; + this.button_Up.Text = "Move Up"; + this.button_Up.UseVisualStyleBackColor = true; + this.button_Up.Click += new System.EventHandler(this.button_Up_Click); + // + // button_Down + // + this.button_Down.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.button_Down.Location = new System.Drawing.Point(93, 42); + this.button_Down.Name = "button_Down"; + this.button_Down.Size = new System.Drawing.Size(96, 23); + this.button_Down.TabIndex = 50; + this.button_Down.Text = "Move Down"; + this.button_Down.UseVisualStyleBackColor = true; + this.button_Down.Click += new System.EventHandler(this.button_Down_Click); + // + // button_Remove + // + this.button_Remove.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.button_Remove.Location = new System.Drawing.Point(195, 42); + this.button_Remove.Name = "button_Remove"; + this.button_Remove.Size = new System.Drawing.Size(75, 23); + this.button_Remove.TabIndex = 51; + this.button_Remove.Text = "Remove"; + this.button_Remove.UseVisualStyleBackColor = true; + this.button_Remove.Click += new System.EventHandler(this.button_Remove_Click); + // + // button_Overwrite + // + this.button_Overwrite.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.button_Overwrite.Location = new System.Drawing.Point(12, 12); + this.button_Overwrite.Name = "button_Overwrite"; + this.button_Overwrite.Size = new System.Drawing.Size(224, 23); + this.button_Overwrite.TabIndex = 52; + this.button_Overwrite.Text = "Load and Overwrite Current Settings"; + this.button_Overwrite.UseVisualStyleBackColor = true; + this.button_Overwrite.Click += new System.EventHandler(this.button_Overwrite_Click); + // + // button_Close + // + this.button_Close.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.button_Close.Location = new System.Drawing.Point(12, 262); + this.button_Close.Name = "button_Close"; + this.button_Close.Size = new System.Drawing.Size(75, 23); + this.button_Close.TabIndex = 53; + this.button_Close.Text = "Close"; + this.button_Close.UseVisualStyleBackColor = true; + this.button_Close.Click += new System.EventHandler(this.button_Close_Click); + // + // QueueForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(282, 290); + this.Controls.Add(this.button_Close); + this.Controls.Add(this.button_Overwrite); + this.Controls.Add(this.button_Remove); + this.Controls.Add(this.button_Down); + this.Controls.Add(this.button_Up); + this.Controls.Add(this.listView_Queue); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "QueueForm"; + this.Text = "Manage Queue"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listView_Queue; + private System.Windows.Forms.ColumnHeader listViewC_Identifier; + private System.Windows.Forms.Button button_Up; + private System.Windows.Forms.Button button_Down; + private System.Windows.Forms.Button button_Remove; + private System.Windows.Forms.Button button_Overwrite; + private System.Windows.Forms.Button button_Close; + + } +} \ No newline at end of file diff --git a/src/Vinesauce ROM Corruptor/QueueForm.cs b/src/Vinesauce ROM Corruptor/QueueForm.cs new file mode 100644 index 0000000..a117b09 --- /dev/null +++ b/src/Vinesauce ROM Corruptor/QueueForm.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace Vinesauce_ROM_Corruptor +{ + public partial class QueueForm : Form + { + static public List CorruptionQueue = new List(); + + public MainForm MainWindow; + + public QueueForm(MainForm MainWindow) + { + InitializeComponent(); + + this.MainWindow = MainWindow; + + PopulateQueueList(); + } + + private void button_Close_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void button_Up_Click(object sender, EventArgs e) + { + if (listView_Queue.SelectedIndices.Count == 0) + { + return; + } + + int index = listView_Queue.SelectedIndices[0]; + if (index == 0) + { + return; + } + + string[] temp = CorruptionQueue[index - 1]; + CorruptionQueue[index - 1] = CorruptionQueue[index]; + CorruptionQueue[index] = temp; + + PopulateQueueList(); + + listView_Queue.Items[index - 1].Selected = true; + } + + private void button_Down_Click(object sender, EventArgs e) + { + if (listView_Queue.SelectedIndices.Count == 0) + { + return; + } + + int index = listView_Queue.SelectedIndices[0]; + if (index == listView_Queue.Items.Count - 1) + { + return; + } + + string[] temp = CorruptionQueue[index + 1]; + CorruptionQueue[index + 1] = CorruptionQueue[index]; + CorruptionQueue[index] = temp; + + PopulateQueueList(); + + listView_Queue.Items[index + 1].Selected = true; + } + + private void PopulateQueueList() + { + listView_Queue.Items.Clear(); + listView_Queue.Focus(); + foreach (string[] Entry in CorruptionQueue) + { + listView_Queue.Items.Add(new ListViewItem(new string[] { Entry[0] })); + } + } + + private void button_Remove_Click(object sender, EventArgs e) + { + if (listView_Queue.SelectedIndices.Count == 0) + { + return; + } + + int index = listView_Queue.SelectedIndices[0]; + CorruptionQueue.RemoveAt(index); + + PopulateQueueList(); + } + + private void button_Overwrite_Click(object sender, EventArgs e) + { + if (listView_Queue.SelectedIndices.Count == 0) + { + return; + } + + if (MessageBox.Show("The current corruption settings will be overwritten, are you sure you wish to do this?", + "Confirm Overwrite", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) + { + int index = listView_Queue.SelectedIndices[0]; + string[] entry = CorruptionQueue[index]; + MainWindow.StringToCorruptionSettings(entry[1]); + this.Close(); + } + } + } +} diff --git a/src/Vinesauce ROM Corruptor/QueueForm.resx b/src/Vinesauce ROM Corruptor/QueueForm.resx new file mode 100644 index 0000000..8e94086 --- /dev/null +++ b/src/Vinesauce ROM Corruptor/QueueForm.resx @@ -0,0 +1,659 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAQAEBAAAAAAIABoBAAARgAAACAgAAAAACAAqBAAAK4EAAAwMAAAAAAgAKglAABWFQAAQEAAAAAA + IAAoQgAA/joAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAD////b//////// + /////////v7+//39/f/n5+f/1tbW/9fX1//y8vL//v7+//7+/v/////////////////////b////2/// + //////////////z8/P/g4OD/7+/v//r6+v/29vb/19fX/8bGxv/+/v7/////////////////////2/// + /9v//////////////////////v7+//Hx8f/Nzc3/6urq//7+/v/Y2Nj//v7+//////////////////// + /9v////b//////////////////////7+/v/U2sD//v79/9bbwf/9/fr/2NjX//7+/v////////////// + ///////b////2//////////////////////+/v7/vtC0//z+/P/A0rj/+fz5/9jY1//+/v7///////// + ////////////2////9v//v///v7+//3+/f/8+/r/7Ovl/9fZzf/Q0Mb/0NLF/93e1f/j4+H//f38//7+ + /v///////////////9v+/v7b9/f3/+Df4f/d3d3/n6lN/4aWCf+InQX/i58D/4ygBP+HmQX/gZEV/8TG + u//IyMf/2dnZ//39/f/+/v7b5ejW2+Xm3P/6+/L/yteP/4umB/+MqBD/vMx1/7O/bv/I04r/lbAo/4mm + Bf+wxWH/9ffq/+np5f+tsp///v7+28TUj9uMqyb/i6wp/4eqGv+KrCT/4+rG/+boz/9/iQ7/xcmR//T3 + 6/+ZuEX/hKsp/4atNP+MsUT/haJL//7+/tvY5MHbha8//4OvPf+Brz3/s8yG//38+v+ztl3/mZ4i/56k + Lf/09Of/0uK+/3yvQ/9+sEb/f7JM/5m0ef/+/v7b9vrx24a2Yf+Atlr/f7dd/7/ar//t7tj/u7lY/+Hh + t/++vV//29mp/+Lv3f93tV3/drVe/3a4Zf+8z7T///7+2/79/dvO5cj/sdat/4jBgv+czp7/5+bC/+np + x//9/v3/8/Pf/9/crf/C4cX/bLxz/5/RoP/H3cb/8vTy//7+/tv//v7b/v7+//7+/v/y+vT/jtGo/7/k + y//7/v3//v7+//3+/f/b8uP/ds2g/6vewP/5/Pv/8/Ly//7+/v/+/v7b////2/7+/v/+/v7//v7+/9nz + 6f9k0Kv/fti6/57kz/+P38v/Z9W3/2rWuf/v+ff/9vf2//7+/v//////////2////9v///////////7+ + /v/0/fz/etzJ/1TUu/9R18D/U9jC/2bdyv+j6N3/9/v7//39/v///////////////9v////b//////// + ///+/v7//v7+//r+/v/x/Pv/4vj2/+v7+f/5/v3//f7+//7+/v/+///////////////////bAAD//wAA + //8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//ygA + AAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAD///+3//////////////////////// + //////////////////////////////7+/v/+/v7//f39//7+/v/+/v7//v7+//7+/v/+/v7///////// + ////////////////////////////////////////////////////////////t////7f///////////// + //////////////////////////////7+/v/+/v7/+vr6/9/f3//BwcH/sLCw/6urq/+oqKj/urq6/9XV + 1f/19fX//v7+//7+/v/+/v7//v7+//////////////////////////////////////////+3////t/// + ////////////////////////////////////////9/f3/8XFxf/BwcH/1dXV/+/v7//5+fn//f39//f3 + 9//k5OT/xcXF/5ycnP+SkpL/4eHh//39/f/+/v7///////////////////////////////////////// + /7f///+3///////////////////////////////////////////7+/v//f39//39/f/9/f3//f39//b2 + 9v/9/f3//f39//7+/v/9/f3//v7+//Dw8P+0tLT//f39//7+/v////////////////////////////// + ////////////t////7f//////////////////////////////////////////////////////v7+//z8 + /P/w8PD/4eHh//7+/v/9/f3//f39//7+/v//////+Pj4/7i4uP/+/v7///////////////////////// + //////////////////////+3////t/////////////////////////////////////////////////// + ///+/v7//f39/9ra2v+oqKj/rq6u/7Gxsf/8/Pz//v7+///+///4+Pj/uLi4//7+/v////////////// + /////////////////////////////////7f///+3//////////////////////////////////////// + //////////////7+/v/7/Pf/8/Tp//79/v/+/v7//vz9//T35P/+/f3///7+//j39f+4uLf//v7+//// + ////////////////////////////////////////////t////7f///////////////////////////// + /////////////////////////v7+/9PYu/+PnmX//v35//3+/v/j59L/gpRS//r88f/+/v7/9/f3/7i4 + uP/+/v7///////////////////////////////////////////////+3////t/////////////////// + ///////////////////////////////////+/v7/w9K0/4KeZP/6/vj//f7+/87exf98mV3/8Pfu//7+ + /P/4+Pf/uLi4//7+/v/+/v7//////////////////////////////////////////7f///+3//////// + //////////////////////////////////////////////3+/v/o9e3/ytzL//z+/P/+/f7/8Pv1/8XV + yP/3/fz//v7+//j49f+4uLj//v7+//7+/v//////////////////////////////////////////t/// + /7f///////7////+//////7//v7+/////v/+//3//v3+//3+/P/9/v7//v3+//38/v/4/fn//vz8//38 + /f/7/vf//Pr9//3++v/9/f3/9/j5/8bHxv/+/v7//v78//7+/v///v7///////////////////////// + //////+3////t////////v////7//////v/9/fz//f39//v9+//++/3/9vTx/+Xl2//Ozb//u76n/6yv + lf+kpJD/oaON/6Kliv+pqZb/tLWm/8XHuP/d3db/8fDv//v7+v/9/Pz//vz+//7+/f////////////// + /////////////////7f///+3/////////v////7///7///v6/P/a2dv/vMC//7Gxlf+Bhi//e4kW/3+Q + DP+Glgn/i5sG/4ycBv+NnAf/jpwG/4uaB/+GlAf/gIsN/3Z8E/91fDf/mZiS/5ibnP/Jycr/+fj1//// + ////////////////////////////t/7+/rf9/f3//Pz8/+Tk5P/Ew8X/w8LD/+Hi4P/7+/j/vspw/46j + AP+QoAL/jaAB/4ihAv+HoQH/iKMB/4qiAf+LowH/jKUB/4ujAf+KogD/jaYB/42nCv/r7sr/8/X0/8bI + xP+Ylpj/mZmZ/8/Pz//5+fn//f39//7+/v////+3/v7+t+Hh4f/Ly8v/3t7d//z7/P/9/fz//f74/9zk + rf+NpRT/jaQC/4mjAf+IogD/hKAF/5OqKf+rv03/r8FU/6a3Rf+KpBb/hqMD/4ejAP+LpgH/jaUF/6S6 + Q//3+ub//f37//z8/f/y8vL/urq6/46Ojv+7u7v//v7+/////7f//fu3xNGU//Hy2P/9/fH//v70//P2 + 3f/F04T/iKUV/4mnBP+IpwL/gqQE/5y0O//e57X/+/3w/97hw/+UnVP/+vrr//b44//C0Ir/hagU/4Om + Bv+IqAr/h6cS/5+3Sv/h6b7/+vvw//7++P/7/PD/3+jA/46Xc//+/v7/////t/7997eSsjL/iqga/5av + Ov+YsUX/i60k/4iqEP+HqA//iKkS/4epEv+mvk//9/fk//z8/P/z8+b/g5Ap/3F+BP+2u37//vz5//38 + +//f5rz/iqoj/4SrFf+Hqx3/h6sh/4SrJ/+Sskf/mbZX/5O1Rv+DrCr/hZda//7+/v////+3//34t6K9 + Vf+IqiL/iaok/4SqHf+EqiH/hqgj/4itJP+EqyH/lbJK//X35//7/P3/+/33/6y0Yv+EjAb/hIsE/3+L + DP/i48D/+v36//r9+//W4q3/gast/4GsLf+CqDf/ga0t/4GrNf+DrTr/gq06/4CnO/+Nn2z//v7+//// + /7f+/fu3scd//4WuMv+Grjr/g641/4CrNP+CrzT/gK0z/4WsP//O3qX//f38//z++//k5cL/j5Ye/5WY + GP+QlxH/kZoO/6WsTP/7+vP/+/z+//r7+P+Wumb/e602/32uPf9+rzz/gK9D/4CvSf+Cs0j/g65I/6Kx + jv/+/v7/////t/z9/bfJ27D/hLBI/4OwR/+Fskb/g7JD/4KvSP+Ar0b/iK1Q//H25f/++/7//fz0/7a6 + Zv+jpC3/nqQs/6GnMv+jpSv/nqQv/9vdsP/+/vv//P38/7rVn/98sEv/fbNN/32xTf98sUv/fbRR/3uz + Tf9/qFX/wcq4//7+/v////+3/v79t+bx3P+CsVb/grRX/4O0VP+CtFH/f7NS/3y2VP+Ptmn/+fvy//z8 + /v/p6cr/sbBN/7WyRP+2uWP/4+Ow/66xRf+zs0D/vb9t//38+P/8/fz/zuHA/3i1Vf96s1r/e7NW/3i0 + Vv95tV7/drZc/3mkYP/o6+X///7//////7f+/f63+f71/5W8ef9/tlz/frhg/365ZP+CuWn/gLlm/4G6 + b//1+vD//P38/9XVnv/DwGb/w8Jq/+zsz//+/Pr/1dGb/8O/XP/DvWr/7+3T//n++v/G37z/drVh/3S4 + Y/90tWT/crlm/3K8af94t3H/k7KP//v8+v///v7/////t//+/rf8/f3/yeC+/4W4eP+Cunr/fLl1/3q7 + cf97uG//c7hx/9/v2//6+vL/1tKQ/9DQhv/q6Mj//v78//z+/f/7+/D/1taf/9TQif/m4rf/+vz8/6bQ + pP9vuWz/ab5o/225bf9+vHv/nc2Y/63Pq//Q29L//v39///+/v////+3//78t/77/v/4/vj/8v70/+35 + 7f/Y7tf/rNSq/36+gP9zv37/qdSs/+/z4P/b2Kf/7O3T//3++//9/f7//v77//7+/f/7+/H/5eLB/9zd + sv/r9+r/e8OL/2q9ff9uvnv/qNSw/+n56P/4/fn/2tzc//v7/P/+/P7//v7+/////7f//v23//3+//7+ + /v/+/v7//v3+//7+/v/5/vz/1u7Z/4DGmP93xY7/x+XI//f47f/7/vz//P7+//7+/v/+/v3//v79//39 + /v/9/Pn/5PPb/6HVsP9px47/Z8GL/7jgwf/0/vr//v39/+7t7v/y8PH//v79//7+/v/+/v7/////t/// + /7f///////////7+/v/+/v7////////////9/v3/0O7d/3LJm/97yZ//w+za//f+/P/+/f7//v3+//7+ + /v/6/v3//v38/+369P+f3sT/Z82i/2bKn/+Y2rr/9f75//z9/v/39/f/7u7u//39/f////////////// + //////+3////t//////+/v7//v7+//7+/v/+/v7///////79/v/8/fv/nN/F/2LOpP9qzaX/i9W7/7vr + 2//Y9u3/4Pnx/9X06/+x5db/fda6/2XTsv9m1bT/bNKy/9f07P/+/P7/+ff4/+zx8P/9/f3//v7+//// + /////////////////7f///+3/////////////////////////////////v7+//3+/f/R8+n/ZdC0/13U + sP9Z0qj/W86p/2DOrv9g0bH/XtG1/1bStv9Z1rb/YdW5/1zWu/953MT/7/37//n39//29vP//P79//// + ////////////////////////////t////7f////////////////////////////////+/f7/+/39/+f7 + 9/9q1L3/Vde4/1TTtP9R07f/UdW6/1TWvP9T17z/Vde+/1XZwf9T2cL/WNjC/43d0f/r9Pb/+fv5//v8 + /P/+/P7///////////////////////////////+3////t/////////////////////////////////3+ + ///+/v7/7/38/6/p4f953c3/WdbB/1HWwP9Q2cT/UdnH/1LZx/9T2cb/ZNzL/43k2f+67+n/7fz6//r+ + /v/+/v7//v7///7+/////////////////////////////////7f///+3//////////////////////// + /////////P7+//7+/v/+/f7//P3+//X+/v/t/fv/3Pj1/8vy7//D8u7/z/Tx/+T7+P/w/v3/+f7+//z+ + /v/7/v7//v7+//7+/v/+/////v//////////////////////////////////t////7f///////////// + ///////////////////+/v7//v7+//z////8/v7//P7+//7+/v/9/v7//P7///z+///7/v7//f7+//7+ + /v/+/v7//f7+//7+/v///v7///////7////+//////////////////////////////////+3AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAoAAAAMAAAAGAAAAABACAAAAAAAIAlAAAAAAAAAAAAAAAAAAAAAAAA////k////////////v7+//// + /////////v7+/////////////v7+/////////////v7+//7+/v///////v7+//7+/v/+/v7//v7+//7+ + /v/9/f3//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+///////+/v7//v7+//// + ///+/v7//v7+///////+/v7//v7+///////+/v7//v7+///////+/v7//v7+//////////+T////k/// + //////////////////////////////////////////////7+/v/////////////////+/v7///////// + ///+/v7//v7+//7+/v/+/v7//f39//7+/v/+/v7//v7+//39/f/+/v7//v7+//7+/v////////////// + ///+/v7///////////////////////////////////////////////////////////////////////// + //////+T////k/7+/v/+/v7//v7+///////+/v7///////7+/v///////v7+//7+/v/+/v7//v7+//7+ + /v/+/v7//v7+//39/f/19fX/19fX/7e3t/+cnJz/i4uL/4WFhf+BgYH/fHx8/4eHh/+dnZ3/uLi4/9zc + 3P/29vb//f39//7+/v/9/f3//v7+//7+/v///////v7+///////+/v7//v7+/////////////v7+//// + /////////v7+//////////+T////k/7+/v////////////////////////////////////////////// + ///////////////////6+vr/0dHR/6enp/+np6f/urq6/9TU1P/v7+//8/Pz//39/f/9/f3/9/f3/+jo + 6P/S0tL/t7e3/4eHh/9qamr/iYmJ/9LS0v/7+/v//f39//7+/v////////////7+/v////////////7+ + /v////////////7+/v////////////7+/v////+T////k/////////////////////////////////// + ///////////////////////////////////r6+v/19fX//f39//9/f3//f39//39/f/8/Pz//f39//z8 + /P/+/v7//v7+//7+/v/+/v7//v7+//39/f/09PT/x8fH/3Fxcf/g4OD//v7+//39/f////////////// + //////////////////////////////////////////////////////+T////k//////+/v7///////// + ///+/v7//v7+///////+/v7//v7+///////+/v7//v7+//7+/v/+/v7//v7+//7+/v/9/f3//f39//7+ + /v/9/f3/8vLy//n5+f/8/Pz//f39//7+/v/+/v7//f39//39/f/+/v7//f39/62trf/a2tr//Pz8//7+ + /v/+/v7//v7+///////+/v7//v7+/////////////v7+//7+/v/+/v7//v7+//////////+T/v7+k/// + /////////v7+//7+/v/////////////////+/v7////////////+/v7///////7+/v/+/v7///////// + ///+/v7/+/v7//39/f/z8/P/0NDQ//39/f///////f39//39/f/9/f3//f39//7+/v///////////66u + rv/b29v//v7+//7+/v////////////7+/v////////////7+/v////////////7+/v////////////7+ + /v/+/v6T////k////////////////////////////v7+//////////////////////////////////// + ///////////////////+/v7//f39//39/f/Nzc3/xcXF/+Tk5P/l5eX/5OTk//Dw8P/9/f3//f39//7+ + /v///////////66urv/b29v//v7+//////////////////////////////////////////////////// + //////////////////////+T////k//////+/v7////////////+/v7////////////+/v7//v7+//// + ///+/v7//v7+///////+/v7///////7+/v/+/v7//f39//39/P/Ozs7/nZ2d/6CgoP+goKD/n5+f/9TU + 1P/9/fz//v7+//7+/v/+/v7//v7+/66vrv/b29v//v7+///////+/v7//v7+///////+/v7//v7+//// + ///+/v7//v7+///////+/v7//v7+//////////+T////k/////////////////////////////////7+ + /v////////////7+/v////////////7+/v////////////7+/v/+/v7//P38//3+9//9/fj//v3+//7+ + /v/+/f7//vv///79+P/9/vL//vz9//7+/v/+/f7//v39/66vq//b29v//v7+///////+/v7///////// + ///+/v7////////////+/v7////////////+/v7//v7+//////////+T////k/////////////////// + /////////v7+///////////////////////////////////////////////////////+/v7//f32/7a9 + mf/V2r////78///9/v///v7///37/8vQsf/Dy6L//v73//7+/f///f7///39/66vrP/b29v//v7+//// + ///////////////////////////////////+/v7///////////////////////////////+T////k/7+ + /v/+/v7//v7+//7+/v/+/v7//v7+///////+/v7//v7+///////+/v7//v7+//7+/v/+/v7//v7+//7+ + /v/+/v7/7vHd/3aJQv+Somj//f71//38/v/9//7//f7x/4CSUf+BllH/9fjn//7+/f/+/v7//f3+/66u + rv/b29v//v7+///////+/v7//v7+//7+/v/+/v7//v7+/////////////v7+///////+/v7//v7+//// + //////+T////k//////////////////////////////////////+/v7//v7+/////////////v7+//7+ + /v////////////7+/v/+/v7/4uvX/3SSTP+HoGb/+P3z//7+/v/9/v7/8/3t/3aTU/9/m1v/6vPj//z+ + /v////z//v7+/66urv/a2tr//v7+///////////////////////////////////////+/v7///////// + //////////////////////+T////k////////////v7+/////////////v7+//////////////////// + ///////////////////////////////////8/v7/7Prv/4Gfdv+guJf/+v/6//7//v/+/v7/9f75/4+s + if+Qqof/7vny//v+/v////z////7/6+urf/b29v//v7+//7+/v////////////////////////////// + //////////////////////////////////////+T////k/7+/v/+/v7///////7+/v/+/v7//v7+//// + /////////v7+///////+/v7//v7+//7+/v///////v7+//7+/v/9/v7/+P78/9/v5f/q+O3//P77//78 + /v/+/f7/+P78/+Pw6v/m8ez/+P79//z+/v/+/v7//v78/6+vrf/b29v//v7+//7+/v/+/v7//v7+//// + ///+/v7//v7+///////+/v7//v7+//7+/v/+/v7//v7+//////////+T////k/////////////////7+ + /v/////////////////+/v7///////7+/v////7///7+///+/v/+/v7//v7+//7+/////v7//vz9//n8 + /f/3/fj//v37//75/v/8/f3/+f72//z9+//7+v3//f75//7+/P/+/P///v3+/7Gysf/b29v//v7+//7+ + /f////7///7+//7+/v////////////7+/v////////////7+/v////////////7+/v/+/v6T////k/// + ///////////////+/////v///v7+//7+/f/+/v3//f78//7+/P/9/vr//fz9//78/v/7/vb/+vz8//z6 + /v/+/f7//vz+//39/f/8/fr//v39//77/v/8/fz/+/73//79/P/9+/7//f39//z+/P/8/vz/+vz8/+js + 6f/09fb/+/v9//7++f/+/vn//v38//79/v/+/v7///////////////////////////////////////// + //////+T////k//////+/v7//v7+//7+/v/+/v7///////39/f/9/P3//f39//7+/v/4+/v//fz9//z1 + +//w7ef/4eDP/8nItv+xsZf/naGB/46Tb/+AhF//eHhZ/3V1Wf9zd1X/dHlS/3h6WP+AgWb/jY12/5ye + hv+ur5v/yMi7/+Hh2f/w7e//+vr3//z9/f/8+/7//fr+//7+/P/+/v3///////7+/v///////v7+//7+ + /v/+/v7//v7+//////////+T////k//////+/v7//////////v////7//v7+//79/v/+/f7//fz+/+zs + 7f/AxsP/q6qh/42JZP96eDv/cnoi/3SCFv96ig//gI8M/4WVDP+ImAj/iZkJ/4mYCv+KmQr/ipkJ/4qZ + Cf+Glgj/gZAH/32JDP92fRT/bGwY/2RnIv9qakj/gX55/5WWl//Ex8r/7u/x//7+9v/+/vv//v7+//// + ///+/v7//v7+///////+/v7//v7+//////////+T/v7+k/7+/v/+/v7//v7+//7+/f/+/v7//Pv8/+3s + 7v+9vL7/np6f/6+vsP/T1Nb/5ObG/5CkIf+OoQP/jqAE/46hAv+OoQH/jKEB/42hAf+OoAD/j6EA/5Gj + Af+SogH/kqIA/5SkAf+RogH/kKAC/4+gA/+PogL/j6MD/4uiBv+QpSj/5OXQ/8HCwf+QlpP/bnBx/317 + ff++vL3/8PDw//z8/P/+/v7//f39//7+/v/+/v7//v7+//////////+T/v7+k/z8/P/9/f3//v7+//Lz + 8f/MzMz/qqmr/7OytP/j4uP//f38//7+/P/+/vb/ytSG/4qhB/+QpAD/kKEB/4+gAv+MnwD/h6AD/4ah + Av+GogH/hqMA/4ejAP+IoQL/iaID/4qkAP+LpgH/i6YA/4mjAP+KogD/jKUB/46nAv+Npwv/2uKf//36 + /P/6/fr/+/33/93d2/+cm5z/b29v/4aGhv/Kysr/9fX1//39/f/9/f3//v7+//7+/v////+T/v7+k/39 + /f/s7Oz/v7+//7q7uf/W1tb/+vn7//z8/f/+/v3//f74//7+9P/l6rf/kqcn/4yiBf+NogH/i6QA/4mi + AP+JogD/hqEC/4WfBv+Dngn/iKUS/5GsG/+RqCD/i6EZ/4agCP+HpAP/iKUB/4mkAP+KowD/jaYA/4+n + Af+NpAn/l7Ar/+/0z//+/vf//f76//37/f/9/f3/9vb2/8rKyv+IiIj/b29v/7CwsP/u7u7//v7+//// + ///+/v6T//7/k/r79v/Fx7z/7u7r//38/f/9/Pz//v3+//79/v/9/fn//v7v/+Dov/+PqSb/iacD/4ql + AP+KpgD/hKMC/4SkAf+Eogf/iage/7bIa//j6rn/9PbZ/9bas//e4bj/8/XT/9virf+wwGn/h6Il/3+i + B/+BpAD/haUC/4qnAv+KpQX/h6YM/5qzQP/r8Mv//v70//39/f/9/f7//f39//z8/P/8/Pz/5ubk/5mb + kP+IiYX//f39///////+/v6T//3+k9nfu/+twWb/5um+//b44P/+/u7//v7w//n86P/p78T/uMlt/4yn + IP+Hpgf/iqcG/4qnBf+IpwT/g6YC/4SjEv+5ym//8/bY//3+9v/8/fn/7+/b/32KLv+Nl0D/9vXh//39 + +P/9/ff/8PPW/6jAWf+Cpw//gqcG/4amCv+IqQ3/iagV/4aoFP+Urjr/ydeR/+3y1f/7/O3//v70//79 + 9f/3+uX/3+m9/6K6Zf+EiW///f39//7+/v/+/v6T//3+k9njsP9/pQ7/iKYa/5ewNf+gtFL/pbZg/5ix + SP+KrCL/h6oP/4elDf+Gpwv/iakP/4imEv+Iqwz/hqkV/8vYiv/+/e///f37//78/v/5+O3/mqRV/25+ + A/9uegf/pqts//z88f/+/fr//f37//r67P+/zoH/haUc/4SpDf+FqhX/h6kc/4arFf+IqyD/gqgk/4yu + PP+bt1j/pr5s/6C4aP+YuE7/hKss/3ylIP+KkXH//v7+//7+/v/+/v6T/vv+k+PqwP+CpRn/hacR/4uq + HP+IqRv/hqkY/4SpFf+Hqxj/iaoZ/4uqGv+Hqxj/hqsY/4aqGf+HqSb/xNOO//789P/8+f3/+fv8//79 + +P/AxYn/eYcI/3qFAP95hAH/eocS/9TWqf/++/r/+/38//r8/f/5+vH/usx8/4OqG/+Erh//h60p/4Sp + KP+IqjX/g60o/4OtKv+EqzP/g6wv/4OvLf+Criz/hKw2/3qeMP+Rmnz//v7+///////+/v6T/v78k+/2 + 0f+IqTD/h6oh/4qrKf+Iqib/g6kf/4SrIv+DqST/hKgl/4mtKf+Hryf/g6wk/4OpKf+ovnD/+/3t//z7 + /v/6/f3/+/36/+rtx/+FkCD/ho4H/4iMB/+GjQX/gI0C/42WMP/09dj//P35//j++//7/vv//P7p/5m1 + Xv9/qy7/ga0u/32oLv+BqDr/g7Ax/36rLv+BrTb/gqw7/4KtP/+CrT//f6c8/3aaOP+iro///v7+//7+ + /v////+T//79k/r95f+LqkX/hK0q/4mvN/+IsDf/hrAz/3+pLv+BqzP/ga0x/4CvKv+BrTL/gqs3/4ir + Q//j8ML//f76//v9/f/8/vz//fzx/6yzY/+KkxP/kZQV/5GWEP+OlA3/j5gI/4qVEP+/wn7//fz0//v9 + /v/7/f7//Pz8/9PivP9/qkH/e60y/3yuNf99rTr/f7A3/4CvO/+BsD7/f65D/4OySP+CskX/gq9F/3SV + Qv+5w67//v7+///////+/v6T/fv/k/z99v+btW//ha5A/4SuQf+DrUH/hK1B/4OuPv+Crz3/hLJA/4Ct + Pv+BrT//h69I/568bf/8/ur//vv+//78/v/9/vb/4uK5/5efMf+dnyX/m58j/5igHf+Xnhz/mp4a/5me + Hf+YoDX/6+vO//77/v/9/vz//Pz9/+/36f+Ks1z/fK9A/3yuR/99r0X/fa5J/3+tTP98rUr/f7BT/36x + T/9/tEv/g7NM/3GQS//Y3tL//v7+//////////+T/f7+k/v++f+40Jj/g7BK/4OxSf+Eskn/hbNI/4Oy + RP+Dskb/grBJ/4CuTf9+sEb/ha9L/7rNm//9/fv//vv+//78/v/7++v/trhr/6OmMf+ppzH/oqcw/6Cn + OP+kqDj/pacw/6SnLf+hqDX/vsN3//799f/+/vr//f77//j9+P+lxoL/e7BK/32zVP99tE3/fbNN/3uy + S/98tEr/frZR/3m0Tf97tE//g7FY/3eQXv/t8Oz//v7+//////////+T/v78k/7+/v/S48D/grBU/4Cz + Uv+CtFT/hLRS/3+vTP+Cs1D/fbJP/320Uv98tVL/ha9b/8vbsf/+/vv//f3+//36/P/n6MH/qqxK/7Ov + Qv+xrz3/p6xE/9TVmf/NzYf/q7A+/66vPP+vsD7/q7JL//Py2//+/f3//f38//38/f+10aD/d7NQ/3e0 + WP99s1j/fbRU/3SyUP96s1P/fLVb/3i1XP93t1f/e65b/5Clfv/8+/v//v7+///////+/v6T//7+k/3+ + /f/x++f/irNn/4O1W/+Bs1v/gbRa/4O3W/+Ct1v/g7dd/4G2XP99uFv/fbNg/8jgtP/+/vz/+/z+//z+ + 9f/Ky5H/vbpf/765U/+7u1X/wMN4//v66f/39eD/u7xu/7u3Tf++u0v/uLdW/9LPpP/+/vj/+f75//n+ + /P+41ab/e7Zc/3a1X/96tGD/e7Rf/3e0X/92uGH/c7dj/3K3Zf91tWj/fKlw/7nLtf/9+/3///7///// + ///+/v6T//3+k/7+/P/3/vX/p8aS/4K1Xv9+uF3/f7tj/3u5ZP98uWj/grtt/4G4bP+Aumj/eLho/7XZ + qv/+/fz//Pz+//b44f/Gw33/xsJr/8PAY//Ix3v/7+7S//78/P/+/fv/6ebH/8W/cf/Hw2D/yMBq/8nG + hf/7+uj/+v75//b++f+qzJz/d7Rg/3K4Zf9zumX/crZk/3S5aP9xumf/c75q/3a8bf98tnf/ep54/+r0 + 6P/8/Pv//v7+//7+/v/+/v6T//3+k/7+/f/5/fz/2e3Q/4a2cP98tmr/e7hv/3q5cf94uG//erpw/3q5 + b/99uG7/crlu/5vKlv/7/ff//fv9/+boxP/TzYP/0tF//83Mhv/t6sz//v76//3+/f/8/v7//v73/+Xi + uv/JyYH/0cuC/9DNgf/x7ND//fz9/+z68f+SwIr/dLhq/2q7aP9ovGT/a7pp/3C6bf95unX/fbh2/4zB + hf+awZf/qbyr//v++v///vz///7+//7+/v/+/v6T/v7+k/79/v/9/P7/9f3z/8Xhw/+83bz/tdi1/6bP + pf+Qwo3/gbt6/328dP95unT/cbx2/3y3f//o+Ob//P34/+Dhtv/b1ZX/0tSX/+vp0P/+/vf//v7+//3+ + /f/8//r//f78//398//o6cX/2Nak/93bmv/m5MD//vz8/9Tw3P98u4D/bLp0/2m/cv9ovm7/crh3/4zE + jf+63Lr/4fbh/+//7//J1Mz/6+/v//77////+////v7+///////+/v6T//76k/78/v/+/P7/+/76//n+ + +v/5/vr/+f76//n++P/s/Ov/y+jL/5nGm/96wIH/c8GA/3a8gf+x2bT/9Pvt/9zdsf/e2rD/7/HY//38 + /P/8/vv//P39//79/v///vr//v7+//7+/P/9/fX/8O7Y/9vYsv/c4Lb/9vzv/6DTrf9wwoP/a7+A/2m+ + f/90vYD/rNm3/+j46f/4/vf/+v37//Py9P/X1df//Pz8//79/f/9/P7//v7+//////////+T//76k//9 + /v/+/f7//v79//7+/v/+/v7//v3+///9/v/9/v7/+P78/+z78v+03rn/ecCP/3HCiP+Bx5P/yunN/+Xo + zf/8+u///f77//z+/f/7/v3//f7+//7+/v/+/v3//v79//7+/f/9/f7//v37//f36f/b68r/yenL/3rC + kf9nxon/YsGH/3S9jP+54sH/7v72//z9/f/+/f3//fv8/9vX2v/49/j//v78//3//P/9/v7//v7+//// + //////+T////k/7+/v/////////////////+/v7//v7+/////////////////////v/4/vj/uOPL/3jG + lv9rx5D/i82j/9705f/w/fv/9/38//r+/f/+/v7//v7+//7+/v/9/v3/+//9//z+/f/+/P7//vz9//b9 + +P/K8tz/fsuh/2jIlv9lypb/Z8aU/67hwf/1/fb/+f79//3+/v/+/f3/5eXl/+7u7v/+/v7///////// + //////////////////////+T////k/7+/v/+/v7//v7+//7+/v/+/v7//v7+///////+/v7//v7+//7+ + /v/9/f7/8P32/5/Yuv9sypv/bMeZ/4jLqf++7Nj/9f76//z9/f/+/f7//v3+//79/v/9/v7/+v7+//3+ + +//9/fr/8v73/7rn1v97z7D/Zc6m/2LNov9ny6L/iNKx/+f98//7/fz//fz+//z9/v/v8PD/7e3t//z8 + /P/9/f3//v7+//7+/v///////v7+//7+/v////+T////k/////////////////7+/v/+/v7//v7+//7+ + /v///////v7+///+///9/P7//v38/9346/93zqz/YM2i/2rNov9uyqL/ldO8/8Lu4P/i/PT/7/76//X+ + /P/2/vz/8v36/+b79P/E7d//k9vD/2vPsP9l1LL/aNWz/2XSrv9uz7D/vOvc//v9/f/+/P7//vv+/+3x + 8P/q7e3//Pz8//39/f/+/v7////////////+/v7///////////////+T////k/////////////////// + ///////////////////////////////////+/f7//v39//n++f+f4s3/Yc+t/2XSrP9e0qr/W8+m/2LM + p/9zz6//iNm//47awv+S3cX/i9nD/3vRvP9ozrP/ZNS0/2bWtf9k1LX/Yta5/2DWt/972L7/3fr0//78 + /v/+/P7/8/Hw/+/y8P/7/v7///////////////////////////////////////////////+T////k/7+ + /v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/9/f3/+/79//79/P/D8eX/adC3/2DU + tf9a07D/WNOp/1nRqv9Yz6v/XNGw/1nQr/9Z1LL/V9O0/1XTuP9Q1Lf/U9a3/13Wuf9e1Ln/WtS6/1vZ + vf+K38z/6v77//78/v/x8O//9/fz//z9/f/+/v7//v7+///////+/v7//v7+///////+/v7//v7+//// + //////+T////k//////+/v7//v7+///////////////////////+/v7//v7+///////+/f7/+f7+//3+ + /f/c+fP/cNG8/1XXuP9Y1bb/VtSz/1LSsv9T1Lb/VNW5/1PUuP9W1rr/Vde6/1PWu/9X2L//V9m//1XZ + wf9S2L//Vde//1rYwf+V39T/5PP1/+zu7//8/vv/+v37//36/f/+/f7///////7+/v////////////7+ + /v///////v7+//7+/v/+/v6T////k/////////////////////////////////////////////////// + ///+/f7//f7+//j+/f/e+vj/g9fH/1vXv/9P1rz/UNS7/07UvP9L1b3/StfA/07Yw/9Q18P/UdjD/0/Y + wv9R2MP/UtrF/1Tbx/9X2cb/YdjG/5Lj1v/P7+v/9Pz9//3//v/+/v7//f7+//79///+/v////////// + ///////////////////////////////////+/v6T////k//////+/v7//v7+//7+/v/+/v7//v7+//7+ + /v/+/v7//v7+//7+/v/8/v7//v7+//3+/v/x/v3/0fby/6jo4P+D4NH/YdjE/1fVwP9U1sL/UtjE/1Pa + yP9T2cf/VNrI/1Tbx/9X2cb/ZdvK/4jk1/+v6+T/1Pb0/+39/P/2/v7/+v7+//3+/v/+/v7//v7+//3/ + ///+/v7//v7+///////+/v7//v7+///////+/v7//v7+//////////+T////k/////////////////// + //////////////7+/v////////////7+/v/7/v7//v7////+///+/f7//P3+//f+/v/w/v7/6P37/9z6 + 9v/L9PD/uO3o/67r5f+o7Ob/tO7p/9D08P/e+/j/6v38//P+/v/5/v3//P7+//v+/v/6/v7//f7+//7+ + /v/+/v7//v7+//3////+/v7//v7+///////+/v7//v7+///////+/v7//v7+///////+/v6T/v7+k/// + ///////////////////////////////////////////////////9/v7//v7+//7+/v/+/v///f7+//z+ + /v/7/v7//P7+//v+/v/5/v3/+v7+//r+/v/7/v7/+v7///j//v/5//7/+v7+//v+/f/8/v3//f7+//3+ + /v/+/v7///7+//7+/v////////////3////+//////////////////////////////////////////// + ///+/v6T////k/7+/v////////////7+/v/+/v7////////////+/v7////////////+/v7///////7/ + ///7/v7//P////z////9/v///v7///7+///9/v///P////z////8////+/////z//v/+/v7///7+///9 + /v///v7//f7+//7//v/+/v7////////////+/v7///////7////+//////////////////////////// + ///+/v7///////////////+TAAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA + AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA + //8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA + AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA + //8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA + AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA + //8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//KAAAAEAAAACAAAAAAQAgAAAA + AAAAQgAAAAAAAAAAAAAAAAAAAAAAAP///2////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7//f39//39/f/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7///////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////2////9v//////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////7+/v/+/v7//v7+//7+/v/9/f3//f39//7+/v/+/v7//v7+//7+/v/9/f3//v7+//7+ + /v/+/v7//v7+//////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////9v////b/// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//39/f/8/Pz/+Pj4//Pz8//v7+//7e3t/+zs + 7P/u7u7/7+/v//X19f/6+vr//f39//7+/v////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ////////////b////2////////////////////////////////////////////////////////////// + ///////////////////////////////////+/v7//v7+//7+/v/6+vr/8PDw/9DQ0P+wsLD/kpKS/35+ + fv9wcHD/bm5u/2tra/9oaGj/YWFh/2NjY/9zc3P/hISE/56env+7u7v/4eHh//b29v/8/Pz//f39//39 + /f/9/f3//v7+//7+/v/+/v7///////////////////////////////////////////////////////// + /////////////////////////////////2////9v//////////////////////////////////////// + /////////////////////////////////////////////////////////f39//Dw8P+6urr/jo6O/5GR + kf+dnZ3/vr6+/9bW1v/r6+v/7+/v//r6+v/9/f3//f39//b29v/q6ur/1dXV/8DAwP+kpKT/enp6/11d + Xf9XV1f/k5OT/9TU1P/6+vr//f39//39/f/+/v7//v7+//////////////////////////////////// + //////////////////////////////////////////////////////9v////b/////////////////// + /////////////////////////////////////////////////////////////////////////////+Hh + 4f+jo6P/ycnJ/+7u7v/4+Pj//Pz8//7+/v/9/f3//Pz8//7+/v/8/Pz//f39//39/f/+/v7//v7+//7+ + /v/+/v7//v7+//n5+f/w8PD/zc3N/4iIiP9aWlr/kZGR//v7+//+/v7//Pz8//////////////////// + ////////////////////////////////////////////////////////////////////////////b/// + /2////////////////////////////////////////////////////////////////////////////// + ///////////////////z8/P/+vr6//39/f/9/f3//f39//39/f/9/f3//f39//z8/P/8/Pz//Pz8//39 + /f/+/v7//v7+//7+/v/+/v7//f39//7+/v/8/Pz//v7+//7+/v/7+/v/19fX/2lpaf/39/f//Pz8//7+ + /v/+/v7///////////////////////////////////////////////////////////////////////// + /////////////////2////9v//////////////////////////////////////////////////////// + /////////////////////////////////////////v7+//7+/v/9/f3//v7+//39/f/8/Pz//v7+//39 + /f/9/f3/9fX1/+rq6v/9/f3//f39//39/f/9/f3//v7+//7+/v/+/v7//f39//7+/v/+/v7//f39//Hx + 8f94eHj/9vb2//39/f/9/f3///////////////////////////////////////////////////////// + //////////////////////////////////////9v////b/////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + ///+/v7/+/v7//39/f/+/v7/9fX1/8LCwv/6+vr//f39///////8/Pz//f39//39/f/9/f3//f39//7+ + /v/////////////////x8fH/eHh4//j4+P/+/v7//v7+//////////////////////////////////// + ////////////////////////////////////////////////////////////b////2////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////////////////////v7+//39/f/9/f3//Pz8/9LS0v/Hx8f//v7+//7+/v/+/v7//v7+//z8 + /P/7+/v//f39//7+/v/+/v7/////////////////8fHx/3h4eP/4+Pj//v7+//7+/v////////////// + //////////////////////////////////////////////////////////////////////////////// + /2////9v//////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////7+/v/8/Pz//v7+//39/f+goKD/jo6O/6Wl + pf+kpKT/p6en/6ampv+srKz//Pz8//7+/v/9/f3//f39//////////////////Hx8f94eHj/+Pj4//7+ + /v/+/v7///////////////////////////////////////////////////////////////////////// + //////////////////////9v////b/////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////+/v7//f39//7+ + /v/8/Pz/0NDQ/7a2tv+3t7f/tra2/7a2tv+2tbb/vr2+//v7+//8/Pz//v7+//7+/v////////7////+ + /v/x8vH/eHh3//j4+P/+/v7//v7+//////////////////////////////////////////////////// + ////////////////////////////////////////////b////2////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// + /////////v7+//z8/f/9/fr//f74//39+//+/f7//v7///7+/v/+/P3//vz///77/v/9/vX//v/3//79 + /f/+/f7////////9/////f7/8fLt/3h4d//4+Pj//v7+//7+/v////////////////////////////// + /////////////////////////////////////////////////////////////////2////9v//////// + //////////////////////////////////////////////////////////////////////////////// + //////////////////////////////79/v/8/fz/9/rp/9vexf/5+e3//v79///9/////v7///7+///8 + /v/+/Pn/4OTG//T63f/+/vn//v3+/////v///P////39//Hy7P94eHb/+Pj4//7+/v/+/v7///////// + //////////////////////////////////////////////////////////////////////////////// + //////9v////b/////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////+/v7//f33/73Enf9te0H/ytGt///+ + +P///f///v7///7//v/+/vr/3uLH/29+QP+msoD//P7u///+/P////7//v3+//79/v/x8vD/eHh3//j4 + +P/+/v7//v7+//////////////////////////////////////////////////////////////////// + ////////////////////////////b////2////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////v7+//j6 + 7f+YqGz/aoIx/5uqdP/8/vH//vz///39///8//7//P71/7K9kP9pgTD/iZ1a//D03v/+//z////9//7+ + /v/9/f//8PHx/3h4eP/4+Pj//v7+//7+/v////////////////////////////////////////////// + /////////////////////////////////////////////////2////9v//////////////////////// + //////////////////////////////////////////////////////////////////////////////// + //////////////7+/v/1+e3/iaBk/2+OPf+OpW7/9v3u//7+///+/v7//P7+//f+8/+ft4P/cJBB/4Gb + XP/l7tj/+/78//7//f////z///7+//Hx8f93d3f/+Pj4//7+/v/+/v7///////////////////////// + //////////////////////////////////////////////////////////////////////9v////b/// + //////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////8/v7/8vv0/5q2iv9ukFb/nbOP//n/9//+//7////+//3+ + /v/3/vr/rMak/3GSW/+MqHz/5/Tn//j9/v/9/v3////7////+//y8vH/eHd3//j4+P/+/v7//v7+//7+ + /v////////////////////////////////////////////////////////////////////////////// + ////////////b////2////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////P7+//T++//E28X/h6OF/8zf + y//5//r//v7+///+/v/+/v7/+P7+/9vw4v+Gn4b/ucy5//H79//5/v7//f7+///+/P////v/8vHu/3d2 + dv/5+fn//v7+//7+/v/+/v7///////////////////////////////////////////////////////// + /////////////////////////////////2////9v//////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////3+ + /v/6/v3/8fz3/+Hx6P/y/fX/+/76///9/v///P///f3+//n//P/0/vn/4u7p//L69//4/v3/+v79//3+ + /////v7///79//Ly7/94eHf/+fn5//7+/v/9/f3//v7+//////////////////////////////////// + //////////////////////////////////////////////////////9v////b/////////////////// + //////////////////////////////////////////////////////7////+///+/v///v////7+//7/ + /v/+/v7//v7////+/////v7//vz9//v8/v/3/v3/9/33//3++v//+/7//vr///z+/f/5//f/+/74//z8 + /v/7+/3//P75//3/+f/+/v7//vz///79/v/y8fH/eHh4//f39//+/v7//v7+//7+/v////7///7+///+ + ////////////////////////////////////////////////////////////////////////////b/// + /2////////////////////////7////+/////////////////v/+/v3//v/+/////v////7//v/8//7/ + +//+/f3//vv///3+/P/7//j/+/79//z8///+/f///v3+///6/f/+/P//+fv6//v++P/+/fv///r+//76 + ///6/fv/+f/1//7++P/9+v3//fn9//79/P/9//v//f78//z9/f/6+/z/9Pf2/66zr//5+vv//f3+//7+ + /P/+//v//v75//7++//+/f////7+//////////////////////////////////////////////////// + /////////////////2////9v///////////////////////+/////v////////////////7//f79//39 + /P/8/fz//v79//z9+//8/fr//f38//75///+/Pz//P71//r9+v/7+v///vz+//78/f/8+/z/+Pj3//Ly + 7v/t7On/6Obm/+bj5v/l4+X/4+Tj/+Pl4P/l5uH/6ujp//Ds8f/18vj/9/j7//v9+//8/vv//P79//n7 + +//4+/n//Pr+//r6/P/9/vr//P35//79/P/9+/3//vv///79/v////////////////////////////// + //////////////////////////////////////9v////b/////////////////////////////////// + //////////////z8/P/9/f3//fz9//7+/v/8/v3/9/v6//39/P/+9/3/9u/0/+nm3f/b2sX/xcWt/6in + jP+Wl3P/gYdd/3Z8Tv9sc0P/Zms7/2JkOf9fYTr/X2E5/11jNf9fZDP/YGU1/2JmO/9naUP/bXBN/3d6 + WP+FiWn/l5h//7KxoP/NzMD/4eDZ/+7p7f/5+Pb//f37//z8/v/8+/7//fr+//7+/f/+/vr////+//// + ////////////////////////////////////////////////////////////b////2////////////// + ///////////+/////v/////////////+///+/f7//fz+//38/v/8/P3/8/b0/+Dm4v/AwL3/oJmK/4N6 + YP9zbkL/am0q/2t2Hf9vexX/dYQR/3uKDv9+jw3/g5QN/4WVCv+FlQv/hpUM/4aWDf+Glg3/h5cM/4aX + C/+Hlw3/gZIK/3uLCP94hQr/c3wP/21wF/9gXxj/Wlcd/1laLf9mYVL/hYJ+/6Oio//Nz9P/6u3w//j5 + +v/+/vj////0/////f////////////////////////////////////////////////////////////// + /2////9v/////////////////////////v////7//////////////v///Pv9//X09v/T0tP/nZye/4uN + jv+Tlpj/t7as/6u3Yv+Bkw7/i5wN/4ueCv+LoQb/jaEF/42gBP+OngT/kaAE/5GgAv+SoQH/k6IA/5Oi + AP+UogD/laIA/5WhAf+WogL/lKEC/5KfAf+SoAP/kqAF/5KgBv+Rngj/kp4L/42cDf+Hmhn/jZpE/7a1 + of+Hh4b/Wl9b/01TUv97fYD/tLO0/+jm5P////7///////////////////////////////////////// + //////////////////////9v////b/39/f/9/f3//f39//39/f/9/f3//f79//7+/v/19Pb/y8rM/6Gg + ov+Xlpj/pqam/+Xl5P/29fb/+/r7//v85P+aqzT/jKMC/5ChAP+QnwP/kKAD/4+gAv+NoAD/iaIA/4mi + AP+JoQD/iqEB/4uhAf+NpAL/i6EA/46jAv+OogH/j6QA/4+lAf+OowL/jKEC/42hA/+LoQL/i6MA/4yl + AP+NpwD/jKkA/5CqGf/s8MT//Pr6//X49v/g5uL/rrGw/3h4dv9aVVz/bm1u/66urv/g4OD/+vr6//7+ + /v/9/f3//Pz8//7+/v/9/f3//v7+////////////////b////2/9/f3//Pz8//39/f/+/v7/+fn5/97f + 3v+2tbb/mZiZ/7a1t//e3d7/9PT1//3+/P/9/vr//v78//7+8v/Y4Jv/iqAP/4yjAP+RowD/kaIB/4+h + Av+OnwH/i58A/4igBP+GoAT/hqEC/4ShAP+FowD/hKMA/4mkAP+GnwL/iKAD/4mjAf+JpQD/i6cA/4uo + AP+KpAD/iaIA/4qiAP+MpAL/jqYD/46mAf+MpQ3/xtJ8//397v/7+v3/+/75//v+9//3+PH/5OLj/7Oz + s/98fHz/W1tb/39/f//FxcX/7+/v//z8/P/+/v7//Pz8//7+/v///////////////2////9v/f39//39 + /f/19fX/2NjY/6qqqv+vsK7/z8/P//n4+f/8+/3//fz9//7+/f/9/fn//f74//7/8f/r8L//nK48/4ig + Bv+OowT/jqMB/4ykAP+KogD/iqIA/4mhAP+HoQL/hp8D/4WgBf+CoAP/g6IG/4enCf+Iowv/iaER/4if + Ef+GoAb/iaYD/4imAf+IpQD/iqUA/4qjAP+KowD/jKUA/4+mAf+PpQP/i6IK/5StJ//d56f//v70//3+ + +P/8/vf//vz9//37/f/8/P3/+Pj4/9XV1f+ZmZn/W1tb/2xsbP+wsLD/6Ojo//r6+v/+/v7///////// + //////9v////b/7+/v/v7+//oaGh/7m5uf/x8fD//f79//z8/P/9/P3//fz9//39/f/9/fr//v/5//3/ + 9v/q8cf/nLBA/4ikC/+JogL/jKMB/4ulAf+HpAL/haMB/4ejAP+FowD/gqMB/4GdD/+NojH/t8Zr/8zX + i//V35n/1eCW/9ffm//S2pT/t8Rr/5SoO/+CnBj/g6EK/4OiAv+EpAD/haQA/4ilAP+KpwH/jaYA/42m + CP+Jpwv/la41/+Xut//+/vT//v77//38/f/8+/7//f3+//39/f/8/Pz//Pz8//f39/+0tLT/Z2dn/1FR + Uf+5ubn//v7+////////////////b//+/2///vz/2+PD//H11//9/PL//vz9//77/v/9/f3//v79//79 + /v/+/v3//v70//3/4f/f6q7/kKU6/4OjBv+JqQD/iaYA/4mmAP+IpQH/g6MC/4KkAv+Eowj/g6AX/6S7 + U//e6aj/+f3b//7+8P/+/vn/7e/X/4KJUf/a3bT//v7v//7+8P/8/eX/4em4/66/bf+DoCT/faMG/3+l + AP+CpQP/hqYG/4mnA/+HpQf/hqQL/4amEv+KozH/2+Ws//v94v/+/vX//v3+//79/v/9/f3//v3+//79 + /f/+/f7//v36//n85/+mr43/ioqF//39/f///////////////2///v9v//32/6GzYv+it1L/2eCk/+7x + zP/5/OD///7p////7P/8/uj/8fbV/9/orf+svl3/jacj/4ekDf+Ipwb/iqgI/4qnCP+JqAX/iKgF/4On + Af+BpAn/lK00/9XhmP/4+uD//v74//v++//8/Pr/9vfl/5igV/9oeQf/jpZA/+/u0//+/vn//Pz2//79 + +//6++v/2+Wr/5ayPP+DqA//gaYG/4WmCv+IqQ7/iaoP/4moFf+JqhT/iKoY/46oM/+zxXH/2eSu/+/0 + 2f/8/ur//v7v//7+9P/8/uz/8/ja/9vntv+owWn/e5U7/42Ogf/9/f3///////////////9v//3/b/7+ + 8v+gulH/f6QN/4ajG/+WrzT/orlO/6q6Zf+uvHP/p7ll/5eyRP+KrCL/hqkQ/4imDv+GpAz/hqcJ/4mp + Dv+JpxH/iqcT/4irCP+CqAj/mrU9/+PrsP/+/e7//v34//78/v/+/P7/+/vx/7a9gP9tfQz/bXwB/214 + DP+eomH/+Pjq//398//+/vv//v38//799//u9Mv/obhT/4WmGv+EqA3/haoR/4aqFv+IqRv/iKwX/4it + Fv+HqyH/hKcm/4erMv+Xs1L/p8Bq/7LGff+uv4H/qb5x/5u5VP+HrDP/fqkc/3SWJf+Wl4j//f39//// + ////////////b//7/2///fX/rMRi/36mCP+Bpgf/iKkS/4emGP+GpRz/hqYf/4apHP+FqRb/h60T/4ms + EP+MqxP/iqoU/4eqE/+Iqhb/hqgU/4aoGP+GqhX/jqo1/+3yw//+/fb//Pj9//r7/f/8/f3//vv7/9fZ + rf95hhr/cYIA/3aDAP9zgAL/d4MW/8nPl//+/Pn//fv8//z8/P/7+/3//fv8/+/y1f+dsVP/g6gS/4Gq + Ev+FrBv/h6sj/4WqIP+DqCL/ia4t/4WuJv+Aqxz/h64w/4KoMP+CqS7/gaku/4OuKP+FsCv/ha4u/4Kr + Kv9wkC3/m56Q//7+/v///////////////2//+/9v//34/7/Sgf9+nxj/hKYY/42sJP+MqyP/iKgc/4er + Gf+CqBX/gaYX/4iqH/+IqCD/h6Yf/4urIf+HrB7/haob/4SrGf+DpyL/jao//9zotv/+/Pv//fr9//v8 + /P/5/fz//f71//Dw1P+Nlzf/fowF/4CJAf+BiAL/f4gA/3uIBP97iB7/6eXL///+9//9/vz/+P37//r9 + /v/7/Pj/7fXJ/5q2TP+AqyL/gq4l/4WtK/+Dqiv/g6g0/4SmOv+ErDH/gKwn/4OqNf+CqjT/hK01/4Ww + Nv+CrzH/gaw1/4GoO/+Apjj/aIUv/6qwnf/+/v3///////////////9v//79b//+9P/O4Jf/f6Ij/4is + Iv+KrCj/iKoq/4msKP+EqiP/g6oi/4WsJv+Dqyf/g6km/4arKf+Iryr/hrAp/4KsJf+FrCn/hqg4/73O + j//8/u7//f39//v8/f/6/fz/+/37//397/+zvGv/gIwS/4ePCf+Kjgn/h4wI/4iPBv+EjwP/gY0M/6iv + Wv/5+eL//P34//j++v/4/vz/+/76//3/8P/T3rD/gaY+/3+sL/+Ari//fqst/36pM/+Bqjr/gq8z/36u + Kf9+qjT/g682/4GsO/+Bq0D/g65C/4KtQf9/qD3/gKg8/2iFNf+6wrD//v7+////////////////b//+ + /W///vb/3euz/32gL/+ErSf/iLAw/4iuN/+JsDX/h7Ey/3+pK/+AqS7/gqsy/4GsMP+Arir/gK4q/4Gt + Mf+BqzP/h6w9/5e2V//r887//f73//3+/v/6/Pz//P78//79+P/l5r//iZUm/4mREf+PkhP/kpUR/42T + Dv+NlAv/jZcG/4uVC/+Hkxv/19in//388//8/v3/+fz+//v9/v/8/Pv/9fjr/527c/9+qjn/e60x/3ut + Mv9+rjf/faw5/3+wN/9/sTT/gbA+/4CxO/9/rkD/hLJI/4KyRv+BsET/ga5D/4SqSf9kfz3/0tjL//7+ + /v///////////////2/+/P9v/v38/+nu0P+Cokj/hK04/4WvO/+Frj//hK09/4WvPv+CrTr/f6s4/4Ct + Of+EsTz/g7I5/36tNf+BrDv/hK1D/4esS/+604n/+/7m//79/f/9+////f78//7++P/7++z/sbZn/5KZ + JP+Wmh3/mZsf/5meHP+UnBb/k5sV/5eeEv+XnBX/j5ka/6WrVf/089z//vv+//78///7/P3//P3+//v8 + +//C2Kr/fapD/3uuOv96rT3/fa9B/3utQf99rkP/fq1D/4CtSv9+rkf/f65O/3+vTv+Bs0v/grZJ/4Ky + R/+FrE//Zn1G/+3y6v/+/v7///////////////9v/fz/b/v9/f/u9eD/lrVq/4WvRv+Er0T/hK9E/4Sv + RP+Er0T/hbFD/4ayQv+EsUH/hLFD/4OuRf+Aq0T/g7BD/4WwRP+Epk//2+rA//7+9v/9+v///vr///79 + /f/+/vX/5uW7/5qiOf+coSj/oaIq/56hJv+ZoSH/m6Mj/5yiJP+eoST/oqIk/5mfIv+YoTT/ztCa///9 + +P///f7////6//z9+//7/f3/4fHW/4KuT/98rkP/fa5L/3+yTP99sUj/fbBM/3+vTf9/sE3/eK1H/3+z + U/98sVD/fLNN/32yTP+Ds1L/fqNU/3SIXv/5/Pr//v7+////////////////b/3+/W/8/v3/9/3v/6vG + h/+CsEv/g7NL/4GwSf+Es0r/hrRL/4OyRv+CskT/grFG/4GvSP+Ar03/f7BN/32wRv+Gskz/j61h/+/0 + 4//9/f3//vz+//77///+/f3/+fnh/7a4bP+jpzn/p6cu/6moMv+lqTP/nKM1/6muSP+jpzn/pqkz/6Wn + L/+nqzH/oac2/6uyWP/19tb///38//7++//+/vr//Pz9//f+8v+OtWb/e7FL/3yzU/9+tVX/fbNN/32z + Tf96skz/erRL/361TP9/tlL/e7VQ/3izTf97tlD/gbJX/3eaV/+ZqIv//v3+//7+/v////////////// + /2////tv/v39//z++v/A1an/gq5U/4G1UP9/s1L/g7VU/4a2U/9/r0v/gLBM/4KzT/99sk7/frNR/3u0 + Uf98tVL/g69Y/524df/0+Oj//f77//z+/v/9+v7//vz4/+TmuP+nqkn/r65D/7KsPf+vrzr/p6w+/6qt + XP/x8Lf/vLxp/6mvOv+srj3/ra46/62vPf+rskX/2duk///8+//+/f3//v78//78/v/7/fn/nMCB/3iy + Uf91tVP/eLJY/32zVv9+tFP/drNQ/3SzT/98s1L/fbVa/3q1XP93tlj/d7dU/3yyWP9zllj/xM24//77 + /f///v////////////////9v//79b//+/v/8/vr/4fPR/4WuX/+DtFb/g7Nb/4O0W/+EtVn/hLZX/4S2 + Vv+BtVT/f7RU/4C1Vv9+tlb/fLdY/4CzXf+cv3z/8/np//7+/P/7/f7//P3+//z87f/Fxo7/tLNY/7u3 + T/+9t03/tbVJ/6+1U//X2J///v7t/+Lgsv+vslT/tLRJ/7i1Q/+5t0b/srRL/7y7ff/7+u3//v78//v+ + +v/6/v7/+v75/6XJjf98tln/d7ZZ/3i0Xf98s1z/frRb/3mzWv92tFr/fLhf/3i2YP91tWL/dbdj/3a2 + Yv9+smr/dZVm/+Lr3v//+/////7/////////////////b//+/2/+/v7//P75//X87f+UuHr/g7Nb/4K1 + XP9/tFv/f7Rb/3+1XP+AuGD/g7pj/4a7Zf+EuGP/grhi/324X/94tGD/lMJ+//D55//+/f3/+/z///r+ + +//v8NH/wsF+/8G9Zv/CvV3/wLxX/76/YP/Fx4X/+/rm///8/v/9++7/0dCb/725YP+/ulH/wr5Q/766 + Wv+5tW//5uTF//7+9//5//f/9//8//b/9v+hxov/erRe/3W2X/90tWL/ebZi/3m0Yv92s2P/dLVi/3C3 + Yv9wuWT/cbpn/3O4af93tG//fKl1/5Krjf/3/ff//fr9///+/////////////////2///f9v/v3+//3+ + +v/2/vX/u9Ss/4SyYv+AuF3/fLhd/3+8Y/99vGb/eLhl/3u5af+Bu2//f7ht/4K5bP+Aumn/d7pp/4K6 + dP/o9uH//v39//z7/v/9/vf/3+Cw/8bBd//Gwm3/xMJn/8XDav/LyYf/8vDU///9/P/+/f7//v78//b0 + 4v/PyY7/w79q/8rGZf/Lw2z/yMJ0/9jVov/9/e//+/74//j+/f/x//H/j7h+/3ezYv9zuGT/cLll/3K7 + Zf9wt2T/crdo/3S8av9xvGn/c79r/3W+bP94unD/frV6/3OZcv/L3cn/+v33//79+////v7///////// + //////9v//3/b//9/v/+/vz/+Pz7/+f34P+PuHj/gLhp/3y3aP96uGz/fLtx/3m5b/92tmz/eLlu/3y8 + cf98uG7/fLds/3O7bv93tXH/1OzP//3++//++v7/+/zv/9TTmv/TzID/0tB+/8zNe//Sz5H/7+vP///+ + +P///v7//P79//z+/v/+/vr/9fLW/8vKj//Lynz/zsl9/9HNff/Sz5D/+/fi//39/P/3/f3/2/Pd/4O0 + eP92uGr/bLlm/2y+af9nu2P/a7pn/265bP9yu23/erx2/3q4c/9/u3f/ir6E/5G4j/+QqJH/7vfv//3+ + +v///vz///7+////////////////b//+/m///v7//v3+//v8/v/3//X/uNWt/424hv+Muof/irqH/4i7 + hf+CuX7/f7t6/3y7df95u2//e7pw/3q4cf9xu3P/crZz/7LUr//4/vX//fz9//P03//Y1pz/2dKL/9PV + if/Pz5b/6+nL//799P///v7//v7+//z//P/7//v//f77//7+9f/u7tD/1NWf/9XSl//b2JH/1tOS//Tx + 1v/+/P3/9fz7/7/ixP98tnn/cLlw/2m7bv9qwW3/Zrxo/2q5bf9zuXX/e7p5/5C9kP+y2LH/yurH/9jx + 1/+/08H/x9HL//v9/v///f7///z+///+/v///////////////2////xv//7+///7///9/P7/+v75//D9 + 8P/q/u3/6f3s/+P35f/Z8dn/yObH/6zUqP+LvYb/g7t8/327eP95vXn/cr16/3K7ev+OwJL/4/bh//r+ + +P/r7NH/2dah/9vWm//T2J7/6+nT//79+P/+/vn//v7+//79///+/vz//v/5//7//f/8/Pv////2//Hz + 1v/d27T/2dai/9rYoP/k48P//f34/+779f+UzaD/dr5//2y7eP9pvXj/Z79z/22+df94uYH/jL6R/8bp + xf/u/+//8/70//T+9f/z+/X/uL26//f4+v/9+/////v////8/////v////////////////9v///4b//9 + /P//+v///v3+//z++v/7/vz/+//7//r++//7/vz//P38//r++f/z/vL/5/vo/7rbvP+Jvo//eMKC/3PC + gv91woT/fLuF/7feuf/0/vD/4+bG/9rZqf/g3bj/8/Xd//7+/P/8/f7/+/77//z9/f/+/P////79///+ + /P///f7//v79//7+/f/+/vn/+fjo/+TfxP/Y2a3/2+K6//T67P/L6M7/c7+I/2/EhP9rwIH/ab2C/23A + gP93uoT/st6+/+r88P/2/vP/+/75//z9/P/9+/3/3Nfc/+Tg4//8/Pz//v79//3+/v/8/P7//v7+//// + ////////////b///+W///v3///v////9/v/+/v3//v7+//7+/v///f7///z+///8/v/+/f7//f7+//f/ + /P/x/fj/1PDa/53Tpf92vYr/csSK/3fCiP+Hx5b/0/LX/9few//t7ND/+/ru//7++v/8/f3/+v79//r+ + /v/8/v7///7////+/v///v7///7+//7++//+/f///fz+//79+v/8+/H/7O/V/9Tlwf/X8Nb/msuk/2/F + jf9mxYb/YsGG/2e8hv98vY7/vObE/+n98v/3/v3//vz9//79/P/+/P3/7+zv/9bR1f/+/f3//v78//7+ + +//9//z//f7+//7+/v///////////////2////5v//7+///+/////v7////+///////+/v7//v7+//7+ + /v/+/v7///7///7////+//7//f/+//3/+//p+On/pde5/3PCkv9yxo7/bMWN/5PSqP/e8t3/+vz5//n9 + /f/5/fz/+v79//z+/f/9/v7//v7+///+/v/9/v7//f/8//3//P/+/v3//fz9//78/v/+/P7//v38//X/ + 9f/a+eL/ntex/3bElf9ox5L/Z8uT/2DFjf9ywpP/td7A//X+9P/2/vv/+f7+//79/v/+/f3/+Pj4/9PT + 0//19PT//////////v////7////+//////////////////////////9v////b/////////////////// + /////////v7+//7+/v/+/v7//v7+///////////////////////+/v7/+f36/+L67v+Tz6v/cMWU/2zJ + lP92xZf/ns+w/9/67v/p/vn/9v79//j9/f/8/v7//v3+//79/v///v////7///3+/v/7//7/+P79//7+ + /f//+/7//vz9//r8+P/j/fD/ntq+/3HJoP9ky5z/ZcmZ/2PIl/9qxpj/nd27/+f+8P/4/fr/+v7+//v+ + /v/+/f7//v39/+Dg4P/t7e3//Pz8////////////////////////////////////////////////b/// + /2///////////////////////////////////////////////////////////////////////v3///39 + /v/4/vz/1PPg/3/MqP9sy53/ZsiZ/3PHnP+IzKr/vOrW//L9+P/8/vz//v39///9/v///P7///3////9 + ///8/v//+//+//z//P/+/vr//P35//H/9//L8eP/i9G4/2/OrP9l0Kj/YM6k/2XOpf9pzKX/hc+w/9P3 + 5//2//v//v3+//78/v/9/P7/+v39/+bm5v/t7e3//Pz8//v7+//+/v7///////////////////////// + /////////////////2////9v//////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+//// + //////////////79///9/P///v39//X++P+q48v/b8un/1/NoP9ky5//bs2i/3TJpP+a0r3/w+3f/9/7 + 8//t/vr/9f78//n+/f/7/v7/+v79//j//f/z//r/6Pz0/87y5v+k483/ec+z/2rSsv9k1LH/Z9Wy/2nU + sP9m0q7/b82v/6jhzv/w/vr//v3+//77////+/7/+/v8/+Lq6P/q6+v/+/v7//z8/P/9/f3//v7+//// + //////////////////////////////////////9v////b//////////////////////+/v7//v7+//7+ + /v/+/v7//v7+//7+/v/////////////////+/v7//v3+///8/f/9/vv/1/fp/4HVuf9fz6n/ZNGp/2bR + qP9gzqX/Ysqm/23Lq/+B07f/nuHK/7Xt2/++8N//x/Tl/8bz5P+97t//rePW/5XZxv97z7f/btGz/2jV + s/9j07L/ZNW0/2XWuP9j1Lb/ZNaz/3fRt//K9On/+f7+///7/v///P///fn7/+3t7P/n7+3//f7+//7+ + /v/+/v7//v7+//7+/v//////////////////////////////////////////b////2////////////// + ///////////////////////////////////////////////////////////+//3+/f/9/v3///78//T+ + +f+Z38z/Ys2w/2TSsf9j1LD/XNOr/1jRpv9az6b/Xs2n/2HKp/9ozK3/aMqs/2jMrv9ozrD/Z86y/2fO + tv9gz7X/WdGz/1vUtP9h1rb/ZtW3/2TVuP9g1rr/XNe6/2DXt/+M38n/3fv2//v8/f/++v3//Pr7/+zq + 6P/29vP/+P78//3///////////////////////////////////////////////////////////////// + /2////9v///////////////////////////////////////////////////////////////////////+ + /v/9/f3/+v/+///+/f/6/vv/u/Dj/27PuP9h07f/XNW0/1nTsP9X0qn/WtSs/1bPqf9Y0a3/WtKx/1jR + sP9Y1LP/V9Wz/1XUtP9V1bn/UNS4/07VuP9R17j/V9a4/17Wuv9c07n/WtO6/1jXvf9f2L3/mePU/+f+ + /P/9/v////3+/+np5v/5+vb//f38//z8/f///v////////////////////////////////////////// + //////////////////////9v////b/////////////////////////////////////////////////// + /////////////////////v///v3+//j+/v/9/f3/+/79/9P27/930Lz/V9S3/1bXuP9Y1bX/V9Wy/1TS + sP9T0rP/U9O1/1TUt/9U1Lf/VdW4/1fWuf9X17n/UtW5/1TWu/9X2b//Vtm//1TYv/9W2cD/U9a+/1XX + vv9Y2cD/XdfA/6Pj2//j9ff/6ezu/+/x8P/8/vr/+v36//r6/P/++v7///7///////////////////// + ////////////////////////////////////////////b////2////////////////////////////// + //////////////////////////////////////////7///78/v/6/v7/+/z8//X+/f/Z+PT/g9bE/1rY + vf9S2bz/Uta5/1TVuP9Q0bf/T9O5/07UvP9N1b3/Tta+/1DXwP9S18D/U9i//1HYv/9U2L//VtfB/1fZ + w/9U2sT/UdvF/1Haw/9V2cP/X9jE/33Zyv+14t3/6Pb4//f7/P/8/v7//P78//v+/f/8/P7///v////+ + /////////////////////////////////////////////////////////////////2////9v//////// + //////////////////////////////////////////////////////////////7+///+/v////////3/ + /v/z//7/2/r3/5rb0f9z1sX/XdfC/0/Uvf9O1Lz/TdS9/07Ywf9I1b//SNfB/0zZxP9O2cb/T9jF/0/Y + xv9L2MT/TNnF/07axv9P2sb/VNnH/1/byv9o2Mn/eNvO/5rp3v/Y9vH/8f79//f+/v/8/v7//v7+//// + /v///////v7///3+//////////////////////////////////////////////////////////////// + //////9v////b/////////////////////////////////////////////////////////////////// + ///9/////P////7+/////v///f7+//T+/f/k/vv/yfby/6rp4P+M49T/advH/17Wwv9X07//WNfE/1XY + xP9V2sf/VNnI/1XZyP9X28n/V9vI/1jax/9b2MX/advK/4Pk1f+l6uH/yPPv/+b8/P/y/f7/9f79//f+ + /v/6/v7//f7+//7+/v////////////7////9//////////////////////////////////////////// + ////////////////////////////b////2////////////////////////////////////////////// + /////////////////////////P/+//v//v/+/v////7////+///+/f7//P3+//f9/f/y/v7/7P79/+T9 + +v/b/Pf/yvTu/73x6/+q6OH/oOXd/5jl3f+W5t//n+fg/7zs5v/N9fD/2fv3/+T9+//t/v3/9P79//n9 + /f/8/v7//P7+//r+/v/6/v7//P39//7+/v/+/v7////////////+/////f////////////////////// + /////////////////////////////////////////////////2////9v//////////////////////// + //////////////////////////////////////////////7+/v/8/v7//v7+///+/////v////7+//79 + /v/+/v7//P7+//r9/f/7/v7/+f7+//f+/v/z/f3/8v7+//D+/v/v/f7/8P7+//H+/v/z//7/9P/+//X/ + /f/3/v7/+P39//v//v/7/v3//P7+//z+/v/8/v7//f7+//7+/v/+/v7//v7+/////////////v////3/ + //////////////////////////////////////////////////////////////////////9v////b/// + ///////////////////////////////////////////////////////////////////+/v7//v7+//7+ + /v///////f////z////7/v7/+/7+//v////7/v7//f7+//z+/v/8/v7/+/7+//z+///8/v///f7///3+ + ///9/v///P/+//3//v/9//7//f7+//3+/f/9/v7//f79//7+/v/9/v3//v7+/////////v7///7+//// + //////////////7////9//////////////////////////////////////////////////////////// + ////////////b////2////////////////////////////////////////////////////////////// + //////////////////////////////z////8/////P////3////9/////v7////+/////v///v7///7+ + ///9/////P////z////8////+/////r//v/8//7//v7+///+/v///f7///3+///+/v/9//7//P/+//// + ///////////////////////////////////+/////v////////////////////////////////////// + /////////////////////////////////28AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + + \ No newline at end of file diff --git a/src/Vinesauce ROM Corruptor/Vinesauce ROM Corruptor.csproj b/src/Vinesauce ROM Corruptor/Vinesauce ROM Corruptor.csproj index 11c1930..81296d6 100644 --- a/src/Vinesauce ROM Corruptor/Vinesauce ROM Corruptor.csproj +++ b/src/Vinesauce ROM Corruptor/Vinesauce ROM Corruptor.csproj @@ -50,6 +50,7 @@ + Form @@ -64,6 +65,12 @@ + + Form + + + QueueForm.cs + HotkeyForm.cs @@ -81,6 +88,9 @@ Resources.resx True + + QueueForm.cs + SettingsSingleFileGenerator Settings.Designer.cs