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

View File

@ -11,6 +11,8 @@ public sealed class TextElement
public string Code { get; set; } = string.Empty;
public bool IsMultiLine { get; set; } = false;
public Section Section { get; set; }
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 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)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.5");
modelBuilder.HasAnnotation("ProductVersion", "6.0.9");
modelBuilder.Entity("DataModel.Database.Section", b =>
{
@ -103,6 +103,9 @@ namespace DataModel.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsMultiLine")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
@ -116,6 +119,8 @@ namespace DataModel.Migrations
b.HasIndex("Id");
b.HasIndex("IsMultiLine");
b.HasIndex("Name");
b.HasIndex("SectionId");
@ -140,6 +145,9 @@ namespace DataModel.Migrations
b.Property<int>("TextElementId")
.HasColumnType("INTEGER");
b.Property<bool>("TranslateManual")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Culture");
@ -150,6 +158,8 @@ namespace DataModel.Migrations
b.HasIndex("TextElementId");
b.HasIndex("TranslateManual");
b.ToTable("Translations");
});

View File

@ -52,6 +52,9 @@ public static class DeepL
var sourceCultureIndex = await AppSettings.GetDeepLSourceCultureIndex();
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);
var translation = await deepl.TranslateTextAsync(text, sourceCulture, targetCulture);

View File

@ -26,7 +26,7 @@ public static class TextElementProcessor
}
// 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>();
@ -45,6 +45,7 @@ public static class TextElementProcessor
Name = elementName,
Code = code,
Section = currentSection,
IsMultiLine = isMultiLine,
};
// Add the new element to the database:
@ -62,15 +63,31 @@ public static class TextElementProcessor
}
}
// Renames a text element:
public static async Task<ProcessorResult<TextElement>> RenameTextElement(int id, string newName)
// Updates the multi-line flag of a text element:
public static async Task<ProcessorResult<TextElement>> UpdateTextElementState(int id, bool isMultiLine)
{
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
var textElement = await db.TextElements.FirstAsync(n => n.Id == id);
if (textElement is null)
throw new ArgumentOutOfRangeException(nameof(id));
textElement.IsMultiLine = isMultiLine;
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:
var section = (await db.TextElements.FirstAsync(n => n.Id == id)).Section;
@ -79,6 +96,7 @@ public static class TextElementProcessor
textElement.Name = newName;
textElement.Code = code;
textElement.IsMultiLine = isMultiLine;
// Save the changes:
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
// 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:
internal static void TextElementChanged(TextElement textElement) => WhenTextElementChanged?.Invoke(null, textElement);
internal static void TextElementChanged(TextElement? textElement) => WhenTextElementChanged?.Invoke(null, textElement);
#endregion
}

View File

@ -40,6 +40,7 @@
this.tabSettings = new System.Windows.Forms.TabPage();
this.settings = new UI_WinForms.Components.Settings();
this.imageList = new System.Windows.Forms.ImageList(this.components);
this.translations = new UI_WinForms.Components.Translations();
this.tableLayout.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainerLR)).BeginInit();
this.splitContainerLR.Panel1.SuspendLayout();
@ -47,6 +48,7 @@
this.splitContainerLR.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainerRTB)).BeginInit();
this.splitContainerRTB.Panel1.SuspendLayout();
this.splitContainerRTB.Panel2.SuspendLayout();
this.splitContainerRTB.SuspendLayout();
this.tabControl.SuspendLayout();
this.tabTranslation.SuspendLayout();
@ -109,6 +111,10 @@
//
this.splitContainerRTB.Panel1.Controls.Add(this.textElements);
this.splitContainerRTB.Panel1MinSize = 340;
//
// splitContainerRTB.Panel2
//
this.splitContainerRTB.Panel2.Controls.Add(this.translations);
this.splitContainerRTB.Size = new System.Drawing.Size(556, 583);
this.splitContainerRTB.SplitterDistance = 340;
this.splitContainerRTB.TabIndex = 0;
@ -136,6 +142,7 @@
this.tabControl.SelectedIndex = 0;
this.tabControl.Size = new System.Drawing.Size(965, 603);
this.tabControl.TabIndex = 1;
this.tabControl.SelectedIndexChanged += new System.EventHandler(this.tabControl_SelectedIndexChanged);
//
// tabTranslation
//
@ -153,10 +160,10 @@
//
this.tabSettings.Controls.Add(this.settings);
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.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.Text = "Settings";
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.Location = new System.Drawing.Point(3, 3);
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;
//
// imageList
@ -178,6 +185,15 @@
this.imageList.Images.SetKeyName(0, "icons8-settings.svg.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
//
this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F);
@ -192,6 +208,7 @@
((System.ComponentModel.ISupportInitialize)(this.splitContainerLR)).EndInit();
this.splitContainerLR.ResumeLayout(false);
this.splitContainerRTB.Panel1.ResumeLayout(false);
this.splitContainerRTB.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.splitContainerRTB)).EndInit();
this.splitContainerRTB.ResumeLayout(false);
this.tabControl.ResumeLayout(false);
@ -213,5 +230,6 @@
private TabPage tabSettings;
private ImageList imageList;
private Settings settings;
private Translations translations;
}
}

View File

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

View File

