diff --git a/BizHawk.Client.Common/lua/LuaDocumentation.cs b/BizHawk.Client.Common/lua/LuaDocumentation.cs index 4ca8396655..8fb60216f9 100644 --- a/BizHawk.Client.Common/lua/LuaDocumentation.cs +++ b/BizHawk.Client.Common/lua/LuaDocumentation.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Reflection; using System.Text; +using Newtonsoft.Json; namespace BizHawk.Client.Common { @@ -53,6 +54,93 @@ namespace BizHawk.Client.Common return sb.ToString(); } + + private class SublimeCompletions + { + public SublimeCompletions() + { + Scope = "source.lua"; + } + + [JsonProperty(PropertyName = "scope")] + public string Scope { get; set; } + + [JsonProperty(PropertyName = "completions")] + public List Completions = new List(); + + public class Completion + { + [JsonProperty(PropertyName = "trigger")] + public string Trigger { get; set; } + + [JsonProperty(PropertyName = "contents")] + public string Contents { get; set; } + } + } + + public string ToSublime2CompletionList() + { + var sc = new SublimeCompletions(); + + foreach (var f in this.OrderBy(lf => lf.Library).ThenBy(lf => lf.Name)) + { + var completion = new SublimeCompletions.Completion + { + Trigger = f.Library + "." + f.Name + }; + + var sb = new StringBuilder(); + + if (f.ParameterList.Any()) + { + sb + .Append(string.Format("{0}.{1}(", f.Library, f.Name)); + + var parameters = f.Method.GetParameters() + .ToList(); + + for (int i = 0; i < parameters.Count; i++) + { + sb + .Append("${") + .Append(i + 1) + .Append(":"); + + if (parameters[i].IsOptional) + { + sb.Append(string.Format("[{0}]", parameters[i].Name)); + } + else + { + sb.Append(parameters[i].Name); + } + + sb.Append("}"); + + if (i < parameters.Count - 1) + { + sb.Append(","); + } + } + + sb.Append(")"); + } + else + { + sb.Append(string.Format("{0}.{1}()", f.Library, f.Name)); + } + + completion.Contents = sb.ToString(); + sc.Completions.Add(completion); + } + + return JsonConvert.SerializeObject(sc); + } + + public string ToNotepadPlusPlusAutoComplete() + { + return string.Empty; // TODO + } } public class LibraryFunction @@ -73,6 +161,8 @@ namespace BizHawk.Client.Common public string Library { get; private set; } public string LibraryDescription { get; private set; } + public MethodInfo Method { get { return _method; } } + public string Name { get { return _luaAttributes.Name; } diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index edcae1c15b..eb508a35ef 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -829,6 +829,7 @@ + Form diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaAutocompleteInstaller.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaAutocompleteInstaller.cs new file mode 100644 index 0000000000..782f043cbc --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaAutocompleteInstaller.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Newtonsoft.Json; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public class LuaAutocompleteInstaller + { + #region API + + public enum TextEditors { Sublime2, NotePad } + + public bool IsInstalled(TextEditors editor) + { + switch(editor) + { + case TextEditors.Sublime2: + return IsSublimeInstalled(); + case TextEditors.NotePad: + return IsNotepadInstalled(); + } + + return false; + } + + public bool IsBizLuaRegistered(TextEditors editor) + { + switch (editor) + { + case TextEditors.Sublime2: + return IsBizLuaSublimeInstalled(); + case TextEditors.NotePad: + return IsBizLuaNotepadInstalled(); + } + + return false; + } + + public void InstallBizLua(TextEditors editor) + { + switch(editor) + { + case TextEditors.Sublime2: + InstallBizLuaToSublime2(); + break; + case TextEditors.NotePad: + InstallBizLuaToNotepad(); + break; + } + } + + #endregion + + private string AppDataFolder + { + get { return Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); } + } + + private bool IsSublimeInstalled() + { + // The most likely location of the app, eventually we should consider looking through the registry or installed apps as a more robust way to detect it; + string exePath = @"C:\Program Files\Sublime Text 2\sublime_text.exe"; + + if (File.Exists(exePath)) + { + return true; + } + + return false; + } + + private bool IsNotepadInstalled() + { + // The most likely location of the app, eventually we should consider looking through the registry or installed apps as a more robust way to detect it; + string exePath = @"C:\Program Files (x86)\Notepad++\notepad++.exe"; + + if (File.Exists(exePath)) + { + return true; + } + + return false; + } + + private string SublimeLuaPath = @"Sublime Text 2\Packages\Lua"; + private string SublimeCompletionsFilename = "bizhawk.lua.sublime-completions"; + + private bool IsBizLuaSublimeInstalled() + { + var bizCompletions = Path.Combine(AppDataFolder, SublimeLuaPath, SublimeCompletionsFilename); + + if (File.Exists(bizCompletions)) + { + return true; + } + + return false; + } + + private string NotepadPath = "TODO"; + private string NotepadAutoCompleteFileName = "TODO"; + + private bool IsBizLuaNotepadInstalled() + { + var bizCompletions = Path.Combine(AppDataFolder, NotepadPath, NotepadAutoCompleteFileName); + + if (File.Exists(bizCompletions)) + { + return true; + } + + return false; + } + + private void InstallBizLuaToSublime2() + { + var bizCompletions = Path.Combine(AppDataFolder, SublimeLuaPath, SublimeCompletionsFilename); + + var text = GlobalWin.Tools.LuaConsole.LuaImp.Docs.ToSublime2CompletionList(); + File.WriteAllText(bizCompletions, text); + } + + private void InstallBizLuaToNotepad() + { + var bizAutocomplete = Path.Combine(AppDataFolder, NotepadPath, NotepadAutoCompleteFileName); + + var text = GlobalWin.Tools.LuaConsole.LuaImp.Docs.ToNotepadPlusPlusAutoComplete(); + + // TODO + //File.WriteAllText(bizCompletions, text); + } + } +} diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs index 26ef33c6c5..1ca7d770f7 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.Designer.cs @@ -72,6 +72,10 @@ this.DisableScriptsOnLoadMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ReturnAllIfNoneSelectedMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.RemoveRegisteredFunctionsOnToggleMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ReloadWhenScriptFileChangesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); + this.RegisterToTextEditorsSubMenu = new System.Windows.Forms.ToolStripMenuItem(); + this.RegisterSublimeText2MenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.HelpSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.FunctionsListMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.OnlineDocsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -103,7 +107,7 @@ this.PathName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.imageList1 = new System.Windows.Forms.ImageList(this.components); this.splitContainer1 = new System.Windows.Forms.SplitContainer(); - this.ReloadWhenScriptFileChangesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.RegisterNotePadMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ScriptListContextMenu.SuspendLayout(); this.menuStrip1.SuspendLayout(); this.ConsoleContextMenu.SuspendLayout(); @@ -458,7 +462,9 @@ this.DisableScriptsOnLoadMenuItem, this.ReturnAllIfNoneSelectedMenuItem, this.RemoveRegisteredFunctionsOnToggleMenuItem, - this.ReloadWhenScriptFileChangesMenuItem}); + this.ReloadWhenScriptFileChangesMenuItem, + this.toolStripSeparator4, + this.RegisterToTextEditorsSubMenu}); this.SettingsSubMenu.Name = "SettingsSubMenu"; this.SettingsSubMenu.Size = new System.Drawing.Size(61, 20); this.SettingsSubMenu.Text = "&Settings"; @@ -485,6 +491,36 @@ this.RemoveRegisteredFunctionsOnToggleMenuItem.Text = "Remove Registered Functions on Toggle"; this.RemoveRegisteredFunctionsOnToggleMenuItem.Click += new System.EventHandler(this.RemoveRegisteredFunctionsOnToggleMenuItem_Click); // + // ReloadWhenScriptFileChangesMenuItem + // + this.ReloadWhenScriptFileChangesMenuItem.Name = "ReloadWhenScriptFileChangesMenuItem"; + this.ReloadWhenScriptFileChangesMenuItem.Size = new System.Drawing.Size(286, 22); + this.ReloadWhenScriptFileChangesMenuItem.Text = "Reload When Script File Changes"; + this.ReloadWhenScriptFileChangesMenuItem.Click += new System.EventHandler(this.ReloadWhenScriptFileChangesMenuItem_Click); + // + // toolStripSeparator4 + // + this.toolStripSeparator4.Name = "toolStripSeparator4"; + this.toolStripSeparator4.Size = new System.Drawing.Size(283, 6); + // + // RegisterToTextEditorsSubMenu + // + this.RegisterToTextEditorsSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.RegisterSublimeText2MenuItem, + this.RegisterNotePadMenuItem}); + this.RegisterToTextEditorsSubMenu.Name = "RegisterToTextEditorsSubMenu"; + this.RegisterToTextEditorsSubMenu.Size = new System.Drawing.Size(286, 22); + this.RegisterToTextEditorsSubMenu.Text = "Register To Text Editors"; + this.RegisterToTextEditorsSubMenu.DropDownOpened += new System.EventHandler(this.RegisterToTextEditorsSubMenu_DropDownOpened); + // + // RegisterSublimeText2MenuItem + // + this.RegisterSublimeText2MenuItem.Image = global::BizHawk.Client.EmuHawk.Properties.Resources.GreenCheck; + this.RegisterSublimeText2MenuItem.Name = "RegisterSublimeText2MenuItem"; + this.RegisterSublimeText2MenuItem.Size = new System.Drawing.Size(152, 22); + this.RegisterSublimeText2MenuItem.Text = "&Sublime Text 2"; + this.RegisterSublimeText2MenuItem.Click += new System.EventHandler(this.RegisterSublimeText2MenuItem_Click); + // // HelpSubMenu // this.HelpSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -809,12 +845,12 @@ this.splitContainer1.SplitterDistance = 280; this.splitContainer1.TabIndex = 7; // - // ReloadWhenScriptFileChangesMenuItem + // RegisterNotePadMenuItem // - this.ReloadWhenScriptFileChangesMenuItem.Name = "ReloadWhenScriptFileChangesMenuItem"; - this.ReloadWhenScriptFileChangesMenuItem.Size = new System.Drawing.Size(286, 22); - this.ReloadWhenScriptFileChangesMenuItem.Text = "Reload When Script File Changes"; - this.ReloadWhenScriptFileChangesMenuItem.Click += new System.EventHandler(this.ReloadWhenScriptFileChangesMenuItem_Click); + this.RegisterNotePadMenuItem.Name = "RegisterNotePadMenuItem"; + this.RegisterNotePadMenuItem.Size = new System.Drawing.Size(152, 22); + this.RegisterNotePadMenuItem.Text = "Notepad++"; + this.RegisterNotePadMenuItem.Click += new System.EventHandler(this.RegisterNotePadMenuItem_Click); // // LuaConsole // @@ -929,5 +965,9 @@ private System.Windows.Forms.ToolStripMenuItem ReturnAllIfNoneSelectedMenuItem; private System.Windows.Forms.ToolStripMenuItem RemoveRegisteredFunctionsOnToggleMenuItem; private System.Windows.Forms.ToolStripMenuItem ReloadWhenScriptFileChangesMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; + private System.Windows.Forms.ToolStripMenuItem RegisterToTextEditorsSubMenu; + private System.Windows.Forms.ToolStripMenuItem RegisterSublimeText2MenuItem; + private System.Windows.Forms.ToolStripMenuItem RegisterNotePadMenuItem; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 8c03c0550d..509d505590 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -1060,6 +1060,68 @@ namespace BizHawk.Client.EmuHawk } } + private readonly LuaAutocompleteInstaller LuaAutoInstaller = new LuaAutocompleteInstaller(); + + private void RegisterToTextEditorsSubMenu_DropDownOpened(object sender, EventArgs e) + { + // Hide until this one is implemented + RegisterNotePadMenuItem.Visible = false; + + if (LuaAutoInstaller.IsInstalled(LuaAutocompleteInstaller.TextEditors.Sublime2)) + { + if (LuaAutoInstaller.IsBizLuaRegistered(LuaAutocompleteInstaller.TextEditors.Sublime2)) + { + RegisterSublimeText2MenuItem.Text = "Sublime Text 2 (installed)"; + RegisterSublimeText2MenuItem.Font = new Font(RegisterSublimeText2MenuItem.Font, FontStyle.Regular); + RegisterSublimeText2MenuItem.Image = Properties.Resources.GreenCheck; + } + else + { + RegisterSublimeText2MenuItem.Text = "Sublime Text 2 (detected)"; + RegisterSublimeText2MenuItem.Font = new Font(RegisterSublimeText2MenuItem.Font, FontStyle.Italic); + RegisterSublimeText2MenuItem.Image = null; + } + } + else + { + RegisterSublimeText2MenuItem.Text = "Sublime Text 2"; + RegisterSublimeText2MenuItem.Font = new Font(RegisterSublimeText2MenuItem.Font, FontStyle.Regular); + RegisterSublimeText2MenuItem.Image = null; + } + + if (LuaAutoInstaller.IsInstalled(LuaAutocompleteInstaller.TextEditors.NotePad)) + { + if (LuaAutoInstaller.IsBizLuaRegistered(LuaAutocompleteInstaller.TextEditors.NotePad)) + { + RegisterNotePadMenuItem.Text = "Notepad++ (installed)"; + RegisterNotePadMenuItem.Font = new Font(RegisterNotePadMenuItem.Font, FontStyle.Regular); + RegisterNotePadMenuItem.Image = Properties.Resources.GreenCheck; + } + else + { + RegisterNotePadMenuItem.Text = "Notepad++ (detected)"; + RegisterNotePadMenuItem.Font = new Font(RegisterNotePadMenuItem.Font, FontStyle.Italic); + RegisterNotePadMenuItem.Image = null; + } + } + else + { + RegisterNotePadMenuItem.Text = "Notepad++"; + RegisterNotePadMenuItem.Font = new Font(RegisterNotePadMenuItem.Font, FontStyle.Regular); + RegisterNotePadMenuItem.Image = null; + } + } + + private void RegisterSublimeText2MenuItem_Click(object sender, EventArgs e) + { + LuaAutoInstaller.InstallBizLua(LuaAutocompleteInstaller.TextEditors.Sublime2); + } + + private void RegisterNotePadMenuItem_Click(object sender, EventArgs e) + { + LuaAutoInstaller.InstallBizLua(LuaAutocompleteInstaller.TextEditors.NotePad); + } + #endregion #region Help diff --git a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.resx b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.resx index f68252bbdb..5627a63862 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.resx +++ b/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.resx @@ -153,70 +153,69 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACE - DgAAAk1TRnQBSQFMAgEBAwEAASgBAAEoAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA - AwABEAMAAQEBAAEgBgABECoAAXYBTwFUAeUBsgG0AdIB/wG7Ab4B1wH/AXgBUwFVAecwAAF2AVQBTwHl - AbIB0gG2Af8BuwHXAb4B/wF4AVUBUwHnMAABewFQAU8B5QHSAb4BsgH/AdcBxQG7Af8BfAJTAedoAAFu - AVkBewH1ATsBQgGXAf8BBwESAYcB/wEIARIBhwH/AQYBEQGHAf8BDQEXAYgB/wEQARoBiQH/AWkBXgGK - AfkgAAFuAXsBYAH1ATsBlwFHAf8BBwGHARYB/wEIAYcBFwH/AQYBhwEUAf8BDQGIARsB/wEQAYkBHgH/ - AWkBigFeAfkgAAGOAWkBWQH1AZcBXQE7Af8BhwE1AQcB/wGHATYBCAH/AYcBNAEGAf8BiAE5AQ0B/wGJ - ATwBEAH/AZQBaAFaAflcAAE2AT4BmAH/ATMBOwGYAf8BsAGyAcsB/wHaAdsB2gH/AtEB1QH/AcsBzAHS - Af8BxAHHAc4B/wFaAWABpQH/AUwBRQF6AfkBKwE0AY8B/xgAASgBkgE0Af8BMwGYAT8B/wGwAcsBswH/ - AdsC2gH/AdEB1QHSAf8BywHSAcsB/wHFAc4BxAH/AVoBpQFjAf8BTAF6AUYB+QErAY8BNgH/GAABkgFO - ASgB/wGYAVgBMwH/AcsBugGwAf8C2gHbAf8B1QHTAdEB/wHSAc0BywH/Ac4BxgHEAf8BpQF1AVoB/wGK - AVwBQAH5AY8BTgErAf9UAAJAAY0B/QF0AUsBTgHjAv4B/QH/Af4B/QH1Af8C9wHzAf8B7wLuAf8C7QHr - Af8B2QLbAf8B4wHkAeIB/wLAAcwB/wFxAVIBXQHtAUwBSQGDAfsQAAFAAY0BQAH9AXQBTgFLAeMB/wH+ - Av8B/gH1Af0B/wH3AfMB9gH/Au4B7wH/Ae0B6wHtAf8C2wHZAf8B5AHiAeMB/wHAAcwBwgH/AXEBXQFS - Ae0BTAGDAUsB+xAAAZMBTAE+Af0BdQFMAUsB4wH+A/8B9QH7Af4B/wHzAfUB9wH/Ae4B7wHuAf8B6wHs - Ae0B/wHbAdkB2gH/AuIB5AH/AcwBxQHAAf8BfAFTAVEB7QGMAVkBQwH7TAABcAFdAXMB8wF7AVcBYAHr - Bf8B/gH9F/8B/gH/AfAB7wHwAf8BzwHQAdYB/wFpAUoBWwHtAXABUwFmAe8IAAFwAXMBXQHzAXsBYAFZ - AesF/wH9Bv8B4wHwAeMB/wGcAc0BnAr/Af4C/wHvAvAB/wHPAdYBzwH/AWkBWwFMAe0BcAFmAVMB7wgA - AY0BYgFXAfMBgwFbAVYB6wT/Af0X/wH+A/8C4wHgAf8BzwHJAccB/wF6AVIBSQHtAYABWwFSAe9IAAFq - AV4BjwH5A/4l/wHwAfIB8AH/AsYBzQH/AUkBPwF1AfkIAAFqAY8BXgH5EP8B3AHtAdwB/wETAXsBEwH/ - AYMBwQGDDf8B8gHxAfAB/wHHAc4ByAH/AUkBdQFBAfkIAAGaAW8BXgH5DP8B4QHNAb4B/wG+AZIBjQH/ - AfcB8QHvAf8B+wH4AfcB/wHBAZgBjwH/AeoB2gHRBf8B5QHiAeYB/wHOAcoBxwH/AYYBVwE/AflEAAF+ - AWYBgAHzAX0BXQFpAe0I/wL1AfsB/wFvAWsB1AH/AaEBnwHnAf8BowGhAeYB/wGiAaEB5QH/AZQBkQHh - Af8BngGcAeYF/wH5AfgB9wH/AecB5AHeAf8BXgFRAXAB9QFdAVkBjwH7AX4BgAFmAfMBfQFpAV0B7RD/ - AeQB8QHkAf8BAwF3AQMB/wETAX0BEwH/AZwBzgGcCf8B+QH3AfkB/wHmAd4B5wH/AV4BcAFWAfUBXQGP - AVkB+wGWAW8BZAHzAYkBYAFdAe0M/wGuAXgBVgH/AVsCAgH/AfgB9QHyAf8B+gH3AfUB/wFbAgIB/wGz - AX0BXAX/AfEB9AH1Af8B3gHmAecB/wGFAVkBTgH1AZcBXwFUAftAAAGCAYgBygH/AdAB0gHtCf8C9QH6 - Af8BPQE6AbsB/wFpAWYB3gH/AWYBYgHYAf8BYQFdAdMB/wFVAVAB0QH/AaIBoQHpBf8C+QH4Af8B/AH7 - AeoB/wGjAaYBvgH/AUUBTAGgAf8BggHKAYoB/wHQAe0B1BH/AeIB8AHiAf8BBAF4AQQB/wECAXgBAgH/ - ARMBhAETAf8BmAHMAZgF/wH5AfgB+QH/AfwB6gH6Af8BowG+AaUB/wFFAaABUAH/AcoBnAGCAf8B7QHb - AdAN/wG6AYwBbAH/AY0BJAECAv8C/gH/A/4B/wGNASMBAgH/AbsBiQFqBf8B8gH0AfUB/wHqAfUB/AH/ - Ab4BrAGjAf8BoAFmAUUB/0AAAXYBfAHCAf8B5QHmAfQJ/wL3AfsB/wFMAUkBwwH/AXcBdQHjAf8BcgFv - Ad0B/wFtAWoB2AH/AWEBXAHTAf8BqwGpAeoF/wP5Af8B/gH7Ae8B/wG0AbYBxQH/AUMBSwGfAf8BdgHC - AYEB/wHlAfQB5xH/AeIB8AHiAf8BAwF6AQMB/wECAXwBAgH/AQIBdAECAf8BEwGEARMB/wH6AfwB+gH/ - A/kB/wH+Ae8B/gH/AbQBxQG2Af8BQwGfAU4B/wHCAZMBdgH/AfQB6wHlDf8BuQGMAW0B/wGnAToBDQH/ - AfsB+QH4Af8B+wH6AfkB/wGnAToBDQH/Ab0BjAFtBf8D9AH/Ae8B+gH+Af8BxQG6AbQB/wGfAWQBQwH/ - QAABcgF5Ab0B/wLaAe8J/wL3AfsB/wFQAU0BxwH/AX0BewHqAf8BeAF3AeMB/wF1AXMB3wH/AWgBZQHa - Af8BrQGrAesF/wL6AfgB/wH9AfwB7gH/AZ0BoAG7Af8BSwFTAaMB/wFyAb0BegH/AdoB7wHeEf8B4gHw - AeIB/wEEAXoBBAH/AQIBcgECAf8BLgGOAS4B/wHiAfAB4gX/AfoB+AH6Af8B/QHuAfsB/wGdAbsBoQH/ - AUsBowFUAf8BvQGOAXIB/wHvAeMB2g3/AbcBiAFoAf8BxAFJASYB/wL9AfwB/wH8AfoB+QH/AcYBTAEo - Af8BwgGPAXIF/wHyAfUB9wH/Ae4B9wH9Af8BuwGoAZ0B/wGjAWoBSwH/QAABegFbAW8B7wGEAWkBeQHx - CP8C9gH7Af8BTQFJAcUB/wF8AXsB6wH/AXgBdwHkAf8BdgFzAeEB/wFmAWMB2wH/AakBpwHrBf8C+wH5 - Af8B+wH8Ae4B/wFNAUoBhwH7AXQBWwFnAe8BegFvAVsB7wGEAXkBagHxEP8B4gHwAeIB/wECAXABAgH/ - ASoBhwEqAf8B5wHzAecJ/wH7AfkB+wH/AfwB7gH5Af8BTQGHAUwB+wF0AWcBWwHvAYsBZAFbAe8BlwFv - AWgB8Qz/AcEBlwF8Af8BpAFAARgB/wH9AfsB+gH/AfwB+gH5Af8BkwE7AREB/wHMAakBlAX/AfQB9wH5 - Af8B7gH1AfwB/wGQAVkBRQH7AYcBWwFaAe9EAAF9AYEBzwn/AvMB+QH/AUsBSAG5Af8BhwGGAdYB/wGH - AYUB1QH/AYcBhQHVAf8BZwFkAcgB/wFvAW4BzAb/Af4B/AH/As4B1wH/ATsBQwGYAf8IAAF9Ac8BjRH/ - AdMB6AHTAf8BJgGHASYB/wHiAfAB4g3/Af4B/AL/Ac4B1wHQAf8BOwGYAUUB/wgAAc8BoQF9Kf8B+wP/ - AdcB0gHOAf8BmAFcATsB/0gAAYgBeQGkAfkBjgFvAYUB8ST/AfwB+wH2Af8BOQFBAZYB/wF2AVQBWwHp - CAABiAGkAXsB+QGOAYUBdQHxDP8B+gH8AfoB/wHvAfYB7xH/AfwB9gH8Af8BOQGWAUMB/wF2AVsBUgHp - CAABswGHAXgB+QGfAXYBbwHxJP8B9QH6AfwB/wGWAVoBOQH/AX4BVwFSAelMAAKDAb4B/QF/AV0BYgHp - HP8B8gH1AfgB/wFcAVQBcAH1AW8BXAF/AfUQAAGDAb4BiAH9AX8BYgFdAekc/wH0AfgB8gH/AVwBcAFU - AfUBbwF/AWIB9RAAAcMBnQF9Af0BgwFfAV0B6Rz/AfgC8gH/AYYBWQFLAfUBkgFpAVkB9VQAAYIBfwGx - AfsBjwGCAa8B+QLTAfcB/wHxAfAB+wH/AfYB9wL/AfcB+AH9Af8B5AHnAfMB/wF0AVsBagHvAXQBXwF0 - AfMBfQFZAWIB6xgAAYIBsQGDAfsBjwGvAYoB+QHTAfcB2gH/AfAB+wHzAf8B9gH/AfcB/wH3Af0B+AH/ - AeQB8wHkAf8BdAFqAVsB7wJ0AWAB8wF9AWIBWQHrGAABuwGOAXgB+wG6AZQBgQH5AfcB4wHTAf8B+wH2 - AfAC/wH5AfYB/wH9AfkB9wH/AfMB6AHkAf8BiQFeAVsB7wGOAWYBXwHzAYUBXgFZAetcAAGBAV4BaQHr - AY0BkwHXAf8BjgGUAd0B/wGPAZUB4AH/AY0BlAHbAf8BmgGfAdoB/wF4AVMBWwHnJAABgQFpAWAB6wGN - AdcBlgH/AY4B3QGYAf8BjwHgAZkB/wGNAdsBlgH/AZoB2gGiAf8BeAFbAVQB5yQAAYoBYQFeAesB1wGo - AY0B/wHdAawBjgH/AeABrQGPAf8B2wGpAY0B/wHaAbIBmgH/AX4BVQFTAedUAAFCAU0BPgcAAT4DAAEo - AwABQAMAARADAAEBAQABAQUAAYAXAAP/AQAB/AE/AfwBPwH8AT8CAAHwAQ8B8AEPAfABDwIAAeABBwHg - AQcB4AEHAgABwAEDAcABAwHAAQMCAAGAAQEBgAEBAYABAQIAAYABAQGAAQEBgAEBKgABgAEBAYABAQGA - AQECAAGAAQEBgAEBAYABAQIAAcABAwHAAQMBwAEDAgAB4AEHAeABBwHgAQcCAAHwAR8B8AEfAfABHwIA - Cw== + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACA + DgAAAk1TRnQBSQFMAgEBAwEAATgBAAE4AQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABEAMAAQEBAAEgBgABECoAAW4BVgFXAeUBsgG0AdIB/wG7Ab4B1wH/AXEBVQFYAecwAAFuAVcBVgHl + AbIB0gG2Af8BuwHXAb4B/wFxAVgBVQHnMAABcwJWAeUB0gG+AbIB/wHXAcUBuwH/AXQCVQHnaAABbAFZ + AXMB9QE5AUABlwH/AQUBEAGHAf8BBgEQAYcB/wEEAQ8BhwH/AQsBFQGIAf8BDgEYAYkB/wFpAV4BiAH5 + IAABbAFzAVwB9QE5AZcBRQH/AQUBhwEUAf8BBgGHARUB/wEEAYcBEgH/AQsBiAEZAf8BDgGJARwB/wFp + AYgBXgH5IAABhgFnAVkB9QGXAVsBOQH/AYcBMwEFAf8BhwE0AQYB/wGHATIBBAH/AYgBNwELAf8BiQE6 + AQ4B/wGQAWgBWgH5XAABNAE8AZgB/wExATkBmAH/AbABsgHLAf8B2gHbAdoB/wLRAdUB/wHLAcwB0gH/ + AcQBxwHOAf8BWAFeAaUB/wFKAUUBdAH5ASkBMgGPAf8YAAEmAZIBMgH/ATEBmAE9Af8BsAHLAbMB/wHb + AtoB/wHRAdUB0gH/AcsB0gHLAf8BxQHOAcQB/wFYAaUBYQH/AUoBdAFGAfkBKQGPATQB/xgAAZIBTAEm + Af8BmAFWATEB/wHLAboBsAH/AtoB2wH/AdUB0wHRAf8B0gHNAcsB/wHOAcYBxAH/AaUBcwFYAf8BiAFc + AUEB+QGPAUwBKQH/VAACQAGNAf0BawFRAVMB4wL+Af0B/wH+Af0B9QH/AvcB8wH/Ae8C7gH/Au0B6wH/ + AdkC2wH/AeMB5AHiAf8CwAHMAf8BawFUAV0B7QFMAUkBgQH7EAABQAGNAUAB/QFrAVMBUQHjAf8B/gL/ + Af4B9QH9Af8B9wHzAfYB/wLuAe8B/wHtAesB7QH/AtsB2QH/AeQB4gHjAf8BwAHMAcIB/wFrAV0BVAHt + AUwBgQFLAfsQAAGTAUoBQAH9AWwBUgFRAeMB/gP/AfUB+wH+Af8B8wH1AfcB/wHuAe8B7gH/AesB7AHt + Af8B2wHZAdoB/wLiAeQB/wHMAcUBwAH/AXUBVQFTAe0BigFZAUMB+0wAAW4BXQFwAfMBdAFZAWAB6wX/ + Af4B/Rf/Af4B/wHwAe8B8AH/Ac8B0AHWAf8BZwFQAV0B7QFrAVUBZAHvCAABbgFwAV0B8wF0AWABWQHr + Bf8B/Qb/AeMB8AHjAf8BnAHNAZwK/wH+Av8B7wLwAf8BzwHWAc8B/wFnAV0BUAHtAWsBZAFVAe8IAAGF + AV8BWQHzAXsBXQFYAesE/wH9F/8B/gP/AuMB4AH/Ac8ByQHHAf8BcgFUAU8B7QF5AVkBVQHvSAABagFe + AY0B+QP+Jf8B8AHyAfAB/wLGAc0B/wFHAUEBbwH5CAABagGNAV4B+RD/AdwB7QHcAf8BEQF5AREB/wGD + AcEBgw3/AfIB8QHwAf8BxwHOAcgB/wFHAW8BQQH5CAABkgFqAV4B+Qz/AeEBzQG+Af8BvgGSAY0B/wH3 + AfEB7wH/AfsB+AH3Af8BwQGYAY8B/wHqAdoB0QX/AeUB4gHmAf8BzgHKAccB/wGEAVcBQQH5RAABdwFi + AXsB8wF1AV0BZwHtCP8C9QH7Af8BbQFpAdQB/wGhAZ8B5wH/AaMBoQHmAf8BogGhAeUB/wGUAZEB4QH/ + AZ4BnAHmBf8B+QH4AfcB/wHnAeQB3gH/AVoBUwFuAfUBXQFZAY0B+wF3AXsBYgHzAXUBZwFdAe0Q/wHk + AfEB5AH/AQEBdQEBAf8BEQF7AREB/wGcAc4BnAn/AfkB9wH5Af8B5gHeAecB/wFaAW4BWAH1AV0BjQFZ + AfsBjQFtAWAB8wF/AV4BXQHtDP8BrgF2AVQB/wFZAgAB/wH4AfUB8gH/AfoB9wH1Af8BWQIAAf8BswF7 + AVoF/wHxAfQB9QH/Ad4B5gHnAf8BgQFZAVAB9QGVAV8BVAH7QAABggGIAcoB/wHQAdIB7Qn/AvUB+gH/ + ATsBOAG7Af8BZwFkAd4B/wFkAWAB2AH/AV8BWwHTAf8BUwFOAdEB/wGiAaEB6QX/AvkB+AH/AfwB+wHq + Af8BowGmAb4B/wFDAUoBoAH/AYIBygGKAf8B0AHtAdQR/wHiAfAB4gH/AQIBdgECAf8BAAF2AQAB/wER + AYQBEQH/AZgBzAGYBf8B+QH4AfkB/wH8AeoB+gH/AaMBvgGlAf8BQwGgAU4B/wHKAZwBggH/Ae0B2wHQ + Df8BugGMAWoB/wGNASIBAAL/Av4B/wP+Af8BjQEhAQAB/wG7AYkBaAX/AfIB9AH1Af8B6gH1AfwB/wG+ + AawBowH/AaABZAFDAf9AAAF0AXoBwgH/AeUB5gH0Cf8C9wH7Af8BSgFHAcMB/wF1AXMB4wH/AXABbQHd + Af8BawFoAdgB/wFfAVoB0wH/AasBqQHqBf8D+QH/Af4B+wHvAf8BtAG2AcUB/wFBAUkBnwH/AXQBwgGB + Af8B5QH0AecR/wHiAfAB4gH/AQEBeAEBAf8BAAF6AQAB/wEAAXIBAAH/AREBhAERAf8B+gH8AfoB/wP5 + Af8B/gHvAf4B/wG0AcUBtgH/AUEBnwFMAf8BwgGTAXQB/wH0AesB5Q3/AbkBjAFrAf8BpwE4AQsB/wH7 + AfkB+AH/AfsB+gH5Af8BpwE4AQsB/wG9AYwBawX/A/QB/wHvAfoB/gH/AcUBugG0Af8BnwFiAUEB/0AA + AXABdwG9Af8C2gHvCf8C9wH7Af8BTgFLAccB/wF7AXkB6gH/AXYBdQHjAf8BcwFxAd8B/wFmAWMB2gH/ + Aa0BqwHrBf8C+gH4Af8B/QH8Ae4B/wGdAaABuwH/AUkBUQGjAf8BcAG9AXgB/wHaAe8B3hH/AeIB8AHi + Af8BAgF4AQIB/wEAAXABAAH/ASwBjgEsAf8B4gHwAeIF/wH6AfgB+gH/Af0B7gH7Af8BnQG7AaEB/wFJ + AaMBUgH/Ab0BjgFwAf8B7wHjAdoN/wG3AYgBZgH/AcQBRwEkAf8C/QH8Af8B/AH6AfkB/wHGAUoBJgH/ + AcIBjwFwBf8B8gH1AfcB/wHuAfcB/QH/AbsBqAGdAf8BowFoAUkB/0AAAXIBWQFpAe8BfwFlAXMB8Qj/ + AvYB+wH/AUsBRwHFAf8BegF5AesB/wF2AXUB5AH/AXQBcQHhAf8BZAFhAdsB/wGpAacB6wX/AvsB+QH/ + AfsB/AHuAf8BTQFKAYUB+wFvAVkBZQHvAXIBaQFZAe8BfwFzAWYB8RD/AeIB8AHiAf8BAAFuAQAB/wEo + AYcBKAH/AecB8wHnCf8B+wH5AfsB/wH8Ae4B+QH/AU0BhQFMAfsBbwFlAVkB7wGBAWIBWQHvAY4BbQFk + AfEM/wHBAZcBegH/AaQBPgEWAf8B/QH7AfoB/wH8AfoB+QH/AZMBOQEPAf8BzAGpAZQF/wH0AfcB+QH/ + Ae4B9QH8Af8BjgFZAUUB+wF/AVkBWAHvRAABewGBAc8J/wLzAfkB/wFJAUYBuQH/AYcBhgHWAf8BhwGF + AdUB/wGHAYUB1QH/AWUBYgHIAf8BbQFsAcwG/wH+AfwB/wLOAdcB/wE5AUEBmAH/CAABewHPAY0R/wHT + AegB0wH/ASQBhwEkAf8B4gHwAeIN/wH+AfwC/wHOAdcB0AH/ATkBmAFDAf8IAAHPAaEBeyn/AfsD/wHX + AdIBzgH/AZgBWgE5Af9IAAGGAXMBnAH5AYUBbQGAAfEk/wH8AfsB9gH/ATcBPwGWAf8BbgFYAVsB6QgA + AYYBnAF1AfkBhQGAAXEB8Qz/AfoB/AH6Af8B7wH2Ae8R/wH8AfYB/AH/ATcBlgFBAf8BbgFbAVYB6QgA + Aa0BhQFyAfkBkwFyAW0B8ST/AfUB+gH8Af8BlgFYATcB/wF2AVgBVgHpTAACgwG8Af0BdgFdAWIB6Rz/ + AfIB9QH4Af8BWQFWAW4B9QFtAVkBeAH1EAABgwG8AYgB/QF2AWIBXQHpHP8B9AH4AfIB/wFZAW4BVgH1 + AW0BeAFeAfUQAAG+AZ0BeQH9AXkBXwFdAekc/wH4AvIB/wGCAVkBSwH1AYkBZwFZAfVUAAGAAXkBqQH7 + AY0BgAGpAfkC0wH3Af8B8QHwAfsB/wH2AfcC/wH3AfgB/QH/AeQB5wHzAf8BbwFZAWYB7wFwAV8BcAHz + AXcBWQFgAesYAAGAAakBgQH7AY0BqQGIAfkB0wH3AdoB/wHwAfsB8wH/AfYB/wH3Af8B9wH9AfgB/wHk + AfMB5AH/AW8BZgFZAe8CcAFfAfMBdwFgAVkB6xgAAbMBjAFyAfsBsgGQAX8B+QH3AeMB0wH/AfsB9gHw + Av8B+QH2Af8B/QH5AfcB/wHzAegB5AH/AX8BXAFZAe8BhgFiAV8B8wF9AWABWQHrXAABeQFgAWcB6wGN + AZMB1wH/AY4BlAHdAf8BjwGVAeAB/wGNAZQB2wH/AZoBnwHaAf8BcQFVAVwB5yQAAXkBZwFgAesBjQHX + AZYB/wGOAd0BmAH/AY8B4AGZAf8BjQHbAZYB/wGaAdoBogH/AXEBXAFWAeckAAGAAmAB6wHXAagBjQH/ + Ad0BrAGOAf8B4AGtAY8B/wHbAakBjQH/AdoBsgGaAf8BdQFYAVUB51QAAUIBTQE+BwABPgMAASgDAAFA + AwABEAMAAQEBAAEBBQABgBcAA/8BAAH8AT8B/AE/AfwBPwIAAfABDwHwAQ8B8AEPAgAB4AEHAeABBwHg + AQcCAAHAAQMBwAEDAcABAwIAAYABAQGAAQEBgAEBAgABgAEBAYABAQGAAQEqAAGAAQEBgAEBAYABAQIA + AYABAQGAAQEBgAEBAgABwAEDAcABAwHAAQMCAAHgAQcB4AEHAeABBwIAAfABHwHwAR8B8AEfAgAL