From 50581a1d6a320057158735fa2531d143a344d61d Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Wed, 20 Sep 2017 19:36:51 +0200 Subject: [PATCH 01/11] Updated .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 304636474..76b5a0e9f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ packages .vscode paket.dependencies paket.dependencies.locked +.vs +UpgradeLog.htm From a1777a96c3a89f28383aab3f299de15595864b6c Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Wed, 20 Sep 2017 19:37:25 +0200 Subject: [PATCH 02/11] Added SearchTextBox --- .../ObjectExplorer/ObjectExplorer.cs | 7 +++ .../ObjectExplorer/SearchTextBox.cs | 49 ++++++++++++++++++ .../Properties/Resources.Designer.cs | 14 ++++- Src/SwqlStudio/Properties/Resources.resx | 3 ++ Src/SwqlStudio/Resources/Search.png | Bin 0 -> 5307 bytes Src/SwqlStudio/SwqlStudio.csproj | 15 +++--- 6 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs create mode 100644 Src/SwqlStudio/Resources/Search.png diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index 178de6105..48bae4c9d 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -25,6 +25,7 @@ class ObjectExplorer : Control { private static readonly Log log = new Log(); + private readonly TextBox _treeSearch; private readonly TreeView _tree; private TreeNode _contextMenuNode; private readonly Dictionary _tableContextMenuItems; @@ -40,6 +41,11 @@ class ObjectExplorer : Control public ObjectExplorer() { + _treeSearch = new SearchTextBox + { + Dock = DockStyle.Top + }; + _tree = new TreeView { Dock = DockStyle.Fill, @@ -60,6 +66,7 @@ public ObjectExplorer() _verbContextMenu.MenuItems.Add("Invoke...", (s, e) => OpenInvokeTab()); Controls.Add(_tree); + Controls.Add(_treeSearch); } private bool AllowExpandCollapse diff --git a/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs new file mode 100644 index 000000000..708dfdd45 --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs @@ -0,0 +1,49 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using SwqlStudio.Properties; + +namespace SwqlStudio +{ + internal class SearchTextBox : TextBox + { + private const int EM_SETMARGINS = 0xd3; + + [System.Runtime.InteropServices.DllImport("user32.dll")] + private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); + + + private readonly PictureBox _searchPictureBox; + + public SearchTextBox() + { + _searchPictureBox = new PictureBox(); + _searchPictureBox.Anchor = AnchorStyles.Top | AnchorStyles.Right; + _searchPictureBox.Size = new Size(16, 16); + _searchPictureBox.TabIndex = 0; + _searchPictureBox.TabStop = false; + _searchPictureBox.Visible = true; + _searchPictureBox.SizeMode = PictureBoxSizeMode.StretchImage; + Controls.Add(_searchPictureBox); + + // Send EM_SETMARGINS to prevent text from disappearing underneath the button + SendMessage(Handle, EM_SETMARGINS, (IntPtr)2, (IntPtr)(16 << 16)); + + SearchImage = Resources.Search; + } + + [Browsable(true)] + public Image SearchImage + { + set + { + _searchPictureBox.Image = value; + _searchPictureBox.Left = Width - _searchPictureBox.Size.Width - 4; + _searchPictureBox.Top = Height - _searchPictureBox.Size.Height - 4; + } + + get => _searchPictureBox.Image; + } + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/Properties/Resources.Designer.cs b/Src/SwqlStudio/Properties/Resources.Designer.cs index 9c982e893..1807c8666 100644 --- a/Src/SwqlStudio/Properties/Resources.Designer.cs +++ b/Src/SwqlStudio/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.0 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -19,7 +19,7 @@ namespace SwqlStudio.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -88,5 +88,15 @@ internal static string ResizableTextAreaStyle { return ResourceManager.GetString("ResizableTextAreaStyle", resourceCulture); } } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Search { + get { + object obj = ResourceManager.GetObject("Search", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } } } diff --git a/Src/SwqlStudio/Properties/Resources.resx b/Src/SwqlStudio/Properties/Resources.resx index d122f6a58..452a9aee7 100644 --- a/Src/SwqlStudio/Properties/Resources.resx +++ b/Src/SwqlStudio/Properties/Resources.resx @@ -118,4 +118,7 @@ ..\ResizableTextAreaStyle.css;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + ..\Resources\Search.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + diff --git a/Src/SwqlStudio/Resources/Search.png b/Src/SwqlStudio/Resources/Search.png new file mode 100644 index 0000000000000000000000000000000000000000..8971d1532057087d62e868417f81fb26da9cd8d7 GIT binary patch literal 5307 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 BuOR>c literal 0 HcmV?d00001 diff --git a/Src/SwqlStudio/SwqlStudio.csproj b/Src/SwqlStudio/SwqlStudio.csproj index a37084f2d..8904fcf81 100644 --- a/Src/SwqlStudio/SwqlStudio.csproj +++ b/Src/SwqlStudio/SwqlStudio.csproj @@ -154,6 +154,14 @@ + + Component + + + True + True + Resources.resx + @@ -234,14 +242,9 @@ ResXFileCodeGenerator - Resources.Designer.cs Designer + Resources.Designer.cs - - True - Resources.resx - True - QueryParameters.cs From 53c341b836369053f8ec5c61b2f57e810ce106b2 Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Wed, 20 Sep 2017 22:14:15 +0200 Subject: [PATCH 03/11] Added 'data' and 'display' trees to ObjectExplorer --- .../ObjectExplorer/ObjectExplorer.cs | 99 ++++++++++++++-- .../ObjectExplorer/TreeNodeUtils.cs | 106 ++++++++++++++++++ .../TreeNodeWithConnectionInfo.cs | 25 ++++- Src/SwqlStudio/SwqlStudio.csproj | 1 + 4 files changed, 220 insertions(+), 11 deletions(-) create mode 100644 Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index 48bae4c9d..c78299cb6 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -25,13 +25,16 @@ class ObjectExplorer : Control { private static readonly Log log = new Log(); - private readonly TextBox _treeSearch; private readonly TreeView _tree; + private readonly TreeView _treeData; + private TreeNodeUtils.TreeNodeBindings _treeBindings = new TreeNodeUtils.TreeNodeBindings(); // default value, so this field is never null private TreeNode _contextMenuNode; private readonly Dictionary _tableContextMenuItems; private readonly Dictionary _serverContextMenuItems; private readonly ContextMenu _verbContextMenu; private bool _isDragging; + private string _filter; + private bool _treeIsUnderUpdate; private Point _lastLocation; private TreeNode _dragNode; @@ -41,7 +44,7 @@ class ObjectExplorer : Control public ObjectExplorer() { - _treeSearch = new SearchTextBox + var treeSearch = new SearchTextBox { Dock = DockStyle.Top }; @@ -52,13 +55,37 @@ public ObjectExplorer() ShowNodeToolTips = true }; + _treeData = new TreeView(); + _tree.MouseDown += TreeMouseDown; _tree.MouseMove += TreeMouseMove; _tree.MouseUp += _tree_MouseUp; _tree.BeforeExpand += (sender, e) => { e.Cancel = !AllowExpandCollapse; if (!e.Cancel) _tree_BeforeExpand(sender, e); }; _tree.BeforeCollapse += (sender, e) => { e.Cancel = !AllowExpandCollapse; }; + // copy expanded / not expanded state to data, so it is persisted + _tree.AfterExpand += (sender, e) => + { + if (_treeIsUnderUpdate) // we are calling expand on the display tree when cloning from data. + // we do not want to update data with such information, as we dont have proper _treeBindings at the moment + return; + + var dataNode = _treeBindings.FindDataNode(e.Node); + dataNode.Expand(); + }; + + _tree.AfterCollapse += (sender, e) => + { + if (_treeIsUnderUpdate) + return; + + var dataNode = _treeBindings.FindDataNode(e.Node); + dataNode.Collapse(); + }; + _tree.NodeMouseDoubleClick += _tree_NodeMouseDoubleClick; + treeSearch.TextChanged += (sender, e) => { SetFilter(((TextBox) sender).Text); }; + _tableContextMenuItems = new Dictionary(); _serverContextMenuItems = new Dictionary(); @@ -66,7 +93,56 @@ public ObjectExplorer() _verbContextMenu.MenuItems.Add("Invoke...", (s, e) => OpenInvokeTab()); Controls.Add(_tree); - Controls.Add(_treeSearch); + Controls.Add(treeSearch); + } + + private void SetFilter(string filter) + { + if (string.IsNullOrWhiteSpace(filter)) + filter = null; + + if (_filter != filter) + { + _filter = filter; + UpdateDrawnNodes(); + } + } + + // since we have data in _treeData, but are displaying _tree, + // we need to copy data from treedata to trees (according to applied filter) + private void UpdateDrawnNodes() + { + _treeData.SelectedNode = _treeBindings.FindDataNode(_tree.SelectedNode); + + _treeIsUnderUpdate = true; + _tree.BeginUpdate(); + _tree.Nodes.Clear(); + try + { + // quick path + if (_filter == null) + { + _treeBindings = TreeNodeUtils.CopyTree(_treeData, _tree); + } + else + { + + } + + UpdateDrawnNodesSelection(); + } + finally + { + _tree.EndUpdate(); + _treeIsUnderUpdate = false; + } + } + + + + private void UpdateDrawnNodesSelection() + { + _tree.SelectedNode = _treeBindings.FindDisplayNode(_treeData.SelectedNode); } private bool AllowExpandCollapse @@ -162,10 +238,12 @@ private IMetadataProvider FindProvider(TreeNode node) public void RefreshAllServers() { - foreach (TreeNode node in _tree.Nodes) + foreach (TreeNode node in _treeData.Nodes) { RefreshServer(node); } + + UpdateDrawnNodes(); } private void RefreshServer(TreeNode node) @@ -191,6 +269,8 @@ private void RefreshServer(TreeNode node) AddTablesToNode(node, provider, treeNodeWithConnectionInfo.Connection); else AddTablesToNode(node, provider, null); + + UpdateDrawnNodes(); })); } catch (FaultException faultEx) @@ -338,18 +418,19 @@ public void AddServer(IMetadataProvider provider, ConnectionInfo connection) TreeNode node = CreateDatabaseNode(provider, connection); - TreeNode[] existingNodes = _tree.Nodes.Find(node.Name, false); + TreeNode[] existingNodes = _treeData.Nodes.Find(node.Name, false); if (existingNodes.Length == 0) { // Node doesn't already exist. Add it - _tree.Nodes.Add(node); - _tree.SelectedNode = node; + _treeData.Nodes.Add(node); + _treeData.SelectedNode = node; RefreshServer(node); } else { // Node exists. Just focus on it. - _tree.SelectedNode = existingNodes[0]; + _treeData.SelectedNode = existingNodes[0]; + UpdateDrawnNodesSelection(); } connection.ConnectionClosed += (o, e) => @@ -370,7 +451,7 @@ private void CloseServer(TreeNode contextMenuNode) if (node != null) { node.Connection.Close(); - _tree.Nodes.Remove(node); + _treeData.Nodes.Remove(_treeBindings.FindDataNode(node)); } } diff --git a/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs b/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs new file mode 100644 index 000000000..71ab4a64a --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Windows.Forms; + +namespace SwqlStudio +{ + internal static class TreeNodeUtils + { + /// + /// Copies tree from data to display. + /// Returns "bindings", mapping data->display (so, if you have data node, you can find it's counterpart on display) + /// + /// + public static TreeNodeBindings CopyTree(TreeView data, TreeView display) + { + var bindings = new TreeNodeBindings(); + display.Nodes.Clear(); + CopyTree(data.Nodes, display.Nodes, bindings); + return bindings; + } + + private static void CopyTree(TreeNodeCollection source, TreeNodeCollection target, TreeNodeBindings bindings) + { + foreach (TreeNode node in source) + { + TreeNode newNode; + if (node is TreeNodeWithConnectionInfo) + newNode = ((TreeNodeWithConnectionInfo) node).CloneShallow(); + else + { + newNode = CloneShallow(node); + } + target.Add(newNode); + bindings.BindNodes(node, newNode); + CopyTree(node.Nodes, newNode.Nodes, bindings); + if (node.IsExpanded) + newNode.Expand(); + } + } + + // we need copy without children + private static TreeNode CloneShallow(TreeNode node) + { + var treeNode = new TreeNode(); + treeNode.Text = node.Text; + treeNode.Name = node.Name; + treeNode.ImageIndex = node.ImageIndex; + treeNode.SelectedImageIndex = node.SelectedImageIndex; + treeNode.StateImageIndex = node.StateImageIndex; + + treeNode.SelectedImageKey = node.SelectedImageKey; + treeNode.ImageKey = node.ImageKey; + treeNode.Tag = node.Tag; + + treeNode.ToolTipText = node.ToolTipText; + treeNode.ContextMenu = node.ContextMenu; + treeNode.ContextMenuStrip = node.ContextMenuStrip; + treeNode.Checked = node.Checked; + return treeNode; + } + + public class TreeNodeBindings + { + private readonly Dictionary _bindingsData2Display = + new Dictionary(ReferenceEqualityComparer.Default); + + private readonly Dictionary _bindingsDisplay2Data = + new Dictionary(ReferenceEqualityComparer.Default); + + public void BindNodes(TreeNode dataNode, TreeNode displayNode) + { + _bindingsData2Display.Add(dataNode, displayNode); + _bindingsDisplay2Data.Add(displayNode, dataNode); + } + + public TreeNode FindDisplayNode(TreeNode dataTreeNode) + { + if (dataTreeNode == null) + return null; + + _bindingsData2Display.TryGetValue(dataTreeNode, out var rv); + return rv; + } + + public TreeNode FindDataNode(TreeNode displayTreeNode) + { + if (displayTreeNode == null) + return null; + + _bindingsDisplay2Data.TryGetValue(displayTreeNode, out var rv); + return rv; + } + } + private sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer + { + public static ReferenceEqualityComparer Default { get; } = new ReferenceEqualityComparer(); + + public new bool Equals(object x, object y) => ReferenceEquals(x, y); + public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj); + } + } +} diff --git a/Src/SwqlStudio/ObjectExplorer/TreeNodeWithConnectionInfo.cs b/Src/SwqlStudio/ObjectExplorer/TreeNodeWithConnectionInfo.cs index 771160b0b..6554102d3 100644 --- a/Src/SwqlStudio/ObjectExplorer/TreeNodeWithConnectionInfo.cs +++ b/Src/SwqlStudio/ObjectExplorer/TreeNodeWithConnectionInfo.cs @@ -1,14 +1,35 @@ -using System.Windows.Forms; +using System; +using System.Windows.Forms; namespace SwqlStudio { - internal class TreeNodeWithConnectionInfo : TreeNode + public class TreeNodeWithConnectionInfo : TreeNode, ICloneable { public TreeNodeWithConnectionInfo(string text, ConnectionInfo connection) : base(text) { Connection = connection; } + public TreeNode CloneShallow() + { + var treeNode = new TreeNodeWithConnectionInfo(Text, Connection); + treeNode.Text = Text; + treeNode.Name = Name; + treeNode.ImageIndex = ImageIndex; + treeNode.SelectedImageIndex = SelectedImageIndex; + treeNode.StateImageIndex = StateImageIndex; + + treeNode.SelectedImageKey = SelectedImageKey; + treeNode.ImageKey = ImageKey; + treeNode.Tag = Tag; + + treeNode.ToolTipText = ToolTipText; + treeNode.ContextMenu = ContextMenu; + treeNode.ContextMenuStrip = ContextMenuStrip; + treeNode.Checked = Checked; + return treeNode; + } + public ConnectionInfo Connection { get; private set; } } } diff --git a/Src/SwqlStudio/SwqlStudio.csproj b/Src/SwqlStudio/SwqlStudio.csproj index 8904fcf81..6e2875c02 100644 --- a/Src/SwqlStudio/SwqlStudio.csproj +++ b/Src/SwqlStudio/SwqlStudio.csproj @@ -157,6 +157,7 @@ Component + True True From a66dc7921877a4ef11d686c5e2d5f4cd830c0600 Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Wed, 20 Sep 2017 22:37:33 +0200 Subject: [PATCH 04/11] Added working filtering --- .../ObjectExplorer/ObjectExplorer.cs | 61 +++++++++++- .../ObjectExplorer/TreeNodeUtils.cs | 94 ++++++++++++++++++- 2 files changed, 150 insertions(+), 5 deletions(-) diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index c78299cb6..e1f9f80c0 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -3,13 +3,18 @@ using System.Data; using System.Drawing; using System.Linq; +using System.Runtime.InteropServices; using System.ServiceModel; using System.ServiceModel.Security; using System.Text; using System.Threading; +using System.Web.UI.WebControls; using System.Windows.Forms; using SolarWinds.Logging; using SwqlStudio.Metadata; +using TextBox = System.Windows.Forms.TextBox; +using TreeNode = System.Windows.Forms.TreeNode; +using TreeView = System.Windows.Forms.TreeView; namespace SwqlStudio { @@ -38,6 +43,10 @@ class ObjectExplorer : Control private Point _lastLocation; private TreeNode _dragNode; + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + public static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw); + private const int SB_HORZ = 0x0; + public IApplicationService ApplicationService { get; set; } public EntityGroupingMode EntityGroupingMode { get; set; } @@ -122,11 +131,31 @@ private void UpdateDrawnNodes() // quick path if (_filter == null) { - _treeBindings = TreeNodeUtils.CopyTree(_treeData, _tree); + _treeBindings = TreeNodeUtils.CopyTree(_treeData, _tree, null, null); } else { + var visibility = new TreeNodeUtils.NodeVisibility(); + TreeNodeUtils.IterateNodes(_treeData, node => + { + if (PassesFilter(node)) + visibility.SetVisible(node); + }); + + _treeBindings = TreeNodeUtils.CopyTree(_treeData, _tree, + node => visibility.GetVisibility(node) != + TreeNodeUtils.NodeVisibility.VisibilityStatus.NotVisible, (data, display) => + { + var nodeVisibility = visibility.GetVisibility(data); + if (nodeVisibility == TreeNodeUtils.NodeVisibility.VisibilityStatus.ChildVisible) + // this one is not directly visible, gray it out + display.ForeColor = Color.LightBlue; + + if (nodeVisibility == TreeNodeUtils.NodeVisibility.VisibilityStatus.Visible) + display.EnsureVisible(); + }); + SetScrollPos(_tree.Handle, SB_HORZ, 0, false); } UpdateDrawnNodesSelection(); @@ -138,6 +167,36 @@ private void UpdateDrawnNodes() } } + private bool PassesFilter(TreeNode node) + { + var nodeText = node.Text.Split('(')[0]; // trim everything after first (, we do not want to use it in search + + if (!_filter.Contains('.')) + return nodeText.IndexOf(_filter, StringComparison.OrdinalIgnoreCase) >= 0; // is filter found? + else // behave in 'special' way for dots. + // let's Met.Ent match also METadata...ENTity + { + var filter = _filter.Split(new[] {'.'}, StringSplitOptions.RemoveEmptyEntries); + var text = nodeText.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + + int textPivot = 0; + + for (int filterPivot = 0; filterPivot < filter.Length; filterPivot++) + { + for (; textPivot <= text.Length; textPivot++) + { + if (textPivot == text.Length) + return false; + + if (text[textPivot].StartsWith(filter[filterPivot], StringComparison.OrdinalIgnoreCase)) + break; + } + textPivot++; + } + + return true; + } + } private void UpdateDrawnNodesSelection() diff --git a/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs b/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs index 71ab4a64a..36d7fa78b 100644 --- a/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs +++ b/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs @@ -13,20 +13,28 @@ internal static class TreeNodeUtils /// /// Copies tree from data to display. /// Returns "bindings", mapping data->display (so, if you have data node, you can find it's counterpart on display) + /// + /// filter method is called for each data node, and if returns false, display node is not created (and data children are not iterated) + /// updateAction is called for each newly created display node, first parameter is data node, second one is display node /// /// - public static TreeNodeBindings CopyTree(TreeView data, TreeView display) + public static TreeNodeBindings CopyTree(TreeView data, TreeView display, Func filter, Action updateAction) { var bindings = new TreeNodeBindings(); display.Nodes.Clear(); - CopyTree(data.Nodes, display.Nodes, bindings); + CopyTree(data.Nodes, display.Nodes, bindings, + filter ?? (_ => true), + updateAction ?? ((dataNode, displayNode) => { })); return bindings; } - private static void CopyTree(TreeNodeCollection source, TreeNodeCollection target, TreeNodeBindings bindings) + private static void CopyTree(TreeNodeCollection source, TreeNodeCollection target, TreeNodeBindings bindings, Func filter, Action updateAction) { foreach (TreeNode node in source) { + if (!filter(node)) + continue; + TreeNode newNode; if (node is TreeNodeWithConnectionInfo) newNode = ((TreeNodeWithConnectionInfo) node).CloneShallow(); @@ -34,11 +42,17 @@ private static void CopyTree(TreeNodeCollection source, TreeNodeCollection targe { newNode = CloneShallow(node); } + + + target.Add(newNode); bindings.BindNodes(node, newNode); - CopyTree(node.Nodes, newNode.Nodes, bindings); + CopyTree(node.Nodes, newNode.Nodes, bindings, filter, updateAction); + if (node.IsExpanded) newNode.Expand(); + + updateAction(node, newNode); } } @@ -63,6 +77,59 @@ private static TreeNode CloneShallow(TreeNode node) return treeNode; } + /// + /// Used in filtering of the nodes. + /// + /// Keeps track of visibility of each single one + /// + public class NodeVisibility + { + private readonly Dictionary _visibility = new Dictionary(ReferenceEqualityComparer.Default); + + + public void SetVisible(TreeNode node) + { + _visibility[node] = VisibilityStatus.Visible; + for (var parent = node.Parent; parent != null; parent = parent.Parent) + { + _visibility.TryGetValue(parent, out var parentVisibility); + if (parentVisibility != VisibilityStatus.Visible) + parentVisibility = VisibilityStatus.ChildVisible; + + _visibility[parent] = parentVisibility; + } + } + + public VisibilityStatus GetVisibility(TreeNode node) + { + if (!_visibility.TryGetValue(node, out var rv)) + rv = VisibilityStatus.NotVisible; + + return rv; + } + + public enum VisibilityStatus + { + /// + /// This node is not visible + /// + NotVisible, + /// + /// Some children of this node passed filter + /// + ChildVisible, + /// + /// This node passed filter + /// + Visible + } + } + + /// + /// used for being able to get 'data' node from 'display' (and back). + /// + /// useful, when someone for example expands display node, we want to sync that to data. + /// public class TreeNodeBindings { private readonly Dictionary _bindingsData2Display = @@ -102,5 +169,24 @@ private sealed class ReferenceEqualityComparer : IEqualityComparer, IEqualityCom public new bool Equals(object x, object y) => ReferenceEquals(x, y); public int GetHashCode(object obj) => RuntimeHelpers.GetHashCode(obj); } + + /// + /// Does DFS walk through the tree. + /// + /// + /// + public static void IterateNodes(TreeView treeData, Action action) + { + IterateNodes(treeData.Nodes, action); + } + + private static void IterateNodes(TreeNodeCollection nodes, Action action) + { + foreach(TreeNode node in nodes) + { + action(node); + IterateNodes(node.Nodes, action); + } + } } } From 81af134e2ec88dc5aa5ad7fbee2ea9b3ddcf565f Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Wed, 20 Sep 2017 22:45:45 +0200 Subject: [PATCH 05/11] Updated behavior of filter to work also for CamelCase --- .../ObjectExplorer/ObjectExplorer.cs | 51 ++++++++++++++++--- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index e1f9f80c0..bb9f3c887 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -171,21 +171,23 @@ private bool PassesFilter(TreeNode node) { var nodeText = node.Text.Split('(')[0]; // trim everything after first (, we do not want to use it in search - if (!_filter.Contains('.')) - return nodeText.IndexOf(_filter, StringComparison.OrdinalIgnoreCase) >= 0; // is filter found? - else // behave in 'special' way for dots. + if (nodeText.IndexOf(_filter, StringComparison.OrdinalIgnoreCase) >= 0) + return true; + + else // behave in 'special' way for dots, and capitals, the same way as resharper does // let's Met.Ent match also METadata...ENTity + // also Met.EntNa should match Metadata.EntityName { - var filter = _filter.Split(new[] {'.'}, StringSplitOptions.RemoveEmptyEntries); - var text = nodeText.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + var filter = SplitTextByCapsAndDot(_filter); + var text = SplitTextByCapsAndDot(nodeText); int textPivot = 0; - for (int filterPivot = 0; filterPivot < filter.Length; filterPivot++) + for (int filterPivot = 0; filterPivot < filter.Count; filterPivot++) { - for (; textPivot <= text.Length; textPivot++) + for (; textPivot <= text.Count; textPivot++) { - if (textPivot == text.Length) + if (textPivot == text.Count) return false; if (text[textPivot].StartsWith(filter[filterPivot], StringComparison.OrdinalIgnoreCase)) @@ -198,6 +200,39 @@ private bool PassesFilter(TreeNode node) } } + private static List SplitTextByCapsAndDot(string text) + { + var rv = new List(); + + var buf = new StringBuilder(); + + void FlushBuffer() + { + if (buf.Length > 0) + rv.Add(buf.ToString()); + + buf.Clear(); + } + + foreach (var t in text) + { + if (t == '.') + { + FlushBuffer(); + } + else + { + if (char.IsUpper(t)) + FlushBuffer(); + + buf.Append(t); + } + } + + FlushBuffer(); + return rv; + } + private void UpdateDrawnNodesSelection() { From 8459ff85f547dda889844bac5926d7a7341ea5df Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Wed, 20 Sep 2017 22:52:32 +0200 Subject: [PATCH 06/11] Fixed behavior of displaying children nodes --- .../ObjectExplorer/ObjectExplorer.cs | 6 ++++++ .../ObjectExplorer/TreeNodeUtils.cs | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index bb9f3c887..f6d5f7fb1 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -151,6 +151,12 @@ private void UpdateDrawnNodes() // this one is not directly visible, gray it out display.ForeColor = Color.LightBlue; + if (nodeVisibility == TreeNodeUtils.NodeVisibility.VisibilityStatus.ParentVisible) + // this one is not directly visible, gray it out + display.ForeColor = Color.DarkGray; + + // this one is visible directly, ensure it is visible (parents are expanded). + // it's children are visible as well, but may be not expanded if (nodeVisibility == TreeNodeUtils.NodeVisibility.VisibilityStatus.Visible) display.EnsureVisible(); }); diff --git a/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs b/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs index 36d7fa78b..4c1610259 100644 --- a/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs +++ b/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs @@ -103,7 +103,20 @@ public void SetVisible(TreeNode node) public VisibilityStatus GetVisibility(TreeNode node) { if (!_visibility.TryGetValue(node, out var rv)) + { rv = VisibilityStatus.NotVisible; + // check if some of the parents is not directly visible (visible, not childvisible) + for (var parent = node.Parent; parent != null; parent = parent.Parent) + { + if (_visibility.TryGetValue(parent, out var parentVisibility)) + { + if (parentVisibility == VisibilityStatus.Visible) + rv = VisibilityStatus.ParentVisible; + else + break; + } + } + } return rv; } @@ -121,7 +134,11 @@ public enum VisibilityStatus /// /// This node passed filter /// - Visible + Visible, + /// + /// This node's parent passed filter + /// + ParentVisible } } From f509a5b3873af4892f1ccee96ca8ff57ec577f19 Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Wed, 20 Sep 2017 23:24:48 +0200 Subject: [PATCH 07/11] Added Cue text to search textbox --- .../ObjectExplorer/ObjectExplorer.cs | 9 +++-- .../ObjectExplorer/SearchTextBox.cs | 9 ++--- Src/SwqlStudio/SwqlStudio.csproj | 1 + Src/SwqlStudio/Utils/Win32.cs | 36 +++++++++++++++++++ 4 files changed, 43 insertions(+), 12 deletions(-) create mode 100644 Src/SwqlStudio/Utils/Win32.cs diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index f6d5f7fb1..20355a931 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -12,6 +12,7 @@ using System.Windows.Forms; using SolarWinds.Logging; using SwqlStudio.Metadata; +using SwqlStudio.Utils; using TextBox = System.Windows.Forms.TextBox; using TreeNode = System.Windows.Forms.TreeNode; using TreeView = System.Windows.Forms.TreeView; @@ -43,9 +44,6 @@ class ObjectExplorer : Control private Point _lastLocation; private TreeNode _dragNode; - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - public static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw); - private const int SB_HORZ = 0x0; public IApplicationService ApplicationService { get; set; } @@ -94,7 +92,7 @@ public ObjectExplorer() _tree.NodeMouseDoubleClick += _tree_NodeMouseDoubleClick; treeSearch.TextChanged += (sender, e) => { SetFilter(((TextBox) sender).Text); }; - + treeSearch.SetCueText("Search (Ctrl + \\)"); _tableContextMenuItems = new Dictionary(); _serverContextMenuItems = new Dictionary(); @@ -161,7 +159,8 @@ private void UpdateDrawnNodes() display.EnsureVisible(); }); - SetScrollPos(_tree.Handle, SB_HORZ, 0, false); + + _tree.SetHorizontalScroll(0); } UpdateDrawnNodesSelection(); diff --git a/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs index 708dfdd45..e16dcaa88 100644 --- a/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs +++ b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs @@ -3,17 +3,12 @@ using System.Drawing; using System.Windows.Forms; using SwqlStudio.Properties; +using SwqlStudio.Utils; namespace SwqlStudio { internal class SearchTextBox : TextBox { - private const int EM_SETMARGINS = 0xd3; - - [System.Runtime.InteropServices.DllImport("user32.dll")] - private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); - - private readonly PictureBox _searchPictureBox; public SearchTextBox() @@ -28,7 +23,7 @@ public SearchTextBox() Controls.Add(_searchPictureBox); // Send EM_SETMARGINS to prevent text from disappearing underneath the button - SendMessage(Handle, EM_SETMARGINS, (IntPtr)2, (IntPtr)(16 << 16)); + Win32.SendMessage(Handle, Win32.EM_SETMARGINS, (IntPtr)2, (IntPtr)(16 << 16)); SearchImage = Resources.Search; } diff --git a/Src/SwqlStudio/SwqlStudio.csproj b/Src/SwqlStudio/SwqlStudio.csproj index 6e2875c02..b68b3f5ab 100644 --- a/Src/SwqlStudio/SwqlStudio.csproj +++ b/Src/SwqlStudio/SwqlStudio.csproj @@ -214,6 +214,7 @@ SubscriptionTab.cs + Component diff --git a/Src/SwqlStudio/Utils/Win32.cs b/Src/SwqlStudio/Utils/Win32.cs new file mode 100644 index 000000000..8e5748e82 --- /dev/null +++ b/Src/SwqlStudio/Utils/Win32.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; + +namespace SwqlStudio.Utils +{ + internal static class Win32 + { + public const int SB_HORZ = 0x0; + public const int EM_SETMARGINS = 0xd3; + public const int EM_SETCUEBANNER = 0x1501; + + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + public static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw); + + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wp, [MarshalAs(UnmanagedType.LPWStr)] string lp); + + + + public static void SetHorizontalScroll(this Control control, int scroll) + { + SetScrollPos(control.Handle, SB_HORZ, scroll, false); + } + + public static void SetCueText(this TextBox textbox, string text) + { + SendMessage(textbox.Handle, EM_SETCUEBANNER, 0, text); + } + } +} From f832ec89c0d369208af8c28888f90b078c479af4 Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Wed, 20 Sep 2017 23:35:01 +0200 Subject: [PATCH 08/11] Added hotkey to focus for search --- Src/SwqlStudio/MainForm.Designer.cs | 50 ++- Src/SwqlStudio/MainForm.cs | 5 + Src/SwqlStudio/MainForm.resx | 382 +++++++++--------- .../ObjectExplorer/ObjectExplorer.cs | 15 +- 4 files changed, 239 insertions(+), 213 deletions(-) diff --git a/Src/SwqlStudio/MainForm.Designer.cs b/Src/SwqlStudio/MainForm.Designer.cs index 093039ce6..5e8437430 100644 --- a/Src/SwqlStudio/MainForm.Designer.cs +++ b/Src/SwqlStudio/MainForm.Designer.cs @@ -69,6 +69,7 @@ private void InitializeComponent() this.objectExplorer = new SwqlStudio.ObjectExplorer(); this.ObjectExplorerImageList = new System.Windows.Forms.ImageList(this.components); this.startTimer = new System.Windows.Forms.Timer(this.components); + this.searchInTreeHotKeyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this.menu.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); @@ -77,15 +78,15 @@ private void InitializeComponent() this.splitContainer1.SuspendLayout(); this.SuspendLayout(); // - // separatorAboveNotificationListenerActive - // - this.separatorAboveNotificationListenerActive.Name = "separatorAboveNotificationListenerActive"; - this.separatorAboveNotificationListenerActive.Size = new System.Drawing.Size(214, 6); - // // toolStripSeparator1 // toolStripSeparator1.Name = "toolStripSeparator1"; - toolStripSeparator1.Size = new System.Drawing.Size(214, 6); + toolStripSeparator1.Size = new System.Drawing.Size(216, 6); + // + // separatorAboveNotificationListenerActive + // + this.separatorAboveNotificationListenerActive.Name = "separatorAboveNotificationListenerActive"; + this.separatorAboveNotificationListenerActive.Size = new System.Drawing.Size(216, 6); // // menu // @@ -114,7 +115,8 @@ private void InitializeComponent() this.separatorAboveNotificationListenerActive, this.menuNotificationListenerActive, toolStripSeparator1, - this.menuFileExit}); + this.menuFileExit, + this.searchInTreeHotKeyToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); this.fileToolStripMenuItem.Text = "&File"; @@ -124,7 +126,7 @@ private void InitializeComponent() // this.menuFileNew.Name = "menuFileNew"; this.menuFileNew.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N))); - this.menuFileNew.Size = new System.Drawing.Size(217, 22); + this.menuFileNew.Size = new System.Drawing.Size(219, 22); this.menuFileNew.Text = "&New"; this.menuFileNew.Click += new System.EventHandler(this.menuFileNew_Click); // @@ -132,7 +134,7 @@ private void InitializeComponent() // this.menuFileTabPage.Name = "menuFileTabPage"; this.menuFileTabPage.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.T))); - this.menuFileTabPage.Size = new System.Drawing.Size(217, 22); + this.menuFileTabPage.Size = new System.Drawing.Size(219, 22); this.menuFileTabPage.Text = "Tab Page"; this.menuFileTabPage.Click += new System.EventHandler(this.menuFileTabPage_Click); // @@ -140,7 +142,7 @@ private void InitializeComponent() // this.menuFileOpen.Name = "menuFileOpen"; this.menuFileOpen.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); - this.menuFileOpen.Size = new System.Drawing.Size(217, 22); + this.menuFileOpen.Size = new System.Drawing.Size(219, 22); this.menuFileOpen.Text = "&Open"; this.menuFileOpen.Click += new System.EventHandler(this.menuFileOpen_Click); // @@ -148,14 +150,14 @@ private void InitializeComponent() // this.menuFileSave.Name = "menuFileSave"; this.menuFileSave.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); - this.menuFileSave.Size = new System.Drawing.Size(217, 22); + this.menuFileSave.Size = new System.Drawing.Size(219, 22); this.menuFileSave.Text = "&Save"; this.menuFileSave.Click += new System.EventHandler(this.menuFileSave_Click); // // menuFileSaveAs // this.menuFileSaveAs.Name = "menuFileSaveAs"; - this.menuFileSaveAs.Size = new System.Drawing.Size(217, 22); + this.menuFileSaveAs.Size = new System.Drawing.Size(219, 22); this.menuFileSaveAs.Text = "&Save As"; this.menuFileSaveAs.Click += new System.EventHandler(this.menuFileSaveAs_Click); // @@ -164,7 +166,7 @@ private void InitializeComponent() this.menuFileClose.Name = "menuFileClose"; this.menuFileClose.ShortcutKeyDisplayString = "Ctrl+W, Ctrl-F4"; this.menuFileClose.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.W))); - this.menuFileClose.Size = new System.Drawing.Size(217, 22); + this.menuFileClose.Size = new System.Drawing.Size(219, 22); this.menuFileClose.Text = "&Close"; this.menuFileClose.Click += new System.EventHandler(this.menuFileClose_Click); // @@ -172,7 +174,7 @@ private void InitializeComponent() // this.menuFileClose2.Name = "menuFileClose2"; this.menuFileClose2.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F4))); - this.menuFileClose2.Size = new System.Drawing.Size(217, 22); + this.menuFileClose2.Size = new System.Drawing.Size(219, 22); this.menuFileClose2.Text = "Close"; this.menuFileClose2.Visible = false; this.menuFileClose2.Click += new System.EventHandler(this.menuFileClose_Click); @@ -182,14 +184,14 @@ private void InitializeComponent() this.menuNotificationListenerActive.Checked = true; this.menuNotificationListenerActive.CheckState = System.Windows.Forms.CheckState.Checked; this.menuNotificationListenerActive.Name = "menuNotificationListenerActive"; - this.menuNotificationListenerActive.Size = new System.Drawing.Size(217, 22); + this.menuNotificationListenerActive.Size = new System.Drawing.Size(219, 22); this.menuNotificationListenerActive.Text = "Notification Listener Active"; this.menuNotificationListenerActive.Click += new System.EventHandler(this.menuNotificationListenerActive_Click); // // menuFileExit // this.menuFileExit.Name = "menuFileExit"; - this.menuFileExit.Size = new System.Drawing.Size(217, 22); + this.menuFileExit.Size = new System.Drawing.Size(219, 22); this.menuFileExit.Text = "&Exit"; this.menuFileExit.Click += new System.EventHandler(this.menuFileExit_Click); // @@ -287,7 +289,7 @@ private void InitializeComponent() this.byHierarchyToolStripMenuItem, this.noGroupingToolStripMenuItem}); this.groupEntityTreeToolStripMenuItem.Name = "groupEntityTreeToolStripMenuItem"; - this.groupEntityTreeToolStripMenuItem.Size = new System.Drawing.Size(170, 22); + this.groupEntityTreeToolStripMenuItem.Size = new System.Drawing.Size(188, 22); this.groupEntityTreeToolStripMenuItem.Text = "&Group Entity Tree"; // // byNamespaceToolStripMenuItem @@ -324,7 +326,7 @@ private void InitializeComponent() this.enableAutocompleteToolStripMenuItem.CheckOnClick = true; this.enableAutocompleteToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.enableAutocompleteToolStripMenuItem.Name = "enableAutocompleteToolStripMenuItem"; - this.enableAutocompleteToolStripMenuItem.Size = new System.Drawing.Size(170, 22); + this.enableAutocompleteToolStripMenuItem.Size = new System.Drawing.Size(188, 22); this.enableAutocompleteToolStripMenuItem.Text = "Enable Autocomplete"; this.enableAutocompleteToolStripMenuItem.CheckedChanged += new System.EventHandler(this.enableAutocompleteToolStripMenuItem_CheckedChanged); // @@ -353,6 +355,7 @@ private void InitializeComponent() this.fileTabs.Name = "fileTabs"; this.fileTabs.SelectedIndex = 0; this.fileTabs.Size = new System.Drawing.Size(632, 571); + this.fileTabs.SizeMode = System.Windows.Forms.TabSizeMode.Fixed; this.fileTabs.TabIndex = 1; this.fileTabs.TabStop = false; this.fileTabs.DragDrop += new System.Windows.Forms.DragEventHandler(this.TextEditorDragDrop); @@ -412,6 +415,16 @@ private void InitializeComponent() // this.startTimer.Tick += new System.EventHandler(this.startTimer_Tick); // + // searchInTreeHotKeyToolStripMenuItem + // + this.searchInTreeHotKeyToolStripMenuItem.Name = "searchInTreeHotKeyToolStripMenuItem"; + this.searchInTreeHotKeyToolStripMenuItem.ShortcutKeyDisplayString = "Ctrl+\\"; + this.searchInTreeHotKeyToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Oem5))); + this.searchInTreeHotKeyToolStripMenuItem.Size = new System.Drawing.Size(219, 22); + this.searchInTreeHotKeyToolStripMenuItem.Text = "SearchInTreeHotKey"; + this.searchInTreeHotKeyToolStripMenuItem.Visible = false; + this.searchInTreeHotKeyToolStripMenuItem.Click += new System.EventHandler(this.searchInTreeHotKeyToolStripMenuItem_Click); + // // MainForm // this.AllowDrop = true; @@ -478,6 +491,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem menuFileClose2; private System.Windows.Forms.ToolStripMenuItem menuFileTabPage; private System.Windows.Forms.ToolStripSeparator separatorAboveNotificationListenerActive; + private System.Windows.Forms.ToolStripMenuItem searchInTreeHotKeyToolStripMenuItem; } } diff --git a/Src/SwqlStudio/MainForm.cs b/Src/SwqlStudio/MainForm.cs index 1fff82598..34d54a689 100644 --- a/Src/SwqlStudio/MainForm.cs +++ b/Src/SwqlStudio/MainForm.cs @@ -586,5 +586,10 @@ private void preferencesToolStripMenuItem_DropDownOpening(object sender, EventAr { enableAutocompleteToolStripMenuItem.Checked = Settings.Default.AutocompleteEnabled; } + + private void searchInTreeHotKeyToolStripMenuItem_Click(object sender, EventArgs e) + { + objectExplorer.FocusSearch(); + } } } diff --git a/Src/SwqlStudio/MainForm.resx b/Src/SwqlStudio/MainForm.resx index 95c3809f0..948d6b925 100644 --- a/Src/SwqlStudio/MainForm.resx +++ b/Src/SwqlStudio/MainForm.resx @@ -139,200 +139,200 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAG - LQAAAk1TRnQBSQFMAgEBDQEAAZQBAQGUAQEBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA - AwABQAMAAQEBAAEgBgABQBIAQP/AAAT/A18B/wPAAf8D9AH/A9YB/wNKKf/AAAT/A7QB/wMoAf8DKAH/ - AygB/wOiKf/AAAT/A/IB/wNBAf8D6AH/A0MB/wPoAf8BJQELAQAB/wElAQsBAAH/ASUBCwEAAf8BJQEL - AQAB/wElAQsBAAH/ASUBCwEAAf8BJQELAQAB/wElAQsBAAn/wAAE/wP5Af8DjQH/A2gB/wNyAf8D9wH/ - Ad8BzgHDAf8B3QHIAbsB/wHbAb8BrQH/AdsBuwGnAf8B2wG7AacB/wHbAbsBpwH/Ac8BtAGjAf8BJQEL - AQAJ/8AABP8D/QH/A9sB/wMoAf8DyQH/A/sB/wH7AewB4wH/AaQBjQFAAf8BmgGDATQB/wH2AdYBwgH/ - AYgBMwEgAf8BgwEtARoB/wHPAbQBowH/ASUBCwEACf/AAAj/AboBpQGWAf8D/gH/A/4B/wP+Af8B/QH7 - AfkB/wH9AfcB8wH/AfsB7AHjAf8B+gHnAdsB/wH4AeEB0gH/AfcB2wHJAf8B0AG5AasB/wElAQsBAAn/ - wAAI/wG+AakBmgH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaMBjgFAAf8BmgGDATQB/wH7AewB4wH/ - AYkBMwEhAf8BgwEtARoB/wHRAcEBtgH/ASUBCwEACf/AAAj/AcMBrgGeAf8D/gH/A/4B/wP+Af8D/gH/ - A/4B/wH9AfcB8wH/AfwB8gHsAf8B+wHsAeMB/wH6AecB2wH/AdEBwQG2Af8BJQELAQAJ/8AACP8ByAGy - AaMB/wP+Af8BugGmAZgB/wG0AaABkQH/A/4B/wGkAY4BQAH/AZkBhAE0Af8B/QH3AfMB/wGIATMBIAH/ - AYMBLQEaAf8B0QHBAbYB/wElAQsBAAn/wAAI/wHMAbYBpwH/A/4B/wP+Af8D/gH/A/4B/wP+Af8D/gH/ - Af0B+wH5Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8BJQELAQAJ/8AACP8B6gGqAYsB/wHqAaoBiwH/ - AeoBqgGLAf8B6QGlAYQB/wHnAZcBMAH/AeYBjgEkAf8B4wE/AQwB/wHjATgBAgH/AeIBNAEAAf8B4gE0 - AQAB/wHiATQBAAH/AcgBJAEACf/AAAj/AeoBqgGLAv8BwgGiAf8B/gHAAZ8B/wH9Ab0BmgH/AfsBtQGQ - Af8B+gGwAYsB/wH4AacBPwH/AfYBogE5Af8B9QGdATMB/wH1AZkBLAH/AfMBlQEnAf8BzQEnAQAJ/8AA - CP8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6gGqAYsB/wHpAaEBQQH/AegBmwE4Af8B5gGOASQB/wHl - AYcBGgH/AeQBgQEQAf8B5AE9AQgB/wHjATgBAAH/AeIBNAEACf/AAED/wABA//8AaQAB0wHfAesB/wHo + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAC + LQAAAk1TRnQBSQFMAgEBDQEAAZwBAQGcAQEBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABQAMAAQEBAAEgBgABQBIAQP/AAAT/A14B/wPAAf8D9AH/A9YB/wNJKf/AAAT/A7QB/wMnAf8DJwH/ + AycB/wOiKf/AAAT/A/IB/wNAAf8D6AH/A0IB/wPoAf8BJAEKAQAB/wEkAQoBAAH/ASQBCgEAAf8BJAEK + AQAB/wEkAQoBAAH/ASQBCgEAAf8BJAEKAQAB/wEkAQoBAAn/wAAE/wP5Af8DjQH/A2cB/wNxAf8D9wH/ + Ad8BzgHDAf8B3QHIAbsB/wHbAb8BrQH/AdsBuwGnAf8B2wG7AacB/wHbAbsBpwH/Ac8BtAGjAf8BJAEK + AQAJ/8AABP8D/QH/A9sB/wMnAf8DyQH/A/sB/wH7AewB4wH/AaQBjQE/Af8BmgGDATMB/wH2AdYBwgH/ + AYgBMgEfAf8BgwEsARkB/wHPAbQBowH/ASQBCgEACf/AAAj/AboBpQGWAf8D/gH/A/4B/wP+Af8B/QH7 + AfkB/wH9AfcB8wH/AfsB7AHjAf8B+gHnAdsB/wH4AeEB0gH/AfcB2wHJAf8B0AG5AasB/wEkAQoBAAn/ + wAAI/wG+AakBmgH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaMBjgE/Af8BmgGDATMB/wH7AewB4wH/ + AYkBMgEgAf8BgwEsARkB/wHRAcEBtgH/ASQBCgEACf/AAAj/AcMBrgGeAf8D/gH/A/4B/wP+Af8D/gH/ + A/4B/wH9AfcB8wH/AfwB8gHsAf8B+wHsAeMB/wH6AecB2wH/AdEBwQG2Af8BJAEKAQAJ/8AACP8ByAGy + AaMB/wP+Af8BugGmAZgB/wG0AaABkQH/A/4B/wGkAY4BPwH/AZkBhAEzAf8B/QH3AfMB/wGIATIBHwH/ + AYMBLAEZAf8B0QHBAbYB/wEkAQoBAAn/wAAI/wHMAbYBpwH/A/4B/wP+Af8D/gH/A/4B/wP+Af8D/gH/ + Af0B+wH5Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8BJAEKAQAJ/8AACP8B6gGqAYsB/wHqAaoBiwH/ + AeoBqgGLAf8B6QGlAYQB/wHnAZcBLwH/AeYBjgEjAf8B4wE+AQsB/wHjATcBAQH/AeIBMwEAAf8B4gEz + AQAB/wHiATMBAAH/AcgBIwEACf/AAAj/AeoBqgGLAv8BwgGiAf8B/gHAAZ8B/wH9Ab0BmgH/AfsBtQGQ + Af8B+gGwAYsB/wH4AacBPgH/AfYBogE4Af8B9QGdATIB/wH1AZkBKwH/AfMBlQEmAf8BzQEmAQAJ/8AA + CP8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6gGqAYsB/wHpAaEBQAH/AegBmwE3Af8B5gGOASMB/wHl + AYcBGQH/AeQBgQEPAf8B5AE8AQcB/wHjATcBAAH/AeIBMwEACf/AAED/wABA//8AaQAB0wHfAesB/wHo AfQC/wHoAfQC/wHTAd8B6wH/CAAD9AH/A/QB/wP1Bf8D9gH/A/QB/wP0Df8D/gH/A/YB/wP1Af8D/Qn/ - EAAB7wHmAdwB/wHOAbUBkwH/AbgBkwFAAf8BsgGIAS4B/wG4AZIBPwH/Ac4BtAGQAf8B7gHmAdsB/3gA - A98B/wHoAfQC/wGYAaQBsAH/AZgBpAGwAf8B6AH0Av8D3wH/BAAD9gH/A14B/wPAAf8D9AH/A9YB/wNJ - Af8D9Qn/A/4B/wP2Af8BbwGuAdsB/wFvAa4B2wH/A/UB/wP9Bf8IAAH9AfsB+gH/AcgBrAGEAf8BoQFP - AQAB/wGdAUkBAAH/AZwBRwEAAf8BpAFVAQAB/wGdAUgBAAH/AZ0BSAEAAf8BnwFOAQAB/wHHAaoBgQH/ - AfwB+wH5Af8cAAOGAf8DHAH/DAADHAH/A4YB/zQAA98B/wP0Af8BTAGoAeYB/wEcAWoBtgH/ARQBagG+ - Af8BRAGoAe4B/wHoAfQC/wHTAd8B6wH/A/oB/wO0Af8DJwH/AycB/wMnAf8DogH/A/oF/wP+Af8D9gH/ - AW8BrgHbAf8BDwFtAccB/wEPAW0BxwH/AW8BrgHbAf8D9QH/A/0B/wQAAfwB+wH5Af8BvAGWAUUB/wGg - AUwBAAH/AaEBTQEAAf8BngFIAQAB/wHKAaoBVgH/AfYB8QHoAf8BzQGvAWAB/wGeAUgBAAH/AaEBTQEA - Af8BoQFMAQAB/wG6AZQBQQH/AfwB+gH4Af8UAAOGAf8DAAH/FwAB/wOGAf84AAFMAagB5gH/ARwBagG2 - Af8BFAFqAb4B/wEUAWoBvgH/AZgBpAGwAf8B6AH0Av8D/gH/A/IB/wNAAf8D6AH/A0IB/wPoAf8D/gH/ - A/QB/wP0Af8D9AH/AZQBvQHgAf8BDwFtAccB/wEPAW0BxwH/AQ8BbQHHAf8BbwGuAdsB/wP1Af8EAAHM - Aa8BiAH/AaUBUQEAAf8BpQFRAQAB/wGlAVIBAAH/AaIBTAEAAf8B5gHWAbsF/wHrAd4ByAH/AaMBTgEA - Af8BpQFRAQAB/wGlAVEBAAH/AaUBUQEAAf8BygGtAYQB/xQAAzYB/wMAAf8XAAH/AzYB/zAAASUBagGu - Af8BJQFqAa4B/wE9AWYBnQH/AT0BZgGdAf8BHAFqAbYB/wEcAWoBtgH/AZgBpAGwAf8B6AH0Bv8D+QH/ - A40B/wNnAf8DcQH/A/cF/wP0Af8BDwFtAccB/wEPAW0BxwH/AQ8BbQHHAf8BlAG9AeAB/wEPAW0BxwH/ - AQ8BbQHHAf8BlAG9AeAB/wP2Af8B8gHqAeEB/wGpAVgBAAH/AaoBVgEAAf8BqgFWAQAB/wGqAVYBAAH/ - AacBUQEAAf8B5QHTAbYF/wHqAdwBwwH/AagBUwEAAf8BqgFVAQAB/wGqAVYBAAH/AaoBVgEAAf8BqQFX - AQAB/wHwAekB3gH/EAADNgH/AwAB/xcAAf8DNgH/HAAD3wH/A98B/wwAASUBagGuAf8BtQH6Av8BzQH2 - Av8BzQH2Av8BTAGoAeYB/wFMAagB5gH/AegB9AL/AdMB3wHrBf8D/QH/A9sB/wMnAf8DyQH/A/sF/wP0 - Af8BDwFtAccB/wP0Af8D9AH/A/QB/wGUAb0B4AH/AZQBvQHgAf8D9gH/A/4B/wHWAb4BnQH/AbABXQEA - Af8BrgFaAQAB/wGvAVsBAAH/Aa8BWwEAAf8BrAFWAQAB/wHmAdUBtgX/AesB3AHEAf8BrQFYAQAB/wGv - AVoBAAH/Aa8BWwEAAf8BrgFbAQAB/wGvAVoBAAH/AdMBuQGWAf8TAAH/A8AB/xQAA8AB/wMAAf8YAAHT - Ad8B6wH/AegB9AL/AegB9AL/AdMB3wHrAf8IAAE9AWYBnQH/Ac0B9gL/AckB9gL/AWkBpAHRAf8BaQGk - AdEB/wHJAfYC/wPlAf8EAAj/A/YB/wP0Af8D9AH/A/0F/wP0Af8BDwFtAccB/wP0Af8D9gH/AW8BrgHb - Af8BbwGuAdsB/wP0Af8D/AX/AcoBqQFdAf8BwAGOARkB/wG1AWIBAAH/AbMBXgEAAf8BtAFgAQAB/wGy - AVwBAAH/AegB1gG4Bf8B7AHeAcUB/wGyAV0BAAH/AbQBXwEAAf8BtAFgAQAB/wG0AWABAAH/AbUBYAEA - Af8BxAGfAUoB/w8AAf8DTwH/HAADTwH/AwAB/xAAA98B/wHoAfQC/wGYAaQBsAH/AZgBpAGwAf8B6AH0 - Av8D3wH/BAABPQFmAZ0B/wHNAfYC/wFpAaQB0QH/ATkBZgGhAf8BOQFmAaEB/wFpAaQB0QH/A/QB/wPf - Bf8D/gH/A/YB/wFvAa4B2wH/AW8BrgHbAf8D9QH/A/0B/wP0Af8BDwFtAccB/wP0Af8BbwGuAdsB/wEP - AW0BxwH/AQ8BbQHHAf8BbwGuAdsB/wP1Af8D/QH/AckBpgFUAf8ByQGbASsB/wHFAZQBJAH/Ab4BiQEP - Af8BugGAAQAB/wG3AWABAAH/AesB2QG7Bf8B7wHhAcgB/wG3AWIBAAH/AbkBZAEAAf8BuQFkAQAB/wG5 - AWQBAAH/AboBZAEAAf8BwwGaAT4B/xAAAxwB/wPAAf8UAAPAAf8DHAH/EAAB0wHfAesB/wHoAfQC/wFE - AagB7gH/ARQBagG+Af8BFAFqAb4B/wFEAagB7gH/Ac0B9gL/Ac0B9gL/ASUBagGuAf8BtQH6Av8BRAGo - Ae4B/wEUAWoBvgH/AQwBagHHAf8BDAFqAccB/wGMAaQBvQH/AdwB9AL/A/4B/wP2Af8BbwGuAdsB/wEP - AW0BxwH/AQ8BbQHHAf8BbwGuAdsB/wP0Af8D9AH/AQ8BbQHHAf8D9AH/AZQBvQHgAf8BDwFtAccB/wEP - AW0BxwH/AQ8BbQHHAf8BbwGuAdsB/wP1Af8B0AGvAYEB/wHOAaABMAH/AcsBnAEvAf8BzAGcAS8B/wHK - AZkBJwH/AcMBjQETAf8B5QHUAbUF/wHnAdgBvAH/Ab4BgwEAAf8BwAGHAQYB/wHBAYgBCQH/AcIBigEM - Af8BxgGQARIB/wHMAagBVwH/EAADNgH/AxwB/xQAAxwB/wM2Af8QAAHoAfQC/wGYAaQBsAH/ARQBagG+ - Af8BFAFqAb4B/wEUAWoBvgH/ARQBagG+Af8BPQFmAZ0B/wE9AWYBnQH/ASUBagGuAf8BJQFqAa4B/wEU - AWoBvgH/ARQBagG+Af8BDAFqAccB/wEMAWoBxwH/AYwBpAG9Af8B3AH0Av8D9gH/AW8BrgHbAf8BDwFt - AccB/wEPAW0BxwH/AQ8BbQHHAf8BDwFtAccB/wFvAa4B2wH/AQ8BbQHHAf8BDwFtAccB/wEPAW0BxwH/ - AQ8BbQHHAf8BlAG9AeAB/wEPAW0BxwH/AQ8BbQHHAf8BlAG9AeAB/wP2Af8B3QHHAasB/wHTAaYBOQH/ - AdABogEyAf8B0AGhATMB/wHQAaEBMwH/AdABnwEuAf8BywGkAUMB/wHUAcMBpQH/AcoBpAFDAf8BzQGb - ASYB/wHOAZwBKQH/Ac4BnAEpAf8BzgGcASgB/wHPAZ0BKAH/AdoBwwGiAf8QAAM2Af8DHAH/FAADHAH/ - AzYB/xAAAegB9AL/AZgBpAGwAf8BFAFqAb4B/wEUAWoBvgH/AQwBagHHAf8BDAFqAccB/wEUAWoBvgH/ - AUQBqAHuAf8B6gH2Av8B6gH2Av8D9gH/A/YB/wGMAaQBvQH/AYwBpAG9Af8D9AH/A98B/wP3Af8BlAG9 - AeAB/wEPAW0BxwH/AQ8BbQHHAf8BDwFtAccB/wEPAW0BxwH/AQ8BbQHHAf8BbwGuAdsB/wP0Af8D9AH/ - A/QB/wP0Af8BlAG9AeAB/wGUAb0B4AH/A/YB/wP+Af8B9QHvAecB/wHRAagBRwH/AdgBqQE5Af8B1QGm - ATkB/wHVAaYBNwH/AdQBowEyAf8B5QHHAZEB/wHzAeoB2AH/AecBywGZAf8B0wGhAS4B/wHTAaIBMQH/ - AdMBoQEvAf8B1QGjAS4B/wHNAZ0BMgH/AfQB7QHkAf8QAAOGAf8DHAH/FAADHAH/A4YB/xAAAdMB3wHr - Af8B6AH0Av8BRAGoAe4B/wEUAWoBvgH/AQwBagHHAf8BDAFqAccB/wEUAWoBvgH/ARQBagG+Af8BmAGk - AbAB/wHoAfQC/wPfAf8D3wH/AdwB9AL/AdwB9AL/A98B/wQAA/4B/wP3Af8BlAG9AeAB/wEPAW0BxwH/ - AQ8BbQHHAf8BDwFtAccB/wEPAW0BxwH/AQ8BbQHHAf8BbwGuAdsB/wP1Af8D/QH/A/4B/wP3Af8D9gH/ - A/4F/wQAAd0ByAGqAf8B3QGyAUgB/wHaAasBPAH/AdkBqwE9Af8B1wGnATYB/wHxAeYB0wX/AfUB7gHh - Af8B1wGmATYB/wHXAacBNgH/AdgBpwE0Af8B2QGqATkB/wHbAcEBngH/GAADhgH/AxwB/wwAAxwB/wOG - Af8YAAPfAf8B6AH0Av8BmAGkAbAB/wEUAWoBvgH/ARQBagG+Af8BFAFqAb4B/wEUAWoBvgH/AZgBpAGw - Af8B6AH0Av8D3wH/BAAD3wH/A98B/wgABP8D/gH/A/cB/wGUAb0B4AH/AQ8BbQHHAf8BDwFtAccB/wEP - AW0BxwH/AQ8BbQHHAf8BlAG9AeAB/wP2Af8D/gX/A/4B/wP+Cf8EAAH+Av0B/wHZAb8BmgH/AeABtgFO - Af8B3wGxAUEB/wHcAa0BPAH/AdcBtQFfAf8B4gHVAb4B/wHXAbcBgAH/AdsBqgE4Af8B3gGuATsB/wHe - AbEBQwH/AdYBuAGNAf8B/gH9AfwB/1AAAdMB3wHrAf8B6AH0Av8BRAGoAe4B/wEUAWoBvgH/ARQBagG+ - Af8BRAGoAe4B/wHoAfQC/wHTAd8B6wH/GAAI/wP+Af8D9wH/AZQBvQHgAf8BDwFtAccB/wEPAW0BxwH/ - AZQBvQHgAf8D9gH/A/4Z/wwAAd8BywGxAf8B3AG4AV8B/wHjAbgBUAH/AeMBtAFEAf8B3QGuATwB/wHh - AbIBQAH/AeIBtgFKAf8B2wGzAVYB/wHeAcgBqgH/Av4B/QH/WAAD3wH/AegB9AL/AZgBpAGwAf8BmAGk + EAAB7wHmAdwB/wHOAbUBkwH/AbgBkwE/Af8BsgGIAS0B/wG4AZIBPgH/Ac4BtAGQAf8B7gHmAdsB/3gA + A98B/wHoAfQC/wGYAaQBsAH/AZgBpAGwAf8B6AH0Av8D3wH/BAAD9gH/A10B/wPAAf8D9AH/A9YB/wNI + Af8D9Qn/A/4B/wP2Af8BbgGuAdsB/wFuAa4B2wH/A/UB/wP9Bf8IAAH9AfsB+gH/AcgBrAGEAf8BoQFO + AQAB/wGdAUgBAAH/AZwBRgEAAf8BpAFUAQAB/wGdAUcBAAH/AZ0BRwEAAf8BnwFNAQAB/wHHAaoBgQH/ + AfwB+wH5Af8cAAOGAf8DGwH/DAADGwH/A4YB/zQAA98B/wP0Af8BSwGoAeYB/wEbAWkBtgH/ARMBaQG+ + Af8BQwGoAe4B/wHoAfQC/wHTAd8B6wH/A/oB/wO0Af8DJgH/AyYB/wMmAf8DogH/A/oF/wP+Af8D9gH/ + AW4BrgHbAf8BDgFsAccB/wEOAWwBxwH/AW4BrgHbAf8D9QH/A/0B/wQAAfwB+wH5Af8BvAGWAUQB/wGg + AUsBAAH/AaEBTAEAAf8BngFHAQAB/wHKAaoBVQH/AfYB8QHoAf8BzQGvAV8B/wGeAUcBAAH/AaEBTAEA + Af8BoQFLAQAB/wG6AZQBQAH/AfwB+gH4Af8UAAOGAf8DAAH/FwAB/wOGAf84AAFLAagB5gH/ARsBaQG2 + Af8BEwFpAb4B/wETAWkBvgH/AZgBpAGwAf8B6AH0Av8D/gH/A/IB/wM/Af8D6AH/A0EB/wPoAf8D/gH/ + A/QB/wP0Af8D9AH/AZQBvQHgAf8BDgFsAccB/wEOAWwBxwH/AQ4BbAHHAf8BbgGuAdsB/wP1Af8EAAHM + Aa8BiAH/AaUBUAEAAf8BpQFQAQAB/wGlAVEBAAH/AaIBSwEAAf8B5gHWAbsF/wHrAd4ByAH/AaMBTQEA + Af8BpQFQAQAB/wGlAVABAAH/AaUBUAEAAf8BygGtAYQB/xQAAzUB/wMAAf8XAAH/AzUB/zAAASQBaQGu + Af8BJAFpAa4B/wE8AWUBnQH/ATwBZQGdAf8BGwFpAbYB/wEbAWkBtgH/AZgBpAGwAf8B6AH0Bv8D+QH/ + A40B/wNmAf8DcAH/A/cF/wP0Af8BDgFsAccB/wEOAWwBxwH/AQ4BbAHHAf8BlAG9AeAB/wEOAWwBxwH/ + AQ4BbAHHAf8BlAG9AeAB/wP2Af8B8gHqAeEB/wGpAVcBAAH/AaoBVQEAAf8BqgFVAQAB/wGqAVUBAAH/ + AacBUAEAAf8B5QHTAbYF/wHqAdwBwwH/AagBUgEAAf8BqgFUAQAB/wGqAVUBAAH/AaoBVQEAAf8BqQFW + AQAB/wHwAekB3gH/EAADNQH/AwAB/xcAAf8DNQH/HAAD3wH/A98B/wwAASQBaQGuAf8BtQH6Av8BzQH2 + Av8BzQH2Av8BSwGoAeYB/wFLAagB5gH/AegB9AL/AdMB3wHrBf8D/QH/A9sB/wMmAf8DyQH/A/sF/wP0 + Af8BDgFsAccB/wP0Af8D9AH/A/QB/wGUAb0B4AH/AZQBvQHgAf8D9gH/A/4B/wHWAb4BnQH/AbABXAEA + Af8BrgFZAQAB/wGvAVoBAAH/Aa8BWgEAAf8BrAFVAQAB/wHmAdUBtgX/AesB3AHEAf8BrQFXAQAB/wGv + AVkBAAH/Aa8BWgEAAf8BrgFaAQAB/wGvAVkBAAH/AdMBuQGWAf8TAAH/A8AB/xQAA8AB/wMAAf8YAAHT + Ad8B6wH/AegB9AL/AegB9AL/AdMB3wHrAf8IAAE8AWUBnQH/Ac0B9gL/AckB9gL/AWgBpAHRAf8BaAGk + AdEB/wHJAfYC/wPlAf8EAAj/A/YB/wP0Af8D9AH/A/0F/wP0Af8BDgFsAccB/wP0Af8D9gH/AW4BrgHb + Af8BbgGuAdsB/wP0Af8D/AX/AcoBqQFcAf8BwAGOARgB/wG1AWEBAAH/AbMBXQEAAf8BtAFfAQAB/wGy + AVsBAAH/AegB1gG4Bf8B7AHeAcUB/wGyAVwBAAH/AbQBXgEAAf8BtAFfAQAB/wG0AV8BAAH/AbUBXwEA + Af8BxAGfAUkB/w8AAf8DTgH/HAADTgH/AwAB/xAAA98B/wHoAfQC/wGYAaQBsAH/AZgBpAGwAf8B6AH0 + Av8D3wH/BAABPAFlAZ0B/wHNAfYC/wFoAaQB0QH/ATgBZQGhAf8BOAFlAaEB/wFoAaQB0QH/A/QB/wPf + Bf8D/gH/A/YB/wFuAa4B2wH/AW4BrgHbAf8D9QH/A/0B/wP0Af8BDgFsAccB/wP0Af8BbgGuAdsB/wEO + AWwBxwH/AQ4BbAHHAf8BbgGuAdsB/wP1Af8D/QH/AckBpgFTAf8ByQGbASoB/wHFAZQBIwH/Ab4BiQEO + Af8BugGAAQAB/wG3AV8BAAH/AesB2QG7Bf8B7wHhAcgB/wG3AWEBAAH/AbkBYwEAAf8BuQFjAQAB/wG5 + AWMBAAH/AboBYwEAAf8BwwGaAT0B/xAAAxsB/wPAAf8UAAPAAf8DGwH/EAAB0wHfAesB/wHoAfQC/wFD + AagB7gH/ARMBaQG+Af8BEwFpAb4B/wFDAagB7gH/Ac0B9gL/Ac0B9gL/ASQBaQGuAf8BtQH6Av8BQwGo + Ae4B/wETAWkBvgH/AQsBaQHHAf8BCwFpAccB/wGMAaQBvQH/AdwB9AL/A/4B/wP2Af8BbgGuAdsB/wEO + AWwBxwH/AQ4BbAHHAf8BbgGuAdsB/wP0Af8D9AH/AQ4BbAHHAf8D9AH/AZQBvQHgAf8BDgFsAccB/wEO + AWwBxwH/AQ4BbAHHAf8BbgGuAdsB/wP1Af8B0AGvAYEB/wHOAaABLwH/AcsBnAEuAf8BzAGcAS4B/wHK + AZkBJgH/AcMBjQESAf8B5QHUAbUF/wHnAdgBvAH/Ab4BgwEAAf8BwAGHAQUB/wHBAYgBCAH/AcIBigEL + Af8BxgGQAREB/wHMAagBVgH/EAADNQH/AxsB/xQAAxsB/wM1Af8QAAHoAfQC/wGYAaQBsAH/ARMBaQG+ + Af8BEwFpAb4B/wETAWkBvgH/ARMBaQG+Af8BPAFlAZ0B/wE8AWUBnQH/ASQBaQGuAf8BJAFpAa4B/wET + AWkBvgH/ARMBaQG+Af8BCwFpAccB/wELAWkBxwH/AYwBpAG9Af8B3AH0Av8D9gH/AW4BrgHbAf8BDgFs + AccB/wEOAWwBxwH/AQ4BbAHHAf8BDgFsAccB/wFuAa4B2wH/AQ4BbAHHAf8BDgFsAccB/wEOAWwBxwH/ + AQ4BbAHHAf8BlAG9AeAB/wEOAWwBxwH/AQ4BbAHHAf8BlAG9AeAB/wP2Af8B3QHHAasB/wHTAaYBOAH/ + AdABogExAf8B0AGhATIB/wHQAaEBMgH/AdABnwEtAf8BywGkAUIB/wHUAcMBpQH/AcoBpAFCAf8BzQGb + ASUB/wHOAZwBKAH/Ac4BnAEoAf8BzgGcAScB/wHPAZ0BJwH/AdoBwwGiAf8QAAM1Af8DGwH/FAADGwH/ + AzUB/xAAAegB9AL/AZgBpAGwAf8BEwFpAb4B/wETAWkBvgH/AQsBaQHHAf8BCwFpAccB/wETAWkBvgH/ + AUMBqAHuAf8B6gH2Av8B6gH2Av8D9gH/A/YB/wGMAaQBvQH/AYwBpAG9Af8D9AH/A98B/wP3Af8BlAG9 + AeAB/wEOAWwBxwH/AQ4BbAHHAf8BDgFsAccB/wEOAWwBxwH/AQ4BbAHHAf8BbgGuAdsB/wP0Af8D9AH/ + A/QB/wP0Af8BlAG9AeAB/wGUAb0B4AH/A/YB/wP+Af8B9QHvAecB/wHRAagBRgH/AdgBqQE4Af8B1QGm + ATgB/wHVAaYBNgH/AdQBowExAf8B5QHHAZEB/wHzAeoB2AH/AecBywGZAf8B0wGhAS0B/wHTAaIBMAH/ + AdMBoQEuAf8B1QGjAS0B/wHNAZ0BMQH/AfQB7QHkAf8QAAOGAf8DGwH/FAADGwH/A4YB/xAAAdMB3wHr + Af8B6AH0Av8BQwGoAe4B/wETAWkBvgH/AQsBaQHHAf8BCwFpAccB/wETAWkBvgH/ARMBaQG+Af8BmAGk + AbAB/wHoAfQC/wPfAf8D3wH/AdwB9AL/AdwB9AL/A98B/wQAA/4B/wP3Af8BlAG9AeAB/wEOAWwBxwH/ + AQ4BbAHHAf8BDgFsAccB/wEOAWwBxwH/AQ4BbAHHAf8BbgGuAdsB/wP1Af8D/QH/A/4B/wP3Af8D9gH/ + A/4F/wQAAd0ByAGqAf8B3QGyAUcB/wHaAasBOwH/AdkBqwE8Af8B1wGnATUB/wHxAeYB0wX/AfUB7gHh + Af8B1wGmATUB/wHXAacBNQH/AdgBpwEzAf8B2QGqATgB/wHbAcEBngH/GAADhgH/AxsB/wwAAxsB/wOG + Af8YAAPfAf8B6AH0Av8BmAGkAbAB/wETAWkBvgH/ARMBaQG+Af8BEwFpAb4B/wETAWkBvgH/AZgBpAGw + Af8B6AH0Av8D3wH/BAAD3wH/A98B/wgABP8D/gH/A/cB/wGUAb0B4AH/AQ4BbAHHAf8BDgFsAccB/wEO + AWwBxwH/AQ4BbAHHAf8BlAG9AeAB/wP2Af8D/gX/A/4B/wP+Cf8EAAH+Av0B/wHZAb8BmgH/AeABtgFN + Af8B3wGxAUAB/wHcAa0BOwH/AdcBtQFeAf8B4gHVAb4B/wHXAbcBgAH/AdsBqgE3Af8B3gGuAToB/wHe + AbEBQgH/AdYBuAGNAf8B/gH9AfwB/1AAAdMB3wHrAf8B6AH0Av8BQwGoAe4B/wETAWkBvgH/ARMBaQG+ + Af8BQwGoAe4B/wHoAfQC/wHTAd8B6wH/GAAI/wP+Af8D9wH/AZQBvQHgAf8BDgFsAccB/wEOAWwBxwH/ + AZQBvQHgAf8D9gH/A/4Z/wwAAd8BywGxAf8B3AG4AV4B/wHjAbgBTwH/AeMBtAFDAf8B3QGuATsB/wHh + AbIBPwH/AeIBtgFJAf8B2wGzAVUB/wHeAcgBqgH/Av4B/QH/WAAD3wH/AegB9AL/AZgBpAGwAf8BmAGk AbAB/wHoAfQC/wPfAf8cAAz/A/4B/wP3Af8BlAG9AeAB/wGUAb0B4AH/A/YB/wP+Hf8QAAH2AfEB6wH/ AeQB1AG/Af8B3gHFAaMB/wHeAcQBnAH/Ad4BxAGhAf8B5AHTAbwB/wH1Ae8B6QH/ZAAB0wHfAesB/wHo - AfQC/wHoAfQC/wHTAd8B6wH/IAAQ/wP+Af8D9wH/A/YB/wP+If9ZAAEsAbkB/wEBAR4BTQH/ARABGQEv - Af/1AAFNAccB/wEXAc0B/AH/AQkBLgGHAf+0AAM7AWUBAAEjAQAB/wM6AWA1AAFNAccB/wEQAaAB0gH/ - AQwBJAFEAf8cAAMBAQIDAAEBGwABAQwAASIBIQEiATEDAAEBXAADPgFqAR4BpwEQAf8BAAEnAQAB/wEA - ASMBAAH/AzYBWDEAAU0BxwH/ARkB0QH8Af8BCQEuAYcB/zMAAQEDAAEBEAAB7AHSAewB/wFEAQABQwH/ - AeYBzAHmAf8DAgEDAxIBGRAAAUEBSwFNAf8BNwE/AUIB/wEuATMBNgH/ASQBJwEqAf8CGgEfAf8BEQEP - ARUB/wEIAQQBCgH/AQEBAAECAf8DAAH/HAADPgFqAR4BpwEQAf8BOwG7AS8B/wEAASsBAAH/AQABKAEA - Af8BAAEjAQAB/wM1AVctAAFNAccB/wESAaEB0QH/AQwBJAFEAf8/AAEBBAAB7QHYAe0B/wGpASIBqAH/ - AYABAgFRAf8BRwEAAUcB/wHrAdEB6wH/FAABSgGCAYMB/wGXAdsB9QH/AS0BqQHKAf8BLQGpAcoB/wEs - AacByQH/ASQBnwHCAf8BGwGWAbkB/wETAY0BsAH/AgABAQH/HAABHQGkAQ8B/wE7AbsBLwH/ATsBuwEv - Af8BAAEqAQAB/wEAASsBAAH/AQABKAEAAf8BAAEjAQAB/wMwAUwpAAFNAccB/wEjAeIB/QH/AQoBKgGA - Af8jAAEBAwABAQMAAQEDAAEBAwABAQMAAQEDAAEBBAAB6AHRAegB/wGqASIBqQH/AcwBOQHLAf8BUAEA - AVAB/wGWAQoBlQH/AU0BAAFMAf8B8AHVAfAB/xAAAVICjAH/AaAB4AH3Af8BQwHNAfEB/wE2AccB7gH/ - ASoBwQHrAf8BHwG8AegB/wEUAbcB5gH/ARkBkgG2Af8BBgEDAQgB/xwAAR4BpwEQAf8BOwG7AS8B/wE7 - AbsBLwH/AaoB1AGiAf8BGgGgAQ0B/wEAASsBAAH/AQABKAEAAf8BAAEiAQAB/ykAAU0BxwH/ASoB1wH8 - Af8BCgEqAYAB/yQAAasB8AH3Af8BqwHiAeUB/wGsAc4BzAH/Aa0BuwG1Af8BrgGnAZwB/wQAAeQBygHk - Af8BqQEiAagB/wHTAT0B0gH/AdQBQAHTAf8BUQECAVAB/wGfAQ4BnwH/AY4BBwGNAf8BTwEAAU4B/xAA - AYUClAH/AacB4wH4Af8BTgHTAfQB/wFDAc4B8QH/ATcByAHuAf8BKgHCAesB/wEfAbwB6AH/AR4BmQG8 - Af8BDgELARAB/xgAAwIBAwEgAasBEgH/ATsBuwEvAf8BqgHUAaIB/wG3AdoBsAH/AaoB1AGiAf8BEwGT - AQcB/wEAASsBAAH/AQABIwEAAf8lAAEyAZAB/wEAAU0BxwH/AUAB3gH8Af8BCgEqAYAB/wEAASABTAH/ - OAABqgEkAakB/wHSATwB0QH/AdUBQQHVAf8BvQFCAbwB/wHeAZgB3QH/AY8BGAGOAf8BnQEOAZwB/wFQ - AQABUAH/EAABjAKbAf8BrgHmAfoB/wGGAdgB9gH/AU4B1AH0Af8BQwHNAfEB/wE3AccB7gH/ASoBwgHr - Af8BJQGgAcEB/wIVARoB/xgAAwQBBQE1AbgBKAH/AbQB2QGtAf8BxQHiAcAB/wG3AdoBsAH/AbcB2gGw - Af8BqgHUAaIB/wENAYgBAgH/AQABIwEAAf8hAAFBAaAB/wEDAYcBxwH/AS0BwAHwAf8BIgHLAf4B/wEj - AbMB3QH/AQ4BHwE4Af8BAAEgAUwB/xgAAasB8AH3Af8BqwHlAekB/wGsAtUB/wGsAcQBwQH/Aa0BtQGs - Af8BrgGkAZgB/wQAAagBIQGnAf8B0gE/AdEB/wG8AUEBuwH/Ae8BpQHuAf8B+wGfAfoB/wHvAZ0B7gH/ - AZcBJAGWAf8BTgEAAU4B/xAAAZEBogGhAf8BsgHoAfwB/wGgAeIB+gH/AYYB2AH2Af8BTwHTAfMB/wFD - Ac4B8QH/ATYByAHuAf8BKQGlAccB/wEeAR8BJAH/GAADAgEDA0QBegGOAcYBhAH/AbkB3AGzAf8BwwHh - Ab4B/wHDAeEBvgH/AbcB2gGwAf8BqgHUAaIB/wEEATkBAAH/HAABCgGAAbEB/wEDAYcByAH/ASQBugH3 - Af8BJgHCAfkB/wEcAbcB+QH/AToB1gH7Af8BFwGmAegB/wEOAR4BNgH/AQABIwGDAf8wAAGnASIBpgH/ - AbwBQQG7Af8B7wGlAe4B/wH7AZsB+gH/AfsBmAH6Af8B+wGZAfoB/wHnAZgB5gH/AZEBIAGQAf8QAAGU - AaYBpQH/Ab0B7AH8Af8BpQHlAfsB/wGfAeIB+gH/AYYB2AH2Af8BTwHUAfQB/wFDAc0B8QH/AS0BqQHK - Af8BJgEqAS0B/yAAA0YBfgGQAccBhgH/Ab4B3gG4Af8BwwHhAb4B/wGzAdkBrAH/AZABxwGGAf8DPQFp - HAABBwFNAbgB/wEmAcEB+QH/ASIBtwH5Af8BkwHuAf4B/wGPAewB/gH/ASQBtAHzAf8BjQHjAf4B/wEh - AboB4gH/AQYBIAE9Af8cAAGrAfAB9wH/AawC1QH/Aa4BtAGsAf8BrgGZAYoB/wP9Af8BzwGIAc8B/wHi - Aa8B4gH/AfsBqwH6Af8B+wGYAfoB/wH7AZgB+gH/AeoBkAHpAf8BzwGIAc8B/wH0AeYB9AH/EAABlAGm - AaUB/wG9AewB/AH/Ab0B7AH8Af8BsgHoAfwB/wGuAeYB+gH/AacB5AH5Af8BoAHgAfcB/wGXAdsB9QH/ - AS8BNAE4Af8kAANHAYEBlAHJAYoB/wG9Ad4BtwH/AY4BxgGEAf8DMAFLIAABCwGDAbsB/wErAcYB+QH/ - ATsBigGsAf8BOwGKAawB/wE7AYoBrAH/ATsBigGsAf8BOwGKAawB/wE0AdUB+gH/AQkBHwE6Af8wAAHw - AdQB8AH/Ac8BiAHPAf8B7gG+Ae4B/wH7Aa4B+gH/AewBkQHrAf8BzwGIAc8B/wHzAeAB8gH/FAABlAGm - AaUB/wGUAaYBpQH/AZMCpQH/AY8BnwGeAf8BiAKXAf8BgQKOAf8BSwKEAf8BQQFLAU0B/wE4AT8BQQH/ - KAADPAFmAZQByQGKAf8DJQE3JAABCwGDAbwB/wEuAdIB+gH/ARwBNgGEAf8MAAEfAZABwQH/ASUBuwHh - Af8BCwEdATcB/zQAAfIB2wHyAf8BzwGIAc8B/wHjAawB4wH/Ac8BiAHPAf8B8wHjAfMB/2AAAwEBAgQA - AwEBAigAARQBiAHBAf8BGAGdAdAB/wFMAeMB+gH/ARwBhQGeAf8BIwE2AYcB/wEjAUgBnAH/ASQBvwH0 - Af8BGgGMAaoB/wEDASoBTAH/OAAB8gHbAfIB/wHPAYgBzwH/AfAB4wHwAf+YAAEbAZQBxgH/ARYBigHB - Af8BGAGaAc0B/wFAAdUB9QH/AUMB6QH+Af8BPwHUAfMB/wEcAZIBsgH/AQkBNgGMAf8BAAFCAaIB/zwA - Af4B+wH+Af+gAAEbAZQBxgH/ARcBjQHDAf8BEgGLAboB/wESAYsBugH/AQ8BiAG3Af8BEAFFAaAB/wEL - AYIBsgH//wCpAAM2AVgBmQIAAf8DMwFT8AADOAFdAdcBmgEcAf8BmQIAAf8BmQIAAf8DLwFKLAADHgEr - A1QBrgFZAmQB7AEfAYMBlgH/AQwBOAGNAf8BAAEvAYwB/wFOAl0B8ANWAbMDJQE3mAADOgFhAdcBmgEc - Af8B2AGbAR0B/wGZAgAB/wGZAgAB/wGZAgAB/wMvAUooAAFbAl4B0AETAbAB0QH/AYQB1QHoAf8BoQHr - AfYB/wE1AeQC/wEAAb4B8wH/AQABnwHeAf8BAAGLAb4B/wFbAl4B2VQAAbcBogGTAf8BJQELAQAB/wEl - AQsBAAH/ASUBCwEAAf8BJQELAQAB/wElAQsBAAH/ASUBCwEAAf8BJQELAQAB/wElAQsBAAH/ASUBCwEA - Af8BJQELAQAB/wElAQsBAAH/FAAB2AGbAR4B/wHYAZsBHQH/AdgBmwEdAf8BmQIAAf8BmQIAAf8BmQIA - Af8BmQIAAf8DLwFKJAABFQGPAaoB/wEPAdcC/wGQAeoB+gH/AaEB6wH2Af8BMwHZAfQB/wEAAbwB8gH/ - AQABpwHoAf8BAAGcAdoB/wEAASUBhAH/FAADMQFNAlIBUQGhAV8CWAHjAV8CWAHjAVICUQGhATECMAFN - BAADMQFNAlIBUQGhAV8CWAHjAV8CWAHjAVICUQGhATECMAFNDAABtwGiAZMB/wH9AfsB+QH/AeEB3AHY - Af8B4AHXAdIB/wHfAc4BwwH/Ad0ByAG7Af8B2wG/Aa0B/wHbAbsBpwH/AdsBuwGnAf8B2wG7AacB/wHP - AbQBowH/ASUBCwEAAf8UAAHYAZsBHQH/AdgBmwEdAf8B6QG0AT4B/wH8AdYBrwH/AbUBJQEAAf8BmQIA - Af8BmQIAAf8BmQIAAf8DLwFKIAABFgGRAa4B/wEOAdIB+gH/AY0B5AH2Af8BoQHrAfYB/wEyAdcB8wH/ - AQABuQHvAf8BAAGnAegB/wEAAZwB2gH/AQABJwGGAf8QAAM1AVUDZAHnAc8BuAGpAf8B6wHWAcgB/wHl - AcsBuwH/AbMBlQFBAf8BZAJcAecDSwGOA2QB5wHPAbgBqQH/AesB1gHIAf8B5QHLAbsB/wGzAZUBQQH/ - AWQCXAHnATUCNAFVCAABtwGiAZMB/wP+Af8BugGmAZgB/wG1AaABkQH/AfsB7AHjAf8BpAGNAUAB/wGa - AYMBNAH/AfYB1gHCAf8BiAEzASAB/wGDAS0BGgH/Ac8BtAGjAf8BJQELAQAB/xQAAdgBmwEdAf8B6gG3 - AYIB/wH7AdgBsgH/Af4B0QGjAf8B+wHYAbIB/wGvARkBAAH/AZkCAAH/AZkCAAH/AZkCAAH/AyoBQRwA - ARkBlQGwAf8BEAHSAfoB/wGNAeQB9AH/AaEB6wH2Af8BMgHXAfIB/wEAAbkB7gH/AQABpwHoAf8BAAGc - AdoB/wEAASoBiAH/EAADVQGyAeYB1gHLAf8DWQHCAmABXAHUA2AB1AFMASoBIQH7AQkCAAH/AQkCAAH/ - AQkCAAH/AWECWAHmAmABXAHUA2AB1ANZAcIBuQGcAYgB/wNVAbIIAAG6AaUBlgH/A/4B/wP+Af8D/gH/ - Af0B+wH5Af8B/QH3AfMB/wH7AewB4wH/AfoB5wHbAf8B+AHhAdIB/wH3AdsByQH/AdABuQGrAf8BJQEL - AQAB/xQAAecBswE+Af8B8QHDAZEB/wH+Ac8BnQL/Ac0BmQH/Af4B0AGfAf8B+wHYAbIB/wGpARABAAH/ - AZkCAAH/AZkCAAH/AZkCAAH/AwQBBRgAARsBmQG1Af8BEQHRAfsB/wGOAeQB9QH/AaEB6wH2Af8BMgHX - AfIB/wEAAbkB7gH/AQABpwHoAf8BAAGcAdoB/wEAAS0BigH/EAADZQH0BP8DVwHfAx0BKgNcAc0F/wH+ - AfcC/wHxAeYB/wH6AeMB1AH/AfMB1wHHAf8DSgGNAx0BKgNcAd8B7wHWAccB/wFkAlIB9AgAAb4BqQGa - Af8D/gH/AboBpgGYAf8BtAGgAZEB/wP+Af8BowGOAUAB/wGaAYMBNAH/AfsB7AHjAf8BiQEzASEB/wGD - AS0BGgH/AdEBwQG2Af8BJQELAQAB/xQAA0UBfAHlAbIBPQH/AfQBwAGLAv8BzQGZAv8BzQGZAf8B/gHQ - AaEB/wH7AdgBsgH/AakBEAEAAf8BmQIAAf8BmQIAAf8cAAEeAZsBtwH/AREB0AH5Af8BjQHjAfUB/wGh - AesB9gH/ATQB2QHyAf8BAAG5Ae4B/wEAAacB6AH/AQABnAHaAf8BAAEvAY0B/xAAA1UBsgHyAeYB3gH/ - A1kBwgNcAdQBYAJcAdQDYQHiAdMBtQGiAf8BUAJNAfoB2gHAAa8B/wNfAfMDWwHWAWACXAHUA1kBwgHL - AbEBoQH/A1UBsggAAcMBrgGeAf8D/gH/A/4B/wP+Af8D/gH/A/4B/wH9AfcB8wH/AfwB8gHsAf8B+wHs - AeMB/wH6AecB2wH/AdEBwQG2Af8BJQELAQAB/xgAA0YBfwHkAbABOwH/AfYBxAGQAv8BzQGZAv8BzQGZ - Af8B/gHQAaEB/wH7AdgBsgH/AakBEAEAAf8BmQIAAf8cAAEgAZ4BugH/AQ8B0AH5Af8BjQHjAfQB/wGh - AesB9gH/ATEB1wHyAf8BAAG3Ae4B/wEAAacB6AH/AQABnAHaAf8BAAExAY8B/xAAAzUBVQNkAecB7QHh - AdcD/wH9Av8B9wHxAf8B2AHEAbcB/wNkAecDSwGOA2QB5wHtAeEB1wP/Af0C/wH3AfEB/wHYAcQBtwH/ - A2QB5wM1AVUIAAHIAbIBowH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaQBjgFAAf8BmQGEATQB/wH9 - AfcB8wH/AYgBMwEgAf8BgwEtARoB/wHRAcEBtgH/ASUBCwEAAf8cAANJAYcB4wGvAToB/wH2AcQBkAL/ - Ac0BmQL/Ac0BmQH/Af4B0AGhAf8B8gHJAZ0B/wGwARwBAAH/HAABIQGiAbwB/wEJAc4B9wH/AYsB4wH0 - Af8BoQHrAfYB/wEwAdYB8gH/AQABtwHuAf8BAAGnAegB/wEAAZwB2gH/AQABMgGSAf8UAAMxAU0DUgGh - A18B4wNfAeMDUgGhAzEBTQQAAzEBTQNSAaEDXwHjA18B4wNSAaEDMQFNDAABzAG2AacB/wP+Af8D/gH/ - A/4B/wP+Af8D/gH/A/4B/wH9AfsB+QH/Af0B9wHzAf8B/AHyAewB/wH7AewB4wH/ASUBCwEAAf8gAANJ - AYcB4wGvAToB/wH2AcQBkAL/Ac0BmQH/AfMBwgGOAf8B4wGwATsB/wNDAXgcAAEtAakBwAH/ARgB1AH6 - Af8BnAHsAfoB/wGrAe8B+gH/AaYB7QH4Af8BlAHnAfgB/wEzAdkB9gH/AQABvQHpAf8BBQE+AZcB/1QA - AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AekBpQGEAf8B5wGXATAB/wHmAY4BJAH/AeMBPwEMAf8B4wE4 - AQIB/wHiATQBAAH/AeIBNAEAAf8B4gE0AQAB/wHIASQBAAH/JAADSQGHAeMBrwE6Af8B7gG9AYoB/wHj - AbABOwH/AzQBVCAAAYABswHFAf8BmwHeAesB/wHFAfkB/QH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/ - AcUB+QH9Af8BoAHfAeoB/wEoAZEBogH/VAAB6gGqAYsC/wHCAaIB/wH+AcABnwH/Af0BvQGaAf8B+wG1 - AZAB/wH6AbABiwH/AfgBpwE/Af8B9gGiATkB/wH1AZ0BMwH/AfUBmQEsAf8B8wGVAScB/wHNAScBAAH/ - KAADQAFuAeUBsgE/Af8DJgE4JAADOwFjA2AB1gE4AasBugH/ATIBowGzAf8BLgGdAa8B/wEtAZsBrgH/ - ATEBogG0Af8DXgHZA0ABb1QAAeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGhAUEB/wHo - AZsBOAH/AeYBjgEkAf8B5QGHARoB/wHkAYEBEAH/AeQBPQEIAf8B4wE4AQAB/wHiATQBAAH//wD/AAoA - AUIBTQE+BwABPgMAASgDAAFAAwABQAMAAQEBAAEBBgABAhYAA/+BAAX/AcMCAAHwAR8D/wGBAgABwAEH - AfMBnwH/AwABgAEDAecBzwH/AcACAAGAAQMB5wHPAf8EAAEBAecBzwHnBAABAQHnAc8BwwEBAwABAQHP - AecBgQQAAQEB5wHPBQABAQHnAc8FAAEBAecBzwUAAQEB5wHPAQABAQIAAYABAwHzAZ8BgAETAgABgAED - Av8BwAE/AgAB4AEHAv8B4AF/AgAB8AEfAv8B8AH/AgAC/wH8AX8G/wH8AX8E/wH8AX8B/AF/AT8BcwL/ - AfgBPwH8AX8B+QHgAfABBwHwAR8B/AF/Af8BQQHwAQcB8AEPAfwBfwKAAfABBwHwAQ8B/AF/AcEBAAHw - AQcB4AEPAfgBPwH/AQAB8AEHAeABDwHwAR8BgQEAAfABBwHgAQ8B4AEPAf8BAAHwAQcB+AEPAeABDwHg - AQAB8AEHAfwBHwHgAQ8B/wEBAfABBwH+AT8B4wGPAf8BgwL/Af0BfwHgAQ8B/wHHBP8B4AEPAf8B7wT/ - AfABHwz/AfgH/wHwAX8B8AEHBP8B4AE/AfABBwL/AcABAwHgAR8B8AEHAcABgQHAAQMB4AEPAfABBwGA - AQABwAEDAeABBwHwAQcBgAEAAcABAwHgAQMB8AEHAYABAAHAAQMB4AEHAfABBwGAAQABwAEDAfABBwHw - AQcBgAEAAcABAwH4AQcB8AEHAcABgQHAAQMB/AEHAfABBwL/AcABAwH+AQ8B8AEHAv8BwAEDAf8BHwHw - AQcC/wHAAQMQ/ws= + AfQC/wHoAfQC/wHTAd8B6wH/IAAQ/wP+Af8D9wH/A/YB/wP+If9ZAAErAbkB/wEAAR0BTAH/AQ8BGAEu + Af/1AAFMAccB/wEWAc0B/AH/AQgBLQGHAf+0AAM7AWUBAAEiAQAB/wM6AWA1AAFMAccB/wEPAaAB0gH/ + AQsBIwFDAf8cAAMBAQIDAAEBGwABAQwAASIBIQEiATEDAAEBXAADPgFqAR0BpwEPAf8BAAEmAQAB/wEA + ASIBAAH/AzYBWDEAAUwBxwH/ARgB0QH8Af8BCAEtAYcB/zMAAQEDAAEBEAAB7AHSAewB/wFDAQABQgH/ + AeYBzAHmAf8DAgEDAxIBGRAAAUABSgFMAf8BNgE+AUEB/wEtATIBNQH/ASMBJgEpAf8CGQEeAf8BEAEO + ARQB/wEHAQMBCQH/AgABAQH/AwAB/xwAAz4BagEdAacBDwH/AToBuwEuAf8BAAEqAQAB/wEAAScBAAH/ + AQABIgEAAf8DNQFXLQABTAHHAf8BEQGhAdEB/wELASMBQwH/PwABAQQAAe0B2AHtAf8BqQEhAagB/wGA + AQEBUAH/AUYBAAFGAf8B6wHRAesB/xQAAUkBggGDAf8BlwHbAfUB/wEsAakBygH/ASwBqQHKAf8BKwGn + AckB/wEjAZ8BwgH/ARoBlgG5Af8BEgGNAbAB/wMAAf8cAAEcAaQBDgH/AToBuwEuAf8BOgG7AS4B/wEA + ASkBAAH/AQABKgEAAf8BAAEnAQAB/wEAASIBAAH/AzABTCkAAUwBxwH/ASIB4gH9Af8BCQEpAYAB/yMA + AQEDAAEBAwABAQMAAQEDAAEBAwABAQMAAQEEAAHoAdEB6AH/AaoBIQGpAf8BzAE4AcsB/wFPAQABTwH/ + AZYBCQGVAf8BTAEAAUsB/wHwAdUB8AH/EAABUQKMAf8BoAHgAfcB/wFCAc0B8QH/ATUBxwHuAf8BKQHB + AesB/wEeAbwB6AH/ARMBtwHmAf8BGAGSAbYB/wEFAQIBBwH/HAABHQGnAQ8B/wE6AbsBLgH/AToBuwEu + Af8BqgHUAaIB/wEZAaABDAH/AQABKgEAAf8BAAEnAQAB/wEAASEBAAH/KQABTAHHAf8BKQHXAfwB/wEJ + ASkBgAH/JAABqwHwAfcB/wGrAeIB5QH/AawBzgHMAf8BrQG7AbUB/wGuAacBnAH/BAAB5AHKAeQB/wGp + ASEBqAH/AdMBPAHSAf8B1AE/AdMB/wFQAQEBTwH/AZ8BDQGfAf8BjgEGAY0B/wFOAQABTQH/EAABhQKU + Af8BpwHjAfgB/wFNAdMB9AH/AUIBzgHxAf8BNgHIAe4B/wEpAcIB6wH/AR4BvAHoAf8BHQGZAbwB/wEN + AQoBDwH/GAADAgEDAR8BqwERAf8BOgG7AS4B/wGqAdQBogH/AbcB2gGwAf8BqgHUAaIB/wESAZMBBgH/ + AQABKgEAAf8BAAEiAQAB/yUAATEBkAH/AQABTAHHAf8BPwHeAfwB/wEJASkBgAH/AQABHwFLAf84AAGq + ASMBqQH/AdIBOwHRAf8B1QFAAdUB/wG9AUEBvAH/Ad4BmAHdAf8BjwEXAY4B/wGdAQ0BnAH/AU8BAAFP + Af8QAAGMApsB/wGuAeYB+gH/AYYB2AH2Af8BTQHUAfQB/wFCAc0B8QH/ATYBxwHuAf8BKQHCAesB/wEk + AaABwQH/AhQBGQH/GAADBAEFATQBuAEnAf8BtAHZAa0B/wHFAeIBwAH/AbcB2gGwAf8BtwHaAbAB/wGq + AdQBogH/AQwBiAEBAf8BAAEiAQAB/yEAAUABoAH/AQIBhwHHAf8BLAHAAfAB/wEhAcsB/gH/ASIBswHd + Af8BDQEeATcB/wEAAR8BSwH/GAABqwHwAfcB/wGrAeUB6QH/AawC1QH/AawBxAHBAf8BrQG1AawB/wGu + AaQBmAH/BAABqAEgAacB/wHSAT4B0QH/AbwBQAG7Af8B7wGlAe4B/wH7AZ8B+gH/Ae8BnQHuAf8BlwEj + AZYB/wFNAQABTQH/EAABkQGiAaEB/wGyAegB/AH/AaAB4gH6Af8BhgHYAfYB/wFOAdMB8wH/AUIBzgHx + Af8BNQHIAe4B/wEoAaUBxwH/AR0BHgEjAf8YAAMCAQMDRAF6AY4BxgGEAf8BuQHcAbMB/wHDAeEBvgH/ + AcMB4QG+Af8BtwHaAbAB/wGqAdQBogH/AQMBOAEAAf8cAAEJAYABsQH/AQIBhwHIAf8BIwG6AfcB/wEl + AcIB+QH/ARsBtwH5Af8BOQHWAfsB/wEWAaYB6AH/AQ0BHQE1Af8BAAEiAYMB/zAAAacBIQGmAf8BvAFA + AbsB/wHvAaUB7gH/AfsBmwH6Af8B+wGYAfoB/wH7AZkB+gH/AecBmAHmAf8BkQEfAZAB/xAAAZQBpgGl + Af8BvQHsAfwB/wGlAeUB+wH/AZ8B4gH6Af8BhgHYAfYB/wFOAdQB9AH/AUIBzQHxAf8BLAGpAcoB/wEl + ASkBLAH/IAADRgF+AZABxwGGAf8BvgHeAbgB/wHDAeEBvgH/AbMB2QGsAf8BkAHHAYYB/wM9AWkcAAEG + AUwBuAH/ASUBwQH5Af8BIQG3AfkB/wGTAe4B/gH/AY8B7AH+Af8BIwG0AfMB/wGNAeMB/gH/ASABugHi + Af8BBQEfATwB/xwAAasB8AH3Af8BrALVAf8BrgG0AawB/wGuAZkBigH/A/0B/wHPAYgBzwH/AeIBrwHi + Af8B+wGrAfoB/wH7AZgB+gH/AfsBmAH6Af8B6gGQAekB/wHPAYgBzwH/AfQB5gH0Af8QAAGUAaYBpQH/ + Ab0B7AH8Af8BvQHsAfwB/wGyAegB/AH/Aa4B5gH6Af8BpwHkAfkB/wGgAeAB9wH/AZcB2wH1Af8BLgEz + ATcB/yQAA0cBgQGUAckBigH/Ab0B3gG3Af8BjgHGAYQB/wMwAUsgAAEKAYMBuwH/ASoBxgH5Af8BOgGK + AawB/wE6AYoBrAH/AToBigGsAf8BOgGKAawB/wE6AYoBrAH/ATMB1QH6Af8BCAEeATkB/zAAAfAB1AHw + Af8BzwGIAc8B/wHuAb4B7gH/AfsBrgH6Af8B7AGRAesB/wHPAYgBzwH/AfMB4AHyAf8UAAGUAaYBpQH/ + AZQBpgGlAf8BkwKlAf8BjwGfAZ4B/wGIApcB/wGBAo4B/wFKAoQB/wFAAUoBTAH/ATcBPgFAAf8oAAM8 + AWYBlAHJAYoB/wMlATckAAEKAYMBvAH/AS0B0gH6Af8BGwE1AYQB/wwAAR4BkAHBAf8BJAG7AeEB/wEK + ARwBNgH/NAAB8gHbAfIB/wHPAYgBzwH/AeMBrAHjAf8BzwGIAc8B/wHzAeMB8wH/YAADAQECBAADAQEC + KAABEwGIAcEB/wEXAZ0B0AH/AUsB4wH6Af8BGwGFAZ4B/wEiATUBhwH/ASIBRwGcAf8BIwG/AfQB/wEZ + AYwBqgH/AQIBKQFLAf84AAHyAdsB8gH/Ac8BiAHPAf8B8AHjAfAB/5gAARoBlAHGAf8BFQGKAcEB/wEX + AZoBzQH/AT8B1QH1Af8BQgHpAf4B/wE+AdQB8wH/ARsBkgGyAf8BCAE1AYwB/wEAAUEBogH/PAAB/gH7 + Af4B/6AAARoBlAHGAf8BFgGNAcMB/wERAYsBugH/AREBiwG6Af8BDgGIAbcB/wEPAUQBoAH/AQoBggGy + Af//AKkAAzYBWAGZAgAB/wMzAVPwAAM4AV0B1wGaARsB/wGZAgAB/wGZAgAB/wMvAUosAAMeASsDVAGu + AVkCZAHsAR4BgwGWAf8BCwE3AY0B/wEAAS4BjAH/AU4CXQHwA1YBswMlATeYAAM6AWEB1wGaARsB/wHY + AZsBHAH/AZkCAAH/AZkCAAH/AZkCAAH/Ay8BSigAAVsCXgHQARIBsAHRAf8BhAHVAegB/wGhAesB9gH/ + ATQB5AL/AQABvgHzAf8BAAGfAd4B/wEAAYsBvgH/AVsCXgHZVAABtwGiAZMB/wEkAQoBAAH/ASQBCgEA + Af8BJAEKAQAB/wEkAQoBAAH/ASQBCgEAAf8BJAEKAQAB/wEkAQoBAAH/ASQBCgEAAf8BJAEKAQAB/wEk + AQoBAAH/ASQBCgEAAf8UAAHYAZsBHQH/AdgBmwEcAf8B2AGbARwB/wGZAgAB/wGZAgAB/wGZAgAB/wGZ + AgAB/wMvAUokAAEUAY8BqgH/AQ4B1wL/AZAB6gH6Af8BoQHrAfYB/wEyAdkB9AH/AQABvAHyAf8BAAGn + AegB/wEAAZwB2gH/AQABJAGEAf8UAAMxAU0CUgFRAaEBXwJYAeMBXwJYAeMBUgJRAaEBMQIwAU0EAAMx + AU0CUgFRAaEBXwJYAeMBXwJYAeMBUgJRAaEBMQIwAU0MAAG3AaIBkwH/Af0B+wH5Af8B4QHcAdgB/wHg + AdcB0gH/Ad8BzgHDAf8B3QHIAbsB/wHbAb8BrQH/AdsBuwGnAf8B2wG7AacB/wHbAbsBpwH/Ac8BtAGj + Af8BJAEKAQAB/xQAAdgBmwEcAf8B2AGbARwB/wHpAbQBPQH/AfwB1gGvAf8BtQEkAQAB/wGZAgAB/wGZ + AgAB/wGZAgAB/wMvAUogAAEVAZEBrgH/AQ0B0gH6Af8BjQHkAfYB/wGhAesB9gH/ATEB1wHzAf8BAAG5 + Ae8B/wEAAacB6AH/AQABnAHaAf8BAAEmAYYB/xAAAzUBVQNkAecBzwG4AakB/wHrAdYByAH/AeUBywG7 + Af8BswGVAUAB/wFkAlwB5wNLAY4DZAHnAc8BuAGpAf8B6wHWAcgB/wHlAcsBuwH/AbMBlQFAAf8BZAJc + AecBNQI0AVUIAAG3AaIBkwH/A/4B/wG6AaYBmAH/AbUBoAGRAf8B+wHsAeMB/wGkAY0BPwH/AZoBgwEz + Af8B9gHWAcIB/wGIATIBHwH/AYMBLAEZAf8BzwG0AaMB/wEkAQoBAAH/FAAB2AGbARwB/wHqAbcBggH/ + AfsB2AGyAf8B/gHRAaMB/wH7AdgBsgH/Aa8BGAEAAf8BmQIAAf8BmQIAAf8BmQIAAf8DKgFBHAABGAGV + AbAB/wEPAdIB+gH/AY0B5AH0Af8BoQHrAfYB/wExAdcB8gH/AQABuQHuAf8BAAGnAegB/wEAAZwB2gH/ + AQABKQGIAf8QAANVAbIB5gHWAcsB/wNZAcICYAFcAdQDYAHUAUwBKgEhAfsBCAIAAf8BCAIAAf8BCAIA + Af8BYQJYAeYCYAFcAdQDYAHUA1kBwgG5AZwBiAH/A1UBsggAAboBpQGWAf8D/gH/A/4B/wP+Af8B/QH7 + AfkB/wH9AfcB8wH/AfsB7AHjAf8B+gHnAdsB/wH4AeEB0gH/AfcB2wHJAf8B0AG5AasB/wEkAQoBAAH/ + FAAB5wGzAT0B/wHxAcMBkQH/Af4BzwGdAv8BzQGZAf8B/gHQAZ8B/wH7AdgBsgH/AakBDwEAAf8BmQIA + Af8BmQIAAf8BmQIAAf8DBAEFGAABGgGZAbUB/wEQAdEB+wH/AY4B5AH1Af8BoQHrAfYB/wExAdcB8gH/ + AQABuQHuAf8BAAGnAegB/wEAAZwB2gH/AQABLAGKAf8QAANlAfQE/wNXAd8DHQEqA1wBzQX/Af4B9wL/ + AfEB5gH/AfoB4wHUAf8B8wHXAccB/wNKAY0DHQEqA1wB3wHvAdYBxwH/AWQCUgH0CAABvgGpAZoB/wP+ + Af8BugGmAZgB/wG0AaABkQH/A/4B/wGjAY4BPwH/AZoBgwEzAf8B+wHsAeMB/wGJATIBIAH/AYMBLAEZ + Af8B0QHBAbYB/wEkAQoBAAH/FAADRQF8AeUBsgE8Af8B9AHAAYsC/wHNAZkC/wHNAZkB/wH+AdABoQH/ + AfsB2AGyAf8BqQEPAQAB/wGZAgAB/wGZAgAB/xwAAR0BmwG3Af8BEAHQAfkB/wGNAeMB9QH/AaEB6wH2 + Af8BMwHZAfIB/wEAAbkB7gH/AQABpwHoAf8BAAGcAdoB/wEAAS4BjQH/EAADVQGyAfIB5gHeAf8DWQHC + A1wB1AFgAlwB1ANhAeIB0wG1AaIB/wFPAk0B+gHaAcABrwH/A18B8wNbAdYBYAJcAdQDWQHCAcsBsQGh + Af8DVQGyCAABwwGuAZ4B/wP+Af8D/gH/A/4B/wP+Af8D/gH/Af0B9wHzAf8B/AHyAewB/wH7AewB4wH/ + AfoB5wHbAf8B0QHBAbYB/wEkAQoBAAH/GAADRgF/AeQBsAE6Af8B9gHEAZAC/wHNAZkC/wHNAZkB/wH+ + AdABoQH/AfsB2AGyAf8BqQEPAQAB/wGZAgAB/xwAAR8BngG6Af8BDgHQAfkB/wGNAeMB9AH/AaEB6wH2 + Af8BMAHXAfIB/wEAAbcB7gH/AQABpwHoAf8BAAGcAdoB/wEAATABjwH/EAADNQFVA2QB5wHtAeEB1wP/ + Af0C/wH3AfEB/wHYAcQBtwH/A2QB5wNLAY4DZAHnAe0B4QHXA/8B/QL/AfcB8QH/AdgBxAG3Af8DZAHn + AzUBVQgAAcgBsgGjAf8D/gH/AboBpgGYAf8BtAGgAZEB/wP+Af8BpAGOAT8B/wGZAYQBMwH/Af0B9wHz + Af8BiAEyAR8B/wGDASwBGQH/AdEBwQG2Af8BJAEKAQAB/xwAA0kBhwHjAa8BOQH/AfYBxAGQAv8BzQGZ + Av8BzQGZAf8B/gHQAaEB/wHyAckBnQH/AbABGwEAAf8cAAEgAaIBvAH/AQgBzgH3Af8BiwHjAfQB/wGh + AesB9gH/AS8B1gHyAf8BAAG3Ae4B/wEAAacB6AH/AQABnAHaAf8BAAExAZIB/xQAAzEBTQNSAaEDXwHj + A18B4wNSAaEDMQFNBAADMQFNA1IBoQNfAeMDXwHjA1IBoQMxAU0MAAHMAbYBpwH/A/4B/wP+Af8D/gH/ + A/4B/wP+Af8D/gH/Af0B+wH5Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8BJAEKAQAB/yAAA0kBhwHj + Aa8BOQH/AfYBxAGQAv8BzQGZAf8B8wHCAY4B/wHjAbABOgH/A0MBeBwAASwBqQHAAf8BFwHUAfoB/wGc + AewB+gH/AasB7wH6Af8BpgHtAfgB/wGUAecB+AH/ATIB2QH2Af8BAAG9AekB/wEEAT0BlwH/VAAB6gGq + AYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGlAYQB/wHnAZcBLwH/AeYBjgEjAf8B4wE+AQsB/wHjATcBAQH/ + AeIBMwEAAf8B4gEzAQAB/wHiATMBAAH/AcgBIwEAAf8kAANJAYcB4wGvATkB/wHuAb0BigH/AeMBsAE6 + Af8DNAFUIAABgAGzAcUB/wGbAd4B6wH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BxQH5 + Af0B/wGgAd8B6gH/AScBkQGiAf9UAAHqAaoBiwL/AcIBogH/Af4BwAGfAf8B/QG9AZoB/wH7AbUBkAH/ + AfoBsAGLAf8B+AGnAT4B/wH2AaIBOAH/AfUBnQEyAf8B9QGZASsB/wHzAZUBJgH/Ac0BJgEAAf8oAANA + AW4B5QGyAT4B/wMmATgkAAM7AWMDYAHWATcBqwG6Af8BMQGjAbMB/wEtAZ0BrwH/ASwBmwGuAf8BMAGi + AbQB/wNeAdkDQAFvVAAB6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6gGqAYsB/wHpAaEBQAH/AegBmwE3 + Af8B5gGOASMB/wHlAYcBGQH/AeQBgQEPAf8B5AE8AQcB/wHjATcBAAH/AeIBMwEAAf//AP8ACgABQgFN + AT4HAAE+AwABKAMAAUADAAFAAwABAQEAAQEGAAECFgAD/4EABf8BwwIAAfABHwP/AYECAAHAAQcB8wGf + Af8DAAGAAQMB5wHPAf8BwAIAAYABAwHnAc8B/wQAAQEB5wHPAecEAAEBAecBzwHDAQEDAAEBAc8B5wGB + BAABAQHnAc8FAAEBAecBzwUAAQEB5wHPBQABAQHnAc8BAAEBAgABgAEDAfMBnwGAARMCAAGAAQMC/wHA + AT8CAAHgAQcC/wHgAX8CAAHwAR8C/wHwAf8CAAL/AfwBfwb/AfwBfwT/AfwBfwH8AX8BPwFzAv8B+AE/ + AfwBfwH5AeAB8AEHAfABHwH8AX8B/wFBAfABBwHwAQ8B/AF/AoAB8AEHAfABDwH8AX8BwQEAAfABBwHg + AQ8B+AE/Af8BAAHwAQcB4AEPAfABHwGBAQAB8AEHAeABDwHgAQ8B/wEAAfABBwH4AQ8B4AEPAeABAAHw + AQcB/AEfAeABDwH/AQEB8AEHAf4BPwHjAY8B/wGDAv8B/QF/AeABDwH/AccE/wHgAQ8B/wHvBP8B8AEf + DP8B+Af/AfABfwHwAQcE/wHgAT8B8AEHAv8BwAEDAeABHwHwAQcBwAGBAcABAwHgAQ8B8AEHAYABAAHA + AQMB4AEHAfABBwGAAQABwAEDAeABAwHwAQcBgAEAAcABAwHgAQcB8AEHAYABAAHAAQMB8AEHAfABBwGA + AQABwAEDAfgBBwHwAQcBwAGBAcABAwH8AQcB8AEHAv8BwAEDAf4BDwHwAQcC/wHAAQMB/wEfAfABBwL/ + AcABAxD/Cw== diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index 20355a931..7a3e2ef58 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -31,6 +31,7 @@ class ObjectExplorer : Control { private static readonly Log log = new Log(); + private readonly TextBox _treeSearch; private readonly TreeView _tree; private readonly TreeView _treeData; private TreeNodeUtils.TreeNodeBindings _treeBindings = new TreeNodeUtils.TreeNodeBindings(); // default value, so this field is never null @@ -51,11 +52,12 @@ class ObjectExplorer : Control public ObjectExplorer() { - var treeSearch = new SearchTextBox + _treeSearch = new SearchTextBox { Dock = DockStyle.Top }; + _tree = new TreeView { Dock = DockStyle.Fill, @@ -90,9 +92,9 @@ public ObjectExplorer() }; _tree.NodeMouseDoubleClick += _tree_NodeMouseDoubleClick; + _treeSearch.TextChanged += (sender, e) => { SetFilter(((TextBox) sender).Text); }; + _treeSearch.SetCueText("Search (Ctrl + \\)"); - treeSearch.TextChanged += (sender, e) => { SetFilter(((TextBox) sender).Text); }; - treeSearch.SetCueText("Search (Ctrl + \\)"); _tableContextMenuItems = new Dictionary(); _serverContextMenuItems = new Dictionary(); @@ -100,7 +102,12 @@ public ObjectExplorer() _verbContextMenu.MenuItems.Add("Invoke...", (s, e) => OpenInvokeTab()); Controls.Add(_tree); - Controls.Add(treeSearch); + Controls.Add(_treeSearch); + } + + public void FocusSearch() + { + _treeSearch.Focus(); } private void SetFilter(string filter) From 2affdaf0f4ef84839b21c0f6fd395d3f3bb5d470 Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Thu, 21 Sep 2017 12:49:45 +0200 Subject: [PATCH 09/11] Added debouncing feature to SearchTextBox --- .../ObjectExplorer/ObjectExplorer.cs | 7 +- .../ObjectExplorer/SearchTextBox.cs | 66 +++++++++++++++++++ Src/SwqlStudio/Utils/Win32.cs | 4 +- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index 7a3e2ef58..144d6fc9b 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -31,7 +31,7 @@ class ObjectExplorer : Control { private static readonly Log log = new Log(); - private readonly TextBox _treeSearch; + private readonly SearchTextBox _treeSearch; private readonly TreeView _tree; private readonly TreeView _treeData; private TreeNodeUtils.TreeNodeBindings _treeBindings = new TreeNodeUtils.TreeNodeBindings(); // default value, so this field is never null @@ -92,8 +92,9 @@ public ObjectExplorer() }; _tree.NodeMouseDoubleClick += _tree_NodeMouseDoubleClick; - _treeSearch.TextChanged += (sender, e) => { SetFilter(((TextBox) sender).Text); }; - _treeSearch.SetCueText("Search (Ctrl + \\)"); + _treeSearch.TextChangedWithDebounce += (sender, e) => { SetFilter(((TextBox) sender).Text); }; + _treeSearch.CueText = "Search (Ctrl + \\)"; + _treeSearch.DebounceLimit = TimeSpan.FromMilliseconds(400); _tableContextMenuItems = new Dictionary(); _serverContextMenuItems = new Dictionary(); diff --git a/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs index e16dcaa88..a30b72ab4 100644 --- a/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs +++ b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs @@ -10,6 +10,14 @@ namespace SwqlStudio internal class SearchTextBox : TextBox { private readonly PictureBox _searchPictureBox; + private string _cueText = string.Empty; + private TimeSpan _debounceLimit = TimeSpan.Zero; + private readonly Timer _timer; + /// + /// Raised after DebounceLimit after user stopped typing. + /// Useful, if the event associated with text change (search) is expensive - we just wait till user stops writing. + /// + public event EventHandler TextChangedWithDebounce; public SearchTextBox() { @@ -20,6 +28,11 @@ public SearchTextBox() _searchPictureBox.TabStop = false; _searchPictureBox.Visible = true; _searchPictureBox.SizeMode = PictureBoxSizeMode.StretchImage; + + _timer = new Timer(); + _timer.Enabled = false; + _timer.Tick += OnTimerTicked; + Controls.Add(_searchPictureBox); // Send EM_SETMARGINS to prevent text from disappearing underneath the button @@ -28,6 +41,54 @@ public SearchTextBox() SearchImage = Resources.Search; } + private void OnTimerTicked(object sender, EventArgs e) + { + var timer = (Timer) sender; + timer.Stop(); + + OnTextChangedWithDebounce(e); + } + + protected override void OnTextChanged(EventArgs e) + { + if (_debounceLimit == TimeSpan.Zero) + { + OnTextChangedWithDebounce(e); + } + else + { + _timer.Stop(); // restart the timer + _timer.Start(); + } + + base.OnTextChanged(e); + } + + [Browsable(true)] + public string CueText + { + set + { + _cueText = value ?? string.Empty; + this.SetCueText(_cueText); + } + get => _cueText; + } + + [Browsable(true)] + public TimeSpan DebounceLimit + { + set + { + if (value < TimeSpan.Zero) + throw new ArgumentException("DebounceLimit must be greater than or equal to zero", nameof(value)); + + _debounceLimit = value; + _timer.Interval = (int)_debounceLimit.TotalMilliseconds; + } + get => _debounceLimit; + } + [Browsable(true)] public Image SearchImage { @@ -40,5 +101,10 @@ public Image SearchImage get => _searchPictureBox.Image; } + + protected virtual void OnTextChangedWithDebounce(EventArgs e) + { + TextChangedWithDebounce?.Invoke(this, e); + } } } \ No newline at end of file diff --git a/Src/SwqlStudio/Utils/Win32.cs b/Src/SwqlStudio/Utils/Win32.cs index 8e5748e82..66fe41d93 100644 --- a/Src/SwqlStudio/Utils/Win32.cs +++ b/Src/SwqlStudio/Utils/Win32.cs @@ -14,12 +14,12 @@ internal static class Win32 public const int EM_SETCUEBANNER = 0x1501; [DllImport("user32.dll", CharSet = CharSet.Unicode)] - public static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw); + private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw); [DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); [DllImport("user32.dll")] - public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wp, [MarshalAs(UnmanagedType.LPWStr)] string lp); + private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wp, [MarshalAs(UnmanagedType.LPWStr)] string lp); From bc5b5e5958644bc1a18a10f9f905cbf1d394d43f Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Thu, 21 Sep 2017 12:53:56 +0200 Subject: [PATCH 10/11] Converted text search icon from image to string --- .../ObjectExplorer/SearchTextBox.cs | 43 ++++++++---------- .../Properties/Resources.Designer.cs | 10 ---- Src/SwqlStudio/Properties/Resources.resx | 3 -- Src/SwqlStudio/Resources/Search.png | Bin 5307 -> 0 bytes 4 files changed, 20 insertions(+), 36 deletions(-) delete mode 100644 Src/SwqlStudio/Resources/Search.png diff --git a/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs index a30b72ab4..2ec002a37 100644 --- a/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs +++ b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs @@ -9,7 +9,7 @@ namespace SwqlStudio { internal class SearchTextBox : TextBox { - private readonly PictureBox _searchPictureBox; + private readonly Label _searchPicture; private string _cueText = string.Empty; private TimeSpan _debounceLimit = TimeSpan.Zero; private readonly Timer _timer; @@ -21,26 +21,36 @@ internal class SearchTextBox : TextBox public SearchTextBox() { - _searchPictureBox = new PictureBox(); - _searchPictureBox.Anchor = AnchorStyles.Top | AnchorStyles.Right; - _searchPictureBox.Size = new Size(16, 16); - _searchPictureBox.TabIndex = 0; - _searchPictureBox.TabStop = false; - _searchPictureBox.Visible = true; - _searchPictureBox.SizeMode = PictureBoxSizeMode.StretchImage; + _searchPicture = new Label(); + _searchPicture.Anchor = AnchorStyles.Top | AnchorStyles.Right; + _searchPicture.Size = new Size(16, 16); + _searchPicture.TabIndex = 0; + _searchPicture.TabStop = false; + _searchPicture.Visible = true; + SearchImageText = "🔍"; _timer = new Timer(); _timer.Enabled = false; _timer.Tick += OnTimerTicked; - Controls.Add(_searchPictureBox); + Controls.Add(_searchPicture); // Send EM_SETMARGINS to prevent text from disappearing underneath the button Win32.SendMessage(Handle, Win32.EM_SETMARGINS, (IntPtr)2, (IntPtr)(16 << 16)); + } - SearchImage = Resources.Search; + private string SearchImageText + { + set + { + _searchPicture.Text = value; + var textSize = TextRenderer.MeasureText(value, _searchPicture.Font); + _searchPicture.Left = Width - textSize.Width - 4; + _searchPicture.Top = Height - textSize.Height - 6; + } } + private void OnTimerTicked(object sender, EventArgs e) { var timer = (Timer) sender; @@ -89,19 +99,6 @@ public TimeSpan DebounceLimit get => _debounceLimit; } - [Browsable(true)] - public Image SearchImage - { - set - { - _searchPictureBox.Image = value; - _searchPictureBox.Left = Width - _searchPictureBox.Size.Width - 4; - _searchPictureBox.Top = Height - _searchPictureBox.Size.Height - 4; - } - - get => _searchPictureBox.Image; - } - protected virtual void OnTextChangedWithDebounce(EventArgs e) { TextChangedWithDebounce?.Invoke(this, e); diff --git a/Src/SwqlStudio/Properties/Resources.Designer.cs b/Src/SwqlStudio/Properties/Resources.Designer.cs index 1807c8666..f83509c88 100644 --- a/Src/SwqlStudio/Properties/Resources.Designer.cs +++ b/Src/SwqlStudio/Properties/Resources.Designer.cs @@ -88,15 +88,5 @@ internal static string ResizableTextAreaStyle { return ResourceManager.GetString("ResizableTextAreaStyle", resourceCulture); } } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap Search { - get { - object obj = ResourceManager.GetObject("Search", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } } } diff --git a/Src/SwqlStudio/Properties/Resources.resx b/Src/SwqlStudio/Properties/Resources.resx index 452a9aee7..d122f6a58 100644 --- a/Src/SwqlStudio/Properties/Resources.resx +++ b/Src/SwqlStudio/Properties/Resources.resx @@ -118,7 +118,4 @@ ..\ResizableTextAreaStyle.css;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - - ..\Resources\Search.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - diff --git a/Src/SwqlStudio/Resources/Search.png b/Src/SwqlStudio/Resources/Search.png deleted file mode 100644 index 8971d1532057087d62e868417f81fb26da9cd8d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5307 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 BuOR>c From 1fb32b486a7612f63d4fb0588e19ab55ea0f201d Mon Sep 17 00:00:00 2001 From: Vita Tauer Date: Thu, 21 Sep 2017 12:56:01 +0200 Subject: [PATCH 11/11] Change icon of SearchTextBox when user is typing --- .../ObjectExplorer/SearchTextBox.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs index 2ec002a37..cbbb3a388 100644 --- a/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs +++ b/Src/SwqlStudio/ObjectExplorer/SearchTextBox.cs @@ -27,7 +27,6 @@ public SearchTextBox() _searchPicture.TabIndex = 0; _searchPicture.TabStop = false; _searchPicture.Visible = true; - SearchImageText = "🔍"; _timer = new Timer(); _timer.Enabled = false; @@ -37,6 +36,21 @@ public SearchTextBox() // Send EM_SETMARGINS to prevent text from disappearing underneath the button Win32.SendMessage(Handle, Win32.EM_SETMARGINS, (IntPtr)2, (IntPtr)(16 << 16)); + UserTypingTimerStop(); + } + + private void UserTypingTimerRestart() + { + SearchImageText = "…"; + + _timer.Stop(); // restart the timer + _timer.Start(); + } + + private void UserTypingTimerStop() + { + _timer.Stop(); + SearchImageText = "🔍"; } private string SearchImageText @@ -53,8 +67,7 @@ private string SearchImageText private void OnTimerTicked(object sender, EventArgs e) { - var timer = (Timer) sender; - timer.Stop(); + UserTypingTimerStop(); OnTextChangedWithDebounce(e); } @@ -67,8 +80,7 @@ protected override void OnTextChanged(EventArgs e) } else { - _timer.Stop(); // restart the timer - _timer.Start(); + UserTypingTimerRestart(); } base.OnTextChanged(e);