Merge branch '12-component-translation' into 'main'

Resolve "Component: Translation"

Closes #12

See merge request open-source/dotnet/i18n-commander!15
This commit is contained in:
Thorsten 2022-09-21 20:53:39 +00:00
commit 32c7865c91
34 changed files with 1753 additions and 353 deletions

View File

@ -47,7 +47,9 @@ public sealed class DataContext : DbContext, IDataContext
modelBuilder.Entity<TextElement>().HasIndex(n => n.Id); modelBuilder.Entity<TextElement>().HasIndex(n => n.Id);
modelBuilder.Entity<TextElement>().HasIndex(n => n.Code); modelBuilder.Entity<TextElement>().HasIndex(n => n.Code);
modelBuilder.Entity<TextElement>().HasIndex(n => n.Name); modelBuilder.Entity<TextElement>().HasIndex(n => n.Name);
modelBuilder.Entity<TextElement>().HasIndex(n => n.IsMultiLine);
modelBuilder.Entity<TextElement>().Navigation(n => n.Section).AutoInclude(); modelBuilder.Entity<TextElement>().Navigation(n => n.Section).AutoInclude();
modelBuilder.Entity<TextElement>().Navigation(n => n.Translations).AutoInclude();
#endregion #endregion
@ -56,6 +58,7 @@ public sealed class DataContext : DbContext, IDataContext
modelBuilder.Entity<Translation>().HasIndex(n => n.Id); modelBuilder.Entity<Translation>().HasIndex(n => n.Id);
modelBuilder.Entity<Translation>().HasIndex(n => n.Culture); modelBuilder.Entity<Translation>().HasIndex(n => n.Culture);
modelBuilder.Entity<Translation>().HasIndex(n => n.Text); modelBuilder.Entity<Translation>().HasIndex(n => n.Text);
modelBuilder.Entity<Translation>().HasIndex(n => n.TranslateManual);
modelBuilder.Entity<Translation>().Navigation(n => n.TextElement).AutoInclude(); modelBuilder.Entity<Translation>().Navigation(n => n.TextElement).AutoInclude();
#endregion #endregion

View File

@ -11,6 +11,8 @@ public sealed class TextElement
public string Code { get; set; } = string.Empty; public string Code { get; set; } = string.Empty;
public bool IsMultiLine { get; set; } = false;
public Section Section { get; set; } public Section Section { get; set; }
public List<Translation> Translations { get; set; } = new(); public List<Translation> Translations { get; set; } = new();

View File

@ -9,4 +9,6 @@ public sealed class Translation
public string Culture { get; set; } = "en-US"; public string Culture { get; set; } = "en-US";
public string Text { get; set; } = string.Empty; public string Text { get; set; } = string.Empty;
public bool TranslateManual { get; set; } = false;
} }

View File

@ -0,0 +1,206 @@
// <auto-generated />
using System;
using DataModel.Database.Common;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace DataModel.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20220917132808_202209AddMultiLineOption")]
partial class _202209AddMultiLineOption
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.9");
modelBuilder.Entity("DataModel.Database.Section", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("DataKey")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Depth")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int?>("ParentId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("DataKey");
b.HasIndex("Depth");
b.HasIndex("Id");
b.HasIndex("Name");
b.HasIndex("ParentId");
b.ToTable("Sections");
});
modelBuilder.Entity("DataModel.Database.Setting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("BoolValue")
.HasColumnType("INTEGER");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("GuidValue")
.HasColumnType("TEXT");
b.Property<int>("IntegerValue")
.HasColumnType("INTEGER");
b.Property<string>("TextValue")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("BoolValue");
b.HasIndex("Code")
.IsUnique();
b.HasIndex("GuidValue");
b.HasIndex("Id");
b.HasIndex("IntegerValue");
b.HasIndex("TextValue");
b.ToTable("Settings");
});
modelBuilder.Entity("DataModel.Database.TextElement", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsMultiLine")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("SectionId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Code");
b.HasIndex("Id");
b.HasIndex("IsMultiLine");
b.HasIndex("Name");
b.HasIndex("SectionId");
b.ToTable("TextElements");
});
modelBuilder.Entity("DataModel.Database.Translation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Culture")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("TextElementId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Culture");
b.HasIndex("Id");
b.HasIndex("Text");
b.HasIndex("TextElementId");
b.ToTable("Translations");
});
modelBuilder.Entity("DataModel.Database.Section", b =>
{
b.HasOne("DataModel.Database.Section", "Parent")
.WithMany()
.HasForeignKey("ParentId");
b.Navigation("Parent");
});
modelBuilder.Entity("DataModel.Database.TextElement", b =>
{
b.HasOne("DataModel.Database.Section", "Section")
.WithMany("TextElements")
.HasForeignKey("SectionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Section");
});
modelBuilder.Entity("DataModel.Database.Translation", b =>
{
b.HasOne("DataModel.Database.TextElement", "TextElement")
.WithMany("Translations")
.HasForeignKey("TextElementId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("TextElement");
});
modelBuilder.Entity("DataModel.Database.Section", b =>
{
b.Navigation("TextElements");
});
modelBuilder.Entity("DataModel.Database.TextElement", b =>
{
b.Navigation("Translations");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DataModel.Migrations
{
public partial class _202209AddMultiLineOption : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsMultiLine",
table: "TextElements",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.CreateIndex(
name: "IX_TextElements_IsMultiLine",
table: "TextElements",
column: "IsMultiLine");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_TextElements_IsMultiLine",
table: "TextElements");
migrationBuilder.DropColumn(
name: "IsMultiLine",
table: "TextElements");
}
}
}

View File

@ -0,0 +1,211 @@
// <auto-generated />
using System;
using DataModel.Database.Common;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace DataModel.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20220921182526_202209AddManualFlag")]
partial class _202209AddManualFlag
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.9");
modelBuilder.Entity("DataModel.Database.Section", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("DataKey")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Depth")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int?>("ParentId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("DataKey");
b.HasIndex("Depth");
b.HasIndex("Id");
b.HasIndex("Name");
b.HasIndex("ParentId");
b.ToTable("Sections");
});
modelBuilder.Entity("DataModel.Database.Setting", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("BoolValue")
.HasColumnType("INTEGER");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid>("GuidValue")
.HasColumnType("TEXT");
b.Property<int>("IntegerValue")
.HasColumnType("INTEGER");
b.Property<string>("TextValue")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("BoolValue");
b.HasIndex("Code")
.IsUnique();
b.HasIndex("GuidValue");
b.HasIndex("Id");
b.HasIndex("IntegerValue");
b.HasIndex("TextValue");
b.ToTable("Settings");
});
modelBuilder.Entity("DataModel.Database.TextElement", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsMultiLine")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("SectionId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Code");
b.HasIndex("Id");
b.HasIndex("IsMultiLine");
b.HasIndex("Name");
b.HasIndex("SectionId");
b.ToTable("TextElements");
});
modelBuilder.Entity("DataModel.Database.Translation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Culture")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("TextElementId")
.HasColumnType("INTEGER");
b.Property<bool>("TranslateManual")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Culture");
b.HasIndex("Id");
b.HasIndex("Text");
b.HasIndex("TextElementId");
b.HasIndex("TranslateManual");
b.ToTable("Translations");
});
modelBuilder.Entity("DataModel.Database.Section", b =>
{
b.HasOne("DataModel.Database.Section", "Parent")
.WithMany()
.HasForeignKey("ParentId");
b.Navigation("Parent");
});
modelBuilder.Entity("DataModel.Database.TextElement", b =>
{
b.HasOne("DataModel.Database.Section", "Section")
.WithMany("TextElements")
.HasForeignKey("SectionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Section");
});
modelBuilder.Entity("DataModel.Database.Translation", b =>
{
b.HasOne("DataModel.Database.TextElement", "TextElement")
.WithMany("Translations")
.HasForeignKey("TextElementId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("TextElement");
});
modelBuilder.Entity("DataModel.Database.Section", b =>
{
b.Navigation("TextElements");
});
modelBuilder.Entity("DataModel.Database.TextElement", b =>
{
b.Navigation("Translations");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DataModel.Migrations
{
public partial class _202209AddManualFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "TranslateManual",
table: "Translations",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.CreateIndex(
name: "IX_Translations_TranslateManual",
table: "Translations",
column: "TranslateManual");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Translations_TranslateManual",
table: "Translations");
migrationBuilder.DropColumn(
name: "TranslateManual",
table: "Translations");
}
}
}

View File

@ -15,7 +15,7 @@ namespace DataModel.Migrations
protected override void BuildModel(ModelBuilder modelBuilder) protected override void BuildModel(ModelBuilder modelBuilder)
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.5"); modelBuilder.HasAnnotation("ProductVersion", "6.0.9");
modelBuilder.Entity("DataModel.Database.Section", b => modelBuilder.Entity("DataModel.Database.Section", b =>
{ {
@ -103,6 +103,9 @@ namespace DataModel.Migrations
.IsRequired() .IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<bool>("IsMultiLine")
.HasColumnType("INTEGER");
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@ -116,6 +119,8 @@ namespace DataModel.Migrations
b.HasIndex("Id"); b.HasIndex("Id");
b.HasIndex("IsMultiLine");
b.HasIndex("Name"); b.HasIndex("Name");
b.HasIndex("SectionId"); b.HasIndex("SectionId");
@ -140,6 +145,9 @@ namespace DataModel.Migrations
b.Property<int>("TextElementId") b.Property<int>("TextElementId")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<bool>("TranslateManual")
.HasColumnType("INTEGER");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("Culture"); b.HasIndex("Culture");
@ -150,6 +158,8 @@ namespace DataModel.Migrations
b.HasIndex("TextElementId"); b.HasIndex("TextElementId");
b.HasIndex("TranslateManual");
b.ToTable("Translations"); b.ToTable("Translations");
}); });

View File

@ -52,6 +52,9 @@ public static class DeepL
var sourceCultureIndex = await AppSettings.GetDeepLSourceCultureIndex(); var sourceCultureIndex = await AppSettings.GetDeepLSourceCultureIndex();
var sourceCulture = await AppSettings.GetCultureCode(sourceCultureIndex); var sourceCulture = await AppSettings.GetCultureCode(sourceCultureIndex);
// In case of the source culture, we cannot specify the region, so we need to remove it:
sourceCulture = sourceCulture.Split('-')[0];
using var deepl = new Translator(deepLAPIKey); using var deepl = new Translator(deepLAPIKey);
var translation = await deepl.TranslateTextAsync(text, sourceCulture, targetCulture); var translation = await deepl.TranslateTextAsync(text, sourceCulture, targetCulture);

View File

@ -26,7 +26,7 @@ public static class TextElementProcessor
} }
// Adds a new text element: // Adds a new text element:
public static async Task<ProcessorResult<TextElement>> AddTextElement(string? currentSectionKey, string elementName) public static async Task<ProcessorResult<TextElement>> AddTextElement(string? currentSectionKey, string elementName, bool isMultiLine)
{ {
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>(); await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
@ -45,6 +45,7 @@ public static class TextElementProcessor
Name = elementName, Name = elementName,
Code = code, Code = code,
Section = currentSection, Section = currentSection,
IsMultiLine = isMultiLine,
}; };
// Add the new element to the database: // Add the new element to the database:
@ -62,15 +63,31 @@ public static class TextElementProcessor
} }
} }
// Renames a text element: // Updates the multi-line flag of a text element:
public static async Task<ProcessorResult<TextElement>> RenameTextElement(int id, string newName) public static async Task<ProcessorResult<TextElement>> UpdateTextElementState(int id, bool isMultiLine)
{ {
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>(); await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
var textElement = await db.TextElements.FirstAsync(n => n.Id == id); var textElement = await db.TextElements.FirstAsync(n => n.Id == id);
if (textElement is null) textElement.IsMultiLine = isMultiLine;
throw new ArgumentOutOfRangeException(nameof(id));
try
{
// Save the changes:
await db.SaveChangesAsync();
return new ProcessorResult<TextElement>(textElement);
}
catch (DbUpdateException updateException)
{
return updateException.ToProcessorResult<TextElement>();
}
}
// Renames a text element:
public static async Task<ProcessorResult<TextElement>> RenameTextElement(int id, string newName, bool isMultiLine)
{
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
var textElement = await db.TextElements.FirstAsync(n => n.Id == id);
// Get the corresponding section: // Get the corresponding section:
var section = (await db.TextElements.FirstAsync(n => n.Id == id)).Section; var section = (await db.TextElements.FirstAsync(n => n.Id == id)).Section;
@ -79,6 +96,7 @@ public static class TextElementProcessor
textElement.Name = newName; textElement.Name = newName;
textElement.Code = code; textElement.Code = code;
textElement.IsMultiLine = isMultiLine;
// Save the changes: // Save the changes:
try try

View File

@ -0,0 +1,54 @@
using DataModel.Database;
using DataModel.Database.Common;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace Processor;
public static class TranslationProcessor
{
public static async Task<List<Translation>> GetTranslations(TextElement textElement)
{
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
var missedTranslations = new List<Translation>();
var cultureInfos = await AppSettings.GetCultureInfos();
foreach (var cultureInfo in cultureInfos)
{
if(!await db.Translations.AnyAsync(n => n.TextElement == textElement && n.Culture == cultureInfo.Code))
missedTranslations.Add(new Translation
{
TranslateManual = false,
Culture = cultureInfo.Code,
Text = string.Empty,
});
}
if(missedTranslations.Count > 0)
{
textElement.Translations.AddRange(missedTranslations);
db.TextElements.Update(textElement);
await db.SaveChangesAsync();
}
return await db.Translations.Where(n => n.TextElement == textElement).ToListAsync();
}
public static async Task<ProcessorResult<Translation>> SaveChangedTranslation(int translationId, string text, bool manualFLag)
{
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
var dbTranslation = await db.Translations.FirstAsync(n => n.Id == translationId);
dbTranslation.Text = text;
dbTranslation.TranslateManual = manualFLag;
try
{
// Save the changes:
await db.SaveChangesAsync();
return new ProcessorResult<Translation>(dbTranslation);
}
catch (DbUpdateException updateException)
{
return updateException.ToProcessorResult<Translation>();
}
}
}

View File

@ -17,10 +17,10 @@ internal static class AppEvents
#region Event: Text element was changed #region Event: Text element was changed
// Text element changed event which can be subscribed: // Text element changed event which can be subscribed:
internal static event EventHandler<TextElement> WhenTextElementChanged; internal static event EventHandler<TextElement?> WhenTextElementChanged;
// Method to raise the text element changed event: // Method to raise the text element changed event:
internal static void TextElementChanged(TextElement textElement) => WhenTextElementChanged?.Invoke(null, textElement); internal static void TextElementChanged(TextElement? textElement) => WhenTextElementChanged?.Invoke(null, textElement);
#endregion #endregion
} }

View File

@ -40,6 +40,7 @@
this.tabSettings = new System.Windows.Forms.TabPage(); this.tabSettings = new System.Windows.Forms.TabPage();
this.settings = new UI_WinForms.Components.Settings(); this.settings = new UI_WinForms.Components.Settings();
this.imageList = new System.Windows.Forms.ImageList(this.components); this.imageList = new System.Windows.Forms.ImageList(this.components);
this.translations = new UI_WinForms.Components.Translations();
this.tableLayout.SuspendLayout(); this.tableLayout.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainerLR)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerLR)).BeginInit();
this.splitContainerLR.Panel1.SuspendLayout(); this.splitContainerLR.Panel1.SuspendLayout();
@ -47,6 +48,7 @@
this.splitContainerLR.SuspendLayout(); this.splitContainerLR.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainerRTB)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerRTB)).BeginInit();
this.splitContainerRTB.Panel1.SuspendLayout(); this.splitContainerRTB.Panel1.SuspendLayout();
this.splitContainerRTB.Panel2.SuspendLayout();
this.splitContainerRTB.SuspendLayout(); this.splitContainerRTB.SuspendLayout();
this.tabControl.SuspendLayout(); this.tabControl.SuspendLayout();
this.tabTranslation.SuspendLayout(); this.tabTranslation.SuspendLayout();
@ -109,6 +111,10 @@
// //
this.splitContainerRTB.Panel1.Controls.Add(this.textElements); this.splitContainerRTB.Panel1.Controls.Add(this.textElements);
this.splitContainerRTB.Panel1MinSize = 340; this.splitContainerRTB.Panel1MinSize = 340;
//
// splitContainerRTB.Panel2
//
this.splitContainerRTB.Panel2.Controls.Add(this.translations);
this.splitContainerRTB.Size = new System.Drawing.Size(556, 583); this.splitContainerRTB.Size = new System.Drawing.Size(556, 583);
this.splitContainerRTB.SplitterDistance = 340; this.splitContainerRTB.SplitterDistance = 340;
this.splitContainerRTB.TabIndex = 0; this.splitContainerRTB.TabIndex = 0;
@ -136,6 +142,7 @@
this.tabControl.SelectedIndex = 0; this.tabControl.SelectedIndex = 0;
this.tabControl.Size = new System.Drawing.Size(965, 603); this.tabControl.Size = new System.Drawing.Size(965, 603);
this.tabControl.TabIndex = 1; this.tabControl.TabIndex = 1;
this.tabControl.SelectedIndexChanged += new System.EventHandler(this.tabControl_SelectedIndexChanged);
// //
// tabTranslation // tabTranslation
// //
@ -153,10 +160,10 @@
// //
this.tabSettings.Controls.Add(this.settings); this.tabSettings.Controls.Add(this.settings);
this.tabSettings.ImageIndex = 0; this.tabSettings.ImageIndex = 0;
this.tabSettings.Location = new System.Drawing.Point(70, 4); this.tabSettings.Location = new System.Drawing.Point(136, 4);
this.tabSettings.Name = "tabSettings"; this.tabSettings.Name = "tabSettings";
this.tabSettings.Padding = new System.Windows.Forms.Padding(3); this.tabSettings.Padding = new System.Windows.Forms.Padding(3);
this.tabSettings.Size = new System.Drawing.Size(891, 595); this.tabSettings.Size = new System.Drawing.Size(60, 92);
this.tabSettings.TabIndex = 1; this.tabSettings.TabIndex = 1;
this.tabSettings.Text = "Settings"; this.tabSettings.Text = "Settings";
this.tabSettings.UseVisualStyleBackColor = true; this.tabSettings.UseVisualStyleBackColor = true;
@ -167,7 +174,7 @@
this.settings.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); this.settings.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.settings.Location = new System.Drawing.Point(3, 3); this.settings.Location = new System.Drawing.Point(3, 3);
this.settings.Name = "settings"; this.settings.Name = "settings";
this.settings.Size = new System.Drawing.Size(885, 589); this.settings.Size = new System.Drawing.Size(54, 86);
this.settings.TabIndex = 0; this.settings.TabIndex = 0;
// //
// imageList // imageList
@ -178,6 +185,15 @@
this.imageList.Images.SetKeyName(0, "icons8-settings.svg.png"); this.imageList.Images.SetKeyName(0, "icons8-settings.svg.png");
this.imageList.Images.SetKeyName(1, "icons8-language-45.png"); this.imageList.Images.SetKeyName(1, "icons8-language-45.png");
// //
// translations
//
this.translations.Dock = System.Windows.Forms.DockStyle.Fill;
this.translations.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.translations.Location = new System.Drawing.Point(0, 0);
this.translations.Name = "translations";
this.translations.Size = new System.Drawing.Size(554, 237);
this.translations.TabIndex = 0;
//
// Main // Main
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F);
@ -192,6 +208,7 @@
((System.ComponentModel.ISupportInitialize)(this.splitContainerLR)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerLR)).EndInit();
this.splitContainerLR.ResumeLayout(false); this.splitContainerLR.ResumeLayout(false);
this.splitContainerRTB.Panel1.ResumeLayout(false); this.splitContainerRTB.Panel1.ResumeLayout(false);
this.splitContainerRTB.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.splitContainerRTB)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerRTB)).EndInit();
this.splitContainerRTB.ResumeLayout(false); this.splitContainerRTB.ResumeLayout(false);
this.tabControl.ResumeLayout(false); this.tabControl.ResumeLayout(false);
@ -213,5 +230,6 @@
private TabPage tabSettings; private TabPage tabSettings;
private ImageList imageList; private ImageList imageList;
private Settings settings; private Settings settings;
private Translations translations;
} }
} }

