diff --git a/DICUI.Forms/App.config b/DICUI.Forms/App.config new file mode 100644 index 00000000..731f6de6 --- /dev/null +++ b/DICUI.Forms/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/DICUI/UI/AllowedSpeeds.cs b/DICUI.Forms/Constants.cs similarity index 71% rename from DICUI/UI/AllowedSpeeds.cs rename to DICUI.Forms/Constants.cs index 747caae6..678aef96 100644 --- a/DICUI/UI/AllowedSpeeds.cs +++ b/DICUI.Forms/Constants.cs @@ -4,13 +4,18 @@ using System.Linq; using System.Windows.Media; using DICUI.Data; -namespace DICUI.UI +namespace DICUI { /// - /// Gets allowed drive speeds for a given media type + /// Variables for UI elements /// - public static class AllowedSpeeds + public static class Constants { + public const string StartDumping = "Start Dumping"; + public const string StopDumping = "Stop Dumping"; + + public const int LogWindowMarginFromMainWindow = 10; + // Private lists of known drive speed ranges private static IReadOnlyList cd { get; } = new List { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 }; private static IReadOnlyList dvd { get; } = cd.Where(s => s <= 24).ToList(); @@ -22,7 +27,7 @@ namespace DICUI.UI /// /// MediaType? that represents the current item /// Read-only list of drive speeds - public static IReadOnlyList GetForMediaType(MediaType? type) + public static IReadOnlyList GetSpeedsForMediaType(MediaType? type) { switch (type) { @@ -42,9 +47,9 @@ namespace DICUI.UI } // Create collections for UI based on known drive speeds - public static DoubleCollection ForCDAsCollection { get; } = GetDoubleCollectionFromIntList(cd); - public static DoubleCollection ForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(dvd); - public static DoubleCollection ForBDAsCollection { get; } = GetDoubleCollectionFromIntList(bd); + public static DoubleCollection SpeedsForCDAsCollection { get; } = GetDoubleCollectionFromIntList(cd); + public static DoubleCollection SpeedsForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(dvd); + public static DoubleCollection SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(bd); private static DoubleCollection GetDoubleCollectionFromIntList(IReadOnlyList list) => new DoubleCollection(list.Select(i => Convert.ToDouble(i)).ToList()); } diff --git a/DICUI.Forms/DICUI.Forms.csproj b/DICUI.Forms/DICUI.Forms.csproj new file mode 100644 index 00000000..b3251bcd --- /dev/null +++ b/DICUI.Forms/DICUI.Forms.csproj @@ -0,0 +1,116 @@ + + + + + Debug + AnyCPU + {A6719A99-BF0E-4637-9A8E-CB38B1E16971} + WinExe + DICUI.Forms + DICUI.Forms + v4.6.1 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Icon.ico + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Settings1.settings + + + + Form + + + LogWindow.cs + + + Form + + + MainWindow.cs + + + + + Form + + + OptionsWindow.cs + + + LogWindow.cs + + + MainWindow.cs + Designer + + + OptionsWindow.cs + + + + + + SettingsSingleFileGenerator + Settings1.Designer.cs + + + + + + + + {51ab0928-13f9-44bf-a407-b6957a43a056} + DICUI.Library + + + + \ No newline at end of file diff --git a/DICUI.Forms/EnumDescriptionConverter.cs b/DICUI.Forms/EnumDescriptionConverter.cs new file mode 100644 index 00000000..1526b272 --- /dev/null +++ b/DICUI.Forms/EnumDescriptionConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Globalization; +using System.Windows.Data; +using DICUI.Data; +using DICUI.Utilities; + +namespace DICUI.Forms +{ + /// + /// Used to provide a converter to XAML files to render comboboxes with enum values + /// + public class EnumDescriptionConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is DICCommand) + return ((DICCommand)value).Name(); + else if (value is DICFlag) + return ((DICFlag)value).Name(); + else if (value is MediaType?) + return ((MediaType?)value).Name(); + else if (value is KnownSystem?) + return ((KnownSystem?)value).Name(); + else + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return string.Empty; + } + } +} diff --git a/DICUI.Forms/Icon.ico b/DICUI.Forms/Icon.ico new file mode 100644 index 00000000..370e6559 Binary files /dev/null and b/DICUI.Forms/Icon.ico differ diff --git a/DICUI.Forms/KnownSystemComboBoxItem.cs b/DICUI.Forms/KnownSystemComboBoxItem.cs new file mode 100644 index 00000000..c9c70b56 --- /dev/null +++ b/DICUI.Forms/KnownSystemComboBoxItem.cs @@ -0,0 +1,35 @@ +using System.Windows.Media; +using DICUI.Data; +using DICUI.Utilities; + +namespace DICUI +{ + /// + /// Represents a single item in the System combo box + /// + public class KnownSystemComboBoxItem + { + private object data; + + public KnownSystemComboBoxItem(KnownSystem? system) => data = system; + public KnownSystemComboBoxItem(KnownSystemCategory? category) => data = category; + + //public Brush Foreground { get => IsHeader() ? Brushes.Gray : Brushes.Black; } // TODO: Re-enable this + + public bool IsHeader() => data is KnownSystemCategory?; + public bool IsSystem() => data is KnownSystem?; + + public static implicit operator KnownSystem? (KnownSystemComboBoxItem item) => item.data as KnownSystem?; + + public string Name + { + get + { + if (IsHeader()) + return "---------- " + (data as KnownSystemCategory?).Name() + " ----------"; + else + return (data as KnownSystem?).Name(); + } + } + } +} diff --git a/DICUI.Forms/Options.cs b/DICUI.Forms/Options.cs new file mode 100644 index 00000000..aef39fa1 --- /dev/null +++ b/DICUI.Forms/Options.cs @@ -0,0 +1,97 @@ +using System; +using System.Configuration; +using System.Reflection; +using DICUI.Data; + +namespace DICUI +{ + public class Options + { + public string DefaultOutputPath { get; private set; } + public string DICPath { get; private set; } + public string SubDumpPath { get; private set; } + + public int preferredDumpSpeedCD { get; set; } + public int preferredDumpSpeedDVD { get; set; } + public int preferredDumpSpeedBD { get; set; } + + public bool QuietMode { get; set; } + public bool ParanoidMode { get; set; } + public bool ScanForProtection { get; set; } + public int RereadAmountForC2 { get; set; } + + public bool SkipMediaTypeDetection { get; set; } + + public bool VerboseLogging { get; set; } + public bool OpenLogWindowAtStartup { get; set; } + + public void Save() + { + Configuration configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); + + //TODO: reflection is used + //TODO: is remove needed, doesn't the value get directly overridden + Array.ForEach( + GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance), + p => { + configFile.AppSettings.Settings.Remove(p.Name); + configFile.AppSettings.Settings.Add(p.Name, Convert.ToString(p.GetValue(this))); + } + ); + + configFile.Save(ConfigurationSaveMode.Modified); + } + + public void Load() + { + //TODO: hardcoded, we should find a better way + DICPath = ConfigurationManager.AppSettings["DICPath"] ?? @"Programs\DiscImageCreator.exe"; + SubDumpPath = ConfigurationManager.AppSettings["SubDumpPath"] ?? "subdump.exe"; + DefaultOutputPath = ConfigurationManager.AppSettings["DefaultOutputPath"] ?? "ISO"; + + this.preferredDumpSpeedCD = Int32.TryParse(ConfigurationManager.AppSettings["preferredDumpSpeedCD"], out int maxDumpSpeedCD) ? maxDumpSpeedCD : 72; + this.preferredDumpSpeedDVD = Int32.TryParse(ConfigurationManager.AppSettings["preferredDumpSpeedDVD"], out int maxDumpSpeedDVD) ? maxDumpSpeedDVD : 24; + this.preferredDumpSpeedBD = Int32.TryParse(ConfigurationManager.AppSettings["preferredDumpSpeedBD"], out int maxDumpSpeedBD) ? maxDumpSpeedBD : 16; + + this.QuietMode = Boolean.TryParse(ConfigurationManager.AppSettings["QuietMode"], out bool quietMode) ? quietMode : false; + this.ParanoidMode = Boolean.TryParse(ConfigurationManager.AppSettings["ParanoidMode"], out bool paranoidMode) ? paranoidMode : false; + this.ScanForProtection = Boolean.TryParse(ConfigurationManager.AppSettings["ScanForProtection"], out bool scanForProtection) ? scanForProtection : true; + this.SkipMediaTypeDetection = Boolean.TryParse(ConfigurationManager.AppSettings["SkipMediaTypeDetection"], out bool skipMediaTypeDetection) ? skipMediaTypeDetection : false; + this.RereadAmountForC2 = Int32.TryParse(ConfigurationManager.AppSettings["RereadAmountForC2"], out int rereadAmountForC2) ? rereadAmountForC2 : 20; + this.VerboseLogging = Boolean.TryParse(ConfigurationManager.AppSettings["VerboseLogging"], out bool verboseLogging) ? verboseLogging : true; + this.OpenLogWindowAtStartup = Boolean.TryParse(ConfigurationManager.AppSettings["OpenLogWindowAtStartup"], out bool openLogWindowAtStartup) ? openLogWindowAtStartup : true; + } + + + //TODO: probably should be generic for non-string options + //TODO: using reflection for Set and Get is orthodox but it works, should be changed to a key,value map probably + public void Set(string key, string value) + { + GetType().GetProperty(key, BindingFlags.Public | BindingFlags.Instance).SetValue(this, value); + } + + public string Get(string key) + { + return GetType().GetProperty(key, BindingFlags.Public | BindingFlags.Instance).GetValue(this) as string; + } + + public int GetPreferredDumpSpeedForMediaType(MediaType? type) + { + switch (type) + { + case MediaType.CDROM: + case MediaType.GDROM: + return preferredDumpSpeedCD; + case MediaType.DVD: + case MediaType.HDDVD: + case MediaType.NintendoGameCube: + case MediaType.NintendoWiiOpticalDisc: + return preferredDumpSpeedDVD; + case MediaType.BluRay: + return preferredDumpSpeedBD; + default: + return 8; + } + } + } +} diff --git a/DICUI.Forms/Program.cs b/DICUI.Forms/Program.cs new file mode 100644 index 00000000..c33e7636 --- /dev/null +++ b/DICUI.Forms/Program.cs @@ -0,0 +1,20 @@ +using System; +using System.Windows.Forms; +using DICUI.Forms.Windows; + +namespace DICUI.Forms +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainWindow()); + } + } +} diff --git a/DICUI.Forms/Properties/AssemblyInfo.cs b/DICUI.Forms/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..87137edc --- /dev/null +++ b/DICUI.Forms/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DICUI.Forms")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DICUI.Forms")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a6719a99-bf0e-4637-9a8e-cb38b1e16971")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DICUI.Forms/Properties/Settings1.Designer.cs b/DICUI.Forms/Properties/Settings1.Designer.cs new file mode 100644 index 00000000..2a34933b --- /dev/null +++ b/DICUI.Forms/Properties/Settings1.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DICUI.Forms.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] + internal sealed partial class Settings1 : global::System.Configuration.ApplicationSettingsBase { + + private static Settings1 defaultInstance = ((Settings1)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings1()))); + + public static Settings1 Default { + get { + return defaultInstance; + } + } + } +} diff --git a/DICUI.Forms/Properties/Settings1.settings b/DICUI.Forms/Properties/Settings1.settings new file mode 100644 index 00000000..049245f4 --- /dev/null +++ b/DICUI.Forms/Properties/Settings1.settings @@ -0,0 +1,6 @@ + + + + + + diff --git a/DICUI.Forms/ViewModels.cs b/DICUI.Forms/ViewModels.cs new file mode 100644 index 00000000..445c7fb0 --- /dev/null +++ b/DICUI.Forms/ViewModels.cs @@ -0,0 +1,107 @@ +using System; +using System.Windows.Media; +using DICUI.Forms.Windows; + +namespace DICUI.Forms +{ + public class OptionsViewModel + { + private Options _options; + + public OptionsViewModel(Options options) + { + this._options = options; + } + + public bool QuietMode + { + get { return _options.QuietMode; } + set { _options.QuietMode = value; } + } + + public bool ParanoidMode + { + get { return _options.ParanoidMode; } + set { _options.ParanoidMode = value; } + } + + public bool ScanForProtection + { + get { return _options.ScanForProtection; } + set { _options.ScanForProtection = value; } + } + + public bool SkipMediaTypeDetection + { + get { return _options.SkipMediaTypeDetection; } + set { _options.SkipMediaTypeDetection = value; } + } + + public string RereadAmountForC2 + { + get { return Convert.ToString(_options.RereadAmountForC2); } + set + { + if (Int32.TryParse(value, out int result)) + _options.RereadAmountForC2 = result; + } + } + + public bool VerboseLogging + { + get { return _options.VerboseLogging; } + set + { + _options.VerboseLogging = value; + _options.Save(); + } + } + + public bool OpenLogWindowAtStartup + { + get { return _options.OpenLogWindowAtStartup; } + set + { + _options.OpenLogWindowAtStartup = value; + _options.Save(); + } + } + } + + public class LoggerViewModel + { + private LogWindow _logWindow; + + public void SetWindow(LogWindow logWindow) => _logWindow = logWindow; + + public bool WindowVisible + { + get => _logWindow != null ? _logWindow.Visible : false; + set + { + if (value) + { + _logWindow.AdjustPositionToMainWindow(); + _logWindow.Show(); + } + else + _logWindow.Hide(); + } + } + + public void VerboseLog(string text) + { + if (ViewModels.OptionsViewModel.VerboseLogging) + _logWindow.AppendToTextBox(text, System.Drawing.Color.Yellow); + } + + public void VerboseLog(string format, params object[] args) => VerboseLog(string.Format(format, args)); + public void VerboseLogLn(string format, params object[] args) => VerboseLog(string.Format(format, args) + "\n"); + } + + public static class ViewModels + { + public static OptionsViewModel OptionsViewModel { get; set; } + public static LoggerViewModel LoggerViewModel { get; set; } = new LoggerViewModel(); + } +} diff --git a/DICUI.Forms/Windows/LogWindow.Designer.cs b/DICUI.Forms/Windows/LogWindow.Designer.cs new file mode 100644 index 00000000..b6c67a69 --- /dev/null +++ b/DICUI.Forms/Windows/LogWindow.Designer.cs @@ -0,0 +1,175 @@ +namespace DICUI.Forms.Windows +{ + partial class LogWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.progressBar = new System.Windows.Forms.ProgressBar(); + this.output = new System.Windows.Forms.RichTextBox(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.Verbose = new System.Windows.Forms.CheckBox(); + this.OpenAtStartupCheckBox = new System.Windows.Forms.CheckBox(); + this.ClearButton = new System.Windows.Forms.Button(); + this.HideButton = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.progressBar, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.output, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 2); + this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 12); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(560, 287); + this.tableLayoutPanel1.TabIndex = 0; + // + // progressBar + // + this.progressBar.Dock = System.Windows.Forms.DockStyle.Fill; + this.progressBar.Location = new System.Drawing.Point(3, 3); + this.progressBar.Name = "progressBar"; + this.progressBar.Size = new System.Drawing.Size(554, 34); + this.progressBar.TabIndex = 0; + // + // output + // + this.output.BackColor = System.Drawing.Color.DimGray; + this.output.Dock = System.Windows.Forms.DockStyle.Fill; + this.output.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.output.Location = new System.Drawing.Point(3, 43); + this.output.Name = "output"; + this.output.ReadOnly = true; + this.output.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; + this.output.Size = new System.Drawing.Size(554, 201); + this.output.TabIndex = 1; + this.output.Text = ""; + this.output.TextChanged += new System.EventHandler(this.OnTextChanged); + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 5; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 15F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 35F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 15F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 15F)); + this.tableLayoutPanel2.Controls.Add(this.Verbose, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.OpenAtStartupCheckBox, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.ClearButton, 3, 0); + this.tableLayoutPanel2.Controls.Add(this.HideButton, 4, 0); + this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 250); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 1; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(554, 34); + this.tableLayoutPanel2.TabIndex = 2; + // + // Verbose + // + this.Verbose.AutoSize = true; + this.Verbose.Dock = System.Windows.Forms.DockStyle.Left; + this.Verbose.Location = new System.Drawing.Point(3, 3); + this.Verbose.Name = "Verbose"; + this.Verbose.Size = new System.Drawing.Size(65, 28); + this.Verbose.TabIndex = 1; + this.Verbose.Text = "Verbose"; + this.Verbose.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.Verbose.UseVisualStyleBackColor = true; + // + // OpenAtStartupCheckBox + // + this.OpenAtStartupCheckBox.AutoSize = true; + this.OpenAtStartupCheckBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.OpenAtStartupCheckBox.Location = new System.Drawing.Point(86, 3); + this.OpenAtStartupCheckBox.Name = "OpenAtStartupCheckBox"; + this.OpenAtStartupCheckBox.Size = new System.Drawing.Size(104, 28); + this.OpenAtStartupCheckBox.TabIndex = 2; + this.OpenAtStartupCheckBox.Text = "Open at startup"; + this.OpenAtStartupCheckBox.UseVisualStyleBackColor = true; + // + // ClearButton + // + this.ClearButton.Dock = System.Windows.Forms.DockStyle.Fill; + this.ClearButton.Location = new System.Drawing.Point(389, 3); + this.ClearButton.Name = "ClearButton"; + this.ClearButton.Size = new System.Drawing.Size(77, 28); + this.ClearButton.TabIndex = 3; + this.ClearButton.Text = "Clear"; + this.ClearButton.UseVisualStyleBackColor = true; + this.ClearButton.Click += new System.EventHandler(this.OnClearButton); + // + // HideButton + // + this.HideButton.Dock = System.Windows.Forms.DockStyle.Fill; + this.HideButton.Location = new System.Drawing.Point(472, 3); + this.HideButton.Name = "HideButton"; + this.HideButton.Size = new System.Drawing.Size(79, 28); + this.HideButton.TabIndex = 4; + this.HideButton.Text = "Hide"; + this.HideButton.UseVisualStyleBackColor = true; + this.HideButton.SizeChanged += new System.EventHandler(this.ScrollViewer_SizeChanged); + this.HideButton.Click += new System.EventHandler(this.OnHideButton); + // + // LogWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(584, 311); + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "LogWindow"; + this.ShowIcon = false; + this.Text = "Log Window"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.OnWindowClosed); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.ProgressBar progressBar; + private System.Windows.Forms.RichTextBox output; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.CheckBox Verbose; + private System.Windows.Forms.CheckBox OpenAtStartupCheckBox; + private System.Windows.Forms.Button ClearButton; + private System.Windows.Forms.Button HideButton; + } +} \ No newline at end of file diff --git a/DICUI.Forms/Windows/LogWindow.cs b/DICUI.Forms/Windows/LogWindow.cs new file mode 100644 index 00000000..d828f557 --- /dev/null +++ b/DICUI.Forms/Windows/LogWindow.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Windows.Threading; + +namespace DICUI.Forms.Windows +{ + public partial class LogWindow : Form + { + private const int GWL_STYLE = -16; + private const int WS_SYSMENU = 0x80000; + [DllImport("user32.dll", SetLastError = true)] + private static extern int GetWindowLong(IntPtr hWnd, int nIndex); + [DllImport("user32.dll")] + private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + private MainWindow _mainWindow; + + private List _matchers; + + volatile Process _process; + + public LogWindow(MainWindow mainWindow) + { + InitializeComponent(); + + this._mainWindow = mainWindow; + + _matchers = new List(); + + _matchers.Add(new Matcher( + "Descrambling data sector of img (LBA)", + @"\s*(\d+)\/\s*(\d+)$", + match => { + if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total)) + { + float percentProgress = (current / (float)total) * 100; + progressBar.Value = (int)percentProgress; + //progressBar.Text = string.Format("Descrambling image.. ({0:##.##}%)", percentProgress); + } + })); + + _matchers.Add(new Matcher( + @"Creating .scm (LBA)", + @"\s*(\d+)\/\s*(\d+)$", + match => { + if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total)) + { + float percentProgress = (current / (float)total) * 100; + progressBar.Value = (int)percentProgress; + //progressBar.Text = string.Format("Creating scrambled image.. ({0:##.##}%)", percentProgress); + } + })); + + _matchers.Add(new Matcher( + "Checking sectors (LBA)", + @"\s*(\d+)\/\s*(\d+)$", + match => { + if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total)) + { + float percentProgress = (current / (float)total) * 100; + progressBar.Value = (int)percentProgress; + //progressBar.Text = string.Format("Checking for errors.. ({0:##.##}%)", percentProgress); + } + })); + + _matchers.Add(new Matcher( + "Scanning sector (LBA)", + @"\s*(\d+)\/\s*(\d+)$", + match => { + if (UInt32.TryParse(match.Groups[1].Value, out uint current) && UInt32.TryParse(match.Groups[2].Value, out uint total)) + { + float percentProgress = (current / (float)total) * 100; + progressBar.Value = (int)percentProgress; + //progressBar.Text = string.Format("Scanning sectors for protection.. ({0:##.##}%)", percentProgress); + } + })); + } + + protected override bool ShowWithoutActivation + { + get { return true; } + } + + public void StartDump(string args) + { + AppendToTextBox(string.Format("Launching DIC with args: {0}\r\n", args), System.Drawing.Color.Orange); + + Task.Run(() => + { + _process = new Process() + { + StartInfo = new ProcessStartInfo() + { + FileName = @"Programs/DiscImageCreator.exe", + Arguments = args, + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + }, + }; + + StreamState stdoutState = new StreamState(false); + StreamState stderrState = new StreamState(true); + + //_cmd.ErrorDataReceived += (process, text) => Dispatcher.CurrentDispatcher.Invoke(() => UpdateConsole(text.Data, Brushes.Red)); + _process.Start(); + + var _1 = ConsumeOutput(_process.StandardOutput, s => Dispatcher.CurrentDispatcher.Invoke(() => UpdateConsole(s, stdoutState))); + var _2 = ConsumeOutput(_process.StandardError, s => Dispatcher.CurrentDispatcher.Invoke(() => UpdateConsole(s, stderrState))); + + _process.EnableRaisingEvents = true; + _process.Exited += OnProcessExit; + }); + } + + public void AdjustPositionToMainWindow() + { + this.Left = _mainWindow.Left; + this.Top = _mainWindow.Top + _mainWindow.Height + Constants.LogWindowMarginFromMainWindow; + this.BringToFront(); + } + + private void GracefullyTerminateProcess() + { + if (_process != null) + { + _process.Exited -= OnProcessExit; + bool isForced = !_process.HasExited; + + if (isForced) + { + AppendToTextBox("\r\nForcefully Killing the process\r\n", System.Drawing.Color.Red); + _process.Kill(); + _process.WaitForExit(); + } + + AppendToTextBox(string.Format("\r\nExit Code: {0}\r\n", _process.ExitCode), _process.ExitCode == 0 ? System.Drawing.Color.Green : System.Drawing.Color.Red); + if (_process.ExitCode == 0) + { + Dispatcher.CurrentDispatcher.Invoke(() => + { + //progressBar.Text = "Done!"; + progressBar.Value = 100; + progressBar.ForeColor = System.Drawing.Color.Green; + }); + } + else + { + Dispatcher.CurrentDispatcher.Invoke(() => + { + //progressBar.Text = isForced ? "Aborted by user" : "Error, please check log!"; + progressBar.Value = 100; + progressBar.ForeColor = System.Drawing.Color.Red; + }); + } + + _process.Close(); + } + + _process = null; + } + + private void ScrollViewer_SizeChanged(object sender, EventArgs e) + { + output.ScrollToCaret(); + } + + async Task ConsumeOutput(TextReader reader, Action callback) + { + char[] buffer = new char[256]; + int cch; + + while ((cch = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + callback(new string(buffer, 0, cch)); + } + } + + // this is used to optimize the work since we need to process A LOT of text + struct Matcher + { + private readonly String prefix; + private readonly Regex regex; + private readonly int start; + private readonly Action lambda; + + public Matcher(String prefix, String regex, Action lambda) + { + this.prefix = prefix; + this.regex = new Regex(regex); + this.start = prefix.Length; + this.lambda = lambda; + } + + public bool Matches(ref string text) => text.StartsWith(prefix); + + public void Apply(ref string text) + { + Match match = regex.Match(text, start); + lambda.Invoke(match); + } + } + + private void ProcessStringForProgressBar(string text) + { + foreach (Matcher matcher in _matchers) + { + if (matcher.Matches(ref text)) + { + matcher.Apply(ref text); + return; + } + } + } + + class StreamState + { + public enum State + { + BEGIN, + READ_CARRIAGE, + }; + + public State state; + public readonly StringBuilder buffer; + public readonly bool isError; + + public StreamState(bool isError) + { + this.state = State.BEGIN; + this.buffer = new StringBuilder(); + this.isError = isError; + } + + public bool HasData() => buffer.Length > 0; + public string Fetch() => buffer.ToString(); + public void Clear() => buffer.Clear(); + public void Append(char c) => buffer.Append(c); + + public bool Is(State state) => this.state == state; + public void Set(State state) => this.state = state; + } + + public void AppendToTextBox(string text, System.Drawing.Color color) + { + if (Dispatcher.CurrentDispatcher.CheckAccess()) + { + output.ForeColor = color; + output.AppendText(text); + } + else + Dispatcher.CurrentDispatcher.Invoke(() => + { + output.ForeColor = color; + output.AppendText(text); + }); + } + + private void UpdateConsole(string text, StreamState state) + { + /*if (c == '\r') { output.Inlines.Add(@"\r"); file.Write("\\r"); } + else if (c == '\n') { output.Inlines.Add(@"\n"); file.Write("\\n\n"); } + output.Inlines.Add(""+c); + file.Write(c); + file.Flush(); + continue;*/ + + if (text != null) + { + foreach (char c in text) + { + switch (c) + { + case '\r' when (state.Is(StreamState.State.BEGIN)): + { + state.Set(StreamState.State.READ_CARRIAGE); + break; + } + + case '\n' when (state.Is(StreamState.State.READ_CARRIAGE)): + { + if (state.buffer.Length > 0) + { + string buffer = state.Fetch(); + + AppendToTextBox(buffer, state.isError ? System.Drawing.Color.Red : System.Drawing.Color.White); + + if (!state.isError) + ProcessStringForProgressBar(buffer); + } + output.AppendText(Environment.NewLine); + state.Clear(); + state.Set(StreamState.State.BEGIN); + break; + } + + default: + if (state.Is(StreamState.State.READ_CARRIAGE) && state.HasData()) + { + if (!String.IsNullOrEmpty(output.Lines.Last())) + output.Lines[output.Lines.Length] = string.Empty; + + string buffer = state.Fetch(); + + AppendToTextBox(buffer, state.isError ? System.Drawing.Color.Red : System.Drawing.Color.White); + + if (!state.isError) + ProcessStringForProgressBar(buffer); + + state.Clear(); + } + + state.Set(StreamState.State.BEGIN); + state.Append(c); + break; + + } + } + } + } + + #region EventHandlers + + private void OnWindowClosed(object sender, FormClosedEventArgs e) + { + GracefullyTerminateProcess(); + } + + private void OnWindowLoaded(object sender, EventArgs e) + { + var hwnd = this.Handle; + SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU); + } + + void OnProcessExit(object sender, EventArgs e) + { + //Dispatcher.CurrentDispatcher.Invoke(() => AbortButton.IsEnabled = false); + GracefullyTerminateProcess(); + } + + private void OnHideButton(object sender, EventArgs e) + { + ViewModels.LoggerViewModel.WindowVisible = false; + //TODO: this should be bound directly to WindowVisible property in two way fashion + // we need to study how to properly do it in XAML + _mainWindow.showLogWindowToolStripMenuItem.Checked = false; + } + + private void OnClearButton(object sender, EventArgs e) + { + output.Clear(); + } + + private void OnAbortButton(object sender, EventArgs args) + { + GracefullyTerminateProcess(); + } + + private void OnStartButton(object sender, EventArgs args) + { + StartDump("cd e Gam.iso 16"); + } + + private void OnTextChanged(object sender, EventArgs e) + { + output.ScrollToCaret(); + } + + #endregion + } +} diff --git a/DICUI.Forms/Windows/LogWindow.resx b/DICUI.Forms/Windows/LogWindow.resx new file mode 100644 index 00000000..61bc649b --- /dev/null +++ b/DICUI.Forms/Windows/LogWindow.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + \ No newline at end of file diff --git a/DICUI.Forms/Windows/MainWindow.Designer.cs b/DICUI.Forms/Windows/MainWindow.Designer.cs new file mode 100644 index 00000000..faaf6143 --- /dev/null +++ b/DICUI.Forms/Windows/MainWindow.Designer.cs @@ -0,0 +1,530 @@ +namespace DICUI.Forms.Windows +{ + partial class MainWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow)); + this.MenuBar = new System.Windows.Forms.MenuStrip(); + this.mainWindowLayout = new System.Windows.Forms.TableLayoutPanel(); + this.settingsGroupBox = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.parametersLabel = new System.Windows.Forms.Label(); + this.driveSpeedLabel = new System.Windows.Forms.Label(); + this.driveLetterLabel = new System.Windows.Forms.Label(); + this.outputDirectoryLabel = new System.Windows.Forms.Label(); + this.outputFilenameLabel = new System.Windows.Forms.Label(); + this.systemMediaTypeLabel = new System.Windows.Forms.Label(); + this.OutputFilenameTextBox = new System.Windows.Forms.TextBox(); + this.SystemTypeComboBox = new System.Windows.Forms.ComboBox(); + this.MediaTypeComboBox = new System.Windows.Forms.ComboBox(); + this.OutputDirectoryTextBox = new System.Windows.Forms.TextBox(); + this.OutputDirectoryBrowseButton = new System.Windows.Forms.Button(); + this.DriveLetterComboBox = new System.Windows.Forms.ComboBox(); + this.DriveSpeedComboBox = new System.Windows.Forms.ComboBox(); + this.ParametersTextBox = new System.Windows.Forms.TextBox(); + this.EnableParametersCheckBox = new System.Windows.Forms.CheckBox(); + this.controlsGroupBox = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.StartStopButton = new System.Windows.Forms.Button(); + this.DiscScanButton = new System.Windows.Forms.Button(); + this.CopyProtectScanButton = new System.Windows.Forms.Button(); + this.EjectWhenDoneCheckBox = new System.Windows.Forms.CheckBox(); + this.statusGroupBox = new System.Windows.Forms.GroupBox(); + this.StatusLabel = new System.Windows.Forms.TextBox(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.showLogWindowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.MenuBar.SuspendLayout(); + this.mainWindowLayout.SuspendLayout(); + this.settingsGroupBox.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.controlsGroupBox.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.statusGroupBox.SuspendLayout(); + this.SuspendLayout(); + // + // MenuBar + // + this.MenuBar.Location = new System.Drawing.Point(0, 0); + this.MenuBar.Name = "MenuBar"; + this.MenuBar.Size = new System.Drawing.Size(584, 24); + this.MenuBar.TabIndex = 0; + this.MenuBar.Text = "menuStrip1"; + this.MenuBar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + fileToolStripMenuItem, toolsToolStripMenuItem, helpToolStripMenuItem}); + // + // mainWindowLayout + // + this.mainWindowLayout.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.mainWindowLayout.ColumnCount = 1; + this.mainWindowLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.mainWindowLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.mainWindowLayout.Controls.Add(this.settingsGroupBox, 0, 0); + this.mainWindowLayout.Controls.Add(this.controlsGroupBox, 0, 1); + this.mainWindowLayout.Controls.Add(this.statusGroupBox, 0, 2); + this.mainWindowLayout.Location = new System.Drawing.Point(13, 28); + this.mainWindowLayout.Name = "mainWindowLayout"; + this.mainWindowLayout.RowCount = 3; + this.mainWindowLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 82.66254F)); + this.mainWindowLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 17.33746F)); + this.mainWindowLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.mainWindowLayout.Size = new System.Drawing.Size(559, 371); + this.mainWindowLayout.TabIndex = 1; + // + // settingsGroupBox + // + this.settingsGroupBox.Controls.Add(this.tableLayoutPanel2); + this.settingsGroupBox.Location = new System.Drawing.Point(3, 3); + this.settingsGroupBox.Name = "settingsGroupBox"; + this.settingsGroupBox.Size = new System.Drawing.Size(553, 259); + this.settingsGroupBox.TabIndex = 0; + this.settingsGroupBox.TabStop = false; + this.settingsGroupBox.Text = "Settings"; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 3; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 26.32794F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 73.67206F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 144F)); + this.tableLayoutPanel2.Controls.Add(this.parametersLabel, 0, 5); + this.tableLayoutPanel2.Controls.Add(this.driveSpeedLabel, 0, 4); + this.tableLayoutPanel2.Controls.Add(this.driveLetterLabel, 0, 3); + this.tableLayoutPanel2.Controls.Add(this.outputDirectoryLabel, 0, 2); + this.tableLayoutPanel2.Controls.Add(this.outputFilenameLabel, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.systemMediaTypeLabel, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.OutputFilenameTextBox, 1, 1); + this.tableLayoutPanel2.Controls.Add(this.SystemTypeComboBox, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.MediaTypeComboBox, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.OutputDirectoryTextBox, 1, 2); + this.tableLayoutPanel2.Controls.Add(this.OutputDirectoryBrowseButton, 2, 2); + this.tableLayoutPanel2.Controls.Add(this.DriveLetterComboBox, 1, 3); + this.tableLayoutPanel2.Controls.Add(this.DriveSpeedComboBox, 1, 4); + this.tableLayoutPanel2.Controls.Add(this.ParametersTextBox, 1, 5); + this.tableLayoutPanel2.Controls.Add(this.EnableParametersCheckBox, 2, 5); + this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 19); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.Padding = new System.Windows.Forms.Padding(0, 5, 0, 5); + this.tableLayoutPanel2.RowCount = 6; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(553, 234); + this.tableLayoutPanel2.TabIndex = 0; + // + // parametersLabel + // + this.parametersLabel.AutoSize = true; + this.parametersLabel.Dock = System.Windows.Forms.DockStyle.Fill; + this.parametersLabel.Location = new System.Drawing.Point(3, 190); + this.parametersLabel.Name = "parametersLabel"; + this.parametersLabel.Size = new System.Drawing.Size(101, 39); + this.parametersLabel.TabIndex = 10; + this.parametersLabel.Text = "Parameters"; + this.parametersLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // driveSpeedLabel + // + this.driveSpeedLabel.AutoSize = true; + this.driveSpeedLabel.Dock = System.Windows.Forms.DockStyle.Fill; + this.driveSpeedLabel.Location = new System.Drawing.Point(3, 153); + this.driveSpeedLabel.Name = "driveSpeedLabel"; + this.driveSpeedLabel.Size = new System.Drawing.Size(101, 37); + this.driveSpeedLabel.TabIndex = 8; + this.driveSpeedLabel.Text = "Drive Speed"; + this.driveSpeedLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // driveLetterLabel + // + this.driveLetterLabel.AutoSize = true; + this.driveLetterLabel.Dock = System.Windows.Forms.DockStyle.Fill; + this.driveLetterLabel.Location = new System.Drawing.Point(3, 116); + this.driveLetterLabel.Name = "driveLetterLabel"; + this.driveLetterLabel.Size = new System.Drawing.Size(101, 37); + this.driveLetterLabel.TabIndex = 6; + this.driveLetterLabel.Text = "Drive Letter"; + this.driveLetterLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // outputDirectoryLabel + // + this.outputDirectoryLabel.AutoSize = true; + this.outputDirectoryLabel.Dock = System.Windows.Forms.DockStyle.Fill; + this.outputDirectoryLabel.Location = new System.Drawing.Point(3, 79); + this.outputDirectoryLabel.Name = "outputDirectoryLabel"; + this.outputDirectoryLabel.Size = new System.Drawing.Size(101, 37); + this.outputDirectoryLabel.TabIndex = 4; + this.outputDirectoryLabel.Text = "Output Directory"; + this.outputDirectoryLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // outputFilenameLabel + // + this.outputFilenameLabel.AutoSize = true; + this.outputFilenameLabel.Dock = System.Windows.Forms.DockStyle.Fill; + this.outputFilenameLabel.Location = new System.Drawing.Point(3, 42); + this.outputFilenameLabel.Name = "outputFilenameLabel"; + this.outputFilenameLabel.Size = new System.Drawing.Size(101, 37); + this.outputFilenameLabel.TabIndex = 2; + this.outputFilenameLabel.Text = "Output Filename"; + this.outputFilenameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // systemMediaTypeLabel + // + this.systemMediaTypeLabel.AutoSize = true; + this.systemMediaTypeLabel.Dock = System.Windows.Forms.DockStyle.Fill; + this.systemMediaTypeLabel.Location = new System.Drawing.Point(3, 5); + this.systemMediaTypeLabel.Name = "systemMediaTypeLabel"; + this.systemMediaTypeLabel.Size = new System.Drawing.Size(101, 37); + this.systemMediaTypeLabel.TabIndex = 0; + this.systemMediaTypeLabel.Text = "System/Media Type"; + this.systemMediaTypeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // OutputFilenameTextBox + // + this.OutputFilenameTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.tableLayoutPanel2.SetColumnSpan(this.OutputFilenameTextBox, 2); + this.OutputFilenameTextBox.Location = new System.Drawing.Point(111, 50); + this.OutputFilenameTextBox.Name = "OutputFilenameTextBox"; + this.OutputFilenameTextBox.Size = new System.Drawing.Size(438, 20); + this.OutputFilenameTextBox.TabIndex = 11; + this.OutputFilenameTextBox.TextChanged += new System.EventHandler(this.OutputFilenameTextBoxTextChanged); + // + // SystemTypeComboBox + // + this.SystemTypeComboBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.SystemTypeComboBox.DisplayMember = "Name"; + this.SystemTypeComboBox.DropDownWidth = 250; + this.SystemTypeComboBox.FormattingEnabled = true; + this.SystemTypeComboBox.Location = new System.Drawing.Point(110, 13); + this.SystemTypeComboBox.Name = "SystemTypeComboBox"; + this.SystemTypeComboBox.Size = new System.Drawing.Size(295, 21); + this.SystemTypeComboBox.TabIndex = 13; + this.SystemTypeComboBox.SelectedIndexChanged += new System.EventHandler(this.SystemTypeComboBoxSelectionChanged); + // + // MediaTypeComboBox + // + this.MediaTypeComboBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.MediaTypeComboBox.DisplayMember = "Name"; + this.MediaTypeComboBox.FormattingEnabled = true; + this.MediaTypeComboBox.Location = new System.Drawing.Point(415, 13); + this.MediaTypeComboBox.Name = "MediaTypeComboBox"; + this.MediaTypeComboBox.Size = new System.Drawing.Size(131, 21); + this.MediaTypeComboBox.TabIndex = 14; + this.MediaTypeComboBox.SelectedIndexChanged += new System.EventHandler(this.MediaTypeComboBoxSelectionChanged); + // + // OutputDirectoryTextBox + // + this.OutputDirectoryTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.OutputDirectoryTextBox.Location = new System.Drawing.Point(110, 87); + this.OutputDirectoryTextBox.Name = "OutputDirectoryTextBox"; + this.OutputDirectoryTextBox.Size = new System.Drawing.Size(295, 20); + this.OutputDirectoryTextBox.TabIndex = 15; + this.OutputDirectoryTextBox.TextChanged += new System.EventHandler(this.OutputDirectoryTextBoxTextChanged); + // + // OutputDirectoryBrowseButton + // + this.OutputDirectoryBrowseButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.OutputDirectoryBrowseButton.Location = new System.Drawing.Point(411, 84); + this.OutputDirectoryBrowseButton.Name = "OutputDirectoryBrowseButton"; + this.OutputDirectoryBrowseButton.Size = new System.Drawing.Size(139, 26); + this.OutputDirectoryBrowseButton.TabIndex = 16; + this.OutputDirectoryBrowseButton.Text = "Browse"; + this.OutputDirectoryBrowseButton.UseVisualStyleBackColor = true; + this.OutputDirectoryBrowseButton.Click += new System.EventHandler(this.OutputDirectoryBrowseButtonClick); + // + // DriveLetterComboBox + // + this.DriveLetterComboBox.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.DriveLetterComboBox.DisplayMember = "Letter"; + this.DriveLetterComboBox.FormattingEnabled = true; + this.DriveLetterComboBox.Location = new System.Drawing.Point(110, 124); + this.DriveLetterComboBox.Name = "DriveLetterComboBox"; + this.DriveLetterComboBox.Size = new System.Drawing.Size(121, 21); + this.DriveLetterComboBox.TabIndex = 17; + this.DriveLetterComboBox.SelectedIndexChanged += new System.EventHandler(this.DriveLetterComboBoxSelectionChanged); + // + // DriveSpeedComboBox + // + this.DriveSpeedComboBox.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.DriveSpeedComboBox.FormattingEnabled = true; + this.DriveSpeedComboBox.Location = new System.Drawing.Point(110, 161); + this.DriveSpeedComboBox.Name = "DriveSpeedComboBox"; + this.DriveSpeedComboBox.Size = new System.Drawing.Size(121, 21); + this.DriveSpeedComboBox.TabIndex = 18; + this.DriveSpeedComboBox.SelectedIndexChanged += new System.EventHandler(this.DriveSpeedComboBoxSelectionChanged); + // + // ParametersTextBox + // + this.ParametersTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.ParametersTextBox.Enabled = false; + this.ParametersTextBox.Location = new System.Drawing.Point(110, 199); + this.ParametersTextBox.Name = "ParametersTextBox"; + this.ParametersTextBox.ReadOnly = true; + this.ParametersTextBox.Size = new System.Drawing.Size(295, 20); + this.ParametersTextBox.TabIndex = 19; + // + // EnableParametersCheckBox + // + this.EnableParametersCheckBox.AutoSize = true; + this.EnableParametersCheckBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.EnableParametersCheckBox.Location = new System.Drawing.Point(411, 193); + this.EnableParametersCheckBox.Name = "EnableParametersCheckBox"; + this.EnableParametersCheckBox.Size = new System.Drawing.Size(139, 33); + this.EnableParametersCheckBox.TabIndex = 20; + this.EnableParametersCheckBox.Text = "Enable Editing"; + this.EnableParametersCheckBox.UseVisualStyleBackColor = true; + this.EnableParametersCheckBox.CheckedChanged += new System.EventHandler(this.EnableParametersCheckBoxClick); + // + // controlsGroupBox + // + this.controlsGroupBox.Controls.Add(this.tableLayoutPanel3); + this.controlsGroupBox.Location = new System.Drawing.Point(3, 270); + this.controlsGroupBox.Name = "controlsGroupBox"; + this.controlsGroupBox.Size = new System.Drawing.Size(553, 50); + this.controlsGroupBox.TabIndex = 1; + this.controlsGroupBox.TabStop = false; + this.controlsGroupBox.Text = "Controls"; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.ColumnCount = 4; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel3.Controls.Add(this.StartStopButton, 0, 0); + this.tableLayoutPanel3.Controls.Add(this.DiscScanButton, 1, 0); + this.tableLayoutPanel3.Controls.Add(this.CopyProtectScanButton, 2, 0); + this.tableLayoutPanel3.Controls.Add(this.EjectWhenDoneCheckBox, 3, 0); + this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 20); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 1; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(553, 32); + this.tableLayoutPanel3.TabIndex = 0; + // + // StartStopButton + // + this.StartStopButton.Dock = System.Windows.Forms.DockStyle.Fill; + this.StartStopButton.Enabled = false; + this.StartStopButton.Location = new System.Drawing.Point(3, 3); + this.StartStopButton.Name = "StartStopButton"; + this.StartStopButton.Size = new System.Drawing.Size(132, 26); + this.StartStopButton.TabIndex = 0; + this.StartStopButton.Text = "Start Dumping"; + this.StartStopButton.UseVisualStyleBackColor = true; + this.StartStopButton.Click += new System.EventHandler(this.StartStopButtonClick); + // + // DiscScanButton + // + this.DiscScanButton.Dock = System.Windows.Forms.DockStyle.Fill; + this.DiscScanButton.Location = new System.Drawing.Point(141, 3); + this.DiscScanButton.Name = "DiscScanButton"; + this.DiscScanButton.Size = new System.Drawing.Size(132, 26); + this.DiscScanButton.TabIndex = 1; + this.DiscScanButton.Text = "Scan For Discs"; + this.DiscScanButton.UseVisualStyleBackColor = true; + this.DiscScanButton.Click += new System.EventHandler(this.DiscScanButtonClick); + // + // CopyProtectScanButton + // + this.CopyProtectScanButton.Dock = System.Windows.Forms.DockStyle.Fill; + this.CopyProtectScanButton.Location = new System.Drawing.Point(279, 3); + this.CopyProtectScanButton.Name = "CopyProtectScanButton"; + this.CopyProtectScanButton.Size = new System.Drawing.Size(132, 26); + this.CopyProtectScanButton.TabIndex = 2; + this.CopyProtectScanButton.Text = "Scan For Protection"; + this.CopyProtectScanButton.UseVisualStyleBackColor = true; + this.CopyProtectScanButton.Click += new System.EventHandler(this.CopyProtectScanButtonClick); + // + // EjectWhenDoneCheckBox + // + this.EjectWhenDoneCheckBox.AutoSize = true; + this.EjectWhenDoneCheckBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.EjectWhenDoneCheckBox.Location = new System.Drawing.Point(417, 3); + this.EjectWhenDoneCheckBox.Name = "EjectWhenDoneCheckBox"; + this.EjectWhenDoneCheckBox.Size = new System.Drawing.Size(133, 26); + this.EjectWhenDoneCheckBox.TabIndex = 3; + this.EjectWhenDoneCheckBox.Text = "Eject When Done"; + this.EjectWhenDoneCheckBox.UseVisualStyleBackColor = true; + // + // statusGroupBox + // + this.statusGroupBox.Controls.Add(this.StatusLabel); + this.statusGroupBox.Location = new System.Drawing.Point(3, 326); + this.statusGroupBox.Name = "statusGroupBox"; + this.statusGroupBox.Size = new System.Drawing.Size(553, 42); + this.statusGroupBox.TabIndex = 2; + this.statusGroupBox.TabStop = false; + this.statusGroupBox.Text = "Status"; + // + // StatusLabel + // + this.StatusLabel.Dock = System.Windows.Forms.DockStyle.Fill; + this.StatusLabel.Enabled = false; + this.StatusLabel.Location = new System.Drawing.Point(3, 16); + this.StatusLabel.Name = "StatusLabel"; + this.StatusLabel.ReadOnly = true; + this.StatusLabel.Size = new System.Drawing.Size(547, 20); + this.StatusLabel.TabIndex = 0; + this.StatusLabel.Text = "Waiting for media..."; + this.StatusLabel.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F))); + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "File"; + // + // toolsToolStripMenuItem + // + this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem"; + this.toolsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.T))); + this.toolsToolStripMenuItem.Size = new System.Drawing.Size(47, 20); + this.toolsToolStripMenuItem.Text = "Tools"; + // + // helpToolStripMenuItem + // + this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; + this.helpToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.H))); + this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); + this.helpToolStripMenuItem.Text = "Help"; + // + // exitToolStripMenuItem + // + this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; + this.exitToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.X))); + this.exitToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.exitToolStripMenuItem.Text = "Exit"; + this.exitToolStripMenuItem.Click += new System.EventHandler(this.AppExitClick); + // + // optionsToolStripMenuItem + // + this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; + this.optionsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.O))); + this.optionsToolStripMenuItem.Size = new System.Drawing.Size(209, 22); + this.optionsToolStripMenuItem.Text = "Options"; + this.optionsToolStripMenuItem.Click += new System.EventHandler(this.OptionsClick); + // + // showLogWindowToolStripMenuItem + // + this.showLogWindowToolStripMenuItem.Checked = true; + this.showLogWindowToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.showLogWindowToolStripMenuItem.Name = "showLogWindowToolStripMenuItem"; + this.showLogWindowToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.L))); + this.showLogWindowToolStripMenuItem.Size = new System.Drawing.Size(209, 22); + this.showLogWindowToolStripMenuItem.Text = "Show Log Window"; + // + // aboutToolStripMenuItem + // + this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; + this.aboutToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.A))); + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.aboutToolStripMenuItem.Text = "About"; + this.aboutToolStripMenuItem.Click += new System.EventHandler(this.AboutClick); + // + // MainWindow + // + this.AcceptButton = this.StartStopButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(584, 411); + this.Controls.Add(this.mainWindowLayout); + this.Controls.Add(this.MenuBar); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.MenuBar; + this.Name = "MainWindow"; + this.Text = "DiscImageCreator GUI"; + this.Activated += new System.EventHandler(this.MainWindowActivated); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainWindowClosing); + this.Load += new System.EventHandler(this.OnContentRendered); + this.LocationChanged += new System.EventHandler(this.MainWindowLocationChanged); + this.MenuBar.ResumeLayout(false); + this.MenuBar.PerformLayout(); + this.mainWindowLayout.ResumeLayout(false); + this.settingsGroupBox.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.controlsGroupBox.ResumeLayout(false); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); + this.statusGroupBox.ResumeLayout(false); + this.statusGroupBox.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MenuStrip MenuBar; + private System.Windows.Forms.TableLayoutPanel mainWindowLayout; + private System.Windows.Forms.GroupBox settingsGroupBox; + private System.Windows.Forms.GroupBox controlsGroupBox; + private System.Windows.Forms.GroupBox statusGroupBox; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.Label systemMediaTypeLabel; + private System.Windows.Forms.Label parametersLabel; + private System.Windows.Forms.Label driveSpeedLabel; + private System.Windows.Forms.Label driveLetterLabel; + private System.Windows.Forms.Label outputDirectoryLabel; + private System.Windows.Forms.Label outputFilenameLabel; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.Button StartStopButton; + private System.Windows.Forms.Button DiscScanButton; + private System.Windows.Forms.Button CopyProtectScanButton; + private System.Windows.Forms.CheckBox EjectWhenDoneCheckBox; + private System.Windows.Forms.TextBox OutputFilenameTextBox; + private System.Windows.Forms.ComboBox SystemTypeComboBox; + private System.Windows.Forms.ComboBox MediaTypeComboBox; + private System.Windows.Forms.TextBox OutputDirectoryTextBox; + private System.Windows.Forms.Button OutputDirectoryBrowseButton; + private System.Windows.Forms.ComboBox DriveLetterComboBox; + private System.Windows.Forms.ComboBox DriveSpeedComboBox; + private System.Windows.Forms.TextBox ParametersTextBox; + private System.Windows.Forms.CheckBox EnableParametersCheckBox; + private System.Windows.Forms.TextBox StatusLabel; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem toolsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem; + internal System.Windows.Forms.ToolStripMenuItem showLogWindowToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; + } +} + diff --git a/DICUI.Forms/Windows/MainWindow.cs b/DICUI.Forms/Windows/MainWindow.cs new file mode 100644 index 00000000..6db59218 --- /dev/null +++ b/DICUI.Forms/Windows/MainWindow.cs @@ -0,0 +1,723 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Forms; +using DICUI.Data; +using DICUI.Utilities; + +namespace DICUI.Forms.Windows +{ + public partial class MainWindow : Form + { + // Private UI-related variables + private List _drives; + private MediaType? _currentMediaType; + private List _systems; + private List _mediaTypes; + private bool _alreadyShown; + + private DumpEnvironment _env; + + // Option related + private Options _options; + private OptionsWindow _optionsWindow; + + private LogWindow _logWindow; + + public MainWindow() + { + InitializeComponent(); + + // Initializes and load Options object + _options = new Options(); + _options.Load(); + ViewModels.OptionsViewModel = new OptionsViewModel(_options); + + _logWindow = new LogWindow(this); + ViewModels.LoggerViewModel.SetWindow(_logWindow); + + // Disable buttons until we load fully + StartStopButton.Enabled = false; + DiscScanButton.Enabled = false; + CopyProtectScanButton.Enabled = false; + + if (_options.OpenLogWindowAtStartup) + { + this.StartPosition = FormStartPosition.CenterScreen; + double combinedHeight = this.Height + _logWindow.Height + Constants.LogWindowMarginFromMainWindow; + Rectangle bounds = GetScaledCoordinates(Screen.PrimaryScreen.WorkingArea); + + this.Left = (int)(bounds.Left + (bounds.Width - this.Width) / 2); + this.Top = (int)(bounds.Top + (bounds.Height - combinedHeight) / 2); + } + } + + #region Events + + private void OnContentRendered(object sender, EventArgs e) + { + if (_alreadyShown) + return; + + _alreadyShown = true; + + if (_options.OpenLogWindowAtStartup) + { + //TODO: this should be bound directly to WindowVisible property in two way fashion + // we need to study how to properly do it in XAML + showLogWindowToolStripMenuItem.Checked = true; + ViewModels.LoggerViewModel.WindowVisible = true; + } + + // Populate the list of systems + StatusLabel.Text = "Creating system list, please wait!"; + PopulateSystems(); + + // Populate the list of drives + StatusLabel.Text = "Creating drive list, please wait!"; + PopulateDrives(); + + // Set the position of the log window + if (_logWindow.Visible) + { + _logWindow.AdjustPositionToMainWindow(); + this.Focus(); + } + } + + private void StartStopButtonClick(object sender, EventArgs e) + { + // Dump or stop the dump + if (StartStopButton.Text == Constants.StartDumping) + { + StartDumping(); + } + else if (StartStopButton.Text == Constants.StopDumping) + { + ViewModels.LoggerViewModel.VerboseLogLn("Canceling dumping process..."); + _env.CancelDumping(); + CopyProtectScanButton.Enabled = true; + + if (EjectWhenDoneCheckBox.Checked == true) + { + ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {_env.Drive.Letter}"); + _env.EjectDisc(); + } + } + } + + private void OutputDirectoryBrowseButtonClick(object sender, EventArgs e) + { + BrowseFolder(); + EnsureDiscInformation(); + } + + private void DiscScanButtonClick(object sender, EventArgs e) + { + PopulateDrives(); + } + + private void CopyProtectScanButtonClick(object sender, EventArgs e) + { + ScanAndShowProtection(); + } + + private void SystemTypeComboBoxSelectionChanged(object sender, EventArgs e) + { + // If we're on a separator, go to the next item and return + if ((SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).IsHeader()) + { + SystemTypeComboBox.SelectedIndex++; + return; + } + + ViewModels.LoggerViewModel.VerboseLogLn("Changed system to: {0}", (SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem).Name); + PopulateMediaType(); + EnsureDiscInformation(); + } + + private void MediaTypeComboBoxSelectionChanged(object sender, EventArgs e) + { + _currentMediaType = MediaTypeComboBox.SelectedItem as MediaType?; + SetSupportedDriveSpeed(); + GetOutputNames(); + EnsureDiscInformation(); + } + + private void DriveLetterComboBoxSelectionChanged(object sender, EventArgs e) + { + CacheCurrentDiscType(); + SetCurrentDiscType(); + GetOutputNames(); + SetSupportedDriveSpeed(); + } + + private void DriveSpeedComboBoxSelectionChanged(object sender, EventArgs e) + { + EnsureDiscInformation(); + } + + private void OutputFilenameTextBoxTextChanged(object sender, EventArgs e) + { + EnsureDiscInformation(); + } + + private void OutputDirectoryTextBoxTextChanged(object sender, EventArgs e) + { + EnsureDiscInformation(); + } + + private void ProgressUpdated(object sender, Result value) + { + StatusLabel.Text = value.Message; + ViewModels.LoggerViewModel.VerboseLogLn(value.Message); + } + + private void MainWindowLocationChanged(object sender, EventArgs e) + { + if (_logWindow.Visible) + _logWindow.AdjustPositionToMainWindow(); + } + + private void MainWindowActivated(object sender, EventArgs e) + { + if (!_logWindow.Visible) + _logWindow.BringToFront(); + this.BringToFront(); + } + + private void MainWindowClosing(object sender, FormClosingEventArgs e) + { + if (_logWindow.Visible) + _logWindow.Close(); + } + + private void EnableParametersCheckBoxClick(object sender, EventArgs e) + { + if (EnableParametersCheckBox.Checked) + { + ParametersTextBox.ReadOnly = false; + ParametersTextBox.Enabled = true; + } + else + { + ParametersTextBox.ReadOnly = true; + ParametersTextBox.Enabled = false; + ProcessCustomParameters(); + } + } + + // Toolbar Events + + private void AppExitClick(object sender, EventArgs e) + { + System.Windows.Application.Current.Shutdown(); + } + + private void AboutClick(object sender, EventArgs e) + { + System.Windows.MessageBox.Show($"ReignStumble - Project Lead / UI Design{Environment.NewLine}" + + $"darksabre76 - Project Co-Lead / Backend Design{Environment.NewLine}" + + $"Jakz - Feature Contributor{Environment.NewLine}" + + $"NHellFire - Feature Contributor{Environment.NewLine}" + + $"Dizzzy - Concept/Ideas/Beta tester{Environment.NewLine}", "About", MessageBoxButton.OK, MessageBoxImage.Information); + } + + private void OptionsClick(object sender, EventArgs e) + { + // lazy initialization + if (_optionsWindow == null) + { + _optionsWindow = new OptionsWindow(this, _options); + _optionsWindow.Closed += delegate + { + _optionsWindow = null; + }; + } + + _optionsWindow.Owner = this; + _optionsWindow.StartPosition = FormStartPosition.CenterParent; + _optionsWindow.RefreshSettings(); + _optionsWindow.Show(); + } + + public void OnOptionsUpdated() + { + GetOutputNames(); + SetSupportedDriveSpeed(); + EnsureDiscInformation(); + } + + #endregion + + #region Helpers + + /// + /// Populate media type according to system type + /// + private void PopulateMediaType() + { + KnownSystem? currentSystem = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem; + + if (currentSystem != null) + { + _mediaTypes = Validators.GetValidMediaTypes(currentSystem).ToList(); + MediaTypeComboBox.DataSource = _mediaTypes; + + MediaTypeComboBox.Enabled = _mediaTypes.Count > 1; + MediaTypeComboBox.SelectedIndex = (_mediaTypes.IndexOf(_currentMediaType) >= 0 ? _mediaTypes.IndexOf(_currentMediaType) : 0); + } + else + { + MediaTypeComboBox.Enabled = false; + MediaTypeComboBox.DataSource = null; + MediaTypeComboBox.SelectedIndex = -1; + } + } + + /// + /// Get a complete list of supported systems and fill the combo box + /// + private void PopulateSystems() + { + _systems = Validators.CreateListOfSystems(); + + ViewModels.LoggerViewModel.VerboseLogLn("Populating systems, {0} systems found.", _systems.Count); + + Dictionary> mapping = _systems + .GroupBy(s => s.Category()) + .ToDictionary( + k => k.Key, + v => v + .OrderBy(s => s.Name()) + .ToList() + ); + + List comboBoxItems = new List(); + + comboBoxItems.Add(new KnownSystemComboBoxItem(KnownSystem.NONE)); + + foreach (var group in mapping) + { + comboBoxItems.Add(new KnownSystemComboBoxItem(group.Key)); + group.Value.ForEach(system => comboBoxItems.Add(new KnownSystemComboBoxItem(system))); + } + + SystemTypeComboBox.DataSource = comboBoxItems; + SystemTypeComboBox.SelectedIndex = 0; + + StartStopButton.Enabled = false; + } + + /// + /// Get a complete list of active disc drives and fill the combo box + /// + /// TODO: Find a way for this to periodically run, or have it hook to a "drive change" event + private void PopulateDrives() + { + ViewModels.LoggerViewModel.VerboseLogLn("Scanning for drives.."); + + // Always enable the disk scan + DiscScanButton.Enabled = true; + + // Populate the list of drives and add it to the combo box + _drives = Validators.CreateListOfDrives(); + DriveLetterComboBox.DataSource = _drives; + + if (DriveLetterComboBox.Items.Count > 0) + { + int index = _drives.FindIndex(d => d.MarkedActive); + DriveLetterComboBox.SelectedIndex = (index != -1 ? index : 0); + StatusLabel.Text = "Valid drive found! Choose your Media Type"; + StartStopButton.Enabled = true; + CopyProtectScanButton.Enabled = true; + + ViewModels.LoggerViewModel.VerboseLogLn("Found {0} drives: {1}", _drives.Count, String.Join(", ", _drives.Select(d => d.Letter))); + } + else + { + DriveLetterComboBox.SelectedIndex = -1; + StatusLabel.Text = "No valid drive found!"; + StartStopButton.Enabled = false; + CopyProtectScanButton.Enabled = false; + + ViewModels.LoggerViewModel.VerboseLogLn("Found no drives"); + } + } + + /// + /// Browse for an output folder + /// + private void BrowseFolder() + { + FolderBrowserDialog folderDialog = new FolderBrowserDialog { ShowNewFolderButton = false, SelectedPath = System.AppDomain.CurrentDomain.BaseDirectory }; + DialogResult result = folderDialog.ShowDialog(); + + if (result == DialogResult.OK) + { + OutputDirectoryTextBox.Text = folderDialog.SelectedPath; + } + } + + /// + /// Create a DumpEnvironment with all current settings + /// + /// Filled DumpEnvironment instance + private DumpEnvironment DetermineEnvironment() + { + // Populate the new environment + var env = new DumpEnvironment() + { + // Paths to tools + SubdumpPath = _options.SubDumpPath, + DICPath = _options.DICPath, + + OutputDirectory = OutputDirectoryTextBox.Text, + OutputFilename = OutputFilenameTextBox.Text, + + // Get the currently selected options + Drive = DriveLetterComboBox.SelectedItem as Drive, + + DICParameters = new Parameters(ParametersTextBox.Text), + + QuietMode = _options.QuietMode, + ParanoidMode = _options.ParanoidMode, + ScanForProtection = _options.ScanForProtection, + RereadAmountC2 = _options.RereadAmountForC2, + + System = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem, + Type = MediaTypeComboBox.SelectedItem as MediaType? + }; + + // Fix the output paths + env.FixOutputPaths(); + + // Disable automatic reprocessing of the textboxes until we're done + OutputDirectoryTextBox.TextChanged -= OutputDirectoryTextBoxTextChanged; + OutputFilenameTextBox.TextChanged -= OutputFilenameTextBoxTextChanged; + + OutputDirectoryTextBox.Text = env.OutputDirectory; + OutputFilenameTextBox.Text = env.OutputFilename; + + OutputDirectoryTextBox.TextChanged += OutputDirectoryTextBoxTextChanged; + OutputFilenameTextBox.TextChanged += OutputFilenameTextBoxTextChanged; + + return env; + } + + /// + /// Begin the dumping process using the given inputs + /// + private async void StartDumping() + { + if (_env == null) + _env = DetermineEnvironment(); + + // If still in custom parameter mode, check that users meant to continue or not + if (EnableParametersCheckBox.Checked == true) + { + MessageBoxResult result = System.Windows.MessageBox.Show("It looks like you have custom parameters that have not been saved. Would you like to apply those changes before starting to dump?", "Custom Changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Question); + if (result == MessageBoxResult.Yes) + { + EnableParametersCheckBox.Checked = false; + ParametersTextBox.Enabled = false; + ProcessCustomParameters(); + } + else if (result == MessageBoxResult.Cancel) + return; + // If "No", then we continue with the current known environment + } + + try + { + // Check for the firmware first + // TODO: Remove this (and method) once DIC end-to-end logging becomes a thing + if (!await _env.DriveHasLatestFimrware()) + { + System.Windows.MessageBox.Show($"DiscImageCreator has reported that drive {_env.Drive.Letter} is not updated to the most recent firmware. Please update the firmware for your drive and try again.", "Outdated Firmware", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + // Validate that the user explicitly wants an inactive drive to be considered for dumping + if (!_env.Drive.MarkedActive) + { + MessageBoxResult mbresult = System.Windows.MessageBox.Show("The currently selected drive does not appear to contain a disc! Are you sure you want to continue?", "Missing Disc", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); + if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None) + { + ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!"); + return; + } + } + + // If a complete dump already exists + if (_env.FoundAllFiles()) + { + MessageBoxResult mbresult = System.Windows.MessageBox.Show("A complete dump already exists! Are you sure you want to overwrite?", "Overwrite?", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); + if (mbresult == MessageBoxResult.No || mbresult == MessageBoxResult.Cancel || mbresult == MessageBoxResult.None) + { + ViewModels.LoggerViewModel.VerboseLogLn("Dumping aborted!"); + return; + } + } + + StartStopButton.Text = Constants.StopDumping; + CopyProtectScanButton.Enabled = false; + StatusLabel.Text = "Beginning dumping process"; + ViewModels.LoggerViewModel.VerboseLogLn("Starting dumping process.."); + + var progress = new Progress(); + progress.ProgressChanged += ProgressUpdated; + Result result = await _env.StartDumping(progress); + + StatusLabel.Text = result ? "Dumping complete!" : result.Message; + ViewModels.LoggerViewModel.VerboseLogLn(result ? "Dumping complete!" : result.Message); + } + catch + { + // No-op, we don't care what it was + } + finally + { + StartStopButton.Text = Constants.StartDumping; + CopyProtectScanButton.Enabled = true; + } + + if (EjectWhenDoneCheckBox.Checked == true) + { + ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {_env.Drive.Letter}"); + _env.EjectDisc(); + } + } + + /// + /// Ensure information is consistent with the currently selected disc type + /// + private void EnsureDiscInformation() + { + // Get the current environment information + _env = DetermineEnvironment(); + + // Take care of null cases + if (_env.System == null) + _env.System = KnownSystem.NONE; + if (_env.Type == null) + _env.Type = MediaType.NONE; + + // Get the status to write out + Result result = Validators.GetSupportStatus(_env.System, _env.Type); + StatusLabel.Text = result.Message; + + // Set the index for the current disc type + SetCurrentDiscType(); + + StartStopButton.Enabled = result && (_drives != null && _drives.Count > 0 ? true : false); + + // If we're in a type that doesn't support drive speeds + DriveSpeedComboBox.Enabled = _env.Type.DoesSupportDriveSpeed(); + + // If input params are not enabled, generate the full parameters from the environment + if (!ParametersTextBox.Enabled) + { + string generated = _env.GetFullParameters((int?)DriveSpeedComboBox.SelectedItem); + if (generated != null) + ParametersTextBox.Text = generated; + } + } + + /// + /// Get the default output directory name from the currently selected drive + /// + private void GetOutputNames() + { + Drive drive = DriveLetterComboBox.SelectedItem as Drive; + KnownSystem? systemType = SystemTypeComboBox.SelectedItem as KnownSystemComboBoxItem; + MediaType? mediaType = MediaTypeComboBox.SelectedItem as MediaType?; + + OutputDirectoryTextBox.Text = Path.Combine(_options.DefaultOutputPath, drive?.VolumeLabel ?? string.Empty); + OutputFilenameTextBox.Text = (drive?.VolumeLabel ?? "disc") + (mediaType.Extension() ?? ".bin"); + } + + /// + /// Scan and show copy protection for the current disc + /// + private async void ScanAndShowProtection() + { + if (_env == null) + _env = DetermineEnvironment(); + + if (_env.Drive.Letter != default(char)) + { + ViewModels.LoggerViewModel.VerboseLogLn("Scanning for copy protection in {0}", _env.Drive.Letter); + + var tempContent = StatusLabel.Text; + StatusLabel.Text = "Scanning for copy protection... this might take a while!"; + StartStopButton.Enabled = false; + DiscScanButton.Enabled = false; + CopyProtectScanButton.Enabled = false; + + string protections = await Validators.RunProtectionScanOnPath(_env.Drive.Letter + ":\\"); + if (!ViewModels.LoggerViewModel.WindowVisible) + System.Windows.MessageBox.Show(protections, "Detected Protection", MessageBoxButton.OK, MessageBoxImage.Information); + ViewModels.LoggerViewModel.VerboseLog("Detected the following protections in {0}:\r\n\r\n{1}", _env.Drive.Letter, protections); + + StatusLabel.Text = tempContent; + StartStopButton.Enabled = true; + DiscScanButton.Enabled = true; + CopyProtectScanButton.Enabled = true; + } + } + + /// + /// Set the drive speed based on reported maximum and user-defined option + /// + private void SetSupportedDriveSpeed() + { + // Set the drive speed list that's appropriate + var values = Constants.GetSpeedsForMediaType(_currentMediaType); + DriveSpeedComboBox.DataSource = values; + ViewModels.LoggerViewModel.VerboseLogLn("Supported media speeds: {0}", string.Join(",", values)); + + // Find the minimum set to compare against + int preferred = 100; + switch (_currentMediaType) + { + case MediaType.CDROM: + case MediaType.GDROM: + preferred = _options.preferredDumpSpeedCD; + break; + case MediaType.DVD: + case MediaType.HDDVD: + case MediaType.NintendoGameCube: + case MediaType.NintendoWiiOpticalDisc: + preferred = _options.preferredDumpSpeedDVD; + break; + case MediaType.BluRay: + preferred = _options.preferredDumpSpeedBD; + break; + default: + preferred = _options.preferredDumpSpeedCD; + break; + } + + // Choose the lower of the two speeds between the allowed speeds and the user-defined one + // TODO: Inform more users about setting preferences in the settings so this comparison doesn't need to happen + int chosenSpeed = Math.Min( + values.Where(s => s <= values[values.Count / 2]).Last(), + preferred + ); + + // Set the selected speed + ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", chosenSpeed); + DriveSpeedComboBox.SelectedIndex = values.ToList().IndexOf(chosenSpeed); + } + + /// + /// Cache the current disc type to internal variable + /// + private void CacheCurrentDiscType() + { + // Get the drive letter from the selected item + Drive drive = DriveLetterComboBox.SelectedItem as Drive; + if (drive == null || drive.IsFloppy) + return; + + // Get the current optical disc type + if (!_options.SkipMediaTypeDetection) + { + ViewModels.LoggerViewModel.VerboseLog("Trying to detect media type for drive {0}.. ", drive.Letter); + _currentMediaType = Validators.GetDiscType(drive.Letter); + ViewModels.LoggerViewModel.VerboseLogLn(_currentMediaType != null ? "unable to detect." : ("detected " + _currentMediaType.Name() + ".")); + } + } + + /// + /// Set the current disc type in the combo box + /// + private void SetCurrentDiscType() + { + // If we have an invalid current type, we don't care and return + if (_currentMediaType == null || _currentMediaType == MediaType.NONE) + return; + + // Now set the selected item, if possible + int index = _mediaTypes.FindIndex(kvp => kvp.Value == _currentMediaType); + if (index != -1) + MediaTypeComboBox.SelectedIndex = index; + else + StatusLabel.Text = $"Disc of type '{Converters.MediaTypeToString(_currentMediaType)}' found, but the current system does not support it!"; + } + + /// + /// Process the current custom parameters back into UI values + /// + private void ProcessCustomParameters() + { + _env.DICParameters = new Parameters(ParametersTextBox.Text); + + int driveIndex = _drives.Select(d => d.Letter).ToList().IndexOf(_env.DICParameters.DriveLetter[0]); + if (driveIndex > -1) + DriveLetterComboBox.SelectedIndex = driveIndex; + + int driveSpeed = _env.DICParameters.DriveSpeed ?? -1; + if (driveSpeed > 0) + DriveSpeedComboBox.SelectedIndex = ((IReadOnlyList)(DriveSpeedComboBox.DataSource)).ToList().IndexOf(driveSpeed); + else + _env.DICParameters.DriveSpeed = (int?)DriveSpeedComboBox.SelectedValue; + + string trimmedPath = _env.DICParameters.Filename?.Trim('"') ?? string.Empty; + string outputDirectory = Path.GetDirectoryName(trimmedPath); + string outputFilename = Path.GetFileName(trimmedPath); + if (!String.IsNullOrWhiteSpace(outputDirectory)) + OutputDirectoryTextBox.Text = outputDirectory; + else + outputDirectory = OutputDirectoryTextBox.Text; + if (!String.IsNullOrWhiteSpace(outputFilename)) + OutputFilenameTextBox.Text = outputFilename; + else + outputFilename = OutputFilenameTextBox.Text; + + MediaType? mediaType = Converters.BaseCommmandToMediaType(_env.DICParameters.Command); + int mediaTypeIndex = _mediaTypes.IndexOf(mediaType); + if (mediaTypeIndex > -1) + MediaTypeComboBox.SelectedIndex = mediaTypeIndex; + } + + #endregion + + #region UI Helpers + + /// + /// Get pixel coordinates based on DPI scaling + /// + /// Rectangle representing the bounds to transform + /// Rectangle representing the scaled bounds + private Rectangle GetScaledCoordinates(Rectangle bounds) + { + using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) + { + return new Rectangle( + TransformCoordinate(bounds.Left, g.DpiX), + TransformCoordinate(bounds.Top, g.DpiY), + TransformCoordinate(bounds.Width, g.DpiX), + TransformCoordinate(bounds.Height, g.DpiY)); + } + } + + /// + /// Transform an individual coordinate using DPI scaling + /// + /// Current integer coordinate + /// DPI scaling factor + /// Scaled integer coordinate + private int TransformCoordinate(int coord, float dpi) + { + return (int)(coord / ((double)dpi / 96)); + } + + #endregion + } +} diff --git a/DICUI.Forms/Windows/MainWindow.resx b/DICUI.Forms/Windows/MainWindow.resx new file mode 100644 index 00000000..a9219137 --- /dev/null +++ b/DICUI.Forms/Windows/MainWindow.resx @@ -0,0 +1,1395 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + 84 + + + + + AAABAAEAAAAAAAEAIACNHQEAFgAAAIlQTkcNChoKAAAADUlIRFIAAAEAAAABAAgGAAAAXHKoZgAAgABJ + REFUeNrsnQeYpFWV/gF1XXVXXfW/uu4qiuAawUxQEJQgIgIimUmdZrp7Ouecc84555xzzjnnPAkQFXMW + OP/33O9+VV9Xd88MOAK6Xc/ze+7X1bmq3veec+65t6666vB2eDu8Hd4Ob4e3w9vh7fB2eDu8Hd4Ob4e3 + w9vh7fB2eDu8Hd4Ob4e3w9vh7fB2eDu8Hd4Ob4e3w9vh7fB2eDu8Hd4Ob4e3w9vh7fD2Frm95z3vuSo4 + OFhHaGjoVSEhIVcFBgYK+DooKOiqgIAA8fnIyMirqqqqDh+4w9vh7a16CwsLE2Jl4aqoAlY/ZnFrP88f + +/n5XXXPPfdcFR8ff7W/v//b8D1vi4mJuTopKemq8PBw8TX8cwy/j+/D11/l4+Nz1Uc+8pGrPvjBD171 + X//1X+J+Nze3wyfk8HZ4e6NFz8LkjyHKa2xtbd/u7Oz8b15eXtd6e3vfhPu+Bb4HwT8GkRrha63xPQ7A + DXjh+/wxhjK4DsDoLT/ngK+1wvcYQ/CP+fr6fg8/75v4uTd5eHh8wtHR8d/NzMzebmJics3zzz+/J7Lg + v+nwdng7vP2NQldFrgqexWVvb38NBPkhiPozEOft4BngCtEl4nvqYmNjRzGTL6Wlpe1kZma+kJOT84vC + wsI/lJWVUU1NDdXV1VFDQwM1NTVRS0sLtbW1Cfia7+PP8ddUV1cTfw9/b3Z29i8yMjJeSE1N3eGfzb+D + fxcMIol/N/8N+Htux9/1GRjEhx5++OFr8DVXJSYmXsVRBf/tHDlYWVkdPrGHt8Pbfjd1BtXO7IDD8/+A + uP4X4noUIvKE8HKioqK6EL6vZ2Vl/Q4ifYVF29XVRUNDQzQ5OUmLi4u0vr5OOzs7dP78ebpw4YLgueee + e02o33fu3Dna3t4WP5N/Nv8O/l38O/l3898As/kd/03R0dFd/Dfi7/ZC9PFjRA2fwd//QRcXl3/B14ha + A/5uXV3i8HZ4+z97g2B2CR5iudrT0/P9EM6tEPsJ3B8BMXUmJydfwEz8O8zgr3R0dNDY2BitrKwIgbM4 + WaQIxemFF14Qo8prFfyl0P5s9XepBsF/y9raGk1NTVF3dzdHEa/w34wI4Hn8DwP4XxLwPxnjf7zVycnp + A88+++w1iE6uQmRxFRvD4e3w9n/ipi2u8WwIQbyLZ3iI40GYQARm0KH09PTniouL/9ra2koTExNC7GfO + nNklwEsJXJ29OQJggZ49e1b8DBUW7H7ovgZfz9/D33u5UYTh38c/h/92NoXOzk6OFP6K1OQ5RDCjeBwS + 8X+LCMHW1vbdc3NzVw0PD1+FdOQqIjp8oRze/rnCezWnl0Wyf0NI/3mI/nR4eHh5XFzcWl5e3p85Dx8f + H6eNjQ2d2C4mdlXgLFQO0Tc3N0WYzqJbWlqihYUFmp+fJ4iLZmdnaWZmhqanpwUsSobDeUb9mD/HXzeD + r5/F983h+xcQ9i8uL9Py6iqt4Oev4/ds4vftsEmwQUhzuHAJU+Cv4f+NTY3rDogQ/oIoaA2PTQXMwBbR + DxcZ/x3/01VNTU2HL5zD2z/2jZfb1KU5b2/vdyC0/wKuT2HmL0dofL68vPwvvb29Qqw8W6qCOUjsqtBZ + RKsQI+fjLOz9BP16UX+OAD93kn82DGGKfw8MYRqGMMO/F3/zHP6GeYT9i/h7Vra2aB3/wzYM4QxHHQcY + gvZ/5P9nGcbCjwGig78kJiZe4McGj9spGMGNR44ceSdHAxwVHN4Ob/9Qomeqq6v54//BTP9jvLCLIPot + hPYv9/X1iRc+z94HzfAcerMp8KzOMzrP5DwzXwmRX44BTEoDmJIGMC0NYAZRBRvADAxgFn/XHAxgAQaw + AANYhDktcdiPv32NZ3v8H9ssdHCeI4CLRAj8//JjMjg4SDDGv+Kx2kbkVIJI6Uk3N7eP4aG9Gl9zmB4c + 3t6aN+2SHUL8d0P4X8Hog5x+NDc3949cMeeZ/iDRqzM8C56FwGE7z+x/T7HvixS/zgDYdAwNgMXPf6OM + ABbwNy/CAJbYAPA/sAGs4v9Zx/+4+ZOf0PaLL9KZn/6Uzv3sZ3QB4wV8/NwLLxxoBvxY8GPFxcT8/Pw/ + 4TEcg4mGIEW41dra+t8OTeDw9pa5qS20XMVHiP9eCP8HMIH85OTk57lqz/kuF9cOEr1aPed8/Y2Y4S/X + AKY0BjCtCf+nL2YA+F+W2QBgcmv4/zbw/27BAHYg+rM//zld+MUv6Plf/pJ+8qtf0U/Bi/j4Rdz/AhuC + wWOjLSTy34XH8lU8pj/BY1vk5eX1QwsLi/9gI5BmcPXhK/Hw9obP+Cz6iIgIDvM/ys0wuG7OzMz8ZXt7 + uwjb1eU57QubIwB+UbPoOax/U2Z5DRMH1QA04f/UxQxgfV1vAPi/2ABWL2IAL8AAXvz1r+lnv/kN/eJ3 + v6Nf/f739Gvwq9/+ln6Gz//kADPgx5IfU46ksrKyfhkaGtru7e1t5OzsLNKDQyM4vL1hFX0WPl583N32 + 0YCAAMvIyMihvLy8P/X394sQ3nC2V8N7rtDzTP9mi/6yioD75f9ch9AYwOw+BiDCfxjAOv7vTYT5uvBf + NQCe+TUG8Os//IF++8c/0u///Gf641/+Qn/A+BsYws/ZDGAe+0UF/BgPDAzwKsKf8dgPI/Kyc3R0/ITG + AK4+NIPD299l1uciH15w/wnxm4SHhw8VFRX9eXR0dN8wn2d7rtpzTs/V+req6C9VADRcAdAVANkAuADI + BqApAOryf9UAkPuff+kleo5FzeE/DODnmPF/ybM/DOB3MIA/SAP481//Sn99+WX6C/gT7vs1vu6nMI/9 + ogKOpPixx3PwF0Rfo3heLG1tbTkiuEZjBIe3w9vfLnzO9SH+D2DGP4YXW19+fv4fhoeHdQ06hhV8nqXe + CiH+azWAyYusAOiWANnQeGVCswIg8n/NCoBaABThPxf/1Pwf4mcDeAnC5vD/N2wAf/qTMIA/SQNg8bMJ + vPzKK/QK4OvfwyRe4ghin6hANQKOCPDcDCM6M7e0tPwvTSRwaASHt9d24/3w6s42GMC7IPwHwsLCGhHq + /4H74Peb8TnM5/V5dbbnAuA/ivj36wFgpg8wgDlpAPNaA9Dm/5j99+T/mvD/JZn/swH8HgbwR2kAf5ER + wMsaA3jl1VfpVcAjRwW/xM8RtYJ9jIBNmdMxPHdt7u7uDz3++OPvOzSCw9trvrHwEeZf7evrexMMIC01 + NfUlLkBxSG844589c1YUqGamZmhifEJ087H4Vf6RDUAfAczrewA0EQAbAOf/i3tWAGAAEOmOmv8jBVAN + 4OeG+f9+BqCKX2MAr2qM4M/42l/h5+xnBPwc9fT0UFpa2i9g3HkODg63ve9973vHoREc3i4r3JfbVz8K + E/CMj4/famxsFAI3XLcWwl9eoempaUX0YxP/8AZgmAJMyhrAlIgA9AYwZ2AA2ghALQByBMD5/7nLyP8P + Cv/3MwAtwgjwMw2NgOFojHcrxsXF7fjgZm5u/glZH7jm0AgOb3uEL7fjvgPivy88PLyzpKTkZQ7nDZfz + WPhLi0s0OT5Jo8OjNDY6JnbojY+NCwN4K5vAhJaJSf3fuOtz0gj2GMA8TRt0Ae6XAmhXAM7KAqAu/+fw + /yL5/1/3MYBXL2IAWiP4JX6+tkagLh/yc1haWvoyUrg+V1fXH911113/ZmAEh7f/60t7fGAF+AQMICQ5 + OflF7kLTFvh4PH/uPK0srdDY8BgN9Q/R8MAwjQyN0OiIYgLCAA6IAt5IEzhQ5JdgTzegoQHwEqaaAmB2 + VQ3AcAVArP/DAHZgAOcusv5/sfD/5cuY/V/dJzXgGgEXC7WGrdYHeM8BntufIa2LtbS0/Cye+rcdRgP/ + xwt9crPOv0D8D+PjkcrKype5DVUXSj7/HF04f4HWVtZobGiMejt6qa+rjwZ6BxQTGBoWUQBXoXVRwBVO + BfYK+vJFfTHGtR/v1w6sMYDpeX0NQG0CmlN7AHipU7sHQNMAZGgAHP7vyf/V8P9vNACdEeD7fo+f/1NE + H4bLh/zc4jl+JSIiYgLRwBO33377vx8awf/BG+/Q4zV9jB+BCQSkpKT8jJtLeAlPO3tsbW4J4Xc0dgi6 + Wruot7OX+rv7abBvkIYGhi4aBYxPaE3g7y/q18uuzsD9IgDZBTgNAc3I8J8NYJ4NQC0ACgPQdwCqDUB7 + 8n9pAJda/rvc8P8g+Gf9Br9PWx9QNx7xpiM85z/38fGJMjIy+hReEm83MILD2z9zhZ9P38Gsfwsv7SHX + /yt36GlfJBzuz03NUXt9BzWUN1JzTTO1N7RTZ3Mndbd1K1FAj4wCBpEKDI8oUYCoBygmMA4TGGMTECgf + v5kiv1QEoAPin5BbgdkAJmfnkALM05RMAWaXV5ACrO2OALT5P1fiDfN/aQDa/P/3GgPYd/nvbzQAFU4L + fs6FSIO0gLdTc20AKWCnnZ3dvXhp/OuhCfyT5/ryWOz3YDTnCj8fsaWu6asvDg73e1p6qbqwRlBXWk+N + lU3UWttK7Y3t1NXSRT3tPbtTAdUE1EhgdFxEA4LxMWkC42+KyC/JuBKdjE/sNgFhANNsALtrANp9AAet + AOzK/w3afw3z/ysZ/h8E/8zf4ncbRgP83PPejdjY2DNubm6299xzz4c00cBhSvDPFPLLs+3/CyF/bFZW + 1m952Ut3QMXz3MF3niaGJ6m6oIaK00upLLuCqvKrqaaolurLGqipCiZQ10odTTIV6FBSgYG+AZEKHGQC + ojagiwTG3zBR72b8omjTlF0GMCMNYH5OvxFI0wbMBqDL/2EAfAaANv9/ThrAT/dZ/9e2/77W5b/XHQ3g + 93GR8DlNcZdHfi3wIatICVKOHj36abxk3iGN4DAa+GeY+eXa/o2hoaF1ZWVlL/O6vrbCv7m+SR313VSY + VEz5iYVUnFpCJRllVJ4DEyioptqSOqQCDSIVaGto25UK9PfIesCgQT1AEwW8VhP4e4j8QAxTgv0MYM7A + ALQ9APsUAPfL/1+S6/+/ucz8/+9hACIawO/hPQaGS4bcN8AnHOO10mFubv4tmRIcmsA/er4PA3gbxP9Q + dHT0THNzs76b73llp9702CxVZNdQVlQeZcfkU15CIRUmF1NxGqKArHKqzK2i6iJ9KtBS26JPBTqQCnTL + VOASUQDXA1SEYC8p6L9B1K/DBFS0dYAJaQCTMABRA0D4P7OPAazqCoB71/9f/BXC/1//Zk/+b7j89/c2 + gFdU5M//A6KQF3mlwCAl4NdIZGTkkr29/dPXX3/9e2U08LZDE/gHuiUkJKgh/78CMz6emiu/uqae55WG + nt62YcqKLqLUkBzKiMjFdR7lxBVQfkIRFaXIKACpQCVSgdpipAKIApqqm6m1vo06mpEKIAro4VWBHk4F + lFWBYUQBwyMjNDLCy4MQPkyAGZUNQypvmLg1jO3DLhOC+McNDYDFrzYBqT0ABkuAbADrF/T5v7oByHD9 + /1Ltvy+/QeJXf9d+KQHv4uTXCl5DL7q4uNjfdNNNH8RL6p0yGjisC/wj3HiJD7P+v8MEPNLS0n7JS1xa + p19f3aL60g5KDsmnpMAcSg3OofSwXMqI5CiggHLjCik/CSaQVkKlmeVUkVspagMcBTRUNCEVaFFSgRak + Au3d1NvJqcCAxgQ0kcDImIgGeJVA7Rf4e5rA2GtkdzQiDWBydwSwywBEBLAudgKqBqDL/2EA6vFfz0kD + 2LP89ybk//uJX406uIvwF/gbnzc4pox3cuK18ys3N7ewu++++380JnCYErxVb3z8tqz0fxihfwLv3tMu + 8TGzU8tUmNZAsb55FO+XS4kBuZQclIsoIJfSw3MpM0qaQDynAiVIBcpEKlDBqUBh7cGpgFwVGOxX6gEH + mYDWAC7HBMb+FsYuhv73a6OBXUuBBxmAjAD4HMCVs2d3FQDZAM4flP9D/JfT/vvK30n8OgOQv5OjD/4b + 2Iz4VKIXDFYJ+LWTm5v7J29v79yHH374f2Vd4B2HjUNvwRvv2edqP7gW16W8xsun8KjFPg7/h/vnKCW8 + miI88ynaOw8mkKuYgH8OpcAE0hAFpHMqEJVPObFIBRKLqFCmAmW6VKBOnwrIVQEuCKoNQtpVgeFhTgXU + msC4PhKA8FSunKjHXhfjukhgXJ8GTF0kAuAUQLMHQBiALABuwwBE/g8DUPL/XyH//7V++692+e8i4f8r + b6D4/yRPIuK/61f4Ow1NgI9vw2vpFUwqNY899tiNeKm9G/zL4VLhWzPs/0RoaGh1ZWXlq1t4gSp79nmJ + 7wLy9SmKCaiiUNciivAopCivfIqBCcTBBBL8ckQqkBKimACnAlnR+SIVKEgqpqLUUn0qoOsNaJSpQDt1 + qKkArwr0wgRkFDA0pJoARD8yJuoAIwYGsK8JjF15oauMGt6nmf3HGGkA49IAJtQCoOwC3GUAcgVgHQag + 3QAktv9KA9h3++8Vbv+9bPHL0F8r/j9K8fPfxgXKX+Dvfd7ABPi1xK8pvMZaH3/88a8dmsBbbOaX+/c/ + DfE38Wm8aqWfxb+zc47qqsco2LuaAt1KKcStmMLcYQKeBRTlDRPwkamAv0wFQmEC4bIeEKukAgW8KiB7 + AyryeFUAqUBZAzVWIRVAFNDW1E6drV3UjVSgt5tNYECawLBSFNSaAFALhCp/q6gvJvaLsct0DAxg4iAD + 0K0AIP/f0RcARf7PDUA/Q/j/EsJ/g/z/jVz+e+Uieb+h+P/wpz+LugT/fRylsFlx1PIcUhnDcwb4dGJE + mN1PP/30bXjpvUfWBQ67B9+sG6/vywM6P4/8v6O+vl7zPnrP0cbGWSrKHyEf1zrydqkkP9dyYQLBwgQK + pQnkUQynAv55lBgIEwhmE8hDKpBHmYgC2ATyRCpQilSgnMpzKqkqv4ZqiutEmzCnAi11bdTepF8V6JOp + wGD/kDQBWQ/gjUMjktHdXClRvxY4ohgdU02ADWBSlwKMT8EApmEAs9IAFvX7ALgAuKRZAdAVAGUHoGH+ + /6t9DOCg039e+buK/2UD8f9pj/g5YuG/mxuYxPsYGOwq5NcYXneDMIE78BL898Pi4Jt4k9t4Px0eHt7F + B3fsEv/6WcrOHCU3x2Zyd6gnL+caGEEl+buxCZQokQBSgUivAlkPQCSAKEBnAmF5MhVQooD8RKQCaZwK + VIiCYJVMBRp0qYBmVaBLLg32K/UAPkbM0AREbeAAExi90ozuj/K7ZGohTUDUATQpgNoDsKsJ6BIFwOe1 + y39y/f+NWP671Mz/F634ARvSLvHzIaR8wAjEz/8DpzLn8H9p39WIj37j1xoigaEnnnjiW9IEDpuG3ugb + F/wg/k9i5m+CK7+qFf/a2llKS5sgR/sOcrJrIVeHJvJwVEzA162SAmACQSIdKKJwNgFPxQTiYAIJAbmU + hFRA1APCEQVE5RukArIgmKdvE1ZTAbEq0KpvEOJ6gFgVGNDUAzQGIPoFIHyVKyHqvYweyJ5agEwDVAMY + ZwOYn6epxUX9TkDDFQDO/zUFQMP8/41a/ruo+KUB7BE//ib+2/YTP0cxHM3wqUY7iG7OayIBNoGGhoZX + 8frrffTRR2/VmMBhOvBGhP2yyefjyPlrOS/Tin95+SwlJE6RjU0P2dp0kqNdOznbt5CbQyN5OnIqUE1+ + wgTKKMi1hEKlCYiioA9MwC9XZwIiFdCZQKGSCnCbcGaZkgoUIBXgNuEKpAKIArhBqF3TINSHKKCfUwEY + wODgbhPgOoChAYz8jYK+FLvMRms4EL9A1gDGDAxgUhqAOAuQDUCzAsAFQN0BIHL9/ye//JXoAHyj2n9f + ucRav8j7Wfyaiv9vpfh/aSD+FwzEz4XNzRd+Qlt81LvmXZv5NVdbW0t+fn4dP/jBD76Ol+b7Dk3gDZr5 + eR8/L/VVVVXtKvitYuaPS5olS+tBOm3dRzbWPWRv2wUTaIMJNMMEGmACteTtWkV+rhXCBIKRDihFwUKl + KIgoIA6pQAJSgSSZCqRH5lNWTAHlcCqQJFOBLC4IVlMVooDaMqQCiAKaa1upVV0V4IJgV58wAS4Isgmo + 9QAuDHIqwEagFghVFLGOXRGRXwoW/4jGAMYMDGCC24BlBKAuAarHgO0tACL8/xnCf2kA+23//ePfIf+/ + LPEbLPfpxf978TdyqzIb1gv4u1n859WZH//TFsTPLc7isFOkO1oT4NZhvAZf9fb2brzrrru+hJfnew9N + 4O88+0P87wsODk7hTT3apb71jXOUmLZA5jZjZG49TJY2g2Rl3a+YAEcCtm3kopqAcy35uFaTv1uFUhR0 + 3b0yEOuXpxQFEQUkh+QhFcinDDYBTgUSipEKlFCx6A2oFL0BNZreAC4ItjUqqwI9ulUBJRUYHNA0CQ2N + iJoAH2U9MjKyi9cr6NeMgQGMykLg2CQbgFIAnNzVA4D8f13uAoQBrJ3TdwCe5YKZdv1fXf5T838Z/l/J + /P8VAwN4+SJr/X98reLH/8N1DX6PAxb/Cr9pKe95QNSjNQF+DfJr0cPDo/jLX/7yZzQmcFgT+DuE/u/i + d93Nz8//o9rkI8S/eZ6SspbopN0kmdlM0CnrURiBNAEbRAI23YgEOhAJtMIEmshdNQG3KvJ316wMeCgr + A9E+0gQC2ATyKCVUMQFOBXLiikRBcNeqQEG1JhVoRhSg7hWACXT2IArQmICaCkgTGJYmMCxrAnvTgr+B + kd0MG3ysSyt0qwFaAzg4AjBsAd6T/8vtv7802P57pcP/fWf/S4hfLfoJ8f/mN8Ks1LCfNzCp4uc3Nll/ + QZn5+bjzZYh/EeJfwKy/iv9dawL8WszLy/uLk5NTwrXXXvsJaQLvPOwTuIJhP4T/Nozm6enpv+LTXFTx + b+2cp7SCFTJzmiETu2kytZ2kkzbjQDWBAZhAL9kiFWATcLJvJVc2AbUoiHRAWRlQegTC1ZUBmEAcTCAh + MI+Sg/OUVCAiX6wK5MQXaVKBctkbUEO1pWoq0KJLBbrau6mnS18PGBjQmoBiAEMwgKGR12kCI5eP3gBG + 9HWAUW0dYEKpA+yXAuy3AiALgLr8HwLSLf+xAVzk9N+X/0YDuKj4X375ouL/hUb8P9GI/6wI+18UM/+G + Kn78j0L8ED2Lfx7/+xweg1WMFzQmwOcNpqWl/fr06dPeH/zgB/9Hs0R4uJPwb5357e3tueL/o6SkpBd4 + k4ZuSebcBSqoWSdT91kycoQBOLAJTAkTMEMqcIpNwHqILJEKWLMJ2HSRg10HObMJODSSh5NSFBQrA4gE + gt1LKNQdJqCrB8AERH+AxgRkPSA3oUhJBXhVAFFAJaKAakQBdUgFGjkVqEcq0NRBHa2d1N2ppAJ9sktQ + NQBDExDRwMjInrrApRnZl+GLwAYwrE0FZBFQwAYgm4AmDc4CFCsABgVAXv8Xy3+/0DcAvdblv1euYMVf + J37we8O1fvxdHJ28qKn4q+I/I8XPXY18utGqnPm543FhG+LfUsQ/izRoZm2d1rZ2mwAfLBIfH/9TU1NT + y7e//e0fkSbwL4epwOu8paSkXGVubs7i/1pMTMwir6fr3nzzwnNU3bFJp/zn6YQrDMBllow5CnCYhglM + wgQmyMx2DFHACFnYDNFpG2kCtmwCysqAzgRc5cqAexkFubEJqE1CBcIElHpAnr4eEFVAWbGFlMupQCpS + gcwKKpe9ARwF1FciFZBRQHtzp6ZBqE+JAvYpCg6rhjA8ouO1ivq1oDOAMQMDUIuA+xiAOAZsk/P/HV0D + 0Dbn/y8q+f8LvzBo//292v775yvW/vtaxL9nrV+KX7fc9wu51s/ilzm/WvBbOY+Z/6x+5p9Drj8L8c9A + /NMwwqmVVZpeXqF1RALazWaczoWHh28/9thjD+Ml/P8Avw/BOw5N4PWv9f93aGhoS2trq85tmbaRbbKK + XKQT3vNk5DVHRu5zehNwnCITe0QBdkgFbJVUQDUBXh60s1WXB5vJ1bGBPJxrpQlUCBMIFiZQRBEiFSig + WL98pR6AKCAlLJ/SIgooE6lANqcCiAKK0sp0qwKiTbiUewOalTZhPlFYpgK92lRAjQQG9UbABifSAYlh + bWD4ChuAuvSoFAMNlgFn1CIgGwDvAtSfA7gn/+cCoG79f3f+fyWX/y5V8d9P/GxAhl1+WvHzexcq4n9R + H/az+M+dx8yv5PzzLP4NzPr4/6dXVyH+FZpaXqYJpEZTMMdNjQnwa5Rfq76+vv233XYb9wh8SLYNH5rA + a+3yQ97/Ht7WW15e/rL+DTmfo8G5M2SfvkjHQzD7ByzQCV+YgDebwOwuEzDVmoCtLArawgRspQnYt5Gz + QzO5O6pFwWryd6+gQJhACC8PehRRpFehUhT0hwkgFUgKyUcqkI9UAFFATKGyKpBSSsUZ5cqqgOwN0K8K + tOpTgY5uXSqgrQdoU4JBQxO4UqLXRBa7ioFig5I0AFEDMIwAFpWTgDQHga5IAxD5PwxAl//L8P9S6/+v + Z/nvlQM2+By01r9H/AZr/Vrxb8uZf11T8FvSzPxzBuKfxOPBvRHjiI7GZKfkNr5eNQHuEeDXrLOzc9H1 + 11//ebyc+VCRd191eKjI5ef9fn5+b4MBWOXk5PyOt2QK8ePBXdg4R75ly3Qsbp6OR8MAQiF+rQl4sAnM + 7DUBO40J8MqAbTfZ2XWQo0MruUgT8IIJiKKgRwUFwQRC3Uso3BMmIFKBAooLyEcqkC8OEkmVqUB2bNGu + VKAMqUAlUoGaXamA0iDU2dal1AN6YAJ9MIH+3UXB/QzgQBMYfu0MSXS1hhElDRiWBsBpwAhHAbIJSGwE + WlQMQF0B4AIgV8HXVQMwyP9/pln/35X/G4T/r2v2v4T4/2QgfrXL7yVV/Pj7VPGrYT+Ln/8PkfNrC374 + P+f3Ez9mfBb/BEQ/jsdnbHaWRvF48RunnMX3arcRZ2Zm/tHS0jL43/7t3z6Jl/V/aHoEDg3gYjfe2gu+ + nZCQcI6Lfqr4t86ep/jWNTqRAeGngISLmIArm8D0PiYwpKwM2Mp6ALcLwwRcHZvI3amevFy5XbhKFAW5 + XTjUQykKRurqAdIEQpVUICO6UKQCeUgFCtPLqQRRQEU+UoFibhBqoIbqJmoWqYCyKtDZ3qWsCvTuTgUG + ZSqgMwFpCIZ1gcsV+ZC6urAv+NyIwrCuFjC22wDwwt5lAJoCoMj/IZZteQKQyP8N239hAL/TrP//+W8w + gP1C/8sR/y+l+NmU1OW+C2qXnyr+/Qp+HPZvGoT9y4r4OewfR1o0hvRodIbFP0MjiJhGEDnN4/PnDYqC + MTExP3n88ceP4WX9UdkteLgycCnxI/f/GL9BJ78lt7boVzS8QSb5C3QcBnA8DbAJJGKMmaMTYRB/4AIZ + +c+RsY9iAsZsAs5sApNk6jABExijU7YjOhOwZhOwYxNoJycuCjo2koczm0A1+bpXUoCHXBlgE0AqEIVU + IEbUA/L19QCDVKCIU4GcKpkK1FNdRSM11mhXBbp2dQlqi4KDA8PCBLRpwaDk4oJ+jWgjCbUWIMUvioBq + BKBdAlT3ABgUAM+p+T9y6p/qDODKtf9e7lr/ni6/g9b6IX6uWSgtvkrOL8R/Vj/zz6niX4P4V1ZFyD+x + CPEjHRrDY8LiH4P4R/A4jUwq4h9G+sQswyy0tSp+DeM1Pf6Nb3zj23h5H64MXOzGR3r5+vq+EylARFlZ + 2V91Pf54INsXtsmieoGOFULwuSBjjo6nY0zFmAhiYQIRMIGgeWECRsIEYABubAJTe0zAAiZw2na3CTir + JuBSR95uNeQHE+B6gDABz2KK8IYJIBXgekACogBRDwhHFBBVSFlIBfISEQWklmlWBRAFlDYgFeBzBFt1 + qwKdbd26swO09QCRDsh9AwODgyISULli4jdMKTgCGFNTAMUAxmUEwAXAKbECsCrOAVyEASgdgOdo8zmZ + //90b/5/2e/+c4n8/7U2+vxO0+X3C0Pxv6Tv8tv+yYuamV8b9u8o4hfLfEqlf3KJ8/0lg5B/hkanVPGz + 8MdpCI/hEPdV4HoDj5O2HsCdgnZ2dnkf/ehHvyBXBg6LgvvdTExMuPj3WFpa2kvcWKGKf277HHl0LtGx + agi+HBRB8Lkgc04xgjSQBOIg+vA5xQQCMPoiFfBUTMDEZZpMnZAKwARO2sME7NgEBmEC/WRt10N29p0w + AaUo6ObUSJ4wAS4K+rnLlQFRDyhGKlBE0VwP8C8QJpAcWkCpEYVIBYooO66Y8pMRBaQhFciqpHJeFSiu + o9ryBqVBqK6FWpEKtMtUoLtL1gN6NfUATWHw72cCMkWQzUFcAxjWGcAUIoAZGMAcIgDVAFb2rABs8YYY + zv8hKG3+z8L79SXW/y9n9n+tjT6/+6N2ue93ssVXK/6XNJt7NGH/WXWdXzvzr2HmV0N+vfhHZb7PfRIj + MMphKf5hKX5mEKbKZyqekUVBfg0vI4JITk7+zbFjx5zxMudOwQ+Adx2mApqbPMzzhujo6Cle/lLFv40n + KWF8hU40Y4ZvQMhfAypgAsUgD6LPwv0wgROcEqgmwJFAsKEJIBVwQSQgTGAcJjAKExiWJtCnrAywCTi0 + kYtjC7kjEvCCCfjqVgZKKYRNwItNoBCpgCwKBhcgFShAKlBImTFFSAVKKF+kAhVKKlCopAL1airQgFSg + WUkFujq6qae7V2kV1hYFD4gCDjSBof0ZPAAW/6BaBxAvXNUAxvUpgIwAxC5AtQAIA1jdpwHoBRjAQdt/ + X2/4/7rFL5f79oT9huLngh/+F1X83OGoin9qRZ/vGxb7RjTiH5Iz/6AQviL+ATwfA3iM55AqnNekArzE + GxwcvHrnnXc+iJf7/xzWAwyW/BD2vxsk8JFefDa7+sBVL62TWc8sneiAyFtAI6iFCVRC8CUgHx9nA6QD + JzgSSMbXxkP4kTCAkHkyhgkYswl4wQTcFRMwdZoQJmCmM4EBOm3XSzZ23WRv30GOjmwCXBRsIC/XWlEU + VFYGYAIebAJFFOWjmEB8YAElsQmEF1K6SAWKKRepQAFSgWJOBTQ7BjkV0K0KtBisCmiiAH1NQJqAjAgE + FxH2XhTTGNhlIrtrAUPaNEB2AbIB6JqANCsAy7wCANGoBUB1AxAbAOf/L/1m/9N//vwaw/+94j+oy4+L + fvuc6CNbfJ/XiH/HcOY/d85A/OsQ/+ou8avLfKMzM7p8fxj5/hAipSEYJhunIvxRYagsfJVBPL4reNx0 + NSz8Try28fqyr/jQhz70Jbzs/0vWAw5TgYiICDaBh1JTU3+hvm0Xz/6jW9vkOAJB982QUfcMTADXrRwJ + sAnMCRM4IU3guDABheMpc8IETkSxCcAMAmEAvvgZXtOKCbhOKibgOCYiAXP7IbK041Sgj2ztYQIOysqA + ixNMwKWevNxqyNe9ShQFgzzkygCbgG8hxfoXIhUooOSwwl2pQB5SAV4VKM1GKsCrAlwQLG9EKtCsrAo0 + qalAN0ygV28CfQMwAjYBaQBsCCIa0HOQ0C+L4YsbgLYHQN0ExC3ASv6/I/J/LgAq+f9P983/Dwz/L8MA + 9mv0eVkj/j8f0OX3S22jjxT/BW1//66w/6zI+cUyn2jthfhX5cyvhvyIfkZnpfiR7w8fKH6e9TXix/PT + LxgUKyvbskmIX9P82kYq8Osnn3zSES/762WT0Lv/T+8c9PHxYfFfCxMY7O/vVx4sXvLDExU9gxl8aJKM + B6bIqHdaYwKgEdRB5FWgFNcFs4oJZKgmgPsSIP5oECpNwA9RgPcMmagm4KyYwCmHEbKACZy2GyAr+16Y + QBdSAZiAI0wAqYA7UgEv9xry86ikAM8yCvJUi4JcD4AJBBSIVIBNIC2yCKlAMeVwKpBcpksFKgpqYQIN + VFfRRI3VLbpVgXakAp1IBbq79CbQ1z+gRAP9SmGwX5iAntck+H1SiEGJYgBK7jqsrgJwBCAMYF40Ac0s + r0gD2KIVuQVYVwDk/P8lZf8/59yce+/K/y/R/vvK6zzDX1fxh/h/LcX/0mWJ/wKtcLUf/4fY1LOhiH+a + xY//c2JJqfSPc6WfZ/5prfgvFvIrURY/N/2a56l/YEC8wYga0bIJ8Gscqe781772te/j5f9x8P7/s/0B + 3OoLA3g7Qv/A8vLyV/ioJTVkqltbJovxMTIdGSeT4QkyHgR9MILuKTrRCSNoA01sAqAKlIFCmEAOyJhV + 0gGNCZwI4+LgLBn7wwR8YAAeSAXcJsnMeZxO6kxgkE7bD5A1m4AD1wPaydmxhVy5KOhaTz7SBAJ5eRCR + QJiXNAG/IooLKqTEkEJKCStCKgATiC1BKlCKVKAcqUAllelSgQaqr1JSAVEPQCrQ0aavB/T2apqEpAEo + JjDwt5mAYfSg6wcYVYqBXAPADCeKgDOzwgCmFrUrAEoH4LqmAHjhYvk/BHqp/P+V11jxNxT/r3Ti/+1u + 8f/8oJlfEf/ClhT/mrrGvyzC/nGR7yvLfCNyfX/YIN9XC30HiV+lD89Xn3zOeObXninIqwJWVlZ573nP + e/5vpwJc+PP19b0lKSnpHL8Lixr6T5/ZIs/ZETo5MURmYyNkigfdZBhGwCbQP0lGPTCCLkQEbALNEHk9 + qAbloAjkzopI4HgaxlRpAjFcHEQUEDyjmIA3TMBTMQFTNgEnpANsAg4wAU4HkAooJtBGzk4t5ObMJlAH + E6gmf2kCXA9gE4j0KaIY/yKKhwkkhSipQHp0MVKBEqQCZboGISUV4FUBfSrQyqlAq0wF5KqAMIH+foMo + wMAABg8W+cXYlTqoBqAWAdkARAqgbgNe0u0BWNLm/3wuHp+dvyv//83ln/6rMYBXXu9a/0XEf07d2Qfx + 8xuWrKnVflX8m+rML8Uv8/3dxT4IfxLCl+If1M38ivD7GTzmTJ9W/AN68QvwHHKr9c7OmV3vOBQTE/Oz + +++/3xQy+JRcGtS2Cv/z3zw9PTkC+Pfg4OCClpaWV9XQ/8yF85S2PEEWUz1kPtlPpyYG6eQYjGAURjA8 + BhMYFyZg3Ks1gZldJmCkmkAmRwIzigkkShOIRBQQjK9RIwHPSaQEE2TqMk5mTqN0ynFYmIAlogBr+x6y + gwk4OrEJNJObSwN5utUqJuBZSUEeZcIEIryLKcq3CKmAYgLJoTABTgViZSqQoqQCpaJNuFa2CSMVqGnZ + tSqgNQE1ClBNgOsCbAL9MiXo36c2MHDZBjC0Ow1QU4BJWQOQ5wCoKwDqMeCqARjm/we1//75Ist/FxX/ + Pmf4Gzb6/Mqwy4/f5PMlA/Hj9bQmc34u+Clh/8a+4h+Ty3xc7NPO+ruEr6ny98tcv08IXv+csOD3YwZR + hbZBCK95cnZ2bv/whz/8TcjhWpkKvPP/TBRARGwAP87MzPyV7nQfPDDdWwvkONtOp2c6yHK6B0bQR+YT + A3RqHEYgTGBUmIBJP6KBXkQDXTCC9mnFBBpANSifUSKBPGkC6UgLVBOIVUzAKGSGjAKmydh3iky8EAXA + BMxcOBIYIXNhAgNk5dBHNg7dZO/YARPgomAzuSMV8HKvJV+PagrwrBAmEOpVShE+xUgFiikusIgSQooo + GalAWjRMII5TgTKRCpRkVSEVqKHKojqqEalAM1KBVmppbIcJdIpUQF8P6Eck0A8jgOj7FANQX0x7TWDw + 8lFXBQwMQHQC4oU/qi4ByhUA9QwAtQC4ySYNAxDr/6oByOO/1e2/l3P6798kfrXLT9Pi+5x2W68681+4 + IM4tWNLu6OM1/lW1u09p6x2dU9p6WfxDeAzErI+IaHBUO+srhb5+jfi1z0PfRcTP8PPEr3M1CtjA35KW + lva7xx9/3Ouaa675vEwFtFuH/7mX/RD6fzg8PLy7r69PJ/6N8zsUvdRBtnMNZDPbQlYzMILpLrIU0UCf + NIFhMsMTYjo4Jk1gAiYAI2iHEbQgImiE+GukCRRD5PkYs0E6RwL4OAnijwNRIBQGABMwgQmYShM46TpG + p1xgAk5DZOkIE3DsJVtHxQScYAKuTk3kIUyA6wHVSAUqKRgmEOZdopgAUgFhAsGIBMLZBIopK66UcpPL + kQpUIBWoQipQQ1XF9aIg2FDdQk1IBVo0qwJdnT276gF6ExhQUgMRCQzsSQv2o/9iBiBzWc5tuY11XwNY + 1RrAeXE6rjCAffL/37yG9f/L3tdv0OW3R/zqzK/29+tmfrXgtyNzfm2Dz7K+2Cd7+kWxT1PlH5RV/gGt + +HUV/iGd6PsH9hN8v6BXol7zey6c02wY4oKgl5fX7Gc+85kHZCrwwf8TDUK82w8mYFlYWPgX3uarhkUN + myPkslBBDvPVZDdXBxNoIuuZVpgARwPdZDHZg5SgHynBIExgmEyHRshkAEbQByOACRh3wAhaYQSNMIJa + CL4CkUEJrgsgfNUEkBIYJUP88SAaaUAYTCAQUYAfTMB7ksw8YAJu0gSckQo49ZO1agJO0gScYQJu9eTt + UQsTqKJARAIhnooJRPoWi3pAXFARJYYWUUpEMWXElFB2QhnlpcAEMiqRClRTBVKBaqQCdTIVaFZTAV0U + ABPo0RQF+wZ0KcHlGkC/Acr9Mh3gJStuCFJrAMIAZBeg3AasWwHY2l0A3Df/v8jpv/sawEHv23fQGf7a + 47wMxM+nEfOpxGJzz3NKzq/M/Gf2Eb+s9M9dhviHZb4vxC+Le7K6r8/x9ULX0rPPffz1SzBV7anC+fn5 + fzlx4kT81Vdf/SXZIPTef+q9Avxefn5+fh+Pjo6e5DekUGb/52nh3CqFr5SR80I+KCHHeRjBXA3ZzdaT + zUwzjKBNGIHFZDdSgl46NTaAaGCIzPAEmQ4gLeiDEfTACDoREbTBBJog/DpQCUpBIciB+DMwIiXYZQLh + IEgxAROYgKnH+B4TUCKBTphAO3K3FnJzaSJPdzYBRAKeVRQkTSDcu5QikQrEcD0AqUASRwFRxZQZW0o5 + SAXy08qpmFMBEQVoU4EWpAL6VYHOTrkqwEXBPr0J6GYYzYtQG4peDH0tYNjAAMaFAahtwMoKwKLufQBE + ByAMQOT/cgOQyP8hwJ9pj/866PhvrfgNuNjML8T/x70n+hiK/+yLmm29cuZfEjP/lqj2K+Jf3SV+0dY7 + Iyv9mnx/YFSZ9bVFPlX4TK/mce+9mPj79ofPYNC2CbMGkAqv33TTTT+GPD4N/vOfuiCIsP8a/MO2JSUl + f1aX/c4/d4EqNlvJYzmN3JcyyXUxDyZQRE7zZTCCKrKfqyXb2UYYAdKC6TakBJ1kMYG0YBzRwCiigeEh + pASIBvphBD3j0gQmdSZwonKKTmhM4ESGNhKA+GPZBBAJBCGK8JuECUxIExgVJmABEzjt3EfWTj1k59RJ + js7SBFwbYQJ15AMTEEVBz3IK8SqlcJ8SivIvptigYkoILUYqUKykAvEyFUAUUJKDVKCghip5VaCikRoQ + BTTVt4lUoK21kzqQCrAJdMMEenr7xIuHUwEdu0LOyzeA/l0RwLBiACIFkG3A6i5A+UYgCzAA7gDk47A3 + ZQPQeRjA85oCoHb77yXD/0vM/H/+y18h/t2NPr/e1eX3axjPL0X/gW5nH5/dL2Z+fc6/oO7l17T2qsU+ + rvSP4P8chvg53x+8iPhV4QvB64Qvxd/3+pibX9C93RhrAFp45fjx46mIAr72T10QRN7Phb9PREVFzUzg + gVdn/9lz8xSxlkreq/HkuZIMI0gnt8Vscl0oENGA03w5ogGkBbMNMIEmmADSgimkBRNdZD6GaGAU0cAw + jAAzm0nfKBlLEzBmE2hGNFAHqmACZTCDIphALkaOBLgmkAITSGQTgAFETJFxMKIAf0QBPuNk5jlGJ91H + ydx1iCxdBsgKJmDDJuDMJtBGLi7N5O7eSF4edeTrWUMBXpUU7FVOoYgCInxLKDqgmOKCFRNIiSym9JjS + XalAiUgF6pAKNIhUQDWBVtkg1CHrAcIExPIgTKB3fxPo3zcS2Jsu9GtrAbIOMKRpAxbvBrSwsGsFQC0A + bhkUAC+V/++7/Hepd+/ZR/zaLj8u+PHv1olfzvxq2L8oC34HiV9t69WJHyH/wKgi/n4W/9CwFL6+wt/X + r4heHV+v8JkewPUXbYcgawFp8dYXv/jFJyGTz4EPyx2D/1xRgLe39zWBgYEupaWlf9XP/uepcruK/NZD + yHctknxWY8lrJREmkIpoIAMmkEsuIhooJce5SiUamJHRwBSigUlEA+OIBsb66NTIAEwA0UA/ooFeRANd + YzABGEEzZvZ6mEE1KIcZFIE8GEAmBI9IwBhGYMwmEAcTiIQBhEyRaQBMwBcm4AUT8EAq4AYTcB0kKxeY + gHM32Tt36E3Ao0GaQLViAp5sAmUU4QcT8C+h+KASSgwroZSoEsrgVCCpHKlABRWJVKCWKovqkQo0KqlA + XSs1N7SLekC7ZlVArQeoKwN98gWlFpwMi4P9uvRAg1oPUJtX2ABGZQSgdgHyQSDyHEAuAC4ihF6BqNbP + ndet/+/p/9+z/HdA998+Lb5/3WfmN1zr17b47trT/5MXRFSyfuEiM/+iKv55vfiR6nC+r4ifZ32If3hE + V+E/SPx9B4i/Zw99l2QWZqRGAVwYhCZeNjIyynrHO97B5wiqJwj982wW4tnf39//EzExMTOTCDX1s/80 + xWyGU8CGH/mvB5PfWjhMIEpGA0nksYS0YDELRpBPzvPF5DRXRg6ziAZm6oURWE+30OnJdn00MIK0YAjR + wMAwmfaOkGkXjKAdEUEL0oJ6UA3KYQTFbAJTigmkTysmkIQxDh9HwQRCYQABE9IERjUmgEjApZds2QRc + OsjJuZVcXVUTqCVfL14e5EiggsJ8yigSJhATCBMIKUEqUIJUoJQy48pEKlCQzqlANZWzCRTXU225GgXI + pcHWDkQBXTIV0BQFhQn0i9pAr8YAdjWg7IO+IKiEt7tSAGEA+l2Ayh4A5P+bMv8/rxiAyP8hwAO3/16s + /Xc/8Wvy/v3et29Xi69m5t/ZlfNrxM97+TVr/BPqzK9p61XErw359xd/rzrjG4T8hkLvvgzBG8K9GFua + KIA1gclxB1HA05DL5+XhIeqy4D++Aci38jZHviNmfxb/+efOUc1OIYVsulHwpicFbfhSwHoA+a9xNBAB + I4hBNJBAnstICxANcFrgwmnBfAmigQqyn60RRmAzjbRgCmnBRAdZjHWT+SiMYLgfJgAj6IMRdMMEOhAN + tCIaaAA1MIAKUIK0IB9kcSQA8afABJIxxuPj6ElpAuOKCXizCQyTufsgTKBfMQGXLphAOzm5wgTcm8jD + g4uCdeQHEwhEJBDiXU7hvmUUhSggFlFAQiiigMhSSkMqkIVUIDe1ggozq/akAo21rWJVoLW5HVFAJ3V0 + cD2gRzEBGECPjAR65YtwV6X5ImvRuqYVtRagFgF1XYDT4hyAqYVF3RkA6hbgTVEA1IT/EOTPfy3D//3y + fwMDePkS4jd8Aw9V/D/b1eW3W/y6nH9bK/41Kf4l5eguiH9ErfRrxa/O+jDBPjXk1+T6e4p7Bwj5kuLv + PZgZmK22FlBUVPTXZ599NgVyuQVc908TBfCyn5eX14ciIyP7+Wx7dfafPz9JCdteFLbtSKFbLjACdxiB + NwUiGghYD0Q0EEq+q5HkvSLTgqUURAOZ5CbSgkJRJHSYqyK7WU4LGsh6qlmJBsa7yGK0BybQRyfxZJr1 + IS3oRlrQASNoRTTQiCigFlSyCUzSiQKM2dIEUqfJJAURQPy0YgJhiAICgR9SAe8ROuU5TBYwgdNu/WTt + 2kO2rl3k4NpOzm4t5ObRSJ4wAR/PGvL3VlYGQmECEX6lFBVQQnHBSAXCS5EKlFI6ooBspAJ5aZVUlF1N + pYgCKhAFVJcjFahupkZOBRAFtMpUgE1AWw9QawKMWiTs1aUF+xmApmNNFgG5FXhQ1wU4qdsGrK4AaAuA + av5/QRrATw3y/98fdPzXy69d/Lu6/Pggz5dki+9Pf6af+bVh/+bemV+7m0/J9ydFsY/z/X610KcTv77Q + 1zdgKPx9xN97ZeDWbW0tgLWBNHnpuuuuexyy+YJBc9A/rgHk5uby0t8TGH+rrPs/D+e7QE1nCyhq25oi + tm0pfNuBwracKBTRQIiIBnwoUEQDwTABpAUrSAtW4pVoYDEdJpBNrvNKWuA4W66PBqYQDUy2wgQQDYwi + GhjupZODbAKIBrphBB0wgtYxMmmCEdSCSkQEpZNkrJoA0gGTNGkCCTCAGBAOAwhGFOA/Rqd8Rsnca4gs + PJAKuPeRjVsP2bl2kiObgAdMwBMm4FlHPl7SBJAKhPqUU6R/GUUHllJ8aCklRZRSanQZZcSXU05yBeWn + V1Fxdo1SDyhpoJpy2SDEqwKcCrR0ynpAD3V1aYqCPa/BALRFQrUOMKIYwJDaBajZBrxfAfAsxLdr/V+3 + /PfHg9f/VRN4+VKHeqji179ppzrzPyfEvzvsX1WX+oT413XiV7r75vet9OsKfSx8jfh795v1+bHsVfZl + 9FxBug3gg0PUPhjWRnZ29l8eeeSR8H+qKCAgIOC9oaGhNb29vbrZf+X8PGXueFL0jgVF7VhR5I4NjMCO + wrfUaABpwYYXjECNBpAWrCItWEFasIy0YBHRwIKMBuYRDcyWwggqYQKIBqbryXqymazG28hyrJMsRhAN + DPbRKQjhZA+MoGOITNpgBE0wgjpQBSMogxEUghyYQQZHAzCAlEmdCZhGwgRCxumkMIGRvSbgxibQRi4w + AXevRvLyqidf72oK8KmiYO8KCvMtRxRQTrHBZcIEkiPKKC22nDITKig3pZIKMqqRCiAKKEQUUNqIVKBZ + pgIyChBLg4oJKE1C2ihApgV9Kv17GlR0tQC1mUU1AN7hpkYAcgmQVwDmIKhFGABvAV4/rxYAZf6vWf83 + PP5LG/7rDeBlfbXfcK1/n7fuUmf+59UuPyn+Lc3MvyzEv7lH/Hxop76n30D8Mtfv0+T6vQaV/Z6+g8Xf + fRmCvji9e+AVgR1NXwBrxMXFZeIDH/jADyGdL8oo4D3/sFGAk5MTz/53paenv6T2/PM/23O2nOJ3TlHc + jjnFwgSid04jGoARIBqIkNFA2KYrjMADRuBNQev+FLAWRH6rYeTL0cByHHktJcII0mAEWYgG8sh5rghG + UE4OM0gLpmvJZrKRrCda6PQY0oIRGMFQD5n3Iy3oRUTQhWigHSbQDOpHybgaJlAOisbJKHdCMYFUmEAq + DCARxMIAIhEFhI6RWcCoYgLeg2Tp2Q8T6CVbt26yd+sgJ7c2cvWUJuBdR74+NRToU00h3pUUrjGBhLAy + So4qQypQTtmJFZSXWkVFWdVUlqcUBMWqQDWvCrQhFWiTqYBaD0A60A0j6JHpgPqC1ISpe3JY3Tq2agCy + EUh2Aep3AS7QzNIyzctDQFbPIP8/rzQAqev/l8z/NYL/60HiVw/1MHzfPjXsFzP/z5X+fo34V3cV/NbF + duWpJf3Mr3b2iZ5+tdJvWOVn4R8gfsFli7v3b4Z/zwL+du0egaSkpN9897vf9YR8bjaIAv7x+gJgAG8L + Dg6OaWxsfEUJdZ6nrQurVHzGlxLOmIKTwghiYQQxO5YwAisYgQ1FbtlRxJYDIgJnkRYEb3hS8Lo+LfBD + WuC7Ei2NQJ8WuMwVwARKEA1UkP1MNdlOIRqYQFowhrRgFGnBUDedGkBagJnTrHsQJjBMpsIEQPUYIoEx + MoIJGMMETMQy4aQwAdMkABMwi4IJhMEEAkfppO8wIgHVBHrI1r2L7N1hAh6tMIFm8vBqQE5XR34wgCCk + AyE+FRTuV45UoJziQsooUZMKZCdXKqlADlKBgjolFaiACcjegGbZINTertQDOrtgAj27TUB9Qal5qmFa + 0CsLgcoqgKEBKAVAZQVgBQagFADXYABbF3bn/y/K9l9t/v/HSxjAXw46w19t9Nmny49z/jM/eVGIf+O8 + FP+2JuxXxc/Hdc/pxT+sEX+/FH+fOvNrxN/DGFb194i/98rQczB8LLv2LAxohU6ePFn/rne96z65IvCP + 2RfAZ/z7+vpeFxsbuzCLsEwN/8fPtVAGBJ9yxoSSYAKJMIGEM6co/gxHBBYUs30aqEZgDyNwRDTgAiNw + pxCRFviKtMB/NRQmgLRgGWnBEqcFqSIt0EcDpYgGkBZM1ZDNRANZjyEaGEU0MIxoYABpAZ7gk92IBjqQ + FrQgImiAGdSMkkk5jKAYqUE+mwAMIB3iFyaAKCAOJhANAwgfo5NBiAL8kQogEjgNE7D2gAl4wAQ828nJ + Cybg1QQTqCdvn1ryhwkEIh0I8a2gCH+YQBBMILSMkiLLKJVTAUQBualIBTKrqRipQDlSgSpEAbVIBRqQ + CjQ1cJdgh75LkIuCaj2gW0kHhBkYhKh76gIiAlAMQLcPwGAFQFcA3OIC4N78/2cQ6UHtv/sZwF8u9gYe + vNavvmnnrhZfjfi1M78259eJX+npH+aZXxT7JmhAil/J9YepF/+zEL4m199bse8VXAlRXw5dEjaa1dU1 + XRTAWgkKCrrw2c9+ls8L+LrsDnzfP9weAd7y6+/vb1RcXKxb+jv33A41nY2h9DNGlL5jQmkwgBSQfMaM + EndgBIgG4mEOcYgGYkQ0YA1sYQSIBjZlWrDhoUQDa5q0YBlpwRKigUVEAwtp5DbP0UA+Oc8Wk9NMOdlP + IxqYrCObcUQDozCC4Q6yHOgi8z4YAQR0UpjAoDQBRAMVSAtKYAYF42SaBSNIh/hTQTIigPhxYQInI5AK + hMAEAmACPgN02quPrD1hAp5d5ODVTs7eLeTmDRPwricfNgHfGgqCCYT6VVBkYAXFBCMNCi9HKlBOaXEV + lJVUSblpVVSYVUOleXVUUdxA1eVNVFe1e1WgrU01gZ49JrArJVANQLuerfYDcASg7gTkHgC5C1BbAFQa + gM4p6/9yA9B++f8fDA1AmoAifP1Zfvse6mEg/ud/LsWP37f9/AuK+M/tLviJ7byamX/kgEo/i793CMLX + FfqUPv2ePeLv1Yv/Cgj6tdNDE5NTuvMCWCuFhYV/feyxx9Igo7vAZzV7BP5xioHu7u7vDgsLa+Btj/ri + 3zjCf1vKPmNMWTvGlAkTSN8xpTSQssNGcBJGcEoxgm1zit22FNFA9JYNRXFasOkII3CGEbjBCDgt8IUR + IC1YDSE/GQ14IxrwEkXCDHKby4URKEVCh+kKGQ0gLRhrotMjbWQ52Enm/d1kDuGc7Owjs9YBMm2EEdQO + k0nlCBmXwgTyEQ1kjwsTMEkd15nAyRiYQCSbAFKBwEGy8BsgK58+svHuITvvTnLwhgn4KCbgCRPw9a2l + AJhAsG8VhflXUBRMIDa0ghIjKygluoLS4yuRClRRXno1FWXXIhVAFFDSiFSgWZcKiChArgrsqgfolgfl + C1KXY/bu3p0mC4FcCRcGwOfaa5YA9QVA5P8QHTcA7eC5E/k/DEDJ/38N4XL+r23/VQ4A0RmA5FLif0k9 + xVc78794kZlft6NPXeM3rPTrxd+nmfX1wlfEry/oHSz8risu9P3Fz7ApaxuDeJu8s7Pz1Ac/+EFeEvwK + +JjcKfiPUQzktX8fH59bUlNTn1Pf3FOcj362gAoQ+ueDPJADA8gGmRB/hjSCVEQCySAJJpAIE4iHCcSJ + tMAaRmAr0wInGIErhW4gLVj3pqA1PxhBkJIWLEfCCGLJe1EWCeezyHUOacFsETnOlJH9VCXZTtTCBBrI + aqSFLIfayaIfRtDbTac6e2ECMIJGGEEd0oIqGEHpCJkWjJEpTMA0A2MaSEEakAADiBlFJDBMp0JhAkFD + ZBnQT1Z+vWTj2032Pp3k6NNOLj6t5O7TRF6+9eTnV0cBftUU7FdJ4QGVFBVcSXFhlcIEUmMrkApUUU5q + NVKBGpkKNCAVaBKpQL2aCjR37K0H6EyAX6Q9uw2AZzmNAezuAty9AjADcXEBkDsA186cEQ1AZ15A/o98 + /AW5/r/r+K8/atb/DQxALfgZrvXzwSG6Rh8p/uel+LnVWOzpl+JXq/2zGvFr+/p39/Sr+b66vDeo6+LT + Fvi6dRV9vfivtKBfD/P4v1QD4II5Uudf33bbbW6Q07fADfK8gH+MA0RhAFcHBAS4VFdXv6wW/3YurFDL + GR8q2TGiYoi+EAZQgDEP5AojMNUYgdkBRmAFI7CBEdjp04INGMG6khYEcVqwirRgJQwmEE0+S/EiLVCi + gRxymc1HSlCMaKCc7CaRFowjGhhFWjDUipQARtCLtKATaUFbL51s6iezOkQDVaAMqUHhKJnmQPyZEL9q + AomKCZyKRCoQhlQgeJAsA/tgAkgFfJEKwAScfNvI1buZPHwaydsPJuBfS4EwgVC/KooIrKTo4AqKC6+g + JEQBaYgCspKqKBdRQAGigJJ8TSpQ3UwNhqlAB0ygc7cJCORs1dPbu6cWoGsE0hmAZgVgeVkUAJe3tmhd + FgDPIhfnAiA35LAB/ELu/zc8/pv7+f/8Vz2G4v+dtstPLvcpO/s04tfM/MvbO2IlgluSWfxT6swvD+3U + LfNpOvvErC/FL4p8UvzdDB6HLoPi3t9b1PycXA6dgN+lST0whE8ShnbomWeeKYGc7gc3aZYE3/rFwMDA + wPcj/O8YhSsr4f8LtHy+h+og5iqE/uUQfBkogQkU7ShGkC/NgI0gSxpBujSCFHxfEkwgcdsCRnBaMQKZ + FkQiLYjYcIERuMMIvJS0YBVpwQrSguUIGQ0kkOd8qowGkBbMIC2YRlowWUl240gLRmEEw810egBpQW8H + WUBQ5m0wgiakBvUDZFYNEygfJrOiETLLHSWzTJAKUkAiooC4EToVNUwW4YgCQgboNEzAOgAm4AcT8GuH + CbSSqw9MwK+BvP3ryT+gloL8YQIBVRQZVEkxSAUSIpAKxFRSekIVZadUU15GDRXl1FIpUoFKkQo0iVSg + UaYCrS1yabBdMQFRD+jq3WUCPWphUNYCtKsAuhWASXkOIBcAl7kAqLwJyPpZ5P/P6Q8Audj6vyr2S4nf + sMuPxX9B7OnXz/xrhuLH3zQlN/WMasQ/OMHFvjFZ7BsRhb4eFr4Uf3e/Inw15O++qPghwr+zyFWhHwT/ + bet47LWdgUijl97//vc/A0mpm4TerykGvjVvrq6u4rTftLS0n2nD//Ez6dSwc4LqEQHUwgSqQQUEz2ZQ + CkRUsKNGBaZID0xhBmaICsxgBCcpdRtGABNIggkkIhqI37KiuC1ritm0pehNB4rcQFqAaCBsw0NJC1b9 + KGAFaQGiAd+lKPJZjCOvhSTymE8n97lsckU04DyDtGCqnOzHq8h2rA4m0EhWAy10ug9G0AUjaEda0Ixo + oAHRQM0gmVWAIhhBHowgC6SCFJA0QifjkQZEwwQiEAWEDpBVcB/ZBPaQnX8nOfjDBPxgAn5N5OHfQD4w + gQCYQDBMIIxNAKlAbBjXAyqRClRRhkgFaihfpAJ1VMapQKmSCjTUcCrQvn89YJcJ9Mh6gAx5tasAcglw + SN0EpOkAXJQFQDX/P7cn//+tbvuvoQFo2U/8v9gj/p+JAuPO86r4z+nDfvXdeWVfP4t/GOLnNf494h9S + xa8s74kZX/bq71fBNxRx598wc19JeH+AticgISGB0wBfTTHw/73ljw2zt7e/GhGAd01NzctKZfN5OnNh + lfrPeFDrznFqhgE0gQYYQN22MdWASmEEpogKTJEimCIqMIURmCIqMKXcbTPKBpkgHSaQhmiAjSB5C0aw + dZriN9kIbCh2056iNhwRETgjInCjsHVPCllDWoBoIEBEA+EwgmhEA0gLFlJgBJlKWjBTQE5TSAsmKsh+ + rIZsRxANDCIt6G8hy+52Mm/vJPMWGEEjooFaUDFAJ4thAvkge5hOpoPUYTqVjCggASYQMyRM4HRYP1mH + 9JEtTMA+oJMcYQIuMAE3mIAnTMDXv44CkA6E+NdQeGA1RYdUIRWoQipQRWlx1ZSZXE25aTVIBeqQCtRT + eVGjUg+oaqGG2jZqUlMBWQ9ohwl0dHE6wC9O1QBwrdYD+mRHIB92wTUA7QoAFwBhAFwAXBINQGr+/wLy + /5/SCz9H/v9Lw/xfvwLwRwPhHyT+n++Z+X8qmow2NeLn9yCYE+KXYb8Q/yzErzT4iGU+2darq/Sz8AfU + Wb9vl/i7DJbtDAXe+XcU9OXRLegA/F4N2p4ApAGvHjlypOKaa675oSwG/vdV+vcReGsagI+Pz39ERka2 + 6t/k8wVaO9dJvdunqAsRQAfE3w7Rt24bUTPGRoyKEZhQFajYVoygFGMxxkKM+dt6I8hCNJABE0jjXgJE + A8lbljACK0QE1hSHaCAGRhCNaIDTgvB1dxgB0gJEA4ErgYgGQslvCWnBEtICRAMiLZjLRDSAtGC6iJwm + kRaMIy0YqSWboQaYQBNMoJUsO9rJorULJtANE0BEUAkTKBmik/kge0hnAubJIAEGEDNIFpFIBcKQCoT0 + kl1QNznABJzYBPxbyN2/ibwCYAIBdRTIJhBYQxHB1RQTVkXxkTCBmGpKS6imrJQays2opcIcmEBBA5Uj + FaiuaKa6aphAfatoEOJUgOsB7R1IBzq7hAkoy4M9uwuC3CEoDUBtA+YeAF4BmFQLgKtrtLypNgBdEOv/ + av4v1v/l+//91tAANPzhcsTPXX67xH9Win9TnEOoK/ipff3yuG6u9Per4hfr+2qVX8n3u7XhvnatXb02 + EHrHGyzyi4Lnjf9O3SnZ8sgwZ2fnxf/3//7fCUjrm/Lw0LduZ6Dc9//l5OTk59R/5MJz52nhTAYNYvbv + 3z5BvTCBboi+E0bAZtAG8bMRNIF6GEAtqIbgK0H5tmIEJaAIFMAA8kAOTEA1gvRtQyOwgRHYwQgcEBE4 + ITVwhREgLVj1puAVfxhBMPkjGvDjtGAB0cB8MnnOIS2YRVowjbRgspgcx5EWjFaT7RDSgv4Gsu5pptMd + SAtaO8i8CUZQ10OnKvvpVMkgnSoEOTCBjCE6lQqSh8g8EQYQO0CWkf3SBJAKBMMEAmECAW2KCQQ0kTdM + wC8QJhBQQ6FBNRQZAhMIr6b4qCpKRhSQnlRD2YgC8rPqqCivnkqLGqgSUUCNXBVobFC6BFvxdylRgCwK + dioHi+pSARkB6FYB1HcDgqi0BcAFtQAIQW7zYRWc/8MA9uT/f/ijLgX4w8XEr2nxFWv9qvh/qhf/uqba + P6+Kf1GKX23t5TV+eXqP2tmn7ehTi3xqoW+/Yt4bLuh9BK6l4wCmZ/RpwCoiMl4NuPHGGz0gr7vliUFv + 3Z6ApKQk0fxTVlb2ilLRfJ7OX1inmR1PGoMBjED8Q2AQ9O+wGRjpzKAdY4tqBFvG0ghMYAQyKtjPCDgi + QFqQCRNIQ0qQChNIhgkkIhpIQDQQh2ggBmlBNKKByHWkBatIC1Z8KWglgAKXQ8gf0YDvQgyMIJG8EQ14 + zGaQ2zSigUmkBROl5DhaSfbDSAsGkBb0NJJVJ9KCNkQDTUgL6pAWVPWReSmMoHCATuUNwgRgBqmDZJ4C + EgdgAv1kGdVHVuG9ZBPaTXYhSAWCO8g5sI1cA5rJI7CRvAPryS+ojoIQBYQFVVNkaDXFRlRTIqKAlPhq + ykiuoRxEAZwKFOcjCijWpwLK0mD7rqVBNgGlHsAHieg7BHXiYLFwYwzXAnglgDsBZ5QmID4DQF3/P4O8 + /PyLe9f/1QIgd/OpBvAHubHnouJX+/t1M/9zotC4op35l6X4ZWuv2t03IHv6lXx/WFfl7wb8/6jV/YMq + +X8XUV+moF8L7Z1KGqC+nyBriBvpHn744XzIi99a/Kvy9GDt24m9dW7W1tbc+5/XjQdIKf49TzvnhmkW + Ap3aPkYTMAE2glEwrBoBhN+HsQdjlzQCNT1ogPjrgEgPtmAGQI0KiiH+QpAPcrdOUvbWKcrcMqd0YQSn + KQVGkLRpQwkbdhS34UCxG84Ute5KEaseFLbiDSPwp+DlIApcCiP/xSgYQTxMIIm85tLIYyaLXKcQDUwU + keNYGTmMVJHdAIygF9FAF6KB9laygOjM67vIvKqHzMt6ybwYRpAHI8gcIPM0ACOwSIQBxCMKiEYUENFD + tmFdMIEOcgpGKhDUSm5BzeQZ1Eg+QfUUABMIDqqlsJAaigqrprioGkqKraG0xBqkArWUl1lHhbmIAgoa + qaKkiaqQCtRWt1JDnVIPaJGpQFuHYgLt7Z3U3NxGNbX1VFVdQ5WgrLJKUF5VTeV8X1091TQ2UUNrG7Xi + Oevh9wyYmBARwer2jkgB2ADU9f9falYA1AhAi3Zbr2j0+fVvRO1AJ34582/tEf+6FL9+Uw+Lf1CKv38/ + 8bPwpfjVWb/TsLJvIPKOv1HkV0roF4MjtU08JmoU0NnZSVZWVsPvfOc7nz4gDXhLdf/9d1xc3Jza+/8c + 8v+NM8U0v30cJnAMkcAxmob4J/GxMAOMI0gLhsAA6IPwe7dlVAAD4PSgBdFAE4RfD2q3TKkaVIIKUAaK + t2AEIB8mkAsTyIEJZMIE0jctKXXzNCVvWsMIbGEE9jACR4pZd6GoNTcKRzQQtuoLIwigoOVgCkA04Ido + wHc+ASaAtADRgPt0DrkiGnAeLyHHEaQFg1Vk21dLNt0wgg4YQQvSgoZOsqjuJovyHrIoRkSQ30/mWf1k + kQ5SYABJbAKIAmIQBUTCBMK7yCEUJhDSTq7BreQe3ExewY3kGyxNIBgmEFpD0RE1FB9dQ8nxMAGRCtRR + nkgFGpAKwATKmqkaUUBdDacC7RB7BzU2tlF1DUyirIIKi4qpsLCYiopKqKS0jErKy6m8spIqamqoqq6O + ahsaqL65GeJHFNHRQS1dXdTGouE8mmsF3CkIM5hFLr6FmehFiFgtABoawO/kx3rx/07sGNR1+UH83E3I + TUVC/Of2in9Khv2GM7/a068U+7Til8Lv3X+t3lDMHZI3WtCvB+0OwXk8Joiqz1933XX2kNh3NWnAW2s1 + QL7b7/eys7N/oTv448IZWtsOp6WtI7QIA5gHc2AWwp8B02By6ziNQ/yjuB7GOLitRAVsBD0wgC6M7TCB + VtAME2gAdaAG4q/SGYEZlQgjOEkF0giyN2EEmxaUARNIgwkkIxpI2mAjcIAROFHMGhuBByICb0QEfhSy + HEhBS6EUsBgJI4gln/lE8ppFWjCdRW6TSAvGC8lpFGnBYAXZ91eTbXcd2XQgLWhtodOYgU/XdJJlOYyg + BEZQ0EsW2SC9jyxT2QT66HQCooBYmEBUN9lGwATCkAqwCYTABEKayTu0kfxCGigwuI5CQmspIryWYqJq + KSG2lpITaigdUUB2Rh3l5zRQMaKAMhkFsAlUlNdTYUEZ5eYVUm5uIRVA+Cz60rJyKiuD6DHrV1RVIQqo + pqraWqqur6e6xkZqaGmhpnZED52IGHjW5M453ifAJwVNKO8WJA4LAdN4Ia5tbdGLELO6CqDCNQE17Gfx + 72rx3Vf8Z/aKXxf2K0d3Kct8Mt8Xy3yaQl+fFH6vfqbXFvjeeqLuuijtKp0KY3jsOQ14/nnloJD09PQ/ + 33777VGQ2Q80qwH/9pZqCoIB8PKfAy9dKMsYL9C587O0tmlHq5tHaGXzKC1vHoMZHKWFLZgBmJVMb0kj + AKNbJ5SoAOPAlhIV9GwhPYAZKEZgIoygUUQFpruignKYQCkoFkZwivI2FSPIQjSQsaEYQYowAjtKZCNY + d6ZoRAORiAYiVnwodNkfRhBEQYvhFLAQTX7zceQ9m0xeM+nkMZlNbuP55DJaTE5DpeTQX0l2PTVk09lA + Vm1NZNXURla1HXS6sossS2EEBTCCHJDBJtBLlsm9ZJXYS9ZxPWQTjVQgspMcwtvJOayNXENbyTO0iXzY + BBAJBIbUUWhYLUVG1FJsNEwgroZSk2opE1FAbibEntdIxYgCCvKqKTOjiNLScikrM5/y83jGx2xfXKYx + gAoqL6+SJgADqIEBIPSv1RhAK7/4WExcGxiWTULcIoyZeII3CfFBIfx+AbxcCNaFEbwkVgN+azDz7yt+ + 3tP/nH7m51bjebnUJ8J+bWuv5vQetdIvxK/r5uvVhfv75fJvVZF3GIj8YnBx88yZs7quwBpEbY899lgl + ZMZ7A257SzYFIUx5F+f/6vv9CQM4y8saRrS2cZRWJcIIMC7BDBY2FSOYMzCCCTAGRrYUIxgE/TCBXozd + GDtgBG2gZdtEpAdKVGCqRAWbiAo2pRFsnkRUwEZgTjkbFpS1wUZgRekbMIJ1W0pat6eEdUeKQzQQs+pB + kSveMAJfGEEgBS+GwggiyH8eacFsAnlPp5DnFNKCiVxyHUNaMAwjGEBa0Iu0oKuWrNsaybq5hazqEA1U + wQjKYASF3WSZCzJ7YAI9dDq5GybQTTZxXWQb00n2UR3kGMkmgCggrIW8wmACiAL8QXBoHYXBBKIiYQIx + NZSYUEtpKXWUlV4PkBokFMAYsik1JY+yM4soN6eY8vJKqKCgFOZQRsUlbAKKAZSVIe+vkAZQWycigFrO + /WEAze0dMAC8gLmQxo1CvESoOSdwUhrALPcJ8GYhzNYzvGwINiHmn/3yl/tv7tlH/Ksy7J9XC34LUvyi + u0+/m29XZ58a8uPv61SF/4aJ/7XN3FcK/l/WNG8mypqysrKafPvb334cUvsO+F/wIc3egLfEEuBHoqOj + 53DTdf/tbBXSxtoRWmfWj+KfUhBGsKEawVFa3JBmAObADJiCIUxuqlEB0oMtTVSwpUQFnZuICjZNdFFB + A67rYQC1oBomwEZQBhMoQSRQBPKREuTCBLIRDWSyEazbwAjsKGnNgRLWnCl21Y2iV5RoIBzRQOhSEIwg + jAIXosh/Lg5GkAQjSCPPySxyH4MRjBSS8yDSgj6kBd3VZNNeTzbNTWRdByOobierik46XQzyuuh0ZhdZ + pcEAUrrIOrmLbOI7yS4WUUB0BzlFIgoIbyWP8GbyQhTgG9JIAaH1FBxeT+ERdRSFKCAutg4mUIOIoJgi + wjIpNiqbUpLyKT2tUEQB2VnFCP9hAvklyP1LqYijAJiAMAARAdRQZY0Uf0MjUoAmamxppVbuHeCZVYT/ + cmWA3ymITwmSBjCtGoA0gXkG1xwNzC4s0A5mKe4T+Jl4555fiMIhi//sLvGfMaj2y7fpEt19U3KNXxF/ + nxR/9wHi79gj/L3ib38dov57Cfr1wOcFcgqgnhGACPvChz/8YTu5N+BGeXT4W2dvAPL/mzMyMl7iFkbF + AM7T9noYba0+C47QJthYVcxgjVk/QquqGWBcYnC9ADOYB3NgFkzDBKbABBjbPEGjYAgMgL5NGAHoghF0 + QPxtMIEWTg+kEdSxEWzACDZOCiMo3TKHEZhTAYwgD0aQAxPIRDSQjmggFdFA0pojxa+6wgjcYQReFIVo + IHwpgEIRDQQvRFAAogG/uXjynUZaMIm0YBxpwUgeuQwVkVNfGTl0Iy3oqCW75nqyrYcR1MAIKmAExR1k + lddJ1tlsAhhhAjbJnWQrTABRQDSiAJiAWyRMAJGAd0gT+YU2UGBYA4VE1FNEVD1FRlVTUFAuBQamIyrI + pfi4fEpMzEcEUIgcsQgpQDHlcBSQy1EAIoDichEFFBWVvpyZnfv72PiEnwYFh5xx9/BcdXZ1XXJ0dl7A + uODh7b0UEBy8kpSWdq60svKlls7OPyL8foUNQIT/HPZrDcAA/hynCgsQ9gXRNvySTvzbe8L+veIflt19 + /a9z5t93Oe0KheJvFm0dnaIOwJ20bAJbSLkSEhJ+8/Wvfz0SUntYHhTysbdMV6CjoyOfAHSyvLz8T8oa + 5vN04dwKba8409bSM7S1fBQcoa0VGMHKUdrAuL56VLC2yoYAI1hTjGBZmMExWgQL66oRHKdpMAUmwLg0 + gmEwCPpVI9gwRlQAIwAtEH/zJkcFMAKYQA2oggmUsxHABIphAoWblpSPaEAxAhvKQDSQimggadWJElZg + BCseFLPsTZFLfhS+GEihCzCC+UgKmIslv+lE8plKJa/xTPIYySG3oQJy6Uda0F1ODh3VZN9SR3aYaW1r + m8imspWsS9rIuqCDrHNgABmdZJMKEjtgAu1kDxxj28glupXcIlqUekBYI/nDAIIjYQShleTlm0V+AZlI + C3IpMjKPYmLyKT4+n5KSCigttZAyOArILkEUUEKZWfl/iYyM+bmDg9Pqj3/82OC3vnV7y1e+8pX6z3zm + M5XXXnttycc//vEiUAgKQP4nPvGJ/C9+8Ysl3/zmNyu/d//99RZWVgMJKSnrtY2NPx+dnHx5Zn5hXwPg + 2X8an5vkvflyW/EGBK+I/3lxvarJ+fVh/7x+U49m5u81mPm7dct7Sr++rpKvVvbfgjP3ZYtc0LkvrTAA + PiNAfSNRNoLi4uJXHnzwwSLI7Qm5Rfi6t8xyoJ2d3dXI/2NbWlpeVfP/s9v9tDV/ijbnn6XNBYh/ASaw + CJYUNmEKGxg3YAxruF6HMayBVZjCCsxgee0YLYFFsADm2QzAzDqMAEyC8Q0YARjekFHBhhH1gW5pBBwV + tIJmmEATqN8w1RlBBVKCMhhByYYFFSEayF+3otx1a6QHtpSxZk8pq44wAhcYgTvFLntRzJIPRS0GUPhC + MIXOh1PQXDQFzMST31Qy+YwjLRhFWjCcR64DReTcg7Sgs5IcW2vIvrGe7OpgBJXNZFPaQjaFbWST2042 + me1km9JOdokwAOCQ0EZOca3kEtVC7pwKhDeRb0QjeQVVkItnJnn7Z1NgSB6FhOUhLchDWpBHsYgCEhLy + KTkZJoBUID4u4w+Ojm6bP/zhwwM33XRTPYRdzoLHWPTJT34y/1Of+lQuyLr++uszbrjhhlSQ8ulPfzqJ + wXXi9Z/6VNJ1113HpODr0r91++3FFpanO3MLCjYHR0f/OKsR/owQv1IY5EiB6wWigDc2hkhugzbPnRdh + v1b8fOQYHz02qm7qka29YplvcGhXPz8X+zp79C27e5tm/nEELeh4bfD/vYGUSU2n29ra6Pjx411vf/vb + jeRy4GcM6gBvXhTg6ur6noiIiNpBuJauALhZT1vTx2hr5ohgcxbMgXnmqDCETQamsLGomMG6hA1hdeWY + MINlsCTQGAHGGTAtzWACjK3rzWAA133rRtQLI+CooGPDhNpBC2iCCTTABOrWzah6/SRVbsAI1i2EERSu + wwjW2AhsKGvNjtJXHSh11ZmSV9xgBB4Uh2ggBtFA1EIghc+HUshcJAXNxFLAVAL5TiST91gGeQ5nk/tg + Prn0FpNzVzk5tlWRQ1Mt2dc1kF0VjKCsmWyLWsg2r41sM9vILq2N7JNhAElt5JjQSs4xLeQa1UwekU3k + GlhB9h4Z5O6bTT6BeeSPFCAoNJdCw2ECUXkULaKAAkQEaX+0tnbe+M537umGuKswq5dC8MUQcQHIxn3p + LPL//d//jUMUEPnZz3429HOf+1zQ5z//+QDg94UvfEGAa3++jz/HX4PviYAZRCM6SDly7FhNTn7+6sjE + xJ9V8U9qxD8q32qbxcyrCdOLS2JfgRr2T6nV/ml9a69Y4x8app7BvSF/xwHCf7PFfyVFfimWV1boec32 + YBsbm4X3ve99VgZ1gDe/LdjLy+vamJiYqXlRuGADuEBnl3NoawL5/+RRhSkYwTQEPw0DmDkqDeGoMAOB + NAQ2g3WwxsAMVsHKssIyIoQlGMMim8EqG8FxmmUjwDgFJtdO0DjGURjAMK4HYQL9bATrxtQNOtdhBKAF + NK/DCNbZCE7CCE5R5bo5lbMRwAQKYQIFiAZy12wpa9We0lccKQ3RQAqigcQVL4pDNBCDaCAS0UD4XBiF + zEZR4FQs+U8kku9oKnkPZ5LnINKCPqQFXSXk0lZBTk3V5FAPI6hBRFDeSHbFTWSX10x22S1kn95KDimt + igHEwQBgAk6hVWTjmUUufrnkAfF7AV8YQEBILgUjCgiLzKfwyJxXnFwCX7jvvh/0f+pT11dhti+FYIsg + +jye5aXooyHmEBY3hOz5pS99ye2rX/2qyze+8Q3nm2++2QHYILc8DSyYr33ta5b4vPWXv/xle3ytM/eh + 43t98bOCvvTlL8danD5dW11ff358ZuZVQ/HzBiNeRejCLM6dhbyRhw8Z5bBfOchDbfAZ04tfhvxdr1P8 + bW+xmftKMoPHTF0JWIDpIs1+4b/+679cZR3gawZtwVe/mSsAX01JSXmRixViA9D5bdqZDqPtERjA6BGF + MTAOI5hQDGFTABNgUxCGIJGmsCFZX2AzOCZYZZaO0QpYWoYRgHlmBUYAY5hZPU7TYBKMwwDGwPAqjGAV + RrBmjKjAhLrXTKgLdOC6DSbQDBNohAmwEdQII7CgClC6ZknFbARrMIJVW8pGNJCx4kRpK66UvOxBiUte + FL/oSzELMIL5EBhBBIVMR1PgZBz5jyWRz0gaeQ1mkkdvHrl3FZFbeyk5N8MIGmAENbXkUF5PDsWNZJ/f + RPY5zeSQAVKaySkJhhBdS6d9c8gBoncNKiC3oHzyBN7B+eSHNCAQBuAXmPanI8fMFz//+S/WQ/hlcsZX + hZ+AmT6cZ3Pk/v4Qud+3vvWtwLvuuiv47rvv9r/nnnu87r33Xrfvfe97Lvfdd58LRrf777/fFdd2+Pyp + 73znO0Z33HHHs9/85jeP3nLLLSZsDPg5tjADF/xcn7u+85342ITEEQj4j6r4WdScx/cglO+EAXBnYUNb + u6jwT2hmflX8vX8n8b+VBX0QrfvSQSNIkZRCoHJMWEJCwu/wnIYZ9AO8703tB/jYxz7GBcCHCgsLXxZ7 + mdkAzq3TzqgLbQ88S9uDR2h7COJnho/CFGAAo5Kxo8IUNpkJaQpTR/WmADZgCutzxwRrzDxMYAEmAJZh + CEtLihEsLB+HGRynOTADQ5heOUGTYAIGMA5GwRCMYGAVRgAz6FlTzKATtK+ZUssaG4EZ1cMIatdOUdWa + OVWsWVDZ2mkqgREUrtpQ7oodZS87UsayM6Utu1HyEoxg0ZviF/woZj6IImdDKWw6koInYyhwPIH8RlPI + ZyiDvPpyyKO7gNzbi8m1pYycGyvJqbaaHCtqybG0nhwLG8kxF2Q2kUNyHVlgprcLzkMUUEDOIfnkBjwg + fi+MvqFIL7zif3P/Az8ewWxfifyeZ/0CCD8Lwk9k4WOmD8AMH3z77beHQ8wBELwrhH0SAn8KQn/0gQce + eOiHP/zhDx566KEHHn744e8/8sgjD/zoRz/6IXgSH5sBK3zeCl93At/zY/yMx/Cznrn11luN2AxgBA6I + EHxd3NyqWzo7f8HhPM/8qvi5q5Cbi+pbW6mupVVU+UW1X4b9+4lfzflZ/O37VPUNRd76Dybyg4W+V/hM + S3u7eCu3c+fOCwPggmBeXt6f8VzkQnbPgjvBp+VZgW9eIfADH/gANwHZ19XVvaoeAHJ+Z5Z2+i1ouxsG + 0AMD6IXw+yD2PphAP4Q9AAbBEO4bPkabMIVNGMImDGGDEYZwjDaEIWCclszACMDaLEwAZrA6fxxmcBxm + cJyWYAhLMITFxeO0sAQzALNgGoYwtQwzwDgGQxhdMaJhMAgj6Ae9oGcVUQFoXzWl1lUzaoIZNKzBCFZP + UfUqIoJVSypbtaLiFWsqgAnkLTtQzrITZS65UNqSO6UselHigg/FzftT9FwwRc6EU9hkFAWPx1HgaBL5 + D6WRT38WeffkkWdnIbm3lpBrUzk511aQc2U1OZXWknNRPTnl1pFldD5ZhWWTI0J8x/B8cgrLJ1fgDuF7 + YrR1i/7Fnd/5fu8nP/mJiuuu+2QJz/o33HBDGof6yOODIPxQzN4sfE+I3hTifwyi/wEEfR8Efvdjjz32 + nSeeeOLOp5566ttPP/30Hc8+++ztWp555pnbcT9/zQ9//OMfn8D3WMAQnoUZPIio4eE777zzCUQGx77+ + 9a+Z33TTTQ6nLCyzapuafsLi59CfOwq5sYj3FzQiAqiqbxCbjZQTe7XiV/r5O3XLfEqVv11b1e/S5N3/ + 4ILW0X758CqI9g1Eq6qqXsFz0gTZ8fkA98h9AdpTgt7425EjR66BAcR24J9TdwCeXemi7Q4T2m6H+Dsg + +k6MTBeuu0EPhN+rsAlj2NCZAkQOU9iEKWzAFARjuB5X2JxUTGEDUcI6DGGNgSGswhBWGJjCCiKEJbAI + Q5hnYAhzYAZMwxAmlxAVgNElGMEyjGDZmAZA3wqMYAVGsGJKHcum1LZiRs0rJ6kBJlC3ak41MILKldNU + vsJGYEOFy2wEjjACZxiBK6UvelDKgjclzvtR3FwQRU+HUMRUBIVORFPwWDwFDCeT/0AG+fZmk3cnxNxW + RO7NJeRWX04u1ZXkUl5DthmFMIA0cojLJceYPHKMQhQQmUcu4XnkBqw9Yn7xzTvu7vrEJ64t41wfs342 + z/rI8cMwIwdhlo5EmO/FITyL9Qc/+MH9LPrHH3/8LlXsx44d++bx48eZ206cOCEwMjK6lVE/5s8x/LUw + hPvw/cfxwjN99NFHOXJAxvC9H+L3PH7bbbcdx++1PGZkFFdZW3eBG4pY/M14LTS0tVF9S4toOS6rqhIt + x2pPPxtFJ4yig0N+zax/0Jq4VnBvvqD/NlFfkjaVdrFZaU1zQEgrIipjY+NByM4MPKA5LPTNKwSampq+ + LTQ0tHIAT+wLL7wgUoCzszW03XyctpuepZ1mCJ9pOUI7bfi47Ygwhp0OaQpgS2cMR2izFyNMYVMTKWww + SB82RiVjStrAkcIGUod1mMIazGEV0cIqTGEFLMMYlmAKizCFhTlEBGAOEcMsmEbEMLmA1ACMLcAIFo1o + aMlYmEH/sgn1gG4gjGDZjFpgBI0rp6h+xZxqly2oio1g2YpKYAJFiAbyl5woZ9GFshbdKX3Bk1LmfShp + zp/iZmAEU6EUMRFJoWMxFDycQIEDqeTfm0F+XTCCdoT1LUXk0VBKLhXFdDophRxSMskxKYccEwCMwCk6 + l1yicsnaJ+43d9z9/V6E/Cz+QhnyxyMnDEKOH4qZOQyitMCM/ygLH2K9+8knn7xTI3qd2PEi0nKLiYmJ + gK+1n9MYAxvBg4gKzGAGj8MMvstGgPTg4W9/+9tPfe2rXzVBJBBXWVf/ohA/Zvz6ZkX81YgAKmpqqaSi + ktr5cBIR8vfuyvd5H/zFhK8V5yWFDBFpMRRY22sSZDu+XkPbfrRJ+O3b2i4NUqK2lraDaZbguh0/c2lp + WWcArDEbG5v5d7zjHTYGhcA3b2PQ6dOn3x0dHT00MTGhRADPv0BnxvNouxZirwP1CtsNGBufFaaw3Yxr + NoRWSfsRGS0gVehEZNClsNkNEC1saiKFjQHFENaHpCloIoU1BpHCKtKHVRjCCgxhefq4YGnmOC2C+VkY + Acxgdu4ETWOcnkdEAMbmjWh0wRhmYExDiybUj7F3CUawZEqdS2bUzkawdJKalsypYRlGsGRJ1UswgiUb + KlmEESw5UMGiE+UuwAgWYATz3pQy50uJMwEUOxVMURPhFDEWRWHDcRQ8kESBvWnk35VFvu255N2ST/YF + KWSfnkjOmRnklJ5JTilZ5JSYTS7xOWQfnvKne3742MgnP/nJcin+TIT8sVzkQ14e9t3vftcfs/5RzMwP + Ily/F0K9i4XPM71W9KrQXyuqUcBIvgNTOQ6eAndxdIHU4AGuEdxyyy3Hnd3c0qobGn6rzPxNhGux9bgS + BlBcVi5GbTvvQTP/HvFrxLsfV1bQGi5b0PvQvFvMiriV+9t33d96kZ/RgolrTmcAk5OT5OrquvWhD33I + HdJ77CrlbcSvfVPfNAR/0McTExMXeZlClwLgBb5T8RTtVD1DO9WSGoi+VgJj2JamsN0I4TdJOFJoZWAE + bTCBdggfprAJU9iEIWx0IQXoBjCFdZjCOkxhHaawPoD7kD6sD2FE+rA+AiMAqzCEVRjCyvhxWpmAEcAU + liZhBFPHaQGmMDejMDMLMwCTYHzOCGZgTCNgaMGEBmAKfRh7FmEEoANm0AojaF46RQ2LFlS7aElVi1ZU + sWhLpYv2VLQAI5iHEcy5UuacB6XPwgimfSlhMoDixkMoeiyCIoZjKGwggUL6UiioO4O8GjDz50aRW34S + ueWmkGtWGrmkp5MLogHnhIxXHjM1X7zuuk9VyLBfiB/5vj9y8VCI3wu5/pPQ4fd5ZsZMfQfP+Brh3/J6 + hb8f+LlcI3gWBvA0fte3Ob3gaAB/wyOIQo5HREdXY9b/C8/8vPGIRc+bkMoqK6mguJga8aJWW3i1Ym+X + vDZRX2FBHyjIfcRsOGNfpqCZ9ovR1KwHJjo9PqFbCVheXualwJ8gCgyC9J4Ct8uOwDdvZ6Cnp+dX0tLS + zujOADx/ls50hNJOCQyg9BnaLoP4yxkIvwKCZ6ok1QDGsF0L0deBetCAFKBRYwgtMAKYwhZMYbNdIkzh + GEyBzQCCZ3pBH+jHfTCEdWEIx2mNGT5OqyMwgVGYwJjCEkxhEaYwz8AUZpkpGAGYnEZUMAMjACOzMII5 + YxqYM6E+0DtvSl0LZtSxcJLaFk5Ry4I5Nc5bUN2CFVUv2FDlvC2VzTtQMUygYM6F8ubcKXvWk9KnfShl + 0p8Sx4MobiyMoocjKXIwjsJ6E8m9IozciyLIqziePAoSyD03mdyyUsgtM41O+vi88Pkbb6zjZT7O+bmZ + h9f0kX8H89tIQ3iPPfjgg99jIcpZ/6AZ/2Y5m98GvmnAbdqvuRT4+d986qmnjoAnjh49+i1ONTjyQPrx + 0EMPP2yWmZs7LcRfXSPFX0VlSAEKi0swVsiZ/uLhuz4nvpSw2/QcKOrLZL9ZWwi3FeKUs/ouQSuj8rmW + XehF3WwgakXYTAfTwDTqqddQ10Djg0PybIDnxZ6AyMjI33zuc5+LkSsBd8mVgA+8aSsBXl5e38nMzPyp + 6FtmA9hZo50GL9ophAEUQfRFEH8xKGHwcSkog+iZcsUQdioxVkLsVaAa1BzRmMJRxRQaYARNoBnAFDZb + YQBtoB2C7wAwhA1ECetIGwwNgVmDKawNwghgCCvDCssjJ2gJprA0doIWYApz4ydobuIEzYDpCSOEXEY0 + MWVE49PGNDqD9AAMziA9mDWlXtA9Z0adcyepfd6cWuYsqHHOkurmrKhmzpYq5+ypfM6RSmadqXDWlfJm + PChzyovSJnwpZTyAEkdDKH44gsK7wsirxI/8y8LJtyyKfEpiyasgnjzzEhEBxPzpOw8+0P+Ja6/lan8u + r+9z2M/r+hC/LwT3OFf3uarPQjxo1meRIyq4+8iRI9+HSfwQPAJ+hI8fkfwQ3/99mMd3NWZwKRO4HQZw + nH8eRxy8qvDII4/ci7/rhw5OTv4lZeW/LJczP4u+tLxcnFFQUFBIDSyAjg49LHoDYbeq4n69IfhBs7YM + wQWXOWPvnbUNRC1QRN3eoGd/Uas0UCdTq1K/D3U0gkjpHL+5LrTFh4Ngsv3LV77ylWRI77hcCVDfL+Bf + 3xQD8PHxeSgvL+83YhMQv5Hk5iLE7Ew7uU/TmXyIXqUAQi98VprCEWUsflaYwjZTyqYAwZeDColqCkzN + UWkKR4UpCENohBE0SWAMmy2KKWzAFNZhCuswhfUuSc9xYQprfTABZuAErQzABGAKyzCFJRjCIgxhgRmF + EYDZMSOaBlPjxjADExqfMqExMDJlSkNgYNqM+mbMqGfmFHWB9hkYwYwlNc5YUf2sNdXM2lLVrD1VzDhS + 6bQLFU67Ue6kJ2VN+FD6mB+ljgZSaIMnBZb7UHBlMMZQCiiLIL/iKPItiH31uPPpjetvuIFD/3zu24fz + h3z1q1/1RM4dCPE/y+Ln2fcg8Uvh3ydF/gN83b34um/jc7eZmpreKuHv+za+7l7+GjYH/h7+3kuYwM0w + jO9A+Mb4+u9yvYFNAJHAPd///vd/lJCY1IBZ/9Wy8gpxMElpWRmVSgMow8gFLhXDELz1cnNqjaD3zNoX + EfVrCcF1NKizddNeUYNOVdBaWMR1uwXdVSPRXHciTeqqBlU81uipqqFB/D9nMblqegFevfXWW7MhPRPZ + EvxF8GHNSsAb3gX4bHFx8V9EDwCfJLs2S9vFNnQm6xk6kwOBq+SCPA35kgKJNIRtFWEKR/SmUK41BZhA + tcImjGGrFtRD/EwDaARNMAIYwgYihXWYwrowBZhAp6QbqQFYhTGs9MEM+k/QMkxhiRk8QYtDMIJhI5of + hhmMGNHMqDFNjcEIxk1oYgJGMGFKI5OmNAwGp8yof+ok9UzDCKbMqX3KglqnT1PTtDXVT9tS7bQdVU05 + UPmkE5VMulDBuDvljntR+qAXhVU5UkS1F0VU+VFYRSCFlIdQUGkYeWYG/uGOe+/sRL7HRb8M7uG/6aab + 3L/97W8H3Hvvvae40s/FPin+Ww3FD0FySvAwPv8Az9a4j6v5t0Ckt8A4bv7e9773deahhx66me/jz/HX + 4Gvv4O/h7+WfcSkT4OiB0wFeKVAjgQceeOAeW1tbu8Kiop+x2EtLSgUlSAGKCouoIC+fWlhUamHskiJX + wmxl1m4V6EJw3edahYAvGYI3GYTgjQfM1DIEV9kjbIOZWlCjIMS8HxB0V2UNdVdWUzeiIzEKqqi7Yh/K + K2kQv+8sZn42AD4luKSk5FVMAKWQ3il5UvCXDN438I274UXIR4GZVyLME8eAsQEsT0LgFrST8axCpiRL + 4QyP2RB3tjLu5EDQMIftPEQF+biGOWzzWAAKAaKF7WJJiaTsqEI5hF8BKgFMYVMYAkQPNuuOwxCO00YD + aAQwhPVmAFNYb4UBtOG+doxMxwla6zpBq90wgh7QCzOAKSz1GdFivxEtDMAIBo1odggMG9P0iAlNjSIi + AGNjMAIwNG5GAxMnqR/0TsIIJs2pY8KSWietqHnSmhomYQQT9lQ96UjlE85UAhPI6HKm6EoHiqv1oBiY + QFSVL0VUBFB4eTCZ+5zauuHTN5Qj9M9B3h//hS98wQfO78EtvJhhf8gNPRCfmPkN832e6Z955plH8Lm7 + MMPfAjHfgu/7+o033vg5GMonP/KRj3z4Ax/4wH/wja+vvfbaT/Ln7rvvvq/jZ97C38Pfy5EDRH3PJVYI + buNUgNMLNiE2pMcff/zORx999AdJiUlNZcWlr5ZC+CVFxTryc3KpFkJob9aL2DCHPjCnbmo+GE1+3b5r + tm46OASvOygE1whaUKtHK2gtlcwBwoaYe3RUKJSB0grqLS3XUEa9JaBYYRA/5wxyfxFdI8quqqoiGGw9 + 5GcplwK/+qadEXj33XezAbjW19frDWBxFII3pZ3UI3rSJOkaMiSZkiyQDXEzwhQYiDzvqGII+XIswFgI + ikCxpASUHqOtMlAOKkAlqIIJVLMhYAQbMIUNmMI6TGG9CTRLWiRtMIJ2GEGHEa10wghgCsswhaVuGEEP + 6IUR9BrTbJ8xzfSb0PQAjGAQEcGQKY0Pm9LoiBkNj5rR0NhJGhg7Rb1j5tQ9Zkkd46epbdyamsdsqXHc + nurGHahqzJkymqwpqdqBkutcKbHWneJrPCm2yociin3++sDj9w184tpPFPC2XQ79v/zlLzshv/aB+I/+ + 6Ec/EtV+TcFPJ0gO5Xn25lmf73/wwQdvxvd/5r3vfS+3jL7jT3/601UQ6VXf+MY3rrr55puvws+4ioj4 + 6XwHvuYDn//85z+L7/mG7Am4HV/LkcDFTOBm/M7vwQSO4XeKXgM2pkceeeROH28fj+LCot+UFRdTKYRf + KsYiKkQEUFJYqJud2/bLpXeF340KB8zOuln6oFxaCpmvu3YJWnNdJQWtCb8VUWsFXb1rhu4RaIRdpoi6 + FymPQBV1STn1QdR9xSql1FdUIugvVCmm/oJiGijgsYgG8plCGsL3ba+sKvU1RNmNjY0Ec+3E88W9AI+C + b7xph4Pgib8mMDAwqKWlRWcAF+aGaCf5BO0kHVVIPkpnUvTsMKmStGMAY7rCNpOBayYT10zWMYAxG2PO + McUUcjHmgXxJwXHaKoTgi0AxKJGUQvgwhc1yCJ+pOEEbVZJqfFxzgtbrIPp6jEwjaDICuK8ZRtACI2g1 + ouV2AFNY7jSipS5jWuw2pnkw12NCs72mNNNnStP9pjQ5YEbjYGzQjEaHTtLw0CkaHDanvmFL6hmxos4R + a2oftaGWEVtqGLKjzCpzyqy1p4w6J0qrdaHkGjcYgif5Jtv8/EtfvbEGuT9X/WN5F99tt93mwJt3ELLf + z2E2h9uG1X6Ij6OCR1TxwzC+/t///d/84ngHIomr3va2i6eI/DX8tYgKPobv/Rp+DpvAt/hncr5/0CoB + RwFPP/00vOIo1w44/eCP78D3P5KbnbVQBtELIPrSggIqyc+nopwcasPE0YEXtEpnA4QMOus1iFl6n1y6 + Vp9Hcw7dedDsXF2tmaWrFUGzgHeF3ZViht6FFLOecszWqqD1M7Re0FLUhQp6UUPIKhC0KuyBvAIazJXk + 5O9iKCePBrMVRvD1mwsLwgA4DeDCKB7bwauvvtpObgpSewHe94YbgJWV1duDgoIi29vb9RHATD/tJMAA + 4iHuhOMAY6LCGcFxOpMEknGfSgpEzCTLMRXAHLbTj0twnQEyFbayIHg2BGkKW7nHFfIk+YBNoeAEjAFj + kcJmCYRfKik7AWMwEqawXgXRVxvRGhtCLZuCkWCtHjQY0WqjMa00gxZjWm41pqU20G5Cix0mtNBhSvNd + pjTbbUYzPWY03WtGk31mNNF/ksb7T9HogDkNg4EBS+obtKKeIWvqHLahhm4ryi0/Rfk1dpRbY0/ZNY6U + We1M6VWuZOv57NonP3ldoWb2t4Mg3RH6cUvud9Sin1b8XLTjAh7uv1MV/3/+539+lCvD73znO696+9sv + Lz3813/lYvJV13zoQx/6yD333PM1TT3hkYMKg0gZbuaoA1HJE/y7ZSrwTW4WSoqLLSgryKcyiL40P4/K + 8vKoFBRkZFBjeTl16cStiloTatfW6j7uFtToqZZUyXwaobFAht49lXJ2VtGG3vi9QtBS1D1q2K2yj6AF + cnYWQMT9OjEDCFmwS8x6IQ9lgcxcjEwOrplsGs6QpKtkacikUXz9Br9dmDQAfqMQGPIIDMBR9gJ8U7Mr + 8I01AHt7+3+BAcTzH6V2AZ6f7KGdOGNwQiH2BG3HGinX8RoSJIkK2zCLbR6TGFwjitCRwkDEqbifScPH + 6Xq2MvC5TIxZGnIkuSDPCGDMh+gLjGizUGGjCBSDEmNaLwXlxjAEiL/CmNaqQDWokdSCehNabTChlUYT + Wm4CzSa01GJKi2ChzYzm2k/SbMdJmuk8SdNdJ2my+xRN9JyisV5zGgXDvRY00Hua+vutqa7xJBWWnaKS + KhsqqrKjgioHyq2CCZQ5vvL4M/cOwAByPv3pT8dh9ve65ZZbTvPs//DDDz/EMytX3A1Dfwjue7yUx/k7 + F/Yw8/OscA1ur/fpveZ//ud/Po7feTP/TP7Z4P6LLAvy5qITGL+l7it4/PHHbwsLCPAozc35U1luDpXl + ZCvgujA9jeqLCqm7lgVdLalSqK7SC7qqUqFSoaeiQg8LGfRqEeF3maCvlIGQSxT6izErc9hdXKIJwYsl + RQL9TF2gwDO1mK3zFVjUUthDglwFFjUYzpQIYWcpQMgjaVkAY2oGUMd0Gk2RJKcpJCmMMYkpNI6v25ic + FAbArfb8rluI/ibwvDrjOXpGNgOp7xb0L2+oAdjZ2b0TBpDS09OjM4BzY520E21KO1HGEiPaxrgdjTHG + SJjB7tFYuWbiQLwkQUOisWCLSVKBqJNBCkgFafgasKWSYUybmbgfbGbiOgv3ZWNkckCuCW3mgXwT2igA + hZJiU1pnSkxorQyUm9JaBaiUVJnSag2oNaXlOlBvSksNZrTYaEYLTSdpnmk+SXMtp2im7RRNt5+iqQ5z + muw0p/FOCxrpsqThLiuqx88pKzGnikprKq+0oZIKOyqqsKf0XOs/3HHn1xuuu+5T6by190tf+pLjHXfc + YfmDH/zAljv99pv9uTGHZ2gO/fHiuOWmm276vHwx/E03zDLvvPHGGz/PP5N/NmaehzklOMAEboUBwJuO + 361GAc88++ytnq7x7DhPAACAAElEQVQuR0sy08+X52RReXamjpK0FKrNzYK4IeIqiLmyXNDLYwUDEauU + S8pKBX1lEG+ppAQUQ8AqSDUEQtAQMlOgCHoQUYiOPCZPMJQLcnL1ZEPAjCrorGyFzCwdI+lMpgYIOi2D + RlOZdAVV3CkQc3KqQpKExZ2YrCcBxCfReFwSTTCxPCbSJL5uY3RMZwC9vb2E538aBsAHgxwB3wbXvynn + A1pbW78LBpCpey8AXqoYaqPtCDMAEwDbKpEq+FwUxigTOYJoE9qCaWzHMCZ6YiVxCltMPL6GSQCJ+JhJ + MlVIlqSYCDZTGVPaTMN9TDquM3BfpqlCliTHjDZyTGkjF8LPM1MoAIUKa0WgxIxWSyVlJ2m1HGMFxsqT + tFwFak7RUu0pWgQLdaDenOYbzWmuyZxmmy1outWCptosabL9NI21naYGGExVoQXVlFlTFagos6WycntK + SDz185tv/lLF9dffkMRNP1/72tdO33333ZaYiU2R++9X+OP1+Ht46Y5nahjFzQjf//MKbvf+MBcF+WfD + AB7kZqGDogCkAI+yEfHfxH8jvvZWS/NT9xelJc1WZqdTRRaTRpWgLC2ZKkFvWRHEXSzGPkGxMpaCEoi4 + pFChGCBiGCjCrFzI5AsGC/L0IMUYys+FqBWGEGkM5eTIMRvChoizpZjFNcSclQlBQ8BMBgMhZ6QLRtMB + izqNR4gY41gqxlQIOIWBiJNBkkqyYCKRgYATQDwDIavEJdBkLIiJpymVaCZOQyxNR0liEmhjcEhnAKw1 + PBdzb3vb29y4DCe7AW94U7oBbW1t38NvBsK7lFQDONvfTNthp2hHcBLXCjvhp2g7XH6M6y2+ZiJwf4Qc + I0/SlkqUJFpDDIiVxBkQf5I2mQSQqCHJTCEZ1ykgVZImST9JG2AzA2TiOos5RevZIEdhLdccpmBOa/mn + aLUQFJ2ilWKMJaAU12XmMARzWqkwp+VKc1qqsqBFsFBtSQs1ljRfd5pm60/TTONpmm46TeMYG/NNqa7A + kuqKrKmm2IaqQVWpHYUGHj37hS98thDhPxf/PG6++WbT+++/3/pHP/rRExDXQct+D7AJcNEOX38j8v1/ + vVLPMV5o7/z6179+k1xhuBt/ww8ushrwfZjA01wT0NQCvlWQGNNdlZlMVRkgPYmqM5Ig/kQqT4zB7J1H + AyUQM49FoDAX5AgGCxSGVPIh2jwJoofhHIm4hngRWYxkZUDYGWIcyUwXjAoQWmcwqWIcE4KGiBGJjKVK + UpIF40yyJClJx0RiIkTNQMBa4uMhbBALIcdBwDzGYIyJFUxHxyhEMdE0w0RGKUTgOiJKMMuEM5E0GxYh + mIuMpo2+fp0BsNZOnTq1iOfFQ3YDfudNOxgEKQAbQP4uA+hroe1gS2BBO2A7RBIq0X4cZkFbEt11OIjY + zWaEOUzBnDYjcR2FMcpCIdpcfgxi8HEsY64nzpw24jUkWNBGosJmEkYmGaTga1MwplrQehrGdIX1DMaS + 1jMtaC3bktZyJLmWtJpnSSsQ8EqhpOg0TAGUnKbl0tO0VH6aFsFChRXNV1nTXLXCbK0NjVdbUUOWGTXk + WcEIbKge1BXYUl2xPXk5P76E8D8T4X8Ewn8nPnyDw//HHnvsQS6s7dPtdxvuf4gbeDhUv+GGGz59hfPA + az772c/+L/cHcPgvZ/iDDOA+GMARNgB1F+HRY8duy4sNr6hOj6fqtDiqYVJBSixVxIUjPM+gocIsCDxT + x3A+RJzHpEPcCiM5aQpZqQqZEHJmigRCzoCA05lkhTQmSTCeClISIegEmsAoSMJ1UrwcQSIELIhTSICA + 40FcrEIshMzEROuY4TEaREHAOiIhbIVZJgKER2gIl+IOp7nQMEmo/jqECaX54BCF0HDaQNivNQBzc/Ml + GICnPBjkuwbvFPSGpgDvRgqQrU0Bzg50QPzWtB10WmKlJ1gzCk7TVogVbeFajCH4ONRKguuw07QZphnD + MUaAcEnkadpgIhQ2ozAy0biWbMRIYkGcFcAYL0mwovVE3JeIa4zrSda0nmylkGJFa6kgzZrW0jFmWNFq + prWeLGtayQY5NrSSa03L+aDABiMoBEUKSyU2tFBqS/MI8efK7Wiu0o4mEPI3IvpoyrahJnx/Y44tNeTa + UUO+A7nbPTb3iU9ex22/wV/96ldtkP8/88Mf/tDuySefvI/Df8PZnyvzvEzH7b3c0Xfdddd94go/zVd/ + 8pOf/BgMiH/fN+VqwG0HGMA9Tz/99BGuB6gGcOzY8VvzYoPza1KjIPpIqgV1yRiTIqkyOggiT6bRfIg4 + j8F1LsgB2UySQhaEnJVIY5kgI0Ewng7S4gUTqSCFidOTDJJiaVIlESTE0BQTL4mDeOOi9MQyEC8TA6Ij + IGg9s5EQbwSIDFOueYwA4RBteKhCGAPhMqEaQphgiDpYjAvBKkG0EGRAoMJiYCAt4vs2NQYgU4B5aQB8 + RPjdBkeEv3EGACf6VxhAqr4IyDWAHtoOtKWtABtgK9hW4fuZIHwuUAM+3gzGGIzPiVF/32YIYyvBdait + BNdhNrQRZgswhksiJJF61nmMthWs8xiDMRbEgXg9awkqdrSWaEerSSDZllZT7BRSQZodraSr2NNKJsZM + e1rOsqPlbHtaygF5IF9SAArtabHIgRbAfIkjTRRC7Inm1JJhRy1Z9tQMmrIdqDHbidysHpv+5HWfSuQd + fwi9Le+6664nkP/bQFj3yPD/ln0M4EcsOhbpxz/+8f+50s/zRz/60Y888sgjPKvz73rogEIgG8DdbADa + 5cLjx0/ckhvtn16XGvZqXUoY1SeHUn1SiKAq2he5eQyN5cbReI4kG8LNjqWJLJAZo5ARQ5Pp0TSZJkmV + pDBRNAlDmWJgKlOJETSdAOJVwiHucJoRhEHcKqE0GwOiQZSGSCYYoXcIzUUE6wmHcMODIO4giFsSqmch + JBBiluB6MThAgz+EjZEJ9KfFAD1LWvz9drHshxEmsNXbt6sIiGhv9pprrmEDMJYbggwN4I1ZCcAT/c7A + wMCErq4u/SrA6ABE7UBb/va0GYAxwF5cKzhI+HMqDgqBCltBuC9QwtdBuD/YgTZUQjSjSqgDrQscaT0M + YziIUFhjIjVEgWgNMZJYSZwjrcY70gqTIEmUJIFkkCJJdaLldMZZsJSBMRNjtjMtgoUckAvyQQHjAlxp + MteJGhCJtKQ6Ugu+vznDiZoynagR3+t++vHJ6z51PS//eX/jG984effdd/8Y4rNCaP3dixjAI7yxhw3g + 2muv/diVfp7/+7//+79+9KMf3SwjAO4y/ObFDICjEZ0BnDhxS36kd0Z9StCrAMIPpAYmMYBqIj0wu4dB + 8BGCSSYrnKYyI2gqI1wwnc6E0XQaSFGYSQmlGRjJDExkJlGSEEwz8SCOCaJZjLOxQYK5mECFaEmUwjwT + GaAQoWch3F9PGONHC6F+tKgS4gtRYwz2lUCoGJeCNAT66FgOwBjAozct+wO/vazw6AN85ce+XrTiAwL9 + aHug33AZcMrAAD77phgAnux/gQFE83mAohEIf+C58REI3IU2/Zxo09dJGRl/hQ0xOus+FgQwzrQRiPsD + lXEXQSDYmdYNCXGmtVCMoS60xtfiY1yHgXA5gtVwSQSIlETpWRG40ko0xhiMsSAO13EYExSWE9wUktxo + KcmVlpIxprgDjKkgzZ0W0xUWMhgPWsjyoHkwlwNyQR7I96SpbDdqQgTSkuRCLSmu1JzqSk1pAN/nbf30 + NAwghguAfCT3Pffc8wjEZwnhcZHv1n268IQoeYRJ3IJw/Tpu/LmSKcD111//SaQgumYjNcTfxwDu5Y1B + 2vvZAIqivQoaU3xJkOSjkOhDtZGuNJ4VhMcjGATRdHYgTWcG0UwGSAdpgTSbygQopEiSQKI/zTEJfgrx + IFZhPk5ex/jSPINIYz6K8YHYfWghwhf4CBYjvCF0jGFavCF0b1oSeNFSCAjWgI+XgxlPWg4CgXpWmABc + S1YCPGjFX4OfO62CFRVfDwnu93XXjas+wNuNVmEaO0MDho1AE1dffbWhAfy/N/xdgvDifHtAQEAoH1ao + M4DJCYjcgzZ8XQWbfm604eeq4K/ipifATXf/Oq6ZtUCMge5yVODrtWB3ifYaD1SoB4QPQnAdggctVLlv + NYzBg4pREI4nJMJDAbPPSpQHLWNc5jHKk5aiQQyIxZMbyyOIwxMZjycdLDIJeHEk4UWT5AUwJoMUb5pP + xYsrjcF1OsjwoTkmE2T50my2L83kgjxfzHbe1BSD2T/RnVqSPagZNKVgTPeiALtjczfc8OnoG2+80Y2P + 4b7vvvseevTRR00g7gf2O92H82yIkpfn7gK3cN8/ZocruS30bTCjz/NuQW724RTgYnsCZASgaxk+YWR8 + S2mcR1VjqicMwJOa8L+2JLlTc6IHNSAam8z2oWk8LtM5PjSDx2g2E48RHrfZDG+axeM5l8qPrbcY5/A4 + z+HxnsdjP58oScDzwMQBPF8L8Z60iOdsAc/jYrQH8FTAcyzA872I539JshgOEw/HNY94jSwL3Gk5FGaP + 19MyXl/LQW60IlkOVlgJwsQQCPB6VXBV8DcEkwxY8cPoC3yAn8RXYc1Hz6r22tsJr3tPOjM6rDMA7rqF + yY7uYwBvfATwn//5n1f7+/t7NTQ06A1gZhqzsx+tw9XW/TT4a/GktYB9CPQSrPIYhBHuugZWxTUI3stK + COOtJ1TPMpx8Ge6uA86/BNcXYDZYivQVLEZJMFMsxvgJFjCDLMRJ4v11zCeARAlmorlkgFlpDjPVXJrC + LIMZbDYTI2a4GUGgMsPlBGHWC6TGGDdqgKE0YTYUJPtQc5ofxXpYbHzpphvjYQCuMAA+l/+HMIBnIawf + H3C8183cBcji44/vvPPOryAC+Pcr9Ry/+93v/rc77rjjK3K58X7u97/Y1mBuB1ZXAUSbMKKFikTXrsZ0 + N2pEpNTEEU8ySHSGCdpA/O40i+hoBszm4DobYyYiJURD8+kKC/i+hTQeASKuRURhi4mMKwxZgmhtMVYZ + lxC9LcUqLMcARHbLUQpLiP6WEAkuRzjrCVdYCQOIIFcQVa6EaAh2guCd8LoEPAbLUd63ggh2VeCoY83f + AD8Nvgb4KOO6j4OCuAbeuA7yoHPTSicga6ypqYk3A/XjqfF40w3gwx/+ML8piBVvUVT2AjxP5+bnkHeH + 4h/1xj/uo2OVCZCjeq0lUMUXzuqDBxwj8ioxgmWYCrMSAvg6RM8S8rIl5GpL4VoC4PSSSIUFBnmfIFph + PjpIIQbEQsBgnvNG5JBz8QqzghCEnRLknrPJTKjIR2dTkZeqpCmIvDUDZHJOG0ZTWUw4ZrxwRADh1BLr + TXVxHA4HUANMpCEFeTFMJDPI+YXbb705BbOui2oAP/7xjx9FCH7sIAPg/n9EATwz34oXxy0f+9jHPn6F + XgRXc0sxfr/o9OPfwb/rIo1AT3MvgBoBGBkb3+xqb3lfdYrzXGOGEzWmgzQnGJ0jUgA7ak20opl8F6RF + LjSfxzjTfK4TUiaM2SALZDrTQjrjBBNwokUm1QmpF0h2RDrmQEuJjrQMluIdBMtxCitMrCTaHmBE1LES + ietIOUZoCLcDGMMkoQqroXaILDEGgyA7TEr4OMhejvg40F6C6wA7/eivZ12HLSZEu934akYtPra0gUj2 + /PKibjtwdXU1bwdux3Pj/qavAsgTgY6XlJS8rBwIAgNYWqLV2BiEPBBqAOMPQfsbjAE6llWCQLDCEo8h + GEMCJUEKobgODUJ+Fow8DYQHCRbCg5HPqYTQPMb5KIxRoXIMobnoMEkockOMsQqzcUy4Qnw4zagkROgQ + VWWuLidF0nSKwlRKlEKqJC2aptJBRjRNqnAFOytGqWhzZTubK92xNJ4XSy0JgVQTB+FzRRxmUgcjqYOB + FMf4//b+796Z9YUv7DKAHzzxxBNGfCDnQW24PPvybkA2iW9+85tfxsz97x/84Adf9/P6nve856p3vetd + 78XP+orc4fdd1WQusiPQmNMEff5v/I1wP+uj1RmOz9dnOlBDpj01ZtpRc4Y9/mcr6so4TdMljjRb5EBz + vEJSaE8L+ZI8kGtHCzl2tJglwfcupUvSbGk51RZGgBGsJIFEGxgBSADxIM4G4gdx1hgliDpWo60FK1EY + VSIlEda0Fo5RJcxKsBaG+0NBiIZgxgZGYI2oF/AYKMcgK+U6QN6nXgdYId1lrCX4OowCX9zvi9EP92Hc + 4I8jPOnCurIdmA8EKS0tffWuu+7i8wDcNH0An5GNQG+8AXh6ej6an5//O50BrK3RSkoKRA2xBgVJgiFq + A0JCdrEYAkGHYgwLpQUmFISHSCDk8DAIWyWc5iJBFBMhR+V6lokGMUykAq/rxkVp4PVfEC9JgHAFMTSV + qDCZFKOsHydLUkAqRJwaB+TI69AZCmOZCTSWlSDHRBrLTqRRMJaTRKO5IC9JrHOPMAUp1AITqYwLodrk + CAVeI4eRVKVEvGz8zOPVX/jiF13VGgAM4G4YwAkZft98wGm9d8liIAvxls985jMcFr5T7u57TTcIn3cR + vfOzn/3s5/hncVWf9wFc5IQg0QTEpwVrewSOHjP+enKkjUtNjv1f6iDm+mw7auDeB1Cbeor68i1optKO + ZsrsaLbUluaKbWi+2JoWiqxpsRDkgzwrWsyV5FjRUpYkE6SfFiwzaadpJRWk4DoZI5NkSSsJIFEZV+NB + nCQWxDAW+jHagtaiLBUiQQRjIUcQjuswxlKwHqohRBIMghgLMW5I1gN3s8EE4NrfQowCvpas++FzfrhG + lHhhY13psTl7lqC1V2+++eZyPpBb0wn4v2+aAbi5ud2XlZX1c/V9Ac9tbtFKVjYtBrOoWchhknAIO1yM + 82EQMa7nw5kIhQgIWRAJcWuIgoCZ6CiIOUqOShfWTEwMzcQqTGuJY2JpKj4W4sYoiIOw45RurySVBMFE + ciKQI3eMpXD3WKLSQcYdZelJkmTRcTYqSBZdaEpnmhyzU2mYu9Vy00QX2xB3svGYn0FDBXoGCzOpOztZ + dMJxR5zojEuLo+p0BX9nu9EvfOEL7rwKcO+99z7CW4CfeuqpH3N+fbHTebglmPN07tvnVODTuLEJ3HDD + DZc8C+AqZevgVddffz1vAvpXjDfgZ2h3Aj5wsUNB+G9jk9Dm/yfNTG/LTbMvqCqwo+p8W6rNs6H6XGtg + RTUZpjRQZkFTNdY0XY1UoBJUWNFs2WmaK7OkhVJQbEGLRQpLhQCGsZhvDlPAda45LeWY03KWhUKmOa1k + gHSQZk6rYAUms5oiScZ9SRgTTwrWEnAdz+DjOIyxIIbB5zAKok7RetRJAV8LIkEEPg4/pScMH4fhazEK + QvFxMD4OwXXIKT18X5B+3GACTwJ5rbtP4o/PpQTQha0NoS0+FDQjI+OvX/rSlwrxdDm/6XsB+Obi4nJr + Wlrahc3NTVGlPA8jWCkuoTkWenikIuiIKBAt+pqZWZUoEB0jmBHEKsQA0XoZpxDHo+yz5vbMeFwnQMBM + vKYnOzFRIHq2uXebe7iTkxRBc393aopA6f1OVjZ1pKXSaLokQ+kXH2Ey05Recu4tV8nOED3nQyq5WXry + smgwP5sGCxQGCpR+9gF53Y/r/qJc6i9m8qi3KIfKEHVUwmiqYS7cI1+VkUTVmcmUFhl87tu3fyvk61// + OvcBPMpvwMF9AE8++aSJPNTzoOO5eJnuIV6OY+Fy7v75z3/+cwjn+dz4a/7jP/5DhPYMUgTdNc/473// + +4UH8NfCfD6P7xXil4eFPnSx04I57IdBGWn/NmNjk5udnczvK8yzXyorsqWKIhuqwsxeXWBF1XmWVJNj + RCP1ljTeaEkTDZY0WWdB0zUWNFsNqsxprsKc5itO0QJYLAOlp2ip5CQtFYMiSYEZTOEkLeeBXDNazjbD + 5CPJNKNVJsOM1tIxMqmmtCZZTcbIJGlIAPGMCa3FYYwFMcq4zuB6PRpEmQjWovgaROI6QoGv1yNwX7iJ + Qhiuw+QYCkJMaSNEP2pZD8aoJYh3rUbQhZ1toS1+n8CYmJjfIzLjQ0Gd3vTdgHJD0A2JiYmrS8j9n5eV + ypXaepqOhKCjWNAQb4xK/F6EsBMgaiYR17xjSu6cSkiCoBXE7ireZZWUAtTNGhA078jinVnqLq1UZdeW + spNLGUcEGXKnF28SyRA7wIazshSyFcSOMR05NJgrkbvLBvNzaUCQB1Hvpr8gHyIvgMiZfOrDKChW6GVK + QGmhoKe0AKJPplIYQGVmqgLvlMtJp5KM5D8ZH302D05vzu/B9/DDD98n37TzCYw/vtj5/bwfn2diuSrA + hbtb7rjjjq9eh9v73ve+/5CHRqiV4qvltTgOjHsI+Gv5e7ixiH/GJbYAi9kfX/8Ys2v9/7jx12Ni7ZwL + ih1+V4TwvrTElspLrKmixIrKC8yppsiYhlosabTFgsZazGmi2Zwmm07RVMMpmq4/SbO1J2muhjGjuWoz + Wqgyo8VKU1qqAOWmtFwGSk1gCCa0XIzrIowFCit5INeEVnMwZiusZoFMYxiCMQwBpElSGSNaS8HnknGd + ZETrKom4H6wngHhJnMIaE4trJsaINqIV1pkoXIP1SBAhiVTYwPVGOGNMG2G4D2yEGSuEquC+EBB8grYq + U+jCOeVY8NXVVfL39//5tddem4rnzPFNPw9AHgv2H3Cl8ampKV078Ep7hyJiQZJCvNweqQNiToCYxb5o + zZZKsW86TcD7qMVeaiY1XRG22J6pIvdi8zZO3V7tbIUs/bZP3t+tIwdCzlXJEwzkMfkQtkJ/QcEu+goL + 9RTxWIQRFOvpZUqKIeySXXSXlVBXeSnGUt11VwWuK8uoAWZSiJSjLCtd2SfPe+YRTVTk51Con+/oN77x + DXsI8ukf/OAH38fs/22E4fzWXMaXOq1XHuP1IMObhLiIx/sEkE587Stf+cqNX/ziFzGJfPZ6BrP9Z7/8 + 5S/fyJ/jZh9pIndwUZG//xLHg6tHg++Z/S0tzW5PyXGozSlzfDWvzJ4KymypqMyGSsusqLDQlJrqT1Ff + x2kaaLeg4fZTNArG2k/SeNtJmmw5SVNNZjTTyJjSbIMpzdeZ0HytCS3UGtNCjQktVkP8lca0XGFEy+UY + S41pCSyX4ONiAINZLjSilXyF1TyQe0Kwlo0RrGUyx2ktA6TjOo05LlhPBSm4TgZJuAZriRg1bCSAeP24 + HgdiFTaYGIV1JhrXTBSuI0GEJFLPBj7eCD8BMIaB0GO001os3m2LtTUzM0NIuS986EMfioX0HAxOBHr/ + m/H2YFffdttt7wwNDW0cGhrSvTno2uAQhJwGYacKxhLlCSdS2GNC2Ony8IQMeTpKhnJiCgQ9LFCPRVKO + TOLjk4ayspWTVyDkwaxchew83SktA7n5eljQecqJLsrxTaAA4i0oUmARFxZL9Ne9RUwJBF0sgZBLWMyl + OrolXUxZmY7O8nKFCqZC0FFZCSoUqioFndWgpopaK8vFyTiliD7K8nIUYArliCbyMzN++cxTT0Xfcsst + R++///4H+RRg3g3IhT7DYttB7+cnDwh9hHN4uXx3mzzii5fsBHwtlxf5nAF+jwF+8xA+A/Degyr+2so/ + fsazsjlI3/xzwvgb/hF2RqmlLj9PL3OizHJHyq6wp7wKW8qDAeSVmFJL52nq6rWinm5L6uuyoIGuUzTc + ZUYjXSdprBNG0GFKE+2mNNlmStMtpjTTbEKzTcY012hEcw1GNF9vRAt1J2ixVmG5GlSByuMwheOIFEAZ + rktP0ErJcVopOk6rTCEoAPkQdN4xWstlcJ2DMVuSdYzWM5ijMIajtM6k4ToVI5OCzyUfFWzIcT0JJIIE + hQ0mXkMciAUxIFoir9eZKFxrWI88Ao7Rmf46eu6FnwgDYI1ZW1uvv/Od7wzjzbhv+pmA/Ms+97nPvcPP + zy9Vvx/gedqYnqExCFURdJY8DgliTtMLWjkuSQpbnI+WK1BEnas7S21AJUcVNwTNos4rVICw+wRS2AXF + gl6mUAJB9+wCQi4GJWWC7hJV1LguK9fRpVLOYq5UKJfIjxWBVylUSaqrqF1QvZuaGlCrUAvq6sRZeYUw + tlKM4uw8pA3lxYUIlYtfDQ8N6fvWt77FdQBuB76H3/oLQv4Wt9uqB29cztt48eoB1wYYntlhDPezOTBc + NJTRwkO8rfgy3xREDf0fkWakNwpjk1tOnTL7VlS2e1VimfurSeWulFrhTOmVjpRZZU/ppacpv+YUNfXZ + UGu/NbX1naaOPkvq7jWn3t6TNNBrRkNguMeURrpNaKzLmCY6jWmyw5im2o1pus2IZlpP0FzLCZpvBk3H + aaERJtBwnBbrIfg6UHuMlmtANag6hkgBY8UxWik/SitlGEuP0WoxKGIg7EJQAPJBHsQH1nJBDsg+AkNQ + WM8EGZL0Z2EKDK5TQcqzCsnP0kYSPmYSn9WTAOLxOSZOQyxzRI7yOuZZwXq8MZ0Z6xB7bFhb3HKP53MO + ugt4S5wKzL8MbvQ2Hx8fT+4GVJcCd1bXaAQCFAcgSiHrD0jM1x2cqMzUu8WsHrbYrxGzlt7CEgNKFUGr + otbQDXF3scBLIWJBmRg7mbIKSaUyQtQdDIu6okoPhN1eWa1QpQIhV+tpq4aYVSDuNkGdQq2e9rp6aq+v + F6fhttU3UHtjIzXi+/OysqgEqQYfmc1HaJfDjCrLy6i4qOjXFhYW0TCBJx588EFxGrB8m+87OeyWZ/Rd + zvv58QEdfE4ff/93pPi/JzsI+d2CviPX72+9nJ/HlX5u+IH41dBf9z1Gx42+4R3pYhVZ5PNSTKk3xZZ7 + UHylKyVWOlNylSPFl1lQUact1QzaU/2QDTUOWlPL4GlqG7SgjgFz6ho4Sb39ZjTQb0qD/SY03GdCI73G + NAYmeoxostuIprpO0HTHCZoFcx3Haa7tOM23HqP5lmO02AzBN4FGiL4B1B+FKYBaUAOqQRWMoOKoMITV + MlB6BFHCEVpliiH2IlD4LEwB5EvycF8uRJmD62yMTCbzDAxBkg7SnqGNNGVcTzEgWWEjCSTiOuFpRArM + M4JNXAviQRzuTzOns3Mjujbg2traVzERDEJ3fuD0m/6+AOov8/T0fLqkpOQV3VLgzg6N4oWtiLpII2iN + qHUht0bMEHHvLjGX6UcxU5cLMQvKyvXCVsVcXrmLjvKq3WIWgt5HzBraqiVVirC1tELQFwUib8HYUluv + UKfQWtdArfUKLQ1Mo3hnnNamZkExv1sOn5qLVKMM4i9HOlGB9KEKf196Ztb8Dx96yOLee+75oXomIG8K + 4p13/LZcF2nNPdAM/sZ3COa8n3v+jfj8P+3Pg8ncbO1ofV9gdsBQSHEAhZX4UUSZN0VXeFJspTtFlztQ + fK0NFQ46U+mQI5UP21PNsC3VDVtT48hpah6xoNZhc+oYPkVdw2bUO2RK/UMmNDhoTEMDRjTcb0SjfSdo + HEz0nqDJnhM01X2cZrqO0WznMZoD8x2gHbQdo4XWo7TUDJoUlhtBA67rj9BSHah9llaqIf4qUAkqQDlM + oOxZmMIztFYiKQZFoBAUgPynBet5EHEuPs7BdbYkS5IpyQDpT8EQMKZhTGUgbrCe8pRCMkhS2GAScZ3w + BG3mO9D5rTVdE1BBQcFf77zzzibuv+Pd+G/6OwNplgK/lZaW9itephBLgfhjJ9o69KIuNpydy8TsvEvQ + pWW7BK2j3EDcELHK5Qt6t5B3zdBaINrWA2iBiPejmanX02TwcTPEvgeIv6WpRdDa3Ep1+Pl5iIZK8NiU + wdjK8X9W4n+pwt9ZXVv316iYmMp77r3nCX4vQHkqMOfr4h2ApAk8cCXfAvxSvQby/QDv3WUmEP9J85Pf + 9E4KTPfPC/tLQEEIBRYHUUiJP4WVsRF4UXCJAyV3uFH2oAflDblS4bATlY44UMWoLVWP2lDtqBU1jFpS + 05g5tY6dovZRM+oaNaXuEWPqA/0jRjQ4BCMYOkGjgydobOA4jfcfp4m+YzTVe5yme4/RTPdRmgVzXUdp + vhN0HKWF9qO02HaEFlsh+maF5SaMjc8KlhtAPWBDqGFTeAam8AytVoIKUA6Rl0lKIf6Sp6UpYCxUWBeG + 8JRCrsJaDsZskKUhQ0P6k9Ic2BSeVEh5UjGFJBhApR89d0F5Z+CNjQ1KSkr6I1Ju7gHwAmZXvRXeG1Au + BX4mJiZmSbcUiFRgdnAY4bdezN0aUe+erat0aGdpLbtELcLu2l201Rwg6to6RcA1+4iaZ2V1dpYIUdfv + RRHzbhE34eOmhovRJGhuaBboPm7Exyx+CL+lpY1aW5V3wuU30SwsQvhfoRd/DVKF+qYmqmlo+JVvQEDU + fffe+yA3BWneEky06EKQJ5CP/1jm7jf/HYR/syz4PcpHf8uDQW82qDV8wzk8wMUrM/oX3jlR5JMXTr6F + YeRfHExBJYHkV+hJQVVulNTnRykDPuJ9EbOG3Sl3xJkKxxypZMyeysdtqGrMimrGLalu3IIaYQQtYyep + bcyUOsZMqBv0jsIMRk/QwMhxGho+TsNgBIwNwggGjtHkwFGa6j9KM30wAjDXc0Qw3w26noUpPEuLHRB+ + OwygDWMrhN8CmplnECWABlAPE6gDtaDmGWEKq8IUnhasCVPANRsCU/yUYghFGAtBgSQfCFN4UmMKT9Ja + Fj5mMiUZEjaFNAYG0JIktMSaYm0FBgb+8sMf/nCKZh/Am//uwHzDrPCh8PDwttHRUfHHij94eoY61eJY + RbWCOltX7j9bt2tnaxZ09W5B68PtA2bqOi2amVor6DqNoHUoH19S0PV6GvH1jbhPUK9B3tfUuA8I95ub + W6i5BeJvbVPeArujkzq6uqmlvYOKEAXxW2pX1dVB9I1Uh69vwNc142tqGpue8/Lx9XrggQfuM3hnILFs + xxtxcDt2qffyez3wbM/v/IPf8RR+3x2G4jeG+B38/U+6J8efcU+PJ4+MOPLIjiHPvEjyLowAweRe4ENh + baEU0xNKcX2BlDgAIxjyprQRD8oadaW8cScqGLen4nFbKhu3psqJ01Q9YUF1E6eoYcKMmsfNqHXchNrH + jalr3AhmcIL6xo5T/+hxGgTDYGTkGI0NH6PxoaM0CaaGjtD04BGaGThCs/0wgr5naa4XJgAWekA3zACG + sMwIUwBtz8AUFJZbQJNiCiswhZV6aQhMNcRfxUDUlaAClIMyUApKnpKm8KRCoaQA5IO8J2AIkhxJNsh6 + gtYylXFnuFK3BDgxMUE2NjY7733ve3kJ0IVlJ7sA35wDQbV1gI985CNvhztl8l5l1QDWlleoC8LaE4LX + HByCHyxqg1l6l7AbBbvFvHvGbjpwxm4S4y4xN+wV8yVp3A0LXaWRgeibpPCbIegWCJ8F39rRRe0Qf0dP + L3X19VM9ooJiRADV+PsV8bdSE76upatLfE19S+uOp4+PPVIBfm/A27VvCS4O4ER4zjM0mwHP0nyfbM19 + LVHBzfJUXz7W+7vSWE7INGPvgSQQv62nz3GX2MQVl8QUcklOIpfURHLNSCC3rDhyy40ix6wg8qyMoJD2 + eArriqKInjCK7gum2EF/Shj2peQRT0ofc6OsCWfKnXSggkk7Kp6yodIpK6qYsqCqKXOqnTpJDZOm1DRp + Qq2TxtQ2aUSdkyeoe+I49YL+8WM0CIbGjtHI6FEaHTlKY2Bi5AhNDcMIwMzQs4hMwQCMoB9GwMAUFnqf + EYawCENYQpSwBENY6nhGsNj2NMxAQTWEFTaExqdhCKDuKVqtgxHUYqwB1YANoRIirwBlklJQ8iStgrVi + iLwIFELoBRiZ/CeEKQhynxCFx7ML/boVAF5lw3Mw8453vCNcNgE9bdAE9OYZAOPp6elcWVn5V7EtGJzZ + 2aEeDm8NhW0g6L3hd+M+Ifg+4Xf9pcNv7ay9R7S7RN64D3uFbUgDi1QVuY4WIXhBkwTCbkK434THg2lu + g6gh/tbObmrv7qHO3j7qHhiknqEhqm1upkpEAPVC/O1C/O0Qf2d/P/UMDlFLZ9dWeGSk86OPPvodiPNb + qgmo4pVv4MHvIHSCl+j4WvYA3GpQCNSi6x2Q7wrM3/+MFD63Ad+u7fFXgOkYnfiGnVegmUtkypJzdCo5 + xaWRU3wqOSYmk1NKEjmnJ5JdaiTZwwR8/n97ZwFmWXVl/8aC/RNgkoEEkiFDbJJMhCQTIZlMZpghxiRo + u3d1ubu7S5e7u7u7u2u70rhbCATY/7XPPfe9W6+qmm7oDE3y3vftr4umpar6rd9Za+9zzm1Mo4DWFArq + SKTQrlgK742iyIEwihkOpriRAEoc86XUCS/KmHKn7CkXypt2pIIZeyqetqXSGWuqnAEIZsypbtaUGmYP + UtPMAWqd3U/tM/upc2YfdU/vpd7pPdQ/tYcGpnbT0ORuGkaNju+icdTk2E6aQk2P7gQMdgIGO2gONQ8g + zA/uEDBYHAAI+iF6AGG5F9UjqxvVBQh0ojoAAkBhhYHQwrWNDjfLaoT4G7gg8npULQTPVY2PUUcqJRQq + GAoQeRmqdIsAwhENFI4WbgZAbOjcsTkBANZTZWXl+7/73e96oLVgzR6An8k9AJ/5OEaAqyDg4uLy65yc + nFdOnjwpiMUjwWGsamtzdZPSBZelteCrRH4BCy5W7Ib1xNz0ocXctEbI6xTye6OsBlmN2oLYVSjoikGA + lb+5rV1UC6/osPTtXd1C/J39UvwjIzQwPgFbO051ra1UzzEB7kAnfsBhYHSUhvD/ewYHn8zKzQ2HWB+A + Sn++zrMCeAX/OY/qdu7cuYWf2MNde7bwcmPQg3IvAO8BeJB/DrWNfw3/Wj7YwxuCNuopcLff1Mz8506+ + kW5uEemn3aIyySU6k5xjMsg5DpWQTk5JaWSflETWyfHkVp5DXrU55N2YSb6tAEF7MgV2xVNwbwyFDURQ + 5HAoRY8EUuyYHyVMelPKlAelTbtS5rQT5cw4UP6sHRXN2lDJrBWVzVpQ1ZwZ1cwdpPo5E2qcPUAtAEHb + 7D7qRHXP7qWemT3UxzCY3k2DgMEwamQSIEBNTAIEE6hxwGB8B82M7aDZUcBgBDDgGt5OC0PbaXEQNbCd + lvoheq4+VC+qB9WN6toGIKA6UG3bAARUKyDAJaFwpAnVqADhCIBwpE4CoUYWQ6GKwQAAVGzRQeFI6eN0 + vD2Qzp89JSYAZ86coZSUlLd+8IMfVEJr/igb1MOoH6G++HGNAFcBwNzc/J7Y2Njji4uLujMBM1PTiqAN + V2zx3+oKrRHph7Hf64m7WVPi5xTxXkjQOsEaCFypZk2t93PNqwSvE75W/LD9QvwQfptG2D1DQ9Q3MirE + P4zv19jcHA1NTVGjXP314h8T4h9BFhybnqbhick3apuaypxdXR/atnXrffwUHoaA9tIQddXm8wG8srOo + uZHHINihvHaitgICjzIs+NdoLvz8yfobi/b92NrO6QGPoIQ0z7DMF93Ds8g1HACIAAAis8gJIHCKzSS7 + 2DQyj0kkx9wCci0rIbfKQnKrzSOPRoCgBSBoTyX/riQK6I2j4IFoCh0Op4iRYIoeC6DYCV9KmPKipBl3 + SptxocxZJ8qGG8ibtaWCWWsqnrOksjlzqpwzpWqAoG7uADXM7aemuX3Uimqf20tds3sAgz3UO7ub+mZ2 + 0wBqaHoXjUztxPdvJ41P7aBJfDw1uYOmJwAC1CyAMDe+nebHlFoYRY0ABIDC0hCEDigsD8jq3wangJ/r + RfVs0wFhBUBYaQcA2mStAgLE3rh1LRBqIfoaiL8aP1ZtEUA4OZyhs/+sKUTsF++44450aM0XZY76Pep7 + cgR40//pXYDrAWDLli3/gE+yjrcrqn2AlZUVAOBCK/YFLPhHWLHXrMLrinq9av7gwp9nWEL0BsXCb5LC + XyX+HkX8nXBH3RrxD0H8o7NzNLmwSDMrh2l8bl782u6BQRoYG6NBiH+YxQ84jM/M0CR+7cTs7Lu9g4Oz + Ofn5HgDwfxps7d0w38v6saw1UWBtHRDCNzU1u8/dO8zSLyxtwDc86x2vsCzyCM0iN5QLyhkwcIrIJrvw + DDIPSyHb5EIAoIKcisrJubSMnCuKyaUGIGjIJ4/mbPJqyyCfrhTy60mggP5DFDwURWEjYRQxGkTREwDB + lA8lTHtS8owbpc06U8asI2XP2VHunA0VAALF8+ZUtmBGFfMHqXrehGrnAYL5fdSEapnfS23ze6gT1TW3 + m3pQfbO7qB81OLOThlFjswDBzA6amAYMUFOAwjRqlmtyO81NAATjSi0ACIsAwiKAsIRaHpI1CBAMbBNA + WNYAYaUb1cVA2KpU+1YAAdWKatkCIEDoTbIaUQ2oelTdZvy4k07NNepuAmZN2djYnLz22mtjNFeBPYD6 + lpwA3PixjQBVAHzjG9/4lJ+fX2BDQ4NY/RkAHAc6YHcb1xPlxdY64lKs9tpqWFUt/ye15nOD8Bu14ofw + uYuvrvztOvEPw/aPCss/NAnxz0DQEP/08grNHzlKSydO0szSsnAI/fh1vPKPYuVXxT89Py9rgSZmZl7r + 7OlpSc/KsrKxteXeAF8TdiEQXFSx1d+/b9+PzWD33T2C9gSGJpcHRWQ+HwCh+0H83hC9Z0g2uaNcUM4h + OWQfnEnm/mlkE1NMjqnV5JBeRQ7ZqPwKciwuJ6dygKAaIKgvILemXPJow5/RlUbePUnk2x9PAUMxFAQ3 + EDoaQhETgRQ95Uux096UADeQNOtCqXNOlD7nQFnztpQzb0X5CxZUvGBOpYumVL5wkKoWTKhm4QDVLeyn + hoV91Lywl1oBgfYFwGBhN3XP76be+V3Uhxqc20lDqJG5HYDBDhpHTQAIk6hpAGFmaruouUml5ieUWhjf + RotjEP4oagSCF8VAwH8PblOgIICwVYECO4RudglbRalQOCygsEUpHRgAgDZTOndiVgCAozTvsn344YdH + obMIOQHgY8C/khOAf/g4G4CrdgS6ubltzcvLe4N3LTEEzj3xBA3gjb7RKrleNWir+WKq5WMrw8+3saVN + AqCdmiD+pvZOAKALAOiGne8V4u+A+LsGh6lnGOIfY/FP0QgEPb5K/CfoyOnTdALfv2V8zA5gCC5hYmaW + JucU8c8scC3oin8O0eDVjp7etsLSUm9vH5/fmZmZ8aO8/m3P7t3/Bmv/k4sRPMDx47179/zbwYOmP7O3 + d/qfgKAou/ColPLImKynw6OzKSQym4Igfn+I3wei9wrOJo+gbHJFOfhnkqVPOtmHl5JTXC05JNSQfTIq + rZrsslC5VWRfWEH2ZeXkUFVCTnVF5NKYT26tOeTemUEe3ank3Z9IfoOx5D8cRUGjYRQ6HkwRk/4UNe1D + h2Y8KR5uIGnOmVLmHSht3o4y520oe94SIDCnokUzKlk8SGWLJlSxeICqF/dT7eI+aljcS02oVkCgDRDo + YBCgegCB3rldNDAPR4Aamd9BoxIGE6hJ1NTMdppGzaBmp1FT22geUFiY3EYLE0otAghLAMIy16hSS8Nb + RS0P4cdB/ChcwlYFCuwSevFjt1IrDIVOCYWOzXR00JfOnzuhy/85OTnv/eQnP6mTDUBH1BbUfZpTgJ+6 + EgBwNd5w30lMTDy+tLSk6wNMTc+sWbmvZFGvV/UGpfy8wecM8Te06Fd/RfydQvz6lb+fukW3f4T6IP5B + If5ZiB8CXl6muSNHdOI/DoieevIpOvvMM3T87Dm2+zQK+6+If4FmkQt1JQCwQFP4fwyJ4YmJP/UMDh6t + b2kpzy0s8jgUH7/X3dPz13zGX6zqgIFaB7jwc3z5h72D4/0+vgFbw8KjnWLjUrMTErPn4hNzXo1NyKXo + 2ByKjMmhsChAICKLAhkCIYBAEFbwwCxy9EkjW+90RIFyco2qJadoACC2juzia8kuqZZsU1GZqNwasi2o + ItvSCrKrLCOHWjiFhkJybs4jl45scutOJ8++JPIejCff4RgKGI2goPFQCp0MpIhpP4DAGyBwp7g5V0qE + G0ieswcIbClzwYpyFi0ob9GcCuEGigUIDggQVAEENQBBPSDQuLiHWhYVELSjOhd2AQYAAWpgYQcNAgLD + 89tpFDWGGp/bDuhup6m5bTSNmpndRrMz22iOa1qpeUCBgbDIBSAsMRDGtypAGAMARvDxsCwAYRlAWGEo + AAgrXIDCCoCw0rNF1Mm5XJ2L5hiNaP3S3XffnSvPAGgbgB/bIaB1b5S69957Px0SEtIwMDCgvxwEKxo3 + wa50Udc3rV916/ycIaRUJ7Cu9Wfxi24/r/yDQvzqyj8KsU7Ma8R//AQdNhD/+eeeo6dffJGefO55Wj56 + FHl1RgBgHpDlmltcEhAQAJibFxGBQcGOoX90jHsIf2np6n6mrqVloaK2rruorLwqr7AoPys3LzUjKycl + PTMnJz0zuzQjK7cjPStvBnU2PTP/z2kZ+ZSSlkeJybkECNCh+ByKPpRNEdFZFAoABAMAAaGZ5B2QTs5e + yeTkAxCEVZBHeA25RdSQS2QdOUbXk92herKNqyebRFRKPVln1JF1Diq/hqxLqsimooJsa8rIvh4gaC4g + 5/Zccu7KILfeVPIcSCTvoTjyHYmmgPFwCp4ModCpAIDAl6LhBg7NulEcYkHCvCMlzdtT6rw1ZSxYUrYA + gRkVAAJFcAMlSweoHACoXNpHNUt7qW5pDzWimhZ3UyuqbXEXdaC6FndSz8JO6mMQoIZQIwyDBQkD1OS8 + BgaoWdQcoDA/u5XmAYUFAGFhaistAgpLkxA51wRKAAEwQC2PbAEMtggYrEggCCgMbEbtodNH9ScA+VmA + lpaWx6+//vo4uQXYDPU71HdRn78SGoCaK+Wuvs7T09Oturr6fb7CWOwHOHOWkE+vGEFfuJovWBeKARcS + f4cUf48Uv1j5+cg0ixY5f+7wEVqE+Fcg/mMQ/0n+vkH8T0D8T73wAj370sv0/Cuv0guvvkqn8X0VgkcU + mMOPDAEVABwPxgGIEfz53DTsHxkRTcT23l7x+TTgc6xpbKLKunoqq6p+v6S88v2i0nIqKCqlvMISyskr + oqzcAsrMyidAgNLS8yg5NZcSknIoLj6bYmKzKSomi8IjsygkHKt/QCq5e6eQV0A++YVXkE94NSBQTW6h + 1eQSVkuO4XVkHwkIAAQ2sQ1kndBIVsmotAayyqony7w6siwGCMqryaYajqAOIGgqIvvWPHLsRKzoSSf3 + vmTyhBvwHj5EfmORFDARRkFTQRQ64wcQeFPUrAfFwA3EzjsBBPaUDDeQCjeQsWBBWYBA7pIp5S+ZUCEg + ULK0n8pQFYBA1fJeqgUE6pd2Awa7qRnVurSL2pcYBjupe3EH9aIGUIOL22kYEBhhEKDGF7YB3NvguACC + eRUGWwGDrRIEW2lB1uI0RD+l1PIqIGwBDAABrhFZw4/TkXF7OndmRewA5PxfWVn53v/+7/8OyvzvIS8C + vf9jex7gB20IcnBwuD8tLe0V9Y5A/iJG8WbcSEAfSeTNl1/kXHUXKf4GTeNPsf0G4peZvxO2vxti7IX4 + ByYnaRjiH5Pin4X4F1j8pyB+WP2T5yH+pyH+Z1XxvwTxv0IvvvYavfT66/TKG2/Q8y+/TMdOnhQQ4Jrl + /gHsPwOAR4TcMGQA9AE4PEbkaUJzZyfVt7YCAI1UWVvHAKDi8gpiAOQzAAqKKTevkLIZANkMgDwAIBcu + IFfvAuKyKRoACA1LI//AFPIPxseRpRQaVUmB4ZXkF1pJXqFV5B5STa4hNeQcghgQihgQ3kA2kY1kHQPx + xzWSZWITWaQ2kkUmKg8gKKolqzKAoBKOoLac7BpLya61kBw6csmpO4Nc+wAauAHP4VjyHo0hX7iBgMlg + gCAAIPChcLiByDk3ip5zBggcKX7ejpIWrCl10ZLSl8wpExDIWTpIeRIExYBACdxAuQDBHrgCBQQNqCYA + oAXVtrRTAcGSAoI+QGAANcQwQI2ixhcBAsBgcoFBsFXUDGoONT8nC0BY4JrZQouopWkInWsKH6OWJ/Hj + BNdmAOFxOjofteoAUFJSEh8AKoe2QjS3AP0CdY/mGrCrN10BL9EH2Llz55cjIyPhQqd048BFvNF5LPZx + rdyXUh8kfrUHUK82/7jppxF/M8TfAvG3QfztfVL8w6Mi8w9gZR7GCj0GsU7xyi3Ef/yixP+yFP+rb75J + r735J/Hj04gFR/D7p7iPICcEco8ADY6Nif0D3HdgGDV1dIhdhtUNjVReW0ulVVUCAIUlZXoAFBRJABRQ + BlxAWkYupQIA7ALiE1j86RQenkLhEZkUc6iIYuMqKepQJYUDACERVYgEgEBIFXkFV5M7yiUILgAQsA9H + DIgAAAABq9gmsowDABKayDwFlYHKbiDzgnqyKK0ly8pqsqqpJOuGMrJpLSa7jnxy6M4mp950chlIIbeh + BPIYOUTe45HkOxFK/tOBFDTtRyEz3hQGNxAx70rRcAOH4AbiFmwpcdGKUpYsKG0RIFg0pWyAIBcQKAAE + igABBkEZQFAJCFQv74Yr2C1dwS64gl1wBQyCHdSJYhj0oQaWttMgahg1AgiMosYXt9IEanIBIJA1i5rj + mt9C86iFOdQsQIBa4gIQlmckEKYZCNvo1LEG3f5/vmbPzc3tqdtuu40PAAXK/P8I6t+utPyvA8Add9xx + g5+fX2JjY+P76rZgvs6Y97wr4vq/F/XFiH6jMoSTAoFWBQCq+HmLb7si/tYuiL8HKz/E3zUA8Q+NUN8o + bP+EFD9y+iTn9sOHaeEYi/8UHT17lk7AKZ3hR6s9+yw9+fwL9IyB+BXhv0mv/+lP9BqXhAD/vyfxe5aP + HoP4Z8TEoH8UwGH7D/h09PWJDUWNAFQtPveqhgYqr6kVZw6KyiqooKQUAChRAJBfhBhQSFk5SgxIS8+h + 5JQs2P90io3NAAQAhJRSSkurpOTkSvx3BUBQTpHRlRQWWUlBiAEBIZXkE1RJnoFV5BZYTc5BNeTILiAM + LgAQsIqG+AEB89hmMotvJtNkVBoqp4nM8hvJvKSezCtqyaK6miwbKsi6pZRs2gvJviuXHHuzyGkgjVyH + ksl9JJ48x2LIeyKC/CZDKGA6ACDwpZBZL4DAjSLgBqLmHegQIBC/aE1JcAMpgEAqYkEGIJANN5ALCOSj + CgCBYkSCMlQFxF8FENSg6pZ3UQOqaZldwU64AoAA1b28nXpQfQDAwNI2GkINo0aXttLYkgQBago1jZpZ + 3IKYtgUwUECggwFqcU6BwfLs47QyZwP7PwfNPK17DNiWLVum5PxfPQKszf83Xyn5X9cH4C2J9vb2D2dn + Z7+mjQEjo2NScFeeyNdU4/qg4s1CQvyy6y/GfW2alV+Ivxcrfz9W/kEx6+/D1z2AFVkr/hkp/uWTevGf + /iDxQ/Svv8X1lg4CCgDeEL/uOcSCc888QyuIBmNwAry1mD+Xpo5Osa2Yxa/L/9U1VFxRSYVlyP/FAEAh + 23/k/+w8ysjModT0LKz8WZSSikrLoeycYsrLr6T8ghrKza2mzMwqSk2thD2toLi4cjiDCoqIqqBQACAw + pIL8girIK7CSPAKqyDWwhpzYBYTABYQ2kHU4IkAUAHCohcziWsgUdTAJP6bhx6xmOpjXRKbFjWRWVkfm + VTVkUV9Jls1lZN1WTLad+WTXnUMOfRnkPJhCrsNJ5D4WS57jUeQzGUZ+U0FwBH4AgTeFwg2EzbkCBE4A + gR1AYENxgEDCogUlIxakIhZkAAJZcAM5y/spb3kfFQAARXACJYBAGQBQCeFXo2pR9ahGVPPyTriCHdQB + AHQt76AeQKAXH/cDAIPLAAFqRMJgnGGAmkJNL60GwdzCZpqXQFgQQID9X4mGVs4JB8CLZkpKyp9/9KMf + 8fgvTHMCUH0QyMfzKLCLcAHXbN68+Z8jIiKm1JuCuZaWV5TV8+MQdePGVbvOz60GlfzvZv3qL8RvmPnF + Lr9erLhS/LDfvVL8QxD/KMQ/saSIf/7YMVqC+I+cMRT/80L8z+nE/4ZO/G9A+Np6/U96B8DNwWcBAI4N + /Oec4ukLnMUUYDOIv58nEA34fCsg/hJYbBZ+XlEx5RRgtc/Lp8zcPMrMyaMc2P88wKCwuIyKSyuprLyG + SsvhFspqqaikhgoKqykvr5qys6soPb2SUpIrKCGhHO6gnKKiyxENyik4tIz8g8vJJ7CCPP0ryd0fUQAQ + cEQcsAuGCwiBCwiFC4iAA4iG8GNb6WAcKrGVTFLayCSjhUxyAYMiuILSBjKrBAjqAILGCrKEG7DuKCLb + 7jyyhxtwHEgn52GAYASxYOwQecENeE+FkC9iQcCMLwXCDQTDDYTCDYTPOQAEthSzYCVBYE5JgEAK3ED6 + 8gHKAASyAYEcVD5AULi8B65AAUE5hF+FqpEwaAAEmlAtAED7sgIDdgUMgj4AYAA1tKy4ghHVFaAmdTDY + QjNLEgaiGAY76MSJBrH6s144Qnt6ej5zyy23pBscALqi5v/rAuBb3/rW//Px8YlRnxr8FOqUGgMaL4Oo + Gz9qNYmqlT9qa93PS83+2o6/YeZXxT/A4ueGH6z4JMTPY7m5OdjCRZpeOUxzQvwnhfiPs/ifeprOPvMs + nYf4n35RK35l5X9div/Nt/5Mb/75z+JHHQDeeFM0Bp8HABgcDBDuIZzEn3vkzBkxVuSowaNGPmfAbqRL + TgX4c+cIU9/SwncNiO9FTX0jVdeh8GNVbSNVVtdTOQRYAhAUl9YADDWUn18NUFRRVhYgkFZByXABCXFl + dCgGUSCyjMLCyig4GBAAALz9K8jDt5Lc/BAFAmrIIbCObIPgAoLhAkKbySIcLiAK4j/URgdjIf54VHIb + HUhH5QAIhc1kUgJHUNFApogtZg1VZNFSTpbtJWTdVUC2PTlk359JjkNp5DySSK5wAx4TUeQ5FUbe08Hk + O+NP/jM+AIEHBcMNhM47UQTcQBQiQQwgEAsIxC+ZUSIgkLJsQmmIA+kAQJYAwV64gj2IB3uoCBAoFSDQ + uoKdVI9Y0ChB0CZB0CnjQS8A0L+suIKh5a00ghKuYHkLYLAFMNgCGGyRMAAAlm3o7LklXfe/qamJsJBO + XnXVVYfkASC+AuwPqB9o7gC87kqy/6tigK2t7SOZmZkv8XZgtRcwNjFx2VbuixX5RrWe+OvWawaq+b9F + k/t5l59G/K290vZDXF0sfs3KPzKLlX9hSRE/cjpv8T3M4n/iCTr1lJz1C/G/CBu/gfj//OdVpQKAm4Iv + vfa6iAv8+3lsyEDhHYTcWGSnwXsMuOk4pAJgaEiAihuD/HXw11PX3CK+3pqGJgUAdQyABgGAiipAoAIQ + KKuhIgCgoIBdQBXlwAVkwgWkpVRQUkIZxceWUUxUGUWEl1FoSCkFBpaRHwDg7QcX4IsoAAA4+SMK+AMC + gQ1kFQwXENJM5mEAQCSEHwPRH2qnA3GopA7an9ZG+7Lxc/mtdKAYIChvJJOaejrYUENmzRVk0V5GVp1F + ZN2DWNAPEAxmkCPcgMtYArmNx5DHZCR5TYWSD9yAH9xAANxA4Jw7BcENhM47UMSCrQSBBUBgBhCYAgQm + cAUHEA8AgqV9lLm0F65gD+UKEOwWICiB+NkVVOBHBQY7AYMdcAU7EA+2SxhsBwy2ISJsAwy2Ud/KVriC + rQIEwwIGW2gMJWCAmlxG/j+WrLP/rBnY/7fvvffeWs34b5+8AYj3/9+u2f9/RQLgut/85jf/hBgwqrsl + CAA4cvSomAb8NQR9KVVrUKr4N2wAtijHc9eIH5m/tadPL/6hEeqByPrHIf4prPwQ/7ih+E+foWPnFPGr + s35F/C/Dyq8v/j9xvf22+FEFwGsSAEr+f4Wewp8h7D/+XN5LsHzqJP7Oo1hploQD4b0HfPZAcQB9+NyV + xmA94gxvduIoVAsA1DAAarn0AKiorEccQBRADCgqqqYCuIDcnCrKzqykDLiA1KRySoQLiIsppejIUgoP + LaGQ4FIKAAR8/cvJy6eC3OAEnOEEHP1ryA4QsAloIMugJjIPRgwIBQQiAIHodgGB/XEdtC8RldZO+7Lw + 33lttL8IIChvpgPVDWRSX0umTdVk3lpOFh0lZNVdSDZ9eWQ3kE0Ow2nkNJIEEMSR20Q0eU6GAwTBAEEA + QOBD/nADgXADIXADYQv2FLFoAxBYUTRAcAhuIA5uQAHBfsSDfXAFexEP9lAWnEAOIJC3tAvxYBdgsEvC + YBdgsBMRQQFBPapRwqBtBSBY2UadqG5UL0DQzzBADa1sESAYWd5MEyv76MTpHp39Hx8fJ2dn5/O33XZb + uhz/OWrGfx/7BSAXEwOuxetGd3ewv6pKtymIzwj04g3Ib7S/tqg3qpr1AKB1HLrVX+3+twqRKB1/zf5+ + CIjF32YofricQay2I9L2T62sCCEuipUf4ueV/0lV/M8L4T4rxP+qsPNa8avCf0sWf6wFAPcI1Pz/JPI/ + RwneRMSNRd5SPHvkCD6HJbHpaABQ4vMHnf2DIq7wFmX+ehokAEQ/pKFRxIAaAKCqBgDAilsBCFRKF1AK + F1BcXE2FwgVUwgVUUGZGOaWlllOycAGldCiqhKLCSygspISCAkvI37+EfHzLyJMh4FdFTr7V5OBXQ7Z+ + dWTtjygQABcQhMwfAssfjhU/Cqt/LMQf30l7E1ApHbQ3E/+dCxgUttL+0hbaX9lEB2rr6GAj3EBLFZnD + DVh0FZNVL0AwkEN2QxkAQQo5jSaQy/ghgCCS3CdDyQtuwAduwA9uwH/WHSBwoWC4gVC4gXC4gUhAIApu + IAYQiEMkiAcEEgGBZEAgFRBIR2Vi9c+B6PNQBcsMg51UjCpFlaMqUTUAQB0A0AgANKFaVxQYdLIrWNG7 + gv5ldgabaeqIDz3xxEmx+rNWKioq3vvDH/4wDB3FSPtvifqjvAL8i1fa+G/dcSB/giYmJr+Ij49/gvcz + q1uDZ2FHhcX+K4p8I+EL8TesrjVOQ9sAbNbO+vWjPkX8iu3vkLafxd/H83cWvzzcM7W8QrNC/LzL7wwd + 1ezyOyd2+WnEj5XcUPyK8N+RtRoAugbgK0r+P/+ckv9PnH9SuAzeWSiOFXP+RxTpH5sQUwnemMRnE/h4 + Mn9N7G6EA+DVXwCgQbiAKohfAUAdXECd6AWUVcAFlFYjClRTfn4V5eZWwAWUwwWUUWpyGSXFl8IFlFBM + ZAlFhpVQaDAgEFBCfn6l5OVdRh7eFeTiU0lOPtVk71tLNj71ZOXbSBb+zWQWCBcQDACEAQCREHwMxB/X + RXvju2hPMj7O6KQ9Oe20Nx8gKEE8qGym/QCVSUMdmbRUk2l7BZl3lZJFbxFZ9eeTzWAW2Q2nk8NoMjnB + DbjADbjBDXjADXhN+wMEPgCBB/nDDQTOO1Lwgh1AYA0QWAIE5gCBqQBBLCJB/DJAsLyPkpZVEOwWIMgG + AHJ1MNgJV7CTSpYUEFQs7UA82KHEAwmCZoi/FeJvRzEMugGBHvzc0sly3eyfL/8MDw9//Z577inR2H/1 + AtBvS/t/05Vq/1fFgG9/+9ufCwgIKOvo6HhfBQBfHc4XYfJq81FFXbuOoNerGlkXFn/TutZfN+uXtr/Z + UPwQlVb8wxD/GMQ/KcR/jBZOKFt8j8L2a8XPKzaL/3kpfrbzhuL/8zvv6IohIADw1p/x6xQA8O97ziD/ + Hz93Xsn/R4+J04U8etTl/8Eh8XnzxIK/Hr52jL9GbgLyBiFRAABXVa0CABUC5VW1gEAtlXJDsAQQKKqi + fJ0LKKP01DJKSSylRLiA2Khiig4vpvCQYgoJKKZAX0DAGxDwKiV373Jy8a4kR+9qsvOuJWtvRAGfRjL3 + bSZTf7iAQFj+UEAgvBMQAABiAQCGQFI37UnDj9kAQT6quI32VrTQvppG2o/P90BzDR1sqyLTznIy7ykh + y/4CshrMJZvhTLIfSSXHsQRyghtwgRtwgxvwhBvwnvEjH7gBP7gB/zlngMABILClULiBMLiBCLiBKEAg + BpEgFm4gDhBIAASSAIEUACANlQHxZ6FyIPpciD8fVYgqXmIY7KByVBXcgOoKVBi0QPhtAEDvYVs6dW5W + Z/+7urr46T8rN9xwQ5K0/9z937qB/b9iAXCVvKLoBltb2z05OTlvqFeFKc3AyY8k6IuvRmVVQ9UalKGr + qGuSADDM/Qbib4H426T4Ow3Er678QvxHjgrxLwvxn6MTvCEKK/S5ZxXxK7N+vfhfu4D4BQDeUQGgbwCq + 83/d+E/N/yc1+R+fE28/7kH+5/Ek71BslvlfmQK0ygagXvyi6lQI1EkXoABAcQFqFKiivBy4gKxyyoQL + SEsqpeT4EoqPKaZDkcUUFVpMYYHFFOxXTAE+JeTrVUKenmXkBgg4e1eRg1c12XrVkpVXA1l4N5KZTzMd + 9IMLCAQAQgCAcAAgmiEA8cf30O7EbtqdhsoCCHI7aXdxO+0ub6W91c20D5/z/ia4gVa4gc5KMutBLOgr + JsvBfLIeyiZbuAF7uAFHuAGn8RhynYwg9+lggCCAvKd94Ag8yQ+RIABuIHDBnoIXbQACS4DAHCAwpUiA + IBpu4BAiQSwiQfzSHkpc2UPJgIACg11wBQyDnQIGeRB+AURfhGIQlC5tp0pUNSBQi6oHABrhAsaPp9L5 + J8/rZv8ZGRnv3HfffS3QTrTmASBq9/+Kt/+GMeBTDz744NfCwsLGtFeGHzt2XJwQvFwi36i04td9bAic + ptXirzMQfyPE37SB+LtZ/OMTq1b+KVX8sODLWImPnD0nbLkq/vMGG32E+N9cK/63NaUFwJr8L8d/PE1g + h8HjRY4cvM2YLxjh/N8/wQAYwec9INxLM1YZAQB+KEmz0gBUJgANumLxcx+ginsAohkICAAA5QBAmeoC + CquoIL+ScrPLKYtdQAq7gBK4gGKKiy6mmPAiigwuolBAIAgQ8PcpJh9AwMOzlFy9ysnJq5LsPavJxhMQ + 8Gwgc+8mMvVpUSAQgBgQDOsfBrFHoWIBgLhu2pWASsXHmQBBbhftKuqgXWVttKeqhfbUNtG+xno60FJL + Ju0AQXcFmfWWwg0UCjdgPZRFtnADDmOJ5DjOsSCKXKfCyH0qECDwhyPwgiNwAwicAQIHgMAWjsCaQuAG + wpbMKAIQiIQbiIYbiIETiIUTiIf4E1FJEH8KKg3iz0BlrexQQIAf85cVGBQDAAyCcoYB8n/jihkdPTNC + T0n7zxrhrb+33nprBrQTLjf/7JGHf755pXf/14PAdZ/97Gf/n7Ozs3tJSck76kUhPOccwop0qYLeSOAX + W7UXagA2KeKva1Gafmz7G9s14u9m8Q/obL8q/gFV/HwaD+KfkeJfkuI/rhO/nPVrN/qIlf9Nsbtvjfj/ + 8hddKQBQpgACADL/M0QYJtxM5L+D9xVw/ufzBdr8z58nb0nm/M8XkzSL/N+uz/8GAOARoACAgIAEgBoD + KvQuoKgYACispLw8dgFllJleSmnJJZScUEwJfFYgqoiiwwopPLgQUaAQUaAIUaCIvD0BAY9ScvEsJ0fP + SrLzqCZrj1qyZAh4MQQQBXzbaL9/B+0NgvhD4QAiIfhDED/cwC64gV0pqAx8nIMqBAhKO2h3BUBQ00x7 + 8W+9r7me9rcBBF2IBT3lZAY3YDGIWDCUQzYjGWQ3mgIQxAMEh8gZbsBtKgSOIIA8Z3zJa9aTfOZcyQ9u + wH/eHiCwgSOwhCMwBwhMKRwQiIQbiEIkUEEQBwgkAABJKwyCnZQqQLADrmAHZS8zDHZQHoMAbqAQAChZ + gv0/eoieOH9GrP78WL3i4uL3fv3rX/dDN4fkA0BtUY/J23/VzT9XbPd/3U1BHAMeeuih70dHR69odwYe + PnJEXPn1UUW9XlWvJ34tZHQAUBt/8ty/ruOvXOjR1AHxy9t8lJV/SNftF+KfZPHP0ug8bP/SshD/vBD/ + KTp8Vtnoc4o3+jy7eqOPMu5Tdvm9Lkd9WvG/A9GrpQOAbADqNgC99roY/z0txn+c/58SEwY1/08tKfmf + 3Unv6Li4hYjzP48uGWz8NdY1c/5vUcSPquLsr1r/2jqU2gfA6l9TKwBQVlkDANSIXgA3BAuLKuECKig3 + p4yyM0opI7WEUpOKKSmuCFGgiA5FFFJUSCGiQAGiQCEFeBeSr2cRebmXkLtHGbl4VJCjexXZuteQtXsd + WXggCngiCni10gGfdtrnBxcQCAiEQOgREH1MD+081Es741BJqHRUdg/tKOimnSWdtKsCsaCmlfbUN9He + pgba11ZHBzqryaSngkz7Ssl8oIgsh/LIajiLbEbTyG4siRzgBpzgBlzgBtymgwACP4DAi7zn3AECF4DA + gQLgBgIXrSkIbiBk0QwwOAgQHAAI9gEEewGCPXRIgiAeIEgEAJJRKRB9Gmo1DLZT8bIJLZzuweqvZP+Z + mRny9fV94a677sqHZvjuf2/UQfn4r+8ZPP/vqk2fkJeIATfeeOOt7u7u0TU1NfqRIH7sHxxSus6XSfhi + J1u9HGVpao3L+ADx61f+Htj+HiH+9n5p++FceoX4p8Sx3lG+k2+ZxX+E5hFtVPEfk+I/88yz9MTzq8d9 + 2ln/KvFrhL8RAHTzf0BEN/57lsd/T9FROA7eYswRhIE0IvL/FICF/A94qfm/QZ3/N7esaQDyMwmq6uok + AOoAgzo5EeBeAEOgRg+BsmpEgSoqLKigfLiA3OwyykovofTkYkpJKKLEQ4UUF1VIMWEFiAIFFOZfQEE+ + BeTvVUg+HkXkCQi4wQk4u5eTg1sV2bjVkJVbPZm7NZKpRwuZeMEFeLfTXkBgT0AX7Q4GAMIh+Ohe2hHb + RzvjJQTS8N9ZgEB+N+0oZgjADVTDDdTDDTTBDbTBDXTW0oHuKjrYCzfQX0zmcAOWcAPWcAO2cAP2Ywnk + MBEj3IDrVChAEEgecAOecAPecAM+c04AgT35ww0ELlgCBOYAgSmFwg2EIxJEwA1ELu1FPNgDGOyGK9gF + GOyEK9iJeKCAIBWVLmCA/H8kjM6dPy20wJrgOzQee+yxiauvvjpec/SXH/7xS83Tf2640pt/GzUDb9y1 + a9ev4uLizqnXhvPGoJXDh8WYTQh1A0FfSq0v/sZV0wDt6l+r5n51l1+b3OgD8TdBKM3Iy60sfmRnJfOP + Sts/RUO88i8o4p8+LMUP8fEuv2NPnKeTYqPPs2tm/avE/9ZG4n9Xlh4AuvwvDwC9ILf/nn9eP/7j7b+c + /2fw+Yzj+zyMVYX3JfDWZGH/+XAQXwzS3iG+5jp5QEhxTfoGoCp+HQREDKgTpTQDa+Q5gWoqAQB4IsAu + IC+nnHIyEQXYBSQWUTJcQEJMIcXCBUSHFlB4YD6F+OVToHcB+XkWkrdbEbm7F5Oreyk5uZWTvSsg4FpD + lq51ZO7aQKbuzXTAo432eSEK+AIC/t0KBMIg+iiIHk5gB5zAjsQ+2pGKyuyl7XkAQXEX7SwHCKrbaVdd + K+3Gv/XeVoCgAyDoqqEDPZV0EG7ADG7AYjBfuoF0sh1LBgjiyHEiGiAIhyMIJtdpf4DAmzzhBrzhBnwQ + C/wW7AACa4DAAiAwQzw4SCFwA2ECBHsBgj1wBbsBgl0AwU4dCBIh/iSs/pnLB2jmdLdu9WdNhIWFvSZH + f9Hy6m+1+fdDefRXffjH1Zs+QS+1GXj93Xff/Y+enp4Z/Ixz7gEo5DtP/RBWdf2li11fDau717LWcxar + m3/N4oScED8/iAPib+joWNXwU8SPlX9Yn/n7WfxY+Ud45V9SxD8H8S9C/CvriP9JVfyv6Df6vCbF/6c/ + Q/wQtt72v0t/eVcpLQDeeluf/8X473WD7b9PPy22FvO4cR75f3plRfQkhkT+Hxc9i3YAgN1MU2enaG7W + yfwv7L+Ep7YByCv+qlIBwL0A6QDKZAwoLoYLKKyECyhXXABHgRStCyigmPB8RIF8Cg9QIBDglU++HgXk + BQh4uJaQi1spOboqELB2qSELQMAMEDjo1kz73QEBzw7a49NJuwGBXUGIAaEQfiREH9Mn3MCOBFRKP22X + ENhe1E3bS7toR2UH7axpo10NiAUtAEE7QNBZR/t7qsikr5xM+0sAggKyGM4lq5FMsh5NBQgSyX78EEAQ + CRCEwhEEwhH4ksesF0DgBhA4AwT2AIENQGCJeGAOEJhSMNxACCAQBgiEAwKRS7sBgl0AwU7Egx2AwQ7A + YBvVHAmns+dP6fb9QxO0bds2fuxXojz556o5+feJa/6tuyeA88v27dv/OzY29vwCVk5tL4Dv2PuwQt+o + 1vQDDBt/OvFrtvgadPuF+PkpxyNjwvb3I/MPzcwJ2z8O8U9B/LPHjknxn6GjEOEJKX5l1v8iPfPyy3Lc + 9/q64771xK+HwF/E/9fm/1Xbf1/QbP/lG4QRP3jL8RRcyahB/uevh7+2Jtn9F/m/sVlkf3H4p65BV5z9 + K0Tu11S1vtRegOgDyBhQJHoB5ZSXW0Y5WaWUlVZMaUmFlBxfCBdQQHER+XABeRQZlEdhAXmIAnkU4AkI + uAMCroXk5lYMCJQBAhVk51JFVs61ZOFST6YujWTi0kL7XNporwesvXcX7fJD3g+ECwjpo+0RKEBgexzE + H49K6qdt6X20LbeXthUCBCUMgU5AoJ12NgAE+Hff3dZEezvraV833EAv3EB/GZnCDZgN5QEE2QBBOhwB + 3MB4PGJBNDnBDThPwg1M+ZM73IDHrDtA4EzecAM+83bku2BF/osWFAg3EAg3EAw3EIpIELa8h8LhBCJF + 7aRoACAR2X9KZP+ntKv/q1/96lfL5M4/vvjTWl788RPUl6/Uk3+X3Az8/Oc/f4ebm1tKTU3Ne3oX8AQN + wKJWX6LAlbx6YfHXrBG/PP4rOv5YAXkMhszf0Naxutvfq2Z+rfj1K78qfj7Zt3DyJC2z+M9B/DzL1Wz0 + WTvue1MRv9zaayj+dw3Fv07+X7X993n99t8jIv+fVPI/b/9V8z8+f25etnL+70T+b+vU7f+vaVTyf9V6 + AFgFgVo9BCB+7gWUcS+golqJAWVVgEAlXEAF5QMCuTmllJ1RgihQRKkMgdgCio/Op9jwPIoOyaOIwDwK + 9QMEvPPI3yOffNwKyNNFgYCzSyk5OFeQrTMg4FRL5k71dNCxiQ44AgLOyPVugIAnLL4PrH4AXICAAIQf + M0DbYiF+gGBbEj5O66etOYBAPkMAVQEQVAME9R2AAGJBazPt6WikvV3sBqrpANzAwYFiMh0qIHO4ActV + biBWuAEnuAEXuAFXuAE3uAGPORUEDuQDN+DHIIAbCIAbCIQbCIIbCFnaS6FwA2FwA+FLO6niSAxW/9O6 + bb+1tbV86cc0sn+iHP25y3v/eOffv6Lu+CQ2/9bdGsxHGB9//PH/OnTo0Jm5uTldL+AohMRHbD+U+DWz + a8X6GzgHXfZfLf56jfgbRebv0WR+peHXJRp+40L8gzrxL0H8h5Vdfiz+06r4nxRWXOn4v7Bq3LdK/Bus + /O9qyhAAHBWU/P8nOf57VUwUVm3/Rfzg8aPI/wuLokHJ83++jqwDMNPl/zYl/4vuf2OTvvlXVy9Kzf0V + tarwDapaX2WVegCUlFZSUTFcQIHGBaQXU3pKIaXGF1BiTL5wATGhuXABuYgCuRQiXEAeXEA+ebsWkAcg + 4OpaTE7OpWQPCNg4VSsQcAAEHJpov2Mr7XVspz0uELE7XIA3ABAA6x8MAIRD+NEQ/iEGASpxgLam9dHW + bIYAqriHtpV30XZAYHs93EBTO+1qhRtob6I9XXADPTW0H27AZKCMDg7CDQznCzdgOZIBEKQABPFkPxFD + jpMR5DQRTM5wA67TPuQ24wFH4EJecAPecAM+C9ZwBJbkBzcQADcQtHgAjmAfiicE1jR7eli3+s/Pz/OV + 368g+5fK1V+99ksd/d3zSdn5d7Eu4MZbbrnldldX10TtzcHsBvio8AVFr92kUmcgfFHrNAO14ud5N5dY + +Vs/WPyjo9SDlb9PI/4xrPyTqvhPKOI/cu4cHdeK/4UX1sz6XzUQ/5/XE/977yllYP//zFuA2f6r+Z/H + f6+op/+U/H9Mzf/HjtPUymGD/D9CbZz/+fhvhz7/67r/EqaGANCBYD0ASBfAvYBSdgGIASWlcAHF0gWI + XgBcQKbiAkQUiCughKg8uIBcuIBcuIAcuIBcuIBcCvDIJR/XPPJyKSB3hoBLCTkCAnZOFWQNCFg61pGZ + fQOZ2DfTfgeGQBvtdgYE3AABL2R+f1QQIBAGCET1CwhsBQS2JgzQltR+2pIFEOShAIGtZd20rQogqOuk + HYDADnwvdrY30+7ORtrTXUf7eqtpfx+DoJRMBwsRC3IBgiyAII1s4Abs4AbsJ6IAgjBymgqCI/Aj1xkv + ckcs8JgDCOYcAAJbRAMrgMAC0cAUIDBBNNhPdcey8V7XH4zjJ/5u3rx56pprrkk02Pf/a3nt1xc2XQEP + /rysOwP5C3rooYd+GRkZeWQCole3B59Efm3r6BINqOp1Ba4Xf5Xhx2oTSy0D+1/TpABAzf113PBr36Dh + J0d9PWPjGvHP0xhsNYt/5pgq/tOK+LH6nsIqfFbu8mPxP6s72rv+rH9D8a8DgPXy/6rTf/j+8VbjJZn/ + J7X5H19D59CQkv/lvYD1ravHf1USAHxVmG7+r2n+sfUvZ7HLUgAgNwVVKS6gRBMDRC+goEJxAdmKC8hI + QRRIKKDkQ/kUDwgcCsulqOAciggABHxyKMgzh/zdAAGXPPJ0zic350JycS4hB6dSsnUEBByrycKhlkzt + AAE7FQLttNsJlt61m3Z4wuL7IfcDAltDAYBIiD9mkLYeGqQt8YO0OaWfNmcCBLl9tKWwl7aWAgSVAEEt + QNAAEDQDBG2ttKuziXZ3NdDenlpAoIoO9JeRySBiwTDHghydG7AZSwAIDpED3IDjZAg5TweQC2KB64wn + QOCKWOAER2BP3tIN+C6YUvyyFy2fndet/vze9/X1ffFLX/pSkSb7qxt/7pP7/tXHfl3zSQeAdiR401VX + XfWPdnZ2/gUFBW/z4SDd04Txxq0xyKP6ql+n1nEKhtm/ST/uE1t8pfgbpfi1K3+HtP2rxM8P2+CVHyvr + DAQ2f0LZ5Xf4rCr+p4X4uePPtnzt0V55pt9g3Leu+A0AsHr89yfd9V/PvPSygI1u+y8+l0WZ//naMT6K + rM7/Owb1+b9R2P823eYfXfYXwq9fv/lnAAAFAhoAVCkugCFQrLqAIqUXkMe9gMxiykxjF1BAKfH5iAJ5 + iAI5iALZFBmYTeF+WRTinU2BAgI5gEAueToxBIrI2YkhUEa2DhVkZV9N5rZ1dNC2gQ4AAvvskeMdYOUB + gR0u3bTdHTbfB6t8ACAQgoqA+BkCqC1xDIEB2pwBEOQwBFAlAEEFQFADENQjFjR10A7AcWcH3EAXu4F6 + 2tuLWNBfSQfgBg4OKU1C8xHFDViPJZHteBxAEAUQsBtALJj2J5cZb3KDG3CHG/CAG/CCG/BFtR2vlRfj + KHv+8/Ly/sK7/pD9EzTZX139v4O6829l9V/PBXzmF7/4xfcDAwOH+cknKgDOnD1L3XizVq4j9vV+bj3x + V68r/lZdx79eiL9Tv/L39lObJvPrxT9Dw3Ny5deJ/6RO/Ks2+qxzrl893SfGfRcrfpTaBDSc/6v2Xxn/ + vaQf/+m2/54QI0nO/4r9n6Qu5H9uZrbI/F8PANQCADVNLat2/lV+AADELkADCCgAqJEbg7gXUAUXUKm4 + gOIKRIFyRIEyRIESys6AC0gtpLREuIDYPEqIzqXYsGyKDs6GC8imMN8sCvbKRhTIJj/XXPJ2yiMPQMAV + EHByLCF7hzKycagkS7saMrNhCDTSAdtm2mvXpkDAsYt2OAMCboCAN8QfAAcQgoqQTiAaEIgdoseTB+jx + dDiBbFRBv4DAFoZAdQ8gABA0AQT4/uxol26gG26gt472wg3sH4AbGCoRbsBsGLEAbsAKbsB6NAEgOER2 + E5HkMBVKjtOBAIEvHIEXuc24AQaOlLoURyeeOC5Wf36f83ve0dHxidtuuy1bs/rbaFb/e+Tqf8Pfyuq/ + xgXwraYHDhwwS09Pf+Xo0aO6hqAyFmy5dPGr2b+hcVXuX9Pw69Bn/pY+Rfz6lV/J/APTs0L8oxD/BMQ/ + DfHPHdeIX8z6n9aN+9Rz/c9rxK/M+pXcL2b964j/PU1pAaC3/zL/C/v/ps7+K+O/5wSA+HYhPnQ0J/M/ + jygHAYBefC18T4GS/3vF183fA+6BcCQSq7+w/ioANsj8ssqra9aWCgA5ESgprxSXieoAkF+mTATgArLg + AtKTFReQdCiP4iNz6BBcQFRglnABod5ZiAJZcAHZ5OuSQ16AgLtjPrk4FUEsJWQHCFjbAwK2DIF6MrFp + ov22LbTHFhCw75AQQBRwRRTwBAT8kf+DAYBwiD+KncAQbY4dpMeTAIE0uAFAYHN+H20uRpUDBIDAlrpu + 2trYSdtaOmg7nOLOzhba2Q0Q9NTTHriBvXAD++EGTAaL4AjydW7AajQJsSAOIIgm+4lwOIIQOAJ/cprm + i0cCafTUqM7683s9OTn5zz/96U/5xF+c5tAPd/4fkKv/F67kO/8umwu4++67v+rl5VXNFyCqY0H+cXxi + UmR8dVXSHUxRxW/YG9Bkf17ZatSmnxz11eGNXy/F3yzE3yfFPwTxjwjxd6sr//SMRvwrEP9RiP8ELWq2 + +J5g8T+rmfXzuA/if/H19Wb9vL//wuJ/bwP7/5Y8/y/Gf2+op/+U8R///Zz/uQ+xdPK0aEzyYSSOLHxA + qUfkf3X+30MNBteD61Z/g8bfRgBQIVAmBa+IX+4KrFRjQJUCgBIlBvBEgF1ADlxAlnQBqYn5lByXR4lw + AXHh2RQTkkWRAVkU5scuIJMCPbLIDxDwAQQ8HXPJzbEAUUCFQDlZ21WShQ0gYF1HJtaNtN9GgcAuO1h4 + B2R6J6zmrrD3HljhfQGBIIg9DBWlRAKGwGOJgEBqPz2ehR/z8GMRIFDWS5urEQ3q4AgaAYJmuAG8b7bD + DezsaqZdcAO74Qb29FXTvoFyOjAIEAwVwhHkAgSZZDmaCjeQCBAobsB+Em5gKojKDtfI477KyJsvyt2/ + f//hG2+8MU1z5NdKzv1/Kg/93Pa3lP03nAiwzXn44Yd/Hx0dfVp9kpDyIJEz1IE3LdvPqlUAWNsbWE/8 + NZpuv1b8G678/BityUkamFHFv6iI/wiL/7gQ/wrEf/SJ83KjD8/6n9fN+p9b52ivYdPvQuJ/z8D+v7Oe + /VfHf+r2X3wOPHo8LI7/nhQHkXhEyScT+0X+H9Pl/ya5/1/b/Tdc/ZWxX514aMgauy9LFf+qqtSXgECZ + hICYCCguIC+3lHKy4ALSi5SxYAK7gFxKiMpBFMii6KBMivDPpFCfTAUC7oCAaxaiQDZ5AAKuiAPOjoXk + 4FBCtnblZGVbSebWNWQKCBywbqJ9DAEbRAFbiNYBVh4Q2OoCCLhjlfdBBTIEIP5IFOLA44cAgQSIPwWV + icpFFQIEZfi1VYBALdxAAyDQ1EXbWvFntrfTDuEGGuEGGgABuIEBuIHBMoCgGG4AsWAkG7EgHSBIJmu4 + AevxKIqYzcL75ohu9ef3eEBAwMtf/epX+VFfsahQlAtqlzzyyzf+fP6TPve/lH0Bn77hhhvusrKyCszL + y3tLfZCI2CG1vCxsvM4F1OkBUKkCYFXjr0nf8dfs8uPM34DMr+7tV8Q/QO2rxD+lET9W/mVF/LOw1Qsn + T9EyRKbb6PO0stFnzbjvdf2s/02DWb8q7I3ErwXAOzL/q9t/9bf/rB3/HQeQVnT5/7C4j4A3K/EFJTzJ + 4MYm5/9Gkf8V+1/N9h/fr8p6dfWv37DZd1EQ0AJA9gKKy/QuoFC6gNwc7gUUUWZqAaUl5VNKXC4lxuRQ + fEQ2okAmokAGokAGhXhnUJBHBvm7ZiIKZJGXYw65OwACiAOODoVkZ1dCNrblZGldRWZWNWRiVU/7AYG9 + Vi20y1pCwA7CdQAEnGHtGQLeqACIPxQxIAIVNUSPww08Fj9AjyUDCBmDCgQKAIFSVCUcQS2qHiBoAgha + EAvwPtre2Uo74AZ29gAEfXWIBOwGKgCCUjqgcQPmcANO42nUc2xMJ36+ECcnJ0dt/PHYL2qT8rQfc7nn + /980u/4+8XP/i94dyHbnX//1X7/v7e3d2YbcpV4hrjxUdELOpteZAAjhN6xt+mm3+MqGX1N397orv2r7 + B2D7h1j8EBCLf4rFD1Ep4udZvyL+U9qNPuvd4W94tFeb+6XIdaJ///31AXAx4z+x/fdpAaU1+X9Kyf+8 + i5HvL2hG/m+A+6mT+b+6Ucn/DNEKgx1/lwaAalk1uhggmoEVVbIXUAEIlAMCZVSQX6q4gGx2AYVwAflw + AXmUFAsARGVTbDhcQHAGokAGhfmmU7BnBqJABlxAJvk4ZZGnQza52+eSswMgYK9AwNqmnCysJAQs62mf + ZRPtsWpVIGDTSTvs4AQc4AKcsaK7AQBeKH8IPQQVDgBED8MJDNGjcQoEHktH5eBjAQHAoAI/1jAEenUQ + 2Aonua2jjbZ3tdCO7iba1VtPu/tr4QaqaN9gOUAANzCcL0aGBYuddO68fp9LO1yEpaXlyU9/+tOZmvP+ + fN0X3/b7H5uUp/2q9/1d+7cs/jW7A3m746OPProtNjb2qdnZWX0UgPi6ensvKP5qjfhX7e9fZftl5u8f + xMo/Qp2y4dcL8fer4oftHxfiP0IzupX/DB2GyI4L8T8jhPeE5g5/nvWvGve9tYH4DVd/Fr9a6wBgvfHf + 89rTf888K4CkjP9Oifw/sbQ6/zPkeLzJX39DeycAoIz/qhubLhEAa5t/evHrISDEz3sCVAAIFwAHUFRO + BYWIAXmligvILKIM1QXE5wkXEBeRJVxAdFAGRfilU5g3IOCVQQHugICLCoEccnPIAwQKAIFiQKAUEKgg + C8tqMrWsBQQaAIFm2mMJCFh10E5rOAHbHkCgT0BgsysE7Qlh+wEAwaiwIXoMTuAxxAEBgaQBBQLZqHx8 + XIICBB6rxu8DBDY3dtOWFlQbQAAxb4Mb2N6tdwN74AY4FuyFGwiZbMC/zUnR1Ob3Mu965Ys+v/3tb1fj + vR4vG3+86efAJuVZf/dqTvx96m999Td0AWx3br3xxhu/bG1tHZWfn/+2GgWelM8SaGxpky5Aa/2VzM8r + Wk1jC9Xw4RZNw69hlfgHqFWIf1iIn1d+rfhHFpaE+Cel+Ofl/v7D53jcp9/os/pcvxT/G+pNvppx3zuX + Lv53Dcd/Bqf/ntOO/555RuxBENt/dfl/WZf/u3X5v1+T/5Xxn9b+G273FeI2FPt6VSXtvrYq9FUiR4IC + AMUVAAD3AtgFlMheQCFlsAtIzKNkuICE6GxAIJNiQjKUKAAXEAIIBHmkIwqkk69zJnk7AgL2OeQKJ+AE + CDjYFZGtbSlZWeshcMACELBopt2AwE7LdtoOCGyzweptj1XcCRBwgZjdAQFfiDsIQkckeCwSLiAaEODm + YAIqDZWF/wYEHi3Gx+X4tVX4fYgEjzcABM2IBa1dtAXf022d+Du6EQt6mmgn3MAuuAG74XoaOr6ks/78 + Xmbr/+CDDw5fc801SZrGn7Uc+/0c9VV53v8Te+LvsowFv/Wtb/3Q09OzjacC6jZhrmm4AtG4kuKv0opf + NvwuKP6B9cU/CDKPLCgr/+RhVfynaOm0VvxP61Z+VfzPG8z61QM+2ht9NhL/+7I2Wv1X2/+3dOM//em/ + 58TnxKNI3orMNxDxwSRt/u9aL/+3yPGfAEC9eE4gA0A0/Wr09r50vUbfOrUGAOtAwNAF5EsXwBDITEMU + SGYXkEtJhwCByCyKDcugGI4C/ukKBDzTKNAdEHBJhwvIIC+HLESBbHJhCNgXkL1tEdnYlJKlVQWZW1bR + QQtAwLyB9po30y5zQMACArXqoq02EK0dIAA38LgzVnWGgA/EHYgKAQQiJAQQCR5LwMep+DgTlYf/LsKv + KQMEKvH7atkN4M9o6qHNrXADcFZbOwCCrjbhBvb2NlLF0qSu668+4svU1PS4tP6x8rIPZ9n4+2954Ec7 + 9rv67w0AurEg73767W9/+wjs0kn1ElH19qBBvKmV2bVW/PrML8TPV13xfXec+REdWvuVzL/hyi9s/7IQ + //SxY2LlXzytbvR5UjnXL8Z9z+uP9vK4b83R3tXn+tdt+mnEf1EAMBj/PaM9/afb/qvk/8mVFXE5iZj/ + j+vn/0r+7xTfmxqR/5vE6q8Xv972l23U5b8ECIhbgrQA0O0LUHoB+QWKC8jlXkCG4gLSknIpJS6HEqOz + hAs4FJqOKJBOEf5pFOqdSsEeaRTglkZ+zulwARmIAhICiAOOdoCATTHZWJchX1eSGZyAiXkd7TNroD1m + DIE2QAACZQhYAwK2CgQ2AwKPu0HUXhC3PyoYogcEHokZEhB4NB6VIiGQi48LUaX4dZX4PTUAgYBALz3e + AhC0wQ3ge7yts43iJ0fo5LmzOuvP72He7nvPPfeUS+vP+/09NymP+f5f1I8MGn9/V6v/ug3B66+//p/3 + 7t3rmZaW9vrhw4d1EOCHi3b19im5X3b7a3hP+6puf5do+LXg17XyAzAMxY/VUVn552kYK6ZyuOeI2N8/ + d0IR/wrEf1Re6nH6mWc1476X6Tkh/rXXeF+q+LUAWNf+rxn/vSImDuxChP3n8Z/M/zMi/y+LCQbfUdgz + qub/AX3+19n/Jl32F+I3yP0fFQB6F1AlegHFai+gtEI8cTifewH5cAA5xZSdVUSZ6QVwAXmUkpBDSbHZ + cAGZ0gWkU1RAGlxAKoV6pVKQeyoFuKaRrxMg4JBBHvZZ5GaXQ872gIBtAdkBAtZWZWRhUUmm5tV0wIwh + 0AgItAgI7GAIWHbrILDZvp82O0HMrhoIBEHk4YAAnACD4JE4VDI+zkABAo8AAo8AAo8CAo9Wo+r66LHG + PgGBx+AGvIeGEBtP68TP793k5OS3f/nLX3bifZ0orb+/3PHHT/n9d3nV1z/+vTT+LiYK8Pzzdry+4+Dg + UFRaWvqeelaAv7HHjh8Xj+IWTT8Wv7zJR4gftr+xa3W3Xyv+Hoi/D+IfQE5WxT/BK/9RKf5Tp1fN+ln8 + ZyF+/bjvVf1Nvm+uf6nHxYrfEACrtv/qxn/K5Z8vasd/zz0n+hHHn3hS3D7EW5OnDeb/nP/bkf9bZP7X + bv8V9l9t/l20+PXNvtL1qhJi15ZoAq4DgBIZA/IRA7gXoLqAVLiAROkCYrIoHi4gNjQDLiCNIv1SKQwu + IMQzlQLdUsnfORUQSEMUAATsssiVIWCXRw42BWQLCFhZlpG5OSBgVgMI1AMCTbTbtIV2msGim8OuW8C2 + W2HVtoFwAYHHBAQGBQQe9QMAAIFHwgfp4SiIPhofx6KSUOn47xz8WIAqwcflAEAVQ6CfHmnoJYvOQRqG + E3taip/fsyUlJe9t3bp17oYbbkiT1p8f8e0krf//aPb7f/rvqfF30VHgRz/60X95e3sPNTc3r+oHLEC4 + fKRVNP34ZJsq/s614u8YGaMuIX7F9g9oVn4W/5TY4nuCFiB+MeuX4j+FVfas4az/Vf2s3/Ayzw8lfgMA + GOb/19aM/17Uj//49h+4Fd6kpOT/pVX5v03k/z7xPVEAwPP/Ftj/Rtn8Ww2AMtnZL/0QpRO9tsr1xQBQ + dgdWUIEaA/IQA9gFZEoXkJJHqQm5lAwXkBiFKBCeQYdC2AWkUoSvhIAHIOCaiiiQRj6OgIB9BrkDAi6A + gJNtPqJAISBQgihQLiBwEBDYb1pPe00ZAq20w7SdtplJCFgyBGDh7QABR5QLxOwBCPgCAoEQediQgMDD + MRICiRB9Gn7MRuWjivHfpQP0MNzAroYBqp9f0b0/+b3a0tJC1tbWpz/3uc/lGXT9TVAPamb+t/0t7ve/ + HFGAD0Lc/cADD2wNDQ09PgR7pd0fMIXVTlhbafuVlb+PWlTbP8gr/xhW/gnYftnwkyv/KIt/5bAQ/yxW + UCF+rPxHWPxPasSPvP0Un+4T13h/wE2+G2z0ef8DVv/3Lnj6T3v5p3L678wzyu2/R2T+nxX5//Cq/N85 + rACAYajO/xmWVXBNFTL/lyP/l9XI3C87+6tX9UurNQDQQEBxARXCBRStcQFFlA0XoGwOQhSIRxRgFxDF + USAdUQAuwD9VHwU8UhAF4ALgBLwd0sjTLoPcbFUI5AkI2FgBAhblZAYImKgQONhEuw4CAgclBMy7aLMF + IGANCNgCAA5wAi4AgDvKBwIPQIUCAJEoRIKHDzEEUKn4OGuYHskDIAoHaWv5EOWPL9I5vCefku9Pfq/6 + +Pg8L3f7JcgNP75yu++jsutvtP4bvK7WTAX4G/T1LVu2OMXHx7/It6eo/QCm7Bje8LzCCfH3quIfWm37 + Jyc14l9QxH+YxS83+pySG32eeELkaiH+VR3/V9Y8tfdiZ/0bif8D87/28g/d+O9F5eEf6vgPwNLl/+UV + kf/7p6bF19wxPCyan03dPVTf0SlcEvdK1PFfucz/OvFfKM9/FAiIUaDeBRTBBRSKsWA55RcCAHlqLwAA + yJAuIDGHkuPgAqIzKS4inQ6FplFUIFyAXwpcQAqiQDIFuaeQv0sK+ToCAvbp5GmbSW42gIBtLjnCCdhZ + F5K1JSBgDgiYVdEB0xrad7Ce9gACO00kBEw7aItZt4RAnw4CjzpLCHgrEHg4BBXBEBgSbuDheFQKKhNO + AU4gsW+eTp97YtW8Pzo6+s2f/OQnLTL3qyf97FE7NimXfH57na6/8bXeNmGOAjfffPN3TU1NE7Oyst7S + NgXPYhUchsDFeX7u9g/KzD86Sl3jLP4pJfPP6cU/vqKIf+a4HPdpZv0nka25468e7X1GO+7Til/t+H9I + 8a+X/7Xbf9ff/fei2Icgxn9YbRhafC8B71gcQ/4fAuB4R2OXyP/DIv8zGLk3ouR//e4/FQCGuf8jAwBV + zLlfW+VqAQDSBYheQBFiQAFiQG6xcAFZmQWUkZZPacm5cAHZlHQoixKiMvQuICAFLiCZwrxSKNg9mQJd + ksnfKYV8HFLJyy6dPGzhBGyyyRkQcLDJJ1srQMC8lCzMKhAFGAK1gEAD7T7YLCCw3aSdtpp2SgjABVgB + ADYAgD3KCfbeDQL3wkrvzxAYpIcYAlFD9BAg8BAg8BAgENw0Q0dOn13V9MvIyOB5/8g111yTohn5uciT + fr+VG37+6e+9639JG4R4h9TnP//5n9na2pYWFRX95TjEq90pOIjcq5/zw/bDBnPm75tSGn5D8ws0ooof + gpk5dkIz639CjvueXjvuw8qr3OT7pr7j//bacd+7F5n7VwFgg/Hfn7Tjv9f147/z6sM/xPjvCXzup0Xv + QrH/i+LiEs7/nSL/D4k4xO6oTs3/fKYCAFB3/hkCQCvi9YS9tqrWreKKylWliwAGAOCJQEEh9wIUAGRn + FopeQAZcADcEVRcQDxcQCxcQHZSKKAAI+EgX4JZEAYCAn2MKokAqokAaudtkkiucgBMgYA8I2AACluYl + cAHldNC0mvab1CIKNNJuE0DgQBttM+mgrQc7abNpDz1u3kuPWfbRozb99KjdAD3CEHCFE/CAE/ADAIJR + sjnIEPAonaT5Y2fwPnxSt8+/sLCQm36zN954Y4bmmC/n/oNyr/9P5Dn/v8sNP5cKAN0DReQ37J/vueee + +52dndurqqreP3PmjK4ncBJi4OuvOvDm7xqT4p9eK/5JIX5l5V+E+Fc2Ev9LL1/wwZ0fpuN/0fl/zd3/ + r+rGf8rpv6d0479Zaf/5rsIBbf7v1+T/NjX/KwDQ2v9SLrnxp/QCot6wKtYvVfBqqacD1WmAOB9QXK40 + BEUvQLoAxIBMuIB0uIBUHguqLiCcXUAqokAKogBcgHcyhXgwBOACAAFfhoB9KlxAuoCAC5yAo00uokA+ + okARWZqVkplpBZkcZAjU0d4DDIEW2iEhsMUEEDjYTY+Z9dKjDAHrfnrEDuUIELgABIDAw35Y9YMG6Y+h + g+ScP0HTh0/rxM/vRb7f0sTE5Ogtt9ySI5t+kfKgj6XM/fxo72/Ivf43/z1u+PkoUeBm+Y372r333vuQ + l5fXhOFkgCHAt+B2IxL0XkD8c2KjD4v/nO5cv/4a7xchtpdXP7hzo5t81236fbD4ldV/df5XVv+/iHsD + 3pT5X3f3v2b8pzz8Uxn/8W3EM4gy4yL/L4j9/yL/D42I/Q9N3b0y/7dTNfJ/pWwAqs2/Um76aRp/H0bo + FwsAdRSolrInQAJAnBGQvQDVBaRqegExcAGR6XQoTLqAgGSKQBQI9UpGFEiiQNck8ndOJh9AwMsuBRBI + QxTIRBTIUiBgVUDWFkWIAqVkKiGw70At7dnfQDv3N9P2/YDAAYZAFyDQIyDwmAVcgFUfPWLLEAAAnLHy + uw/TQz5DZJc2QeNLp+hpKX6+2JM7/nZ2due+8IUvFMqmn7rV11Ye9PlPTe43jvw+5Gjw0/Ib+C//8R// + sScgIOBwR0fHKgicAAT4MEy/FD8f6x2T4p9m8es2+pylo+fVWf864z7NTb6vr3eTr0b8716i+A0BsN7u + PzX/v2Bw+u/k00+LMaXY/ivy/xEl/88h/08h/48h/w8NiTGoLv/zVevI/5UNjfruv27L7wd08T9CCcuv + qeIy2QhEFYoYUEEF3AwEBLgXkAMXkK32AtLzKS0ll1ISsikpNpMSojMoLiKNDoWkUnRgMkXCBYR7J1Go + Z5KMAknk55REPvbJCgRs0sjVOoOcEAccrFUIFAMCZWR6sJIOmFTDBdTR7v2NOghsZQgc6KLHGQKmcALm + AIBVPz1sO0APO8D2IxLYRI/TyOxJsfKrjWh+D7q5uT3zla98pVzT9AuUp/x2ynn/9+RBn1uMuf+j9QP4 + G3gX752+//77zQMDA493dXXpbhJSISAOxQjxr9DEEWWLr+G477hm1v8Ej/vETb7yqb2q+Dd4cOd64r80 + AHzQ6T9p/w3Gfyfk7T8Msdnjx8UNxXyCkfN/r8z/7Zz/e/upoUvJ/zUt0v5rdv/pAFB56QAovsgqMgSA + uiGoDOLnKi1XmoFid2CpsjswFwDgiQAAwC4gLSmHUuKz4AIyKAEuIBYu4FBwCkUJF5BEYV5JFOKeCBeQ + SAHOieTnqEDA0zaF3K3TyEVAIBsQyBNNQSuzYjI/WEYHBQRqAIF6AYEd+1tom4AAooCJCgFEAXM4AMsB + esh6kGzDxmho6oRO/Pye6+3tJbjR57/5zW9WSfGrR3ydNU2/H24w7zcC4EPuD7hVdlG//8ADD9iGhISc + 6evrWwWBk8hkfDkmi39KFf9pVfz6o71nnpXif9HgGu833vyAyzzf+1DWf73Vf6Px34urTv/pt/+ye1nQ + jP/U/N8j83+rmP/3ib0RuvzfwPbfIP8DACXaJp8U7qUKfXWtbgAWlVesLnUvQJlsBJaoMUCdCBTBBRTK + XkCe0gtIzKZkuIBEuADREIQLiAlMgQtIki4gEVEAEHBJJH+4AF8HdgHJiAKp5AYIOAMCjtbZZG+VRzaW + hWQJCJgBAiYmVbRfRIF62rWvCRBoBQTaacv+DkCgmx4z6aFHD/bSw6b9ZB88RsNTJ1eJny/19Pf3f+k7 + 3/lOHd6LSZqOPz/T74Dc5//jTcrV3mrT71qj+C9PU5A3CfG9aT/43e9+5xoeHn5+YGBgFQROQyj8kMwZ + WGVV/Mq5fuV035ln1z6yWzndp4pfHvC5jOJf3/6/exGXf2hO/+m2/x5TnI6Y/8+IDU9K/h+U+b9Ln/8Z + AHL8p4i/lkokAEo2Gt9tIOoNa53crxO9tkr1VahtBvLuwPxiysmRLiAjn9KFC1DHgkovIDYMAFjlAhIp + xCORgtgFqFGAIWALCFinkqtVOiCQKSBgBwhYWxQgCjAEysnkQBXt219De/ZJCOyDE9jHEOikxxEHGAKu + waM0Pr1a/IODg+Jar3vvvbcR78Fk2fHnq73cZcf/j9PWD/MAAB08SURBVJuUp/p8zdj0u/z9AN3RYTlS + +bcHH3zQMyws7LyhEzgDu8wPy1yCaA5j5T/G7kCK/9zz+qf2bnyTr+G5/o8m/lX2/9331rn8U738w2D3 + nxj/qdt/z4jxn5L/l2lwdl7M/7kByGNQPvrc2N1Dde2dVIP8X9XUQhXI/+UAQJkKANn804/uqi5K0B+m + tOIv1ABA9AEQAwrUGKDuC8grFi4gU90XkJIrG4JZiguIRAwABKKDkinKP4kifOACGALuCYBAAiCQQL6O + iYgCSYgCyYgCKQICTlaZ5GCVQ3aWgIB5IVmYlpCpiR4CuwGBnXubaPveFtoKCGze10HeoSM0M6c0/LQr + P6LnKz/84Q+bNOIPk+M+M9TDmo7/HXKzj7Hp91eaDPBOwa9dffXVP/3Nb37jERwcfLa7u3tVY/AsPj56 + Rmn6sfgNT/dtfJPv2x9wk++HEf8Hb//V3/3/qub037MitvCGpUV1+y8iDjc5eYcjH2/uHB2jtkHk/z6Z + /9s5/7fptv8q9l8rfv0e/ssldsPGX1G5JvNrSzYB+Uc9AMooj3cHansBOheQozQED2VQQlQaxYWn0qGQ + FIoOTKJI30REgQREgQQKdktAFEhAFAAEHAABO0DABhCwSiUXhgCcgD0gYGuRR1ZmRWRxUIHAAUBgz75a + uIB62rGnkbbva6XgqBGaWzglV37lIZ49PT3C9v/gBz9ovOqqq7Ti5+O9FpuUyz1+ifqWpuN/vVH8f73J + wP+TFov3Vf/0/vvvdwGdT/Hdazye0W0bZvHDPp/a4DJP7YM717vM83KIf0P7v2r331sa+68Z/yH/834F + Nf9zU5NvLObdjXyRKZ9y7BgeEfm/qVfJ/7VtbP9bNfZ/dfYv0TT+LlnUl1iFG0FA5wLKVvcC8tReQD5c + APcCcpReQFymaAjGR6RRbGgKxbALCIALAATCvBIQBeACGALOgABcgK99InkBAh6AgBtDwDKDHOEE7C1z + yMYynyxNi8jcpAQuoJz27wcE9tbSPpNGSk4bo8NH9Jt8+L3U2dlJ3t7ez3/3u9+tN1j5vaT4H9+k3OvH + 47475YE2Y8f//2g8eIe0XD/75S9/6ejr63uU9wnwBg0VAmzfTqNYUKtv8n39g8X/ruENvh8WAO994Ok/ + 5fKP15TLP2T+V+y/uv33pNz+u0xDcwtK/h+fUADA8/8ezfy/SZP/DZp/q7frfnSR66ti3SosK1c6/9oq + 0U8CVgOgWLiA7KwCMRFIT0UMSMoWEwExFoxK17gAHgtqXABHAbiAALgAP8cERAFAwDZJiQKWaeQsIJAF + J5BLNhaAwMEiMjMppQP7KsjCoo6Kiibo1OlzOvGfBXR5zs+jvn/5l3+plg0/rfgtpfh/tUm52ecu47jv + /64peI0GAp+XELjvxz/+sbWHh8dsdXU1ae8WZAic5X3bL7woZuzq6b431r3J911d7r8c4n//Inf/vbxm + 95+8/FNs/z0jDjCp9l/M/yen1+b/Ds7/7Ur+l93/MgCAd/6VrAOAyyXyVd1+g1ojfhUAxdIBqH0ANQZw + LyCHewGKCxD7AtgFyLFgPKKA0hBkF5AIF5BAYd7sAuIRBeIRBeLJ3zkeUQAQsEtEFNBAwCqDHAABO4tc + sjLPhwsoJFenWmpsmMFqf37V9l5+Dzk4ODzx1a9+teIDxM9n+78op1TGcd//MQSul5ZLhcDPvvnNbx6w + t7cfLCwsfFd7gOg8Fz5+BvZadPw/QPzvXm7xa3f/acd/a+7+f0n0KsTuP3n7jxj/If/zUeaRDfO/bADy + JaqNzQIAZRcAQFGFtOmXKOiLKUPbX8B2X1OiB1CsaQQWa1xAvuICsrKVjUGiF5DMvQDpAqLhAiLgAkKT + KTooiaL8JQS84gUEglwlBLgfYJ9A3gwBa0DAKoVcLNLIyTKd7C2yyMY8h8KC62lkaEm8P1TxHzlyBG6g + 6D3e3nvnnXcWyTl/rEHm1678WvEbx31XAAR+etddd203NTVtzszMfJuPEquNQRUEz8IJ8Njtom7yvYgT + fh/a/r91odN/z+jHf1iR+PYisf13YRH5f1bJ/yNj1AoAiPzf1U217R1U3dKq2/7LABDir67Rdf2LKtbv + 1F+qqC+lDAFQoE4BZOVrm4G8O5B7AXABWVkMAcUFcBRIjs+kxEPKRCA2LAVRIAlRIBFRIAFRIB5RgF1A + HCAQRwFwAX4O8YgC8eRtm0gegICbZTI5m6eSi3UWpae00tKS3iVy8XsF75m/bNu2be7WW2/N0WzyCdF0 + +x+Tmd8o/ivZCfzDP/zDY7t27SqOj49/bXh4WHRztW7gWdhsFt8HPbjzo4j/gwDwhmb8Z7j7j/M/71xk + +z+n5n8AgLc684EnNf/zXQiNnP91DcAWsf1XjP/E6q/s/NPm/mJNl/5yCv2SIKABgBoDFBdQvMoFZGbk + 6XsBcAHJsRmUCBcQr7qAQEMXAAAAAooLiEMUiIMLSEAUSAQAEinANYfqKvth88/onkTFEXFkZIRiY2Pf + +sMf/jB200038S2+CXJ7L1/nxQ/w5Ms8H5Hd/m/LzG8U/xUGAbUxyBsxfnzDDTf87+9///vYoKCg89zQ + 4Weza4n/1NNP06vI3izKv7b41737/0/r3f2v7v6T4z/d9l/9+K9valpcdybyPwNAcwBIP/9XZv+rrP8H + degve5XrS+36a6tYX3oA6GOAsi8AMSAtFy4gR/QCklQXwL2A8BSK0boAH8UFhLirLiCO/BzjyMdOgUBC + eAmNDM4KwauWn98TPD3y8/N78ec//3n7ddddl7ZJf7CHt/fymX4TzZz/W5qGn1H8V2BjUB0R8gMX+P61 + 3/zwhz90c3FxmS8rK3ufM54WAk/i4xdeekmsypdT/Bvm/wvs/hN3/8vLP7XjP13+X1gSpx3Xy/+1yP/V + rUr+L5f5X83+xRIARZcFAOVrhP1BpV/1IXTDKtZXnmgGlsgYUEzZuYXSBSgQSE1SewFwATFwAZFwAWHJ + FMO9ANEQjFeiAFyAiAIuseTvGAsgJFN5QTMdOay/T0LN+/yesLW1Pfv1r3+9Ujb7+EgvX+Xlv0m5yHPf + JuVM/32blEd4fUHT7TeK/wqGwD/KHYN8KOO/77nnHgszM7OutLS0tyYmJuQqoIkEEN4bsOPvXibxX+jw + j+7uf8Pdf+r4Tz39h/zP9l+X/2H/+/no88SUuANByf/9VC8AwPl/NQBKNAAo0jT+PhgA5Zcs9IKLqPyN + AFCk/liq7wOwC8hDDFjVCwAANL0AZXMQ9wK4IQgX4J9AEXABYV5xEH0sXEAsJUXkUl/XKJ09e26V5ef3 + QGpq6ts7duxYuP322/M1nX6+v5/v8bNH7Ub9fpPy6O6vy4hpOOc3iv8Kg4B2xyAfxvjyJuVY5n/ecsst + O/74xz9mBgcHP8WRgMc9hm7gRazE70Ckl0v8H7j773XD3X/P6MZ/i+r4D/mfrzXj/M/3HHaLBuAotcgN + QPWd3cj/HWIDUEVjEwDQQKW1svuvrv4Gh3QuaeW+jJV/QRdQutoF5LMLKFrtAtSJQBwAIF1ALLuAYHYB + CcIFhHnFioND1SWNtLJ0RP7b6kd8/G8fGBj48n/913/1yFt81GZfqBzz8aO7tqN+vUl5gMdXpKtUt/ca + xf8JgQAfIOLjmF+SXVt+IMND9957r4+9vf1MXl7eu3yZo+GU4Jlnn6XXIc6PEgU2yv/aR3+/subu/+d1 + u//E7T+nTos7DPka89GlJfFQk16R/yfEg07VBmAdPy+hzSD/16y2/8UG23ML/koC/zAQEJOAIgUA+RIA + ai9AAEDdF6C6gMQs2QsAAKJSFRcQqgAgGlEgJ6WIRocmdI1fFfLc5S8oKHjXwsLi1De+8Y0qubMvXpP3 + 3WSnnx/ecf8m5R4/Pnz2uU1r9/Ybxf8J2DGoniLkbi1v0/zmJuW01u+/8IUvWMD+1cbExLzC5wgMG4Si + N/DiS/QWxPrX2v33itz9t/r0nz7/z4v8f0zcbMSPMlPzP18A2jY0jPyv3QCktf/q7F+f/Qs1tl8nxI8T + ACx2XckxYNFaB6COBDM5BuhcAGJAQqboBSTEIAZEpIheQHpCLnW09NDxYydWZX3+t+X7I6Kiot6AAxzT + jPhUy6/m/QOy2fdLucGHj5/zCdSbNhlP9X1i3cC1slv7GTkh+Kq0df9z3XXXbb/vvvsinZ2dF+EG/jI9 + Pb2mN8CTgpewQr99ibFgw8s/5O6/19Tdf9pHfz/7rLiqjO8uWDP+W1gU+X/1/F/fAKxC/tfbfyX/67L/ + BgC4fLW6u59/EZXHdt+wivSVKyBQLGNAoeICBASUsWBKkt4FpCXmUGNtCy0vrehEr2Z9fuR8fn7+u9zo + +/73v19/zTXXpMouv9by8xVeu2Te/5ls9qljPvU8v1H8fyPNwc9p+gK8oeOhO+64w+bxxx+vDgsLe4Hz + Id8+bBgLnoY4X4VdZzF/5O2/PP57g3f/vbbG/uue/cen/9T8v7ysn/8DAO0i/ysbgOq7uqmmvYOqOP83 + NFFZnZL/1wDgku3/pYv6UmpDABRqAFBYLCEgNwZxL0COBVOSs8TtQbVVjTQ7M7dqnwf/yP+Gra2tFBIS + 8urvf//7kdtuuy1Xs+rzxZ18fZertPxbNilXeP1QLhB3yAXjBqP4/7YiwXXSzrGt+6Kc6fJ45/dYGXbd + e++9oTY2NtPp6elv81Ne+EDIqljA/YHnnqPXYN0vBIILjv/W7P57ZfXuP2H/z4kHl4jx32HYf+T/AZH/ + Z6hrHPl/WGkANvb0If8DAG0dVNncYgCAmgsCIF9U2V9d6JfNBYiJABwAAMD7A2prG2kK3w/tv5F6iIc3 + fuHf8B1TU9NjfG3X1VdfnaJZ9XlLr4/s8u/lBUAuBN+VC4Oa942d/r/hvsANcpb7eUn8H8qmz6NYKawf + eOCBHA8Pj5NFRUXvcizQri66RqEKgr+8e4nbfw0u/5B3/59RL/88r9/+y48w48tNh2X+75lUNgC1DY9Q + s9wApDYAK5taqLwB+b+ufm3+Z9GXfUAn/mOqC7mAvCLNNCCvUGwUqm9opunp2VUnPrV2n/fxu7q6Ps1P + 5r355puzNlj1eT8/39r7m03Knf2q5b9Nk/eN4v8bjwTXayLB3XJKwDu9+AGOO+688053xIKGoKCg52pr + a2kZNlzbH9DuH3gFK7l2dPhB+X/D8d9T+tN/Iv8fVfO/Mv/nJx51jHL+H6YmzQGgapH/m6msvpFKa7D6 + V+ntvyL+ilUNvysaABoXkMsAgAvgR4u1wOXMzs7r5vla4S/BIdXV1YnR3oMPPjh6++23F2g29fB2Xt7L + 742ykxt7uNH3K9T35V6R242W/+8TAtcZTAm+LhuE/81uALHA5Fvf+lbYvn37BqKiol5ubGwUIFDffKt6 + BBDwy1jReZV/1yD/82Ej/ek/fvT3Bnf/P6nafx7/nZDjv2UaXJX/x0T+b5T5v1bN/9wAZPsPABSr9l82 + /woMcv+VBIANXQCqHCDrwte5BAhqL3pRf1xZWSH+N4mMjHxj586dC/fcc0/5VVddpbX74bLD7yyz/la5 + 6v9Uxr8vyjh4s2a+bxT/32EkMHQD35a9gd/xm+baa6+1/O53vxsLEAxHR0e/2tTUJN586zkCBsFzsPSv + Q+T8KDHx7D+D7b8vrzP+4+cTCvsvx3/Tx5T5vzj+y/l/ep3836XmfwUAZRoAFAEAhZru/5Uqfi0AeMXn + vQp1iDPDcDpHEYG032N1xefvPTdr8W/xxu7du5f4wg78G6l7+GM1dp8v67SWHf4/yKz/Pbnqq42+Gw1G + fEbxG92A2O/NvYF7pVXk21534U1mc++99yaamJiMx8TEvFZfX08LsOfa1Ul394CcHLwAkau3DetP/2nH + f/rTf3z5Jz+0dE7m/3GR/5X9/z1T09Q5NiHz/+CqDUBK/tcAQGwAqtKL/woGAAufPy9+XiGv9nNwO+rj + 37TC5z4Mf6/5e85P4WXhf/Ob36zBv4k61uOcz3v4g+Voj+3+/k3K47nY0fG5kG/IrG+46huFbwTBGjfA + 24i/JBtEP1ZjAXeOb7zxRkc4goQ9e/YMhYSEvFBRUUFTU1O6jrQhDHhT0VOAwfMQPDf+1N1/2vx//CnN + 9l/k/0luAC4fVub/ogHIB4DGqW1IaQA2yAZgdaseALr5fxU7gCsTAOpqr4q+FV/DOL62Y8ePrxnlqV19 + /t5WVla+Hxwc/Arv3Yfwqz/1qU+laRp8UZqc77hJuaKbR3u/lU7uX6WzM2Z94+uS3MBn5JvmyzIW8CYR + 3h/ON8Lsv+aaa+y//vWvxzz66KPtvr6+T/JmIr6inE+ZGcYD9WoyvpXo/NNP05N8Selzz4tHf/GTivjq + cj7+y88yEPn/COf/FeT/ReoTzz6UDcAh2QAUOwC7xAnACgYANwC1AKi4cgCgip7tfSU+x1Z83hNwNEeP + HYN70m/XfUpj848ePUr8zAferu3t7f3cQw89NP7lL3+59OqrrzZc8UPkWI+Fbyq7+7yh59+l3f+KnPbc + Kjv8xlXf+LooN6BuHrpJvnk+L7Mjz4t/LleXzdJm2t15552hDzzwQLWFhcViXFzcGzw54JWLt6EaNg1V + Z3D2ifN0lp9SjDf8kbPnxMM/Of9PIf+Pc/6XDcBecQJwUj8B6FUAUNshdwA2NRsAoHo1AAwagHn/R4Ln + v5sPI9UDUL0DgzQzN4eV/gRW+vM6sWu/N2z9eZTHHf3Y2Ng/4Xt58le/+lW3PK2n7ttXM36wZsXnBt92 + OcH5pYxuX9PYfXWub1z1ja9LcgOGseAf5LTgq3J1+YUBCGxuvvlmn+985zvp27dvH8TK9VROTs5f+Gpp + PoiijQirYgIAwFeYn4YDOMrPMeQzALwDUNMA7NQ1AHkCII8AqwBo1AIAq/8GANAJ9LJ37+WhHvwd/OzB + hpZW6ukbEKv8YXwdLGzVERkWf0/4e8MP28zOzn7Xy8vr2c2bN0+zzcf3MlPa/HjZ1Y+QzT3O+A4a4f+v + 7NX8UOb8L8qG7qel3TfO9Y2vvyoIfi7HSxwN9qKsUC5wBVG/+MUvyvbt2zcdGBj4HN7g7/Abnd/wp06d + WpV1te5APNgEMDgFR3Dk5EmaWzlM4/PKo8D5IBCfAuQ9ANVyAlCumQCUyAagCgDtHoDLNabjo8J8zVhl + XT3VN7dQR08vjYyN09zCAh05emxVE8+w+Of5a+eGHoORvyf+/v4v7tmzZ/lnP/tZ2x133KGezVc7+nxS + L0yO89xlc89EjvQelJ39H0jhf0kKX9vdNwrf+LqsILhOripqo/BOmTO/K3sEvKf8YTl64hXKAbnV6wtf + +MKh//iP/6gGDGYCAgKe5wtLuaM9NjZGx0QWViYJTz/9tN4aG0QGbpLxU5BXILKF5RWaAkiGEQ26B4eo + FZGgnh8Jxs8DqFWOA5dW6p2Ackf/+ucAtNuExRN9+cEh+L1lcBNVAAuv6O0ATh/+nlE4kWnY9KXlZTpx + 4qT4vNXHshlmefVr4V/DXyN/rfw1Z2RkvMNXcHEnn6/h4o07mu26nO1j5GofJG2+s4TqPgnZ38qMz1b/ + 63LF/8d1hG+0+8bXX60/oAWB6gjukc1Cnhr8l7Sm3JTiY6Y8j3a+/vrr/QGD2J/85CdlW7duHXF0dDwZ + FRX1amlp6fvsDsbHx4mvM2fRrLuKGvwci+8cwHAGVvo0Vt5TiBDcUV/BnzGPCDE9O0eTiBATU1M0NjlJ + IxAwz9i5RvB3jQEgbNX517Cw5xcWaRmO4+ix43QSKzX3MPjPVoV+oc9F90Qmfizb0aM0ib+Pv6aSkpL3 + eXSHr/Xc448/Ps3P1+Ncf91116VKex8nLX6kbOr5aVZ7buztlFD9H9nV/57M+F80WPGNm3mMr48VBLyX + nDeY8MjpX6Q1/YWcHDwi38j8hubjp3zZpPenP/3piK9//etZ999/f9OuXbumXV1dn4iIiHgZ1vht3uXG + h5L40hKGAlvnjbL0x1HiacwABIudYw1/rvw55+TkvAuovebm5vYUj+1+9atfdX3ta1+r+MxnPpOlyfSq + vY+QDT0WvYfM9rxXf49c7X8n8/2/SbjeI2H7WZnxjSu+8XVF9Qh4g8kt0pJ+UcaDf5Wu4FfyDf2YjAgq + DNjiesEGB9x4442RX/7ylzPvu+++mscee2zIzMzssLu7+zO86y0rK+vtioqK99ra2sSjqvmgEoOBr7li + IZ7VrNQsTrbgH6bUxiT/Wfxn8p/NfwfvwOO/k/9u/hwqKyvf4wwfGxv7poeHx7MHDx489sgjj0z84he/ + 6PjKV75SftNNN2VcddVVSRrBx8hVPkzaex7fuWlEz/2TLdI53S8j1fekzf8nCdfbJGxvMArf+LpSQfAp + uTJ9WsaDz0tX8A35hua96P+5SZlXPyadgYmMCY7S/nL2DYSIoj772c8m3H333Vk//vGPa37/+9/3IjvP + WFlZHWW34O/v/3xMTAzD4d3i4uL3IUqRs1mg/FRbnqXzysxHZEdHR0XE4Asxufhj/jm+E59/Df9a/j18 + jp7/DP6zioqK3s/MzHyXLTxy+wsuLi7nLS0tj8OtzP/2t78d/NGPftT0pS99qfi2227LBry023EPGQhe + XeU9JfBsZY9kj0b0/y0bquyc+Pamf5arvWrzb9qkH+cZhW98XdEgUOOB1hXwG5m3GX9ZA4OfyE42TxEe + kt3tPdIdqEDgVdJLCohXzhDk5yiILvGLX/xiJiJE4fe///0KuIYGRImOBx98cABZe4JFamJictjc3PwY + gHHS3t7+jJOT0zmA4zyXs7PzE3Z2dmf4/+HXHMevPcKHauA8JgGaIfxZ3T/72c+av/e979XAwpfddddd + +bfeemvmtddeq96gqxV6lLTzYTLHB8gV3kMK3k6u8jwu3S4j0e9kr+Q+2dD7lrT4d0kHdatmtTfM90bh + G1+fOFeg9gq0MLhbNrQ4JvxIroD3S3E8LIGwWzoESykkJwkFTykyPyk4XmVDpRCjECmiUYeuueaaWFSc + rHgIOIELH2srHr82HpbdUNjRUtyR8s/lCpd/D/99gfLv95Zi596GvYSXqbT1LHjeRv2gbOT9u4xE35O9 + kn+Wor9dWnw12xtu3jGK3vj6xDcNtTBQncFnZb79klwBWRTf1QDhP6VD+IMU0jYJhQPSRltJS+0oBegm + xeitAYS/hESgrKANSv3/AfL3+Mk/w1sCx13+HY4SRtZyZTeRYt+xSdkY9ZCE2P1S8Ox0vi9X+a/KTP8F + CUJ1pVdFf51xtTe+/h4ighYGN8mV71Ypis9rgPAN6RDulSvnz2VD8X+kyP4oLfVmudrukmJkQByUkLCQ + DsJKitZGlq2mbOT/s5a/ln+Pufwz+M/aJ8GzQ+b2R+XfzSv7r6Wd/3fZ4/ihhNi/yEboP8k8f7vsi3xG + AlC190bRG19/tzDQ9gy07kAFguoQ7pRCYsv8dbmafkeCgcdk3DX/hewp/JcEBAvzt7Lh+L/SRTwk62GD + Un/+j/LXPigB8xv5Z90vwfPvMrf/WDbs2Mp/W4LqKzLW3CUh9jlp69cTvKG9N4re+DICQdM3MHQIN0sh + qVD4RymyO6Vb+LJ0DF+TYvymFOZ3pEi/LwX7Q1k/Mij1538gofI9uYr/q4TNv0jwfEVC6J80Qr9dI/Zb + pKW/SX7u12sEf41R9MaX8XVxMDB0CNdqXML1MjPfpHELt0g4/IMGELdL96CC4k4pWq4vrlN3aX7d5+Xv + vV3+WZ+Tf7Yq8s9ohH7jOqv7NZrP3yh448v4usxguMYADFo4XC8FqUJCBcXNUrQfVDdrfp8qbnU1/5Tm + 77tW83lcbczwxpfx9fEAQesWrjZwDlpQXEpds464r95gVTeK3vgyvj4hoLjUMr6ML+PL+DK+jC/jy/gy + vowv48v4Mr6ML+PL+DK+jC/jy/gyvowv48v4Mr6ML+PL+DK+jC/jy/gyvowv48v4Mr6ML+PL+DK+jC/j + y/gyvowv48v4Mr6ML+PL+DK+rpTX/wfqHFXzmzx8YgAAAABJRU5ErkJggg== + + + \ No newline at end of file diff --git a/DICUI.Forms/Windows/OptionsWindow.Designer.cs b/DICUI.Forms/Windows/OptionsWindow.Designer.cs new file mode 100644 index 00000000..8f5aeec4 --- /dev/null +++ b/DICUI.Forms/Windows/OptionsWindow.Designer.cs @@ -0,0 +1,565 @@ +namespace DICUI.Forms.Windows +{ + partial class OptionsWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.pathsGroupBox = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.DefaultOutputPathButton = new System.Windows.Forms.Button(); + this.SubDumpPathButton = new System.Windows.Forms.Button(); + this.discImageCreatorPathLabel = new System.Windows.Forms.Label(); + this.subdumpPathLabel = new System.Windows.Forms.Label(); + this.defaultOutputPathLabel = new System.Windows.Forms.Label(); + this.DICPathTextBox = new System.Windows.Forms.TextBox(); + this.SubDumpPathTextBox = new System.Windows.Forms.TextBox(); + this.DefaultOutputPathTextBox = new System.Windows.Forms.TextBox(); + this.DICPathButton = new System.Windows.Forms.Button(); + this.preferredSpeedGroupBox = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.DumpSpeedCDLabel = new System.Windows.Forms.Label(); + this.DumpSpeedDVDLabel = new System.Windows.Forms.Label(); + this.DumpSpeedBDLabel = new System.Windows.Forms.Label(); + this.DumpSpeedCDSlider = new System.Windows.Forms.TrackBar(); + this.DumpSpeedDVDSlider = new System.Windows.Forms.TrackBar(); + this.DumpSpeedBDSlider = new System.Windows.Forms.TrackBar(); + this.DumpSpeedCDTextBox = new System.Windows.Forms.TextBox(); + this.DumpSpeedDVDTextBox = new System.Windows.Forms.TextBox(); + this.DumpSpeedBDTextBox = new System.Windows.Forms.TextBox(); + this.optionsGroupBox = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.QuietModeCheckBox = new System.Windows.Forms.CheckBox(); + this.AutoScanCheckBox = new System.Windows.Forms.CheckBox(); + this.ParanoidModeCheckBox = new System.Windows.Forms.CheckBox(); + this.SkipDetectionCheckBox = new System.Windows.Forms.CheckBox(); + this.C2RereadTimesTextBox = new System.Windows.Forms.TextBox(); + this.C2RereadLabel = new System.Windows.Forms.Label(); + this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel(); + this.AcceptButton = new System.Windows.Forms.Button(); + this.CancelButton = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); + this.pathsGroupBox.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.preferredSpeedGroupBox.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.DumpSpeedCDSlider)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.DumpSpeedDVDSlider)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.DumpSpeedBDSlider)).BeginInit(); + this.optionsGroupBox.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.tableLayoutPanel5.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.pathsGroupBox, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.preferredSpeedGroupBox, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.optionsGroupBox, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel5, 0, 3); + this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 12); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 4; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 150F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(475, 417); + this.tableLayoutPanel1.TabIndex = 0; + this.tableLayoutPanel1.UseWaitCursor = true; + // + // pathsGroupBox + // + this.pathsGroupBox.Controls.Add(this.tableLayoutPanel2); + this.pathsGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.pathsGroupBox.Location = new System.Drawing.Point(3, 3); + this.pathsGroupBox.Name = "pathsGroupBox"; + this.pathsGroupBox.Size = new System.Drawing.Size(469, 121); + this.pathsGroupBox.TabIndex = 0; + this.pathsGroupBox.TabStop = false; + this.pathsGroupBox.Text = "Paths"; + this.pathsGroupBox.UseWaitCursor = true; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 3; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 29.41176F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 58.82353F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 11.76471F)); + this.tableLayoutPanel2.Controls.Add(this.DefaultOutputPathButton, 2, 2); + this.tableLayoutPanel2.Controls.Add(this.SubDumpPathButton, 2, 1); + this.tableLayoutPanel2.Controls.Add(this.discImageCreatorPathLabel, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.subdumpPathLabel, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.defaultOutputPathLabel, 0, 2); + this.tableLayoutPanel2.Controls.Add(this.DICPathTextBox, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.SubDumpPathTextBox, 1, 1); + this.tableLayoutPanel2.Controls.Add(this.DefaultOutputPathTextBox, 1, 2); + this.tableLayoutPanel2.Controls.Add(this.DICPathButton, 2, 0); + this.tableLayoutPanel2.Location = new System.Drawing.Point(6, 15); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 3; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(457, 100); + this.tableLayoutPanel2.TabIndex = 0; + this.tableLayoutPanel2.UseWaitCursor = true; + // + // DefaultOutputPathButton + // + this.DefaultOutputPathButton.Location = new System.Drawing.Point(405, 69); + this.DefaultOutputPathButton.Name = "DefaultOutputPathButton"; + this.DefaultOutputPathButton.Size = new System.Drawing.Size(49, 23); + this.DefaultOutputPathButton.TabIndex = 8; + this.DefaultOutputPathButton.Text = "..."; + this.DefaultOutputPathButton.UseVisualStyleBackColor = true; + this.DefaultOutputPathButton.UseWaitCursor = true; + this.DefaultOutputPathButton.Click += new System.EventHandler(this.BrowseForPathClick); + // + // SubDumpPathButton + // + this.SubDumpPathButton.Location = new System.Drawing.Point(405, 36); + this.SubDumpPathButton.Name = "SubDumpPathButton"; + this.SubDumpPathButton.Size = new System.Drawing.Size(49, 23); + this.SubDumpPathButton.TabIndex = 7; + this.SubDumpPathButton.Text = "..."; + this.SubDumpPathButton.UseVisualStyleBackColor = true; + this.SubDumpPathButton.UseWaitCursor = true; + this.SubDumpPathButton.Click += new System.EventHandler(this.BrowseForPathClick); + // + // discImageCreatorPathLabel + // + this.discImageCreatorPathLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.discImageCreatorPathLabel.AutoSize = true; + this.discImageCreatorPathLabel.Cursor = System.Windows.Forms.Cursors.WaitCursor; + this.discImageCreatorPathLabel.Location = new System.Drawing.Point(15, 10); + this.discImageCreatorPathLabel.Name = "discImageCreatorPathLabel"; + this.discImageCreatorPathLabel.Size = new System.Drawing.Size(116, 13); + this.discImageCreatorPathLabel.TabIndex = 0; + this.discImageCreatorPathLabel.Text = "DiscImageCreator Path"; + // + // subdumpPathLabel + // + this.subdumpPathLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.subdumpPathLabel.AutoSize = true; + this.subdumpPathLabel.Location = new System.Drawing.Point(56, 43); + this.subdumpPathLabel.Name = "subdumpPathLabel"; + this.subdumpPathLabel.Size = new System.Drawing.Size(75, 13); + this.subdumpPathLabel.TabIndex = 1; + this.subdumpPathLabel.Text = "subdump Path"; + this.subdumpPathLabel.UseWaitCursor = true; + // + // defaultOutputPathLabel + // + this.defaultOutputPathLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.defaultOutputPathLabel.AutoSize = true; + this.defaultOutputPathLabel.Location = new System.Drawing.Point(30, 76); + this.defaultOutputPathLabel.Name = "defaultOutputPathLabel"; + this.defaultOutputPathLabel.Size = new System.Drawing.Size(101, 13); + this.defaultOutputPathLabel.TabIndex = 2; + this.defaultOutputPathLabel.Text = "Default Output Path"; + this.defaultOutputPathLabel.UseWaitCursor = true; + // + // DICPathTextBox + // + this.DICPathTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.DICPathTextBox.Location = new System.Drawing.Point(138, 6); + this.DICPathTextBox.Name = "DICPathTextBox"; + this.DICPathTextBox.Size = new System.Drawing.Size(259, 20); + this.DICPathTextBox.TabIndex = 3; + this.DICPathTextBox.UseWaitCursor = true; + // + // SubDumpPathTextBox + // + this.SubDumpPathTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.SubDumpPathTextBox.Location = new System.Drawing.Point(138, 39); + this.SubDumpPathTextBox.Name = "SubDumpPathTextBox"; + this.SubDumpPathTextBox.Size = new System.Drawing.Size(259, 20); + this.SubDumpPathTextBox.TabIndex = 4; + this.SubDumpPathTextBox.UseWaitCursor = true; + // + // DefaultOutputPathTextBox + // + this.DefaultOutputPathTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.DefaultOutputPathTextBox.Location = new System.Drawing.Point(138, 73); + this.DefaultOutputPathTextBox.Name = "DefaultOutputPathTextBox"; + this.DefaultOutputPathTextBox.Size = new System.Drawing.Size(259, 20); + this.DefaultOutputPathTextBox.TabIndex = 5; + this.DefaultOutputPathTextBox.UseWaitCursor = true; + // + // DICPathButton + // + this.DICPathButton.Location = new System.Drawing.Point(405, 3); + this.DICPathButton.Name = "DICPathButton"; + this.DICPathButton.Size = new System.Drawing.Size(49, 23); + this.DICPathButton.TabIndex = 6; + this.DICPathButton.Text = "..."; + this.DICPathButton.UseVisualStyleBackColor = true; + this.DICPathButton.UseWaitCursor = true; + this.DICPathButton.Click += new System.EventHandler(this.BrowseForPathClick); + // + // preferredSpeedGroupBox + // + this.preferredSpeedGroupBox.Controls.Add(this.tableLayoutPanel3); + this.preferredSpeedGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.preferredSpeedGroupBox.Location = new System.Drawing.Point(3, 130); + this.preferredSpeedGroupBox.Name = "preferredSpeedGroupBox"; + this.preferredSpeedGroupBox.Size = new System.Drawing.Size(469, 144); + this.preferredSpeedGroupBox.TabIndex = 1; + this.preferredSpeedGroupBox.TabStop = false; + this.preferredSpeedGroupBox.Text = "Preferred Dump Speed"; + this.preferredSpeedGroupBox.UseWaitCursor = true; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.ColumnCount = 3; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 80F)); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel3.Controls.Add(this.DumpSpeedCDLabel, 0, 0); + this.tableLayoutPanel3.Controls.Add(this.DumpSpeedDVDLabel, 0, 1); + this.tableLayoutPanel3.Controls.Add(this.DumpSpeedBDLabel, 0, 2); + this.tableLayoutPanel3.Controls.Add(this.DumpSpeedCDSlider, 1, 0); + this.tableLayoutPanel3.Controls.Add(this.DumpSpeedDVDSlider, 1, 1); + this.tableLayoutPanel3.Controls.Add(this.DumpSpeedBDSlider, 1, 2); + this.tableLayoutPanel3.Controls.Add(this.DumpSpeedCDTextBox, 2, 0); + this.tableLayoutPanel3.Controls.Add(this.DumpSpeedDVDTextBox, 2, 1); + this.tableLayoutPanel3.Controls.Add(this.DumpSpeedBDTextBox, 2, 2); + this.tableLayoutPanel3.Location = new System.Drawing.Point(6, 19); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 3; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(457, 119); + this.tableLayoutPanel3.TabIndex = 0; + this.tableLayoutPanel3.UseWaitCursor = true; + // + // DumpSpeedCDLabel + // + this.DumpSpeedCDLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.DumpSpeedCDLabel.AutoSize = true; + this.DumpSpeedCDLabel.Location = new System.Drawing.Point(3, 13); + this.DumpSpeedCDLabel.Name = "DumpSpeedCDLabel"; + this.DumpSpeedCDLabel.Size = new System.Drawing.Size(50, 13); + this.DumpSpeedCDLabel.TabIndex = 0; + this.DumpSpeedCDLabel.Text = "CD-ROM"; + this.DumpSpeedCDLabel.UseWaitCursor = true; + // + // DumpSpeedDVDLabel + // + this.DumpSpeedDVDLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.DumpSpeedDVDLabel.AutoSize = true; + this.DumpSpeedDVDLabel.Location = new System.Drawing.Point(3, 52); + this.DumpSpeedDVDLabel.Name = "DumpSpeedDVDLabel"; + this.DumpSpeedDVDLabel.Size = new System.Drawing.Size(58, 13); + this.DumpSpeedDVDLabel.TabIndex = 1; + this.DumpSpeedDVDLabel.Text = "DVD-ROM"; + this.DumpSpeedDVDLabel.UseWaitCursor = true; + // + // DumpSpeedBDLabel + // + this.DumpSpeedBDLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.DumpSpeedBDLabel.AutoSize = true; + this.DumpSpeedBDLabel.Location = new System.Drawing.Point(3, 92); + this.DumpSpeedBDLabel.Name = "DumpSpeedBDLabel"; + this.DumpSpeedBDLabel.Size = new System.Drawing.Size(50, 13); + this.DumpSpeedBDLabel.TabIndex = 2; + this.DumpSpeedBDLabel.Text = "BD-ROM"; + this.DumpSpeedBDLabel.UseWaitCursor = true; + // + // DumpSpeedCDSlider + // + this.DumpSpeedCDSlider.Dock = System.Windows.Forms.DockStyle.Fill; + this.DumpSpeedCDSlider.Location = new System.Drawing.Point(83, 3); + this.DumpSpeedCDSlider.Name = "DumpSpeedCDSlider"; + this.DumpSpeedCDSlider.Size = new System.Drawing.Size(331, 33); + this.DumpSpeedCDSlider.TabIndex = 3; + this.DumpSpeedCDSlider.UseWaitCursor = true; + this.DumpSpeedCDSlider.Value = 1; + this.DumpSpeedCDSlider.Scroll += new System.EventHandler(this.SliderChanged); + // + // DumpSpeedDVDSlider + // + this.DumpSpeedDVDSlider.Dock = System.Windows.Forms.DockStyle.Fill; + this.DumpSpeedDVDSlider.Location = new System.Drawing.Point(83, 42); + this.DumpSpeedDVDSlider.Name = "DumpSpeedDVDSlider"; + this.DumpSpeedDVDSlider.Size = new System.Drawing.Size(331, 33); + this.DumpSpeedDVDSlider.TabIndex = 4; + this.DumpSpeedDVDSlider.UseWaitCursor = true; + this.DumpSpeedDVDSlider.Value = 1; + this.DumpSpeedDVDSlider.Scroll += new System.EventHandler(this.SliderChanged); + // + // DumpSpeedBDSlider + // + this.DumpSpeedBDSlider.Dock = System.Windows.Forms.DockStyle.Fill; + this.DumpSpeedBDSlider.Location = new System.Drawing.Point(83, 81); + this.DumpSpeedBDSlider.Name = "DumpSpeedBDSlider"; + this.DumpSpeedBDSlider.Size = new System.Drawing.Size(331, 35); + this.DumpSpeedBDSlider.TabIndex = 5; + this.DumpSpeedBDSlider.UseWaitCursor = true; + this.DumpSpeedBDSlider.Value = 1; + this.DumpSpeedBDSlider.Scroll += new System.EventHandler(this.SliderChanged); + // + // DumpSpeedCDTextBox + // + this.DumpSpeedCDTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.DumpSpeedCDTextBox.Enabled = false; + this.DumpSpeedCDTextBox.Location = new System.Drawing.Point(420, 9); + this.DumpSpeedCDTextBox.Name = "DumpSpeedCDTextBox"; + this.DumpSpeedCDTextBox.ReadOnly = true; + this.DumpSpeedCDTextBox.Size = new System.Drawing.Size(34, 20); + this.DumpSpeedCDTextBox.TabIndex = 6; + this.DumpSpeedCDTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + this.DumpSpeedCDTextBox.UseWaitCursor = true; + // + // DumpSpeedDVDTextBox + // + this.DumpSpeedDVDTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.DumpSpeedDVDTextBox.Enabled = false; + this.DumpSpeedDVDTextBox.Location = new System.Drawing.Point(420, 48); + this.DumpSpeedDVDTextBox.Name = "DumpSpeedDVDTextBox"; + this.DumpSpeedDVDTextBox.ReadOnly = true; + this.DumpSpeedDVDTextBox.Size = new System.Drawing.Size(34, 20); + this.DumpSpeedDVDTextBox.TabIndex = 7; + this.DumpSpeedDVDTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + this.DumpSpeedDVDTextBox.UseWaitCursor = true; + // + // DumpSpeedBDTextBox + // + this.DumpSpeedBDTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.DumpSpeedBDTextBox.Enabled = false; + this.DumpSpeedBDTextBox.Location = new System.Drawing.Point(420, 88); + this.DumpSpeedBDTextBox.Name = "DumpSpeedBDTextBox"; + this.DumpSpeedBDTextBox.ReadOnly = true; + this.DumpSpeedBDTextBox.Size = new System.Drawing.Size(34, 20); + this.DumpSpeedBDTextBox.TabIndex = 8; + this.DumpSpeedBDTextBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + this.DumpSpeedBDTextBox.UseWaitCursor = true; + // + // optionsGroupBox + // + this.optionsGroupBox.Controls.Add(this.tableLayoutPanel4); + this.optionsGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.optionsGroupBox.Location = new System.Drawing.Point(3, 280); + this.optionsGroupBox.Name = "optionsGroupBox"; + this.optionsGroupBox.Size = new System.Drawing.Size(469, 94); + this.optionsGroupBox.TabIndex = 2; + this.optionsGroupBox.TabStop = false; + this.optionsGroupBox.Text = "Options"; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 4; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel4.Controls.Add(this.QuietModeCheckBox, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.AutoScanCheckBox, 0, 1); + this.tableLayoutPanel4.Controls.Add(this.ParanoidModeCheckBox, 1, 0); + this.tableLayoutPanel4.Controls.Add(this.SkipDetectionCheckBox, 2, 1); + this.tableLayoutPanel4.Controls.Add(this.C2RereadTimesTextBox, 3, 0); + this.tableLayoutPanel4.Controls.Add(this.C2RereadLabel, 2, 0); + this.tableLayoutPanel4.Location = new System.Drawing.Point(6, 19); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 2; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(457, 69); + this.tableLayoutPanel4.TabIndex = 0; + // + // QuietModeCheckBox + // + this.QuietModeCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.QuietModeCheckBox.AutoSize = true; + this.QuietModeCheckBox.Location = new System.Drawing.Point(3, 8); + this.QuietModeCheckBox.Name = "QuietModeCheckBox"; + this.QuietModeCheckBox.Size = new System.Drawing.Size(81, 17); + this.QuietModeCheckBox.TabIndex = 0; + this.QuietModeCheckBox.Text = "Quiet Mode"; + this.QuietModeCheckBox.UseVisualStyleBackColor = true; + // + // AutoScanCheckBox + // + this.AutoScanCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.AutoScanCheckBox.AutoSize = true; + this.tableLayoutPanel4.SetColumnSpan(this.AutoScanCheckBox, 2); + this.AutoScanCheckBox.Location = new System.Drawing.Point(3, 43); + this.AutoScanCheckBox.Name = "AutoScanCheckBox"; + this.AutoScanCheckBox.Size = new System.Drawing.Size(182, 17); + this.AutoScanCheckBox.TabIndex = 1; + this.AutoScanCheckBox.Text = "Automatically Scan for Protection"; + this.AutoScanCheckBox.UseVisualStyleBackColor = true; + // + // ParanoidModeCheckBox + // + this.ParanoidModeCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.ParanoidModeCheckBox.AutoSize = true; + this.ParanoidModeCheckBox.Location = new System.Drawing.Point(117, 8); + this.ParanoidModeCheckBox.Name = "ParanoidModeCheckBox"; + this.ParanoidModeCheckBox.Size = new System.Drawing.Size(98, 17); + this.ParanoidModeCheckBox.TabIndex = 2; + this.ParanoidModeCheckBox.Text = "Paranoid Mode"; + this.ParanoidModeCheckBox.UseVisualStyleBackColor = true; + // + // SkipDetectionCheckBox + // + this.SkipDetectionCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.SkipDetectionCheckBox.AutoSize = true; + this.tableLayoutPanel4.SetColumnSpan(this.SkipDetectionCheckBox, 2); + this.SkipDetectionCheckBox.Location = new System.Drawing.Point(231, 43); + this.SkipDetectionCheckBox.Name = "SkipDetectionCheckBox"; + this.SkipDetectionCheckBox.Size = new System.Drawing.Size(155, 17); + this.SkipDetectionCheckBox.TabIndex = 3; + this.SkipDetectionCheckBox.Text = "Skip Media Type Detection"; + this.SkipDetectionCheckBox.UseVisualStyleBackColor = true; + // + // C2RereadTimesTextBox + // + this.C2RereadTimesTextBox.Anchor = System.Windows.Forms.AnchorStyles.None; + this.C2RereadTimesTextBox.Location = new System.Drawing.Point(349, 7); + this.C2RereadTimesTextBox.Name = "C2RereadTimesTextBox"; + this.C2RereadTimesTextBox.Size = new System.Drawing.Size(100, 20); + this.C2RereadTimesTextBox.TabIndex = 4; + // + // C2RereadLabel + // + this.C2RereadLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.C2RereadLabel.AutoSize = true; + this.C2RereadLabel.Location = new System.Drawing.Point(250, 10); + this.C2RereadLabel.Name = "C2RereadLabel"; + this.C2RereadLabel.Size = new System.Drawing.Size(89, 13); + this.C2RereadLabel.TabIndex = 5; + this.C2RereadLabel.Text = "C2 Reread Times"; + // + // tableLayoutPanel5 + // + this.tableLayoutPanel5.ColumnCount = 2; + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel5.Controls.Add(this.AcceptButton, 0, 0); + this.tableLayoutPanel5.Controls.Add(this.CancelButton, 1, 0); + this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel5.Location = new System.Drawing.Point(3, 380); + this.tableLayoutPanel5.Name = "tableLayoutPanel5"; + this.tableLayoutPanel5.RowCount = 1; + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel5.Size = new System.Drawing.Size(469, 34); + this.tableLayoutPanel5.TabIndex = 3; + // + // AcceptButton + // + this.AcceptButton.Anchor = System.Windows.Forms.AnchorStyles.None; + this.AcceptButton.Location = new System.Drawing.Point(79, 5); + this.AcceptButton.Name = "AcceptButton"; + this.AcceptButton.Size = new System.Drawing.Size(75, 23); + this.AcceptButton.TabIndex = 0; + this.AcceptButton.Text = "Accept"; + this.AcceptButton.UseVisualStyleBackColor = true; + this.AcceptButton.Click += new System.EventHandler(this.OnAcceptClick); + // + // CancelButton + // + this.CancelButton.Anchor = System.Windows.Forms.AnchorStyles.None; + this.CancelButton.Location = new System.Drawing.Point(314, 5); + this.CancelButton.Name = "CancelButton"; + this.CancelButton.Size = new System.Drawing.Size(75, 23); + this.CancelButton.TabIndex = 1; + this.CancelButton.Text = "Cancel"; + this.CancelButton.UseVisualStyleBackColor = true; + this.CancelButton.Click += new System.EventHandler(this.OnCancelClick); + // + // OptionsWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(499, 441); + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "OptionsWindow"; + this.ShowIcon = false; + this.Text = "Options"; + this.UseWaitCursor = true; + this.tableLayoutPanel1.ResumeLayout(false); + this.pathsGroupBox.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.preferredSpeedGroupBox.ResumeLayout(false); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.DumpSpeedCDSlider)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.DumpSpeedDVDSlider)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.DumpSpeedBDSlider)).EndInit(); + this.optionsGroupBox.ResumeLayout(false); + this.tableLayoutPanel4.ResumeLayout(false); + this.tableLayoutPanel4.PerformLayout(); + this.tableLayoutPanel5.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.GroupBox pathsGroupBox; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.Label discImageCreatorPathLabel; + private System.Windows.Forms.Label subdumpPathLabel; + private System.Windows.Forms.Label defaultOutputPathLabel; + private System.Windows.Forms.TextBox DICPathTextBox; + private System.Windows.Forms.TextBox SubDumpPathTextBox; + private System.Windows.Forms.TextBox DefaultOutputPathTextBox; + private System.Windows.Forms.Button DICPathButton; + private System.Windows.Forms.Button DefaultOutputPathButton; + private System.Windows.Forms.Button SubDumpPathButton; + private System.Windows.Forms.GroupBox preferredSpeedGroupBox; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.Label DumpSpeedCDLabel; + private System.Windows.Forms.Label DumpSpeedDVDLabel; + private System.Windows.Forms.Label DumpSpeedBDLabel; + private System.Windows.Forms.TrackBar DumpSpeedCDSlider; + private System.Windows.Forms.TrackBar DumpSpeedDVDSlider; + private System.Windows.Forms.TrackBar DumpSpeedBDSlider; + private System.Windows.Forms.TextBox DumpSpeedCDTextBox; + private System.Windows.Forms.TextBox DumpSpeedDVDTextBox; + private System.Windows.Forms.TextBox DumpSpeedBDTextBox; + private System.Windows.Forms.GroupBox optionsGroupBox; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private System.Windows.Forms.CheckBox QuietModeCheckBox; + private System.Windows.Forms.CheckBox AutoScanCheckBox; + private System.Windows.Forms.CheckBox ParanoidModeCheckBox; + private System.Windows.Forms.CheckBox SkipDetectionCheckBox; + private System.Windows.Forms.TextBox C2RereadTimesTextBox; + private System.Windows.Forms.Label C2RereadLabel; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; + private System.Windows.Forms.Button AcceptButton; + private System.Windows.Forms.Button CancelButton; + } +} \ No newline at end of file diff --git a/DICUI.Forms/Windows/OptionsWindow.cs b/DICUI.Forms/Windows/OptionsWindow.cs new file mode 100644 index 00000000..5043d417 --- /dev/null +++ b/DICUI.Forms/Windows/OptionsWindow.cs @@ -0,0 +1,179 @@ +using System; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Forms; + +namespace DICUI.Forms.Windows +{ + /// + /// Interaction logic for OptionsWindow + /// + public partial class OptionsWindow : Form + { + private readonly MainWindow _mainWindow; + private readonly Options _options; + + public OptionsWindow(MainWindow mainWindow, Options options) + { + InitializeComponent(); + _mainWindow = mainWindow; + _options = options; + + // Create data sets + DumpSpeedCDSlider.Minimum = (int)Constants.SpeedsForCDAsCollection.First(); + DumpSpeedCDSlider.Maximum = (int)Constants.SpeedsForCDAsCollection.Last(); + DumpSpeedDVDSlider.Minimum = (int)Constants.SpeedsForDVDAsCollection.First(); + DumpSpeedDVDSlider.Maximum = (int)Constants.SpeedsForDVDAsCollection.Last(); + DumpSpeedBDSlider.Minimum = (int)Constants.SpeedsForBDAsCollection.First(); + DumpSpeedBDSlider.Maximum = (int)Constants.SpeedsForBDAsCollection.Last(); + + // Select the current values + DumpSpeedCDSlider.Value = _options.preferredDumpSpeedCD; + DumpSpeedDVDSlider.Value = _options.preferredDumpSpeedDVD; + DumpSpeedBDSlider.Value = _options.preferredDumpSpeedBD; + + // Create textbox outputs + DumpSpeedCDTextBox.Text = DumpSpeedCDSlider.Value.ToString(); + DumpSpeedDVDTextBox.Text = DumpSpeedDVDSlider.Value.ToString(); + DumpSpeedBDTextBox.Text = DumpSpeedBDSlider.Value.ToString(); + + // Set options + QuietModeCheckBox.Checked = _options.QuietMode; + ParanoidModeCheckBox.Checked = _options.ParanoidMode; + C2RereadTimesTextBox.Text = _options.RereadAmountForC2.ToString(); + AutoScanCheckBox.Checked = _options.ScanForProtection; + SkipDetectionCheckBox.Checked = _options.SkipMediaTypeDetection; + } + + private OpenFileDialog CreateOpenFileDialog() + { + OpenFileDialog dialog = new OpenFileDialog(); + + dialog.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory; + dialog.Filter = "Executables (*.exe)|*.exe"; + dialog.FilterIndex = 0; + dialog.RestoreDirectory = true; + + return dialog; + } + + private FolderBrowserDialog CreateFolderBrowserDialog() + { + FolderBrowserDialog dialog = new FolderBrowserDialog(); + return dialog; + } + + private string[] PathSettings() + { + string[] pathSettings = { "DefaultOutputPath", "DICPath", "SubDumpPath" }; + return pathSettings; + } + + private TextBox TextBoxForPathSetting(string name) + { + switch (name) + { + case "DICPath": + return DICPathTextBox; + case "SubDumpPath": + return SubDumpPathTextBox; + case "DefaultOutputPath": + return DefaultOutputPathTextBox; + default: + return null; + } + } + + private void BrowseForPathClick(object sender, EventArgs e) + { + Button button = sender as Button; + // strips button prefix to obtain the setting name + string pathSettingName = button.Name.Substring(0, button.Name.IndexOf("Button")); + + // TODO: hack for now, then we'll see + bool shouldBrowseForPath = pathSettingName == "DefaultOutputPath"; + + CommonDialog dialog = shouldBrowseForPath ? (CommonDialog)CreateFolderBrowserDialog() : CreateOpenFileDialog(); + using (dialog) + { + DialogResult result = dialog.ShowDialog(); + + if (result == System.Windows.Forms.DialogResult.OK) + { + string path; + bool exists; + + if (shouldBrowseForPath) + { + path = (dialog as FolderBrowserDialog).SelectedPath; + exists = Directory.Exists(path); + } + else + { + path = (dialog as OpenFileDialog).FileName; + exists = File.Exists(path); + } + + if (exists) + TextBoxForPathSetting(pathSettingName).Text = path; + else + { + System.Windows.MessageBox.Show( + "Specified path doesn't exists!", + "Error", + MessageBoxButton.OK, + MessageBoxImage.Error + ); + } + } + } + } + + public void RefreshSettings() + { + Array.ForEach(PathSettings(), setting => TextBoxForPathSetting(setting).Text = _options.Get(setting)); + + DumpSpeedCDSlider.Value = _options.preferredDumpSpeedCD; + DumpSpeedDVDSlider.Value = _options.preferredDumpSpeedDVD; + DumpSpeedBDSlider.Value = _options.preferredDumpSpeedBD; + } + + #region Event Handlers + + private void SliderChanged(object sender, EventArgs e) + { + DumpSpeedCDTextBox.Text = DumpSpeedCDSlider.Value.ToString(); + DumpSpeedDVDTextBox.Text = DumpSpeedDVDSlider.Value.ToString(); + DumpSpeedBDTextBox.Text = DumpSpeedBDSlider.Value.ToString(); + } + + private void OnAcceptClick(object sender, EventArgs e) + { + Array.ForEach(PathSettings(), setting => _options.Set(setting, TextBoxForPathSetting(setting).Text)); + + _options.preferredDumpSpeedCD = Convert.ToInt32(DumpSpeedCDSlider.Value); + _options.preferredDumpSpeedDVD = Convert.ToInt32(DumpSpeedDVDSlider.Value); + _options.preferredDumpSpeedBD = Convert.ToInt32(DumpSpeedBDSlider.Value); + + _options.QuietMode = QuietModeCheckBox.Checked; + _options.ParanoidMode = ParanoidModeCheckBox.Checked; + _options.RereadAmountForC2 = Convert.ToInt32(C2RereadTimesTextBox.Text); + _options.ScanForProtection = AutoScanCheckBox.Checked; + _options.SkipMediaTypeDetection = SkipDetectionCheckBox.Checked; + + _options.Save(); + Hide(); + + _mainWindow.OnOptionsUpdated(); + } + + private void OnCancelClick(object sender, EventArgs e) + { + // just hide the window and don't care + Hide(); + } + + #endregion + } +} diff --git a/DICUI.Forms/Windows/OptionsWindow.resx b/DICUI.Forms/Windows/OptionsWindow.resx new file mode 100644 index 00000000..61bc649b --- /dev/null +++ b/DICUI.Forms/Windows/OptionsWindow.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + \ No newline at end of file diff --git a/DICUI.Library/DICUI.Library.csproj b/DICUI.Library/DICUI.Library.csproj new file mode 100644 index 00000000..148c0cd0 --- /dev/null +++ b/DICUI.Library/DICUI.Library.csproj @@ -0,0 +1,101 @@ + + + + + Debug + AnyCPU + {51AB0928-13F9-44BF-A407-B6957A43A056} + Library + Properties + DICUI.Library + DICUI.Library + v4.6.1 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\BurnOutSharp.1.3.7.1\lib\net461\BurnOutSharp.dll + + + ..\packages\LessIO.0.5.0\lib\net40\LessIO.dll + + + ..\packages\libmspack4n.0.8.0\lib\net40\libmspackn.dll + + + + + + + + + + + + + + ..\packages\UnshieldSharp.1.4.2.2\lib\net461\UnshieldSharp.dll + + + ..\packages\zlib.net.1.0.4.0\lib\zlib.net.dll + + + + + + + + + + + + + + + + Always + + + + + {2735412F-7F64-5B0F-8F00-5D77AFBE261E} + 1 + 0 + 0 + tlbimp + False + True + + + {2C941FD0-975B-59BE-A960-9A2A262853A5} + 1 + 0 + 0 + tlbimp + False + True + + + + + + + \ No newline at end of file diff --git a/DICUI/Data/Constants.cs b/DICUI.Library/Data/Constants.cs similarity index 94% rename from DICUI/Data/Constants.cs rename to DICUI.Library/Data/Constants.cs index ef0afbfb..f0b36f78 100644 --- a/DICUI/Data/Constants.cs +++ b/DICUI.Library/Data/Constants.cs @@ -1,17 +1,5 @@ namespace DICUI.Data { - /// - /// Variables for UI elements - /// - public static class UIElements - { - public const string DiscNotDetected = "Disc Not Detected"; - public const string StartDumping = "Start Dumping"; - public const string StopDumping = "Stop Dumping"; - - public const int LogWindowMarginFromMainWindow = 10; - } - /// /// Top-level commands for DiscImageCreator /// @@ -125,5 +113,6 @@ public const string RequiredIfExistsValue = "(REQUIRED, IF EXISTS)"; public const string OptionalValue = "(OPTIONAL)"; public const string YesNoValue = "Yes/No"; + public const string DiscNotDetected = "Disc Not Detected"; } } diff --git a/DICUI/Data/Enumerations.cs b/DICUI.Library/Data/Enumerations.cs similarity index 100% rename from DICUI/Data/Enumerations.cs rename to DICUI.Library/Data/Enumerations.cs diff --git a/DICUI.Library/Properties/AssemblyInfo.cs b/DICUI.Library/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..331f1859 --- /dev/null +++ b/DICUI.Library/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DICUI.Library")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DICUI.Library")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("51ab0928-13f9-44bf-a407-b6957a43a056")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DICUI/Utilities/Converters.cs b/DICUI.Library/Utilities/Converters.cs similarity index 96% rename from DICUI/Utilities/Converters.cs rename to DICUI.Library/Utilities/Converters.cs index f404ca52..b7c63d95 100644 --- a/DICUI/Utilities/Converters.cs +++ b/DICUI.Library/Utilities/Converters.cs @@ -1,36 +1,8 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using IMAPI2; +using IMAPI2; using DICUI.Data; namespace DICUI.Utilities { - /// - /// Used to provide a converter to XAML files to render comboboxes with enum values - /// - public class EnumDescriptionConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is DICCommand) - return ((DICCommand)value).Name(); - else if (value is DICFlag) - return ((DICFlag)value).Name(); - else if (value is MediaType?) - return ((MediaType?)value).Name(); - else if (value is KnownSystem?) - return ((KnownSystem?)value).Name(); - else - return ""; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return string.Empty; - } - } - public static class Converters { /// diff --git a/DICUI/Utilities/DumpEnvironment.cs b/DICUI.Library/Utilities/DumpEnvironment.cs similarity index 97% rename from DICUI/Utilities/DumpEnvironment.cs rename to DICUI.Library/Utilities/DumpEnvironment.cs index 1f206017..3ef6906c 100644 --- a/DICUI/Utilities/DumpEnvironment.cs +++ b/DICUI.Library/Utilities/DumpEnvironment.cs @@ -6,9 +6,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using System.Windows; using DICUI.Data; -using DICUI.UI; namespace DICUI.Utilities { @@ -70,8 +68,6 @@ namespace DICUI.Utilities /// public void CancelDumping() { - ViewModels.LoggerViewModel.VerboseLogLn("Canceling dumping process..."); - try { if (dicProcess != null && !dicProcess.HasExited) @@ -86,8 +82,6 @@ namespace DICUI.Utilities /// public async void EjectDisc() { - ViewModels.LoggerViewModel.VerboseLogLn($"Ejecting disc in drive {Drive.Letter}"); - // Validate that the required program exists if (!File.Exists(DICPath)) return; @@ -164,10 +158,7 @@ namespace DICUI.Utilities // If we get the firmware message if (output.Contains("[ERROR] This drive isn't latest firmware. Please update.")) - { - MessageBox.Show($"DiscImageCreator has reported that drive {Drive.Letter} is not updated to the most recent firmware. Please update the firmware for your drive and try again.", "Outdated Firmware", MessageBoxButton.OK, MessageBoxImage.Error); return false; - } // Otherwise, we know the firmware's good return true; @@ -237,12 +228,12 @@ namespace DICUI.Utilities #endregion - #region Internal for Testing Purposes + #region Public for Testing Purposes /// /// Fix output paths to strip out any invalid characters /// - internal void FixOutputPaths() + public void FixOutputPaths() { try { @@ -285,11 +276,73 @@ namespace DICUI.Utilities /// Checks if the parameters are valid /// /// True if the configuration is valid, false otherwise - internal bool ParametersValid() + public bool ParametersValid() { return DICParameters.IsValid() && !(IsFloppy ^ Type == MediaType.FloppyDisk); } + /// + /// Ensures that all required output files have been created + /// + /// + public bool FoundAllFiles() + { + // First, sanitized the output filename to strip off any potential extension + string outputFilename = Path.GetFileNameWithoutExtension(OutputFilename); + + // Now ensure that all required files exist + string combinedBase = Path.Combine(OutputDirectory, outputFilename); + switch (Type) + { + case MediaType.CDROM: + case MediaType.GDROM: // TODO: Verify GD-ROM outputs this + return File.Exists(combinedBase + ".c2") + && File.Exists(combinedBase + ".ccd") + && File.Exists(combinedBase + ".cue") + && File.Exists(combinedBase + ".dat") + && File.Exists(combinedBase + ".img") + && File.Exists(combinedBase + ".img_EdcEcc.txt") + && File.Exists(combinedBase + ".scm") + && File.Exists(combinedBase + ".sub") + && File.Exists(combinedBase + "_c2Error.txt") + && File.Exists(combinedBase + "_cmd.txt") + && File.Exists(combinedBase + "_disc.txt") + && File.Exists(combinedBase + "_drive.txt") + && File.Exists(combinedBase + "_img.cue") + && File.Exists(combinedBase + "_mainError.txt") + && File.Exists(combinedBase + "_mainInfo.txt") + && File.Exists(combinedBase + "_subError.txt") + && File.Exists(combinedBase + "_subInfo.txt") + // && File.Exists(combinedBase + "_subIntention.txt") + && (File.Exists(combinedBase + "_subReadable.txt") || File.Exists(combinedBase + "_sub.txt")) + && File.Exists(combinedBase + "_volDesc.txt"); + case MediaType.DVD: + case MediaType.HDDVD: + case MediaType.BluRay: + case MediaType.NintendoGameCube: + case MediaType.NintendoWiiOpticalDisc: + return File.Exists(combinedBase + ".dat") + && File.Exists(combinedBase + "_cmd.txt") + && File.Exists(combinedBase + "_disc.txt") + && File.Exists(combinedBase + "_drive.txt") + && File.Exists(combinedBase + "_mainError.txt") + && File.Exists(combinedBase + "_mainInfo.txt") + && File.Exists(combinedBase + "_volDesc.txt"); + case MediaType.FloppyDisk: + return File.Exists(combinedBase + ".dat") + && File.Exists(combinedBase + "_cmd.txt") + && File.Exists(combinedBase + "_disc.txt"); + case MediaType.UMD: + return File.Exists(combinedBase + "_disc.txt") + || File.Exists(combinedBase + "_mainError.txt") + || File.Exists(combinedBase + "_mainInfo.txt") + || File.Exists(combinedBase + "_volDesc.txt"); + default: + // Non-dumping commands will usually produce no output, so this is irrelevant + return true; + } + } + #endregion #region Private Helpers @@ -319,8 +372,6 @@ namespace DICUI.Utilities /// private void ExecuteDiskImageCreator() { - ViewModels.LoggerViewModel.VerboseLogLn("Launching DiscImageCreator process."); - dicProcess = new Process() { StartInfo = new ProcessStartInfo() @@ -764,68 +815,6 @@ namespace DICUI.Utilities } } - /// - /// Ensures that all required output files have been created - /// - /// - private bool FoundAllFiles() - { - // First, sanitized the output filename to strip off any potential extension - string outputFilename = Path.GetFileNameWithoutExtension(OutputFilename); - - // Now ensure that all required files exist - string combinedBase = Path.Combine(OutputDirectory, outputFilename); - switch (Type) - { - case MediaType.CDROM: - case MediaType.GDROM: // TODO: Verify GD-ROM outputs this - return File.Exists(combinedBase + ".c2") - && File.Exists(combinedBase + ".ccd") - && File.Exists(combinedBase + ".cue") - && File.Exists(combinedBase + ".dat") - && File.Exists(combinedBase + ".img") - && File.Exists(combinedBase + ".img_EdcEcc.txt") - && File.Exists(combinedBase + ".scm") - && File.Exists(combinedBase + ".sub") - && File.Exists(combinedBase + "_c2Error.txt") - && File.Exists(combinedBase + "_cmd.txt") - && File.Exists(combinedBase + "_disc.txt") - && File.Exists(combinedBase + "_drive.txt") - && File.Exists(combinedBase + "_img.cue") - && File.Exists(combinedBase + "_mainError.txt") - && File.Exists(combinedBase + "_mainInfo.txt") - && File.Exists(combinedBase + "_subError.txt") - && File.Exists(combinedBase + "_subInfo.txt") - // && File.Exists(combinedBase + "_subIntention.txt") - && (File.Exists(combinedBase + "_subReadable.txt") || File.Exists(combinedBase + "_sub.txt")) - && File.Exists(combinedBase + "_volDesc.txt"); - case MediaType.DVD: - case MediaType.HDDVD: - case MediaType.BluRay: - case MediaType.NintendoGameCube: - case MediaType.NintendoWiiOpticalDisc: - return File.Exists(combinedBase + ".dat") - && File.Exists(combinedBase + "_cmd.txt") - && File.Exists(combinedBase + "_disc.txt") - && File.Exists(combinedBase + "_drive.txt") - && File.Exists(combinedBase + "_mainError.txt") - && File.Exists(combinedBase + "_mainInfo.txt") - && File.Exists(combinedBase + "_volDesc.txt"); - case MediaType.FloppyDisk: - return File.Exists(combinedBase + ".dat") - && File.Exists(combinedBase + "_cmd.txt") - && File.Exists(combinedBase + "_disc.txt"); - case MediaType.UMD: - return File.Exists(combinedBase + "_disc.txt") - || File.Exists(combinedBase + "_mainError.txt") - || File.Exists(combinedBase + "_mainInfo.txt") - || File.Exists(combinedBase + "_volDesc.txt"); - default: - // Non-dumping commands will usually produce no output, so this is irrelevant - return true; - } - } - /// /// Get the existance of an anti-modchip string from the input file, if possible /// @@ -1601,26 +1590,6 @@ namespace DICUI.Utilities if (!File.Exists(DICPath)) return Result.Failure("Error! Could not find DiscImageCreator!"); - // Validate that the user explicitly wants an inactive drive to be considered for dumping - if (!Drive.MarkedActive) - { - MessageBoxResult result = MessageBox.Show("The currently selected drive does not appear to contain a disc! Are you sure you want to continue?", "Missing Disc", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); - if (result == MessageBoxResult.No || result == MessageBoxResult.Cancel || result == MessageBoxResult.None) - { - return Result.Failure("Dumping aborted!"); - } - } - - // If a complete dump already exists - if (FoundAllFiles()) - { - MessageBoxResult result = MessageBox.Show("A complete dump already exists! Are you sure you want to overwrite?", "Overwrite?", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); - if (result == MessageBoxResult.No || result == MessageBoxResult.Cancel || result == MessageBoxResult.None) - { - return Result.Failure("Dumping aborted!"); - } - } - return Result.Success(); } diff --git a/DICUI/Utilities/Extensions.cs b/DICUI.Library/Utilities/Extensions.cs similarity index 100% rename from DICUI/Utilities/Extensions.cs rename to DICUI.Library/Utilities/Extensions.cs diff --git a/DICUI/Utilities/Parameters.cs b/DICUI.Library/Utilities/Parameters.cs similarity index 100% rename from DICUI/Utilities/Parameters.cs rename to DICUI.Library/Utilities/Parameters.cs diff --git a/DICUI/Utilities/Result.cs b/DICUI.Library/Utilities/Result.cs similarity index 100% rename from DICUI/Utilities/Result.cs rename to DICUI.Library/Utilities/Result.cs diff --git a/DICUI/Utilities/Validators.cs b/DICUI.Library/Utilities/Validators.cs similarity index 99% rename from DICUI/Utilities/Validators.cs rename to DICUI.Library/Utilities/Validators.cs index e79d92b7..6586dd06 100644 --- a/DICUI/Utilities/Validators.cs +++ b/DICUI.Library/Utilities/Validators.cs @@ -431,7 +431,7 @@ namespace DICUI.Utilities // Get the optical disc drives List discDrives = DriveInfo.GetDrives() .Where(d => d.DriveType == DriveType.CDRom) - .Select(d => Drive.Optical(d.Name[0], (d.IsReady ? d.VolumeLabel : UIElements.DiscNotDetected), d.IsReady)) + .Select(d => Drive.Optical(d.Name[0], (d.IsReady ? d.VolumeLabel : Template.DiscNotDetected), d.IsReady)) .ToList(); // Add the two lists together and order diff --git a/DICUI/mspack.dll b/DICUI.Library/mspack.dll similarity index 100% rename from DICUI/mspack.dll rename to DICUI.Library/mspack.dll diff --git a/DICUI/packages.config b/DICUI.Library/packages.config similarity index 100% rename from DICUI/packages.config rename to DICUI.Library/packages.config diff --git a/DICUI.Test/DICUI.Test.csproj b/DICUI.Test/DICUI.Test.csproj index db2befea..6be8f167 100644 --- a/DICUI.Test/DICUI.Test.csproj +++ b/DICUI.Test/DICUI.Test.csproj @@ -78,14 +78,18 @@ + + + + + {51ab0928-13f9-44bf-a407-b6957a43a056} + DICUI.Library + {7b1b75eb-8940-466f-bd51-76471a57f9be} DICUI - - - diff --git a/DICUI.Test/UI/AllowedSpeedsTest.cs b/DICUI.Test/UI/AllowedSpeedsTest.cs index 6396b1af..386ae01c 100644 --- a/DICUI.Test/UI/AllowedSpeedsTest.cs +++ b/DICUI.Test/UI/AllowedSpeedsTest.cs @@ -1,6 +1,5 @@ using System.Linq; using DICUI.Data; -using DICUI.UI; using Xunit; namespace DICUI.Test.Data @@ -15,7 +14,7 @@ namespace DICUI.Test.Data [InlineData(null, 72)] // TODO: Update when fully determined public void GetAllowedDriveSpeedForMediaTypeTest(MediaType? mediaType, int maxExpected) { - var actual = AllowedSpeeds.GetForMediaType(mediaType); + var actual = Constants.GetSpeedsForMediaType(mediaType); Assert.Equal(maxExpected, actual.Last()); } } diff --git a/DICUI.sln b/DICUI.sln index fcb2872d..8350a403 100644 --- a/DICUI.sln +++ b/DICUI.sln @@ -7,6 +7,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DICUI", "DICUI\DICUI.csproj EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DICUI.Test", "DICUI.Test\DICUI.Test.csproj", "{7CC064D2-38AB-4A05-8519-28660DE4562A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DICUI.Library", "DICUI.Library\DICUI.Library.csproj", "{51AB0928-13F9-44BF-A407-B6957A43A056}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DICUI.Forms", "DICUI.Forms\DICUI.Forms.csproj", "{A6719A99-BF0E-4637-9A8E-CB38B1E16971}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +25,14 @@ Global {7CC064D2-38AB-4A05-8519-28660DE4562A}.Debug|Any CPU.Build.0 = Debug|Any CPU {7CC064D2-38AB-4A05-8519-28660DE4562A}.Release|Any CPU.ActiveCfg = Release|Any CPU {7CC064D2-38AB-4A05-8519-28660DE4562A}.Release|Any CPU.Build.0 = Release|Any CPU + {51AB0928-13F9-44BF-A407-B6957A43A056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51AB0928-13F9-44BF-A407-B6957A43A056}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51AB0928-13F9-44BF-A407-B6957A43A056}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51AB0928-13F9-44BF-A407-B6957A43A056}.Release|Any CPU.Build.0 = Release|Any CPU + {A6719A99-BF0E-4637-9A8E-CB38B1E16971}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6719A99-BF0E-4637-9A8E-CB38B1E16971}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6719A99-BF0E-4637-9A8E-CB38B1E16971}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6719A99-BF0E-4637-9A8E-CB38B1E16971}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/DICUI/App.xaml b/DICUI/App.xaml index bcd42346..b9f57038 100644 --- a/DICUI/App.xaml +++ b/DICUI/App.xaml @@ -2,7 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:DICUI" - StartupUri="MainWindow.xaml"> + StartupUri="Windows\MainWindow.xaml"> diff --git a/DICUI/App.xaml.cs b/DICUI/App.xaml.cs index 138640a0..4f140534 100644 --- a/DICUI/App.xaml.cs +++ b/DICUI/App.xaml.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; namespace DICUI { diff --git a/DICUI/Constants.cs b/DICUI/Constants.cs new file mode 100644 index 00000000..678aef96 --- /dev/null +++ b/DICUI/Constants.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Media; +using DICUI.Data; + +namespace DICUI +{ + /// + /// Variables for UI elements + /// + public static class Constants + { + public const string StartDumping = "Start Dumping"; + public const string StopDumping = "Stop Dumping"; + + public const int LogWindowMarginFromMainWindow = 10; + + // Private lists of known drive speed ranges + private static IReadOnlyList cd { get; } = new List { 1, 2, 3, 4, 6, 8, 12, 16, 20, 24, 32, 40, 44, 48, 52, 56, 72 }; + private static IReadOnlyList dvd { get; } = cd.Where(s => s <= 24).ToList(); + private static IReadOnlyList bd { get; } = cd.Where(s => s <= 16).ToList(); + private static IReadOnlyList unknown { get; } = cd; // TODO: All or {1}? Maybe null? + + /// + /// Get list of all drive speeds for a given MediaType + /// + /// MediaType? that represents the current item + /// Read-only list of drive speeds + public static IReadOnlyList GetSpeedsForMediaType(MediaType? type) + { + switch (type) + { + case MediaType.CDROM: + case MediaType.GDROM: + return cd; + case MediaType.DVD: + case MediaType.HDDVD: + case MediaType.NintendoGameCube: + case MediaType.NintendoWiiOpticalDisc: + return dvd; + case MediaType.BluRay: + return bd; + default: + return unknown; + } + } + + // Create collections for UI based on known drive speeds + public static DoubleCollection SpeedsForCDAsCollection { get; } = GetDoubleCollectionFromIntList(cd); + public static DoubleCollection SpeedsForDVDAsCollection { get; } = GetDoubleCollectionFromIntList(dvd); + public static DoubleCollection SpeedsForBDAsCollection { get; } = GetDoubleCollectionFromIntList(bd); + private static DoubleCollection GetDoubleCollectionFromIntList(IReadOnlyList list) + => new DoubleCollection(list.Select(i => Convert.ToDouble(i)).ToList()); + } +} diff --git a/DICUI/DICUI.csproj b/DICUI/DICUI.csproj index 2c79be4b..e1708fa4 100644 --- a/DICUI/DICUI.csproj +++ b/DICUI/DICUI.csproj @@ -67,68 +67,42 @@ - - ..\packages\BurnOutSharp.1.3.7.1\lib\net461\BurnOutSharp.dll - - - ..\packages\LessIO.0.5.0\lib\net40\LessIO.dll - - - ..\packages\libmspack4n.0.8.0\lib\net40\libmspackn.dll - - - - - - 4.0 - - ..\packages\UnshieldSharp.1.4.2.2\lib\net461\UnshieldSharp.dll - - - ..\packages\zlib.net.1.0.4.0\lib\zlib.net.dll - MSBuild:Compile Designer - + + + + LogWindow.xaml - - - - - - - - - - - - + OptionsWindow.xaml - + + + Designer MSBuild:Compile - + MSBuild:Compile Designer @@ -136,12 +110,11 @@ App.xaml Code - - + MainWindow.xaml Code - + Designer MSBuild:Compile @@ -153,7 +126,6 @@ - @@ -171,29 +143,10 @@ - - {2735412F-7F64-5B0F-8F00-5D77AFBE261E} - 1 - 0 - 0 - tlbimp - False - True - - - {2C941FD0-975B-59BE-A960-9A2A262853A5} - 1 - 0 - 0 - tlbimp - False - True - - - - - Always - + + {51ab0928-13f9-44bf-a407-b6957a43a056} + DICUI.Library + \ No newline at end of file diff --git a/DICUI/EnumDescriptionConverter.cs b/DICUI/EnumDescriptionConverter.cs new file mode 100644 index 00000000..ffb04c9f --- /dev/null +++ b/DICUI/EnumDescriptionConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Globalization; +using System.Windows.Data; +using DICUI.Data; +using DICUI.Utilities; + +namespace DICUI +{ + /// + /// Used to provide a converter to XAML files to render comboboxes with enum values + /// + public class EnumDescriptionConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is DICCommand) + return ((DICCommand)value).Name(); + else if (value is DICFlag) + return ((DICFlag)value).Name(); + else if (value is MediaType?) + return ((MediaType?)value).Name(); + else if (value is KnownSystem?) + return ((KnownSystem?)value).Name(); + else + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return string.Empty; + } + } +} diff --git a/DICUI/UI/KnownSystemComboBoxItem.cs b/DICUI/KnownSystemComboBoxItem.cs similarity index 98% rename from DICUI/UI/KnownSystemComboBoxItem.cs rename to DICUI/KnownSystemComboBoxItem.cs index d9940db2..ef91bd51 100644 --- a/DICUI/UI/KnownSystemComboBoxItem.cs +++ b/DICUI/KnownSystemComboBoxItem.cs @@ -2,7 +2,7 @@ using DICUI.Data; using DICUI.Utilities; -namespace DICUI.UI +namespace DICUI { /// /// Represents a single item in the System combo box diff --git a/DICUI/UI/ViewModels.cs b/DICUI/ViewModels.cs similarity index 98% rename from DICUI/UI/ViewModels.cs rename to DICUI/ViewModels.cs index 574769f1..1c7938d0 100644 --- a/DICUI/UI/ViewModels.cs +++ b/DICUI/ViewModels.cs @@ -1,7 +1,8 @@ using System; using System.Windows.Media; +using DICUI.Windows; -namespace DICUI.UI +namespace DICUI { public class OptionsViewModel { diff --git a/DICUI/LogWindow.xaml b/DICUI/Windows/LogWindow.xaml similarity index 90% rename from DICUI/LogWindow.xaml rename to DICUI/Windows/LogWindow.xaml index b2a74db5..d483079b 100644 --- a/DICUI/LogWindow.xaml +++ b/DICUI/Windows/LogWindow.xaml @@ -1,7 +1,7 @@ - @@ -35,12 +35,12 @@