diff --git a/.gitignore b/.gitignore index 7f56945..bed6fde 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bin obj *.suo *.user -*.cache \ No newline at end of file +*.cache +*.userprefs \ No newline at end of file diff --git a/Model/CubicRegionDataNode.cs b/Model/CubicRegionDataNode.cs index 271a575..6e6fca6 100644 --- a/Model/CubicRegionDataNode.cs +++ b/Model/CubicRegionDataNode.cs @@ -1,5 +1,6 @@ using System.IO; using System.Text.RegularExpressions; +using System.Collections.Generic; namespace NBTExplorer.Model { @@ -30,7 +31,8 @@ namespace NBTExplorer.Model { get { - return NodeCapabilities.Search; + return NodeCapabilities.Search + | NodeCapabilities.Refresh; } } @@ -71,5 +73,14 @@ namespace NBTExplorer.Model _region = null; Nodes.Clear(); } + + public override bool RefreshNode () + { + Dictionary expandSet = BuildExpandSet(this); + Release(); + RestoreExpandSet(this, expandSet); + + return true; + } } } diff --git a/Model/DataNode.cs b/Model/DataNode.cs index bfe356e..1107ebd 100644 --- a/Model/DataNode.cs +++ b/Model/DataNode.cs @@ -1,4 +1,5 @@ using Substrate.Nbt; +using System.Collections.Generic; namespace NBTExplorer.Model { @@ -8,7 +9,9 @@ namespace NBTExplorer.Model private DataNodeCollection _children; private bool _expanded; - private bool _modified; + + private bool _dataModified; + private bool _childModified; public DataNode () { @@ -28,15 +31,50 @@ namespace NBTExplorer.Model public bool IsModified { - get { return _modified; } + get { return _dataModified || _childModified; } + } + + protected bool IsDataModified + { + get { return _dataModified; } set { - if (value && Parent != null) - Parent.IsModified = value; - _modified = value; + _dataModified = value; + CalculateChildModifiedState(); } } + protected bool IsChildModified + { + get { return _childModified; } + set + { + _childModified = value; + CalculateChildModifiedState(); + } + } + + protected bool IsParentModified + { + get { return Parent != null && Parent.IsModified; } + set + { + if (Parent != null) + Parent.IsDataModified = value; + } + } + + private void CalculateChildModifiedState () + { + _childModified = false; + foreach (DataNode child in Nodes) + if (child.IsModified) + _childModified = true; + + if (Parent != null) + Parent.CalculateChildModifiedState(); + } + public bool IsExpanded { get { return _expanded; } @@ -68,6 +106,7 @@ namespace NBTExplorer.Model ReleaseCore(); IsExpanded = false; + IsDataModified = false; } protected virtual void ReleaseCore () @@ -82,7 +121,7 @@ namespace NBTExplorer.Model node.Save(); SaveCore(); - IsModified = false; + IsDataModified = false; } protected virtual void SaveCore () @@ -104,6 +143,34 @@ namespace NBTExplorer.Model get { return false; } } + protected Dictionary BuildExpandSet (DataNode node) + { + if (node == null || !node.IsExpanded) + return null; + + Dictionary dict = new Dictionary(); + foreach (DataNode child in node.Nodes) { + Dictionary childDict = BuildExpandSet(child); + if (childDict != null) + dict[child.NodeDisplay] = childDict; + } + + return dict; + } + + protected void RestoreExpandSet (DataNode node, Dictionary expandSet) + { + node.Expand(); + + foreach (DataNode child in node.Nodes) { + if (expandSet.ContainsKey(child.NodeDisplay)) { + Dictionary childDict = (Dictionary)expandSet[child.NodeDisplay]; + if (childDict != null) + RestoreExpandSet(child, childDict); + } + } + } + #region Capabilities protected virtual NodeCapabilities Capabilities @@ -151,6 +218,11 @@ namespace NBTExplorer.Model get { return (Capabilities & NodeCapabilities.Reorder) != NodeCapabilities.None; } } + public virtual bool CanRefreshNode + { + get { return (Capabilities & NodeCapabilities.Refresh) != NodeCapabilities.None; } + } + public virtual bool CanMoveNodeUp { get { return false; } @@ -210,6 +282,11 @@ namespace NBTExplorer.Model return false; } + public virtual bool RefreshNode () + { + return false; + } + #endregion } } diff --git a/Model/DirectoryDataNode.cs b/Model/DirectoryDataNode.cs index 8d2d272..83efe03 100644 --- a/Model/DirectoryDataNode.cs +++ b/Model/DirectoryDataNode.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Collections.Generic; namespace NBTExplorer.Model { @@ -15,7 +16,8 @@ namespace NBTExplorer.Model { get { - return NodeCapabilities.Search; + return NodeCapabilities.Search + | NodeCapabilities.Refresh; } } @@ -51,5 +53,14 @@ namespace NBTExplorer.Model { Nodes.Clear(); } + + public override bool RefreshNode () + { + Dictionary expandSet = BuildExpandSet(this); + Release(); + RestoreExpandSet(this, expandSet); + + return true; + } } } diff --git a/Model/NbtFileDataNode.cs b/Model/NbtFileDataNode.cs index e344296..af1ced2 100644 --- a/Model/NbtFileDataNode.cs +++ b/Model/NbtFileDataNode.cs @@ -2,6 +2,7 @@ using System.Text.RegularExpressions; using Substrate.Core; using Substrate.Nbt; +using System.Collections.Generic; namespace NBTExplorer.Model { @@ -57,7 +58,8 @@ namespace NBTExplorer.Model { return NodeCapabilities.CreateTag | NodeCapabilities.PasteInto - | NodeCapabilities.Search; + | NodeCapabilities.Search + | NodeCapabilities.Refresh; } } @@ -108,6 +110,15 @@ namespace NBTExplorer.Model } } + public override bool RefreshNode () + { + Dictionary expandSet = BuildExpandSet(this); + Release(); + RestoreExpandSet(this, expandSet); + + return true; + } + public bool IsNamedContainer { get { return true; } diff --git a/Model/NodeCapabilities.cs b/Model/NodeCapabilities.cs index 9588730..45f35c3 100644 --- a/Model/NodeCapabilities.cs +++ b/Model/NodeCapabilities.cs @@ -15,5 +15,6 @@ namespace NBTExplorer.Model CreateTag = 0x40, Search = 0x80, Reorder = 0x100, + Refresh = 0x200, } } diff --git a/Model/RegionFileDataNode.cs b/Model/RegionFileDataNode.cs index dbd2993..8b2b2d7 100644 --- a/Model/RegionFileDataNode.cs +++ b/Model/RegionFileDataNode.cs @@ -1,6 +1,7 @@ using System.IO; using System.Text.RegularExpressions; using Substrate.Core; +using System.Collections.Generic; namespace NBTExplorer.Model { @@ -31,7 +32,8 @@ namespace NBTExplorer.Model { get { - return NodeCapabilities.Search; + return NodeCapabilities.Search + | NodeCapabilities.Refresh; } } @@ -72,5 +74,14 @@ namespace NBTExplorer.Model _region = null; Nodes.Clear(); } + + public override bool RefreshNode () + { + Dictionary expandSet = BuildExpandSet(this); + Release(); + RestoreExpandSet(this, expandSet); + + return true; + } } } diff --git a/Model/TagCompoundDataNode.cs b/Model/TagCompoundDataNode.cs index 8063c21..267a2fa 100644 --- a/Model/TagCompoundDataNode.cs +++ b/Model/TagCompoundDataNode.cs @@ -103,7 +103,7 @@ namespace NBTExplorer.Model private void AddTag (TagNode tag, string name) { _container.AddTag(tag, name); - IsModified = true; + IsDataModified = true; if (IsExpanded) { TagDataNode node = TagDataNode.CreateFromTag(tag); diff --git a/Model/TagDataNode.cs b/Model/TagDataNode.cs index 0d44ceb..465cad6 100644 --- a/Model/TagDataNode.cs +++ b/Model/TagDataNode.cs @@ -226,7 +226,7 @@ namespace NBTExplorer.Model if (FormRegistry.RenameTag(data)) { if (TagParent.NamedTagContainer.RenameTag(Tag, data.Value)) { - IsModified = true; + IsDataModified = true; return true; } } @@ -273,7 +273,7 @@ namespace NBTExplorer.Model DataNode parent = Parent; parent.Nodes.Remove(this); parent.Nodes.Insert(newIndex, this); - parent.IsModified = true; + IsParentModified = true; return true; } @@ -284,7 +284,7 @@ namespace NBTExplorer.Model { if (FormRegistry.EditTagScalar != null) { if (FormRegistry.EditTagScalar(new TagScalarFormData(tag))) { - IsModified = true; + IsDataModified = true; return true; } } @@ -297,7 +297,7 @@ namespace NBTExplorer.Model StringFormData data = new StringFormData(tag.ToTagString().Data); if (FormRegistry.EditString(data)) { tag.ToTagString().Data = data.Value; - IsModified = true; + IsDataModified = true; return true; } } @@ -318,7 +318,7 @@ namespace NBTExplorer.Model if (FormRegistry.EditByteArray(data)) { Array.Copy(data.Data, tag.ToTagByteArray().Data, tag.ToTagByteArray().Length); - IsModified = true; + IsDataModified = true; return true; } } @@ -347,7 +347,7 @@ namespace NBTExplorer.Model iatag.Data[i] = BitConverter.ToInt32(data.Data, i * 4); } - IsModified = true; + IsDataModified = true; return true; } } diff --git a/Model/TagListDataNode.cs b/Model/TagListDataNode.cs index 3a9c26b..63e2db2 100644 --- a/Model/TagListDataNode.cs +++ b/Model/TagListDataNode.cs @@ -102,7 +102,7 @@ namespace NBTExplorer.Model private void AppendTag (TagNode tag) { _container.InsertTag(tag, _container.TagCount); - IsModified = true; + IsDataModified = true; if (IsExpanded) { TagDataNode node = TagDataNode.CreateFromTag(tag); diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 66baf9f..c9d4599 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.0.2.0")] -[assembly: AssemblyFileVersion("2.0.2.0")] +[assembly: AssemblyVersion("2.1.0.0")] +[assembly: AssemblyFileVersion("2.1.0.0")] diff --git a/Windows/MainForm.Designer.cs b/Windows/MainForm.Designer.cs index 069f0c1..8a2baef 100644 --- a/Windows/MainForm.Designer.cs +++ b/Windows/MainForm.Designer.cs @@ -37,6 +37,9 @@ this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); this._menuItemSave = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); + this._menuItemRecentFiles = new System.Windows.Forms.ToolStripMenuItem(); + this._menuItemRecentFolders = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); this._menuItemExit = new System.Windows.Forms.ToolStripMenuItem(); this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this._menuItemCut = new System.Windows.Forms.ToolStripMenuItem(); @@ -86,9 +89,8 @@ this.ContentPanel = new System.Windows.Forms.ToolStripContentPanel(); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); this.testToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this._menuItemRecentFiles = new System.Windows.Forms.ToolStripMenuItem(); - this._menuItemRecentFolders = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); + this._buttonRefresh = new System.Windows.Forms.ToolStripButton(); + this._menuItemRefresh = new System.Windows.Forms.ToolStripMenuItem(); this.menuStrip1.SuspendLayout(); this.toolStrip1.SuspendLayout(); this.contextMenuStrip1.SuspendLayout(); @@ -115,6 +117,7 @@ this._menuItemOpenMinecraftSaveFolder, this.toolStripSeparator3, this._menuItemSave, + this._menuItemRefresh, this.toolStripSeparator4, this._menuItemRecentFiles, this._menuItemRecentFolders, @@ -165,6 +168,23 @@ this.toolStripSeparator4.Name = "toolStripSeparator4"; this.toolStripSeparator4.Size = new System.Drawing.Size(220, 6); // + // _menuItemRecentFiles + // + this._menuItemRecentFiles.Name = "_menuItemRecentFiles"; + this._menuItemRecentFiles.Size = new System.Drawing.Size(223, 22); + this._menuItemRecentFiles.Text = "Recent Files"; + // + // _menuItemRecentFolders + // + this._menuItemRecentFolders.Name = "_menuItemRecentFolders"; + this._menuItemRecentFolders.Size = new System.Drawing.Size(223, 22); + this._menuItemRecentFolders.Text = "Recent Folders"; + // + // toolStripSeparator8 + // + this.toolStripSeparator8.Name = "toolStripSeparator8"; + this.toolStripSeparator8.Size = new System.Drawing.Size(220, 6); + // // _menuItemExit // this._menuItemExit.Image = ((System.Drawing.Image)(resources.GetObject("_menuItemExit.Image"))); @@ -254,7 +274,7 @@ this._menuItemFind.Image = ((System.Drawing.Image)(resources.GetObject("_menuItemFind.Image"))); this._menuItemFind.Name = "_menuItemFind"; this._menuItemFind.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F))); - this._menuItemFind.Size = new System.Drawing.Size(146, 22); + this._menuItemFind.Size = new System.Drawing.Size(152, 22); this._menuItemFind.Text = "Find..."; // // _menuItemFindNext @@ -262,7 +282,7 @@ this._menuItemFindNext.Image = ((System.Drawing.Image)(resources.GetObject("_menuItemFindNext.Image"))); this._menuItemFindNext.Name = "_menuItemFindNext"; this._menuItemFindNext.ShortcutKeys = System.Windows.Forms.Keys.F3; - this._menuItemFindNext.Size = new System.Drawing.Size(146, 22); + this._menuItemFindNext.Size = new System.Drawing.Size(152, 22); this._menuItemFindNext.Text = "Find Next"; // // helpToolStripMenuItem @@ -278,7 +298,7 @@ this._menuItemAbout.Image = ((System.Drawing.Image)(resources.GetObject("_menuItemAbout.Image"))); this._menuItemAbout.Name = "_menuItemAbout"; this._menuItemAbout.ShortcutKeys = System.Windows.Forms.Keys.F1; - this._menuItemAbout.Size = new System.Drawing.Size(126, 22); + this._menuItemAbout.Size = new System.Drawing.Size(152, 22); this._menuItemAbout.Text = "&About"; // // _nodeTree @@ -324,6 +344,7 @@ this._buttonOpen, this._buttonOpenFolder, this._buttonSave, + this._buttonRefresh, this.toolStripSeparator1, this._buttonCut, this._buttonCopy, @@ -611,22 +632,24 @@ this.testToolStripMenuItem.Size = new System.Drawing.Size(96, 22); this.testToolStripMenuItem.Text = "Test"; // - // _menuItemRecentFiles + // _buttonRefresh // - this._menuItemRecentFiles.Name = "_menuItemRecentFiles"; - this._menuItemRecentFiles.Size = new System.Drawing.Size(223, 22); - this._menuItemRecentFiles.Text = "Recent Files"; + this._buttonRefresh.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this._buttonRefresh.Image = ((System.Drawing.Image)(resources.GetObject("_buttonRefresh.Image"))); + this._buttonRefresh.ImageTransparentColor = System.Drawing.Color.Magenta; + this._buttonRefresh.Name = "_buttonRefresh"; + this._buttonRefresh.Size = new System.Drawing.Size(23, 22); + this._buttonRefresh.Text = "Refresh Content From Disk"; + this._buttonRefresh.Click += new System.EventHandler(this._buttonRefresh_Click); // - // _menuItemRecentFolders + // _menuItemRefresh // - this._menuItemRecentFolders.Name = "_menuItemRecentFolders"; - this._menuItemRecentFolders.Size = new System.Drawing.Size(223, 22); - this._menuItemRecentFolders.Text = "Recent Folders"; - // - // toolStripSeparator8 - // - this.toolStripSeparator8.Name = "toolStripSeparator8"; - this.toolStripSeparator8.Size = new System.Drawing.Size(220, 6); + this._menuItemRefresh.Image = ((System.Drawing.Image)(resources.GetObject("_menuItemRefresh.Image"))); + this._menuItemRefresh.Name = "_menuItemRefresh"; + this._menuItemRefresh.ShortcutKeys = System.Windows.Forms.Keys.F5; + this._menuItemRefresh.Size = new System.Drawing.Size(223, 22); + this._menuItemRefresh.Text = "Refresh"; + this._menuItemRefresh.Click += new System.EventHandler(this.refreshToolStripMenuItem_Click); // // MainForm // @@ -713,6 +736,8 @@ private System.Windows.Forms.ToolStripMenuItem _menuItemRecentFiles; private System.Windows.Forms.ToolStripMenuItem _menuItemRecentFolders; private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; + private System.Windows.Forms.ToolStripButton _buttonRefresh; + private System.Windows.Forms.ToolStripMenuItem _menuItemRefresh; } } diff --git a/Windows/MainForm.cs b/Windows/MainForm.cs index 968bfcb..cf68595 100644 --- a/Windows/MainForm.cs +++ b/Windows/MainForm.cs @@ -132,6 +132,9 @@ namespace NBTExplorer.Windows private void OpenFile () { + if (!ConfirmAction("Open new file anyway?")) + return; + OpenFileDialog ofd = new OpenFileDialog(); ofd.RestoreDirectory = true; ofd.Multiselect = true; @@ -145,6 +148,9 @@ namespace NBTExplorer.Windows private void OpenFolder () { + if (!ConfirmAction("Open new folder anyway?")) + return; + FolderBrowserDialog ofd = new FolderBrowserDialog(); if (_openFolderPath != null) ofd.SelectedPath = _openFolderPath; @@ -192,6 +198,9 @@ namespace NBTExplorer.Windows private void OpenMinecraftDirectory () { + if (!ConfirmAction("Open Minecraft save folder anyway?")) + return; + try { string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); path = Path.Combine(path, ".minecraft"); @@ -448,6 +457,40 @@ namespace NBTExplorer.Windows } } + private void RefreshNode (TreeNode node) + { + if (node == null || !(node.Tag is DataNode)) + return; + + DataNode dataNode = node.Tag as DataNode; + if (!dataNode.CanRefreshNode) + return; + + if (!ConfirmAction("Refresh data anyway?")) + return; + + if (dataNode.RefreshNode()) { + RefreshChildNodes(node, dataNode); + UpdateUI(dataNode); + ExpandToEdge(node); + } + } + + private void ExpandToEdge (TreeNode node) + { + if (node == null || !(node.Tag is DataNode)) + return; + + DataNode dataNode = node.Tag as DataNode; + if (dataNode.IsExpanded) { + if (!node.IsExpanded) + node.Expand(); + + foreach (TreeNode child in node.Nodes) + ExpandToEdge(child); + } + } + private void Save () { foreach (TreeNode node in _nodeTree.Nodes) { @@ -469,6 +512,16 @@ namespace NBTExplorer.Windows return true; } + private bool ConfirmAction (string actionMessage) + { + if (CheckModifications()) { + if (MessageBox.Show("You currently have unsaved changes. " + actionMessage, "Unsaved Changes", MessageBoxButtons.OKCancel) != DialogResult.OK) + return false; + } + + return true; + } + private CancelSearchForm _searchForm; private SearchStateWin _searchState; @@ -670,6 +723,7 @@ namespace NBTExplorer.Windows _buttonFindNext.Enabled = node.CanSearchNode || _searchState != null; _buttonPaste.Enabled = node.CanPasteIntoNode && NbtClipboardController.IsInitialized; _buttonRename.Enabled = node.CanRenameNode; + _buttonRefresh.Enabled = node.CanRefreshNode; _menuItemSave.Enabled = _buttonSave.Enabled; _menuItemCopy.Enabled = node.CanCopyNode && NbtClipboardController.IsInitialized; @@ -679,6 +733,7 @@ namespace NBTExplorer.Windows _menuItemFind.Enabled = node.CanSearchNode; _menuItemPaste.Enabled = node.CanPasteIntoNode && NbtClipboardController.IsInitialized; _menuItemRename.Enabled = node.CanRenameNode; + _menuItemRefresh.Enabled = node.CanRefreshNode; _menuItemFind.Enabled = node.CanSearchNode; _menuItemFindNext.Enabled = _searchState != null; } @@ -893,6 +948,11 @@ namespace NBTExplorer.Windows SearchNode(_nodeTree.SelectedNode); } + private void _buttonRefresh_Click (object sender, EventArgs e) + { + RefreshNode(_nodeTree.SelectedNode); + } + #endregion #region Menu Event Handlers @@ -977,6 +1037,11 @@ namespace NBTExplorer.Windows OpenPaths(new string[] { item.Tag as string }); } + private void refreshToolStripMenuItem_Click (object sender, EventArgs e) + { + RefreshNode(_nodeTree.SelectedNode); + } + #endregion #endregion diff --git a/Windows/MainForm.resx b/Windows/MainForm.resx index f77388b..203c890 100644 --- a/Windows/MainForm.resx +++ b/Windows/MainForm.resx @@ -343,7 +343,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADQ - MwAAAk1TRnQBSQFMAgEBEAEAARgBAQEYAQEBEAEAARABAAT/ARkBAAj/AUIBTQE2BwABNgMAASgDAAFA + MwAAAk1TRnQBSQFMAgEBEAEAASABAQEgAQEBEAEAARABAAT/ARkBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABUAMAAQEBAAEYBgABPP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AB4AA/wD+SH4A/kD/AMAA/0D+SH4 A/kD/TkAA/8D/AP5EvgD+QP7A/4GAAGWAakBvAFcAYQBrgFcAYQBrgFcAYQBrgFcAYQBrgFcAYQBrgFc AYQBrgFcAYQBrgFcAYQBrgFcAYQBrgFcAYQBrgFcAYQBrgFcAYQBrgFcAYQBrgGWAakBvAMAAs8BywK5 @@ -614,20 +614,38 @@ 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 - ZtRzYgAAAABJRU5ErkJggg== + WsImaxYpMLlFMALnGowiaIsapJaIhHAQghAu4pak5aCQuKEWg4L8ep8PL1RMGhIe3u99/u47leg/PolE + YjEej6t/6YIP/h5vKpXSgFgsNrQEuu3tKfB4PJqu6yKZTGrhcHhgCXjo8MHff1sVpGEYgq+o+f3+nhLs + 4KF3wgMfonq9Xq3RaIhoNKqxUZowsYOHztTQ15QlpmmKUCikOZ3OJUzsfwnL11rgJ/h8Pq3ZbIpIJHJV + rVYFdvC//kovRI5nouUnRdlhnJYVpbLlchmWZYmaw2Hc8Q4eOnzw/5QZvDwqyrYVDNbf0+m3Vj7fFsWi + uM9kxDVRC2cAPHT44EdOluhEK2YgoMN05nY/7BLVvwoFccHzkqiEiR08dPjgR04W1BTlsDv8kc2KczYz + pAETO/juEuRkQZmo8prNtiF+5nLimOeJ3d55UezgocMHP3JS3iPav1XVJm5xxOJmX9j+ssBDhw9+5KTm + JQqXiA6YuFkl2mBqHv8fxhzDyZhluBm+NaJ1+OBHzi6f4YONaT5PMsYZo4yRDsZ4TjCmurzI0Dfrcewz + 610f4QAAAABJRU5ErkJggg== @@ -820,11 +838,11 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFySURBVDhPY2CgBthfz8CyP4kl40AiczcM19sxnEHGyHIg tSA9cLv3xrErn6rWXPp+T+f/d7s7wHh2hikKhomD1IDUgvTADdiVwOx+c4r3EWQDlpc4/ofhJYV2cINB - akBqQXrgBuyIZ8m9vyz7wbPNDf9heEuj338YXlftARcHyYPUgvTADdgawzz19v7lf//fXfUfhu+uKgcy + akBqQXrgBuyIZ8m9vyz7wbPNDf9heEuj338YXlftARcHyYPUgvTADdgawzz11v7lf//fXfUfhu+uKgcy IfjMzDS4OEgepBakB27A5ijmGT8vzf//+cRUON7dEfofhjc3+KLIgdSC9MAN2BDFPPvbudn/PxyZCMcg zavKXcCGLCt2QJEDqQXpgRuwOoJ5/qeT0/6/2d8DxyDNID6MRpYDqQXpgRuwPIx58btD/f9f7monCoPU gvTADVgSwrjsFTDun25tIgqD1IL0wA2YH8C4+smWxv8PN9QShUFqQXrgBkzxZNzxYF31//trq4jCILUg - PTAD5FKNGee1uTAeJQWD9AANkAMZwg/E4kAsRSIG6QHppQwAAGlc3T6Cl1OsAAAAAElFTkSuQmCC + PTAD5FKNGee1uTAeJQWD9AANkAMZwg/E4kAsRSIG6QHppQwAAGQE3TzRiGWiAAAAAElFTkSuQmCC @@ -846,6 +864,25 @@ 347, 17 + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAC50lEQVQ4T6XTa0hTYRgH8NdT + CSWpaVobplPTbAWlm5SGKM0vSgmJoZElXgPbumjasBpqGluUzbLQLgYO5kwstS2nqUtFjTq2SBOzCZW6 + LbPVvORS8e15D/UhPwUd+HGey3v+53w5CGOM/gcKLjUwQm59RGG3x1H4PbNzROXn/eAK6AA0UAIh7Nhh + d4wI6kRQQV68PMBHcN8kTmu2KvP18/qS4SUrwAX6+dn0p9bRvZUmHbykGNDE3wE3P7AElWNJV4cW5cX6 + efWl1wuDsoFFK8BQY5hhWf8Chi+lr48sMXcmgFfyDvGvDduHlo0IZG9sogvdM/K83pnGWNV4C1/+vgPQ + UBuK++ZwXucUhNgwqcmcCdgpGyBYB6s/xeS2fhWdabeUQi8NvPw2moTvkPaTfRmgi/pmcFbTBJb0WDHp + mQBuYR/hl9FgjDulMQsjy4fE2y6+CtpepEcB+S/R1gI6Efbw8DQ+2zbJkHR/x2TGBPif70X+53o4J7Xm + cKHaGOGX183zEXciTo4Oeed2kF0FzOjlyJwJ2HS6FXlmtVV4ZbfTy5E5J+cZ8hV3kTMI9rzk+vGIDLUp + HHoOE8A6/oSgk7VfcHy9iZGps2AyYwubEjdmatD6tEeIlakJCizqFceoRoX7qgxxsPdjAsgS0FENk5iv + MOLYJgsmPShzSalDTkkPkGvqw2jopZHVY6V7VGZRoPRFDPQsJsDxiIqgQx5P4UjtNN6ssmBS+0q6DGQO + OnwknS27akyN3NpvcoF2WuSSWidwOlpjzwSsia8i6AjdT0zuXM0c9qj/gT0b5vAWjY2wQj0IMzW/xSZ3 + TqlNckhQsNYeVjL/EKLcAtCqA3fp34rtExQ6dtHzUa/qiVlO8yIGVi/lhJ5V2KtcfUghXhmW60O5ByBy + MQFweVCh2VUULz0Lap6dO1dA7T6RT0XfqKX2l/eBTipKXkoFH0uxW+cdCme4wA2s+BPgCI0r2ADY/4A8 + 7AAoEvALSboOLClv94sAAAAASUVORK5CYII= + + AAABAAQAMDAAAAEAIACoJQAARgAAACAgAAABACAAqBAAAO4lAAAYGAAAAQAgAIgJAACWNgAAEBAAAAEA