View File

@ -5,5 +5,19 @@ public partial class Main : UserControl
public Main() public Main()
{ {
this.InitializeComponent(); this.InitializeComponent();
Program.RestartMainApp = false;
}
private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.settings.NeedRestart())
{
var result = MessageBox.Show("You need to restart the app for the changes to take effect. Do you want to restart?", "Restart required", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if(result == DialogResult.Yes)
{
Program.RestartMainApp = true;
this.ParentForm!.Close();
}
}
} }
} }

View File

@ -64,313 +64,312 @@
<value> <value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAjEoAAAJNU0Z0AUkBTAIBAQIB SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAUEoAAAJNU0Z0AUkBTAIBAQIB
AAEgAQABIAEAAS0BAAEtAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABtAMAAS0DAAEBAQABIAUAAZAB AAE4AQABOAEAAS0BAAEtAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABtAMAAS0DAAEBAQABIAUAAZAB
fvoAAw8BFAMTARkEAf8A/wAqAAMnATkDTgGWA1EBoQNRAaEDUQGhA04BlgMnATp8AAMLAQ4BVQFTAVEB fvoAAw8BFAMTARkEAf8A/wAqAAMnATkDTgGWA1EBoQNRAaEDUQGhA04BlgMnATp8AAMLAQ4CUwFRAaIB
ogFpAVsBUgHHAyUBNv8A/wAmAAMRARYDQgHzAToCOQH/AT0BPAE7Af8BPQE8ATsB/wE9ATwBOwH/AToC XgFbAVkBxwMlATb/AP8AJgADEQEWA0wB8wE6AjkB/wE9ATwBOwH/AT0BPAE7Af8BPQE8ATsB/wE6AjkB
OQH/A0AB9AMRARZ4AAMSARgBbQFdAVIBzAG8AVsBGQH/AXkBXgFOAdcDEAEV/wD/ACIAAz8BbgFGAUMB /wNGAfQDEQEWeAADEgEYAWABXQFaAcwBvAFbARkB/wFnAV4BWQHXAxABFf8A/wAiAAM/AW4BRgFDAUIB
QgH/AcQBrwGmAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8BxAGuAaYB/wFGAUMBQgH/A0ABcHgAAxIB /wHEAa8BpgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AcQBrgGmAf8BRgFDAUIB/wNAAXB4AAMSARgB
GAFtAV0BUgHMAbwBWwEZAf8BvAFbARkB/wF3AV8BTAHYAyUBNwQB/wD/ABoAA1YBtwFXAVIBUAH/Ad4B YAFdAVoBzAG8AVsBGQH/AbwBWwEZAf8BaAFfAVkB2AMlATcEAf8A/wAaAANYAbcBVwFSAVAB/wHeAcUB
xQG7Af8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B3gHFAbsB/wFXAVIBTwH/A1YBugQBdAADEgEYAW0B uwH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/Ad4BxQG7Af8BVwFSAU8B/wNYAboEAXQAAxIBGAFgAV0B
XQFSAcwBuwFbARkB/wG8AVsBGQH/AbwBWwEZAf8BdwFfAU8B1QIaARkBI/8A8QADAwEEAyIBMQMpAT4D WgHMAbsBWwEZAf8BvAFbARkB/wG8AVsBGQH/AWgBXwFaAdUCGgEZASP/APEAAwMBBAMiATEDKQE+AxIB
EgEYFAADEgEYA1UB2wF7AXABbAH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB GBQAAxIBGANcAdsBewFwAWwB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B
/wF6AXABawH/A1UB2wMTARoUAAMSARcDKQE+AyIBMQMDAQRQAAMSARgBbQFdAVIBzAG7AVsBGQH/AbsB egFwAWsB/wNcAdsDEwEaFAADEgEXAykBPgMiATEDAwEEUAADEgEYAWABXQFaAcwBuwFbARkB/wG7AVsB
WwEZAf8BuwFbARkB/wG8AVsBGQH/AXUBXQFRAdQDIQEvBAH/AOUAAwIBAwM9AWkDTwHkA0UB7wNWAdAD GQH/AbsBWwEZAf8BvAFbARkB/wFmAV0BWwHUAyEBLwQB/wDlAAMCAQMDPQFpA1cB5ANNAe8DWwHQAzYB
NgFZAwQBBQwAAygBOwNKAewBqwGaAZMB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB WQMEAQUMAAMoATsDVAHsAasBmgGTAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B
zQHCAf8BqgGZAZIB/wNIAe0DKQE9DAADAwEEAzYEVwHPA0UB7wNPAeUDPgFqAwIBA0wAAxIBGAFtAV0B wgH/AaoBmQGSAf8DUgHtAykBPQwAAwMBBAM2AVcDXQHPA00B7wNZAeUDPgFqAwIBA0wAAxIBGAFgAV0B
UgHMAbsBWwEaAf8BuwFbARkB/wG7AVsBGQH/AbsBWwEZAf8BuwFbARkB/wFzAVwBTwHTAyIBMf8A4QAD WgHMAbsBWwEaAf8BuwFbARkB/wG7AVsBGQH/AbsBWwEZAf8BuwFbARkB/wFjAVwBWgHTAyIBMf8A4QAD
AgEDAzQBUwNHAfEBbwFpAWYB/wG3AasBpAH/AV0BWQFXAf8DOgH7A1EBpAMZASIDBAEFAwkBDAM/AW4B AgEDAzQBUwNRAfEBbwFpAWYB/wG3AasBpAH/AV0BWQFXAf8DOgH7A1EBpAMZASIDBAEFAwkBDAM/AW4B
OAI3AfsB3AHIAb4B/wHnAc4BwwH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B2AHAAbYB OAI3AfsB3AHIAb4B/wHnAc4BwwH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B2AHAAbYB
/wIzATIB/ANAAXEDCgENAwMBBAMYASADUQGiATsBOgE5AfsBXgFXAVQB/wG2AaMBmwH/AXABZwFjAf8D /wIwAS8B/ANAAXEDCgENAwMBBAMYASADUQGiATsBOgE5AfsBXgFXAVQB/wG2AaMBmwH/AXABZwFjAf8D
SAHyAzUBVQMCAQNIAAMSARgBbQFdAVIBzAG7AVsBGgH/AbsBWwEaAf8BuwFbARkB/wG7AVsBGQH/AbsB TgHyAzUBVQMCAQNIAAMSARgBYAFdAVoBzAG7AVsBGgH/AbsBWwEaAf8BuwFbARkB/wG7AVsBGQH/AbsB
WwEZAf8BuwFbARkB/wF1AV0BUQHUAxgBIP8A2QADAwEEAz0BaANHAfEBfwF0AW8B/wHjAcwBwQH/AewB WwEZAf8BuwFbARkB/wFmAV0BWwHUAxgBIP8A2QADAwEEAz0BaANRAfEBfwF0AW8B/wHjAcwBwQH/AewB
2gHQAf8B5AHVAcsB/wGnAZ0BlwH/AVMBUAFPAf8DTwHkA04BmANVAbQBTAJLAewBeAFyAW4B/wHtAdwB 2gHQAf8B5AHVAcsB/wGnAZ0BlwH/AVMBUAFPAf8DVwHkA04BmANVAbQDVAHsAXgBcgFuAf8B7QHcAdIB
0gH/AeoB1QHLAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AXUBawFnAf8D /wHqAdUBywH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wF1AWsBZwH/A1IB
SAHtA1QBtQNOAZcDUAHiAVMBTgFMAf8BpAGUAY0B/wHfAcYBuwH/AecBzQHCAf8B4wHJAb4B/wGAAXUB 7QNWAbUDTgGXA1kB4gFTAU4BTAH/AaQBlAGNAf8B3wHGAbsB/wHnAc0BwgH/AeMByQG+Af8BgAF1AXAB
cAH/A0gB8gM+AWoDAwEERAADEgEYAW0BXQFSAcwBugFbARoB/wG7AVsBGgH/AbsBWwEaAf8BuwFbARoB /wNOAfIDPgFqAwMBBEQAAxIBGAFgAV0BWgHMAboBWwEaAf8BuwFbARoB/wG7AVsBGgH/AbsBWwEaAf8B
/wG7AVsBGQH/AbsBWwEZAf8BuwFbARkB/wF2AVwBTgHWAyUBN/8A1QADIQEvA1AB4wFvAWoBZgH/AeMB uwFbARkB/wG7AVsBGQH/AbsBWwEZAf8BZwFcAVkB1gMlATf/ANUAAyEBLwNZAeMBbwFqAWYB/wHjAcwB
zAHCAf8B5wHNAcIB/wHoAdABxQH/Ae0B3AHSAf8B7QHdAdMB/wHoAdkBzwH/AYQBfgF5Af8DNwH/AU4B wgH/AecBzQHCAf8B6AHQAcUB/wHtAdwB0gH/Ae0B3QHTAf8B6AHZAc8B/wGEAX4BeQH/AzcB/wFOAUwB
TAFLAf8BtwGrAaUB/wHqAdsB0QH/Ae0B3QHTAf8B7QHdAdMB/wHrAdUBywH/AecBzQHCAf8B5wHNAcIB SwH/AbcBqwGlAf8B6gHbAdEB/wHtAd0B0wH/Ae0B3QHTAf8B6wHVAcsB/wHnAc0BwgH/AecBzQHCAf8B
/wHnAc0BwgH/AecBzQHCAf8B5QHLAcAB/wGzAaABmAH/AU0BSgFIAf8BNwI2Af8BgQF1AXEB/wHjAckB 5wHNAcIB/wHnAc0BwgH/AeUBywHAAf8BswGgAZgB/wFNAUoBSAH/ATcCNgH/AYEBdQFxAf8B4wHJAb8B
vwH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B4wHJAb4B/wFwAWcBYwH/A08B5QMiATEk /wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AeMByQG+Af8BcAFnAWMB/wNZAeUDIgExJAAD
AAMhATABVAFSAVABoAFZAVYBUwGrAVkBVgFTAasBWQFWAVMBqwFZAVYBUwGrAVkBVgFTAasBWQFWAVMB IQEwA1IBoAJWAVQBqwJWAVQBqwJWAVQBqwJWAVQBqwJWAVQBqwJWAVQBqwJYAVYBswGEAWIBSAHuAboB
qwFdAVgBUwGzAZQBXwE5Ae4BugFbARoB/wG6AVsBGgH/AbsBWwEaAf8BuwFbARoB/wG7AVsBGgH/AbsB WwEaAf8BugFbARoB/wG7AVsBGgH/AbsBWwEaAf8BuwFbARoB/wG7AVsBGgH/AbsBWwEZAf8BuwFbARkB
WwEaAf8BuwFbARkB/wG7AVsBGQH/AYkBXwFGAeUBWgFVAVMBrQFZAVYBUwGrAVkBVgFTAasBWQFWAVMB /wF3AV8BVAHlA1UBrQJWAVQBqwJWAVQBqwJWAVQBqwJUAVMBqQJWAVQBqwJWAVQBqwJWAVQBqwJWAVQB
qwFYAVQBUgGpAVsBWQFUAasBWwFZAVQBqwFbAVkBVAGrAVsBWQFUAasBWwFZAVQBqwFbAVkBVAGrAVsB qwJWAVQBqwJWAVQBqwJWAVQBqwJWAVQBqwJWAVQBqwJWAVQBqwJWAVQBqwNSAaADIQEw/wCNAAMoATwD
WQFUAasBWwFZAVQBqwFbAVkBVAGrAVsBWQFUAasBWwFZAVQBqwFVAVQBUQGgAyEBMP8AjQADKAE8A0gB UgHtAbcBqwGkAf8B7AHbAdAB/wHpAdEBxgH/AecBzQHCAf8B6AHRAcYB/wHsAdoB0AH/Ae0B3QHTAf8B
7QG3AasBpAH/AewB2wHQAf8B6QHRAcYB/wHnAc0BwgH/AegB0QHGAf8B7AHaAdAB/wHtAd0B0wH/AewB 7AHcAdIB/wHeAc8BxgH/AewB3AHSAf8B7QHdAdMB/wHtAd0B0wH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B
3AHSAf8B3gHPAcYB/wHsAdwB0gH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B0wH/Ae0B3QHTAf8B7QHdAdMB 0wH/AeoB1QHLAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AeYBzAHBAf8B
/wHqAdUBywH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHmAcwBwQH/AdgB 2AHAAbYB/wHmAcwBwQH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B
wAG2Af8B5gHMAcEB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB wgH/AbEBngGXAf8DTQHvAykBPSAAAyABLgGCAV0BTAHsAbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AbkB
/wGxAZ4BlwH/A0UB7wMpAT0gAAMgAS4BkwFdAT0B7AG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoB WgEaAf8BuQFaARoB/wG6AVoBGgH/AboBWgEaAf8BugFbARoB/wG6AVsBGgH/AboBWwEaAf8BugFbARoB
GgH/AbkBWgEaAf8BugFaARoB/wG6AVoBGgH/AboBWwEaAf8BugFbARoB/wG6AVsBGgH/AboBWwEaAf8B /wG6AVsBGgH/AboBWwEaAf8BuwFbARoB/wG7AVsBGgH/AbsBWwEaAf8BuwFbARkB/wG7AVsBGQH/AbsB
ugFbARoB/wG6AVsBGgH/AbsBWwEaAf8BuwFbARoB/wG7AVsBGgH/AbsBWwEZAf8BuwFbARkB/wG7AVsB WwEZAf8BuwFbARkB/wG7AVsBGQH/AbwBWwEZAf8BvwF1ASsB/AHsAaQBQgH/AewBpAFCAf8B7AGkAUIB
GQH/AbsBWwEZAf8BuwFbARkB/wG8AVsBGQH/AcUBdQErAfwB7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B /wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B6wGkAUIB/wHrAaQBQgH/AesB
7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AesBpAFCAf8B6wGkAUIB/wHrAaQB pAFCAf8B6wGkAUIB/wGPAXkBWQHrAyABLf8AiQADEAEVA1sBzQFcAVkBVgH/AeMB1AHLAf8B7QHcAdIB
QgH/AesBpAFCAf8BqwGGAVMB6wMgAS3/AIkAAxABFQNUAc0BXAFZAVYB/wHjAdQBywH/Ae0B3AHSAf8B /wHpAdEBxgH/AecBzQHCAf8B6AHQAcUB/wHsAdsB0QH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B0wH/Ae0B
6QHRAcYB/wHnAc0BwgH/AegB0AHFAf8B7AHbAdEB/wHtAd0B0wH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B 3QHTAf8B7QHdAdMB/wHtAd0B0wH/Ae0B3QHTAf8B7QHdAdMB/wHtAdwB0gH/AesB1QHKAf8B5wHNAcIB
0wH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B0wH/Ae0B3QHTAf8B7QHcAdIB/wHrAdUBygH/AecBzQHCAf8B /wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB
5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B zQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B3QHFAboB/wFaAVUBUgH/A10BzgMRARYgAAMzAVAB
wgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/Ad0BxQG6Af8BWgFVAVIB/wNWAc4DEQEWIAADMwFQAaIB lAFgATMB9gG5AVoBGwH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoB
XgEtAfYBuQFaARsB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB
/wG5AVoBGgH/AboBWgEaAf8BugFbARoB/wG6AVsBGgH/AboBWwEaAf8BugFbARoB/wG6AVsBGgH/AboB
WwEaAf8BuwFbARoB/wG7AVsBGgH/AbsBWwEaAf8BuwFbARkB/wG7AVsBGQH/AbsBWwEZAf8BtQFhAR4B
/gHQAYoBOwH9Ae0BpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewB
pAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHrAaQBQgH/AccBkwFIAfYDMwFQ/wCN
AAMzAVICQQFAAfoBpgGbAZUB/wHtAd0B0wH/AewB2wHQAf8B6QHRAcYB/wHrAdcB0AH/AewB2gHTAf8B
7AHbAdEB/wHtAd0B0wH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B0wH/Ae0B3QHTAf8B7QHdAdMB/wHqAdoB
0AH/AcYBuQGxAf8B6gHaAdAB/wHqAdUBygH/AecBzgHDAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B
5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wGhAZEB
iwH/AToCOQH7AzUBViQAAzMBUQGnAVsBLgH3AbgBWgEbAf8BuQFaARsB/wG5AVoBGwH/AbkBWgEaAf8B
uQFaARoB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG6AVoBGgH/AboBWgEaAf8BugFaARoB/wG6AVsB
GgH/AboBWwEaAf8BugFbARoB/wG6AVsBGgH/AboBWwEaAf8BuwFbARoB/wG7AVsBGgH/AbsBWwEaAf8B
uwFbARkB/wG7AVsBGQH/AboBZwEiAf4B2wGZAUAB/QHtAaQBQgH/Ae0BpAFCAf8B7AGkAUIB/wHsAaQB
QgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B
7AGkAUIB/wHHAZMBSAH2AzMBUf8AjQADAwEEA1ABnQFSAU8BTQH/AecB1wHNAf8B7QHdAdMB/wHwAeQB
3wH/AfYB8gH3Af8B9QHxAfUB/wHtAdsB1QH/AewB2gHQAf8B7QHdAdMB/wHYAcoBwQH/AcYBuQGxAf8B
6AHWAcwB/wHfAcsBwQH/Ac8BuwGxAf8BQQI/Af8BzwG6AbEB/wHfAcoBwAH/AaQBlgGPAf8BjwGCAXwB
/wHmAcwBwQH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB
zQHCAf8B4QHIAb4B/wFQAUwBSgH/A1EBogMDAQQkAAMzAVEBpwFbAS4B9wG4AVoBGwH/AbgBWgEbAf8B
uAFaARsB/wG5AVoBGwH/AbkBWgEbAf8BuQFaARoB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoB
GgH/AbkBWgEaAf8BugFaARoB/wG6AVsBGgH/AboBWwEaAf8BugFbARoB/wG6AVsBGgH/AboBWwEaAf8B GgH/AbkBWgEaAf8BugFaARoB/wG6AVsBGgH/AboBWwEaAf8BugFbARoB/wG6AVsBGgH/AboBWwEaAf8B
ugFbARoB/wG7AVsBGgH/AbsBWwEaAf8BuwFbARoB/wHDAXMBKwH8AewBowFBAf8B7QGkAUIB/wHtAaQB ugFbARoB/wG7AVsBGgH/AbsBWwEaAf8BuwFbARoB/wG7AVsBGQH/AbsBWwEZAf8BuwFbARkB/wGvAWQB
QgH/Ae0BpAFCAf8B7QGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B IQH+AccBigFAAf0B7QGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B
7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8ByQGTAUgB9gMzAVH/AJEAAxcBHwNQAd8BfwF5AXQB/wHsAdwB 7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AesBpAFCAf8BsgGJAUgB9gMzAVD/
0gH/Ae0B3QHUAf8B9ALtAf8B8AHkAeIB/wHnAc0BwgH/AeUBzgHDAf8BuwGvAagB/wFGAUQBQwH/AU8B AI0AAzMBUgJHAUYB+gGmAZsBlQH/Ae0B3QHTAf8B7AHbAdAB/wHpAdEBxgH/AesB1wHQAf8B7AHaAdMB
SwFJAf8B0AG3AawB/wHQAbcBrAH/AcQBrQGjAf8BOAI3Af8BxAGtAaMB/wHDAawBogH/AU8BSwFJAf8B /wHsAdsB0QH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B0wH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B0wH/AeoB
ZAFcAVkB/wHiAcgBvQH/AeYBzAHBAf8B5gHMAcEB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B 2gHQAf8BxgG5AbEB/wHqAdoB0AH/AeoB1QHKAf8B5wHOAcMB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB
wgH/AeYBzAHBAf8BfgF0AW4B/wNQAeIDGAEgKAADMwFRAacBWwEuAfcBuAFaARsB/wG4AVoBGwH/AbgB /wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AaEB
WgEbAf8BuAFaARsB/wG4AVoBGwH/AbkBWgEbAf8BuQFaARoB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB kQGLAf8BOgI5AfsDNQFWJAADMwFRAZ4BWwE2AfcBuAFaARsB/wG5AVoBGwH/AbkBWgEbAf8BuQFaARoB
/wG5AVoBGgH/AbkBWgEaAf8BugFaARoB/wG6AVoBGgH/AboBWwEaAf8BugFbARoB/wG6AVsBGgH/AboB /wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AboBWgEaAf8BugFaARoB/wG6AVoBGgH/AboB
WwEaAf8BugFbARoB/wG6AVsBGgH/AbsBWwEaAf8B0wGMATgB+wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB WwEaAf8BugFbARoB/wG6AVsBGgH/AboBWwEaAf8BugFbARoB/wG7AVsBGgH/AbsBWwEaAf8BuwFbARoB
/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHtAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewB /wG7AVsBGQH/AbsBWwEZAf8BtAFqASUB/gHSAZkBQAH9Ae0BpAFCAf8B7QGkAUIB/wHsAaQBQgH/AewB
pAFCAf8B7AGkAUIB/wHsAaQBQgH/AckBkwFIAfYDMwFR/wCRAAMDAQQDTQGTAzYB/wHaAcoBwQH/Ae0B pAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB
3QHTAf8B7gHfAdYB/wHtAd0B1AH/AeUBzgHDAf8BlgGIAYIB/wE4AjcB/wFsAWMBXwH/AbYBoQGYAf8B /wHsAaQBQgH/AbIBiQFIAfYDMwFR/wCNAAMDAQQDUAGdAVIBTwFNAf8B5wHXAc0B/wHtAd0B0wH/AfAB
0AG3AawB/wHQAbcBrAH/AcwBtAGpAf8BnAGLAYQB/wHMAbQBqQH/AbYBogGYAf8BVAFPAUwB/wGqAZcB 5AHfAf8B9gHyAfcB/wH1AfEB9QH/Ae0B2wHVAf8B7AHaAdAB/wHtAd0B0wH/AdgBygHBAf8BxgG5AbEB
jwH/Ac8BtgGsAf8BlAGFAYAB/wGvAZ4BlgH/AeYBzAHBAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B /wHoAdYBzAH/Ad8BywHBAf8BzwG7AbEB/wFBAj8B/wHPAboBsQH/Ad8BygHAAf8BpAGWAY8B/wGPAYIB
2QHAAbYB/wE3AjYB/wNOAZYDAwEEKAADMwFRAacBWwEuAfcBuAFaARsB/wG4AVoBGwH/AbgBWgEbAf8B fAH/AeYBzAHBAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B
uAFaARsB/wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB/wG5AVoBGwH/AbkBWgEaAf8BuQFaARoB/wG5AVoB 5wHNAcIB/wHhAcgBvgH/AVABTAFKAf8DUQGiAwMBBCQAAzMBUQGeAVsBNgH3AbgBWgEbAf8BuAFaARsB
GgH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AboBWgEaAf8BugFaARoB/wG6AVsBGgH/AboBWwEaAf8B /wG4AVoBGwH/AbkBWgEbAf8BuQFaARsB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AbkB
ugFbARoB/wG6AVsBGgH/AboBZgEoAfwB5gGcAUUB/gHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHtAaQB WgEaAf8BuQFaARoB/wG6AVoBGgH/AboBWwEaAf8BugFbARoB/wG6AVsBGgH/AboBWwEaAf8BugFbARoB
QgH/Ae0BpAFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHsAaQBQgH/AewBpAFCAf8B /wG6AVsBGgH/AbsBWwEaAf8BuwFbARoB/wG7AVsBGgH/Ab0BcwErAfwB7AGjAUEB/wHtAaQBQgH/Ae0B
7AGkAUIB/wHsAaQBQgH/AckBkwFIAfYDMwFR/wCRAAMJAQwDVAGyAUkBRgFFAf8B5gHPAcQB/wHtAdwB pAFCAf8B7QGkAUIB/wHtAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB
0gH/Ae0B3QHTAf8B7QHdAdMB/wG8AbABqAH/AjgBNwH/AXsBcAFrAf8BzgG1AaoB/wHQAbcBrAH/AdAB /wHsAaQBQgH/AewBpAFCAf8B7AGkAUIB/wGyAYkBSAH2AzMBUf8AkQADFwEfA1gB3wF/AXkBdAH/AewB
twGsAf8B0AG3AawB/wHQAbcBrAH/AdABtwGsAf8B0AG3AawB/wHPAbYBqwH/AcwBtAGpAf8BzwG2AasB 3AHSAf8B7QHdAdQB/wH0Au0B/wHwAeQB4gH/AecBzQHCAf8B5QHOAcMB/wG7Aa8BqAH/AUYBRAFDAf8B
/wGEAXcBcgH/AzUB/wGTAYUBfwH/AeYBzAHBAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5gHMAcEB TwFLAUkB/wHQAbcBrAH/AdABtwGsAf8BxAGtAaMB/wE4AjcB/wHEAa0BowH/AcMBrAGiAf8BTwFLAUkB
/wFQAUsBSgH/A1UBtAMJAQwoAAMzAVEBpgFbAS4B9wG3AVoBGwH/AbgBWgEbAf8BuAFaARsB/wG4AVoB /wFkAVwBWQH/AeIByAG9Af8B5gHMAcEB/wHmAcwBwQH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB
GwH/AbgBWgEbAf8BuAFaARsB/wG4AVoBGwH/AbgBWgEbAf8BuQFaARsB/wG5AVoBGgH/AbkBWgEaAf8B zQHCAf8B5gHMAcEB/wF+AXQBbgH/A1kB4gMYASAoAAMzAVEBngFbATYB9wG4AVoBGwH/AbgBWgEbAf8B
uQFaARoB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG6AVoBGgH/AboBWgEaAf8BugFbARoB/wG6AVsB uAFaARsB/wG4AVoBGwH/AbgBWgEbAf8BuQFaARsB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoB
GgH/AboBWwEaAf8BygF9ATEB+wHuAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8B GgH/AbkBWgEaAf8BuQFaARoB/wG6AVoBGgH/AboBWgEaAf8BugFbARoB/wG6AVsBGgH/AboBWwEaAf8B
7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7AGkAUIB/wHsAaQB ugFbARoB/wG6AVsBGgH/AboBWwEaAf8BuwFbARoB/wHKAYkBOAH7Ae0BpAFCAf8B7QGkAUIB/wHtAaQB
QgH/AewBpAFCAf8ByQGTAUgB9gMzAVH/AIkAAxMBGgMpAT0DQAFwA0wB6wGvAZ8BmAH/AecBzQHCAf8B QgH/Ae0BpAFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8B
6QHRAcYB/wHsAdsB0AH/AdYByAG/Af8BRgFEAUMB/wFrAWIBXgH/Ac4BtQGqAf8B0AG3AawB/wHOAbYB 7AGkAUIB/wHsAaQBQgH/AewBpAFCAf8BsgGJAUgB9gMzAVH/AJEAAwMBBANNAZMDNgH/AdoBygHBAf8B
qwH/AaIBkQGJAf8BaAFgAVwB/wFBAT8BPgH/AzUB/wFBAT4BPQH/AWgBXwFbAf8BogGQAYgB/wHNAbQB 7QHdAdMB/wHuAd8B1gH/Ae0B3QHUAf8B5QHOAcMB/wGWAYgBggH/ATgCNwH/AWwBYwFfAf8BtgGhAZgB
qgH/AZQBhQF+Af8BhAF3AXEB/wHPAbYBrAH/AeMByQG+Af8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B /wHQAbcBrAH/AdABtwGsAf8BzAG0AakB/wGcAYsBhAH/AcwBtAGpAf8BtgGiAZgB/wFUAU8BTAH/AaoB
5wHNAcIB/wG0AaIBmgH/A0wB6wM/AW4DKAE8AxMBGSAAAzMBUQGmAVsBLgH3AbcBWgEbAf8BtwFaARsB lwGPAf8BzwG2AawB/wGUAYUBgAH/Aa8BngGWAf8B5gHMAcEB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB
/wG4AVoBGwH/AbgBWgEbAf8BwwFyATwB/wHLAYUBVgH/Ab8BaQEwAf8BuAFaARsB/wG4AVoBGwH/AbkB /wHZAcABtgH/ATcCNgH/A04BlgMDAQQoAAMzAVEBngFbATYB9wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB
WgEbAf8BuQFaARsB/wG9AWQBKAH/AcsBhQFWAf8BxQF2AUEB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB /wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB/wG4AVoBGwH/AbkBWgEbAf8BuQFaARoB/wG5AVoBGgH/AbkB
/wG6AVoBGgH/AboBWwEaAf8BvgFdASUB/QHaAZcBQAH9Ae4BpAFCAf8B7gGkAUIB/wHeAZQBOgH/Ae0B WgEaAf8BuQFaARoB/wG5AVoBGgH/AbkBWgEaAf8BugFaARoB/wG6AVoBGgH/AboBWwEaAf8BugFbARoB
owFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHrAaIBQQH/Ad0BkwE6Af8B7QGkAUIB /wG6AVsBGgH/AboBWwEaAf8BtAFmASsB/AHgAZYBSAH+Ae0BpAFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0B
/wHtAaQBQgH/AewBpAFCAf8B7AGkAUIB/wHJAZMBSAH2AzMBUf8AfQADEQEWA0ABcANWAboDVQHbA0gB pAFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHtAaQBQgH/AewBpAFCAf8B7AGkAUIB
7QMzAfwBdgFwAW0B/wHpAdkBzwH/AekB0QHHAf8B5wHNAcIB/wHoAdABxQH/AYUBfQF3Af8BPgE8ATsB /wHsAaQBQgH/AewBpAFCAf8BsgGJAUgB9gMzAVH/AJEAAwkBDANWAbIBSQFGAUUB/wHmAc8BxAH/Ae0B
/wGxAZ0BlAH/AdABtwGsAf8BzgG2AasB/wGCAXUBcAH/AT0CPAH/AUsBYAFnAf8BcgGnAboB/wF9AbsB 3AHSAf8B7QHdAdMB/wHtAd0B0wH/AbwBsAGoAf8COAE3Af8BewFwAWsB/wHOAbUBqgH/AdABtwGsAf8B
0gH/AXIBqAG8Af8BTAFhAWgB/wE9AjwB/wGBAXQBbwH/Ac0BtQGqAf8BzwG2AasB/wHAAakBnwH/AYUB 0AG3AawB/wHQAbcBrAH/AdABtwGsAf8B0AG3AawB/wHQAbcBrAH/Ac8BtgGrAf8BzAG0AakB/wHPAbYB
eAFzAf8BoAGQAYkB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHlAcsBwAH/AXkBbwFqAf8COAE3AfsD qwH/AYQBdwFyAf8DNQH/AZMBhQF/Af8B5gHMAcEB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHmAcwB
SgHsA1UB2wNWAbgDQAFvAxEBFhQAAzMBUQGmAVsBLgH3AbcBWgEbAf8BtwFaARsB/wG3AVoBGwH/AbcB wQH/AVABSwFKAf8DVQG0AwkBDCgAAzMBUQGdAVsBNgH3AbcBWgEbAf8BuAFaARsB/wG4AVoBGwH/AbgB
WgEbAf8BzgGMAWEB/wH7AfUB8QH/Ad0BsQGTAf8BuAFaARsB/wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB WgEbAf8BuAFaARsB/wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB/wG5AVoBGwH/AbkBWgEaAf8BuQFaARoB
/wHWAaABfAH/AfsB9QHxAf8B1wGhAX4B/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AbkB /wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AboBWgEaAf8BugFaARoB/wG6AVsBGgH/AboB
WgEaAf8BvgFqASwB/QHkAZkBRAH+Ae4BpAFCAf8B2QGPATgB/wGWAUwBFwH/AcUBegEuAf8B7AGjAUEB WwEaAf8BugFbARoB/wHBAXcBMQH7Ae4BpAFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB
/wHtAaQBQgH/Ae0BpAFCAf8B6QGgAUAB/wG5AW0BJwH/AZgBSgEVAf8B3gGUAToB/wHtAaQBQgH/Ae0B /wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHsAaQBQgH/AewB
pAFCAf8B7QGkAUIB/wHKAZMBSAH2AzMBUf8AeQADJgE4A0IB8wFGAUMBQgH/AVcBUgFPAf8BeQFvAWoB pAFCAf8B7AGkAUIB/wGyAYkBSAH2AzMBUf8AiQADEwEaAykBPQNAAXADVgHrAa8BnwGYAf8B5wHNAcIB
/wGqAZkBkgH/AdoBxgG9Af8B7QHcAdIB/wHtAd0B0wH/AewB2wHRAf8B6AHQAcYB/wHWAb4BtAH/AVcB /wHpAdEBxgH/AewB2wHQAf8B1gHIAb8B/wFGAUQBQwH/AWsBYgFeAf8BzgG1AaoB/wHQAbcBrAH/Ac4B
UQFPAf8BZAFcAVgB/wHQAbcBrAH/AdABtwGsAf8BowGRAYkB/wE9AjwB/wFaAXsBiAH/AYsB1gHwAf8B tgGrAf8BogGRAYkB/wFoAWABXAH/AUEBPwE+Af8DNQH/AUEBPgE9Af8BaAFfAVsB/wGiAZABiAH/Ac0B
jwHdAfkB/wGPAd0B+QH/AY8B3QH5Af8BiwHWAfEB/wFbAXwBiQH/AT0CPAH/AaIBkAGJAf8BzAG0AakB tAGqAf8BlAGFAX4B/wGEAXcBcQH/Ac8BtgGsAf8B4wHJAb4B/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB
/wFNAUkBRwH/AUcBRAFCAf8BiwF/AXoB/wHmAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB /wHnAc0BwgH/AbQBogGaAf8DVgHrAz8BbgMoATwDEwEZIAADMwFRAZ0BWwE2AfcBtwFaARsB/wG3AVoB
zQHCAf8B3QHEAboB/wGvAZ0BlgH/AX4BcwFvAf8BWQFUAVEB/wFHAUQBQwH/A0IB8wMnATkQAAMzAVEB GwH/AbgBWgEbAf8BuAFaARsB/wHDAXIBPAH/AcsBhQFWAf8BvwFpATAB/wG4AVoBGwH/AbgBWgEbAf8B
pgFbAS4B9wG3AVoBGwH/AbcBWgEbAf8BtwFaARsB/wG3AVoBGwH/AbgBXgEgAf8B+QHxAewB/wH4Ae4B uQFaARsB/wG5AVoBGwH/Ab0BZAEoAf8BywGFAVYB/wHFAXYBQQH/AbkBWgEaAf8BuQFaARoB/wG5AVoB
5wH/AckBgQFQAf8ByQGBAVAB/wHJAYEBUAH/AckBgQFQAf8B9AHlAdwB/wH7AfYB8wH/AcYBeAFEAf8B GgH/AboBWgEaAf8BugFbARoB/wG+AVoBKwH9AdEBlwFAAf0B7gGkAUIB/wHuAaQBQgH/Ad4BlAE6Af8B
uQFaARoB/wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AcgBewEwAfsB7gGkAUIB/wHtAaMB 7QGjAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wHtAaQBQgH/AesBogFBAf8B3QGTAToB/wHtAaQB
QgH/AbwBcgEqAf8BjQFCARIB/wGOAUIBEgH/Ab8BdAErAf8B6AGeAT8B/wHbAZEBOQH/AaMBVQEbAf8B QgH/Ae0BpAFCAf8B7AGkAUIB/wHsAaQBQgH/AbIBiQFIAfYDMwFR/wB9AAMRARYDQAFwA1gBugNcAdsD
jgE/ARAB/wGYAUoBFgH/AcwBggExAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8BygGTAUgB9gMzAVH/ UgHtAzAB/AF2AXABbQH/AekB2QHPAf8B6QHRAccB/wHnAc0BwgH/AegB0AHFAf8BhQF9AXcB/wE+ATwB
AHkAA04BlAE6AjkB/wHCAa0BpAH/Ad4BxQG7Af8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B6gHUAcoB OwH/AbEBnQGUAf8B0AG3AawB/wHOAbYBqwH/AYIBdQFwAf8BPQI8Af8BSwFgAWcB/wFyAacBugH/AX0B
/wHtAd0B0wH/Ae0B3QHTAf8B7AHbAdEB/wHFAbMBqgH/AUMBQAE/Af8BoAGOAYcB/wHQAbcBrAH/AdAB uwHSAf8BcgGoAbwB/wFMAWEBaAH/AT0CPAH/AYEBdAFvAf8BzQG1AaoB/wHPAbYBqwH/AcABqQGfAf8B
twGsAf8BagFhAV0B/wFKAV4BZQH/AYsB1gHwAf8BjwHdAfkB/wGPAd0B+QH/AY8B3QH5Af8BjwHdAfkB hQF4AXMB/wGgAZABiQH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AeUBywHAAf8BeQFvAWoB/wI4ATcB
/wGPAd0B+QH/AYsB1gHxAf8BSwFgAWgB/wFoAWABXAH/Ac8BtgGrAf8BqAGWAY0B/wG4AaMBmQH/Ad0B +wNUAewDXAHbA1gBuANAAW8DEQEWFAADMwFRAZ0BWwE2AfcBtwFaARsB/wG3AVoBGwH/AbcBWgEbAf8B
yQG/Af8B6gHVAcoB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB twFaARsB/wHOAYwBYQH/AfsB9QHxAf8B3QGxAZMB/wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB/wG4AVoB
/wHnAc0BwgH/AeABxwG9Af8BxgGxAacB/wE7AjkB/wNOAZYQAAMzAVEBpQFbAS4B9wG3AVoBGwH/AbcB GwH/AdYBoAF8Af8B+wH1AfEB/wHXAaEBfgH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AbkBWgEaAf8B
WgEbAf8BtwFaARsB/wG3AVoBGwH/AbcBWwEcAf8B5gHGAbEZ/wHvAdkBywH/Ab4BZwEtAf8BuAFaARsB uQFaARoB/wG+AWcBMgH9Ad4BkwFHAf4B7gGkAUIB/wHZAY8BOAH/AZYBTAEXAf8BxQF6AS4B/wHsAaMB
/wG5AVoBGwH/AbkBWgEaAf8BuQFaARoB/wGyAV8BHgH+AdQBjgE5AfwB7gGkAUIB/wHuAaQBQgH/AekB QQH/Ae0BpAFCAf8B7QGkAUIB/wHpAaABQAH/AbkBbQEnAf8BmAFKARUB/wHeAZQBOgH/Ae0BpAFCAf8B
nwE/Af8BxwF9AS8B/wGTAUcBFQH/AY0BQQESAf8BpwFbAR4B/wGZAUwBFgH/AY4BQAERAf8BrwFhASEB 7QGkAUIB/wHtAaQBQgH/AbMBiQFIAfYDMwFR/wB5AAMmATgDTAHzAUYBQwFCAf8BVwFSAU8B/wF5AW8B
/wHbAZEBOQH/AewBowFCAf8B7QGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8BygGTAUgB9gMzAVH/AHkAA1EB agH/AaoBmQGSAf8B2gHGAb0B/wHtAdwB0gH/Ae0B3QHTAf8B7AHbAdEB/wHoAdABxgH/AdYBvgG0Af8B
ogE9ATwBOwH/AeYBzAHBAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AeoB VwFRAU8B/wFkAVwBWAH/AdABtwGsAf8B0AG3AawB/wGjAZEBiQH/AT0CPAH/AVoBewGIAf8BiwHWAfAB
1AHJAf8B7QHdAdMB/wHtAd0B0wH/Ab0BsQGpAf8BNwI2Af8BxAGtAaMB/wHQAbcBrAH/AdABtwGsAf8B /wGPAd0B+QH/AY8B3QH5Af8BjwHdAfkB/wGLAdYB8QH/AVsBfAGJAf8BPQI8Af8BogGQAYkB/wHMAbQB
QwFAAT8B/wFwAaUBtwH/AY8B3QH5Af8BjwHdAfkB/wFsAZwBrQH/AToBQQFEAf8BagGaAasB/wGPAd0B qQH/AU0BSQFHAf8BRwFEAUIB/wGLAX8BegH/AeYBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B
+QH/AY8B3QH5Af8BcgGnAboB/wFBAT8BPgH/AdABtwGsAf8BzAGzAakB/wHEAa0BowH/Ac8BuwGxAf8B 5wHNAcIB/wHdAcQBugH/Aa8BnQGWAf8BfgFzAW8B/wFZAVQBUQH/AUcBRAFDAf8DTAHzAycBORAAAzMB
6gHaAdAB/wHrAdUBygH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B UQGdAVsBNgH3AbcBWgEbAf8BtwFaARsB/wG3AVoBGwH/AbcBWgEbAf8BuAFeASAB/wH5AfEB7AH/AfgB
wgH/AecBzQHCAf8B5wHNAcIB/wE9ATwBOwH/A1EBoRAAAzMBUQGlAVsBLwH3AbYBWgEcAf8BtwFaARsB 7gHnAf8ByQGBAVAB/wHJAYEBUAH/AckBgQFQAf8ByQGBAVAB/wH0AeUB3AH/AfsB9gHzAf8BxgF4AUQB
/wG3AVoBGwH/AbcBWgEbAf8BtwFaARsB/wHUAZwBdgH/Af4B/QH8Af8B9gHqAeMB/wHjAcABqAH/AeQB /wG5AVoBGgH/AbkBWgEaAf8BuQFaARoB/wG5AVoBGgH/AbkBWgEaAf8BvwF1ATAB+wHuAaQBQgH/Ae0B
wAGnAf8B8gHgAdQF/wHhAbgBnAH/AbgBWwEcAf8BuAFaARsB/wG4AVoBGwH/AbkBWgEbAf8BuQFaARsB owFCAf8BvAFyASoB/wGNAUIBEgH/AY4BQgESAf8BvwF0ASsB/wHoAZ4BPwH/AdsBkQE5Af8BowFVARsB
/wG1AW4BKgH6Ae8BowFCAf8B7wGjAUIB/wHuAaQBQgH/Ae4BpAFCAf8B7gGkAUIB/wHNAYMBMgH/AZAB /wGOAT8BEAH/AZgBSgEWAf8BzAGCATEB/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wGzAYkBSAH2AzMB
RAETAf8BjAFAAREB/wGNAT8BEAH/AbgBbAEmAf8B7AGiAUEB/wHuAaQBQgH/Ae0BpAFCAf8B7QGkAUIB Uf8AeQADTgGUAToCOQH/AcIBrQGkAf8B3gHFAbsB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHqAdQB
/wHtAaQBQgH/Ae0BpAFCAf8BygGTAUgB9gMzAVH/AHkAA1EBogE9ATwBOwH/AeYBzAHBAf8B5wHNAcIB ygH/Ae0B3QHTAf8B7QHdAdMB/wHsAdsB0QH/AcUBswGqAf8BQwFAAT8B/wGgAY4BhwH/AdABtwGsAf8B
/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B6gHUAcoB/wHtAdwB0gH/AbgB 0AG3AawB/wFqAWEBXQH/AUoBXgFlAf8BiwHWAfAB/wGPAd0B+QH/AY8B3QH5Af8BjwHdAfkB/wGPAd0B
rAGlAf8DMwH/Ac4BtQGqAf8B0AG3AawB/wHQAbcBrAH/ATgCNwH/AXwBuQHQAf8BjwHdAfkB/wGPAd0B +QH/AY8B3QH5Af8BiwHWAfEB/wFLAWABaAH/AWgBYAFcAf8BzwG2AasB/wGoAZYBjQH/AbgBowGZAf8B
+QH/AT0BRgFJAf8DMwH/ATsBQwFFAf8BjwHdAfkB/wGPAd0B+QH/AXwBuwHRAf8BNgI1Af8B0AG3AawB 3QHJAb8B/wHqAdUBygH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B
/wGcAYsBgwH/ATgCNwH/AUEBQAE/Af8BxwG6AbIB/wHtAdwB0gH/AeoB1QHKAf8B5wHNAcIB/wHnAc0B wgH/AecBzQHCAf8B4AHHAb0B/wHGAbEBpwH/ATsCOQH/A04BlhAAAzMBUQGbAVsBNgH3AbcBWgEbAf8B
wgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wE9ATwBOwH/A1EBoRAAAzMB twFaARsB/wG3AVoBGwH/AbcBWgEbAf8BtwFbARwB/wHmAcYBsRn/Ae8B2QHLAf8BvgFnAS0B/wG4AVoB
UQGlAVsBLwH3AbYBWgEcAf8BtgFaARwB/wG3AVoBGwH/AbcBWgEbAf8BtwFaARsB/wHFAXoBRwH/AfkB GwH/AbkBWgEbAf8BuQFaARoB/wG5AVoBGgH/AawBYgEhAf4BzgGFATYB/AHuAaQBQgH/Ae4BpAFCAf8B
8gHtAf8B8QHeAdIB/wG9AWgBLwH/AboBYAEjAf8B6AHJAbQF/wHMAYgBWwH/AbgBWgEbAf8BuAFaARsB 6QGfAT8B/wHHAX0BLwH/AZMBRwEVAf8BjQFBARIB/wGnAVsBHgH/AZkBTAEWAf8BjgFAAREB/wGvAWEB
/wG4AVoBGwH/AbgBWgEbAf8BsgFfAR8B/gHTAY0BOQH7Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8B IQH/AdsBkQE5Af8B7AGjAUIB/wHtAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wGzAYkBSAH2AzMBUf8AeQAD
pAFCAf8B7gGkAUIB/wHOAYMBMgH/AZEBRQETAf8BjAFAAREB/wGOAUABEQH/AcUBeQEtAf8B7QGjAUIB UQGiAT0BPAE7Af8B5gHMAcEB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B
/wHuAaQBQgH/Ae4BpAFCAf8B7gGkAUIB/wHtAaQBQgH/Ae0BpAFCAf8BygGTAUgB9gMzAVH/AHkAA1EB 6gHUAckB/wHtAd0B0wH/Ae0B3QHTAf8BvQGxAakB/wE3AjYB/wHEAa0BowH/AdABtwGsAf8B0AG3AawB
ogE9ATwBOwH/AeYBzAHBAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB /wFDAUABPwH/AXABpQG3Af8BjwHdAfkB/wGPAd0B+QH/AWwBnAGtAf8BOgFBAUQB/wFqAZoBqwH/AY8B
zQHCAf8B5wHNAcIB/wHqAdQBygH/Ab0BsQGqAf8CNwE2Af8BwwGsAaIB/wHQAbcBrAH/AdABtwGsAf8B 3QH5Af8BjwHdAfkB/wFyAacBugH/AUEBPwE+Af8B0AG3AawB/wHMAbMBqQH/AcQBrQGjAf8BzwG7AbEB
QwFBAUAB/wFvAaMBtgH/AY8B3QH5Af8BjwHdAfkB/wFuAaABsQH/AT4BSAFLAf8BbQGeAa8B/wGPAd0B /wHqAdoB0AH/AesB1QHKAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB
+QH/AY8B3QH5Af8BcQGmAbgB/wFCAUABPgH/AdABtwGsAf8BzAG0AakB/wHEAa0BowH/Ac8BuwGxAf8B zQHCAf8B5wHNAcIB/wHnAc0BwgH/AT0BPAE7Af8DUQGhEAADMwFRAZsBWwE3AfcBtgFaARwB/wG3AVoB
6gHaAdAB/wHtAd0B0wH/Ae0B3QHTAf8B6wHVAcoB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B GwH/AbcBWgEbAf8BtwFaARsB/wG3AVoBGwH/AdQBnAF2Af8B/gH9AfwB/wH2AeoB4wH/AeMBwAGoAf8B
wgH/AecBzQHCAf8B5wHNAcIB/wE9ATwBOwH/A1EBoRAAAzMBUQGlAVsBLwH3AbYBWgEcAf8BtgFaARwB 5AHAAacB/wHyAeAB1AX/AeEBuAGcAf8BuAFbARwB/wG4AVoBGwH/AbgBWgEbAf8BuQFaARsB/wG5AVoB
/wG2AVoBHAH/AbYBWgEcAf8BtgFaARsB/wG4AV0BHwH/AfEB3wHSAf8B+gHzAe8B/wHHAX8BTgH/Ab4B GwH/AawBbgEtAfoB7wGjAUIB/wHvAaMBQgH/Ae4BpAFCAf8B7gGkAUIB/wHuAaQBQgH/Ac0BgwEyAf8B
aQEwAf8B9gHrAeQB/wH7AfUB8gH/AboBXwEhAf8BuAFaARsB/wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB kAFEARMB/wGMAUABEQH/AY0BPwEQAf8BuAFsASYB/wHsAaIBQQH/Ae4BpAFCAf8B7QGkAUIB/wHtAaQB
/wG+AWQBKgH9AeUBmAFEAf4B7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHpAZ0BPwH/AZcB QgH/Ae0BpAFCAf8B7QGkAUIB/wGzAYkBSAH2AzMBUf8AeQADUQGiAT0BPAE7Af8B5gHMAcEB/wHnAc0B
SwEWAf8BjAFAAREB/wGsAWABIAH/AZEBQwESAf8BlQFGARQB/wHWAYsBNgH/Ae4BpAFCAf8B7gGkAUIB wgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHqAdQBygH/Ae0B3AHSAf8B
/wHuAaQBQgH/Ae4BpAFCAf8B7QGkAUIB/wHKAZMBSAH2AzMBUf8AeQADTQGSAToCOQH/AcIBrQGkAf8B uAGsAaUB/wMzAf8BzgG1AaoB/wHQAbcBrAH/AdABtwGsAf8BOAI3Af8BfAG5AdAB/wGPAd0B+QH/AY8B
3QHFAboB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B 3QH5Af8BPQFGAUkB/wMzAf8BOwFDAUUB/wGPAd0B+QH/AY8B3QH5Af8BfAG7AdEB/wE2AjUB/wHQAbcB
wgH/AcYBtAGrAf8BRAFCAUEB/wGeAY0BhQH/AdABtwGsAf8B0AG3AawB/wFrAWIBXgH/AUkBXAFkAf8B rAH/AZwBiwGDAf8BOAI3Af8BQQFAAT8B/wHHAboBsgH/Ae0B3AHSAf8B6gHVAcoB/wHnAc0BwgH/AecB
iwHVAe8B/wGPAd0B+QH/AY8B3QH5Af8BjwHdAfkB/wGPAd0B+QH/AY8B3QH5Af8BiwHVAfAB/wFKAV4B zQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AT0BPAE7Af8DUQGhEAAD
ZQH/AWkBYQFdAf8BzwG2AasB/wG2AaEBmAH/AcIBqwGhAf8B4AHMAcEB/wHtAd0B0wH/Ae0B3QHTAf8B MwFRAZsBWwE3AfcBtgFaARwB/wG2AVoBHAH/AbcBWgEbAf8BtwFaARsB/wG3AVoBGwH/AcUBegFHAf8B
7QHdAdMB/wHtAd0B0wH/AeoB1QHKAf8B5wHOAcMB/wHnAc0BwgH/AecBzQHCAf8B2wHDAbkB/wHBAawB +QHyAe0B/wHxAd4B0gH/Ab0BaAEvAf8BugFgASMB/wHoAckBtAX/AcwBiAFbAf8BuAFaARsB/wG4AVoB
pAH/AToCOQH/A04BlRAAAzMBUQGlAVsBLwH3AbYBWgEcAf8BtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8B GwH/AbgBWgEbAf8BuAFaARsB/wGsAWIBIgH+AcoBigE5AfsB7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B
tgFaARwB/wG2AVoBGwH/AdYBoAF8Bf8B1wGjAYAB/wHNAYwBXwP/Af4B/wHdAbABkwH/AbcBWgEbAf8B 7wGkAUIB/wHuAaQBQgH/Ac4BgwEyAf8BkQFFARMB/wGMAUABEQH/AY4BQAERAf8BxQF5AS0B/wHtAaMB
uAFaARsB/wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB/wHIAXoBKwH8Ae4BogFBAf8B7wGjAUIB/wHvAaMB QgH/Ae4BpAFCAf8B7gGkAUIB/wHuAaQBQgH/Ae0BpAFCAf8B7QGkAUIB/wGzAYkBSAH2AzMBUf8AeQAD
QgH/Ae8BowFCAf8B7wGjAUIB/wHRAYUBMwH/AZsBUAEZAf8BuQFtASgB/wHrAaABQQH/AbgBbAEmAf8B UQGiAT0BPAE7Af8B5gHMAcEB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B
jgE/ARAB/wGoAVsBHgH/AewBoQFBAf8B7gGkAUIB/wHuAaQBQgH/Ae4BpAFCAf8B7gGkAUIB/wHKAZMB 5wHNAcIB/wHnAc0BwgH/AeoB1AHKAf8BvQGxAaoB/wI3ATYB/wHDAawBogH/AdABtwGsAf8B0AG3AawB
SAH2AzMBUf8AeQADIwEzA0gB7gFFAUMBQQH/AVYBUQFPAf8BeAFuAWoB/wGpAZgBkQH/AdgBwAG2Af8B /wFDAUEBQAH/AW8BowG2Af8BjwHdAfkB/wGPAd0B+QH/AW4BoAGxAf8BPgFIAUsB/wFtAZ4BrwH/AY8B
5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHXAb8BtQH/AVgBUgFQAf8BYgFbAVcB/wHPAbcB 3QH5Af8BjwHdAfkB/wFxAaYBuAH/AUIBQAE+Af8B0AG3AawB/wHMAbQBqQH/AcQBrQGjAf8BzwG7AbEB
rAH/AdABtwGsAf8BpAGSAYoB/wE+AjwB/wFZAXgBhAH/AYoB1QHvAf8BjwHdAfkB/wGPAd0B+QH/AY8B /wHqAdoB0AH/Ae0B3QHTAf8B7QHdAdMB/wHrAdUBygH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB
3QH5Af8BiwHVAfAB/wFZAXoBhgH/AT0CPAH/AaMBkQGKAf8BzQG0AakB/wFWAVEBTgH/AU4BSgFIAf8B zQHCAf8B5wHNAcIB/wHnAc0BwgH/AT0BPAE7Af8DUQGhEAADMwFRAZsBWwE3AfcBtgFaARwB/wG2AVoB
qAGdAZYB/wHtAd0B0wH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B0wH/Ae0B3AHSAf8B1wHDAboB/wGlAZUB HAH/AbYBWgEcAf8BtgFaARwB/wG2AVoBGwH/AbgBXQEfAf8B8QHfAdIB/wH6AfMB7wH/AccBfwFOAf8B
jgH/AXUBawFnAf8BVQFQAU4B/wFEAUIBQQH/AkcBRgHxAyUBNhAAAzMBUQGlAVsBLwH3AbUBWgEcAf8B vgFpATAB/wH2AesB5AH/AfsB9QHyAf8BugFfASEB/wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB/wG4AVoB
tgFaARwB/wG2AVoBHAH/AbYBWgEcAf8BtgFaARwB/wG2AVoBHAH/AbwBZQErAf8B/AH4AfYB/wHuAdgB GwH/Ab4BYQEwAf0B3wGSAUcB/gHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/AekBnQE/Af8B
yAH/AekBzQG6Af8B/QH6AfgB/wG/AW0BNQH/AbcBWgEbAf8BtwFaARsB/wG3AVoBGwH/AbgBWgEbAf8B lwFLARYB/wGMAUABEQH/AawBYAEgAf8BkQFDARIB/wGVAUYBFAH/AdYBiwE2Af8B7gGkAUIB/wHuAaQB
ugFcARwB/wHQAYIBMwH8AfABowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMB QgH/Ae4BpAFCAf8B7gGkAUIB/wHtAaQBQgH/AbMBiQFIAfYDMwFR/wB5AANNAZIBOgI5Af8BwgGtAaQB
QgH/AeMBlwE8Af8B6wGfAUAB/wHvAaMBQgH/AekBngE/Af8BpQFXARwB/wGPAUABEQH/AcQBeAEsAf8B /wHdAcUBugH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB
7gGkAUIB/wHuAaQBQgH/Ae4BpAFCAf8B7gGkAUIB/wHLAZMBSAH2AzMBUf8AfQADDAEQAzwBZgNUAbAD zQHCAf8BxgG0AasB/wFEAUIBQQH/AZ4BjQGFAf8B0AG3AawB/wHQAbcBrAH/AWsBYgFeAf8BSQFcAWQB
UwHZA0kB6gI+AT0B+gFyAWkBZQH/AeQBygG/Af8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8BhQF5AXUB /wGLAdUB7wH/AY8B3QH5Af8BjwHdAfkB/wGPAd0B+QH/AY8B3QH5Af8BjwHdAfkB/wGLAdUB8AH/AUoB
/wE+ATwBOwH/Aa8BmwGSAf8B0AG3AawB/wHPAbYBqwH/AYUBeAFyAf8BPgE9ATwB/wFJAVwBYwH/AW8B XgFlAf8BaQFhAV0B/wHPAbYBqwH/AbYBoQGYAf8BwgGrAaEB/wHgAcwBwQH/Ae0B3QHTAf8B7QHdAdMB
ogG1Af8BewG5Ac8B/wFvAaMBtQH/AUoBXQFkAf8BPgI8Af8BhAF3AXEB/wHMAbQBqQH/Ac4BtgGrAf8B /wHtAd0B0wH/Ae0B3QHTAf8B6gHVAcoB/wHnAc4BwwH/AecBzQHCAf8B5wHNAcIB/wHbAcMBuQH/AcEB
rQGaAZEB/wFnAWABXQH/AaABlgGRAf8B7QHdAdMB/wHtAd0B0wH/Ae0B3QHTAf8B6gHaAdAB/wFzAW0B rAGkAf8BOgI5Af8DTgGVEAADMwFRAZsBWwE3AfcBtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8BtgFaARwB
agH/ATcCNgH7A0wB6wNVAdoDVQG0Az0BaQMOARIUAAMzAVEBpQFaAS8B9wG1AVoBHAH/AbUBWgEcAf8B /wG2AVoBHAH/AbYBWgEbAf8B1gGgAXwF/wHXAaMBgAH/Ac0BjAFfA/8B/gH/Ad0BsAGTAf8BtwFaARsB
tgFaARwB/wG2AVoBHAH/AbYBWgEcAf8BtgFaARwB/wG2AVoBHAH/AegByQG1Af8B/gL9Af8B/gH9AfwB /wG4AVoBGwH/AbgBWgEbAf8BuAFaARsB/wG4AVoBGwH/AcIBegErAfwB7gGiAUEB/wHvAaMBQgH/Ae8B
/wHuAdcByAH/AbgBXQEfAf8BtwFaARsB/wG3AVoBGwH/AbcBWgEbAf8BtwFaARsB/wG2AWYBIwH+AeIB owFCAf8B7wGjAUIB/wHvAaMBQgH/AdEBhQEzAf8BmwFQARkB/wG5AW0BKAH/AesBoAFBAf8BuAFsASYB
nwFAAf0B8AGjAUIB/wHwAaMBQgH/Ae8BowFCAf8BugFuASkB/wGmAVsBHwH/AacBWwEfAf8BpwFbAR8B /wGOAT8BEAH/AagBWwEeAf8B7AGhAUEB/wHuAaQBQgH/Ae4BpAFCAf8B7gGkAUIB/wHuAaQBQgH/AbMB
/wGnAVsBHwH/AaUBWAEdAf8BpwFZAR0B/wGgAVIBGQH/AY4BPwEQAf8BkAFBAREB/wGoAVsBHQH/Ac8B iQFIAfYDMwFR/wB5AAMjATMDUAHuAUUBQwFBAf8BVgFRAU8B/wF4AW4BagH/AakBmAGRAf8B2AHAAbYB
hAEyAf8B7gGkAUIB/wHuAaQBQgH/AcsBkwFIAfYDMwFR/wCJAAMPARQDJQE3Az0BaQNMAekBrQGcAZQB /wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AdcBvwG1Af8BWAFSAVAB/wFiAVsBVwH/Ac8B
/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHTAbwBsgH/AUgBRQFEAf8BaAFgAVwB/wHOAbUBqgH/AdAB twGsAf8B0AG3AawB/wGkAZIBigH/AT4CPAH/AVkBeAGEAf8BigHVAe8B/wGPAd0B+QH/AY8B3QH5Af8B
twGsAf8BzwG2AasB/wGlAZMBiwH/AWsBYgFeAf8BRAFCAUAB/wI5ATgB/wFEAUEBQAH/AWsBYgFeAf8B jwHdAfkB/wGLAdUB8AH/AVkBegGGAf8BPQI8Af8BowGRAYoB/wHNAbQBqQH/AVYBUQFOAf8BTgFKAUgB
pAGSAYoB/wHNAbQBqgH/AY0BfwF4Af8BgAFzAW4B/wHOAbcBrQH/AegB1gHMAf8B7QHdAdMB/wHtAd0B /wGoAZ0BlgH/Ae0B3QHTAf8B7QHdAdMB/wHtAd0B0wH/Ae0B3QHTAf8B7QHcAdIB/wHXAcMBugH/AaUB
0wH/Ae0B3QHTAf8B7QHdAdMB/wG0AakBogH/A0wB6wM/AW0DJwE6AxEBFiAAAzMBUQGlAVoBLwH3AbUB lQGOAf8BdQFrAWcB/wFVAVABTgH/AUQBQgFBAf8CUQFQAfEDJQE2EAADMwFRAZsBWwE3AfcBtQFaARwB
WQEcAf8BtQFZARwB/wG1AVoBHAH/AbUBWgEcAf8BtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8B0AGUAWwB /wG2AVoBHAH/AbYBWgEcAf8BtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8BvAFlASsB/wH8AfgB9gH/Ae4B
/wH+Af0B/AL/Av4B/wHbAa0BjgH/AbcBWwEcAf8BtwFaARsB/wG3AVoBGwH/AbcBWgEbAf8BtwFaARsB 2AHIAf8B6QHNAboB/wH9AfoB+AH/Ab8BbQE1Af8BtwFaARsB/wG3AVoBGwH/AbcBWgEbAf8BuAFaARsB
/wHAAX0BMwH6AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8BpgFbAR8B/wGLAUABEQH/AYsB /wG6AVwBHAH/AcoBfgEwAfwB8AGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8B
QAERAf8BiwFAAREB/wGMAUABEQH/AY0BQAERAf8BjwE/ARAB/wGNAT8BEAH/AY4BPwEQAf8BjgE/ARAB owFCAf8B4wGXATwB/wHrAZ8BQAH/Ae8BowFCAf8B6QGeAT8B/wGlAVcBHAH/AY8BQAERAf8BxAF4ASwB
/wGPAT8BEAH/AcQBeAEsAf8B7gGkAUIB/wHuAaQBQgH/AcsBkwFIAfYDMwFR/wCRAAMIAQoDVAGvAUkB /wHuAaQBQgH/Ae4BpAFCAf8B7gGkAUIB/wHuAaQBQgH/AbQBiQFIAfYDMwFR/wB9AAMMARADPAFmA1YB
RgFEAf8B5QHLAcAB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wG7AacBnwH/ATkCOAH/AXQBagFlAf8B sANbAdkDUwHqAkQBQwH6AXIBaQFlAf8B5AHKAb8B/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wGFAXkB
zgG1AaoB/wHQAbcBrAH/AdABtwGsAf8B0AG3AawB/wHQAbcBrAH/AdABtwGsAf8B0AG3AawB/wHQAbcB dQH/AT4BPAE7Af8BrwGbAZIB/wHQAbcBrAH/Ac8BtgGrAf8BhQF4AXIB/wE+AT0BPAH/AUkBXAFjAf8B
rAH/AdABtwGsAf8BzwG2AasB/wGFAXgBcwH/AzUB/wGSAYYBgQH/AewB2wHRAf8B7QHdAdMB/wHtAd0B bwGiAbUB/wF7AbkBzwH/AW8BowG1Af8BSgFdAWQB/wE+AjwB/wGEAXcBcQH/AcwBtAGpAf8BzgG2AasB
0wH/Ae0B3QHTAf8B6wHbAdEB/wFLAUkBSAH/A1UBswMJAQwoAAMzAVEBpQFaAS8B9wG1AVkBHAH/AbUB /wGtAZoBkQH/AWcBYAFdAf8BoAGWAZEB/wHtAd0B0wH/Ae0B3QHTAf8B7QHdAdMB/wHqAdoB0AH/AXMB
WQEcAf8BtQFZARwB/wG1AVoBHAH/AbUBWgEcAf8BtgFaARwB/wG2AVoBHAH/AcIBdQFCAf8B9QHoAeAB bQFqAf8BNwI2AfsDVgHrA10B2gNVAbQDPQFpAw4BEhQAAzMBUQGbAVoBNwH3AbUBWgEcAf8BtQFaARwB
/wH6AfQB7wH/AcoBhwFaAf8BtgFaARwB/wG2AVoBGwH/AbcBWgEbAf8BtwFaARsB/wGxAV8BIAH+AdkB /wG2AVoBHAH/AbYBWgEcAf8BtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8B6AHJAbUB/wH+Av0B/wH+Af0B
mgFDAfsB8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B7wGjAUIB /AH/Ae4B1wHIAf8BuAFdAR8B/wG3AVoBGwH/AbcBWgEbAf8BtwFaARsB/wG3AVoBGwH/AbABaQEmAf4B
/wHvAaMBQgH/Ae8BowFCAf8BjQFAAREB/wGmAVgBHAH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8B 2QGfAUAB/QHwAaMBQgH/AfABowFCAf8B7wGjAUIB/wG6AW4BKQH/AaYBWwEfAf8BpwFbAR8B/wGnAVsB
owFCAf8B7wGkAUIB/wHuAaQBQgH/Ae4BpAFCAf8BywGTAUgB9gMzAVH/AJEAAwMBBANOAZQDNgH/AdYB HwH/AacBWwEfAf8BpQFYAR0B/wGnAVkBHQH/AaABUgEZAf8BjgE/ARAB/wGQAUEBEQH/AagBWwEdAf8B
vgG0Af8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5AHKAb8B/wGbAYwBhQH/AToCOQH/AWgBYAFcAf8B zwGEATIB/wHuAaQBQgH/Ae4BpAFCAf8BtAGJAUgB9gMzAVH/AIkAAw8BFAMlATcDPQFpA1MB6QGtAZwB
rwGbAZIB/wHPAbYBrAH/AdABtwGsAf8B0AG3AawB/wHQAbcBrAH/AdABtwGsAf8B0AG3AawB/wHQAbcB lAH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AdMBvAGyAf8BSAFFAUQB/wFoAWABXAH/Ac4BtQGqAf8B
rAH/AdABtwGsAf8B0AG5Aa4B/wGZAYwBhgH/AbIBoAGYAf8B6AHQAcUB/wHsAdsB0QH/AfEB5QHhAf8B 0AG3AawB/wHPAbYBqwH/AaUBkwGLAf8BawFiAV4B/wFEAUIBQAH/AjkBOAH/AUQBQQFAAf8BawFiAV4B
7QHdAdQB/wHdAc4BxQH/AzcB/wNOAZcDAwEEKAADMwFRAaUBWgEvAfcBtQFZARwB/wG1AVkBHAH/AbUB /wGkAZIBigH/Ac0BtAGqAf8BjQF/AXgB/wGAAXMBbgH/Ac4BtwGtAf8B6AHWAcwB/wHtAd0B0wH/Ae0B
WQEcAf8BtQFZARwB/wG1AVoBHAH/AbUBWgEcAf8BtQFaARwB/wG3AV0BIQH/AcEBcwE+Af8BwwF2AUIB 3QHTAf8B7QHdAdMB/wHtAd0B0wH/AbQBqQGiAf8DVgHrAz8BbQMnAToDEQEWIAADMwFRAZsBWgE3AfcB
/wG4AV8BIwH/AbYBWgEcAf8BtgFaARwB/wG2AVoBHAH/AbcBWgEbAf8BvQFqASgB+wHwAaMBQgH/AfAB tQFZARwB/wG1AVkBHAH/AbUBWgEcAf8BtQFaARwB/wG2AVoBHAH/AbYBWgEcAf8BtgFaARwB/wHQAZQB
owFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB bAH/Af4B/QH8Av8C/gH/AdsBrQGOAf8BtwFbARwB/wG3AVoBGwH/AbcBWgEbAf8BtwFaARsB/wG3AVoB
/wHvAaMBQgH/AZsBTwEZAf8BsQFjASIB/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8B GwH/AbEBfQE4AfoB8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wGmAVsBHwH/AYsBQAERAf8B
owFCAf8B7wGjAUIB/wHuAaQBQgH/AcsBkwFIAfYDMwFR/wCRAAMYASADUAHiAX8BdAFvAf8B5gHMAcEB iwFAAREB/wGLAUABEQH/AYwBQAERAf8BjQFAAREB/wGPAT8BEAH/AY0BPwEQAf8BjgE/ARAB/wGOAT8B
/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AeQBygG/Af8BvgGpAaEB/wFKAUcBRQH/AT4B EAH/AY8BPwEQAf8BxAF4ASwB/wHuAaQBQgH/Ae4BpAFCAf8BtAGJAUgB9gMzAVH/AJEAAwgBCgNVAa8B
PAE7Af8BYgFaAVcB/wGmAZQBjAH/AdABtwGsAf8B0AG3AawB/wHFAa4BpAH/AZ4BjQGGAf8BkwGEAX0B SQFGAUQB/wHlAcsBwAH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AbsBpwGfAf8BOQI4Af8BdAFqAWUB
/wHZAcMBuAH/AegB1gHMAf8B7AHcAdEB/wHpAdEBxgH/AecBzQHCAf8B7AHYAdIB/wH3AfQB+QH/AfIB /wHOAbUBqgH/AdABtwGsAf8B0AG3AawB/wHQAbcBrAH/AdABtwGsAf8B0AG3AawB/wHQAbcBrAH/AdAB
6AHkAf8B7AHcAdIB/wGGAX4BegH/A1AB4wMYASEoAAMzAVEBpQFaAS8B9wG0AVkBHAH/AbUBWQEcAf8B twGsAf8B0AG3AawB/wHPAbYBqwH/AYUBeAFzAf8DNQH/AZIBhgGBAf8B7AHbAdEB/wHtAd0B0wH/Ae0B
tQFZARwB/wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWgEcAf8BtgFaARwB/wG2AVoB 3QHTAf8B7QHdAdMB/wHrAdsB0QH/AUsBSQFIAf8DVgGzAwkBDCgAAzMBUQGbAVoBNwH3AbUBWQEcAf8B
HAH/AbYBWgEcAf8BtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8BsAFfASAB/gHPAX4BMQH8AfEBowFCAf8B tQFZARwB/wG1AVkBHAH/AbUBWgEcAf8BtQFaARwB/wG2AVoBHAH/AbYBWgEcAf8BwgF1AUIB/wH1AegB
4AH/AfoB9AHvAf8BygGHAVoB/wG2AVoBHAH/AbYBWgEbAf8BtwFaARsB/wG3AVoBGwH/AasBYgEjAf4B
0AGXAUYB+wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHvAaMB
QgH/Ae8BowFCAf8B7wGjAUIB/wGNAUABEQH/AaYBWAEcAf8B7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B
7wGjAUIB/wHvAaQBQgH/Ae4BpAFCAf8B7gGkAUIB/wG0AYkBSAH2AzMBUf8AkQADAwEEA04BlAM2Af8B
1gG+AbQB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHkAcoBvwH/AZsBjAGFAf8BOgI5Af8BaAFgAVwB
/wGvAZsBkgH/Ac8BtgGsAf8B0AG3AawB/wHQAbcBrAH/AdABtwGsAf8B0AG3AawB/wHQAbcBrAH/AdAB
twGsAf8B0AG3AawB/wHQAbkBrgH/AZkBjAGGAf8BsgGgAZgB/wHoAdABxQH/AewB2wHRAf8B8QHlAeEB
/wHtAd0B1AH/Ad0BzgHFAf8DNwH/A04BlwMDAQQoAAMzAVEBmwFaATcB9wG1AVkBHAH/AbUBWQEcAf8B
tQFZARwB/wG1AVkBHAH/AbUBWgEcAf8BtQFaARwB/wG1AVoBHAH/AbcBXQEhAf8BwQFzAT4B/wHDAXYB
QgH/AbgBXwEjAf8BtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8BtwFaARsB/wGxAWQBKAH7AfABowFCAf8B
8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMB 8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMB
QgH/AfABowFCAf8B6AGbAT4B/wHpAZ0BPwH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B QgH/Ae8BowFCAf8BmwFPARkB/wGxAWMBIgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B
7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8BzAGSAUgB9gMzAVH/AI0AAwMBBANRAaIBUQFMAUoB/wHhAcgB 7wGjAUIB/wHvAaMBQgH/Ae4BpAFCAf8BtAGJAUgB9gMzAVH/AJEAAxgBIANZAeIBfwF0AW8B/wHmAcwB
vgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B wQH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5AHKAb8B/wG+AakBoQH/AUoBRwFFAf8B
1QG+AbQB/wGLAX4BeAH/AVoBVQFSAf8BXwFaAVcB/wHbAcYBuwH/AdEBvAGyAf8BTwFMAUoB/wFGAUMB PgE8ATsB/wFiAVoBVwH/AaYBlAGMAf8B0AG3AawB/wHQAbcBrAH/AcUBrgGkAf8BngGNAYYB/wGTAYQB
QgH/AWIBWwFYAf8B7AHbAdEB/wHtAd0B0wH/Ae0B3QHTAf8B7AHbAdAB/wHpAdEBxgH/AecBzQHCAf8B fQH/AdkBwwG4Af8B6AHWAcwB/wHsAdwB0QH/AekB0QHGAf8B5wHNAcIB/wHsAdgB0gH/AfcB9AH5Af8B
7AHaAdQB/wHsAdsB0QH/Ae0B3QHTAf8B6QHZAdAB/wFUAVIBUAH/A1EBpAMEAQUkAAMzAVEBpQFaATAB 8gHoAeQB/wHsAdwB0gH/AYYBfgF6Af8DWQHjAxgBISgAAzMBUQGbAVoBNwH3AbQBWQEcAf8BtQFZARwB
9wG0AVkBHAH/AbQBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUB /wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWQEcAf8BtQFaARwB/wG2AVoBHAH/AbYB
WQEcAf8BtQFaARwB/wG1AVoBHAH/AbYBWgEcAf8BtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8BtgFnASUB WgEcAf8BtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8BtgFaARwB/wGqAWIBIwH+AckBfgEuAfwB8QGjAUIB
/gHcAZcBQAH9AfEBowFCAf8B8QGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfAB
owFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/Ae8BowFCAf8B7wGjAUIB
/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8BzAGSAUgB9gMzAVH/AI0AAzUB
VgE6AjkB+wGhAZEBiwH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B
wgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B2QHCAbcB/wHWAcIBuQH/Ae0B3QHTAf8B
6wHcAdIB/wHJAb0BtAH/AckBtgGtAf8B2gHCAbgB/wHoAdEBxgH/AewB2wHQAf8B7QHdAdMB/wHtAd0B
0wH/Ae0B2wHRAf8B6QHSAccB/wHnAc0BwgH/AegB0AHFAf8B7AHaAdAB/wHtAd0B0wH/AakBngGYAf8B
OwI6AfsDNgFYJAADMwFRAaUBWgEwAfcBtAFZAR0B/wG0AVkBHQH/AbQBWQEcAf8BtAFZARwB/wG0AVkB
HAH/AbUBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB/wG1AVoBHAH/AbUBWgEcAf8B
tgFaARwB/wG2AVoBHAH/Ab8BcAErAfwB8AGiAUEB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMB
QgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B
8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMB
QgH/AcwBkgFIAfYDMwFR/wCJAAMRARYDVgHOAVoBVQFSAf8B3QHFAboB/wHnAc0BwgH/AecBzQHCAf8B
5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0B
wgH/AecBzQHCAf8B5wHNAcIB/wHqAdQBygH/Ae0B3gHUAf8B7QHdAdMB/wHsAdsB0QH/AegB0AHFAf8B
5wHNAcIB/wHpAdEBxgH/Ae0B3AHSAf8B7QHdAdMB/wHtAd0B0wH/AewB2wHRAf8B6QHRAcYB/wHnAc0B
wgH/AegB0QHGAf8B7QHcAdIB/wHlAdYBzAH/AWABXAFZAf8DVgHQAxIBFyAAAzMBUQGlAVoBMAH3AbQB
WQEdAf8BtAFZAR0B/wG0AVkBHQH/AbQBWQEcAf8BtAFZARwB/wG0AVkBHAH/AbUBWQEcAf8BtQFZARwB
/wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB/wG1AVoBHAH/AbUBWgEcAf8BtgFaARwB/wHSAYcBNwH7AfEB
owFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8AGjAUIB
/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfAB /wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfAB
owFCAf8B8AGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHMAZIBSAH2AzMBUf8AiQADKAE8A0gB owFCAf8B8AGjAUIB/wHoAZsBPgH/AekBnQE/Af8B7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB
7QGuAZwBlQH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AeYB /wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wG1AYgBSAH2AzMBUf8AjQADAwEEA1EBogFRAUwBSgH/AeEB
zAHBAf8B1QG9AbMB/wHkAcoBwAH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHOAcMB yAG+Af8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB
/wHxAeYB5AH/AfAB5AHeAf8B7QHdAdMB/wHsAdsB0AH/AekB0QHGAf8B5wHNAcIB/wHnAc8BxAH/AdsB /wHVAb4BtAH/AYsBfgF4Af8BWgFVAVIB/wFfAVoBVwH/AdsBxgG7Af8B0QG8AbIB/wFPAUwBSgH/AUYB
ywHCAf8B7AHcAdIB/wHtAd0B0wH/AewB2wHQAf8B6QHRAcYB/wHnAc0BwgH/AegB0AHFAf8B7AHaAdAB QwFCAf8BYgFbAVgB/wHsAdsB0QH/Ae0B3QHTAf8B7QHdAdMB/wHsAdsB0AH/AekB0QHGAf8B5wHNAcIB
/wG6Aa4BpgH/A0UB7wMpAT4gAAMzAVEBpAFaATAB9wG0AVkBHQH/AbQBWQEdAf8BtAFZAR0B/wG0AVkB /wHsAdoB1AH/AewB2wHRAf8B7QHdAdMB/wHpAdkB0AH/AVQBUgFQAf8DUQGkAwQBBSQAAzMBUQGbAVoB
HQH/AbQBWQEdAf8BtAFZARwB/wG0AVkBHAH/AbQBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWQEcAf8B NwH3AbQBWQEcAf8BtAFZARwB/wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWQEcAf8B
tQFZARwB/wG1AVkBHAH/AbQBYgEoAfwB6AGZAUUB/gHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMB tQFZARwB/wG1AVoBHAH/AbUBWgEcAf8BtgFaARwB/wG2AVoBHAH/AbYBWgEcAf8BtgFaARwB/wGwAWoB
QgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHwAaMBQgH/AfABowFCAf8B KAH+AdMBlwFAAf0B8QGjAUIB/wHxAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B
8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHvAaMB 8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B7wGjAUIB/wHvAaMB
QgH/Ae8BowFCAf8BzAGSAUgB9gMzAVH/AIkAAyABLgNQAeIBaQFiAV4B/wHhAcgBvQH/AecBzQHCAf8B QgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wG1AYgBSAH2AzMBUf8AjQAD
5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B4QHIAb0B/wF+AXMBbgH/AzYB/wFHAUQBQwH/AasBmgGTAf8B NQFWAToCOQH7AaEBkQGLAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB
4wHKAb8B/wHnAc0BwgH/AecBzQHCAf8B7gHeAdkB/wH3AfYB/AH/AfcB9gH7Af8B8AHjAd0B/wHtAd0B zQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHZAcIBtwH/AdYBwgG5Af8B7QHdAdMB
0wH/AeoB2QHPAf8BsQGhAZoB/wFLAUgBRgH/ATcCNgH/AX4BdwFzAf8B5gHXAc0B/wHtAd0B0wH/Ae0B /wHrAdwB0gH/AckBvQG0Af8ByQG2Aa0B/wHaAcIBuAH/AegB0QHGAf8B7AHbAdAB/wHtAd0B0wH/Ae0B
3AHSAf8B6QHRAcYB/wHnAc0BwgH/AeMBywHBAf8BbQFnAWMB/wNPAeQDIQEwIAADMwFRAZ0BXQEuAfYB 3QHTAf8B7QHbAdEB/wHpAdIBxwH/AecBzQHCAf8B6AHQAcUB/wHsAdoB0AH/Ae0B3QHTAf8BqQGeAZgB
swFZAR0B/wGzAVkBHQH/AbQBWQEdAf8BtAFZAR0B/wG0AVkBHQH/AbQBWQEdAf8BtAFZAR0B/wG0AVkB /wE7AjoB+wM2AVgkAAMzAVEBmwFaATcB9wG0AVkBHQH/AbQBWQEdAf8BtAFZARwB/wG0AVkBHAH/AbQB
HAH/AbQBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB/wHHAXcBLwH7AfIBowFCAf8B WQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWgEcAf8BtQFaARwB
8gGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMB /wG2AVoBHAH/AbYBWgEcAf8BuQFwASsB/AHwAaIBQQH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEB
QgH/AfEBowFCAf8B8QGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B owFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB
8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHvAaMBQgH/AcwBkgFIAfYDMwFR/wCJAAMCAQMD /wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHvAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/Ae8B
OwFkA0gB7wF7AXEBbQH/AeEByAG9Af8B5wHNAcIB/wHeAcUBuwH/AaIBkgGLAf8BUQFMAUsB/wNSAeAD owFCAf8BtQGIAUgB9gMzAVH/AIkAAxEBFgNdAc4BWgFVAVIB/wHdAcUBugH/AecBzQHCAf8B5wHNAcIB
TQGTA1QBsANMAekBbwFmAWIB/wHnAc0BwgH/AeoB1gHPAf8B8wHsAe4B/wH4AfcB/gH/AfcB9gH9Af8B /wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecB
8gHpAegB/wHuAd4B1gH/AXwBdQFxAf8DSgHqA1QBsANNAZIDUAHfAVABTQFMAf8BowGZAZMB/wHhAdIB zQHCAf8B5wHNAcIB/wHnAc0BwgH/AeoB1AHKAf8B7QHeAdQB/wHtAd0B0wH/AewB2wHRAf8B6AHQAcUB
yQH/AewB2wHQAf8B4wHMAcEB/wF9AXIBbQH/A0cB8QM9AWgDAwEEIAADHQEoAXsBXgFLAd0BswFZAR0B /wHnAc0BwgH/AekB0QHGAf8B7QHcAdIB/wHtAd0B0wH/Ae0B3QHTAf8B7AHbAdEB/wHpAdEBxgH/AecB
/wGzAVkBHQH/AbMBWQEdAf8BtAFZAR0B/wG0AVkBHQH/AbQBWQEdAf8BtAFZAR0B/wG0AVkBHQH/AbQB zQHCAf8B6AHRAcYB/wHtAdwB0gH/AeUB1gHMAf8BYAFcAVkB/wNbAdADEgEXIAADMwFRAZsBWgE3AfcB
WQEcAf8BtAFZARwB/wG0AVkBHAH/AbUBWQEcAf8BsgFiASIB/gHcAZUBQAH9AfIBowFCAf8B8gGjAUIB tAFZAR0B/wG0AVkBHQH/AbQBWQEdAf8BtAFZARwB/wG0AVkBHAH/AbQBWQEcAf8BtQFZARwB/wG1AVkB
HAH/AbUBWQEcAf8BtQFZARwB/wG1AVkBHAH/AbUBWgEcAf8BtQFaARwB/wG2AVoBHAH/AckBhAE3AfsB
8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHwAaMB
QgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B
8AGjAUIB/wHwAaMBQgH/Ae8BowFCAf8B7wGjAUIB/wHvAaMBQgH/AbUBiAFIAfYDMwFR/wCJAAMoATwD
UgHtAa4BnAGVAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B
5gHMAcEB/wHVAb0BswH/AeQBygHAAf8B5wHNAcIB/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHnAc4B
wwH/AfEB5gHkAf8B8AHkAd4B/wHtAd0B0wH/AewB2wHQAf8B6QHRAcYB/wHnAc0BwgH/AecBzwHEAf8B
2wHLAcIB/wHsAdwB0gH/Ae0B3QHTAf8B7AHbAdAB/wHpAdEBxgH/AecBzQHCAf8B6AHQAcUB/wHsAdoB
0AH/AboBrgGmAf8DTQHvAykBPiAAAzMBUQGaAVoBNwH3AbQBWQEdAf8BtAFZAR0B/wG0AVkBHQH/AbQB
WQEdAf8BtAFZAR0B/wG0AVkBHAH/AbQBWQEcAf8BtAFZARwB/wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB
/wG1AVkBHAH/AbUBWQEcAf8BrgFiASsB/AHiAZMBSAH+AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEB
owFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfABowFCAf8B8AGjAUIB
/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/Ae8B
owFCAf8B7wGjAUIB/wG1AYgBSAH2AzMBUf8AiQADIAEuA1kB4gFpAWIBXgH/AeEByAG9Af8B5wHNAcIB
/wHnAc0BwgH/AecBzQHCAf8B5wHNAcIB/wHhAcgBvQH/AX4BcwFuAf8DNgH/AUcBRAFDAf8BqwGaAZMB
/wHjAcoBvwH/AecBzQHCAf8B5wHNAcIB/wHuAd4B2QH/AfcB9gH8Af8B9wH2AfsB/wHwAeMB3QH/Ae0B
3QHTAf8B6gHZAc8B/wGxAaEBmgH/AUsBSAFGAf8BNwI2Af8BfgF3AXMB/wHmAdcBzQH/Ae0B3QHTAf8B
7QHcAdIB/wHpAdEBxgH/AecBzQHCAf8B4wHLAcEB/wFtAWcBYwH/A1cB5AMhATAgAAMzAVEBkQFgATQB
9gGzAVkBHQH/AbMBWQEdAf8BtAFZAR0B/wG0AVkBHQH/AbQBWQEdAf8BtAFZAR0B/wG0AVkBHQH/AbQB
WQEcAf8BtAFZARwB/wG1AVkBHAH/AbUBWQEcAf8BtQFZARwB/wG1AVkBHAH/Ab4BcQEvAfsB8gGjAUIB
/wHyAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEB /wHyAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEB
owFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB owFCAf8B8QGjAUIB/wHxAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB
/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AY8BdQFXAd0DHQEo/wCNAAQCAzIBTwNIAe8B /wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/Ae8BowFCAf8BtQGIAUgB9gMzAVH/AIkAAwIB
aQFiAV4B/wGxAZ4BlgH/AVsBVQFTAf8BQQJAAfoDTwGeAxgBIAMDAQQDCQELAz8BbAM2AfsB1AG9AbMB AwM7AWQDTwHvAXsBcQFtAf8B4QHIAb0B/wHnAc0BwgH/Ad4BxQG7Af8BogGSAYsB/wFRAUwBSwH/A1oB
/wHnAc0BwgH/AegB0AHHAf8B8wHrAe0B/wHvAeEB3wH/AegBzwHFAf8B4AHMAcIB/wM1AfwDPwFuAwkB 4ANNAZMDVgGwA1MB6QFvAWYBYgH/AecBzQHCAf8B6gHWAc8B/wHzAewB7gH/AfgB9wH+Af8B9wH2Af0B
CwMDAQQDFgEeA1ABmgNBAfkBWQFWAVQB/wGwAaUBngH/AWwBZwFjAf8DRgHwAzMBUgMCAQMkAAQBAxoB /wHyAekB6AH/Ae4B3gHWAf8BfAF1AXEB/wNUAeoDVgGwA00BkgNYAd8BUAFNAUwB/wGjAZkBkwH/AeEB
0gHJAf8B7AHbAdAB/wHjAcwBwQH/AX0BcgFtAf8DUQHxAz0BaAMDAQQgAAMdASgBawFeAVcB3QGzAVkB
HQH/AbMBWQEdAf8BswFZAR0B/wG0AVkBHQH/AbQBWQEdAf8BtAFZAR0B/wG0AVkBHQH/AbQBWQEdAf8B
tAFZARwB/wG0AVkBHAH/AbQBWQEcAf8BtQFZARwB/wGsAWUBJQH+AdMBlQFAAf0B8gGjAUIB/wHyAaMB
QgH/AfIBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B
8QGjAUIB/wHxAaMBQgH/AfEBowFCAf8B8QGjAUIB/wHwAaMBQgH/AfABowFCAf8B8AGjAUIB/wHwAaMB
QgH/AfABowFCAf8B8AGjAUIB/wHwAaMBQgH/AfABowFCAf8BdQFpAVsB3QMdASj/AI0ABAIDMgRPAe8B
aQFiAV4B/wGxAZ4BlgH/AVsBVQFTAf8BRwJGAfoDUQGeAxgBIAMDAQQDCQELAz8BbAM2AfsB1AG9AbMB
/wHnAc0BwgH/AegB0AHHAf8B8wHrAe0B/wHvAeEB3wH/AegBzwHFAf8B4AHMAcIB/wMyAfwDPwFuAwkB
CwMDAQQDFgEeA1ABmgNBAfkBWQFWAVQB/wGwAaUBngH/AWwBZwFjAf8DTwHwAzMBUgMCAQMkAAQBAxoB
JAM9AWgCQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXEC JAM9AWgCQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXECQQFAAXEC
QQFAAXECQQFAAXECQQFAAXACQQFAAXEDQQFxA0EBcQNBAXEDQQFxA0EBcQNBAXEDQQFxA0EBcQNBAXED QQFAAXECQQFAAXECQQFAAXACQQFAAXEDQQFxA0EBcQNBAXEDQQFxA0EBcQNBAXEDQQFxA0EBcQNBAXED
QQFxA0EBcQNBAXEDQQFxA0EBcQNBAXEDQQFxA0EBcQNBAXEDQQFxA0EBcQM9AWgDGgEkBAH/AJEABAID QQFxA0EBcQNBAXEDQQFxA0EBcQNBAXEDQQFxA0EBcQNBAXEDQQFxA0EBcQM9AWgDGgEkBAH/AJEABAID
OwFkA1AB4gNIAe0DVAHNAzQBVAMDAQQMAAMnAToDTAHrAaUBlAGOAf8B5wHNAcIB/wHnAc0BwgH/AeoB OwFkA1kB4gNSAe0DWwHNAzQBVAMDAQQMAAMnAToDVgHrAaUBlAGOAf8B5wHNAcIB/wHnAc0BwgH/AeoB
1gHOAf8B6AHOAcQB/wHnAc0BwgH/AbEBnwGXAf8DSgHsAykBPQwAAwIBAwMzAVEDVgHLA0gB7QNQAeMD 1gHOAf8B6AHOAcQB/wHnAc0BwgH/AbEBnwGXAf8DVAHsAykBPQwAAwIBAwMzAVEDWwHLA1IB7QNZAeMD
PQFnAwIBA/8A/wBaAAMCAQMDIAEtAygBOwMQARUUAAMSARcDVQHaAXQBawFnAf8B5wHNAcIB/wHnAc0B PQFnAwIBA/8A/wBaAAMCAQMDIAEtAygBOwMQARUUAAMSARcDXQHaAXQBawFnAf8B5wHNAcIB/wHnAc0B
wgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AYABdQFwAf8DVQHbAxMBGRQAAw8BFAMoATsDIAEuAwIB wgH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AYABdQFwAf8DXAHbAxMBGRQAAw8BFAMoATsDIAEuAwIB
A/8A/wCGAANVAbMBVQFQAU4B/wHcAcMBuQH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AeEByAG9Af8B A/8A/wCGAANWAbMBVQFQAU4B/wHcAcMBuQH/AecBzQHCAf8B5wHNAcIB/wHnAc0BwgH/AeEByAG9Af8B
WgFUAVIB/wNWAbr/AP8ArgADPQFpAUQBQgFBAf8BwAGrAaMB/wHlAcwBwQH/AeUBzAHBAf8B5QHMAcEB WgFUAVIB/wNYAbr/AP8ArgADPQFpAUQBQgFBAf8BwAGrAaMB/wHlAcwBwQH/AeUBzAHBAf8B5QHMAcEB
/wHFAbABpwH/AUgBRQFDAf8DQAFx/wD/AK4AAw0BEQJEAUMB8AE6AjkB/wE9AjsB/wE9AjsB/wE9AjsB /wHFAbABpwH/AUgBRQFDAf8DQAFx/wD/AK4AAw0BEQJOAUwB8AE6AjkB/wE9AjsB/wE9AjsB/wE9AjsB
/wE6AjkB/wNCAfMDEQEW/wD/ALIAAyQBNANNAZIDUQGiA1EBogNRAaIDTQGTAyUBN/8A/wD/AP8A/wA9 /wE6AjkB/wNMAfMDEQEW/wD/ALIAAyQBNANNAZIDUQGiA1EBogNRAaIDTQGTAyUBN/8A/wD/AP8A/wA9
AAFCAU0BPgcAAT4DAAEoAwABtAMAAS0DAAEBAQABAQUAATgBBBYAA/8BAAf/AccD/wHADAAC/wHgAT8D AAFCAU0BPgcAAT4DAAEoAwABtAMAAS0DAAEBAQABAQUAATgBBBYAA/8BAAf/AccD/wHADAAC/wHgAT8D
/wGHA/8BwAwAAv8BwAEfA/8BgwP/AcAMAAL/AcABHwP/AYAD/wHADAAC/wHAAQ8D/wGAA/8BwAwAAf8B /wGHA/8BwAwAAv8BwAEfA/8BgwP/AcAMAAL/AcABHwP/AYAD/wHADAAC/wHAAQ8D/wGAA/8BwAwAAf8B
DwGAAQ8BhwL/AYABPwL/AcAMAAH+AQMBgAEOAQMC/wGAAT8C/wHADAAB/AMAAQEC/wGAAR8C/wHADAAB DwGAAQ8BhwL/AYABPwL/AcAMAAH+AQMBgAEOAQMC/wGAAT8C/wHADAAB/AMAAQEC/wGAAR8C/wHADAAB