@ -17,6 +17,12 @@ public partial class Settings : UserControl
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)
{
// Get the current indices of cultures:

View File

@ -34,6 +34,7 @@
this.buttonAdd = new System.Windows.Forms.Button();
this.buttonRemove = 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.labelFilter = 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.Percent, 100F));
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;
//
// flowLayoutToolbar
@ -70,13 +71,14 @@
this.flowLayoutToolbar.Controls.Add(this.buttonAdd);
this.flowLayoutToolbar.Controls.Add(this.buttonRemove);
this.flowLayoutToolbar.Controls.Add(this.buttonRename);
this.flowLayoutToolbar.Controls.Add(this.buttonChangeMultiLine);
this.flowLayoutToolbar.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutToolbar.FlowDirection = System.Windows.Forms.FlowDirection.BottomUp;
this.flowLayoutToolbar.Location = new System.Drawing.Point(0, 0);
this.flowLayoutToolbar.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutToolbar.Name = "flowLayoutToolbar";
this.tableLayout.SetRowSpan(this.flowLayoutToolbar, 3);
this.flowLayoutToolbar.Size = new System.Drawing.Size(66, 201);
this.tableLayout.SetRowSpan(this.flowLayoutToolbar, 2);
this.flowLayoutToolbar.Size = new System.Drawing.Size(66, 262);
this.flowLayoutToolbar.TabIndex = 0;
//
// buttonAdd
@ -85,7 +87,7 @@
this.buttonAdd.FlatAppearance.BorderSize = 0;
this.buttonAdd.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
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.Size = new System.Drawing.Size(60, 60);
this.buttonAdd.TabIndex = 0;
@ -99,7 +101,7 @@
this.buttonRemove.FlatAppearance.BorderSize = 0;
this.buttonRemove.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
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.Size = new System.Drawing.Size(60, 60);
this.buttonRemove.TabIndex = 2;
@ -113,7 +115,7 @@
this.buttonRename.FlatAppearance.BorderSize = 0;
this.buttonRename.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
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.Size = new System.Drawing.Size(60, 60);
this.buttonRename.TabIndex = 1;
@ -121,10 +123,24 @@
this.buttonRename.UseVisualStyleBackColor = true;
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
//
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.Size = new System.Drawing.Size(554, 34);
this.textBoxFilter.TabIndex = 2;
@ -135,7 +151,7 @@
//
this.labelFilter.AutoSize = true;
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.Size = new System.Drawing.Size(74, 40);
this.labelFilter.TabIndex = 3;
@ -166,7 +182,7 @@
this.listTextElements.Location = new System.Drawing.Point(69, 43);
this.listTextElements.MultiSelect = false;
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.UseCompatibleStateImageBehavior = false;
this.listTextElements.View = System.Windows.Forms.View.SmallIcon;
@ -191,7 +207,7 @@
this.Controls.Add(this.tableLayout);
this.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
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.PerformLayout();
this.flowLayoutToolbar.ResumeLayout(false);
@ -212,5 +228,6 @@
private Label labelSectionPath;
private ListView listTextElements;
private ColumnHeader column;
private Button buttonChangeMultiLine;
}
}

View File

@ -22,6 +22,7 @@ public partial class TextElements : UserControl
var imgList = new ImageList();
imgList.ImageSize = new Size(45, 45);
imgList.ColorDepth = ColorDepth.Depth32Bit;
imgList.Images.Add(Icons.icons8_row_512);
imgList.Images.Add(Icons.icons8_align_text_left_512);
// Set the image list to the list box:
@ -33,8 +34,8 @@ public partial class TextElements : UserControl
this.currentSection = section;
this.currentTextElement = 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)
return;
@ -47,7 +48,12 @@ public partial class TextElements : UserControl
AppEvents.WhenTextElementChanged += (sender, 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:
this.listTextElements.Items.Clear();
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,
});
@ -80,21 +86,22 @@ public partial class TextElements : UserControl
Message: "Please type the desired text element's name.",
Title: "Add a text element",
Placeholder: "My text element",
ShowQuestionCheckbox: false
ShowQuestionCheckbox: true,
QuestionCheckboxText: "Is multi-line?"
));
if(result.DialogResult == DialogResult.Cancel)
return;
// 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();
if(!newTextElement.Successful)
return;
// 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,
});
@ -131,16 +138,39 @@ public partial class TextElements : UserControl
var result = InputDialog.Show(new InputDialog.Options(
Message: "Please edit the text element's name.",
PreloadedText: this.currentTextElement!.Name,
ShowQuestionCheckbox: false,
Title: "Rename text element"
ShowQuestionCheckbox: true,
Title: "Rename text element",
QuestionCheckboxText: "Is multi-line?",
QuestionCheckboxState: this.currentTextElement.IsMultiLine
));
// If the user canceled, return:
if(result.DialogResult == DialogResult.Cancel)
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:
var alteredTextElement = await TextElementProcessor.RenameTextElement(this.currentTextElement.Id, result.Text);
alteredTextElement.ProcessError();
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();
if(!alteredTextElement.Successful)
@ -152,12 +182,19 @@ public partial class TextElements : UserControl
private async void listTextElements_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
// Load the text element:
var selectedTextElementId = (int)e.Item.Tag;
this.currentTextElement = await TextElementProcessor.LoadTextElement(selectedTextElementId);
// Fire the event:
AppEvents.TextElementChanged(this.currentTextElement);
if (e.IsSelected)
{
// Get the text element's id:
var selectedTextElementId = (int)e.Item.Tag;
// 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();

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

View File

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

View File

@ -2,8 +2,32 @@ namespace UI_WinForms;
public partial class Main : Form
{
private readonly Dictionary<int, Action> deferredSaveOperations = new();
public Main()
{
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 static IServiceProvider? SERVICE_PROVIDER;
internal static bool RestartMainApp = false;
[STAThread]
private static void Main()
{
@ -56,7 +58,10 @@ internal static class Program
Setup.PerformDataMigration(database).Wait();
// 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>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </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>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
@ -299,5 +319,15 @@ namespace UI_WinForms.Resources {
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">
<value>icons8-align-text-left-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</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">
<value>icons8-browse-folder-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
@ -184,10 +187,16 @@
<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>
</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">
<value>icons8-settings.svg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<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>
</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>

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