From b9c89fa7edcbd1bdadd488ab818529d216585c33 Mon Sep 17 00:00:00 2001 From: WC Leung Date: Tue, 9 May 2017 18:43:12 +0000 Subject: [PATCH] Initial commit * Initial commit. --- .gitattributes | 5 + DotNetEditor.sln | 22 + DotNetEditor/AboutBox.Designer.cs | 190 +++++ DotNetEditor/AboutBox.cs | 109 +++ DotNetEditor/AboutBox.resx | 603 +++++++++++++++ DotNetEditor/App.config | 58 ++ DotNetEditor/App.xaml | 9 + DotNetEditor/App.xaml.cs | 18 + DotNetEditor/AppCommands.cs | 23 + DotNetEditor/AvalonUtils/AvalonRichTextBox.cs | 169 +++++ DotNetEditor/AvalonUtils/PixelSnapper.cs | 27 + DotNetEditor/CodeRunner/CSCodeRunner.cs | 90 +++ DotNetEditor/CodeRunner/CodeRunnerBase.cs | 237 ++++++ DotNetEditor/CodeRunner/VBCodeRunner.cs | 94 +++ DotNetEditor/ConsoleColorScheme.cs | 71 ++ DotNetEditor/ConsoleUtil.cs | 40 + DotNetEditor/Converters.cs | 56 ++ DotNetEditor/DotNetEditor.csproj | 316 ++++++++ DotNetEditor/DumpReader.cs | 74 ++ DotNetEditor/FileUtils/FileHandler.cs | 108 +++ DotNetEditor/FodyWeavers.xml | 4 + DotNetEditor/Images/about-30.png | Bin 0 -> 407 bytes DotNetEditor/Images/cs-30.png | Bin 0 -> 477 bytes DotNetEditor/Images/down_left-30.png | Bin 0 -> 470 bytes DotNetEditor/Images/open_document-30.png | Bin 0 -> 444 bytes DotNetEditor/Images/play-30.png | Bin 0 -> 431 bytes DotNetEditor/Images/save-30.png | Bin 0 -> 319 bytes DotNetEditor/Images/save_as-30.png | Bin 0 -> 671 bytes DotNetEditor/Images/vb-30.png | Bin 0 -> 474 bytes DotNetEditor/MainWindow.xaml | 182 +++++ DotNetEditor/MainWindow.xaml.cs | 208 ++++++ DotNetEditor/Properties/AssemblyInfo.cs | 55 ++ DotNetEditor/Properties/Resources.Designer.cs | 95 +++ DotNetEditor/Properties/Resources.resx | 127 ++++ DotNetEditor/Properties/Settings.Designer.cs | 26 + DotNetEditor/Properties/Settings.settings | 7 + DotNetEditor/Properties/app.manifest | 70 ++ DotNetEditor/TextBuffer/TextBuffer.cs | 66 ++ DotNetEditor/TextData/aboutbox.txt | 11 + DotNetEditor/TextData/samplecode.txt | 21 + .../TextWriterWithConsoleColor/ColorInfo.cs | 25 + .../IWithConsoleColor.cs | 13 + .../StringWriterBW.cs | 37 + .../StringWriterColor.cs | 80 ++ .../TextWriterWithConsoleColor.cs | 14 + DotNetEditor/packages.config | 51 ++ GPLv3 | 674 +++++++++++++++++ LICENSE | 695 ++---------------- README.md | 22 +- 49 files changed, 4148 insertions(+), 654 deletions(-) create mode 100644 .gitattributes create mode 100644 DotNetEditor.sln create mode 100644 DotNetEditor/AboutBox.Designer.cs create mode 100644 DotNetEditor/AboutBox.cs create mode 100644 DotNetEditor/AboutBox.resx create mode 100644 DotNetEditor/App.config create mode 100644 DotNetEditor/App.xaml create mode 100644 DotNetEditor/App.xaml.cs create mode 100644 DotNetEditor/AppCommands.cs create mode 100644 DotNetEditor/AvalonUtils/AvalonRichTextBox.cs create mode 100644 DotNetEditor/AvalonUtils/PixelSnapper.cs create mode 100644 DotNetEditor/CodeRunner/CSCodeRunner.cs create mode 100644 DotNetEditor/CodeRunner/CodeRunnerBase.cs create mode 100644 DotNetEditor/CodeRunner/VBCodeRunner.cs create mode 100644 DotNetEditor/ConsoleColorScheme.cs create mode 100644 DotNetEditor/ConsoleUtil.cs create mode 100644 DotNetEditor/Converters.cs create mode 100644 DotNetEditor/DotNetEditor.csproj create mode 100644 DotNetEditor/DumpReader.cs create mode 100644 DotNetEditor/FileUtils/FileHandler.cs create mode 100644 DotNetEditor/FodyWeavers.xml create mode 100644 DotNetEditor/Images/about-30.png create mode 100644 DotNetEditor/Images/cs-30.png create mode 100644 DotNetEditor/Images/down_left-30.png create mode 100644 DotNetEditor/Images/open_document-30.png create mode 100644 DotNetEditor/Images/play-30.png create mode 100644 DotNetEditor/Images/save-30.png create mode 100644 DotNetEditor/Images/save_as-30.png create mode 100644 DotNetEditor/Images/vb-30.png create mode 100644 DotNetEditor/MainWindow.xaml create mode 100644 DotNetEditor/MainWindow.xaml.cs create mode 100644 DotNetEditor/Properties/AssemblyInfo.cs create mode 100644 DotNetEditor/Properties/Resources.Designer.cs create mode 100644 DotNetEditor/Properties/Resources.resx create mode 100644 DotNetEditor/Properties/Settings.Designer.cs create mode 100644 DotNetEditor/Properties/Settings.settings create mode 100644 DotNetEditor/Properties/app.manifest create mode 100644 DotNetEditor/TextBuffer/TextBuffer.cs create mode 100644 DotNetEditor/TextData/aboutbox.txt create mode 100644 DotNetEditor/TextData/samplecode.txt create mode 100644 DotNetEditor/TextWriterWithConsoleColor/ColorInfo.cs create mode 100644 DotNetEditor/TextWriterWithConsoleColor/IWithConsoleColor.cs create mode 100644 DotNetEditor/TextWriterWithConsoleColor/StringWriterBW.cs create mode 100644 DotNetEditor/TextWriterWithConsoleColor/StringWriterColor.cs create mode 100644 DotNetEditor/TextWriterWithConsoleColor/TextWriterWithConsoleColor.cs create mode 100644 DotNetEditor/packages.config create mode 100644 GPLv3 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c129d83 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +* text eol=lf + +*.jpg binary +*.png binary +*.gif binary diff --git a/DotNetEditor.sln b/DotNetEditor.sln new file mode 100644 index 0000000..0f1e860 --- /dev/null +++ b/DotNetEditor.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetEditor", "DotNetEditor\DotNetEditor.csproj", "{E54077C3-703E-4A13-9D01-382B30E8AAEE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E54077C3-703E-4A13-9D01-382B30E8AAEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E54077C3-703E-4A13-9D01-382B30E8AAEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E54077C3-703E-4A13-9D01-382B30E8AAEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E54077C3-703E-4A13-9D01-382B30E8AAEE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/DotNetEditor/AboutBox.Designer.cs b/DotNetEditor/AboutBox.Designer.cs new file mode 100644 index 0000000..8f6a023 --- /dev/null +++ b/DotNetEditor/AboutBox.Designer.cs @@ -0,0 +1,190 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +namespace DotNetEditor +{ + partial class AboutBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + 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(AboutBox)); + this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.logoPictureBox = new System.Windows.Forms.PictureBox(); + this.labelProductName = new System.Windows.Forms.Label(); + this.labelVersion = new System.Windows.Forms.Label(); + this.labelCopyright = new System.Windows.Forms.Label(); + this.labelLicense = new System.Windows.Forms.Label(); + this.textBoxDescription = new System.Windows.Forms.TextBox(); + this.okButton = new System.Windows.Forms.Button(); + this.tableLayoutPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // tableLayoutPanel + // + this.tableLayoutPanel.ColumnCount = 2; + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20F)); + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 80F)); + this.tableLayoutPanel.Controls.Add(this.logoPictureBox, 0, 0); + this.tableLayoutPanel.Controls.Add(this.labelProductName, 1, 0); + this.tableLayoutPanel.Controls.Add(this.labelVersion, 1, 1); + this.tableLayoutPanel.Controls.Add(this.labelCopyright, 1, 2); + this.tableLayoutPanel.Controls.Add(this.labelLicense, 1, 3); + this.tableLayoutPanel.Controls.Add(this.textBoxDescription, 1, 4); + this.tableLayoutPanel.Controls.Add(this.okButton, 1, 5); + this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel.Location = new System.Drawing.Point(9, 9); + this.tableLayoutPanel.Name = "tableLayoutPanel"; + this.tableLayoutPanel.RowCount = 6; + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.Size = new System.Drawing.Size(417, 265); + this.tableLayoutPanel.TabIndex = 0; + // + // logoPictureBox + // + this.logoPictureBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.logoPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("logoPictureBox.Image"))); + this.logoPictureBox.Location = new System.Drawing.Point(3, 3); + this.logoPictureBox.Name = "logoPictureBox"; + this.tableLayoutPanel.SetRowSpan(this.logoPictureBox, 6); + this.logoPictureBox.Size = new System.Drawing.Size(77, 259); + this.logoPictureBox.TabIndex = 12; + this.logoPictureBox.TabStop = false; + // + // labelProductName + // + this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelProductName.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelProductName.Location = new System.Drawing.Point(89, 0); + this.labelProductName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelProductName.MaximumSize = new System.Drawing.Size(0, 17); + this.labelProductName.Name = "labelProductName"; + this.labelProductName.Size = new System.Drawing.Size(325, 17); + this.labelProductName.TabIndex = 19; + this.labelProductName.Text = "Product Name"; + this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelVersion + // + this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelVersion.Location = new System.Drawing.Point(89, 17); + this.labelVersion.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelVersion.MaximumSize = new System.Drawing.Size(0, 17); + this.labelVersion.Name = "labelVersion"; + this.labelVersion.Size = new System.Drawing.Size(325, 17); + this.labelVersion.TabIndex = 0; + this.labelVersion.Text = "Version"; + this.labelVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelCopyright + // + this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCopyright.Location = new System.Drawing.Point(89, 34); + this.labelCopyright.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 17); + this.labelCopyright.Name = "labelCopyright"; + this.labelCopyright.Size = new System.Drawing.Size(325, 17); + this.labelCopyright.TabIndex = 21; + this.labelCopyright.Text = "Copyright"; + this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelLicense + // + this.labelLicense.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelLicense.Location = new System.Drawing.Point(89, 51); + this.labelLicense.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelLicense.MaximumSize = new System.Drawing.Size(0, 17); + this.labelLicense.Name = "labelLicense"; + this.labelLicense.Size = new System.Drawing.Size(325, 17); + this.labelLicense.TabIndex = 22; + this.labelLicense.Text = "License"; + this.labelLicense.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // textBoxDescription + // + this.textBoxDescription.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBoxDescription.Location = new System.Drawing.Point(89, 71); + this.textBoxDescription.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); + this.textBoxDescription.Multiline = true; + this.textBoxDescription.Name = "textBoxDescription"; + this.textBoxDescription.ReadOnly = true; + this.textBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBoxDescription.Size = new System.Drawing.Size(325, 162); + this.textBoxDescription.TabIndex = 23; + this.textBoxDescription.TabStop = false; + this.textBoxDescription.Text = "Description"; + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.okButton.Location = new System.Drawing.Point(339, 239); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 24; + this.okButton.Text = "&OK"; + // + // AboutBox + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(435, 283); + this.Controls.Add(this.tableLayoutPanel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutBox"; + this.Padding = new System.Windows.Forms.Padding(9); + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "AboutBox"; + this.tableLayoutPanel.ResumeLayout(false); + this.tableLayoutPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; + private System.Windows.Forms.PictureBox logoPictureBox; + private System.Windows.Forms.Label labelProductName; + private System.Windows.Forms.Label labelVersion; + private System.Windows.Forms.Label labelCopyright; + private System.Windows.Forms.Label labelLicense; + private System.Windows.Forms.TextBox textBoxDescription; + private System.Windows.Forms.Button okButton; + } +} diff --git a/DotNetEditor/AboutBox.cs b/DotNetEditor/AboutBox.cs new file mode 100644 index 0000000..6893dc0 --- /dev/null +++ b/DotNetEditor/AboutBox.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace DotNetEditor +{ + // TODO: remake the dialog box in WPF. + partial class AboutBox : Form + { + public AboutBox() + { + InitializeComponent(); + this.Text = String.Format("About {0}", AssemblyTitle); + this.labelProductName.Text = AssemblyProduct; + this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); + this.labelCopyright.Text = AssemblyCopyright; + this.labelLicense.Text = "Released under GPLv3 with exceptions."; + this.textBoxDescription.Text = + Properties.Resources.aboutbox + .Replace("\n", Environment.NewLine) + .Replace("{app}", AssemblyProduct); + } + + #region Assembly Attribute Accessors + + public string AssemblyTitle + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); + if (attributes.Length > 0) + { + AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; + if (titleAttribute.Title != "") + { + return titleAttribute.Title; + } + } + return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); + } + } + + public string AssemblyVersion + { + get + { + return Assembly.GetExecutingAssembly().GetName().Version.ToString(); + } + } + + public string AssemblyDescription + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyDescriptionAttribute)attributes[0]).Description; + } + } + + public string AssemblyProduct + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyProductAttribute)attributes[0]).Product; + } + } + + public string AssemblyCopyright + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; + } + } + + public string AssemblyCompany + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCompanyAttribute)attributes[0]).Company; + } + } + #endregion + } +} diff --git a/DotNetEditor/AboutBox.resx b/DotNetEditor/AboutBox.resx new file mode 100644 index 0000000..76cc9af --- /dev/null +++ b/DotNetEditor/AboutBox.resx @@ -0,0 +1,603 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + iVBORw0KGgoAAAANSUhEUgAAAHgAAAEGCAIAAAAhWcaAAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6 + JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AABvkklEQVR4Xu29B1hUd9r+z3X939+7bzax + RQWmnZmhS++9i4KCXRRRsKGoiKKIKIJKlSrSpTdpioWmYm9gLzEao4kliTGmZ3ez6767yb7/+3u+M8fD + DBiTTVE33+u5cKSe85n73M/9nJk5oyEsE4rKRaIKkbhKLKmVMPUM08hIW6Ty3XL5PrlOl45Ot47uEV3d + 47p6J/X0TrGFG8f09I7o6Xbr6u7X1W3X1d2nq7NbR2enjk6zjk6jjk69jk6djixDxsxhRJailJSUy5cv + f/vtt3/729/+/ve//+///u8//vGPf/7zn999993333//L3b936u+WNBlInG5WFIhkVRKmCpGWiOV1kpl + O2TyJrm8RS5vlevs1dHt1NU9oAuy4Esoo46yrA+xn8dX29RY1+joVOvI0mXMbEZkIUpPT7958+Zf/vKX + v/71r0+ePPlPw60BylA0Bc1UMgR0lVRWLZPVyuR1cnm9XKeBBdeio9OqA+US/Xbp6h7UJYi5UrLW3aOr + s6sPa3mVXF4pl6ZKJTMlQmNhYWHhhx9++B+Im4B+SrlSSblaJq+Rk6qVwwQIsh06hHiTkvheljjgwjoA + HQXWuAOojbSqsa6Qy8vl0o1SyWSJUEfY0NDwpz/96T8KtwYoiysUoEFZWk1AP6Vcq/O0OOIgCI4qxEEZ + hRucZeMbVFiXyeWlcmY1I/YRR0REHDlyhMP9ynu3hrhMLCmXMBWsnCtZOdcoQPehzBVwqxCHL+9mXQXW + Acq0uPaIgwDfybEulcu3y+WFcmYRI7IXbdmy5c6dO3zcYK2CW7GlL/nSEBeLxaWENaFcJUPJq+WkBgLN + lYqlgPguHXi0gjgKN2DZtD2qsC6Ry4vlsmSZZLpEqC9samr6+uuvgZtLJq+etDXEOWLJNglTxDAljLRM + KquQySoJa3DpUyqUuepX4LAUShzGwrVH3B+1PNbFcnkRK+0oRuwpXr9+/ZUrV4D7z3/+80DGrdjkl3Np + iNPF4gyxJEPC5DDSPKmsSCYrkREzLSdpAfnsuYir44ZBgy8sBaDhIVwUqevLulAuL5AjcUtmkUxSX1// + 5ZdffvPNNxQ337hfdmlriFPFkjQJs4VhMhhplhQl2yqTb2MRwExBHFCApur5NK6CWylwUmDNtcdqnT6s + 8+WyPBmzihF7iTds2HDjxo2vvvqKc5JXQ9oa4mSxJEXCpDFgLU2XSjOkskyZLJstEM9jD3Ae8efSOB83 + tW/gpkV1ja/Csvms8+SybTJpmlQSKBEaCPfs2fPFF1/06yQvqbQ1JIkSJplhUhjMFNhP2RYZZjnCmsNN + ieezRMDl+QWujhuKpqy5KMJjDVHjD8lyZMwyRuQkysrK+vjjj+EkNJO87NJmQScx0mQpqRSpLE1GiuLO + YHFnKXHnyMBCxVJ+QOAq3k1x0+JYVypZw6y3KVhLN0jF/mKBUNDb2/v555+rS/ulCyQaoMyBlqXIFJXK + w60u8FwWN9D8NNwoyho3KGscIiqs2T/EzGaEo4QtLS2ffvrpyy5tAvqpnDnQfNwDCRx+UvBj/EQdN0RN + WdPYh7sNvw2NEaxx9FDWsBFH0bZt2x4/fsyXtnrWVuzQi7o0xIvFTDxhrUqZX8/G3de+f1jdYM3H3S/r + 3Kespeuk4jEkaN+6deuzzz7jAsnLZSMazs7OAgOByE0kni5mljOqiPnF95OB1P08ZsKXNj01iI/qrJUG + QlinSCVTJAKJ4PTp05A2AgmytoqNvOCsNerq6vLz82NiYoKCghwdHUVWIom/hAljZBvVQNN6hrqpd2O8 + Biy0OHXcHGsV3FzRcaY/1ihi2YbC9vb2Tz755KWzEY2dO3e2trbuZhfSa3Z29pIlS8aMGSMyF0nGSZhF + jCxRjTVKHTdHBMmERu/nNG7OSVC4MbCuUVCAyEKEARLJDx2S2ghNIy84a42Ojo7Ozs6urq79+/fjBhYk + 09bWBpkvX76cELcWSSZLmEg1V+GchOIGaw53zg8ZtwprDjetZ7NeTk77FRcXP3z4EDZC00i/lq3YxRdj + aRw5cuTo0aPH2IUbhw8fPnTo0MGDByl3QIfGFyxYIJQJxR5iJlTNUp5h3NRJIG32tMkPS5uPm2Y+yhpD + o7Ix0sKwLnIR5eTkfPjhh8+2bMVevgBL4yy7zp07h4+YDs6cOXPq1KkTJ06AO+4DDjrC7IYNGyZOnEgE + Pl0iXaMWujnc/6a0KW58fCZr6Vop7vjU1NQPPviAb9kvbHvUeOutt65fv46P165du3r16uXLly9dunT+ + /HlwB3R0eUCH0kG8u7sbxHNzc0NDQ4UmQskECROl9JNnJ26+tNVdm8+aj5vPuogd0Pmss2TSOKnYW5yY + mPjgwYNHjx4h+am3xxeHtcadO3feU6533333nXfeuXnzJtCD+5UrVy5evAjoUDqInzx5EjKHt4B4RUUF + eiYyAIkoK1ncYP08rg1qz2kj6qwxyHCgUWAdLxX7iDdu3Hj//n2uPapHkReBtcZHygW/w2GILb537x6g + 3759m4MOpUPmFy5cgMw54tA4un9kZCTBHSCRrpI+ZT2QtGkgeR4b4XDjBjejq7DGr82USRPIOJOQkIAt + p+2RiyIvFGsNqAAHHTwON7CV8DtIA9wp9Lt373JKf/vttzniVONwFfj4jh07IiIihKZCyVSJdL3ytJQK + a07anI30G/74oLliv6Q491TIDo3qrH3EmzZtgkSw5VwUeaFYa8DX0LKxWfiI29hEQAd6DjqUDhOkMqfE + OY2jhfb09KB5QuBVVVVhYWEiWxEzh3USPmsVG6FjJOaa57FsWvh8NY81F/hY0IQ1PMRbnJycDGXwWSP2 + vSCsNXC3cwsJCQanAp0qncqcTxyughYKH+cEfvz48YKCghkzZoi9xMxS5lmsn23ZKpRpUdY4DnA09Msa + vdFDnJGRAdZc7HtxWGvQjcBCKsJtxH4kJEDH9nHQ4XrYaCpzSpy6Chop31IgcOonSUlJxLgnS6Qb2EcS + ONZ9LZs8fPOc7ZGCpmYN1jgaMMhwIYRjHSMVOYvy8vLef//9F421Bv4wXdgIrH6hQ+l84pzGqY9D4Ldu + 3bpx4waCCsWNXIixfunSpSInETltMjBrNLc+7ZEPGvUM1jRc01+CYkGjkDhFdqLy8vJnsP5NZhkNevfS + hS3A6he6OnG4CnYDAZYKHDvG+QmHG6FbqCuUTJLAQ38G1spPEtbw92JeCFGKmrBeyojMRc3NzSqssf2/ + IWsNxb/KRYljUeIUugpxzlXg41TgaJuIVnBw+IkK7q6uLkRAsQvr2j8Xa5g1WNNwzYUQjnWGjFnACA2E + Bw4c4Fir55BfmbUqaP7iiFPofOJwFb7AsRvUwVVwUzNB+s7OzhaOEjJBjAK0OmvEvudhrfwMAa0eQiho + yjqIEUgEuKdfENbPAs2tfomrCJzvJ3zc8G60SkyYLS0tmN3F48Qka3Ogfyxr3mcIa3wnQkiBsjHyRI0/ + IZkoiYqKQrvGltDMhy2kcyM2HruAffnVWD8XaG5xxPsVOPUT7AynburdaJVIJpcvX0YKjI2NRTBgIlhp + q7PmPEQlh3CK7pc1QgjXGDnW6TJpolQ8WpySkqLOGvr4lVn/ONB0cbixgJsTOB83NRN4N22VNAhS487J + yRGaC5m5DAE9EGv4L0DzZ/T+QCvMWqUx0l/Iilq6RiqyJyEEdzYmANz36Cj03BNljY0Ha7pHit37ZdZP + Ac0tDjffTzjc1LuxY0gmCILYT+okmHHq6upIGgmUPAXNZ50nU+Tr5xC1gjXfrHmiRjHhjNBI2NHRgb+O + uxypFAoAazQYbCq2GVuOXXihQdPFqqGPn1Dc1LtpMsExiz2EcSN0U2l3dnbOmzdPMkGCA/wpawqam2XY + GV0BlA+6L2sCul+zZkVNWKMxCgTwLsoadzx6CXSALfzVWP8MoOlSx821Ss644SQIAJD27du3IW0E7RUr + VojHiskASUFzoqYzOsyXa4wqoFHqrPlmTX8hCxqxEk04Pj4erQImhvsbW6ISrn9ps/7ZQNNFWWNR1hQ3 + 30lUpI38t379erGXWBqrxnqr8jwf9+xhFdAojrV6su4ravx+kYOorKwMdzD+NKwMW8IFvl+hMf7MoOlS + kTbnJNgrOAkOW07aOJahssTERLGrmIlmFKwpaI41/HcgUaOUrAloLllTA6G/TSlqZjEj1BceOnQIAZ8L + 1/wQgq3FNr9MoLGwuSq4qZOgBUHa1LVp/sOxjD1PT08nsW81y5oTNQohhG/W3KMBaqAVrKmB5PMMhIqa + Pd8imSbBmIpcj4OJH0J+hcb4S4Gmi8OtLm3q2jSQUBvB9EhOQoE1QKuYNVhXsAYCsj/ImqY9voEoRS3d + LBW7i5Ev0Y25EMI1xl/UrH9Z0HRR1nxpU9fm2wgGCkRdwhq6hofwRa1iIBS0Cm6ONcxa3UB4omaWkbTX + 1tZ2/fp19GSVxsiZ9UsJGosIu6+0qY1g92iHpHMNVJaZmSl2E0vXSZ+CRvGnGGB9JmuFgaCL8hOIUtSy + NPJSsCVLlmB0oo2xX7P+2UX9K4Gmi7LmpA0bgYiojcArcRSDNVSWmppKckg8jzUMhCZrGAhogi997kd/ + oBWsYSBIIHSEAWjKmhW1dJMUvXfr1q0YnWBZOJhg1r/0FPOrgsZSYc23EewqTX5ojxs3bhT7ismTiTnW + XNqjBsI9p6lf1pyBYIShP04NhAUNUZNxUU948OBB5Ev+FPPLGcivDRoLW09x822Es2yuPUZHR0smSp6C + huEqDYR0RSrqgVkrDIQ7B8J1RRY0MZAJktWrV1+8eJFOMVyy/oUM5DcATRdlDdVwrGnyo+0Ruw2thYeH + S2byWEPUynGR0ARi+gRUvocoQStYw9ZVuqJS1GSEsRZVVlZiNKfJGn3il0t7vxloLI419gesueRHUzZY + nz59WqgrZBYwCtBU1DAQ2hUBl3uyb3+sFaKG29BYrSZqZjYze/bsc+fOIVkj83Bp75cwkN8SNBafNfZK + nTVymNBCSJ51RllTUXNdEZTpqwWeYSAqXZGKmj4VIlmGWI1ZCQaCtPeLGshvDBrrB1lXVFSIXEWKEMKJ + msZq8KUvzlBhrQT9tCvyZ0VO1KnsXC4jcznSnoqB/LwjzG8PGgv7gMWxxu6psE5OThb7ixWg1UXNveKo + P9YKA0FX7FfUqTLEm/Xr1/MNBA2ZP8Jgq/59A3khQGNR1hBOv6yx80uXLoWlElLgxT1ZkoqagqasBzIQ + Oiv2K+pI8tKY1tZWlQRCR5ifqyu+KKCxnsEaOeTkyZNCYyGzgiGgqXtw8QOIm9iCjTxb1PQESF/QshSZ + JECycuXKnp4eJBB6vok7BwJRcwbyioDGUmHN+TXN17W1tWQ6xxSTy7oHN5RDyPTFz882EBr1+KKm7pEi + k66SCk3IlZ7Onz9PzzfRcyBcV/z3Rf1igcbqlzXN11BZQkKCZJqEgMZETgfFSjbnATH/Zc9qoElXhKhL + lPOLuqgnSZYtW3bmzJlnd8VXBzQWZc31RrDGBEFn9Bs3bpBkHcEoQLOnqglHmAYotyhZ/6CoaabmgZZG + E1HX19efPXv2GV3xJ4v6RQSNxWeNPeRmdEisubkZaQ9oFKC5lgjEO1nW9LoJHGiONSdqdadmX4mDiR+i + xpREuyJ3Yo/Oiv+mqF9Q0FjYH8hHhTWSAPY8Pj6emcEQ0LBpuAfXEvnXXunPQFRFzeU8FjRxaiNhY2Nj + b28vPbGnPiv+ZFG/uKCxONaQEnYSu4odRoNCNgARHOwENLIH3KOaJQvEu5Ss+00gVNT8TE1bIuseRNT+ + 5Flkp06dunDhAn9WpKKmUe+nifqFBo3FZ42Dl7KGxDAuiseIiagBmjv1QUG3sqxVDERF1PT0KUD3FTWz + nBHqCPfu3ase9f5NUb/ooLEoa+yeSmMMDw9nwhkCGjaN7AGa1D12s6y5C2X9oKh5oFHi0eK4uDjEdhr1 + fi5RvwSgsfisObPu7OwUOYlAioCmNg27YEE/vdjeQKLGj9CzH1xLVLoHE8aMGzfu6NGjiHo/o6hfDtBY + 2CuuMVIDQfCC9JgQhlgBQMOmafag1++kF5F8hqiL2PPUai0RhfsvMzPz5xX1ywSab9Z0ikHmFVmKMCsS + cJxN08sv04ujPkPU2/sOLzzQTBAza9asn1fULw1oLMpaxaxTU1MlMyVPQbM2TUCzF0d9KmoKWsmagC5X + 5jw195CuI8NLVVUVFbV6/PgJmfplAo3FsYamYNbQFw5tobFQmiQloMGRgqYXW0bBQAYSdSU7vAzQEiXj + Sc6DqBE/uEzNDYr8sx+KLfuh9ZKBxgJrFQOBn0pmSBSg2VkcfAnljh8SNcyd3xL57hFOnunb3d1NMzU3 + KPLPfvwo93gpQfMNBAkEhzaOdGAiEOnYgn4I0F0s64FEzbVEgEZL7OseKJEDuZrksWPH6KBIz36onNJ7 + fvd4+UBj8Q2EJhA4NTObISg50PBoepH2NqWoOdBK1kTUaIncqY++oCXTJHPnzj106BA9+3Hjxg16Sg8R + np6n/lEt8aUEjYV94xvIpUuXED/kW9m3fgBoBA8Kmr7LAxV1vzkPLZGbElXcI4o8nNja2nr8+HHEG/pU + mwcPHqAl8h98eU5Rv8SgOQOhIwzJ1IsYolwKGsEDoOm7PLSzosZ9oC5qtERMiZx78ECjxC7kigmHDx+G + qOl56oFynmKzBl4vK2gsFVEfOXJE5CwiLZEPupt99xLcgKibBmiJpbxA3dc9mBlMcHDwwYMHT5w4oT68 + /KiW+HKD5kRNu2JYWBgTw6iCPszqGk7dMnBL5AJ135BHTpzKhDt37lTPeT+2Jb7EoLE41rQrNjQ0SAIk + xCUoaLjzIfJWSIR1F/vuMAO1ROoeajaNwjgO90BLRM7jWiJ99umPco+XGzQW9pAaCESN/RfqCuG2itMd + FPRR8oZTRNrI1LQlqoOGe9DJhZ734IFG9ggNDT1w4AC/JVL3QEt8/inxpQetImqojwljyMBCrQOgj+np + nWDf1quTbYl896CsqXtwk4uKTS8nk0tHRwdaIn3ott8p8dUHjYU95EQN3Yldxbot7LkODvQpwpo4NVpi + v+6B7EEnl37dw0qUm5uLKfHkyZPclNhvoFZsUH/rFQHNF/WsWbNkybKnoI/r6Z1mC6JGzhvIPTC50LOm + aqAl4yTLly/fv38/nRKvXr3KD9Sce2AbniHqVwE0Fl/U+fn5TAhDhu/9CtD6p/UNTxsSUe9XugcHmrKG + e5SxF4vsz6aZuUxAQEBnZycXqLkTp8/vHuRSP4qbL/PiixpHt8hBRIIHRhWAPqFncNrA+IwxcOO/A7qH + Ssjj2bQ0ViqUk0fH/x33eEVAY2FHsKtQFvSFKQOHPzHlwwQ05GzWYwbWUPez3IMLeX1Bo3DPpaWlUfeg + z7D5se6h8Yw74eVaVNTYW+wzehezgCFyPkI6IRBb9lpa9FgQUVP34INmWStC3kA2HSAJDw+n7qGePZ5n + ciGgXxlRY1+oe8BJxW5i8satCNEsaKteK9uztiZnTBTu0e95j3KeTfcFzcwnj9i2tbXx3aPfyWVA0D8Y + AF+ihR3hWuL48eMRJGjkgG+AsuM5R+AmLRHj+EAhj2/TPNDSGKmAEbS0tNDJ5dy5c2+99dbt27f55z2e + bdMaz7bwl2sBNCfquLg40KGd0LzH3OGcg+t5V7CGX5NxXMWmWdaqNs0DjUKazs7OhnscOXIE7qH+UADu + 3WfYtMazLfylW5yooT5Mz/ANkIVBO5138rzo6XHBA9DhHuRZH2qgSchDmh6gH4pHi1etWtXe3k4fClA/ + a/psmyagXzH3gG6wUziuRZYivQPEoK17rSHn0ZdG+1zygbRJ9tjL2rQKaIgaaXpr//2QCWSCgoJg09xZ + 0+vXr/cb8voHzTnLK8Oac4+pU6fql+jDoO3O2kHL4y6NC7gcgBskeyDkDZSm6Uv11UGHM56ennv37uVC + 3rVr11Rsmjs9rdgU3tKgzvJKtsT4+Hi9dXrUNyDniVcmTr061feSL9CTkAeb5oNmWRObpv1QLXhI15N+ + 2NTUxIU8+tya57Rpcv3oZ7fLl25hJ7Ev2GFAkQfJkTfgG+ALyjPfmjn5ymS4B7HpgdL0M/qhOXl7tJ9m + 0xrPeU7k5VrYF0gHwYBxYoAVdjH+8vjAa4Eh10PAGv+FTZMnjP1gP+wLGtkcYYZv0/xZ/NlpWoO7H/r9 + 8ku6sCOQFQ5kgUjgsMfB+6I3fGP29dkLbyyc+/ZcmDUyH3kcQP3sEu2HmA/7A435MCwsbN++fZxNP3+a + 1kC75H/51WBNQUM9oaGhdoV2IDv92vT5N+Yve2fZkneWTLs6jYS8TrYf8kGzrNEPSfAAaPTDvgmPmc1M + mTJlz549NE3TRxHVT3r0D5rv4q9SS6TusXnzZus4a8g5+Hpw+Dvhq99djQp9O5TY9IEB+iHmQwQPmvBU + QC9h3N3dd+/e3dHRwdm0ysO1A/VDDfUTfa+MqLE7dXV15nPNIed5b89bcWvF+jvr496Lg6i9LnrpHdEj + j4s/I3ioJTzpWqmZmdmuXbtg09zDteiHd+/e/cF+qEE1/+qJGnuBfQELo7FGkPOim4tibsckvp+YfDc5 + +t1oBGpM52Q+7Bc0fVhLLeHJkmVCXWFlZeVAYwvXD/sB/fDhw3/n+dUv7MIuYEfQpuTm8rnX5i5/Zzm0 + nH4vPft+dsJ7CUgg6If9Bw+wpglPHTSb8HJyclT64Z07d/hPNKUYVUH3+2QybKLi6y/zwl5ghx0dHUMO + h0DF0PK2B9uKPihKv5++4MYCMrYgeKiAZlk/TXjqoJ1EGzduRD/s6uqiz6qhDwJwwWOgfqjBXYzslRQ1 + 9mXy5MkhLSHx78VDy2UflVV9XFX4QWHkO5GYy8kgrpLwKOjSgaO0tzgqKgr9kD8fcqfxqF65uUSxHezS + 4NIJv2m+Gqyx/Tg6lyxZMqt4Vtq9tOIPi3c82rHz8c7qj6vj7sRhbCGDeL8JD1F6ANA0Sre2tvLnQ5VH + W7jgodgOdmnQpklFTTM1vUNega5IQeNID0wNzH2QC767H+/u/Kxz1+Nd4I6hXLd74Cg90MwSKJk5cyYN + HvTRlucMHhrcFfZ+3stTvCALu1BYWDhpzaTSj0qbP2k+8PmBo18e7fqsK+9B3pSrU0jCQ5TuFzSdWdRA + MyHkqQc7d+7kggf/YS0uVvQDGsrnnsv+M16e4gVZAN3U1DQ+bHztx7Xtn7Uf/+r42W/O4mPlw0pM5OSM + R7+gq9gn8vYLOowZPXo0QCN4cA9rPc+JafKes7/E5SlekIWNh+68Z3jDLg5/cRiUaUHdYTfC9E6xM4sK + aPY9nMmjtP2CjmCcnZ1bWlr4J6afJ+FpZGdn08tTcE+x5ke9l501thyKcxnnArvo+bqHAw11I3gYnjYk + J0v7A02e84gpXA20NEpqbW3d3NzMJTz6JLF+Ty31Ac0w5rh/+K8PfZW6IrYc+2XraktNgys4deztWJMz + JmQ4VANNTpYOBHqt1NTUlILmP1D7g6eWNMzMloSGhuJugf7pd9OuSLvni2Yg2IwfXIpvZRf+C6GZWZvx + KaOg7s3vb7bosSDPTlehjALoQuV5JRXQcVIDAwOA7jdKPwu0q2u9kVFgbGws7Yowdf71bX5RA8GhgzaC + bW1sbMzPz9+0adOKFStwr2PEQMNxcnKysLAwNDSUyWQSiUTILtzAf/FJfAnf4O3tPWnSJPxIZGQkYty2 + bdt27NiBeIsohV3ANmPhrxiMMuj9updfYI1x3KrXikzhKpRR6IcDgJZtlMnlcjTYfs/hqT+mpdhVFvQO + R8c8Pb3RGOFxCHAGgqSiYiD4sZ/MGr8HbQCRKC8vb/Xq1YGBgcBkbjxqrIdryNSJq8Pmpq1ZuT1lY0t+ + dnd1ydld9Tf2775/vOvx2aN/unz6ydvn//HOpe/fvYzCDfwXn8SX8A032prO1pV0F6S3JK/bHr0kNSx4 + VWDAHB+3sbaW5ga6GL7xh5YvX/7m8DczdmTUnak78uGRni97SH3Vk3Mvx67HjiiaPb9B6nlAJ8oYhgHo + gWaWZ4FG2dhslkqt6+rq6EMG1EBUEsiPMmv8FP489JWQkICEr6cjH+PuGh48Y0tMVMPW9FNNVcD0j3cu + /uv2lX+3bvT+6/Kx73u7vj/e+v2hhu87Kr9vLfy+IevvFZvvpq84GRNaP39ilLPxPDdzD1M5I9bynuw9 + d83cjds3xrTF2B2zk+9krz+B4nCjYB0FA4BOlolEIoBWP1kKgT5jOAToBrZ2WFquEov14Tt8A6EJ5DlH + GNyZyJXQ7KJFi3Tl8gAf7zWL5pelbj7RUPXxmUOqgH7GunXxX9dO/evCoe9Pt31/uPn7rqrvdxPW31Ul + fVca911B9KN1M55smfckefa9NRO753sVTrKLdBvlbSIaqvWHQT6DhgcPF6wVMAUMCRts6VSxoGm8S2aL + xxoOBq9THw77fZRWgYYF3eTq2khxm5qGzZs3D+5ODYTO5c82a9zGn9m+fXt4eLiJkeGsiQHQbHtZwb1j + Xao4ftF699K/rvf869KR73s6ibQP1H6/t+T75q3f1aZ9V77x0aa5T3LCWdbBTzZO/9uGSX+L9f/zau/z + c83K/WVRjlrehoNHav73IM9BI0JHCBOE9NmO0gypNFUqS1KyVhYFTYdD7jmPUGe/U7gCE0C7uTXzWY8a + FYyOxM3lOBa4sZJv1qCPv5GcnIy/OsHHe/PKZftKtj04cUB1/3/NeufCv946rWS9i7BuK/1+V/73OzIf + pUc8KV79JHfZk4yFT1LnPNk042/xU/4cM/bxSodHS60eLTJ7tND47Az9ojHixTYj7HRe/6+h/9+w8cO0 + FmhJNpD3TCOVRIpATyLWAUtEJqZT+LNBc6IkoHmsG52cyg0Np6xfv54bYbi0B9YQOH57XFyckYH+3OmT + ixI3XNjToLrDv34BMeR89SQo/+vcwe/PdCj8urPq+7bt3+3M+yQ35kll/JPtMU/yVjzJXkyknTTr2/hJ + j6PdH0XaP1rCsl4w6sP5RvfnGb0fatjkL13rqOmjP3jY8P8e4j5Ec7amZJ1Eii4G4hulaIb19fUAzU3h + 9HkH/NMd/YJu4bEmuB0dCw0M/BMTE+E71KzBGlEGbc1AX2/e9KllqZve7tr93S2SBFT3+WcvNEyi06MK + gif3ErUeaf7+UCOp7h3fd9d/f7CO6Be1v+b7rmqWb/n3+7Z/v7vo+10F/2zKebwt5knN5ifl65+URD/J + X0FsJH3+t0lBn8aNeQTWK5weLbV5tMgcuias5xrdCTF8d47hO8EGe/xl6x21xugNHjbsv4d6DdWap4Uc + jXxZW1uLfoiZhZvC6emOZ5xX0nB3363Gusnefque3pj09HRMmUlJSVpaWlN8x2Stj0bw+utbZ/9+A3nr + 4j+VkUsVzU+oqydJHwM10GnK/q46mTSxwujvtkZ+l7Xku/Sw71Lnf5cc+l1SyHeJs0ltDmZvzPkuOeS7 + lLnfpc0n35Ox+LvsZeRHtq38Ln8V+fGitd+VrPtHUezjlEUEcdHqJwVRT/Iin+QufZK16Nu0kE83BXyy + Hqw9CesIu0fhlo8WmjycPwq6fi/E8FawwY1ZBteD9K/O1G/wY1bajnSSv/Ffb/x/mpqaW7ZsaWhoQMKj + wyEd97jTHfS8kipoT8+Oflmbm6doatrpSqWRc2c3b8t8eKr707NHv7p44s9Xz/zt+rn//TdYkygG0dWn + f1cU8136ou82Bf1z3aR/Ro39Z6T3/y7z+HaJ+5/C3b5c7Pr5YtfHi1wfh7k8Wujy8UKXhwtdPlpACjfw + X9QnYS746meLXL9Y7Pp1uBt+6q9L3f++zP2fER7/XOFNfuEaf/zmJ2snfxrh82RT4JPEoCcpc56khTxJ + C0V9mzLr8Sb/T+J8P4n1eRTt8Wil86Pl9oT1ItOPF4x6EGp0d46C9VtB+ldm6l+coX8hUD/fUzhHb7iV + WDMgIACHOBeluSkcRz93uqMPaG/vQyzrPZS1i0ujrW21qWmJqUmRqXGCTOKSFbvq1sE9SBFg/dm5Y19f + OvmXaz0ca2ogz2ZN1Lozj+grZS7L1Ac4wAWMwOuDBc735zm/P9fpTqjTu6FO74Q63QxxuhHi9HaI4/U5 + jm/NcbzWX+Hz+Cq+B4Vvxk+h8OPvzXW6O8/p/nxn/Fr8ctwTn8xzuBto/M0Sx78uc/pbhOvfVnr9LXrM + 39aO/3PsuE/Wejxa40kUvdr9UZQr0TVYE8s2fzTf+MO5hPWd2YZU12AN0Oem6p3z1z800SzJWW+8gdDL + yysmJgZ9i5/w6MxCswMX0gD6KMu608Vll41NtZFRgYV5qb1tpatjHcrOKkVX6p4ZE/Vu9977x/d/fJqw + /ubSqR9gjc8caviuctN3aQsI2eVef1niTrECAZhSoADER3l19s9Q3D1B7wbcZ9dmWp+baPROqO2deXZ3 + 59t9sMD+UZjDZ4scvwi3e7TIGPolKoZHwzpo4TbRNWH9Ueio+yFGYA2/VrCepndhgsH1mVbXZlhemWFV + 5GUUYs7oCTTXrFmDxgj3+Oijj2DTcA/0Q+6MB1gD9HEPj257+z2mpjU2VjWOdrVuTjuUVY+ys0rTl3ul + rlp+u3vfgxP7H5059Pn545Q1pmE+6+9O7CH2mjofx+w/lnngcMZRzyeLPf95sT5PnZtmcWKC4aVga9SV + 2TbX5ti8HWJzM9T2Zqjl5Tn61+cYvDPH8L1QQ/gyHAP98FGYKaEcZv5ogemjecYfzyWs359NbOTtWQZX + p+tfnWx0c6bV24S11dWZ1pdnWNX5miy10bWUCmNjY48ePYpBD/MhHT64oVrD0XG/lWWrg91ed5cOT9d9 + Hi673JwaVFg72GQa6PgmRCy6c6gNrD/pOcxn/fe9pX/PXfG/66f8Y7kn4MI6AReH8C3WBDi4Kvv/q1XP + ZLMTE0ddmGVN62IwKUA/F2x2fKbuqUDdnhl652bqXZqlfy3Y4Ca8IsTw3lwj+MbDuaNAGUV1fXe24buw + kUCDG1OMb8+yfifI+u0gaxwuV2aAtfWlmTY7/c2jHPTtdMTwbrRHbtADa3iIhqN9p6fbodGeh709ur3c + 93u5tXm4tLo7N/bFvcPRLs9Qb2L0gpCrbc2U9Wf12V+lhH2zatyfwl0J3HmA60jg8pSrss+/SZ2eaHJq + sgkHmqszQaaHZ+gcmqZzZJrO0Wk6J6brnmahXwjSvxSkf32W/s1gA5gG+IIy6t4cwvr2DMM7gab3Z1u/ + F2zzbrDNjSCb60HWV2faXJ5pc3Gm7YWZtq0TLKMcDe11Jampqch8MGskEODWGO15jK2joz2PeHsc8nI/ + 4OXW7um6x925SYW1s0OZscHMReO9T6wIvLd0zAfznO7MdbgZYv/2bPtrsx2ukb1yuELKEaWyt79hnQwY + dWaqqQpl1KmZJoem6xyaqqxpOodZ4sen6Z6crntmmt65QD0kDWQ7OAZ8A9BJBRren2n2YYjN/Tk278+2 + BetbwTZvz7K5FmR7JciWsA6yOxdk1xJgudzBwEIuLigoQOaDtDnQlPVRsPb2OOjlBhsB6xaWNYvbsc7N + psLNcrspM104aHjl6FGnA23OBNr2zLDtnWl7Nsjuwiz7C7McLgU7XCb1ArE+Nt6wZ7q5CmXUyZnGfUDz + 6vBUnaNTdI5N0T05RfcMYsZ0PeQNEEc/vDHV4P5M84chNh+F2H4QYndvju17c2zfnW17M9juerDdlVl2 + F4PszgfZnZ1p1xtkVzPOYoGNgT4jQujmg+Zww0YOerl3sZbd6u5Q52Zd7mZR7Gpe5GJe5GxWZCqbLxoq + S3TSOTjF+uh0mxOBNqcJbvwBsLZXZ001zhX7VVL4zouzSJ2f5XAuyP5skH3PTFKnUTPsUKdm2J0MtDvB + K/wXhc/Tb8B34vt72Z/Fb8A9jd+GX6vcBnJ4HfbVOzvD8vwsaxQf9ImZRv2DnqLTPZnUock6hycT4sf5 + xCfqvTvD/P5smwdzbD8MsfsgxPZ+iN3dELs7c+xvzWYP7mD7S7PsLpBNsqP7kudjNs1cF6CPs3zpR441 + bKTby2mfp22jh1WNq0W5s3mJs1mxk1kRLQu9KOkIqwgLSeckq8NTbY5Ptzk1A+q2OzeTsKbSvhTseFmJ + lTLF54GD/nnAOh5odyTQ9tB02wPTbDqn2HSw1T7Fml9tk1VL5RvoT+HH90+16Z5GftvRQFvcJbgbyN02 + w6ZzjE7PTKveIKuzQVbn2KLQj84w7J6mRnmqTjcFPUlRwM0RPzFF99R4navTzNEJbwdbwzruz7F9EGL3 + INT+Xqj9+6EO74Y43Jjj8NZse+wyOODuP8OKBrtJQfctj2OjnfePtm/ztm31tNnpbtXgalnjYlHhbL7d + 0azE0ayYrSJbo0Q97dEzDLQrfIy7p9ocg7Rn2J6ZYdcL3MSniMTOBjlAbhTrsUA7PlMwouD2KWvvJOs9 + bO1+jqLfiR9Bcb+Bf09Q+vsCzJu8dQ5Oszg03eJooMWJGZanZlr2BBHuhwP1Dk6VH5wi7wZctvoFzRXF + fcRXfn6q+ZVAy7dmWN2cBdy278+xvRdifz/U4f5ch7tzHe+EON4Kcbg+x+EKYe1AWWP3+4IGYqcDo+3b + ve3avGwh572etrvdbXa5WTe5WtW5WFY7mZc59cU9igkSDhYlOunCRo5MswbuY9NQtvh4eBrB2jXVun2y + TRu78xQrBUp5tU602jXRaievWiYoqlmtuC+h+D+C34DCr+LuA45+s69xnbfO7klmqL2TzNummHdNteie + ZnEk0KJtqk77ZFnnZPn+KfIDU3jEp+gc7A80qQk6h311z06zOD/N4mIgGVjeCrK+Ocv29mzb90Ls7811 + uDfX8d5cTKdIX45vk9BFjmOwhtSUHq2KmFabh80+D5s97ta73K13ulrtcLGsdbao5OEmxM11V0pH2Cww + EdX5me2baLl7kiUiDtlt3CY7jxso61YWK0Wj4Bjws1bfO4Cirx1tUOOj3zLRbOckUrtY4qhdk0zqJjCN + /szOAOnuCdK2SbL2SbKuySzxyfKDk1A6tPqADtA54qffO9UCrM9Nt7ww3fLSDKtrSHizbN8JtrsTAvcg + oO/Nc8KMdpuMESTjwjbBmgVNjcJuH4fYA2VDQNPicLPSroe0n+I2J7htjdP1hBNGvvHmWjt53Tizen/z + hvEWDf4Wjf4WDQGWTQGW5KO/VVMAKVVAv1Cx92WZu071WMOGCaZNqIlmqGYW+o4JhhXjJZV+kio/SfU4 + yY7xTLM/Ib5voqx9oqxronz/RPlBWnzi/jrHxhkQ0IS15blplucDrS7OsL4SZPPWLLsbwXa35jjcCXV8 + f67jXbBG/GXnYYwUYK0x2qFtNEEMlyBFEXNFKCvL3Wavu81uNyLtJhfLOmeLakfzSkfzcgezMnuzUpSJ + PEI83DLQQJDpYVTua1bpZ17jZ143zqJ+vMWO8ZYN/paN/grcqlB+mcIfyrMXVfuNqvM3rQ8w3RFgCuKN + LPRqf73tfpLSsZIyX0m5b1/i46W7/aV7A2TtAbKuCfIDfNzjdI77G/UBPd3qfKD1RQwsQbbXSMKzvzkH + LdHxDjEQha7B+vocRw0v292etntQHqBsQ6sPayXodrYIbjebVlfrFmerRifLOkfgtqhyMK9wAHHzchvj + bF3hlJFvaIebM2VjzSp8zar9zGv9LOoJbsIa9atJu97PrNCZAWV+UeJl4+VFvuLiMeKSsZLtYxXEK0Dc + V1w5VlLjK2nwY3aOk+7xl7UFyDonKAR+wFd+YoJxz1QL1j0s4R4AfSHQ+sIMMhZenmV3dZYdIgeCxzsh + ju+GOkLRwE1Za3jY7PSwbYUzsNWHtTtbStBt7qTa3WxQ+1yt97hY7XKxanGybHC0qHcwr3EwB25Fmemt + lWq6+khHxNrrQtpVvpC2Rb/S/kVxV/uMKnGXq4CmVeQrLRgrLvQRF40hxREvGysuHyOuYKtqjKTel2ny + Y3aPl+71JwLvHCM7OdHkzBRzgO6dZnl2utU5FvTFGTaXZtpeCrK7Emx/NZjMyUgdN+Y4srjJCTWUhpt1 + ozsynM0uD5vdHGvWJRSgSdm2Aa6bDT6CcoerotpcrPc4W+1yJrgbHS12OFrUOZjXstBr7M0qjaSLhMNM + p+hpJ7sYVPqaq0sbuBv8rQrGmKd4msQ4G4XbGQZb6k001RltJHPSZ6x0GGOpWE8ikoqEYqFQKBCgcAP/ + xSfxJXwDvg3fjB/BD+LH8UvwqwrHmDeyoMs99cu89FQQo2r9TQp8Jfk+4vzRpAp8nhIvQfmIS33EZT7i + CtQYceUYSa2vpNGP2eUn3eslPTbR9NRk8zNTFazPBRLrgKIp6Muz7K/MskfYAOu3ZjvQ87SQ8y2ARmdD + nHCzbkGvA2t3ND0FaFJEvDZ7Xa1JsbfbXG3aQdnNthPF4XaxbmVxN7ECB/F6WrYm+friWdpD5EFGwgx3 + I0g7y9NkrZPRQhuDiaZyF33GiBGbmJg4OTn5+fkFBgYuWLAgMjJy3bp1SUlJWVlZeXl527dvr6ioqK6u + rmNXbW1tVVVVWVlZYWFhdnZ2SkpKXFxcVFTUokWLZs6cOX78eBcXF1NT01GM2NVA6iEeNsdcstZFP3u0 + ER905XjD/LFiDjRXwE1qtKh4tKhktHj7aIK7XIm7erSk2Ut+IMD0yESzE5PNT0+x6KGiBmj2jBIHGgn6 + ajBhjcjBnRbXQHJwtqhClnCzakajc7dpZVnvcVPw3UMpu7DlSlijONZdbFHi+1ysdysFDuJw8AbC3bLR + 3CiDEUwd9EeBePhQzZEj3N3dp06dunjx4vXr1+fk5FRWVoJdTU0NIALlDnY1sKuxsbFJuZr7Wy3sUvyH + t0pKSqKjo0dqj/Se7G3vZT9Se4SFXNvPWLLARp7gZrBtjE6/oEl5iwu8RWBd6C0q9u6L21Nc56nTOs64 + 3d/k4ASzo5PNTxLWVmcDrc/PsAFrgL40y56wZkFD11fZByKQOkgzxNCBfOZsUYGM7GrVCGm7Wu9ytd7N + IibFClYBegDW+9mixKnAdztY7rS1aLYybzI3a7Kw2Glt3WpqmiOTBY8caTBt2rTNmzeXlpaWl5cDMdQK + xPX19RxZkAK+nTt37mJXa2vrbnbtUa69AyzFl/fswTfHxsY6jXZKrU1FpVSnrExbOXvF7LGBYy2dLcWi + 1+303phmNmy1g2aeGuh8LxGqgC3gLlLiLnUX13nptfiN2uVnsme8SWeA2aFJ5senWJ4mrG3OzySn7gjo + YAKasGZBU9YoChqFMa/MyaLKyXKHs1UzGp2rdSt4sUVZP8WtZA0boaz3u9sdQLnZHnCy2W9n1WFl0WZl + 1WZj02Fn1+no2OXsvN/JiZSz8wFr6+36+gu0tEwnTZoUHx8PIUPFVL/gC7jAClKgtm/fvra2tnZ2dXR0 + dLKrS7n2qy3FF7q66HfOmjUrcHFgVnNWVlNWZmNmRkNGxo6M9Pr0LXVbZLGyodOGvu78+v/o/Y+e+DUf + w8HhtiMyPYUsaEKZlCcpylqhbhdx3WiDJt9RmDZ3jjNuHW+6L8D0wCTzo1MsT06z7p1hew6siajREgno + K0rQtDQcTAsczAodTIvsUWYlDuaVThb1zpaNcAD4wECslbgJa1fbTkfrTnvr/dZWB2xsjjg4HHd2PuHm + dtLV9TjKxeWoi8thlLMz+YhydT1ib7/DyGilWOzs4+OzatUquAcQU82CL8V64MCBgwcPdrPr0KFDhw8f + PsKuo+w6prbo5+n34JsdHBxicmLy9uZt27Mtd3dubmvu1l1bs3dmR9VGCdOFWrFaWlFaWiu0hgcNH+w9 + +DWT1xjh/3gbDA63HpHt8RT0U9woR1Gdj9GOsaMafI2b/cDaBKz3+Jt1TrQ4NMXqxDTrHsKanC6GexBd + s6fmcRtB8GTAKA170wI7kwJ700I7RRWzibgG9joA66e4naz32VnutbLYZw3Q9t0s3zNubr3u7mfZ6nVz + 63FzO+3mdsrNDV8iRenjhrv7CReXAxYWKTo6U0aOZObOnUsvdgZtgizFCnwnTpw4efLkqVOnTp8+febM + mZ6enl7lOstbik/19uIb8G3on9ZO1iX7S1DFXcVFnUWowo7CgraCaVXTBOkCQZxAe4229mq2orQJ8eDh + gz0Gv2bwmr7gtQDDodH2mnzW+e5QtLR2jFHdGMrapNnPpGW8aau/2Z4A87YJlgenWB2bRk4XnwXrIPtL + wfYIJKcnmXaP1T3mP+rMZAsNO5N8lK1JAcoO0AnrIjvTUsRh5Ae0NeBGqODjdrbeY2+5x9pij7nZbviD + o+NBF5cjLi7HWIigeRqI3d3PeXhcYOs8W4Q7ysPjjLJ62Or19Dzn4FBrbLyKYdypwOmbVIEXwAHi+fPn + L168eIldV65cuXr16rVr195SW/gkFr6K70Fumb5wevWJ6urj1VXHqiqPVlYcrag4UlF2qMy50lmUKRIm + CIXrhYJ1AkGsQBAj0I5mcS/V0lyg+ab/m2/YvDFo2P+zl74x1/zNTHchQOe5iLa76VT7GNX4jKobO6re + 17jRz6R5nOlOf7PWAPO9Eyz2TbTsmmJ1ZJoNnOTIRJPucYbdfvonJpj0TEX4c0ABdJ4tKbAmpWRNpG1v + hnmvli9tJ6vdtpa7Lc13w4Lhv05OUPEhFPUE1iWAG2olrMHX0/Oip+dlL68r7EfUJRQ+6eXVp7y9L48e + fcXL65yd3fZRo5ZKJE4IauhmsG9QA77r16+//fbbN2/efOedd26x6za77vAW/cy77Jo8eXJ8QXzT+abG + c42NZxsbzjbU99TXnakrP1luWG0ozhGLkkSijSJRgkgYT4gL1wkF0QLtZdpaYVpa87S0QrVGBo0c6jH0 + NaPX9IWvTRk1LN5aq8xDr2q0Uc2YUbVjCOh6XxPCerzZLn/z1gkWcJKmMYY7vHSbPOVtvkaHJlicnmbb + G2h/bob9+Rn2BLS+eLqtyTa21HE/lba9RZONebO5WYuNTZuDA/obENMioClrmC9bxBlgF2Dt6XkeZL29 + r3p7v+XtfX30aK7e8vG55uODj09rzJjrY8a8PXbsO6NHX3J0rDI2DpPJ3Dw9PSMiIpCajx8//t57791l + 17179+6z68GDBx+oLRi6jbMN+O55a8/ua7tbr7W2Xm3ddWVXy6WWtUfXSuukkq0S8RaxOEUsThaLE8Wi + zazAY4WC5QLBMoF2mLb2Am2t+Qrib45/8w3TN4Sv//d0I2Gykx6mTbCuG0tAQ9o1ow2qvPTK3WSVbrI6 + L/3msca7/a3aJ1p3T7Y5NtX21HS7nkD7syxrjWH/85qOwM/KaEt/uIm0rU2KLUzKTIyrrKxaHBzanJxI + inB2PsgWAe3iwikadcTN7aib2zHWhU/BHOAMlPXo0W/7+NwcM+bWmDHv0ho7ltYttnDjtq/vHT8/1Ht+ + fnd9fC6gXFx2WFltNDAIkkis/P39YSzIhbDvDz/88OHDhx+z69GjR5988gn9iJWZmRkSGdJ5u7Pjdkf7 + u+2kbrXvu7lv3419k7snM7WMJF8iyZJIMiWSDIlki0SSJhEniUVxIuEqoXC5ULBEIFgsECxiiS/U1p6v + rTlGE1OVl5eXrtbwyfqCBFtmu5u82JkpdJRsd5VVeurX+Rg3jbNsGWe509+q1d9qT4DVvgDr/ZNsj0yx + PTnN7kygPaStkeJqMF5HkxnpbKYXq2StwG1lnG82Kt/IMN/MrMzGptbOrtnBodXREaxhGoS1i0s3S5nK + mVP0UXf3Y2wdd3c/6el52sur19v7AswBsoVgKVBf3/dBEzVu3D227rP1gK0Pxo37cOzYG2PH3vTzu+Xn + d3vcuPd8fa+5u++0t081M5uvq+umrS1EgIMXY3RE/4SxfM6uL774AiNiRn1G973u7vvd+Hjw7kHU/vf2 + d93pst1vK62RMkUMk8cwuQyzlSHEsyTiNLFog0i0RiSKEokiRcAtXCYULhFqL9IeOX/kEKshBgYGGDhf + f/31YcOGCwa9PkFHM8lBp3q0ce0Y03pfs3pf80Y/C8J6vNUuBWvrvRNsOifaHp5iewKsp9tp5HmZ5HiO + mmkoFAwdNUq2mIK2Nt5mZpRrZJhralpsZVVua1vNVo2dXYODQ4uj414npw5n5y4XF7A+5OqKIpTd3Kic + FaA9PI6jPD0p6x5v73PwhDFjroKgr++7fn7vs2Q/HD/+o/HjH44f/8jf/1FAAOqTgIDHKEp//PgPAgI+ + mDDhg0mTPpoy5aPAwIdBQQ+Dgz+eNq3H37/J23uLo+MSc3N/XV0LOzu7gICAiRMnWmPKurGn672u/Xf3 + H7x3kOBGPejOuJ4h65IBtLREKi2UMvmMJE8izhULs4SCFIHmOs2Rq0YOXz58WPiwIWFD3pj3xushr/9x + 9h9fn/3G/4j+aGnpNG7czFmzli1ZEh8aGuXpGWAk0JpjKsvzgIeY7fAz3+Fn0TjOonm8FVjvBO4A6z0T + COv2iTbdk21hIxpFo03zvAnrxeaM5iCBnmi6mdHWUYZbTU0LLC2329hAy+U2NpUoJe46e/tmR8dWJ6c2 + lvUBV9duN7fDbAExLQVlCtrLC3XKy+uMt3evj8/5MWMujx37lq/vO7AI0Bw//kMW8eMJEz6bMOGLiRO/ + mDTpi8mT8fHjyZMfTZ36ybRpnwQGPp458/GsWZ/OmfPp3Lmfzp//aVjYZ0uXfhYZ+fnq1Z/Hxn4eF/d4 + zZprkZEH7e2D5kaHtd/uarvdue9W+9532nbf2NP6duuu67vGdI15o+KN17Nefz3t9deTSb2R9MagpEGD + Ng0avG7I4KjBgyOHDl325rBlw99cPnJEhObICG2t5cKRMwXDho2IiEhYtmxTRMTmyMjkqKjU1avTw8LW + entPsJOKIqz1a30J6IZxYG0J1s3+Vjv9rcF6N4u7bYLNgUm2GmVjTYt9COutnsazTZk//Nd/aWqOHjUq + ydq6FKUETVjb2lbZ2VXb2UHXtfb29Y6OLU5Oe1xcOlxdD7i5dbu7H3Z3P+LhcdTDA5SPeXoC8QlaLOiT + 3t6nvL1Pe3v3jB59dsyYC8Dt6/uWn987sAV///v+/g9Z1gTx1KlfBgZ+OWPGpzNnfhocDLifhYR8Nm/e + 5wsXfrFo0RdLl34REfHFihVfRkd/uW7dlwkJXyYmfrVly9fZ2V9nZn4oYnSL91ceeXj6yEenjjw8dfTj + U0cfnTrGlvVxO6ZFLqmQS0rlkhJS4iKZuFAmypWKUqXCjYwwTiJcKxHESARrJILVYpT2KvFIH21XVz/A + XbkybdWqtDVrstauzV63buuGDQWbNhUvXrze3X28r4F0k/OohnGWKMLa3xrFsW7xs2oaba1R4WsG1uke + xtPN5HpCLRjchAkTBAI7Q8OV1tZltADa1halYG1vX2NvX+vgANaNzs6tLi5tbm5d7u4HwRqgPT0p5eNe + XkDMp0xq9OjTbPX4+JxVqvuan9/NcePujB9/PyDg4YQJn06a9CVYz5jx+ezZn4eEfDl//pdhYV8tXvxV + RMRXUVHfREd/Exv7TVzcN5s2/Skl5U8ZGX/euvXPhYV/KSv7duXKxolzAo89OnPskzPHH5858bjn5Kc9 + J/HxcU/SrTTpIR2mQQkatZ1lXSgT58pEKVLRZkYYzwjXM8J1jDCW4YgPt9QKDFy8Zk1GTExWbOzW9evz + 4uMLN20qSU4uT0urycioz85unD8/Wl8oDLHQK/Exaxxv2QQD8bfe4WtV621V42lV7WFZ62GhUe1nvtrR + 0E1PguwZFxeXlpaWnJw8b9684cOlOjozLS23saJWsLazq7Szq7K3J6xZ0KgdTk7Nrq573Nw63N0PeHgc + 8vQ84uV1zMuLgPb2BmJafUD7+Jxhi+AeM+bc2LEXx4694uf39rhx744ff9ff/8MJEz6BgUyf/uWsWV+F + hn4dFvZ1ePg3K1b8KTr6T+vW/Sk+/k+JiX/esuXPOTl/KSj4trT026qqvzY2/s3PLzy5MuPkp70nP+s9 + 9fnZ02ydwu3PeidemCpt12HqdZgqHaacrTI5iog6h4KWijYoK05BXLBYMlyoBTmvW7ctLi4/IQEqLklM + rEhLq87M3JGT07xtW2t+/t6iorbU1Mrp0xe660qjbUdVeVlWuJMqd7eocDOvckeZacy21NUTC1esWJGb + m7t161Zko4yMjC1btqCh+/r6isUexsZrbW3LWEUDdAVY29tXOThUY5xzdKxzcgLoBmfnRheXXW5u+9zd + Oz08Dnp5HfbyOurtfdzbm7IGX1pUzk9LSRzeDeLnx4695Ot7lRL3978bEPARBD55MtT9VUgIwR0R8c2q + VYQ15JyaSkAXFX1bXv7Xurq/pqaedBnjvf/9I4TyZwrKtNo/6TI5ZSFt1WFqWdAVbBHWOpIiuThTJk6R + ihOlogS24tliiWtPFHt4+G/YkA8Vb9xYvHlzWWpqVXp6XXZ2U15ea2FhGyJPWdnBlJQDS5d2Tp3aaWWV + POIN7ck68kwHkzJXs3I3RVUCdFBQUFZWVlFREYaC/Pz8vLw8EMfKzs7G5+fPn6+pqaenN9vaOs/ODqDL + 7e0ButLBocrRscbRsdbJibBmQaOaXF13ubu3eXh0eXp2e3kd8fY+Nnr0idGjT7I1IG5UX40T4kqN34LG + AwKg8cewlMBAIvBFi75ZvvybNWuItIF769a/FBd/O2VK/Mq02BOPe0/0VTQq8sYq6SFdpkmHqdZhKtli + WRMDyZeLtwC0TJwoE2+k9ZS4pp1w9uxIVsWlyckQck1mZn1OTkt29p74+PYlS7oCAw/4+cEzD8A/nZx2 + 4fgGKIaZaactWm1mUOZqWu5mWuZGPmqUsQtTAAIpVgm7itkF+lhJSUnITAzjYWoaY29f4eAAyqQcHavB + 2tm51tm5ztkZrBvYF9CBdbObG8Xd6eXVzb6iQB23Kmh+KYn3wlWUMoeP3+DJ/DGVOaAvXkwsZdGiy6Ms + 7Wp7Wo9+3HvsUe+xT3qPc8Q/O+vS6yFt02F2qIFGS8yVi9NZ0Jtl4k282igTLmVGigToe/HxpdHRFUuX + Vs2ZUz1lSr2fX4uHx26kAGfnvc7OuIEAhlzQAMpwVPagL9XXjxQP0QrWl4MyLY0KdtGHOaqrq+nHmpoa + 7iMWPrl69WptbR19/Rk2NpmYj1FOTtVsEdYuLnUuLvUuLg3QtZJ1i7v7Lg+PfZ6enZ6exExY4seVrFXh + 9ls8mT+FrlT6O+PHk7gSEPAx7MXMLDVk1fIDD3oPPujt/qC3+8PeQx/1Hn7Ye+Rhb9LNLNFBPcEOHUGF + XFgmF5aSEuFjiUyYLxNskQlSZILNMkGCVDuelNYGqWacdOR66dAxIgODSe7uBc7ORXZ2SLq0iIXCPMEU + LYrappOTovAZOCq+ikPf1DRJIPAbyzBpdqMIaAqUPozU0NBAHzfiP8CBhdtY5eXlCxYsYBh7E5Mljo7l + Tk5Vzs6gzBXB7epaz76Kn7w2lL7My81tp7v7Hk/Pdi+vA97eh/rifl7itPjclQ6DLnrZw+OAVM+0sLOu + 697prntn9pPqUdT9Ho9jE99skr9ZKnuzQPZmnuzNfNnwPFJv5siGpcmGJkiHxkmHxkiHrpEOiWZ4JXlN + X0tHJ9zcPNXcPI2tDEvLLGvrbba2Rba2pax5AjT4tjg773R23sV+RDVB2g4OmDYQ0rZLpbNttYQx5gYa + QLxjx47Gxsbm5mb66EZbW1tHR0cX+ygGPfuOj1j4b2dnJxrmtGnTdHXHWlrGOjtXs1Xj4gLKtIi0WdYK + J1HipgJvg8C9vA56e/8UgasXRW9ktHrmsrCuuye77p5S1D1F5d2oEnUYDatihhYyQ7cxQ3OZoVtJDcmR + DEmXDN4kHhwnHrxWPHg1LRFXbwQK/vCHEcbGG0xM4k1NN5qZJVpYpFlaZlpZ5draltjZlTk41Dg5NYEv + rMPVda+r6z5kAfYG8u5OfIlVN8aOcn39ZTpDtTQ4xHv37m1vbwfNQ4cOHT169AS7zpw5c/r06Z6eHnrq + HZ85fvw4vpqYmCgS6RgaTrWxSaK4XVyAeyDi5IWLPOK7WeJdrIOThvnvEMd+MromeW1VLGjV8jseOLRZ + MnS7eGieeOg28dBc8dCtpIZkiYakiAbHCQfHCgevEQ5erVp/dNASCscbG69Xgk42N99iZZVtY5MPC2Z9 + Y4eLSwuba9sxRrCTRCebcTvc3PYig7HSxrRRgSNg1KjVGvAEqmJo9vDhw8eOHQPQs2fPXrhw4dKlS5cv + X77GnmXHxytXruC/58+f7+3txR0Aya9du1YiMRk1KtjOLl2pbg66Cm7qJxxuSpxYCo/4T9G4gcHK4MjF + fLhcVd7aKe00GVojGVrEglZSHpojHpIuGrKJBb1WFTFq0CLBHwQjdHXDjY3jTEwSTE03m5mlWFhAzvCN + YogUudbZucXFZTcou7sDMQaIg2wdYEFD3dA1LBtWXmJjk2ttnaGxb98+GEJ3dzd0CtkCMfgC640bN27d + uvXuu+/euXPnPXbhBj6Dz4M7oFPicHBkcIaxMDaeY2eX4ewM46b1o4i38lyF83EElR/wcchKz9Sq+EC9 + CmJaU06GDNvJDC0TD81Xk3OqaPAGVs4xqpRRr4/VHjHC1dh4HawDcjY1TYScWYPOg+2i16EH8uaGA8iy + +MhWp7s7DASujVGuwtER3wxDz7OxydGAMOEV8AT4w8WLF69evQqU4Pv+++8/ePCAnvbF+uijj3D7gw8+ + uH//PiX+9ttvQ+AQPn4QXXTZsmUMYzlq1Bxb2y083D9MnO8q6JweHnt5MlexclXourqLF65bqcKXVs27 + rfIus6G1kqHF/cl584ByRv2PwUipNFjpG5uUvpFjY1PAujNGB2x2KyIsTbEs37301ccuLki60Du8BSEY + JoPEAtDZGrCLkydPUiGDHRDfvXsXiAH3k08++eyzz+h5XroeP3788ccfgzhwQ+McbqgbZlJfX8/iNjUy + QgpM7IubloqVD9Q51aGrKJ1wx1Fs7eZe27NbBTEtIuddA8g5TTQ4Xjh4Xf9yfmOKYOhQaypnExPIGb6R + amGRwbZBUCN5A3MDpjN2QINNNyt3ATLH5+uxm4hkjo64S0rs7QsB2s4uVwOODEywgps3b0KqIEgRA+tX + X331zTff/OlPf/ozu3Dj66+//vLLL0Ef3wCNU3W/8847MBPcT7i38NvQXaOiosRifUPDiZaWa9VYczWQ + zNWhE+6svSCVP+UukUxfnbVRhS+tsneaiDv3K+cM0ZBEpZyjVSmjXrPSFIkmsXKOMzWFogE6CZHDyirT + xmarrS2aYREIgiPMgc21ZOOVO4L/wlgqnJzw1VKUknW+Bo59ODJgQaFwhkePHoEjEAPrX/7yl7/+9a9/ + U64nT57gv5Q4cH/66af4ZvzIvXv3cBzgfoLtwHxg3PB6ZJi4uLhx48bp6nqZmS1xcMjtS1mlVKCrKl2d + +6hR0WOmT26/fbTz7gmuuhSFsDF92E7JkNIfL+dZ2n8YMhyBDDkBf2LUqBhj41gTk/VmZvEWFpssLdNs + bLKgUBgCyxpdsdLJqZK3I7hNimWNrxLcDg7bHRyKNSBGOADsAoZAhQzZgiaY/v3vf6cvr8XCDbo43Pi2 + L774gpoJrAaeTp0EBwc1bjgSGmxmZuasWbNg30ZGgVZWcbxtGqj6sRcVvWM/RTL9tB3bOu8eV6+st4pE + 7QZDq0VDioVDtgmHbFXU4Gzh4HTh4EThoDjBoFjBoGjBoNW0tAetUtQfHUdoaXkYGCwxMFhmaLjcyGgl + cJuYrDUz22BuvtnSMgX5wdY2x94erAtZ1qUQL7CyfLld4FgrpA3W5ELdcAD4AJDRS/pAyNAvmIIvfXE+ + 1nfswn8pdHzDt99+i2+G9nHfcE6CwwIHx/Xr1znjprgxxMNPBAKhjo67icl8W9tU3mY9u1R6KUEvkwWF + rl7SefdYv+V22Hdoo3BIqWBIvmBIrmDIVsGQHFKDswSDUwSDNmgPWqc9aM1TuFy9Ear1h5HD8Mv19ReD + taEhWK8YNSrKxGSNmdl6c/ONFhZJ1tZb0Nns7LaxoLezoCllPmgU/cxTaWuADiQJH6B2AbVCsxQxyNJL + IPyf8lqV+C/HGnqn0oaPc05C+yRn3Cq4ESKzsrLmzp2LYUdPz8fUdLFaRPnhMjGJcfTxrjvb2vn+MfVa + c2HjiH3M0CrhkELBkG18ytqDt2gP3qw9aL3WoLVag1ZrDVqlWq+5DB850klPb6G+fhhlbWQUwYKOMTUl + oKFoGxsoeqvSPQBaXc78UrC2sUnVAGWYMt8u1Clzi7LmS7tfJ6HGrYKbjpfHjh1DmsQgmpycHBwcDOK6 + ut7QuI3NZrWt7KewhyMF0oTSLSp8uTI74DB0h2BIiWBIXl85Z2gPTtYeFKc1KFZr0BpVxKg35mn+QXso + w0zT01ugpwfQ4VC0kVGksfEqU1NYBzw60cqKejTkXADbZeVc/gzQ2CnsGroUdlODM2UVu2AV3IcyXfTz + fNy4bzgnwa/iUiAfN8yEejdaJZIJ5njEyoMHD2IuBfHQ0FC4ikzmCB+3sFhlb5+jssVc4bieHbVIBS5X + M0/PH7ZbOLSCNQ2+nDNZOW96ppxdh48Y4airC8oL9PUXsdYBOa+Eb5iarmPlnGxtnQ6DZuVMfYOT81PQ + 2HjsAnYEu4OdCgwMjImJKSwsJO+VxTflfoWsvlRYU9yQNn7VM3DTVolkQoMgpiT4CQSO6b+joyM3N3f5 + 8uUBAQFisR6sfNSoWZaWq+3ts7l9gLjcxvkOZBrbrpcyHUZD6wRDivvKOVswOF17cJKScr9yDlWR82JW + zstZOcegE1pYbGblnIlEbGfHyVkBGhuJTcUGY7Ox8WPHjl2wYMHmzZu5c861tbUaUCIOf1AeyC4GWkTY + ak7yDNy0VdIhHoESuZvzEypwODg9QYgknpaWFh4ejnQoEjEymQMiuYHBTKmeQWpdjgpfrlwOjxnaLBhS + ptYDIedU7UEJWoPWaQ2KUUVM6zUnuLMzT87wDch5hbFxNCvnBFbOW2xtFW3Q1jbTwmKticlCQ8MJ2Dxs + pI+PD45LJNqioiL+mWcMcfTkqOIdOn8sZW71i5satwpurlUiCNLcTc+ZUIHThgkH5xNva2traWnJzs5e + uXKlsbHxssRlbbfb2u50tN/pan/vQMd73R3vHep4/0jn+0cX9EYM2ysaWikYUsSaBkBzPRBy5npgtCpi + 1OvBI/8wYqhMNoOTs4HBUipn2gZNTVeNGhU+alSInt5kudxLIrEQChlXV9epU6cuWbIkKSmpvLxchSyF + y3/1Anlz359MmVvPgxutEsmEBkHkbs5POIFzDs4nDlcBcUz2syNnH/vkGOrIx0cOfXTo4IOD++/v77zb + 2f5ee961fFm7zqCaoYOKhg7KfXNQzvDBOSMGZ49EDUofOShZc9AGzUGxmoNiNPsixn9J/Y/N0BEj7KTS + iQwznmHGSCToXS5CoZ1AYKGtbaCpKdHT07OxsYFmZ86cGRERAU+AbKktAC5HlnvYhIPLvXoBiiHvCw46 + lJQC209d9Jc8Gzed4Pl+QgVOHRyzJSXOaRyukpKS4jvNt+Viy4lPT5x4TOr44+NP65PjY3rGCNoEmrWa + I7aPGF44/M28N4fmDh26dejgzMGDUge9kfDG67Gv/3HNH/8Y9cc/ruhbK//42qTX/t8b/08ikejq6uKg + sbKycnR09PLyQqtAKIJ9rVu3Lj09HUdVfn5+cXExfd0N9EsfkKJn8zmyu3bt4l63ALjt7e1QCY5OtH0N + KmQsBa1/e9HfpoKbSyY0d9Mxh/rJw4cPOQdXJw7V2LrYFrYXnvz0JIqw5oqFvvjaYvFhsWinSFgjFFYI + hWVCYalQuF0oKBYICgSCbIF2irZ2orb2Rm3teFJa8VpPK05ruN1wPz+/xYsXg+nSpUvRjWFT0dHR4JuQ + kIBElJGRgS5dUFBQVlZWWVkJxBAvlS3VLJ8sFn1dCIWLPo/jEkcn2r4G5aKA9PMt+mv5uLEobggcuFUE + DuKcpXDEsZV6hnrJFcmnPj916jNSJz87SYqFjtp6Z6vxcWPxHrGoXiSqEonKRU9BFwkEuQLtNG0CerOC + skqNnDoSngCfhTUB8YoVK1atWoU0tn79+o0bN4JyZmYmKMMoIGTc5RQx+AIuyGJRzdKH/ShZLO5FIbBB + HJc4OtH2CWgFm19gqeDmBE79hAocxCFwODhnKZQ4vBsIojOjT39xmtTnpwluWiz0A58ccOlxkXRKxE1i + cbVYXCkGaFGZSFQqEpYIhflC8jTRVIEgSSDYJBAkqJZ2pPZwk+Gw3cjISKgYiNesWRMbGxsfH5+YmIjY + w72iFEKGEUPC0C+FC7JoHmghVLMIqZQsfcAPUYrCxUGJYQ0dCGOEhgLJL7k43HyBc37COTi1FI74hg0b + lsQtOfPlGVJfkFIQZ6GjplycIj0kZXYxkjqJpEoirhCLy8XiMrFou0hUJBJtFQnThMJkoXCzULhRKNgo + UJQStOYYTfqSGRgF1tq1a/EXN23ahJYAU+aEDC+Giili8IVsqRugeaCFUM1yZOlrbRClEKhggPS1ILdv + 38Yx+muA5hZHXEXg6sShppDIkIP3Dire++DLHgVxJfSIGxE6J3Ske6RMA8NUM0wVI6mQSMolkjKJuEQs + zhOLMkSiNJEoSSTcJCS1sU9pz9MewYyAXUDCsGPkXzgygtqWLVtycnLQ9yBkeAXaHfobfcya8oVmKVb0 + D4oVmkVHAVnIlpKF71G4sEH0HnQgHKO/Kmi6ONx8gfOJYycDwwL3vb2v96teVM9X5E0mSCmhp72fZnrK + VNYukzZJpXVSCpqpIAXQkkKJJEciTheLUxUvURFt6lPCdUItB61Zs2bBJcAXKgbi1NRU3Lvbtm1DtKio + qIBXwIvR3IAYngvxgi91A4qVEyxGMJBFVAXZu3fvgix8j8KFDSLO4ujEMfobgOYWRxy4OeLYw0lzJiHM + PX3bFBY3B732Ya3DWQd5l1y2UyarZ5/BXyWVVpJiyhimhGG2MeTFKWkSSbIEoElt7lPak7R9fX0BF+0O + fKFiIKZegWiBaAw7RvgFYpgvJHzu3DnwBVy0Dc4KkEopVqpZzGKULLo6yFK4SFbo9uj5OEZ/S9Dc4ojD + DQOCAnac2XH267Oop6yVdfiLw6MvjNY5rCNvlcsaZbJamaxGJqsiJa2QSkul0gIpk8Uw6YwkVSJJ7KdE + i0Ra+lpwDBgxQgWMgqY3HEYIyPAK2DEiGowCKgZiGC7EC77QLOBSrGCKVEqxUs1iFuPIotMALjwQC90e + PR+u+EKApgs68p/hX3eqjlJWKQp68pXJusd0dfbqyJvk8nq5vFYur5HLq+WEdZlMWiRlchgmk2G2MEwK + wySplmSDROAiCAsLA18sGEVhYWFJSQm8ggoZHQ9ChhfDKKiK4Qzgy7cCjikWWjfFyieLTkPhwgaRr+CH + cMUXBTRGLGi57nQd93ZWiuKxnnN9ju5JXZ12HXlLH8rkXfEqZLISmWybTJollaaTt/WQJvcpJpmAFk0S + TZkyBaENiyKGV0DICMjUkREqIGT0OhgxjAIWAcOFeKkVcFhhBRzWgchi0d7Ddv1/vhCgsauTQyYTx1Ch + zKvFNxcbnDbQ7dAlb4y3Q/l+3uwbAZH3pt8ul+XLZNnsm6ekqVKmJVkoEegKEJDhxRQxFTJNb5g7YBdw + ZMQJCBlGjMwAFUO/1BAAF0wBlDLlY+2XLBYaD9vyyez924PGbs9YNKPlUosKWX6tvLVy1JlRul0s5Ubl + m3lzlMvk5I2ABng7XlrSNVKhvXD16tVAXFpaCsRIb2i8oIwxj6OMxIaUBsoQMvwXlKFfqlmKlQLFokzp + 4rByZLFo48Giu/lbgsYOoCOFrgxtu9mmQpZfMbdjyHt479clbyCmTrmcfWP6HJnira1SVRHTEvmK5s2b + B8T0lAWEDLtoYd9oE2MIAhzmDlBG30PTo08IgFFAxdAvRcwBpWsgrFiK3eu7fjPQaC+YFJYlLDv04JAK + WX6tu7NOlTJMg1Kukssr5ORd6bcS0+j3jelpSWZIBAIBcgV9yn1NTQ3SBVrfHvZdNkEZAx4cA5Q5LYMy + LBj+AFugiClWBUvlUuzMc6zfBjQaupGpUWxOrApWlQJl8x5z3QPPpLyNpQzTGIAys4gRGgkRlrkzyJQy + HAMx7hD79m2cL4My1TIoQ8iwCCCmfBWb/lPXbwAau+fk5ZRem66CVaUUjgHKu3V0mpSU6ZsNUsol7Fvw + PtuaV0lFdqK1a9fS147Qk5yUMgbr7u7uEydOICwjYyDGISMjwKH1US1TI4aQ/33KWL8qaKgDvWhC8ISy + g2UqWFUK3e+pY/SlTN5sEJS3y+V5P9QAE6Rib/HixYs5yrT77WLfIe/AgQM0L1++fBnDNMIyzRjofmh9 + nCn/LHLG+vVAo8msX79+YczCfdf3qWBVqfCb4SRjqPgyR5kNc+TNdyll9fd2VJYkgLwrPaUM06irq0Na + R16m5+GoNXMNED0DYRkxDi365zUNun4l0Bi3bJxsEgoTMN2pYFWpkOshhqcNSZL79ygzMxiBRIDZmm/N + iBlogAhzsGYMJufPn7/W3xsK/rymQdcvDhpbj2EX88j2/dtVmKrUkS+PkLf5P6WnmEqeTbnf9ylVFhPK + CA0UDRCLhjm+NR8/fhzj3xX2PXbv3r2L2Q+D3y9kGnT9sqBxeCJdrExe2XWnSwWrStU/qve55KN3XE+3 + vS9lNmP0T3mAyMyEMyIzUXx8PL8BqlgzUjOSDx2ykZphGpitfyHToEtje1HiL1HpqdHTpoz1muCRVpdy + 9OPDz65NN+ItjpkJ27UEDVra1ZraZZrapZraJZraxaS0Ckdq5Y3U2jpSa8tIzaQRmptHaG4coblhhGZc + PzViwZvDjAf7+DiHzJ4UOmfS3NAp8+dODVswfdHCGUvDgyIj5kStmBezeuG6teEJG5YlblyRlrw6c8ua + 7MzYbTlx+dviC/MSivI3FhdsKincrLJH/2b9IopubW01tzFflbrqB4WMQsCw6LHQPairu0dXp1ntPAZN + cs+nZRLmnETLly/ntMw1QEyA1JqRmmHNSM3UmmmeoxMgnU24wUSxMz/T6qPo0uIkWmUlycpKKd+OSkVV + lKLSKsrSKsu2oKrK0xVVkVFNKrOmMjM+LsLX121SyIRtu7cee3REtT7pU10POyac9ZccFglbBcJ6bWG1 + trBcW1imLSzVFm4nJSjWEhRoCXK1BBla2ila2kla2pu1tBO0tOO1BLQSnpZ2pOYI++Hj/EZHrVy8Kip8 + 9aqlMdERsWsjN8RFbUxYk5y4Lj0tPic7qSA/vbQkp7oyv2HH9p3NFXt313a0NR7o2nmoe/eRw3uPH207 + cbzz1InOM6f2nzl1oOf0wZ4zB3vPdPf2HDrbe/gc6uyR82ePXjh37ML5YxfPH7944cSliycvXzx1+dKp + K5dPX7185uqVnmtXet662vvWtbPXr527/ta5t6+ff/v6hZ9N0Qj8qampPpN8UqpSznxxRkW26lX0QZHX + Ra9+TFlFy5j9uKlk4O4nXScVe4kXLFjAhTluAkTM4Bpgb28vl5r7teafN2nw18+g6KyM9cFBE8xsTZYn + Ltt5pVlVxfxSannRlYVGRw2EbdrCJm1BjbagUilkTstFWoJ8LcFWLe10Te0UTYWW458WX9HaqzRHuAz3 + 9naLWrEoagXkvCR69bK1ayLi1q2M3xCduGltWmpcZsbmvG0pxYWZFWW5dTVFTQ2lu3dV79tT19XRdHD/ + zsOcnI91nDzRefpk14ul6AcPHhQVFVnaWy7fvLz5QrOKZvut5k+aJ16ZqHdajyRlzNZqpkwCBrRcxp6T + o2eLBp79UNL1UvFocUhISEVFBadlGubQKlRiBp1N+Cc0uNNGv5A1c+snKjotOXrWzABDU/15q0PLDm1X + Ve4AFXktwuy4iahDIGzWFtRqCSq1BGXaglJtAatiUiXagkItQZ6WIEtLO5XVcqKm9iZNvpZpUUVrRxEt + e3k6r4gMW7liMdyZWPOaZetiYc2rNiXEpCSvz0jfmJuTVJifXrY9uwrWXF/SQqy5pn3fjv2dzd0HdkHO + Rw/vPXYMcm6HO5862fVCKPrcuXNJSUn2rvYrklY09jaqCHagQkyGkPVP62OwVqSLhgFMGQGDnsVHDXzm + EyWNIb4cGhpKtYzFaZlGZvpMAXoKlB8zfunZpN/1vIrOz01YtmS2l6ej02iHFSnL63trjz06rCxV5arU + /MtziSO3s46sELKWoFRLsF1LAAmjqCkjYGzVEqQjYMCUNbU3a2pvhJZpqSpae5nmCLs3fXzcVywPo3Je + HbVkTfTStTHLYc2bEDOSYrekxudkJeZtS91enFlZvq2+trCpoax1J7HmzvaGg/tbug/sPHKIyBnufPxY + 28njHb+lopE6MzMz9Q31Zyyakbkj8+hHR1XU+ozacm8LiRYn+zpyXyH3MeVcXsAYICyjmOUM8nJ4eDg/ + Y/DHv66uLvrQFDb+6tWrdM7+iH2JHz9m/ArWzK0BFb0pYTmGKycHS0cv+yXxi0oOFh19dJhfz1Z04Xv5 + vj1jmENi4R5tYSOihZaggidkomVS2lxSVjVllXqqZa25I4ebDvP391kesRByZmPG4jWrl8TGLF+/bkVC + /OrEzYgZG7IyN27bipiRUV62tbamAKl5V0vFntaajrYGNmm0HDrYCjkfO7L32JF9cOcTx9t/VUVfvHgR + QQLG5+ztHL4uvGBfwcnHJ1V0+uza/Xj37OuzySMjh3R125QZmUYLdSGXk6SsOLOMqe+ZpoxiQsl5jOjo + aBUtc77MaZmezoeWucj8JftyVf6jU7+Olukiik5NXrU0PMh/vKe5maGDh+3cVSEZDVs6brcpzkX0FTJX + 6opu+aAp+EIQ7JjkihZtQb2WoEpLUM53ZKWQizS1CzW1t2lpZ/cV8lNTVimiZc2JI95khs4InLA8YkHk + 8oWw5qiVi6JXLVkbs4xoecOqpM0xqcnrMzM25m5NLirYUsZOgDvqiluaylt3VbfthTVjCGxGcD50cNfR + w3tQx4/uY+PzL6/owMBASwfLwIWBcXlxNSdqfvB8cb+179N9C28stDlro3eUPcnZytoxP1dwQuY9EKU4 + fUFNeeCkjJImSCUBEoFEsGXLFv55DDr70byMjDGQltUfaf01tUyXxrbdW9tu7eVOpPVTalqmReVc+n7J + 1HOTjY4YCDu0hTu1iIqr+6pYRcgFELKmdramFl/ICSr67VNaSzVHOL3p4my3aGEwq+UFKyPDVhEth69d + s2x9LLQclbiJajlhKyJzQVppSXZVxbZ6MgGWwZqVqZnIGUnjcDfnzsgbv5aiVbT5/JV9P3vylcnkkT14 + cfsPqLiPIz+3kFHMIkZkJ+Ie96Narq+vb2xspA+X0Nnv6NGjyMtcxlDRMndmjjub8SvLGUtDVb/q1VfI + ux60hF9eZH/SVtQtEOzREjRqCWo1BVWaRMWchHkqJkKGHUPIuZraWRDySK3kkVqJmlo/JGTUSJiybOjk + Sb4RS+dFLJun0HLUoujVS9auiVgfG0m0vDEmNUWp5fy07cVZVRW5dTWFjQ3bdzaV724l1tzV0bC/E0lD + IWcU3PnFVXTG/YxpV6dZ9lrqHSO5mAx4LcpE0a+KqR1XKjMyfQIGosVzCJlMfb5igeCpKfPDMj2/3NHR + 0d3dTc9jICzRZ35yeZlmjBdBy3T9sKIzb6VPPz/V/Jip8KA2kXCTlnatpnY1JKwpKNUUbGerBNVXxTRX + 5Glq52hqZ2gSFSdByCO1No3UShiptUETpY1SUzFKc/aI4ebDvD2dwxeHRCydq9DyioVEy4qMEZkQv4r4 + csq6zPQE9lRGamkJtLy1trqgkZxoLt+9q6ptT11H2w7I+UAXDc4kbMCd2WnwxVD0ia9OZN3PQhx2OudE + zrR181xYXcJ9VfzUjpErCthnxVE7xrD3zIyMIuliikSoL4yNjeWEzDfl3bt304BBH8bu7e2l5+ToeQz6 + /FrMfioZ47fVMl19FF30XsGSK4u9T3sYHtEXHlDqt05Tu0pTu0L5UN529tE8ImG2ipU3IORi1o7zWTvO + 5Ox4pNbmkVoboWJ+9aNozXkjhtu+6exsGxoyfemSkGVLQpcTLc9fuSJs9crFa6Ix+0VsWL9iY/yqpMS1 + W1LXZ2Vg9ksszN9Suj2rkvgytIzIXAYt79tT276vrpPIGUmjqfsAOa1xuHsXzRu/jaKLPyyOuhWF/OBw + zoE8AfmwLvHffexEN5B+n6Hi7XJ5ofI8Mp30YMcDn7WgRYQ8TSI0EkZFRfHTBZeUMfXtU14IEabMBYyb + N2/S54o/Yq+5RZ9iq56Xf1st06UhPKAl2KslQARuUIq3nCdepX77FPvgNNEybhSNVHjxVtaLVVQcryJk + rp4qWjNkxHCbYY4O1rNnTVkSPgdahi8vj5i3MnIBO/iFx6xZuj52+Ya4lZs3Ricnrd2SFpeduSkvl539 + tmdWlSu03NxY2rqTROa2vbWw5s72HQc6m9g5sJm682+s6H6Uqy5eWnwJ8xMFjcbUi59bxShEC8x7Qj3h + Kvad9tSFjHRBH/FDUj7CvgbtLHshxOvXr8OU7927x4Xlb/pe3uU3mf2evTQGlC2/WAkrisSJkdr5I7Vz + R2pnk+daEAmjIGGaKAZUMa/iNEdOGf7mqKFurvZzQ6YTIYfPYU157gqYciQJGGtWh8euXRbHBoykzWtS + kxEw4rdmb87fllxcmF62neTl+tqCxnr4cunuXdBy9b499IQGGQJRB4mc4c6KvPFbK1pFtvwaSMKIE5wR + c4nih6IxVxj2xO7igICAhIQElWihLuTDhw+fUF43lbsQIkz54+e4stkLtTRUxYvi65c+UahgpFY++1yh + rJFaaSO0ktn6YSNWLc2wEcPdhw3TGuLn67F4UXD44tnQ8jKY8rK5kcvmrVi+YNXKsOjVi2Njlq6LXR4P + U94UnZK4Np2YcgIbMDD4pVeUZVdXbSNaJhmjtJWcZa5ktQxrJnKmwZlk5xdU0er6RVXI5aVkriOnjDkX + 5iT8HEZMS7qKtWNDYVhYWGFhIWfHdNhDRqbRAvOeupBpurijvG7qs035BdQyXRp99FukqRAvfa5b5kjN + LSM0k0eQZ7wljtDaPEJr0withBFa8SO04kaoqHWg0lw2YsTYN4fpDHFxsZ01a+LiMAg5eMni2UuXzIlg + kzJMOWrlwuhVi9ZGL1m3NiI+bsXmjUjKa7akrsvM2LA1exNrymmlJGBg8MvbUVfQ1FCysxkZA+NfJay5 + bW8NtNzRVt/ZXs+e1iDZ+cVTtIp4ESHgv/SxO06/NEj80FynUkTFEyVCE2FwcHBaWhpVMT1lQe2YnrWg + wx4y8sGDB2m0UBcyPX3xed/rpr7gpqyyNLRyR2ohPGSM1ExjlcuKlzxjkz5pM2GEZrziiZpExfxSEy9X + IxcMH+41bJh0iJOjdeD08YsWBi0OmxW+KHgphBwesmwpmy4i56+CkFcvXrtmybpYCDlyU0JU8uaYtJTY + zPS4nOyNeblJRQUppcXp5WVZNZVba2vyGuoKqZZ3tZTDl6k1t+/FEFgLLbPuTAz6BVW0QrkoKJczX4j3 + uf2XX0wYIx4tFuoI586dm5mZ2a+KW1paWvu+dwMd9mhGfuuttxAtBhIy0oXKo9cvvpbp0iCy5ZSrFG+/ + 9QxFa64YMWLim8MshhgZ6Xp7Os2ZNTls4UxOyHDkZXDkpaErls9duWLBqqiFayDkmKVxEPKGFZsSWEdO + WZuRFrc1a+O23M2F+SklRWnlMOWKnJoqhOX8xvqi5saSnU3QchkiM9UykfO+2o59cGeEjRdf0T9JuVwx + 4YxkPDHiiRMnxsTEcBKmAx6XKODFnIq72HcVOHr0KLXjCxcu0Es10OsI0IxMo4W6kF/8dDHQ0lCR7TOK + L+eRi4cPHzdsmNmQIUMGubrYTp82buG8GWHzZ4QtCFoUFhS+aBaixdLw2cuWzomMmLsyct6qFQtXRy1a + uyZ83dqlG9ZHJGwg0SIlMXpLKufImwvykkuKtpRtz6gsz66u3FoPU64vbNpBtbydaHknsea9u2lqrkG9 + VIpWE+kzCkGCmcGIXcRCGbmObFxcHH+0oxLmjBi5mD6m19HRQb2YqvjMmTPnz5+/fPky344//PBD+iJ3 + 7joCNFq87ELm1nMpeuSCN4l+LYYM1RxsbWXiO8ZtTvCkBfMCF8wPXDg/kNhx2EyoeGk4UXHEspDIiNAV + kfOiVixYHRUWE70oNmbJhnVsQE6IStq8OjU5Jj11XVbGhtychLxczHsQclrZ9i0VpVnVFTl1Ndsa6vIb + dxRAyy1NVMul0PLuXeV7iZyr9u1BvUKKlsZKmbmMZJxEZCUSCAT0OshF7DU5IV6qXwQJzoU5Ce9TXhmO + Xrns+PHjSBS9vb3Ui69fv05VfO/evQ8++IDaMc0V9CE+DHvqGfnlFTK3+ih6ZMTwETOHDfceCvMdqjXY + 2FjPxdlmQoD3vNCp8+dOWzBv2oL50xcuCFyklPCSxUTFMOLlS6Fi1otXLohetTAmevG6tUviYpex6XhF + 0uZVKUmY9GKz0tfnZMXn5mws2JZYVJBcWgwhp1eWZVVX5tRWs6bMarm5Ab5cvLOpBFpuhZx3le8hSaPi + 5VY0YgMTSMIvUS4j+MHrIMN/aYrg9EvnOrhwd3c3lfAp9uJwMGLk4mvKd4N677334MXqKv4L+yYkfDt+ + lYTMLQ19XamVpbGHu92EAK+Q4Enz2BfmKcRLCvqdAf0uDpu5ZHHQEjZLREDCy0IQiqNWQMLzWQmTRLE+ + lk0U8cs3b1wJFacSFa/NSl+XnRnH2vHmovykksKU7cWp5SRaZLJCzq2vQVLOa6xHWC6ElluaiJZ3NpdA + y607kTQQnF8JRUOwfM1i0dhAlQvnpREY4kUKhnjhv9DvAfbKnNAvhjoECc6FOQlzRoxcjAGPXlyLRmNO + xfx0/EqqmL80FsyfBuWGLUAR8S5eSMQbvgjiZf13CfQ7m9Vv6MrIuatWzotetWDNKpolwuNil8SvXwYJ + w4gTN0WlJK1OS1mTnrY2M319dlZcbnZCfu6mwnzYcdL2otTSEuSKjKpyOHJ2bRUx5R2123bAlOvzmxqg + ZSJnquVdzUga2181RVO3hWZ3P991kCFeBOFz585R/V69ehVDHfT77rvvci788OFDhGJqxF+xb7iFXMwl + iv8cFfOXxtLwWcuWoIKXL5sdGYFBLmRlZGjUirmrqP+S8xJha9dAv4vj1i3ZsH5p/IaITfGRiRtXJpMs + sSotJXoLJLwlNjsDEt6wbWtC/raNBXmbiwqh4pRSYsdbKsvI62qrK7Ig5LrqrXU1udByQz3ryyRjFDY3 + FrWQUrjzq6loCBZuSzX7PNdBvnnzJiLE7du332evH0ktmAYJ7hJ8cGEqYRUj/k9TMX9prI5CbJi/ZvWC + mOiFsWvC1q1dtH6tUrxxyzbGR27eGJm4aUXy5qhU6DcZ+o3J2EKyRA5x4bhtOfF5ucjFmwrzEoupikuI + iivIq2vhyBk1lVk1ldl11TlIFztqiZZ31G1jtZzfhPGPuvN/gqJhtRd/zHWQIV5ECL5+YcFckFBx4f9k + CassjY0blm1KiNicsDxxY2TSJkxxMF9WvDDf1DXpqTGZ6WuzMmJzMtdtzVrPuvCG/NyEgm0bi/I3Fxcg + FydtL04pK0GlkdfVlqZXlqdXwZErM2urkC6IllFUyw11qDylO/+HKRpW+6Oug8z3X75+qYSh398l3O/S + SE+NzkiLztiyJnPLmqz0tdkZyA+xrHjhv8SCqX4L8jYVF0DCiSXkFYlJpcXkRbVlxI5TWTveAjumV+1Q + aLlaoeX6mq2o3xVN3v0Ni7otNEsnNypb2C6nXIQHFfFy/vu7fp9naeQS2cblbd2Ays+NL9iWUMBeV4gt + ouKSQhTiBH2BeErZ9hTWixVX7SBa5l2BhmSMKuTl3xWtpmi+YKlmVWSLpaJcLMXd9Pt67qVRmLcRRSXM + ipcU73XhimscoJ7nmkq/K3pARbMxQSFYLIVi2aW4L35fP8fS4CSscnUDZfV/BZrfFf2jFa0A/vv6hdfP + cJWw3xX9u6JfoPW7on9X9Ku1flf074p+tdbviv5d0a/S+r//+/8BPTxUq6Ub7iwAAAAASUVORK5CYII= + + + \ No newline at end of file diff --git a/DotNetEditor/App.config b/DotNetEditor/App.config new file mode 100644 index 0000000..0c012c7 --- /dev/null +++ b/DotNetEditor/App.config @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DotNetEditor/App.xaml b/DotNetEditor/App.xaml new file mode 100644 index 0000000..ea9f5cb --- /dev/null +++ b/DotNetEditor/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/DotNetEditor/App.xaml.cs b/DotNetEditor/App.xaml.cs new file mode 100644 index 0000000..37a1662 --- /dev/null +++ b/DotNetEditor/App.xaml.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace DotNetEditor +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + public const string AppName = ".NET Snippet Editor"; + } +} diff --git a/DotNetEditor/AppCommands.cs b/DotNetEditor/AppCommands.cs new file mode 100644 index 0000000..e246f0b --- /dev/null +++ b/DotNetEditor/AppCommands.cs @@ -0,0 +1,23 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace DotNetEditor +{ + public static class AppCommands + { + public static readonly RoutedUICommand Run = new RoutedUICommand( + "Run", "Run", typeof(MainWindow), + new InputGestureCollection{new KeyGesture(Key.F5)}); + + public static readonly RoutedUICommand About = new RoutedUICommand( + "About", "About", typeof(MainWindow)); + } +} diff --git a/DotNetEditor/AvalonUtils/AvalonRichTextBox.cs b/DotNetEditor/AvalonUtils/AvalonRichTextBox.cs new file mode 100644 index 0000000..599f0e1 --- /dev/null +++ b/DotNetEditor/AvalonUtils/AvalonRichTextBox.cs @@ -0,0 +1,169 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Rendering; +using System; +using System.Linq; +using System.Windows; +using System.Windows.Media; + +namespace DotNetEditor +{ + /// + /// Interaction logic for AvalonRichTextBox.xaml + /// + public class AvalonRichTextBox : ICSharpCode.AvalonEdit.TextEditor + { + private class TextFormat : TextSegment + { + public Color ForegroundColor = Brushes.LightGray.Color; + public Color BackgroundColor = Brushes.Black.Color; + public bool? IsBold; + public bool? IsItalic; + } + + private class RTBBackgroundRenderer : IBackgroundRenderer + { + private readonly TextSegmentCollection _formatData; + + public KnownLayer Layer { get; } = KnownLayer.Background; + + public RTBBackgroundRenderer(TextSegmentCollection formatData) + { + _formatData = formatData; + } + + public void Draw(TextView textView, DrawingContext drawingContext) + { + if (textView == null) + { + throw new ArgumentNullException(nameof(textView)); + } + if (drawingContext == null) + { + throw new ArgumentNullException(nameof(drawingContext)); + } + + if (_formatData == null || !textView.VisualLinesValid) + { + return; + } + + var visualLines = textView.VisualLines; + if (visualLines.Count == 0) + { + return; + } + + int viewStart = visualLines.First().FirstDocumentLine.Offset; + int viewEnd = visualLines.Last().LastDocumentLine.EndOffset; + + Size pixelSize = AvalonUtils.PixelSnappers.GetPixelSize(textView); + + foreach (var segment in + _formatData.FindOverlappingSegments(viewStart, viewEnd - viewStart)) + { + Brush brush = new SolidColorBrush(segment.BackgroundColor); + + foreach (Rect r in + BackgroundGeometryBuilder.GetRectsForSegment(textView, segment, false)) + { + // Skip rectangles with width less than two pixels. + // These rectangles shouldn't be there. + if (r.Width < 2) + { + continue; + } + drawingContext.DrawRectangle(brush, null, + AvalonUtils.PixelSnappers.AlignRectToWholePixel(r, pixelSize)); + } + } + } + } + + class RTBColorizer : DocumentColorizingTransformer + { + private readonly TextSegmentCollection _formatData; + + public RTBColorizer(TextSegmentCollection formatData) + { + _formatData = formatData; + } + + private static void FormatVisualLineElement(TextFormat seg, VisualLineElement element) + { + element.TextRunProperties.SetForegroundBrush( + new SolidColorBrush(seg.ForegroundColor)); + + if (!seg.IsBold.HasValue && !seg.IsItalic.HasValue) + { + return; + } + + Typeface tf = element.TextRunProperties.Typeface; + + FontStyle style = + seg.IsItalic.HasValue + ? (seg.IsItalic == true ? FontStyles.Italic : FontStyles.Normal) + : tf.Style; + + FontWeight weight = + seg.IsBold.HasValue + ? (seg.IsBold == true ? FontWeights.Bold : FontWeights.Regular) + : tf.Weight; + + element.TextRunProperties.SetTypeface( + new Typeface(tf.FontFamily, style, weight, tf.Stretch)); + } + + protected override void ColorizeLine(DocumentLine line) + { + TextSegment segment = new TextSegment(); + segment.StartOffset = line.Offset; + segment.EndOffset = line.EndOffset; + + var segments = _formatData.FindOverlappingSegments(segment); + foreach (var seg in segments) + { + base.ChangeLinePart(Math.Max(seg.StartOffset, line.Offset), + Math.Min(seg.EndOffset, line.EndOffset), + (element) => FormatVisualLineElement(seg, element)); + } + } + } + + private TextSegmentCollection formatInfo; + + public AvalonRichTextBox() + { + formatInfo = new TextSegmentCollection(Document); + TextArea.TextView.LineTransformers.Add(new RTBColorizer(formatInfo)); + TextArea.TextView.BackgroundRenderers.Add(new RTBBackgroundRenderer(formatInfo)); + } + + public void SetStyle(int startOffset, int endOffset, + Color foregroundColor, Color backgroundColor, bool? IsBold, bool? IsItalic) + { + TextFormat fmt = new TextFormat(); + fmt.StartOffset = startOffset; + fmt.EndOffset = endOffset; + fmt.ForegroundColor = foregroundColor; + fmt.BackgroundColor = backgroundColor; + fmt.IsBold = IsBold; + fmt.IsItalic = IsItalic; + + formatInfo.Add(fmt); + } + + + public void AppendTextWithStyle(string text, Color foregroundColor, Color backgroundColor, + bool? isBold, bool? isItalic) + { + int start = Text.Length; + AppendText(text); + SetStyle(start, Text.Length, foregroundColor, backgroundColor, isBold, isItalic); + } + } +} diff --git a/DotNetEditor/AvalonUtils/PixelSnapper.cs b/DotNetEditor/AvalonUtils/PixelSnapper.cs new file mode 100644 index 0000000..1bd13bf --- /dev/null +++ b/DotNetEditor/AvalonUtils/PixelSnapper.cs @@ -0,0 +1,27 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using System.Windows; +using System.Windows.Media; + +using PixelSnapHelpers = ICSharpCode.AvalonEdit.Utils.PixelSnapHelpers; + +namespace DotNetEditor.AvalonUtils { + + public static class PixelSnappers + { + // Wraps around ICSharpCode.AvalonEdit.Utils.PixelSnapHelpers + public static Size GetPixelSize(Visual visual) + { + return PixelSnapHelpers.GetPixelSize(visual); + } + + // Aligns the borders of rect to whole pixels. + public static Rect AlignRectToWholePixel(Rect rect, Size pixelSize) + { + return new Rect(PixelSnapHelpers.Round(rect.TopLeft, pixelSize), + PixelSnapHelpers.Round(rect.BottomRight, pixelSize)); + } + } +} \ No newline at end of file diff --git a/DotNetEditor/CodeRunner/CSCodeRunner.cs b/DotNetEditor/CodeRunner/CSCodeRunner.cs new file mode 100644 index 0000000..863df78 --- /dev/null +++ b/DotNetEditor/CodeRunner/CSCodeRunner.cs @@ -0,0 +1,90 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace DotNetEditor.CodeRunner +{ + class CSCodeRunner : CodeRunnerBase + { + public CSCodeRunner(string code, string inputData, AvalonRichTextBox outputArea) + : base(code, inputData, outputArea) + { + } + + protected override Compilation GetCompilation() + { + var parseOptions = new CSharpParseOptions( + preprocessorSymbols: new[] { "DEBUG", "TRACE" }); + + SyntaxTree tree = GetSyntaxTree(parseOptions); + + SortedSet uniqueImports = new SortedSet(AssemblyImports); + uniqueImports.Add("mscorlib.dll"); + uniqueImports.Add("Microsoft.CSharp.dll"); + + string dllPath = GetReferenceAssembliesPath(); + IEnumerable references = + uniqueImports.Select(import => MetadataReference.CreateFromFile( + System.IO.Path.Combine(dllPath, import))); + + var options = new CSharpCompilationOptions(OutputKind.ConsoleApplication); + + return CSharpCompilation.Create( + "DotNetEditor_Script", new[] { tree }, references, options); + } + + private SyntaxTree GetSyntaxTree(CSharpParseOptions options) + { + string[] templates = + { + // the raw program + "{0}", + // the program put inside a class + "{1} class Program {{ {0} }}", + // the program put inside Main function + "{1} class Program {{ static void Main(string[] args) {{ {0} }} }}" + }; + + SyntaxTree tree = null; + int errorCount = int.MaxValue; + + // Select the template with the least number of parsing errors. For ties, select the + // first template that has the least number of errors. + foreach (string template in templates) + { + string parsedCode = String.Format(template, Code, GetUsings(NSImports)); + SyntaxTree newTree = CSharpSyntaxTree.ParseText(parsedCode, options); + int newErrorCount = newTree.GetDiagnostics().Count(); + if (newErrorCount < errorCount) + { + errorCount = newErrorCount; + tree = newTree; + if (errorCount == 0) + { + break; + } + } + } + + return tree; + } + + private string GetUsings(string[] usings) + { + System.Text.StringBuilder str = new System.Text.StringBuilder(); + foreach (string s in usings) + { + str.Append("using "); + str.Append(s); + str.Append("; "); + } + return str.ToString(); + } + } +} diff --git a/DotNetEditor/CodeRunner/CodeRunnerBase.cs b/DotNetEditor/CodeRunner/CodeRunnerBase.cs new file mode 100644 index 0000000..6db8796 --- /dev/null +++ b/DotNetEditor/CodeRunner/CodeRunnerBase.cs @@ -0,0 +1,237 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using Microsoft.CodeAnalysis; +using System; +using System.CodeDom; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Brushes = System.Windows.Media.Brushes; +using Color = System.Windows.Media.Color; + +namespace DotNetEditor.CodeRunner +{ + abstract class CodeRunnerBase + { + public static readonly string[] DefaultNSImports = { + "Microsoft.VisualBasic", + "System", + "System.Diagnostics", + "System.Drawing", + "System.Windows.Forms" + }; + + public static readonly string[] DefaultAssemblyImports = { + "System.dll", + "System.Drawing.dll", + "System.Windows.Forms.dll" + }; + + public string Code { get; set; } + public string InputData { get; set; } + public string[] NSImports { get; set; } + public string[] AssemblyImports { get; set; } + public bool ColoredOutput { get; set; } = true; + public bool DumpInput { get; set; } = true; + public ConsoleColorScheme ColorScheme { get; set; } = ConsoleColorScheme.DefaultColorScheme; + + private AvalonRichTextBox _outputArea; + + // Default text colors + readonly Color defaultTextBgColor = Brushes.Black.Color; + readonly Color defaultTextFgColor = Brushes.LightGray.Color; + readonly Color defaultTitleBgColor = Brushes.LightGray.Color; + readonly Color defaultTitleFgColor = Brushes.Black.Color; + + // TODO: constants to be abstracted + readonly Color errorFgColor = Brushes.Red.Color; + + protected CodeRunnerBase(string code, string inputData, AvalonRichTextBox outputArea) + { + Code = code; + InputData = inputData; + NSImports = DefaultNSImports; + AssemblyImports = DefaultAssemblyImports; + _outputArea = outputArea; + } + + public void SetOutputArea(AvalonRichTextBox outputArea) + { + _outputArea = outputArea; + } + + void addStyledText(string s, Color foregroundColor, Color backgroundColor, + bool? isBold, bool? isItalic) + { + int pos = _outputArea.Text.Length; + _outputArea.AppendTextWithStyle(s, foregroundColor, backgroundColor, isBold, isItalic); + } + + void addConsoleColoredText(string s, TextWriterWithConsoleColor.ColorInfo color) + { + addStyledText(s, ColorScheme.ConvertColor(color.Foreground), + ColorScheme.ConvertColor(color.Background), false, false); + } + + void addResult(string mainText, string title, + Color? textFgColor = null, Color? textBgColor = null, + Color? titleFgColor = null, Color? titleBgColor = null) + { + if (_outputArea.Text.Length > 0) + { + _outputArea.AppendText("\n\n"); + } + + addStyledText(" --- " + title + " --- \n", + titleFgColor ?? defaultTitleFgColor, + titleBgColor ?? defaultTitleBgColor, + true, null); + + addStyledText(mainText, + textFgColor ?? defaultTextFgColor, + textBgColor ?? defaultTextBgColor, + null, null); + } + + void dumpConsoleBuffer(TextWriterWithConsoleColor.TextWriterWithConsoleColor buffer, + string title, Color? titleFgColor = null, Color? titleBgColor = null) + { + if (_outputArea.Text.Length > 0) + { + _outputArea.AppendText("\n\n"); + } + + addStyledText(" --- " + title + " --- \n", + titleFgColor ?? defaultTitleFgColor, + titleBgColor ?? defaultTitleBgColor, + true, null); + + buffer.ForEachPart(addConsoleColoredText); + } + + // Return: whether a the code runs successfully without error. + protected string GetReferenceAssembliesPath() + { + return @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1"; + } + + protected abstract Compilation GetCompilation(); + + private string DiagToString(Diagnostic diag) + { + return String.Format("({0}) : {1}", + diag.Location.GetMappedLineSpan().StartLinePosition, + diag.GetMessage()); + } + + public bool Run() + { + _outputArea.Clear(); + Compilation compilation = GetCompilation(); + + var stream = new System.IO.MemoryStream(); + var emitResult = compilation.Emit(stream); + + if (!emitResult.Success) + { + addResult(Environment.NewLine + + emitResult.Diagnostics + .Select(diag => DiagToString(diag)) + .Aggregate((current, next) => current + Environment.NewLine + Environment.NewLine + next), + "Compile error", errorFgColor); + + System.Diagnostics.Debug.WriteLine( + "Code being compiled with errors:\n" + + emitResult.Diagnostics[0].Location.SourceTree.GetText().ToString()); + + return false; + } + + Assembly compiledAssembly = Assembly.Load(stream.ToArray()); + MethodInfo methodToInvoke = compiledAssembly.EntryPoint; + + // Prepare console and debug + TextWriterWithConsoleColor.TextWriterWithConsoleColor consoleWriter; + + if (ColoredOutput) + { + consoleWriter = new TextWriterWithConsoleColor.StringWriterColor(); + } + else + { + consoleWriter = new TextWriterWithConsoleColor.StringWriterBW(); + } + + var debugWriter = new System.IO.StringWriter(); + var debugListener = new System.Diagnostics.TextWriterTraceListener(debugWriter); + + Console.SetOut(consoleWriter); + if (DumpInput) + { + Console.SetIn(new DumpReader(new System.IO.StringReader(InputData), consoleWriter)); + } + else + { + Console.SetIn(new System.IO.StringReader(InputData)); + } + + System.Diagnostics.Debug.Listeners.Add(debugListener); + + // Run code + object result = null; + bool hasError = false; + Exception exStore = null; + try + { + if (methodToInvoke.GetParameters().Any()) + { + result = methodToInvoke.Invoke(null, new object[] { new string[] { } }); + } + else + { + result = methodToInvoke.Invoke(null, null); + } + } + catch (Exception ex) + { + hasError = true; + exStore = ex; + } + finally + { + System.Diagnostics.Debug.Listeners.Remove(debugListener); + } + + // Reset console and debug + System.Diagnostics.Debug.Flush(); + Console.ResetColor(); + + // Output results + _outputArea.Clear(); + + dumpConsoleBuffer(consoleWriter, "Console output"); + + var s = debugWriter.ToString(); + if (s != "") + { + addResult(debugWriter.ToString(), "Debug/trace output"); + } + + if (result != null) + { + addResult(result.ToString(), "Return value"); + } + + if (hasError) + { + addResult(exStore.InnerException.Message, + "Runtime error");//, errorColor) + } + + return !hasError; + } + } +} diff --git a/DotNetEditor/CodeRunner/VBCodeRunner.cs b/DotNetEditor/CodeRunner/VBCodeRunner.cs new file mode 100644 index 0000000..f6de5a9 --- /dev/null +++ b/DotNetEditor/CodeRunner/VBCodeRunner.cs @@ -0,0 +1,94 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace DotNetEditor.CodeRunner +{ + class VBCodeRunner : CodeRunnerBase + { + public VBCodeRunner(string code, string inputData, AvalonRichTextBox outputArea) + : base(code, inputData, outputArea) + { + } + + protected override Compilation GetCompilation() + { + var preprocessorSymbols = + new Dictionary { { "DEBUG", true}, { "TRACE", true} }; + + var parseOptions = new VisualBasicParseOptions( + preprocessorSymbols: preprocessorSymbols); + + SyntaxTree tree = GetSyntaxTree(parseOptions); + + SortedSet uniqueImports = new SortedSet(AssemblyImports); + uniqueImports.Add("mscorlib.dll"); + uniqueImports.Add("Microsoft.VisualBasic.dll"); + + string dllPath = GetReferenceAssembliesPath(); + IEnumerable references = + uniqueImports.Select(import => MetadataReference.CreateFromFile( + System.IO.Path.Combine(dllPath, import))); + + var compilationOptions = new VisualBasicCompilationOptions( + OutputKind.ConsoleApplication, + globalImports: GlobalImport.Parse(NSImports), + parseOptions: parseOptions); + + return VisualBasicCompilation.Create( + "DotNetEditor_Script", new[] { tree }, references, compilationOptions); + } + + private SyntaxTree GetSyntaxTree(VisualBasicParseOptions options) + { + SyntaxTree tree = VisualBasicSyntaxTree.ParseText(Code, options); + + if (IsInsideOfSubMain(tree)) + { + string parsedCode = String.Format( + "Module Module1\nSub Main\n{0}\nEnd Sub\nEnd Module", Code); + return VisualBasicSyntaxTree.ParseText(parsedCode, options); + } + else if (IsInsideOfClass(tree)) + { + string parsedCode = String.Format( + "Module Module1\n{0}\nEnd Module", Code); + return VisualBasicSyntaxTree.ParseText(parsedCode, options); + } + else + { + return tree; + } + } + + private bool IsInsideOfSubMain(SyntaxTree tree) + { + return tree.GetRoot().ChildNodes().All( + (node) => node is StatementSyntax && + !(node is ClassBlockSyntax) && + !(node is InterfaceBlockSyntax) && + !(node is MethodBlockSyntax) && + !(node is ModuleBlockSyntax) && + !(node is NamespaceBlockSyntax) + ); + } + + private bool IsInsideOfClass(SyntaxTree tree) + { + return tree.GetRoot().ChildNodes().All( + (node) => node is StatementSyntax && + !(node is ClassBlockSyntax) && + !(node is InterfaceBlockSyntax) && + !(node is ModuleBlockSyntax) && + !(node is NamespaceBlockSyntax) + ); + } + } +} diff --git a/DotNetEditor/ConsoleColorScheme.cs b/DotNetEditor/ConsoleColorScheme.cs new file mode 100644 index 0000000..5d10214 --- /dev/null +++ b/DotNetEditor/ConsoleColorScheme.cs @@ -0,0 +1,71 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using System; +using System.Windows.Media; + +namespace DotNetEditor +{ + class ConsoleColorScheme + { + private static readonly Color[] DefaultColors = { + Brushes.Black.Color, + Brushes.Navy.Color, + Brushes.Green.Color, + Brushes.Teal.Color, + Brushes.Maroon.Color, + Brushes.Purple.Color, + Brushes.Olive.Color, + Brushes.Silver.Color, + Brushes.Gray.Color, + Brushes.Blue.Color, + Brushes.Lime.Color, + Brushes.Cyan.Color, + Brushes.Red.Color, + Brushes.Magenta.Color, + Brushes.Yellow.Color, + Brushes.White.Color + }; + + [Serializable] + public class ColorCountException : Exception + { + public ColorCountException() + : base("The color scheme must have exactly 16 colors.") {} + + public ColorCountException(string message) + : base(message) {} + + public ColorCountException(string message, Exception inner) + : base(message, inner) {} + } + + private Color[] _colors; + public Color[] Colors { + get { return _colors; } + set + { + if (value.Length != 16) + { + throw new ColorCountException(); + } + + _colors = value; + } + } + + public ConsoleColorScheme(Color[] colors) + { + Colors = colors; + } + + public static readonly ConsoleColorScheme DefaultColorScheme = + new ConsoleColorScheme(DefaultColors); + + public Color ConvertColor(ConsoleColor color) + { + return Colors[Convert.ToInt32(color)]; + } + } +} diff --git a/DotNetEditor/ConsoleUtil.cs b/DotNetEditor/ConsoleUtil.cs new file mode 100644 index 0000000..a33f79c --- /dev/null +++ b/DotNetEditor/ConsoleUtil.cs @@ -0,0 +1,40 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using System; +using System.Runtime.InteropServices; + +namespace DotNetEditor +{ + static class ConsoleUtil + { + [DllImport("Kernel32.dll", EntryPoint = "AllocConsole", ExactSpelling = false, + CharSet = CharSet.Unicode, SetLastError = true)] + public extern static bool AllocConsole(); + + [DllImport("Kernel32.dll", EntryPoint = "GetConsoleWindow", ExactSpelling = false, + CharSet = CharSet.Unicode)] + public extern static IntPtr GetConsoleWindow(); + + [DllImport("user32.dll", EntryPoint = "ShowWindow", ExactSpelling = false, + CharSet = CharSet.Unicode)] + public extern static bool ShowWindow(IntPtr hWnd, int nCmdShow); + + public static bool HasConsoleWindow() + { + IntPtr handle = ConsoleUtil.GetConsoleWindow(); + return handle != IntPtr.Zero; + } + + public static void CreateHiddenConsoleWindowIfNotExists() + { + if (!HasConsoleWindow()) + { + AllocConsole(); + IntPtr handle = GetConsoleWindow(); + ShowWindow(handle, 0); + } + } + } +} diff --git a/DotNetEditor/Converters.cs b/DotNetEditor/Converters.cs new file mode 100644 index 0000000..17dba01 --- /dev/null +++ b/DotNetEditor/Converters.cs @@ -0,0 +1,56 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using System; +using System.Globalization; +using System.Windows.Data; +using System.Windows.Input; + +namespace DotNetEditor.Converters +{ + class InputGestureConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (targetType != typeof(string)) + { + throw new ArgumentException("Can only convert to string."); + } + + string s = ((KeyGesture) value).DisplayString; + if (String.IsNullOrEmpty(s)) + { + s = new KeyGestureConverter().ConvertToString(value); + } + return s; + } + + public object ConvertBack(object value, Type targetType, object parameter, + CultureInfo culture) + { + throw new NotSupportedException("Conversion is one-way."); + } + } + + class CommandConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + RoutedCommand cmd = (RoutedCommand)value; + RoutedUICommand uiCmd = cmd as RoutedUICommand; + string s = uiCmd != null ? uiCmd.Text : cmd.Name; + if (cmd.InputGestures.Count > 0) + { + s += " (" + new InputGestureConverter().Convert(cmd.InputGestures[0], + typeof(string), null, System.Globalization.CultureInfo.CurrentUICulture) + ")"; + } + return s; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotSupportedException("Conversion is one-way."); + } + } +} diff --git a/DotNetEditor/DotNetEditor.csproj b/DotNetEditor/DotNetEditor.csproj new file mode 100644 index 0000000..566334a --- /dev/null +++ b/DotNetEditor/DotNetEditor.csproj @@ -0,0 +1,316 @@ + + + + + Debug + AnyCPU + {E54077C3-703E-4A13-9D01-382B30E8AAEE} + WinExe + Properties + DotNetEditor + DotNetEditor + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + true + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + LocalIntranet + + + false + + + Properties\app.manifest + + + + ..\packages\AvalonEdit.5.0.3\lib\Net40\ICSharpCode.AvalonEdit.dll + True + + + ..\packages\Microsoft.CodeAnalysis.Common.2.1.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll + True + + + ..\packages\Microsoft.CodeAnalysis.CSharp.2.1.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll + True + + + ..\packages\Microsoft.CodeAnalysis.VisualBasic.2.1.0\lib\netstandard1.3\Microsoft.CodeAnalysis.VisualBasic.dll + True + + + + ..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll + True + + + ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + True + + + + ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll + True + + + + ..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll + True + + + ..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll + True + + + + ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll + True + + + ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll + True + + + ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll + True + + + + ..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll + True + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll + True + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + + + ..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll + True + + + ..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll + True + + + ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll + True + + + + + + + + + + 4.0 + + + ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll + True + + + ..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll + True + + + ..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll + True + + + ..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll + True + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Form + + + AboutBox.cs + + + App.xaml + Code + + + + + + + + + + + + + + + + + + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + AboutBox.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + Microsoft .NET Framework 4.6.1 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/DotNetEditor/DumpReader.cs b/DotNetEditor/DumpReader.cs new file mode 100644 index 0000000..d80b78a --- /dev/null +++ b/DotNetEditor/DumpReader.cs @@ -0,0 +1,74 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using System.IO; + +namespace DotNetEditor +{ + // DumpReader is a TextReader that dumps input into the output + + // Initialization: New DumpReader(reader, writer) + // reader: the TextReader to read from + // writer: the TextWriter that the read operations dump to + class DumpReader : TextReader + { + const ConsoleColor DumpForegroundColor = System.ConsoleColor.Black; + const ConsoleColor DumpBackgroundColor = System.ConsoleColor.Gray; + + TextReader _reader; + TextWriter _writer; + + public DumpReader(TextReader reader, TextWriter writer) + { + _reader = reader; + _writer = writer; + } + + public override int Peek() + { + return _reader.Peek(); + } + + public override int Read() + { + ConsoleColor fg = Console.ForegroundColor; + ConsoleColor bg = Console.BackgroundColor; + + Console.ForegroundColor = DumpForegroundColor; + Console.BackgroundColor = DumpBackgroundColor; + + int c = _reader.Read(); + if (c >= 0) + _writer.Write(Convert.ToChar(c)); + + Console.ForegroundColor = fg; + Console.BackgroundColor = bg; + + return c; + } + + public override string ReadLine() + { + ConsoleColor fg = Console.ForegroundColor; + ConsoleColor bg = Console.BackgroundColor; + + Console.ForegroundColor = DumpForegroundColor; + Console.BackgroundColor = DumpBackgroundColor; + + string s = _reader.ReadLine(); + _writer.WriteLine(s); + + Console.ForegroundColor = fg; + Console.BackgroundColor = bg; + + return s; + } + } +} diff --git a/DotNetEditor/FileUtils/FileHandler.cs b/DotNetEditor/FileUtils/FileHandler.cs new file mode 100644 index 0000000..ae3f5d6 --- /dev/null +++ b/DotNetEditor/FileUtils/FileHandler.cs @@ -0,0 +1,108 @@ +// Copyright 2017 Leung Wing-chung. All rights reserved. +// Use of this source code is governed by a GPLv3 license that can be found in +// the LICENSE file. + +using System; +using System.IO; + +namespace DotNetEditor.FileUtils +{ + // Handles file loading and saving actions. A load and a save action is required to instantiate + // the class. If file operation fails, the action should throw an System.IO.IOException for this + // class to catch. + class FileHandler + { + public delegate void FileOperation(Stream stream); + + System.Windows.Window _window; + FileOperation _load; + FileOperation _save; + + public struct FileOperationResult + { + public bool Success; + public string Filename; + + public FileOperationResult(bool success, string filename) + { + this.Success = success; + this.Filename = filename; + } + } + + // Return for cancelled or failed file operations. + private static readonly FileOperationResult _fileOperationNotSucceed = + new FileOperationResult(false, ""); + + public FileHandler(System.Windows.Window window, + FileOperation loadAction, FileOperation saveAction) + { + _window = window; + _load = loadAction; + _save = saveAction; + } + + public FileOperationResult Load(string filename) + { + try + { + _load(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)); + } + catch (IOException) + { + // TODO: display dialog for failure. + return _fileOperationNotSucceed; + } + catch (UnauthorizedAccessException) + { + return _fileOperationNotSucceed; + } + return new FileOperationResult(true, filename); + } + + public FileOperationResult LoadWithDialog(string filter) + { + var dialog = new Microsoft.Win32.OpenFileDialog(); + dialog.Filter = filter; + + if (dialog.ShowDialog(_window) == true) + { + return Load(dialog.FileName); + } + else + { + return _fileOperationNotSucceed; + } + } + + public FileOperationResult Save(string filename) + { + try + { + _save(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Write)); + } + catch (System.IO.IOException) + { + // TODO: display dialog for failure. + return _fileOperationNotSucceed; + } + return new FileOperationResult(true, filename); + } + + + public FileOperationResult SaveAs(string filter) + { + var dialog = new Microsoft.Win32.SaveFileDialog(); + dialog.Filter = filter; + + if (dialog.ShowDialog(_window) == true) + { + return Save(dialog.FileName); + } + else + { + return _fileOperationNotSucceed; + } + } + } +} diff --git a/DotNetEditor/FodyWeavers.xml b/DotNetEditor/FodyWeavers.xml new file mode 100644 index 0000000..c6e1b7c --- /dev/null +++ b/DotNetEditor/FodyWeavers.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/DotNetEditor/Images/about-30.png b/DotNetEditor/Images/about-30.png new file mode 100644 index 0000000000000000000000000000000000000000..a84f3875a80d2f17e1601639faf83c44daac50cf GIT binary patch literal 407 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX3?zBp#Z3TGjR8I(u0XnU(Vd{Wo&MF^gX(tp zS8wyJ+~!xgEwFAUP_TUQT_9PuwW`=ckqi zcdlmvKxL~uT^vIy;*t*VOGrxm_+KA*SgE-C?|pwZHMU0k|0?x~jFWnLa(H-n_VjpJ zFeq~~3o}pGV&+?L#YAj6w#m}X;^;qhQ{>V*j@2iTW<@ML0WTxHB3w{C3|$akKuelF{r5}E)+CcRYv literal 0 HcmV?d00001 diff --git a/DotNetEditor/Images/cs-30.png b/DotNetEditor/Images/cs-30.png new file mode 100644 index 0000000000000000000000000000000000000000..301eea843040e08cb29cdc830b0302eb1a631518 GIT binary patch literal 477 zcmV<30V4j1P)7nZ}~C+P1pj zy-$m0b*Y73oOZ9+w0*COtktr#+_<97tBbmpOo?NEv5ln8t7e^eZlr&3rGRFfcwm@w zoXMqMm~(KYfv?xIVw!etqkp5%tg_m-RFG@8-n*sGtXq|EV3>4Ljc9A3eXZ8BrqHcR zhhtWdYk{(ka;Jls#iCo3Z%~Y9s?x8BxRjd5qnO5`kiMI8r-G!=t)$SbRgY`A;JmQd zwOS0I6aWAK3v^OWQvgj%>Feq2?(FXEZ_-3=00022Nkl9B#b4!$5*K{WjvJ$pkuSUF@Cr& zP`dlzz<95!fc9kj9YTzS0RgUoh|2^*jk?mG46sWXeg-@3*Kr=K(#L->3}yfTvDhTH T^5?|X00000NkvXXu0mjfhqmZh literal 0 HcmV?d00001 diff --git a/DotNetEditor/Images/down_left-30.png b/DotNetEditor/Images/down_left-30.png new file mode 100644 index 0000000000000000000000000000000000000000..ff7d617507107e43c8d8c9fbad311ca994c5d609 GIT binary patch literal 470 zcmV;{0V)28P)>rWi$@yJ2_2`9{By-zb}DG1tFs31fH(Sh0jBJ6AwBWNl?ND&e; zVk!;E6uIr;7yl_c`UZ?nL}!Qq$yN=W6e9OEOYv9TFW%N9kCBb4B_ANd70H|jpr!m+R8vph*rdD+Fui3O>8 z`98qo5tY}qK5BKFONlc1{S%!sT@_UQ=Rctmj z|GM>f`xgGJRnayHc53WDLUUaYmUv%PIK69oJwx&)UA61Sov$Yq1%3U%|0;6!`lKZ( zDcut{)?eM`8M67u`}_6(Uq74wYrg4Io;yw@bBsP-`F`Nm+iGX$aKm8J75o4H`D~wk zXyO0X;&llTv&=t#dVk=S>~<&VZ=Wxy^xd!d^Ur==?)(3rj+Q^1HcfZmZ~X;n$ED}L zI(x|^^Md~UI*}Nccb5NO)JHsC_rG-YyoN%Dv)}X?L!)_LTx$Ke_RcHeknNwfIht>j kytQTx$=7B`%qe0BGF*T0ti8H6FkBftUHx3vIVCg!0EFhniU0rr literal 0 HcmV?d00001 diff --git a/DotNetEditor/Images/play-30.png b/DotNetEditor/Images/play-30.png new file mode 100644 index 0000000000000000000000000000000000000000..89b3b0e832b19675e7b3c4c0c7bd3630306b3e5f GIT binary patch literal 431 zcmV;g0Z{&lP)quf(}xl@0*N_Dksm(oyt zw@`bxNo}@ajK@-axlenxV2sC6eYj0~wP%ygP<*&id$(q0%y697Qhm2jeYa70u2+M; zQGK{jc(h-N#ZY{Xw@-VwOL(+SdbLh?xPq?ePI|S2ujq-j?uxeXini~B zujzlQJXab1y*gF38tr+_Dg9r2G zP4wwg`1EoG{q~s?^UyQ(>s0~vl@YWg4W=nb0001fNklEaloasKY*-FyuSJgtdaA2_=5zyH65Pi>la zXLD!s|6i@kWF^|BKRng>>{ySd(1aByO}<5_xZS*}yKL9VS7!I`CBA!+=Qrt0h330? z+1q}#ZGW)((6mB}psRvL-&UTSzDLaT&xc?AhZ*x(9=v6@X6!7KGhjE;Gu%ScGeNlBK1tTsSRW_gcmV^D2m zP;zl=b98C;gXv{ literal 0 HcmV?d00001 diff --git a/DotNetEditor/Images/vb-30.png b/DotNetEditor/Images/vb-30.png new file mode 100644 index 0000000000000000000000000000000000000000..b130ae6816992bc7ce806f9aa6a5e4fc0f97937c GIT binary patch literal 474 zcmV<00VV#4P)b(5 + + + + + + + + + + + + + + + + + + + + + + + +