View File

@ -6,23 +6,29 @@ namespace UI_WinForms.Components;
public sealed partial class Setting : UserControl public sealed partial class Setting : UserControl
{ {
private SettingUIData data; private readonly SettingUIData data;
private bool needRestart = false;
public Setting() public Setting()
{ {
this.InitializeComponent(); this.InitializeComponent();
} }
public bool NeedRestart => this.needRestart;
private Setting(SettingUIData settingMetaData) private Setting(SettingUIData settingMetaData)
{ {
this.InitializeComponent(); this.InitializeComponent();
if(this.DesignMode)
return;
this.Dock = DockStyle.Top; this.Dock = DockStyle.Top;
this.data = settingMetaData; this.data = settingMetaData;
this.labelIcon.Image = settingMetaData.Icon; this.labelIcon.Image = settingMetaData.Icon;
this.labelSettingName.Text = settingMetaData.SettingName(); this.labelSettingName.Text = settingMetaData.SettingName();
this.labelExplanation.Text = settingMetaData.SettingExplanation(); this.labelExplanation.Text = settingMetaData.SettingExplanation();
var dataControl = settingMetaData.SetupDataControl(); var dataControl = settingMetaData.SetupDataControl(this.ChangeTrigger);
this.tableLayout.Controls.Add(dataControl, 2, 0); this.tableLayout.Controls.Add(dataControl, 2, 0);
// Ensure, that this data control is vertical centered by calculating the needed margin, considering the outer size of the table layout: // Ensure, that this data control is vertical centered by calculating the needed margin, considering the outer size of the table layout:
@ -41,14 +47,21 @@ public sealed partial class Setting : UserControl
dataControl.Margin = new Padding(0, (int) margin, 0, (int)margin); dataControl.Margin = new Padding(0, (int) margin, 0, (int)margin);
}; };
} }
private void ChangeTrigger()
{
if(this.data.ChangeNeedsRestart)
this.needRestart = true;
}
private void UpdateExplanation() => this.labelExplanation.Text = this.data.SettingExplanation(); private void UpdateExplanation() => this.labelExplanation.Text = this.data.SettingExplanation();
private readonly record struct SettingUIData( private readonly record struct SettingUIData(
Bitmap Icon, Bitmap Icon,
Func<string> SettingName, Func<string> SettingName,
Func<string> SettingExplanation, Func<string> SettingExplanation,
Func<Control> SetupDataControl Func<Action, Control> SetupDataControl,
bool ChangeNeedsRestart
); );
private static async Task<Setting> ShowDeepLModeSettingAsync() private static async Task<Setting> ShowDeepLModeSettingAsync()
@ -57,8 +70,9 @@ public sealed partial class Setting : UserControl
var settingData = new SettingUIData( var settingData = new SettingUIData(
Icon: Icons.deepl_logo_icon_170284, Icon: Icons.deepl_logo_icon_170284,
SettingName: () => "DeepL Service", SettingName: () => "DeepL Service",
ChangeNeedsRestart: true,
SettingExplanation: () => "DeepL is a translation service that offers a wide range of translation services. This setting allows you to choose between the free and pro version of DeepL.", SettingExplanation: () => "DeepL is a translation service that offers a wide range of translation services. This setting allows you to choose between the free and pro version of DeepL.",
SetupDataControl: () => SetupDataControl: (changeTrigger) =>
{ {
var dropdown = new ComboBox(); var dropdown = new ComboBox();
dropdown.Items.Add("Disabled"); dropdown.Items.Add("Disabled");
@ -82,6 +96,9 @@ public sealed partial class Setting : UserControl
_ => SettingDeepLMode.DISABLED, _ => SettingDeepLMode.DISABLED,
}); });
// Fires the change trigger:
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout: // Apply the desired layout:
dropdown.Dock = DockStyle.Fill; dropdown.Dock = DockStyle.Fill;
@ -100,12 +117,14 @@ public sealed partial class Setting : UserControl
var settingData = new SettingUIData( var settingData = new SettingUIData(
Icon: Icons.icons8_key_512, Icon: Icons.icons8_key_512,
SettingName: () => "DeepL API Key", SettingName: () => "DeepL API Key",
ChangeNeedsRestart: true,
SettingExplanation: () => "The API key is required to use the DeepL translation service. You can find your API key on the DeepL website.", SettingExplanation: () => "The API key is required to use the DeepL translation service. You can find your API key on the DeepL website.",
SetupDataControl: () => SetupDataControl: (changeTrigger) =>
{ {
var textbox = new TextBox(); var textbox = new TextBox();
textbox.Text = currentSetting; textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetDeepLAPIKey(textbox.Text); textbox.TextChanged += async (sender, args) => await AppSettings.SetDeepLAPIKey(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill; textbox.Dock = DockStyle.Fill;
return textbox; return textbox;
} }
@ -128,8 +147,9 @@ public sealed partial class Setting : UserControl
var settingData = new SettingUIData( var settingData = new SettingUIData(
Icon: Icons.icons8_increase_512, Icon: Icons.icons8_increase_512,
SettingName: () => "DeepL Usage", SettingName: () => "DeepL Usage",
ChangeNeedsRestart: false,
SettingExplanation: GetUsageText, SettingExplanation: GetUsageText,
SetupDataControl: () => SetupDataControl: (changeTrigger) =>
{ {
var progressbar = new ProgressBar(); var progressbar = new ProgressBar();
progressbar.Maximum = 100; progressbar.Maximum = 100;
@ -199,8 +219,9 @@ public sealed partial class Setting : UserControl
var settingData = new SettingUIData( var settingData = new SettingUIData(
Icon: Icons.icons8_play_512__2_, Icon: Icons.icons8_play_512__2_,
SettingName: () => "DeepL Operation", SettingName: () => "DeepL Operation",
ChangeNeedsRestart: true,
SettingExplanation: () => "Should the missing translations be automatically completed by DeepL? This can lead to higher costs. By default, DeepL is only applied manually.", SettingExplanation: () => "Should the missing translations be automatically completed by DeepL? This can lead to higher costs. By default, DeepL is only applied manually.",
SetupDataControl: () => SetupDataControl: (changeTrigger) =>
{ {
// We set up a combo box with the available actions: // We set up a combo box with the available actions:
var dropdown = new ComboBox(); var dropdown = new ComboBox();
@ -215,6 +236,7 @@ public sealed partial class Setting : UserControl
}; };
// Setup the change event handler: // Setup the change event handler:
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
dropdown.SelectedValueChanged += async (sender, args) => await AppSettings.SetDeepLAction(dropdown.SelectedIndex switch dropdown.SelectedValueChanged += async (sender, args) => await AppSettings.SetDeepLAction(dropdown.SelectedIndex switch
{ {
0 => SettingDeepLAction.MANUAL, 0 => SettingDeepLAction.MANUAL,
@ -246,15 +268,15 @@ public sealed partial class Setting : UserControl
// We load the corresponding culture for that index. As dropdown items, we show // We load the corresponding culture for that index. As dropdown items, we show
// all other available cultures: // all other available cultures:
var allCultures = await AppSettings.GetCultureInfos(); var allCultures = await AppSettings.GetCultureInfos();
var sourceCulture = allCultures.FirstOrDefault(n => n.Index == currentSourceCultureIndex);
// Attention: We have to store the culture's index, because the index is not // Attention: We have to store the culture's index, because the index is not
// continuous and can change when the user adds or removes a culture! // continuous and can change when the user adds or removes a culture!
var settingData = new SettingUIData( var settingData = new SettingUIData(
Icon: Icons.icons8_chat_bubble_512, Icon: Icons.icons8_chat_bubble_512,
SettingName: () => "DeepL Source Culture", SettingName: () => "DeepL Source Culture",
ChangeNeedsRestart: true,
SettingExplanation: () => "The source culture is used to translate the missing translations.", SettingExplanation: () => "The source culture is used to translate the missing translations.",
SetupDataControl: () => SetupDataControl: (changeTrigger) =>
{ {
var dropdown = new ComboBox(); var dropdown = new ComboBox();
var currentCultureDropdownIndex = 0; var currentCultureDropdownIndex = 0;
@ -270,6 +292,7 @@ public sealed partial class Setting : UserControl
dropdown.SelectedIndex = currentCultureDropdownIndex; dropdown.SelectedIndex = currentCultureDropdownIndex;
// Setup the change event handler: // Setup the change event handler:
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
dropdown.SelectedValueChanged += async (sender, args) => dropdown.SelectedValueChanged += async (sender, args) =>
{ {
if(dropdown.SelectedItem is ComboBoxItem selectedItem) if(dropdown.SelectedItem is ComboBoxItem selectedItem)
@ -322,14 +345,16 @@ public sealed partial class Setting : UserControl
{ {
Icon = Icons.icons8_chat_bubble_512, Icon = Icons.icons8_chat_bubble_512,
SettingName = () => $"{localCultureIndex}. Culture", SettingName = () => $"{localCultureIndex}. Culture",
ChangeNeedsRestart = true,
SettingExplanation = () => "The culture according to RFC 4646: First comes the ISO 639-1 language code in lower case, followed by a hyphen, followed by the ISO 3166-1 alpha-2 country code in upper case. Example: en-US for English in the USA, de-DE for German in Germany.", SettingExplanation = () => "The culture according to RFC 4646: First comes the ISO 639-1 language code in lower case, followed by a hyphen, followed by the ISO 3166-1 alpha-2 country code in upper case. Example: en-US for English in the USA, de-DE for German in Germany.",
SetupDataControl = () => SetupDataControl = (changeTrigger) =>
{ {
var textbox = new TextBox(); var textbox = new TextBox();
textbox.Text = currentCultureCode; textbox.Text = currentCultureCode;
textbox.TextChanged += async (sender, args) => textbox.TextChanged += async (sender, args) =>
{ {
await AppSettings.SetCultureCode(localCultureIndex, textbox.Text); await AppSettings.SetCultureCode(localCultureIndex, textbox.Text);
changeTrigger();
}; };
textbox.Dock = DockStyle.Fill; textbox.Dock = DockStyle.Fill;
return textbox; return textbox;

View File

@ -17,6 +17,12 @@ public partial class Settings : UserControl
this.panelSettings.Controls.Add(await setting); this.panelSettings.Controls.Add(await setting);
} }
public bool NeedRestart()
{
// Iterate through all settings and check if any of them need a restart:
return this.panelSettings.Controls.Cast<Setting>().Any(setting => setting.NeedRestart);
}
private async void buttonAddCulture_Click(object sender, EventArgs e) private async void buttonAddCulture_Click(object sender, EventArgs e)
{ {
// Get the current indices of cultures: // Get the current indices of cultures:

View File

@ -34,6 +34,7 @@
this.buttonAdd = new System.Windows.Forms.Button(); this.buttonAdd = new System.Windows.Forms.Button();
this.buttonRemove = new System.Windows.Forms.Button(); this.buttonRemove = new System.Windows.Forms.Button();
this.buttonRename = new System.Windows.Forms.Button(); this.buttonRename = new System.Windows.Forms.Button();
this.buttonChangeMultiLine = new System.Windows.Forms.Button();
this.textBoxFilter = new System.Windows.Forms.TextBox(); this.textBoxFilter = new System.Windows.Forms.TextBox();
this.labelFilter = new System.Windows.Forms.Label(); this.labelFilter = new System.Windows.Forms.Label();
this.labelSectionPath = new System.Windows.Forms.Label(); this.labelSectionPath = new System.Windows.Forms.Label();
@ -62,7 +63,7 @@
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F));
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F));
this.tableLayout.Size = new System.Drawing.Size(706, 201); this.tableLayout.Size = new System.Drawing.Size(706, 302);
this.tableLayout.TabIndex = 0; this.tableLayout.TabIndex = 0;
// //
// flowLayoutToolbar // flowLayoutToolbar
@ -70,13 +71,14 @@
this.flowLayoutToolbar.Controls.Add(this.buttonAdd); this.flowLayoutToolbar.Controls.Add(this.buttonAdd);
this.flowLayoutToolbar.Controls.Add(this.buttonRemove); this.flowLayoutToolbar.Controls.Add(this.buttonRemove);
this.flowLayoutToolbar.Controls.Add(this.buttonRename); this.flowLayoutToolbar.Controls.Add(this.buttonRename);
this.flowLayoutToolbar.Controls.Add(this.buttonChangeMultiLine);
this.flowLayoutToolbar.Dock = System.Windows.Forms.DockStyle.Fill; this.flowLayoutToolbar.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutToolbar.FlowDirection = System.Windows.Forms.FlowDirection.BottomUp; this.flowLayoutToolbar.FlowDirection = System.Windows.Forms.FlowDirection.BottomUp;
this.flowLayoutToolbar.Location = new System.Drawing.Point(0, 0); this.flowLayoutToolbar.Location = new System.Drawing.Point(0, 0);
this.flowLayoutToolbar.Margin = new System.Windows.Forms.Padding(0); this.flowLayoutToolbar.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutToolbar.Name = "flowLayoutToolbar"; this.flowLayoutToolbar.Name = "flowLayoutToolbar";
this.tableLayout.SetRowSpan(this.flowLayoutToolbar, 3); this.tableLayout.SetRowSpan(this.flowLayoutToolbar, 2);
this.flowLayoutToolbar.Size = new System.Drawing.Size(66, 201); this.flowLayoutToolbar.Size = new System.Drawing.Size(66, 262);
this.flowLayoutToolbar.TabIndex = 0; this.flowLayoutToolbar.TabIndex = 0;
// //
// buttonAdd // buttonAdd
@ -85,7 +87,7 @@
this.buttonAdd.FlatAppearance.BorderSize = 0; this.buttonAdd.FlatAppearance.BorderSize = 0;
this.buttonAdd.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.buttonAdd.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonAdd.Image = global::UI_WinForms.Resources.Icons.icons8_add_tag_512; this.buttonAdd.Image = global::UI_WinForms.Resources.Icons.icons8_add_tag_512;
this.buttonAdd.Location = new System.Drawing.Point(3, 138); this.buttonAdd.Location = new System.Drawing.Point(3, 199);
this.buttonAdd.Name = "buttonAdd"; this.buttonAdd.Name = "buttonAdd";
this.buttonAdd.Size = new System.Drawing.Size(60, 60); this.buttonAdd.Size = new System.Drawing.Size(60, 60);
this.buttonAdd.TabIndex = 0; this.buttonAdd.TabIndex = 0;
@ -99,7 +101,7 @@
this.buttonRemove.FlatAppearance.BorderSize = 0; this.buttonRemove.FlatAppearance.BorderSize = 0;
this.buttonRemove.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.buttonRemove.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonRemove.Image = global::UI_WinForms.Resources.Icons.icons8_remove_tag_512; this.buttonRemove.Image = global::UI_WinForms.Resources.Icons.icons8_remove_tag_512;
this.buttonRemove.Location = new System.Drawing.Point(3, 72); this.buttonRemove.Location = new System.Drawing.Point(3, 133);
this.buttonRemove.Name = "buttonRemove"; this.buttonRemove.Name = "buttonRemove";
this.buttonRemove.Size = new System.Drawing.Size(60, 60); this.buttonRemove.Size = new System.Drawing.Size(60, 60);
this.buttonRemove.TabIndex = 2; this.buttonRemove.TabIndex = 2;
@ -113,7 +115,7 @@
this.buttonRename.FlatAppearance.BorderSize = 0; this.buttonRename.FlatAppearance.BorderSize = 0;
this.buttonRename.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.buttonRename.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonRename.Image = global::UI_WinForms.Resources.Icons.icons8_rename_512; this.buttonRename.Image = global::UI_WinForms.Resources.Icons.icons8_rename_512;
this.buttonRename.Location = new System.Drawing.Point(3, 6); this.buttonRename.Location = new System.Drawing.Point(3, 67);
this.buttonRename.Name = "buttonRename"; this.buttonRename.Name = "buttonRename";
this.buttonRename.Size = new System.Drawing.Size(60, 60); this.buttonRename.Size = new System.Drawing.Size(60, 60);
this.buttonRename.TabIndex = 1; this.buttonRename.TabIndex = 1;
@ -121,10 +123,24 @@
this.buttonRename.UseVisualStyleBackColor = true; this.buttonRename.UseVisualStyleBackColor = true;
this.buttonRename.Click += new System.EventHandler(this.buttonRename_Click); this.buttonRename.Click += new System.EventHandler(this.buttonRename_Click);
// //
// buttonChangeMultiLine
//
this.buttonChangeMultiLine.Enabled = false;
this.buttonChangeMultiLine.FlatAppearance.BorderSize = 0;
this.buttonChangeMultiLine.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonChangeMultiLine.Image = global::UI_WinForms.Resources.Icons.icons8_align_text_left_512;
this.buttonChangeMultiLine.Location = new System.Drawing.Point(69, 199);
this.buttonChangeMultiLine.Name = "buttonChangeMultiLine";
this.buttonChangeMultiLine.Size = new System.Drawing.Size(60, 60);
this.buttonChangeMultiLine.TabIndex = 3;
this.toolTip.SetToolTip(this.buttonChangeMultiLine, "Toggles the selected element\'s multi-line state");
this.buttonChangeMultiLine.UseVisualStyleBackColor = true;
this.buttonChangeMultiLine.Click += new System.EventHandler(this.buttonChangeMultiLine_Click);
//
// textBoxFilter // textBoxFilter
// //
this.textBoxFilter.Dock = System.Windows.Forms.DockStyle.Fill; this.textBoxFilter.Dock = System.Windows.Forms.DockStyle.Fill;
this.textBoxFilter.Location = new System.Drawing.Point(149, 164); this.textBoxFilter.Location = new System.Drawing.Point(149, 265);
this.textBoxFilter.Name = "textBoxFilter"; this.textBoxFilter.Name = "textBoxFilter";
this.textBoxFilter.Size = new System.Drawing.Size(554, 34); this.textBoxFilter.Size = new System.Drawing.Size(554, 34);
this.textBoxFilter.TabIndex = 2; this.textBoxFilter.TabIndex = 2;
@ -135,7 +151,7 @@
// //
this.labelFilter.AutoSize = true; this.labelFilter.AutoSize = true;
this.labelFilter.Dock = System.Windows.Forms.DockStyle.Fill; this.labelFilter.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelFilter.Location = new System.Drawing.Point(69, 161); this.labelFilter.Location = new System.Drawing.Point(69, 262);
this.labelFilter.Name = "labelFilter"; this.labelFilter.Name = "labelFilter";
this.labelFilter.Size = new System.Drawing.Size(74, 40); this.labelFilter.Size = new System.Drawing.Size(74, 40);
this.labelFilter.TabIndex = 3; this.labelFilter.TabIndex = 3;
@ -166,7 +182,7 @@
this.listTextElements.Location = new System.Drawing.Point(69, 43); this.listTextElements.Location = new System.Drawing.Point(69, 43);
this.listTextElements.MultiSelect = false; this.listTextElements.MultiSelect = false;
this.listTextElements.Name = "listTextElements"; this.listTextElements.Name = "listTextElements";
this.listTextElements.Size = new System.Drawing.Size(634, 115); this.listTextElements.Size = new System.Drawing.Size(634, 216);
this.listTextElements.TabIndex = 5; this.listTextElements.TabIndex = 5;
this.listTextElements.UseCompatibleStateImageBehavior = false; this.listTextElements.UseCompatibleStateImageBehavior = false;
this.listTextElements.View = System.Windows.Forms.View.SmallIcon; this.listTextElements.View = System.Windows.Forms.View.SmallIcon;
@ -191,7 +207,7 @@
this.Controls.Add(this.tableLayout); this.Controls.Add(this.tableLayout);
this.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point); this.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.Name = "TextElements"; this.Name = "TextElements";
this.Size = new System.Drawing.Size(706, 201); this.Size = new System.Drawing.Size(706, 302);
this.tableLayout.ResumeLayout(false); this.tableLayout.ResumeLayout(false);
this.tableLayout.PerformLayout(); this.tableLayout.PerformLayout();
this.flowLayoutToolbar.ResumeLayout(false); this.flowLayoutToolbar.ResumeLayout(false);
@ -212,5 +228,6 @@
private Label labelSectionPath; private Label labelSectionPath;
private ListView listTextElements; private ListView listTextElements;
private ColumnHeader column; private ColumnHeader column;
private Button buttonChangeMultiLine;
} }
} }

View File

@ -22,6 +22,7 @@ public partial class TextElements : UserControl
var imgList = new ImageList(); var imgList = new ImageList();
imgList.ImageSize = new Size(45, 45); imgList.ImageSize = new Size(45, 45);
imgList.ColorDepth = ColorDepth.Depth32Bit; imgList.ColorDepth = ColorDepth.Depth32Bit;
imgList.Images.Add(Icons.icons8_row_512);
imgList.Images.Add(Icons.icons8_align_text_left_512); imgList.Images.Add(Icons.icons8_align_text_left_512);
// Set the image list to the list box: // Set the image list to the list box:
@ -33,8 +34,8 @@ public partial class TextElements : UserControl
this.currentSection = section; this.currentSection = section;
this.currentTextElement = null; this.currentTextElement = null;
this.buttonAdd.Enabled = this.currentSection is not null; this.buttonAdd.Enabled = this.currentSection is not null;
this.buttonRename.Enabled = this.buttonRemove.Enabled = false; this.buttonRename.Enabled = this.buttonRemove.Enabled = this.buttonChangeMultiLine.Enabled = false;
if (this.currentSection is null) if (this.currentSection is null)
return; return;
@ -47,7 +48,12 @@ public partial class TextElements : UserControl
AppEvents.WhenTextElementChanged += (sender, textElement) => AppEvents.WhenTextElementChanged += (sender, textElement) =>
{ {
this.currentTextElement = textElement; this.currentTextElement = textElement;
this.buttonRename.Enabled = this.buttonRemove.Enabled = this.currentTextElement is not null; this.buttonRename.Enabled = this.buttonRemove.Enabled = this.buttonChangeMultiLine.Enabled = this.currentTextElement is not null;
if (this.currentTextElement is not null && this.currentTextElement.IsMultiLine)
this.buttonChangeMultiLine.Image = Icons.icons8_row_512;
else
this.buttonChangeMultiLine.Image = Icons.icons8_align_text_left_512;
}; };
} }
@ -63,7 +69,7 @@ public partial class TextElements : UserControl
// Update the list: // Update the list:
this.listTextElements.Items.Clear(); this.listTextElements.Items.Clear();
foreach (var textElement in textElements) foreach (var textElement in textElements)
this.listTextElements.Items.Add(new ListViewItem(textElement.Name, 0) this.listTextElements.Items.Add(new ListViewItem(textElement.Name, textElement.IsMultiLine ? 1 : 0)
{ {
Tag = textElement.Id, Tag = textElement.Id,
}); });
@ -80,21 +86,22 @@ public partial class TextElements : UserControl
Message: "Please type the desired text element's name.", Message: "Please type the desired text element's name.",
Title: "Add a text element", Title: "Add a text element",
Placeholder: "My text element", Placeholder: "My text element",
ShowQuestionCheckbox: false ShowQuestionCheckbox: true,
QuestionCheckboxText: "Is multi-line?"
)); ));
if(result.DialogResult == DialogResult.Cancel) if(result.DialogResult == DialogResult.Cancel)
return; return;
// Add the text element to the database into the current section: // Add the text element to the database into the current section:
var newTextElement = await TextElementProcessor.AddTextElement(this.currentSection?.DataKey, result.Text); var newTextElement = await TextElementProcessor.AddTextElement(this.currentSection?.DataKey, result.Text, result.AnswerToQuestion);
newTextElement.ProcessError(); newTextElement.ProcessError();
if(!newTextElement.Successful) if(!newTextElement.Successful)
return; return;
// Add the text element to the list: // Add the text element to the list:
this.listTextElements.Items.Add(new ListViewItem(newTextElement.Result!.Name, 0) this.listTextElements.Items.Add(new ListViewItem(newTextElement.Result!.Name, newTextElement.Result.IsMultiLine ? 1 : 0)
{ {
Tag = newTextElement.Result.Id, Tag = newTextElement.Result.Id,
}); });
@ -131,16 +138,39 @@ public partial class TextElements : UserControl
var result = InputDialog.Show(new InputDialog.Options( var result = InputDialog.Show(new InputDialog.Options(
Message: "Please edit the text element's name.", Message: "Please edit the text element's name.",
PreloadedText: this.currentTextElement!.Name, PreloadedText: this.currentTextElement!.Name,
ShowQuestionCheckbox: false, ShowQuestionCheckbox: true,
Title: "Rename text element" Title: "Rename text element",
QuestionCheckboxText: "Is multi-line?",
QuestionCheckboxState: this.currentTextElement.IsMultiLine
)); ));
// If the user canceled, return: // If the user canceled, return:
if(result.DialogResult == DialogResult.Cancel) if(result.DialogResult == DialogResult.Cancel)
return; return;
ProcessorResult<TextElement> alteredTextElement;
if(this.currentTextElement.Name == result.Text)
// Update the multi-line state:
alteredTextElement = await TextElementProcessor.UpdateTextElementState(this.currentTextElement.Id, result.AnswerToQuestion);
else
// Rename the text element:
alteredTextElement = await TextElementProcessor.RenameTextElement(this.currentTextElement.Id, result.Text, result.AnswerToQuestion);
// Rename the text element: alteredTextElement.ProcessError();
var alteredTextElement = await TextElementProcessor.RenameTextElement(this.currentTextElement.Id, result.Text); if(!alteredTextElement.Successful)
return;
// Reload the text elements:
await this.LoadTextElements();
}
private async void buttonChangeMultiLine_Click(object sender, EventArgs e)
{
if(this.DesignMode)
return;
// Update the multi-line state:
var alteredTextElement = await TextElementProcessor.UpdateTextElementState(this.currentTextElement!.Id, !this.currentTextElement.IsMultiLine);
alteredTextElement.ProcessError(); alteredTextElement.ProcessError();
if(!alteredTextElement.Successful) if(!alteredTextElement.Successful)
@ -152,12 +182,19 @@ public partial class TextElements : UserControl
private async void listTextElements_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) private async void listTextElements_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{ {
// Load the text element: if (e.IsSelected)
var selectedTextElementId = (int)e.Item.Tag; {
this.currentTextElement = await TextElementProcessor.LoadTextElement(selectedTextElementId); // Get the text element's id:
var selectedTextElementId = (int)e.Item.Tag;
// Fire the event:
AppEvents.TextElementChanged(this.currentTextElement); // Load the text element:
this.currentTextElement = await TextElementProcessor.LoadTextElement(selectedTextElementId);
// Fire the event:
AppEvents.TextElementChanged(this.currentTextElement);
}
else
AppEvents.TextElementChanged(null);
} }
private async void textBoxFilter_KeyUp(object sender, KeyEventArgs e) => await this.LoadTextElements(); private async void textBoxFilter_KeyUp(object sender, KeyEventArgs e) => await this.LoadTextElements();

View File

@ -0,0 +1,156 @@
namespace UI_WinForms.Components
{
sealed partial class Translation
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.tableLayout = new System.Windows.Forms.TableLayoutPanel();
this.labelHead = new System.Windows.Forms.Label();
this.textBox = new System.Windows.Forms.TextBox();
this.flowLayoutHeaderTools = new System.Windows.Forms.FlowLayoutPanel();
this.buttonDeepL = new System.Windows.Forms.Button();
this.checkBoxManual = new System.Windows.Forms.CheckBox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.tableLayout.SuspendLayout();
this.flowLayoutHeaderTools.SuspendLayout();
this.SuspendLayout();
//
// tableLayout
//
this.tableLayout.ColumnCount = 2;
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 366F));
this.tableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayout.Controls.Add(this.labelHead, 0, 0);
this.tableLayout.Controls.Add(this.textBox, 0, 1);
this.tableLayout.Controls.Add(this.flowLayoutHeaderTools, 1, 0);
this.tableLayout.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayout.Location = new System.Drawing.Point(0, 0);
this.tableLayout.Name = "tableLayout";
this.tableLayout.RowCount = 2;
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 66F));
this.tableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayout.Size = new System.Drawing.Size(820, 279);
this.tableLayout.TabIndex = 0;
//
// labelHead
//
this.labelHead.Dock = System.Windows.Forms.DockStyle.Fill;
this.labelHead.Location = new System.Drawing.Point(3, 0);
this.labelHead.Name = "labelHead";
this.labelHead.Size = new System.Drawing.Size(360, 66);
this.labelHead.TabIndex = 0;
this.labelHead.Text = "header";
this.labelHead.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// textBox
//
this.tableLayout.SetColumnSpan(this.textBox, 2);
this.textBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.textBox.Location = new System.Drawing.Point(3, 69);
this.textBox.Multiline = true;
this.textBox.Name = "textBox";
this.textBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.textBox.Size = new System.Drawing.Size(814, 207);
this.textBox.TabIndex = 1;
this.textBox.TextChanged += new System.EventHandler(this.textBox_TextChanged);
//
// flowLayoutHeaderTools
//
this.flowLayoutHeaderTools.Controls.Add(this.buttonDeepL);
this.flowLayoutHeaderTools.Controls.Add(this.checkBoxManual);
this.flowLayoutHeaderTools.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutHeaderTools.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
this.flowLayoutHeaderTools.Location = new System.Drawing.Point(366, 0);
this.flowLayoutHeaderTools.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutHeaderTools.Name = "flowLayoutHeaderTools";
this.flowLayoutHeaderTools.Size = new System.Drawing.Size(454, 66);
this.flowLayoutHeaderTools.TabIndex = 3;
//
// buttonDeepL
//
this.buttonDeepL.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.buttonDeepL.AutoSize = true;
this.buttonDeepL.FlatAppearance.BorderSize = 0;
this.buttonDeepL.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonDeepL.Image = global::UI_WinForms.Resources.Icons.icons8_bot_512;
this.buttonDeepL.Location = new System.Drawing.Point(391, 3);
this.buttonDeepL.Name = "buttonDeepL";
this.buttonDeepL.Size = new System.Drawing.Size(60, 60);
this.buttonDeepL.TabIndex = 2;
this.toolTip.SetToolTip(this.buttonDeepL, "Auto-generate this text by using DeepL sourced by the source culture.");
this.buttonDeepL.UseVisualStyleBackColor = true;
this.buttonDeepL.Click += new System.EventHandler(this.buttonDeepL_Click);
//
// checkBoxManual
//
this.checkBoxManual.AutoSize = true;
this.checkBoxManual.Location = new System.Drawing.Point(188, 3);
this.checkBoxManual.Name = "checkBoxManual";
this.checkBoxManual.Padding = new System.Windows.Forms.Padding(0, 14, 0, 14);
this.checkBoxManual.Size = new System.Drawing.Size(197, 60);
this.checkBoxManual.TabIndex = 0;
this.checkBoxManual.Text = "Manual translation";
this.toolTip.SetToolTip(this.checkBoxManual, "Never overwrites this translation automatically");
this.checkBoxManual.UseVisualStyleBackColor = true;
this.checkBoxManual.CheckedChanged += new System.EventHandler(this.checkBoxManual_CheckedChanged);
//
// toolTip
//
this.toolTip.AutoPopDelay = 30000;
this.toolTip.InitialDelay = 500;
this.toolTip.ReshowDelay = 100;
this.toolTip.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Info;
this.toolTip.ToolTipTitle = "Help";
//
// Translation
//
this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.Controls.Add(this.tableLayout);
this.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.Name = "Translation";
this.Size = new System.Drawing.Size(820, 279);
this.tableLayout.ResumeLayout(false);
this.tableLayout.PerformLayout();
this.flowLayoutHeaderTools.ResumeLayout(false);
this.flowLayoutHeaderTools.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private TableLayoutPanel tableLayout;
private Label labelHead;
private TextBox textBox;
private Button buttonDeepL;
private ToolTip toolTip;
private FlowLayoutPanel flowLayoutHeaderTools;
private CheckBox checkBoxManual;
}
}

View File

@ -0,0 +1,181 @@
using System.Timers;
using DataModel.Database;
using Processor;
using UI_WinForms.Resources;
using Timer = System.Timers.Timer;
namespace UI_WinForms.Components;
public sealed partial class Translation : UserControl
{
private readonly string culture = "en-US";
private readonly Timer saveTimer;
private readonly Timer translationTimer;
private bool isLoading = false;
private int currentTranslationId = -1;
private bool isDeepLSourceCulture = false;
private bool isManualOnlyMode = false;
private Translation? mainCultureTranslation = null;
public Translation()
{
this.InitializeComponent();
this.Dock = DockStyle.Top;
}
public Translation(AppSettings.CultureInfo cultureInfo)
{
this.InitializeComponent();
this.culture = cultureInfo.Code;
this.labelHead.Text = $"Culture: {cultureInfo.Code}";
this.Dock = DockStyle.Top;
this.saveTimer = new Timer
{
Enabled = false, // disable timer for now,
Interval = 1_000, // 1 second interval,
AutoReset = false, // runs only once
};
this.translationTimer = new Timer
{
Enabled = false, // disable timer for now,
Interval = 1_600, // 1.6 second interval,
AutoReset = false, // runs only once
};
this.saveTimer.Elapsed += this.SaveChanges;
this.translationTimer.Elapsed += this.TriggerTranslateNow;
this.Load += async (sender, args) => await this.LateSetup(cultureInfo);
}
private async Task LateSetup(AppSettings.CultureInfo cultureInfo)
{
this.isDeepLSourceCulture = await AppSettings.GetDeepLSourceCultureIndex() == cultureInfo.Index;
this.textBox.ReadOnly = !(this.isDeepLSourceCulture || await AppSettings.GetDeepLAction() == SettingDeepLAction.MANUAL);
this.checkBoxManual.Visible = !this.isDeepLSourceCulture;
this.buttonDeepL.Visible = await AppSettings.GetDeepLMode() != SettingDeepLMode.DISABLED;
this.buttonDeepL.Image = this.isDeepLSourceCulture ? Icons.icons8_trigger_1__svg : Icons.deepl_logo_icon_170284;
if (this.isDeepLSourceCulture)
{
this.labelHead.Text = $"Culture: {cultureInfo.Code} (DeepL source culture)";
this.toolTip.SetToolTip(this.buttonDeepL, "Replaces all other translations by DeepL translations using this culture as source culture.\nWarning: already translated texts will be replaced as well.");
if(this.Parent.Parent is Translations translations)
translations.RegisterMainCultureTranslationComponent(this);
}
}
public async Task Configure(DataModel.Database.Translation translation)
{
this.isLoading = true;
this.isManualOnlyMode = this.checkBoxManual.Checked = translation.TranslateManual;
this.currentTranslationId = translation.Id;
try
{
this.textBox.Text = translation.Text;
this.textBox.Multiline = translation.TextElement.IsMultiLine;
this.textBox.ReadOnly = !(this.isDeepLSourceCulture || await AppSettings.GetDeepLAction() == SettingDeepLAction.MANUAL);
if (this.isManualOnlyMode)
this.textBox.ReadOnly = false;
}
catch (ObjectDisposedException)
{
}
this.Height = translation.TextElement.IsMultiLine ? 280 : 106;
this.buttonDeepL.Visible = await AppSettings.GetDeepLMode() != SettingDeepLMode.DISABLED;
this.isLoading = false;
}
public void Clear()
{
this.isLoading = true;
this.currentTranslationId = -1;
this.textBox.Text = string.Empty;
this.textBox.Multiline = true;
this.Height = 280;
this.isLoading = false;
}
private async void textBox_TextChanged(object sender, EventArgs e)
{
if(this.isLoading)
return;
if(this.saveTimer.Enabled)
this.saveTimer.Stop();
this.saveTimer.Start();
if(this.ParentForm is UI_WinForms.Main main)
main.AddDeferredSaveOperation(this.currentTranslationId, () => this.SaveChanges(null, null));
if (this.isDeepLSourceCulture && await AppSettings.GetDeepLAction() == SettingDeepLAction.AUTOMATIC_ALL)
{
if (this.translationTimer.Enabled)
this.translationTimer.Stop();
this.translationTimer.Start();
}
}
private async void SaveChanges(object? sender, ElapsedEventArgs e)
{
if (this.currentTranslationId > -1)
await TranslationProcessor.SaveChangedTranslation(this.currentTranslationId, this.textBox.Text, this.checkBoxManual.Checked);
if(this.ParentForm is UI_WinForms.Main main)
main.RemoveDeferredSaveOperation(this.currentTranslationId);
this.isManualOnlyMode = this.checkBoxManual.Checked;
}
private async void TriggerTranslateNow(object? sender, ElapsedEventArgs e)
{
if (this.currentTranslationId < 0 || this.isDeepLSourceCulture == false)
return;
if(this.Parent.Parent is Translations translations)
await translations.MainCultureWasChanged();
}
internal void SetMainCultureTranslation(Translation translation) => this.mainCultureTranslation = translation;
internal string GetCurrentText() => this.textBox.Text;
internal async Task Translate(bool wasManualTriggered = false)
{
if (this.mainCultureTranslation is null)
return;
if(this.isManualOnlyMode && !wasManualTriggered)
return;
var text = await Processor.DeepL.Translate(this.mainCultureTranslation.GetCurrentText(), this.culture);
if (this.textBox.InvokeRequired)
this.textBox.Invoke(() => this.textBox.Text = text);
else
this.textBox.Text = text;
}
private async void buttonDeepL_Click(object sender, EventArgs e)
{
if (this.isDeepLSourceCulture)
this.TriggerTranslateNow(null, null);
else
await this.Translate(wasManualTriggered: true);
}
private async void checkBoxManual_CheckedChanged(object sender, EventArgs e)
{
if(this.isLoading)
return;
this.SaveChanges(null, null);
this.textBox.ReadOnly = !(this.isDeepLSourceCulture || await AppSettings.GetDeepLAction() == SettingDeepLAction.MANUAL);
if (this.isManualOnlyMode)
this.textBox.ReadOnly = false;
}
}

View File

@ -0,0 +1,63 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@ -0,0 +1,59 @@
namespace UI_WinForms.Components
{
partial class Translations
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.panelTranslations = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// panelTranslations
//
this.panelTranslations.AutoScroll = true;
this.panelTranslations.Dock = System.Windows.Forms.DockStyle.Fill;
this.panelTranslations.Location = new System.Drawing.Point(0, 0);
this.panelTranslations.Name = "panelTranslations";
this.panelTranslations.Size = new System.Drawing.Size(942, 462);
this.panelTranslations.TabIndex = 0;
//
// Translations
//
this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.Controls.Add(this.panelTranslations);
this.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.Name = "Translations";
this.Size = new System.Drawing.Size(942, 462);
this.ResumeLayout(false);
}
#endregion
private Panel panelTranslations;
}
}

View File

@ -0,0 +1,115 @@
using DataModel.Database;
using Processor;
using Timer = System.Timers.Timer;
namespace UI_WinForms.Components;
public partial class Translations : UserControl
{
private readonly Dictionary<string, Translation> translationComponents = new();
private readonly Timer clearTimer;
private Translation? mainCulture = null;
public Translations()
{
this.InitializeComponent();
this.Enabled = false;
this.clearTimer = new Timer
{
Enabled = false,
Interval = 600, // ms
AutoReset = false,
};
this.clearTimer.Elapsed += (sender, args) => this.ClearTranslations();
this.Load += async (sender, args) => await this.SetupTranslations();
AppEvents.WhenTextElementChanged += async (sender, textElement) =>
{
if(textElement is null)
{
this.clearTimer.Start();
return;
}
this.clearTimer.Stop();
if (!this.Enabled)
this.Enabled = true;
var allTranslations = await TranslationProcessor.GetTranslations(textElement);
foreach (var translation in allTranslations)
if (this.translationComponents.ContainsKey(translation.Culture))
await this.translationComponents[translation.Culture].Configure(translation);
};
AppEvents.WhenSectionChanged += (sender, section) => this.ClearTranslations();
}
private void ClearTranslations()
{
// Perform UI changes on the UI thread:
if (this.InvokeRequired)
{
this.Invoke(this.ClearTranslations);
return;
}
this.Enabled = false;
foreach (var (_, translation) in this.translationComponents)
translation.Clear();
}
private async Task SetupTranslations()
{
if(this.DesignMode)
return;
// Apply a custom order for the cultures. We want to show the default culture first,
// then the other cultures in order of their index. Please note: whatever we want to
// show as first, we have to return last!
async IAsyncEnumerable<AppSettings.CultureInfo> DesiredOrder()
{
// Get all configured cultures:
var cultureInfos = (await AppSettings.GetCultureInfos()).OrderByDescending(n => n.Index).ToList();
// Get the main culture:
var mainCultureIndex = await AppSettings.GetDeepLSourceCultureIndex();
// First, we return all the non-main cultures in descending order of their index:
foreach (var cultureInfo in cultureInfos.Where(n => n.Index != mainCultureIndex))
yield return cultureInfo;
// Last, we return the main culture:
if(cultureInfos.Any(n => n.Index == mainCultureIndex))
yield return cultureInfos.First(n => n.Index == mainCultureIndex);
}
await foreach (var cultureInfo in DesiredOrder())
{
var translationComponent = new Translation(cultureInfo);
this.translationComponents.Add(cultureInfo.Code, translationComponent);
this.panelTranslations.Controls.Add(translationComponent);
}
}
internal void RegisterMainCultureTranslationComponent(Translation trans)
{
this.mainCulture = trans;
// Register the main culture translation component into all the other
// translation components:
foreach (var (_, translation) in this.translationComponents.Where(n => n.Value != trans))
translation.SetMainCultureTranslation(trans);
}
internal async Task MainCultureWasChanged()
{
if(this.mainCulture is null || await AppSettings.GetDeepLMode() == SettingDeepLMode.DISABLED)
return;
var allTasks = new List<Task>();
foreach (var (_, translation) in this.translationComponents.Where(n => n.Value != this.mainCulture))
allTasks.Add(translation.Translate());
await Task.WhenAll(allTasks);
}
}

View File

@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -10,7 +10,8 @@ public partial class InputDialog : Form
string OkButtonText = "Ok", string OkButtonText = "Ok",
string CancelButtonText = "Cancel", string CancelButtonText = "Cancel",
bool ShowQuestionCheckbox = false, bool ShowQuestionCheckbox = false,
string QuestionCheckboxText = "" string QuestionCheckboxText = "",
bool QuestionCheckboxState = false
); );
private InputDialog() private InputDialog()
@ -29,6 +30,7 @@ public partial class InputDialog : Form
inputDialog.buttonCancel.Text = options.CancelButtonText; inputDialog.buttonCancel.Text = options.CancelButtonText;
inputDialog.checkBoxQuestion.Visible = options.ShowQuestionCheckbox; inputDialog.checkBoxQuestion.Visible = options.ShowQuestionCheckbox;
inputDialog.checkBoxQuestion.Text = options.QuestionCheckboxText; inputDialog.checkBoxQuestion.Text = options.QuestionCheckboxText;
inputDialog.checkBoxQuestion.Checked = options.QuestionCheckboxState;
// Ensure, that the text box is focused on load: // Ensure, that the text box is focused on load:
inputDialog.textBoxInput.Select(); inputDialog.textBoxInput.Select();

View File

@ -52,6 +52,7 @@
this.Name = "Main"; this.Name = "Main";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "I18N Commander"; this.Text = "I18N Commander";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Main_FormClosing);
this.ResumeLayout(false); this.ResumeLayout(false);
} }

View File

@ -2,8 +2,32 @@ namespace UI_WinForms;
public partial class Main : Form public partial class Main : Form
{ {
private readonly Dictionary<int, Action> deferredSaveOperations = new();
public Main() public Main()
{ {
this.InitializeComponent(); this.InitializeComponent();
} }
private void Main_FormClosing(object sender, FormClosingEventArgs e)
{
foreach (var (_, action) in this.deferredSaveOperations)
action();
this.deferredSaveOperations.Clear();
}
internal void AddDeferredSaveOperation(int id, Action action)
{
if (this.deferredSaveOperations.ContainsKey(id))
this.deferredSaveOperations.Remove(id);
this.deferredSaveOperations.Add(id, action);
}
internal void RemoveDeferredSaveOperation(int id)
{
if (this.deferredSaveOperations.ContainsKey(id))
this.deferredSaveOperations.Remove(id);
}
} }

View File

@ -11,6 +11,8 @@ internal static class Program
internal const string VERSION = "v0.1.0"; internal const string VERSION = "v0.1.0";
internal static IServiceProvider? SERVICE_PROVIDER; internal static IServiceProvider? SERVICE_PROVIDER;
internal static bool RestartMainApp = false;
[STAThread] [STAThread]
private static void Main() private static void Main()
{ {
@ -56,7 +58,10 @@ internal static class Program
Setup.PerformDataMigration(database).Wait(); Setup.PerformDataMigration(database).Wait();
// Start the app: // Start the app:
Application.Run(new Main()); do
{
Application.Run(new Main());
} while (Program.RestartMainApp);
} }
} }
} }

View File

@ -100,6 +100,16 @@ namespace UI_WinForms.Resources {
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap icons8_bot_512 {
get {
object obj = ResourceManager.GetObject("icons8_bot_512", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap. /// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary> /// </summary>
@ -280,6 +290,16 @@ namespace UI_WinForms.Resources {
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap icons8_row_512 {
get {
object obj = ResourceManager.GetObject("icons8_row_512", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap. /// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary> /// </summary>
@ -299,5 +319,15 @@ namespace UI_WinForms.Resources {
return ((System.Drawing.Bitmap)(obj)); return ((System.Drawing.Bitmap)(obj));
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap icons8_trigger_1__svg {
get {
object obj = ResourceManager.GetObject("icons8_trigger_1__svg", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
} }
} }

View File

@ -130,6 +130,9 @@
<data name="icons8_align_text_left_512" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="icons8_align_text_left_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-align-text-left-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>icons8-align-text-left-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="icons8_bot_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-bot-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="icons8_browse_folder_512" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="icons8_browse_folder_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-browse-folder-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>icons8-browse-folder-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
@ -184,10 +187,16 @@
<data name="icons8_rename_512" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="icons8_rename_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-rename-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>icons8-rename-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="icons8_row_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-row-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="icons8_settings_svg" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="icons8_settings_svg" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-settings.svg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>icons8-settings.svg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="icons8_trash_can_512" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="icons8_trash_can_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-trash-can-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>icons8-trash-can-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="icons8_trigger_1__svg" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-trigger(1).svg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root> </root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB