diff --git a/.gitignore b/.gitignore index bff1e36e5..f377c2268 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ paket-files/ \.paket/ *.nupkg +*.user diff --git a/Src/SwqlStudio/DocumentationContent.Designer.cs b/Src/SwqlStudio/DocumentationContent.Designer.cs new file mode 100644 index 000000000..c5928ec26 --- /dev/null +++ b/Src/SwqlStudio/DocumentationContent.Designer.cs @@ -0,0 +1,77 @@ +namespace SwqlStudio +{ + partial class DocumentationContent + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.itemTypeLabel = new System.Windows.Forms.Label(); + this.docTextBox = new System.Windows.Forms.RichTextBox(); + this.SuspendLayout(); + // + // itemTypeLabel + // + this.itemTypeLabel.AutoSize = true; + this.itemTypeLabel.Dock = System.Windows.Forms.DockStyle.Top; + this.itemTypeLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.itemTypeLabel.Location = new System.Drawing.Point(5, 5); + this.itemTypeLabel.Name = "itemTypeLabel"; + this.itemTypeLabel.Padding = new System.Windows.Forms.Padding(3); + this.itemTypeLabel.Size = new System.Drawing.Size(6, 19); + this.itemTypeLabel.TabIndex = 2; + // + // docTextBox + // + this.docTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.docTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.docTextBox.Location = new System.Drawing.Point(5, 24); + this.docTextBox.Name = "docTextBox"; + this.docTextBox.ReadOnly = true; + this.docTextBox.Size = new System.Drawing.Size(274, 232); + this.docTextBox.TabIndex = 3; + this.docTextBox.Text = ""; + // + // DocumentationContent + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(284, 261); + this.Controls.Add(this.docTextBox); + this.Controls.Add(this.itemTypeLabel); + this.Name = "DocumentationContent"; + this.Padding = new System.Windows.Forms.Padding(5); + this.Text = "Documentation"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label itemTypeLabel; + private System.Windows.Forms.RichTextBox docTextBox; + } +} diff --git a/Src/SwqlStudio/DocumentationContent.cs b/Src/SwqlStudio/DocumentationContent.cs new file mode 100644 index 000000000..2f7d9f978 --- /dev/null +++ b/Src/SwqlStudio/DocumentationContent.cs @@ -0,0 +1,24 @@ +using System.Drawing.Design; +using System.Windows.Forms; +using WeifenLuo.WinFormsUI.Docking; + +namespace SwqlStudio +{ + public partial class DocumentationContent : DockContent + { + public DocumentationContent() + { + InitializeComponent(); + } + + public void UpdateDocumentation(TreeNode newNode) + { + if (newNode != null) + { + var doc = DocumentationBuilder.Build(newNode); + this.itemTypeLabel.Text = doc.ItemType; + this.docTextBox.Text = doc.Documents; + } + } + } +} diff --git a/Src/SwqlStudio/DocumentationContent.resx b/Src/SwqlStudio/DocumentationContent.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/Src/SwqlStudio/DocumentationContent.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Src/SwqlStudio/LexerService.cs b/Src/SwqlStudio/LexerService.cs index e973f6f50..d89b7e6b2 100644 --- a/Src/SwqlStudio/LexerService.cs +++ b/Src/SwqlStudio/LexerService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using SwqlStudio.Autocomplete; +using SwqlStudio.Metadata; using SwqlStudio.Properties; namespace SwqlStudio diff --git a/Src/SwqlStudio/MainForm.Designer.cs b/Src/SwqlStudio/MainForm.Designer.cs index eb08faad1..d11de49a4 100644 --- a/Src/SwqlStudio/MainForm.Designer.cs +++ b/Src/SwqlStudio/MainForm.Designer.cs @@ -49,6 +49,7 @@ private void InitializeComponent() this.redoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); this.findToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.replaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); this.menuEditCut = new System.Windows.Forms.ToolStripMenuItem(); this.menuEditCopy = new System.Windows.Forms.ToolStripMenuItem(); @@ -77,7 +78,6 @@ private void InitializeComponent() this.saveFileDialog = new System.Windows.Forms.SaveFileDialog(); this.fontDialog = new System.Windows.Forms.FontDialog(); this.filesDock = new SwqlStudio.QueriesDockPanel(); - this.ObjectExplorerImageList = new System.Windows.Forms.ImageList(this.components); this.startTimer = new System.Windows.Forms.Timer(this.components); this.mainToolbar = new System.Windows.Forms.ToolStrip(); this.connectionsCombobox = new System.Windows.Forms.ToolStripComboBox(); @@ -93,7 +93,6 @@ private void InitializeComponent() this.newFileToolButton = new System.Windows.Forms.ToolStripButton(); this.openFileButton = new System.Windows.Forms.ToolStripButton(); this.saveToolButton = new System.Windows.Forms.ToolStripButton(); - this.replaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this.menu.SuspendLayout(); this.mainToolbar.SuspendLayout(); @@ -254,7 +253,7 @@ private void InitializeComponent() this.undoToolStripMenuItem.Image = global::SwqlStudio.Properties.Resources.Undo_16x; this.undoToolStripMenuItem.Name = "undoToolStripMenuItem"; this.undoToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Z))); - this.undoToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.undoToolStripMenuItem.Size = new System.Drawing.Size(158, 22); this.undoToolStripMenuItem.Text = "Undo"; this.undoToolStripMenuItem.Click += new System.EventHandler(this.undoToolStripMenuItem_Click); // @@ -263,34 +262,42 @@ private void InitializeComponent() this.redoToolStripMenuItem.Image = global::SwqlStudio.Properties.Resources.Redo_16x; this.redoToolStripMenuItem.Name = "redoToolStripMenuItem"; this.redoToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Y))); - this.redoToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.redoToolStripMenuItem.Size = new System.Drawing.Size(158, 22); this.redoToolStripMenuItem.Text = "Redo"; this.redoToolStripMenuItem.Click += new System.EventHandler(this.redoToolStripMenuItem_Click); // // toolStripSeparator5 // this.toolStripSeparator5.Name = "toolStripSeparator5"; - this.toolStripSeparator5.Size = new System.Drawing.Size(177, 6); + this.toolStripSeparator5.Size = new System.Drawing.Size(155, 6); // // findToolStripMenuItem // this.findToolStripMenuItem.Name = "findToolStripMenuItem"; this.findToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F))); - this.findToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.findToolStripMenuItem.Size = new System.Drawing.Size(158, 22); this.findToolStripMenuItem.Text = "&Find"; this.findToolStripMenuItem.Click += new System.EventHandler(this.findToolStripMenuItem_Click); // + // replaceToolStripMenuItem + // + this.replaceToolStripMenuItem.Name = "replaceToolStripMenuItem"; + this.replaceToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.H))); + this.replaceToolStripMenuItem.Size = new System.Drawing.Size(158, 22); + this.replaceToolStripMenuItem.Text = "Replace"; + this.replaceToolStripMenuItem.Click += new System.EventHandler(this.replaceToolStripMenuItem_Click); + // // toolStripSeparator6 // this.toolStripSeparator6.Name = "toolStripSeparator6"; - this.toolStripSeparator6.Size = new System.Drawing.Size(177, 6); + this.toolStripSeparator6.Size = new System.Drawing.Size(155, 6); // // menuEditCut // this.menuEditCut.Image = ((System.Drawing.Image)(resources.GetObject("menuEditCut.Image"))); this.menuEditCut.Name = "menuEditCut"; this.menuEditCut.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.X))); - this.menuEditCut.Size = new System.Drawing.Size(180, 22); + this.menuEditCut.Size = new System.Drawing.Size(158, 22); this.menuEditCut.Text = "Cu&t"; this.menuEditCut.Click += new System.EventHandler(this.menuEditCut_Click); // @@ -299,7 +306,7 @@ private void InitializeComponent() this.menuEditCopy.Image = global::SwqlStudio.Properties.Resources.ASX_Copy_blue_16x; this.menuEditCopy.Name = "menuEditCopy"; this.menuEditCopy.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C))); - this.menuEditCopy.Size = new System.Drawing.Size(180, 22); + this.menuEditCopy.Size = new System.Drawing.Size(158, 22); this.menuEditCopy.Text = "&Copy"; this.menuEditCopy.Click += new System.EventHandler(this.menuEditCopy_Click); // @@ -308,7 +315,7 @@ private void InitializeComponent() this.menuEditPaste.Image = global::SwqlStudio.Properties.Resources.ASX_Paste_blue_16x; this.menuEditPaste.Name = "menuEditPaste"; this.menuEditPaste.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); - this.menuEditPaste.Size = new System.Drawing.Size(180, 22); + this.menuEditPaste.Size = new System.Drawing.Size(158, 22); this.menuEditPaste.Text = "&Paste"; this.menuEditPaste.Click += new System.EventHandler(this.menuEditPaste_Click); // @@ -319,7 +326,7 @@ private void InitializeComponent() this.curlBashToolStripMenuItem, this.getSwisDataPowerShellToolStripMenuItem}); this.copyQueryAsToolStripMenuItem.Name = "copyQueryAsToolStripMenuItem"; - this.copyQueryAsToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.copyQueryAsToolStripMenuItem.Size = new System.Drawing.Size(158, 22); this.copyQueryAsToolStripMenuItem.Text = "Copy &Query As"; // // curlCmdToolStripMenuItem @@ -494,25 +501,6 @@ private void InitializeComponent() this.filesDock.Size = new System.Drawing.Size(827, 571); this.filesDock.TabIndex = 2; // - // ObjectExplorerImageList - // - this.ObjectExplorerImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("ObjectExplorerImageList.ImageStream"))); - this.ObjectExplorerImageList.TransparentColor = System.Drawing.Color.Transparent; - this.ObjectExplorerImageList.Images.SetKeyName(0, "Column"); - this.ObjectExplorerImageList.Images.SetKeyName(1, "Database"); - this.ObjectExplorerImageList.Images.SetKeyName(2, "Link"); - this.ObjectExplorerImageList.Images.SetKeyName(3, "Table"); - this.ObjectExplorerImageList.Images.SetKeyName(4, "InheritedColumn"); - this.ObjectExplorerImageList.Images.SetKeyName(5, "KeyColumn"); - this.ObjectExplorerImageList.Images.SetKeyName(6, "Verb"); - this.ObjectExplorerImageList.Images.SetKeyName(7, "Argument"); - this.ObjectExplorerImageList.Images.SetKeyName(8, "Indication"); - this.ObjectExplorerImageList.Images.SetKeyName(9, "Namespace"); - this.ObjectExplorerImageList.Images.SetKeyName(10, "BaseType"); - this.ObjectExplorerImageList.Images.SetKeyName(11, "BaseTypeAbstract"); - this.ObjectExplorerImageList.Images.SetKeyName(12, "TableAbstract"); - this.ObjectExplorerImageList.Images.SetKeyName(13, "TableCrud"); - // // startTimer // this.startTimer.Tick += new System.EventHandler(this.startTimer_Tick); @@ -652,14 +640,6 @@ private void InitializeComponent() this.saveToolButton.ToolTipText = "Save (Ctrl+S)"; this.saveToolButton.Click += new System.EventHandler(this.menuFileSave_Click); // - // replaceToolStripMenuItem - // - this.replaceToolStripMenuItem.Name = "replaceToolStripMenuItem"; - this.replaceToolStripMenuItem.Size = new System.Drawing.Size(180, 22); - this.replaceToolStripMenuItem.Text = "Replace"; - this.replaceToolStripMenuItem.Click += new System.EventHandler(this.replaceToolStripMenuItem_Click); - this.replaceToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.H))); - // // MainForm // this.AllowDrop = true; @@ -705,7 +685,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem menuEditPaste; private System.Windows.Forms.ToolStripMenuItem queryToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem menuQueryExecute; - private System.Windows.Forms.ImageList ObjectExplorerImageList; private System.Windows.Forms.Timer startTimer; private System.Windows.Forms.ToolStripMenuItem parametersToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem enumEntitiesToolStripMenuItem; diff --git a/Src/SwqlStudio/MainForm.cs b/Src/SwqlStudio/MainForm.cs index 3b832e903..2fcdc3a41 100644 --- a/Src/SwqlStudio/MainForm.cs +++ b/Src/SwqlStudio/MainForm.cs @@ -7,6 +7,7 @@ using System.Windows.Forms; using SolarWinds.InformationService.Contract2; using SolarWinds.InformationService.InformationServiceClient; +using SwqlStudio.Metadata; using SwqlStudio.Properties; using SwqlStudio.Subscriptions; using SwqlStudio.Utils; @@ -53,7 +54,6 @@ public MainForm() private void InitializeDockPanel() { - this.filesDock.SetObjectExplorerImageList(this.ObjectExplorerImageList); this.serverList = new ServerList(); this.serverList.ConnectionAdded += ServerListOnConnectionAdded; this.serverList.ConnectionRemoved += ServerListOnConnectionRemoved; diff --git a/Src/SwqlStudio/MainForm.resx b/Src/SwqlStudio/MainForm.resx index a6189d612..d0b7f431f 100644 --- a/Src/SwqlStudio/MainForm.resx +++ b/Src/SwqlStudio/MainForm.resx @@ -151,221 +151,6 @@ ZHMuSW5mb3JtYXRpb25TZXJ2aWNlLkNvbnRyYWN0Mi5Qcm9wZXJ0eUJhZwMAAAAHVmVyc2lvbghDb21w YXJlcghIYXNoU2l6ZQADAAgWU3lzdGVtLk9yZGluYWxDb21wYXJlcggCAAAAAAAAAAkDAAAAAAAAAAQD AAAAFlN5c3RlbS5PcmRpbmFsQ29tcGFyZXIBAAAAC19pZ25vcmVDYXNlAAEBCw== - - - - 467, 17 - - - - AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w - LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAG - MAAAAk1TRnQBSQFMAgEBDgEAAYwBAgGMAQIBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA - AwABQAMAAQEBAAEgBgABQBIAgP+AAAT/A0AB/wPAAf8D9AH/A9YB/wMrTf8DAAH/AwAB/wE5AVwBuRH/ - gAAE/wO0Af8DCQH/AwkB/wMJAf8Dok3/AwAB/wMAAf8BOQFcAbkB/wMADf+AAAT/A/IB/wMiAf8D6AH/ - AyQB/wPoAf8BBgIAAf8BBgIAAf8BBgIAAf8BBgIAAf8BBgIAAf8BBgIAAf8BBgIAAf8BBgIAEf8BtwGi - AZMB/wFFASsBFwH/AUUBKwEXAf8BRQErARcB/wFFASsBFwn/AwAB/wE5AVwBuQH/ATkBXAG5Af8BRQEr - ARcB/wMACf+AAAT/A/kB/wONAf8DSQH/A1MB/wP3Af8B3wHOAcMB/wHdAcgBuwH/AdsBvwGtAf8B2wG7 - AacB/wHbAbsBpwH/AdsBuwGnAf8BzwG0AaMB/wEGAgAR/wG3AaIBkwH/Af0B+wH5Af8B4QHcAdgB/wHg - AdcB0gH/Ad8BzgHDAf8B3QHIAbsJ/wMAAf8DYQH/AUUBKwEXAf8BRQErARcB/wMABf+AAAT/A/0B/wPb - Af8DCQH/A8kB/wP7Af8B+wHsAeMB/wGkAY0BIQH/AZoBgwEVAf8B9gHWAcIB/wGIARQBAQH/AYMBDgEA - Af8BzwG0AaMB/wEGAgAR/wG3AaIBkwH/A/4B/wG6AaYBmAH/AbUBoAGRAf8B+wHsAeMB/wGkAY0BYAH/ - AZoBgwFUCf8DAAH/A2EB/wFFASsBFwH/AUUBKwEXAf8DAAH/gAAI/wG6AaUBlgH/A/4B/wP+Af8D/gH/ - Af0B+wH5Af8B/QH3AfMB/wH7AewB4wH/AfoB5wHbAf8B+AHhAdIB/wH3AdsByQH/AdABuQGrAf8BBgIA - Ef8BugGlAZYB/wP+Af8D/gH/A/4B/wH9AfsB+QH/Af0B9wHzAf8B+wHsAeMB/wH6AecB2wn/AwAB/wNh - Af8BRQErARcB/wFFASsBFwH/gAAI/wG+AakBmgH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaMBjgEh - Af8BmgGDARUB/wH7AewB4wH/AYkBFAECAf8BgwEOAQAB/wHRAcEBtgH/AQYCABH/Ab4BqQGaAf8D/gH/ - AboBpgGYAf8BtAGgAZEB/wP+Af8BowGOAWAB/wGaAYMBVAH/AfsB7AHjAf8BiQFTAUEJ/wMAAf8DYQH/ - AUUBKwEXAf+AAAj/AcMBrgGeAf8D/gH/A/4B/wP+Af8D/gH/A/4B/wH9AfcB8wH/AfwB8gHsAf8B+wHs - AeMB/wH6AecB2wH/AdEBwQG2Af8BBgIAEf8BwwGuAZ4B/wP+Af8D/gH/A/4B/wP+Af8D/gH/Af0B9wHz - Af8B/AHyAewB/wH7AewB4wH/AfoB5wHbCf8DAAH/A2EB/4AACP8ByAGyAaMB/wP+Af8BugGmAZgB/wG0 - AaABkQH/A/4B/wGkAY4BIQH/AZkBhAEVAf8B/QH3AfMB/wGIARQBAQH/AYMBDgEAAf8B0QHBAbYB/wEG - AgAR/wHIAbIBowH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaQBjgFgAf8BmQGEAVQB/wH9AfcB8wH/ - AYgBUwFAAf8BgwFNAToB/wHRAcEBtgn/AUUBKwEXAf+AAAj/AcwBtgGnAf8D/gH/A/4B/wP+Af8D/gH/ - A/4B/wP+Af8B/QH7AfkB/wH9AfcB8wH/AfwB8gHsAf8B+wHsAeMB/wEGAgAR/wHMAbYBpwH/A/4B/wP+ - Af8D/gH/A/4B/wP+Af8D/gH/Af0B+wH5Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8BRQErARcJ/4AA - CP8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGlAYQB/wHnAZcBEQH/AeYBjgEFAf8B4wEgAQAB/wHj - ARkBAAH/AeIBFQEAAf8B4gEVAQAB/wHiARUBAAH/AcgBBQEAEf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGL - Af8B6QGlAYQB/wHnAZcBUAH/AeYBjgFEAf8B4wFfASwB/wHjAVgBIgH/AeIBVAEbAf8B4gFUARsB/wHi - AVQBGwH/AcgBRAERCf+AAAj/AeoBqgGLAv8BwgGiAf8B/gHAAZ8B/wH9Ab0BmgH/AfsBtQGQAf8B+gGw - AYsB/wH4AacBIAH/AfYBogEaAf8B9QGdARQB/wH1AZkBDQH/AfMBlQEIAf8BzQEIAQAR/wHqAaoBiwL/ - AcIBogH/Af4BwAGfAf8B/QG9AZoB/wH7AbUBkAH/AfoBsAGLAf8B+AGnAV8B/wH2AaIBWQH/AfUBnQFT - Af8B9QGZAUwB/wHzAZUBRwH/Ac0BRwETCf+AAAj/AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGL - Af8B6QGhASIB/wHoAZsBGQH/AeYBjgEFAf8B5QGHAQAB/wHkAYEBAAH/AeQBHgEAAf8B4wEZAQAB/wHi - ARUBABH/AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGhAWEB/wHoAZsBWAH/AeYBjgFE - Af8B5QGHAToB/wHkAYEBMAH/AeQBXQEoAf8B4wFYASAB/wHiAVQBGwn/gACA/4AAgP//ACkAAdMB3wHr - Af8B6AH0Av8B6AH0Av8B0wHfAesB/wgAA/QB/wP0Af8D9QX/A/YB/wP0Af8D9A3/A/4B/wP2Af8D9QH/ - A/0J/xAAAe8B5gHcAf8BzgG1AZMB/wG4AZMBIQH/AbIBiAEPAf8BuAGSASAB/wHOAbQBkAH/Ae4B5gHb - Af94AAPfAf8B6AH0Av8BmAGkAbAB/wGYAaQBsAH/AegB9AL/A98B/wQAA/YB/wM/Af8DwAH/A/QB/wPW - Af8DKgH/A/UJ/wP+Af8D9gH/AVABrgHbAf8BUAGuAdsB/wP1Af8D/QX/CAAB/QH7AfoB/wHIAawBhAH/ - AaEBMAEAAf8BnQEqAQAB/wGcASgBAAH/AaQBNgEAAf8BnQEpAQAB/wGdASkBAAH/AZ8BLwEAAf8BxwGq - AYEB/wH8AfsB+QH/HAADhgH/AwAB/w8AAf8DhgH/NAAD3wH/A/QB/wEtAagB5gH/AQABSwG2Af8BAAFL - Ab4B/wElAagB7gH/AegB9AL/AdMB3wHrAf8D+gH/A7QB/wMIAf8DCAH/AwgB/wOiAf8D+gX/A/4B/wP2 - Af8BUAGuAdsB/wEAAU4BxwH/AQABTgHHAf8BUAGuAdsB/wP1Af8D/QH/BAAB/AH7AfkB/wG8AZYBJgH/ - AaABLQEAAf8BoQEuAQAB/wGeASkBAAH/AcoBqgE3Af8B9gHxAegB/wHNAa8BQQH/AZ4BKQEAAf8BoQEu - AQAB/wGhAS0BAAH/AboBlAEiAf8B/AH6AfgB/xQAA4YB/wMAAf8XAAH/A4YB/zgAAS0BqAHmAf8BAAFL - AbYB/wEAAUsBvgH/AQABSwG+Af8BmAGkAbAB/wHoAfQC/wP+Af8D8gH/AyEB/wPoAf8DIwH/A+gB/wP+ - Af8D9AH/A/QB/wP0Af8BlAG9AeAB/wEAAU4BxwH/AQABTgHHAf8BAAFOAccB/wFQAa4B2wH/A/UB/wQA - AcwBrwGIAf8BpQEyAQAB/wGlATIBAAH/AaUBMwEAAf8BogEtAQAB/wHmAdYBuwX/AesB3gHIAf8BowEv - AQAB/wGlATIBAAH/AaUBMgEAAf8BpQEyAQAB/wHKAa0BhAH/FAADFwH/AwAB/xcAAf8DFwH/MAABBgFL - Aa4B/wEGAUsBrgH/AR4BRwGdAf8BHgFHAZ0B/wEAAUsBtgH/AQABSwG2Af8BmAGkAbAB/wHoAfQG/wP5 - Af8DjQH/A0gB/wNSAf8D9wX/A/QB/wEAAU4BxwH/AQABTgHHAf8BAAFOAccB/wGUAb0B4AH/AQABTgHH - Af8BAAFOAccB/wGUAb0B4AH/A/YB/wHyAeoB4QH/AakBOQEAAf8BqgE3AQAB/wGqATcBAAH/AaoBNwEA - Af8BpwEyAQAB/wHlAdMBtgX/AeoB3AHDAf8BqAE0AQAB/wGqATYBAAH/AaoBNwEAAf8BqgE3AQAB/wGp - ATgBAAH/AfAB6QHeAf8QAAMXAf8DAAH/FwAB/wMXAf8cAAPfAf8D3wH/DAABBgFLAa4B/wG1AfoC/wHN - AfYC/wHNAfYC/wEtAagB5gH/AS0BqAHmAf8B6AH0Av8B0wHfAesF/wP9Af8D2wH/AwgB/wPJAf8D+wX/ - A/QB/wEAAU4BxwH/A/QB/wP0Af8D9AH/AZQBvQHgAf8BlAG9AeAB/wP2Af8D/gH/AdYBvgGdAf8BsAE+ - AQAB/wGuATsBAAH/Aa8BPAEAAf8BrwE8AQAB/wGsATcBAAH/AeYB1QG2Bf8B6wHcAcQB/wGtATkBAAH/ - Aa8BOwEAAf8BrwE8AQAB/wGuATwBAAH/Aa8BOwEAAf8B0wG5AZYB/xMAAf8DwAH/FAADwAH/AwAB/xgA - AdMB3wHrAf8B6AH0Av8B6AH0Av8B0wHfAesB/wgAAR4BRwGdAf8BzQH2Av8ByQH2Av8BSgGkAdEB/wFK - AaQB0QH/AckB9gL/A+UB/wQACP8D9gH/A/QB/wP0Af8D/QX/A/QB/wEAAU4BxwH/A/QB/wP2Af8BUAGu - AdsB/wFQAa4B2wH/A/QB/wP8Bf8BygGpAT4B/wHAAY4BAAH/AbUBQwEAAf8BswE/AQAB/wG0AUEBAAH/ - AbIBPQEAAf8B6AHWAbgF/wHsAd4BxQH/AbIBPgEAAf8BtAFAAQAB/wG0AUEBAAH/AbQBQQEAAf8BtQFB - AQAB/wHEAZ8BKwH/DwAB/wMwAf8cAAMwAf8DAAH/EAAD3wH/AegB9AL/AZgBpAGwAf8BmAGkAbAB/wHo - AfQC/wPfAf8EAAEeAUcBnQH/Ac0B9gL/AUoBpAHRAf8BGgFHAaEB/wEaAUcBoQH/AUoBpAHRAf8D9AH/ - A98F/wP+Af8D9gH/AVABrgHbAf8BUAGuAdsB/wP1Af8D/QH/A/QB/wEAAU4BxwH/A/QB/wFQAa4B2wH/ - AQABTgHHAf8BAAFOAccB/wFQAa4B2wH/A/UB/wP9Af8ByQGmATUB/wHJAZsBDAH/AcUBlAEFAf8BvgGJ - AQAB/wG6AYABAAH/AbcBQQEAAf8B6wHZAbsF/wHvAeEByAH/AbcBQwEAAf8BuQFFAQAB/wG5AUUBAAH/ - AbkBRQEAAf8BugFFAQAB/wHDAZoBHwH/EwAB/wPAAf8UAAPAAf8DAAH/EAAB0wHfAesB/wHoAfQC/wEl - AagB7gH/AQABSwG+Af8BAAFLAb4B/wElAagB7gH/Ac0B9gL/Ac0B9gL/AQYBSwGuAf8BtQH6Av8BJQGo - Ae4B/wEAAUsBvgH/AQABSwHHAf8BAAFLAccB/wGMAaQBvQH/AdwB9AL/A/4B/wP2Af8BUAGuAdsB/wEA - AU4BxwH/AQABTgHHAf8BUAGuAdsB/wP0Af8D9AH/AQABTgHHAf8D9AH/AZQBvQHgAf8BAAFOAccB/wEA - AU4BxwH/AQABTgHHAf8BUAGuAdsB/wP1Af8B0AGvAYEB/wHOAaABEQH/AcsBnAEQAf8BzAGcARAB/wHK - AZkBCAH/AcMBjQEAAf8B5QHUAbUF/wHnAdgBvAH/Ab4BgwEAAf8BwAGHAQAB/wHBAYgBAAH/AcIBigEA - Af8BxgGQAQAB/wHMAagBOAH/EAADFwH/AwAB/xcAAf8DFwH/EAAB6AH0Av8BmAGkAbAB/wEAAUsBvgH/ - AQABSwG+Af8BAAFLAb4B/wEAAUsBvgH/AR4BRwGdAf8BHgFHAZ0B/wEGAUsBrgH/AQYBSwGuAf8BAAFL - Ab4B/wEAAUsBvgH/AQABSwHHAf8BAAFLAccB/wGMAaQBvQH/AdwB9AL/A/YB/wFQAa4B2wH/AQABTgHH - Af8BAAFOAccB/wEAAU4BxwH/AQABTgHHAf8BUAGuAdsB/wEAAU4BxwH/AQABTgHHAf8BAAFOAccB/wEA - AU4BxwH/AZQBvQHgAf8BAAFOAccB/wEAAU4BxwH/AZQBvQHgAf8D9gH/Ad0BxwGrAf8B0wGmARoB/wHQ - AaIBEwH/AdABoQEUAf8B0AGhARQB/wHQAZ8BDwH/AcsBpAEkAf8B1AHDAaUB/wHKAaQBJAH/Ac0BmwEH - Af8BzgGcAQoB/wHOAZwBCgH/Ac4BnAEJAf8BzwGdAQkB/wHaAcMBogH/EAADFwH/AwAB/xcAAf8DFwH/ - EAAB6AH0Av8BmAGkAbAB/wEAAUsBvgH/AQABSwG+Af8BAAFLAccB/wEAAUsBxwH/AQABSwG+Af8BJQGo - Ae4B/wHqAfYC/wHqAfYC/wP2Af8D9gH/AYwBpAG9Af8BjAGkAb0B/wP0Af8D3wH/A/cB/wGUAb0B4AH/ - AQABTgHHAf8BAAFOAccB/wEAAU4BxwH/AQABTgHHAf8BAAFOAccB/wFQAa4B2wH/A/QB/wP0Af8D9AH/ - A/QB/wGUAb0B4AH/AZQBvQHgAf8D9gH/A/4B/wH1Ae8B5wH/AdEBqAEoAf8B2AGpARoB/wHVAaYBGgH/ - AdUBpgEYAf8B1AGjARMB/wHlAccBkQH/AfMB6gHYAf8B5wHLAZkB/wHTAaEBDwH/AdMBogESAf8B0wGh - ARAB/wHVAaMBDwH/Ac0BnQETAf8B9AHtAeQB/xAAA4YB/wMAAf8XAAH/A4YB/xAAAdMB3wHrAf8B6AH0 - Av8BJQGoAe4B/wEAAUsBvgH/AQABSwHHAf8BAAFLAccB/wEAAUsBvgH/AQABSwG+Af8BmAGkAbAB/wHo - AfQC/wPfAf8D3wH/AdwB9AL/AdwB9AL/A98B/wQAA/4B/wP3Af8BlAG9AeAB/wEAAU4BxwH/AQABTgHH - Af8BAAFOAccB/wEAAU4BxwH/AQABTgHHAf8BUAGuAdsB/wP1Af8D/QH/A/4B/wP3Af8D9gH/A/4F/wQA - Ad0ByAGqAf8B3QGyASkB/wHaAasBHQH/AdkBqwEeAf8B1wGnARcB/wHxAeYB0wX/AfUB7gHhAf8B1wGm - ARcB/wHXAacBFwH/AdgBpwEVAf8B2QGqARoB/wHbAcEBngH/GAADhgH/AwAB/w8AAf8DhgH/GAAD3wH/ - AegB9AL/AZgBpAGwAf8BAAFLAb4B/wEAAUsBvgH/AQABSwG+Af8BAAFLAb4B/wGYAaQBsAH/AegB9AL/ - A98B/wQAA98B/wPfAf8IAAT/A/4B/wP3Af8BlAG9AeAB/wEAAU4BxwH/AQABTgHHAf8BAAFOAccB/wEA - AU4BxwH/AZQBvQHgAf8D9gH/A/4F/wP+Af8D/gn/BAAB/gL9Af8B2QG/AZoB/wHgAbYBLwH/Ad8BsQEi - Af8B3AGtAR0B/wHXAbUBQAH/AeIB1QG+Af8B1wG3AYAB/wHbAaoBGQH/Ad4BrgEcAf8B3gGxASQB/wHW - AbgBjQH/Af4B/QH8Af9QAAHTAd8B6wH/AegB9AL/ASUBqAHuAf8BAAFLAb4B/wEAAUsBvgH/ASUBqAHu - Af8B6AH0Av8B0wHfAesB/xgACP8D/gH/A/cB/wGUAb0B4AH/AQABTgHHAf8BAAFOAccB/wGUAb0B4AH/ - A/YB/wP+Gf8MAAHfAcsBsQH/AdwBuAFAAf8B4wG4ATEB/wHjAbQBJQH/Ad0BrgEdAf8B4QGyASEB/wHi - AbYBKwH/AdsBswE3Af8B3gHIAaoB/wL+Af0B/1gAA98B/wHoAfQC/wGYAaQBsAH/AZgBpAGwAf8B6AH0 - Av8D3wH/HAAM/wP+Af8D9wH/AZQBvQHgAf8BlAG9AeAB/wP2Af8D/h3/EAAB9gHxAesB/wHkAdQBvwH/ - Ad4BxQGjAf8B3gHEAZwB/wHeAcQBoQH/AeQB0wG8Af8B9QHvAekB/2QAAdMB3wHrAf8B6AH0Av8B6AH0 - Av8B0wHfAesB/yAAEP8D/gH/A/cB/wP2Af8D/iH/WQABDQG5Af8CAAEuAf8CAAEQAf/1AAEuAccB/wEA - Ac0B/AH/AQABDwGHAf+0AAM7AWUBAAEEAQAB/wM6AWA1AAEuAccB/wEAAaAB0gH/AQABBQElAf8cAAMB - AQIDAAEBGwABAQwAASIBIQEiATEDAAEBXAADPgFqAQABpwEAAf8BAAEIAQAB/wEAAQQBAAH/AzYBWDEA - AS4BxwH/AQAB0QH8Af8BAAEPAYcB/zMAAQEDAAEBEAAB7AHSAewB/wElAQABJAH/AeYBzAHmAf8DAgED - AxIBGRAAASIBLAEuAf8BGAEgASMB/wEPARQBFwH/AQUBCAELAf8DAAH/AwAB/wMAAf8DAAH/AwAB/xwA - Az4BagEAAacBAAH/ARwBuwEQAf8BAAEMAQAB/wEAAQkBAAH/AQABBAEAAf8DNQFXLQABLgHHAf8BAAGh - AdEB/wEAAQUBJQH/PwABAQQAAe0B2AHtAf8BqQEDAagB/wGAAQABMgH/ASgBAAEoAf8B6wHRAesB/xQA - ASsBggGDAf8BlwHbAfUB/wEOAakBygH/AQ4BqQHKAf8BDQGnAckB/wEFAZ8BwgH/AQABlgG5Af8BAAGN - AbAB/wMAAf8dAAGkAQAB/wEcAbsBEAH/ARwBuwEQAf8BAAELAQAB/wEAAQwBAAH/AQABCQEAAf8BAAEE - AQAB/wMwAUwpAAEuAccB/wEEAeIB/QH/AQABCwGAAf8jAAEBAwABAQMAAQEDAAEBAwABAQMAAQEDAAEB - BAAB6AHRAegB/wGqAQMBqQH/AcwBGgHLAf8BMQEAATEB/wGWAQABlQH/AS4BAAEtAf8B8AHVAfAB/xAA - ATMCjAH/AaAB4AH3Af8BJAHNAfEB/wEXAccB7gH/AQsBwQHrAf8BAAG8AegB/wEAAbcB5gH/AQABkgG2 - Af8DAAH/HQABpwEAAf8BHAG7ARAB/wEcAbsBEAH/AaoB1AGiAf8BAAGgAQAB/wEAAQwBAAH/AQABCQEA - Af8BAAEDAQAB/ykAAS4BxwH/AQsB1wH8Af8BAAELAYAB/yQAAasB8AH3Af8BqwHiAeUB/wGsAc4BzAH/ - Aa0BuwG1Af8BrgGnAZwB/wQAAeQBygHkAf8BqQEDAagB/wHTAR4B0gH/AdQBIQHTAf8BMgEAATEB/wGf - AQABnwH/AY4BAAGNAf8BMAEAAS8B/xAAAYUClAH/AacB4wH4Af8BLwHTAfQB/wEkAc4B8QH/ARgByAHu - Af8BCwHCAesB/wEAAbwB6AH/AQABmQG8Af8DAAH/GAADAgEDAQEBqwEAAf8BHAG7ARAB/wGqAdQBogH/ - AbcB2gGwAf8BqgHUAaIB/wEAAZMBAAH/AQABDAEAAf8BAAEEAQAB/yUAARMBkAH/AQABLgHHAf8BIQHe - AfwB/wEAAQsBgAH/AQABAQEtAf84AAGqAQUBqQH/AdIBHQHRAf8B1QEiAdUB/wG9ASMBvAH/Ad4BmAHd - Af8BjwEAAY4B/wGdAQABnAH/ATEBAAExAf8QAAGMApsB/wGuAeYB+gH/AYYB2AH2Af8BLwHUAfQB/wEk - Ac0B8QH/ARgBxwHuAf8BCwHCAesB/wEGAaABwQH/AwAB/xgAAwQBBQEWAbgBCQH/AbQB2QGtAf8BxQHi - AcAB/wG3AdoBsAH/AbcB2gGwAf8BqgHUAaIB/wEAAYgBAAH/AQABBAEAAf8hAAEiAaAB/wEAAYcBxwH/ - AQ4BwAHwAf8BAwHLAf4B/wEEAbMB3QH/AgABGQH/AQABAQEtAf8YAAGrAfAB9wH/AasB5QHpAf8BrALV - Af8BrAHEAcEB/wGtAbUBrAH/Aa4BpAGYAf8EAAGoAQIBpwH/AdIBIAHRAf8BvAEiAbsB/wHvAaUB7gH/ - AfsBnwH6Af8B7wGdAe4B/wGXAQUBlgH/AS8BAAEvAf8QAAGRAaIBoQH/AbIB6AH8Af8BoAHiAfoB/wGG - AdgB9gH/ATAB0wHzAf8BJAHOAfEB/wEXAcgB7gH/AQoBpQHHAf8CAAEFAf8YAAMCAQMDRAF6AY4BxgGE - Af8BuQHcAbMB/wHDAeEBvgH/AcMB4QG+Af8BtwHaAbAB/wGqAdQBogH/AQABGgEAAf8dAAGAAbEB/wEA - AYcByAH/AQUBugH3Af8BBwHCAfkB/wEAAbcB+QH/ARsB1gH7Af8BAAGmAegB/wIAARcB/wEAAQQBgwH/ - MAABpwEDAaYB/wG8ASIBuwH/Ae8BpQHuAf8B+wGbAfoB/wH7AZgB+gH/AfsBmQH6Af8B5wGYAeYB/wGR - AQEBkAH/EAABlAGmAaUB/wG9AewB/AH/AaUB5QH7Af8BnwHiAfoB/wGGAdgB9gH/ATAB1AH0Af8BJAHN - AfEB/wEOAakBygH/AQcBCwEOAf8gAANGAX4BkAHHAYYB/wG+Ad4BuAH/AcMB4QG+Af8BswHZAawB/wGQ - AccBhgH/Az0BaR0AAS4BuAH/AQcBwQH5Af8BAwG3AfkB/wGTAe4B/gH/AY8B7AH+Af8BBQG0AfMB/wGN - AeMB/gH/AQIBugHiAf8BAAEBAR4B/xwAAasB8AH3Af8BrALVAf8BrgG0AawB/wGuAZkBigH/A/0B/wHP - AYgBzwH/AeIBrwHiAf8B+wGrAfoB/wH7AZgB+gH/AfsBmAH6Af8B6gGQAekB/wHPAYgBzwH/AfQB5gH0 - Af8QAAGUAaYBpQH/Ab0B7AH8Af8BvQHsAfwB/wGyAegB/AH/Aa4B5gH6Af8BpwHkAfkB/wGgAeAB9wH/ - AZcB2wH1Af8BEAEVARkB/yQAA0cBgQGUAckBigH/Ab0B3gG3Af8BjgHGAYQB/wMwAUshAAGDAbsB/wEM - AcYB+QH/ARwBigGsAf8BHAGKAawB/wEcAYoBrAH/ARwBigGsAf8BHAGKAawB/wEVAdUB+gH/AgABGwH/ - MAAB8AHUAfAB/wHPAYgBzwH/Ae4BvgHuAf8B+wGuAfoB/wHsAZEB6wH/Ac8BiAHPAf8B8wHgAfIB/xQA - AZQBpgGlAf8BlAGmAaUB/wGTAqUB/wGPAZ8BngH/AYgClwH/AYECjgH/ASwChAH/ASIBLAEuAf8BGQEg - ASIB/ygAAzwBZgGUAckBigH/AyUBNyUAAYMBvAH/AQ8B0gH6Af8BAAEXAYQB/w0AAZABwQH/AQYBuwHh - Af8CAAEYAf80AAHyAdsB8gH/Ac8BiAHPAf8B4wGsAeMB/wHPAYgBzwH/AfMB4wHzAf9gAAMBAQIEAAMB - AQIpAAGIAcEB/wEAAZ0B0AH/AS0B4wH6Af8BAAGFAZ4B/wEEARcBhwH/AQQBKQGcAf8BBQG/AfQB/wEA - AYwBqgH/AQABCwEtAf84AAHyAdsB8gH/Ac8BiAHPAf8B8AHjAfAB/5kAAZQBxgH/AQABigHBAf8BAAGa - Ac0B/wEhAdUB9QH/ASQB6QH+Af8BIAHUAfMB/wEAAZIBsgH/AQABFwGMAf8BAAEjAaIB/zwAAf4B+wH+ - Af+hAAGUAcYB/wEAAY0BwwH/AQABiwG6Af8BAAGLAboB/wEAAYgBtwH/AQABJgGgAf8BAAGCAbIB//8A - qQADNgFYAZkCAAH/AzMBU/AAAzgBXQHXAZoBAAH/AZkCAAH/AZkCAAH/Ay8BSiwAAx4BKwNUAa4BWQJk - AewBAAGDAZYB/wEAARkBjQH/AQABEAGMAf8BTgJdAfADVgGzAyUBN5gAAzoBYQHXAZoBAAH/AdgBmwEA - Af8BmQIAAf8BmQIAAf8BmQIAAf8DLwFKKAABWwJeAdABAAGwAdEB/wGEAdUB6AH/AaEB6wH2Af8BFgHk - Av8BAAG+AfMB/wEAAZ8B3gH/AQABiwG+Af8BWwJeAdlUAAG3AaIBkwH/AQYCAAH/AQYCAAH/AQYCAAH/ - AQYCAAH/AQYCAAH/AQYCAAH/AQYCAAH/AQYCAAH/AQYCAAH/AQYCAAH/AQYCAAH/FAAB2AGbAQAB/wHY - AZsBAAH/AdgBmwEAAf8BmQIAAf8BmQIAAf8BmQIAAf8BmQIAAf8DLwFKJQABjwGqAf8BAAHXAv8BkAHq - AfoB/wGhAesB9gH/ARQB2QH0Af8BAAG8AfIB/wEAAacB6AH/AQABnAHaAf8BAAEGAYQB/xQAAzEBTQJS - AVEBoQFfAlgB4wFfAlgB4wFSAlEBoQExAjABTQQAAzEBTQJSAVEBoQFfAlgB4wFfAlgB4wFSAlEBoQEx - AjABTQwAAbcBogGTAf8B/QH7AfkB/wHhAdwB2AH/AeAB1wHSAf8B3wHOAcMB/wHdAcgBuwH/AdsBvwGt - Af8B2wG7AacB/wHbAbsBpwH/AdsBuwGnAf8BzwG0AaMB/wEGAgAB/xQAAdgBmwEAAf8B2AGbAQAB/wHp - AbQBHwH/AfwB1gGvAf8BtQEGAQAB/wGZAgAB/wGZAgAB/wGZAgAB/wMvAUohAAGRAa4B/wEAAdIB+gH/ - AY0B5AH2Af8BoQHrAfYB/wETAdcB8wH/AQABuQHvAf8BAAGnAegB/wEAAZwB2gH/AQABCAGGAf8QAAM1 - AVUDZAHnAc8BuAGpAf8B6wHWAcgB/wHlAcsBuwH/AbMBlQEiAf8BZAJcAecDSwGOA2QB5wHPAbgBqQH/ - AesB1gHIAf8B5QHLAbsB/wGzAZUBIgH/AWQCXAHnATUCNAFVCAABtwGiAZMB/wP+Af8BugGmAZgB/wG1 - AaABkQH/AfsB7AHjAf8BpAGNASEB/wGaAYMBFQH/AfYB1gHCAf8BiAEUAQEB/wGDAQ4BAAH/Ac8BtAGj - Af8BBgIAAf8UAAHYAZsBAAH/AeoBtwGCAf8B+wHYAbIB/wH+AdEBowH/AfsB2AGyAf8BrwIAAf8BmQIA - Af8BmQIAAf8BmQIAAf8DKgFBHQABlQGwAf8BAAHSAfoB/wGNAeQB9AH/AaEB6wH2Af8BEwHXAfIB/wEA - AbkB7gH/AQABpwHoAf8BAAGcAdoB/wEAAQsBiAH/EAADVQGyAeYB1gHLAf8DWQHCAmABXAHUA2AB1AFM - ASoBIQH7AwAB/wMAAf8DAAH/AWECWAHmAmABXAHUA2AB1ANZAcIBuQGcAYgB/wNVAbIIAAG6AaUBlgH/ - A/4B/wP+Af8D/gH/Af0B+wH5Af8B/QH3AfMB/wH7AewB4wH/AfoB5wHbAf8B+AHhAdIB/wH3AdsByQH/ - AdABuQGrAf8BBgIAAf8UAAHnAbMBHwH/AfEBwwGRAf8B/gHPAZ0C/wHNAZkB/wH+AdABnwH/AfsB2AGy - Af8BqQIAAf8BmQIAAf8BmQIAAf8BmQIAAf8DBAEFGQABmQG1Af8BAAHRAfsB/wGOAeQB9QH/AaEB6wH2 - Af8BEwHXAfIB/wEAAbkB7gH/AQABpwHoAf8BAAGcAdoB/wEAAQ4BigH/EAADZQH0BP8DVwHfAx0BKgNc - Ac0F/wH+AfcC/wHxAeYB/wH6AeMB1AH/AfMB1wHHAf8DSgGNAx0BKgNcAd8B7wHWAccB/wFkAlIB9AgA - Ab4BqQGaAf8D/gH/AboBpgGYAf8BtAGgAZEB/wP+Af8BowGOASEB/wGaAYMBFQH/AfsB7AHjAf8BiQEU - AQIB/wGDAQ4BAAH/AdEBwQG2Af8BBgIAAf8UAANFAXwB5QGyAR4B/wH0AcABiwL/Ac0BmQL/Ac0BmQH/ - Af4B0AGhAf8B+wHYAbIB/wGpAgAB/wGZAgAB/wGZAgAB/x0AAZsBtwH/AQAB0AH5Af8BjQHjAfUB/wGh - AesB9gH/ARUB2QHyAf8BAAG5Ae4B/wEAAacB6AH/AQABnAHaAf8BAAEQAY0B/xAAA1UBsgHyAeYB3gH/ - A1kBwgNcAdQBYAJcAdQDYQHiAdMBtQGiAf8DTQH6AdoBwAGvAf8DXwHzA1sB1gFgAlwB1ANZAcIBywGx - AaEB/wNVAbIIAAHDAa4BngH/A/4B/wP+Af8D/gH/A/4B/wP+Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHj - Af8B+gHnAdsB/wHRAcEBtgH/AQYCAAH/GAADRgF/AeQBsAEcAf8B9gHEAZAC/wHNAZkC/wHNAZkB/wH+ - AdABoQH/AfsB2AGyAf8BqQIAAf8BmQIAAf8cAAEBAZ4BugH/AQAB0AH5Af8BjQHjAfQB/wGhAesB9gH/ - ARIB1wHyAf8BAAG3Ae4B/wEAAacB6AH/AQABnAHaAf8BAAESAY8B/xAAAzUBVQNkAecB7QHhAdcD/wH9 - Av8B9wHxAf8B2AHEAbcB/wNkAecDSwGOA2QB5wHtAeEB1wP/Af0C/wH3AfEB/wHYAcQBtwH/A2QB5wM1 - AVUIAAHIAbIBowH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaQBjgEhAf8BmQGEARUB/wH9AfcB8wH/ - AYgBFAEBAf8BgwEOAQAB/wHRAcEBtgH/AQYCAAH/HAADSQGHAeMBrwEbAf8B9gHEAZAC/wHNAZkC/wHN - AZkB/wH+AdABoQH/AfIByQGdAf8BsAIAAf8cAAECAaIBvAH/AQABzgH3Af8BiwHjAfQB/wGhAesB9gH/ - AREB1gHyAf8BAAG3Ae4B/wEAAacB6AH/AQABnAHaAf8BAAETAZIB/xQAAzEBTQNSAaEDXwHjA18B4wNS - AaEDMQFNBAADMQFNA1IBoQNfAeMDXwHjA1IBoQMxAU0MAAHMAbYBpwH/A/4B/wP+Af8D/gH/A/4B/wP+ - Af8D/gH/Af0B+wH5Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8BBgIAAf8gAANJAYcB4wGvARsB/wH2 - AcQBkAL/Ac0BmQH/AfMBwgGOAf8B4wGwARwB/wNDAXgcAAEOAakBwAH/AQAB1AH6Af8BnAHsAfoB/wGr - Ae8B+gH/AaYB7QH4Af8BlAHnAfgB/wEUAdkB9gH/AQABvQHpAf8BAAEfAZcB/1QAAeoBqgGLAf8B6gGq - AYsB/wHqAaoBiwH/AekBpQGEAf8B5wGXAREB/wHmAY4BBQH/AeMBIAEAAf8B4wEZAQAB/wHiARUBAAH/ - AeIBFQEAAf8B4gEVAQAB/wHIAQUBAAH/JAADSQGHAeMBrwEbAf8B7gG9AYoB/wHjAbABHAH/AzQBVCAA - AYABswHFAf8BmwHeAesB/wHFAfkB/QH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BoAHf - AeoB/wEJAZEBogH/VAAB6gGqAYsC/wHCAaIB/wH+AcABnwH/Af0BvQGaAf8B+wG1AZAB/wH6AbABiwH/ - AfgBpwEgAf8B9gGiARoB/wH1AZ0BFAH/AfUBmQENAf8B8wGVAQgB/wHNAQgBAAH/KAADQAFuAeUBsgEg - Af8DJgE4JAADOwFjA2AB1gEZAasBugH/ARMBowGzAf8BDwGdAa8B/wEOAZsBrgH/ARIBogG0Af8DXgHZ - A0ABb1QAAeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGhASIB/wHoAZsBGQH/AeYBjgEF - Af8B5QGHAQAB/wHkAYEBAAH/AeQBHgEAAf8B4wEZAQAB/wHiARUBAAH//wD/AAoAAUIBTQE+BwABPgMA - ASgDAAFAAwABQAMAAQEBAAEBBgABAhYAA/+BAAX/AcMCAAHwAR8D/wGBAgABwAEHAfMBnwH/AwABgAED - AecBzwH/AcACAAGAAQMB5wHPAf8EAAEBAecBzwHnBAABAQHnAc8BwwEBAwABAQHPAecBgQQAAQEB5wHP - BQABAQHnAc8FAAEBAecBzwUAAQEB5wHPAQABAQIAAYABAwHzAZ8BgAETAgABgAEDAv8BwAE/AgAB4AEH - Av8B4AF/AgAB8AEfAv8B8AH/AgAC/wH8AX8G/wH8AX8E/wH8AX8B/AF/AT8BcwL/AfgBPwH8AX8B+QHg - AfABBwHwAR8B/AF/Af8BQQHwAQcB8AEPAfwBfwKAAfABBwHwAQ8B/AF/AcEBAAHwAQcB4AEPAfgBPwH/ - AQAB8AEHAeABDwHwAR8BgQEAAfABBwHgAQ8B4AEPAf8BAAHwAQcB+AEPAeABDwHgAQAB8AEHAfwBHwHg - AQ8B/wEBAfABBwH+AT8B4wGPAf8BgwL/Af0BfwHgAQ8B/wHHBP8B4AEPAf8B7wT/AfABHwz/AfgH/wHw - AX8B8AEHBP8B4AE/AfABBwL/AcABAwHgAR8B8AEHAcABgQHAAQMB4AEPAfABBwGAAQABwAEDAeABBwHw - AQcBgAEAAcABAwHgAQMB8AEHAYABAAHAAQMB4AEHAfABBwGAAQABwAEDAfABBwHwAQcBgAEAAcABAwH4 - AQcB8AEHAcABgQHAAQMB/AEHAfABBwL/AcABAwH+AQ8B8AEHAv8BwAEDAf8BHwHwAQcC/wHAAQMQ/ws= diff --git a/Src/SwqlStudio/ObjectExplorer/IMetadataProvider.cs b/Src/SwqlStudio/Metadata/IMetadataProvider.cs similarity index 88% rename from Src/SwqlStudio/ObjectExplorer/IMetadataProvider.cs rename to Src/SwqlStudio/Metadata/IMetadataProvider.cs index 1bbe11b9b..a65538de1 100644 --- a/Src/SwqlStudio/ObjectExplorer/IMetadataProvider.cs +++ b/Src/SwqlStudio/Metadata/IMetadataProvider.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; -using SwqlStudio.Metadata; -namespace SwqlStudio +namespace SwqlStudio.Metadata { interface IMetadataProvider { diff --git a/Src/SwqlStudio/Metadata/ITypedMetadata.cs b/Src/SwqlStudio/Metadata/ITypedMetadata.cs new file mode 100644 index 000000000..9b52685bb --- /dev/null +++ b/Src/SwqlStudio/Metadata/ITypedMetadata.cs @@ -0,0 +1,9 @@ +namespace SwqlStudio.Metadata +{ + public interface ITypedMetadata + { + string Name { get; set; } + string Type { get; set; } + string Summary { get; set; } + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/Metadata/Property.cs b/Src/SwqlStudio/Metadata/Property.cs index ab4aac946..2c9d7d7eb 100644 --- a/Src/SwqlStudio/Metadata/Property.cs +++ b/Src/SwqlStudio/Metadata/Property.cs @@ -1,7 +1,7 @@  namespace SwqlStudio.Metadata { - public class Property + public class Property : ITypedMetadata { public string Name { get; set; } public string Type { get; set; } diff --git a/Src/SwqlStudio/ObjectExplorer/SwisMetaDataProvider.cs b/Src/SwqlStudio/Metadata/SwisMetaDataProvider.cs similarity index 98% rename from Src/SwqlStudio/ObjectExplorer/SwisMetaDataProvider.cs rename to Src/SwqlStudio/Metadata/SwisMetaDataProvider.cs index fa4988b1e..c3eae838f 100644 --- a/Src/SwqlStudio/ObjectExplorer/SwisMetaDataProvider.cs +++ b/Src/SwqlStudio/Metadata/SwisMetaDataProvider.cs @@ -2,9 +2,8 @@ using System.Collections.Generic; using System.Data; using System.Linq; -using SwqlStudio.Metadata; -namespace SwqlStudio +namespace SwqlStudio.Metadata { class SwisMetaDataProvider : IMetadataProvider { diff --git a/Src/SwqlStudio/Metadata/VerbArgument.cs b/Src/SwqlStudio/Metadata/VerbArgument.cs index 1fe7f2b29..25e9498a7 100644 --- a/Src/SwqlStudio/Metadata/VerbArgument.cs +++ b/Src/SwqlStudio/Metadata/VerbArgument.cs @@ -1,6 +1,6 @@ namespace SwqlStudio.Metadata { - public class VerbArgument + public class VerbArgument : ITypedMetadata { public string Name { get; set; } diff --git a/Src/SwqlStudio/ObjectExplorer/ArgumentsPlaceholderTreeNode.cs b/Src/SwqlStudio/ObjectExplorer/ArgumentsPlaceholderTreeNode.cs new file mode 100644 index 000000000..99ffc8915 --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/ArgumentsPlaceholderTreeNode.cs @@ -0,0 +1,17 @@ +using System.Windows.Forms; +using SwqlStudio.Metadata; + +namespace SwqlStudio +{ + internal class ArgumentsPlaceholderTreeNode : TreeNode + { + public Verb Verb { get; set; } + public IMetadataProvider Provider { get; set; } + + public ArgumentsPlaceholderTreeNode(Verb verb, IMetadataProvider provider) + { + Verb = verb; + Provider = provider; + } + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/ObjectExplorer/Documentation.cs b/Src/SwqlStudio/ObjectExplorer/Documentation.cs new file mode 100644 index 000000000..fe1bd3e6e --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/Documentation.cs @@ -0,0 +1,16 @@ +namespace SwqlStudio +{ + internal class Documentation + { + public string ItemType { get; set; } + public string Documents { get; set; } + + public static readonly Documentation Empty = new Documentation(string.Empty, string.Empty); + + public Documentation(string itemType, string documents) + { + this.ItemType = itemType; + this.Documents = documents; + } + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/ObjectExplorer/DocumentationBuilder.cs b/Src/SwqlStudio/ObjectExplorer/DocumentationBuilder.cs new file mode 100644 index 000000000..b45efaa8c --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/DocumentationBuilder.cs @@ -0,0 +1,141 @@ +using System; +using System.Text; +using System.Windows.Forms; +using SwqlStudio.Metadata; + +namespace SwqlStudio +{ + internal class DocumentationBuilder + { + public static Documentation Build(TreeNode node) + { + var data = node.Tag; + var connectedNode = node as TreeNodeWithConnectionInfo; + var provider = connectedNode?.Provider; + + if (provider == null) + return Documentation.Empty; + + if (data is SwisMetaDataProvider) + return ProviderDocumentation(provider); + + if (data is string nameSpace) + return NamespaceDocumentation(nameSpace, node.Nodes.Count); + + if (data is Entity entity) + return EntityDocumentation(provider, entity); + + if (data is Property property) + return PropertyDocumentation(property); + + if (data is Verb verb) + return VerbDocumentation(verb); + + if (data is VerbArgument verbArg) + return VerbArgumentDocumentation(verbArg); + + return Documentation.Empty; + } + + private static Documentation VerbArgumentDocumentation(VerbArgument verbArg) + { + var docs = MetadataDocumentation(verbArg); + return new Documentation("Verb argument", docs); + } + + private static Documentation VerbDocumentation(Verb verb) + { + var builder = new StringBuilder(); + builder.AppendName(verb.Name); + builder.AppendSummaryParagraph(verb.Summary); + var docs = builder.ToString(); + return new Documentation("Verb", docs); + } + + private static Documentation EntityDocumentation(IMetadataProvider provider, Entity entity) + { + var builder = new StringBuilder(); + builder.AppendName(entity.FullName); + builder.Append($"Base type: {entity.BaseType}\r\n"); + builder.AppendAccessControl(provider.ConnectionInfo, entity); + builder.AppendSummaryParagraph(entity.Summary); + var docs = builder.ToString(); + return new Documentation("Entity", docs); + } + + private static Documentation NamespaceDocumentation(string nameSpace, int childrenCount) + { + var builder = new StringBuilder(); + builder.AppendName(nameSpace); + var children = ChildrenText(childrenCount); + builder.Append(children); + var docs = builder.ToString(); + return new Documentation("Namespace", docs); + } + + private static Documentation PropertyDocumentation(Property property) + { + var docs = MetadataDocumentation(property); + return new Documentation("Property", docs); + } + + private static Documentation ProviderDocumentation(IMetadataProvider provider) + { + var documents = $@"Connection: {provider.Name}"; + return new Documentation("Database", documents); + } + + private static string MetadataDocumentation(ITypedMetadata metadata) + { + var builder = new StringBuilder(); + builder.AppendName(metadata.Name); + builder.AppendType(metadata.Type); + builder.AppendSummaryParagraph(metadata.Summary); + return builder.ToString(); + } + + public static string ToToolTip(ITypedMetadata metadata) + { + var builder = new StringBuilder(); + builder.AppendSummary(metadata.Summary); + return builder.ToString(); + } + + public static string ToToolTip(ConnectionInfo connection, Entity entity) + { + var builder = new StringBuilder(); + builder.AppendSummary(entity.Summary); + return builder.ToString(); + } + + public static string ToToolTip(Verb verb) + { + var builder = new StringBuilder(); + builder.AppendSummary(verb.Summary); + return builder.ToString(); + } + + public static string ToNodeText(string name, int childrenCount) + { + var children = ChildrenText(childrenCount); + return $"{name} ({children})"; + } + + private static string ChildrenText(int childrenCount) + { + var countSuffix = childrenCount > 1 ? "s" : String.Empty; + return $"{childrenCount} item{countSuffix}"; + } + + public static string ToNodeText(ITypedMetadata metadata) + { + return $"{metadata.Name} ({metadata.Type})"; + } + + public static string ToBaseNodeText(TreeNode baseNode, int childrenCount) + { + var entitiesSuffix = childrenCount > 1 ? "ies" : "y"; + return $"{baseNode.Text} ({childrenCount} derived entit{entitiesSuffix})"; + } + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/ObjectExplorer/EntityGroupingMode.cs b/Src/SwqlStudio/ObjectExplorer/EntityGroupingMode.cs new file mode 100644 index 000000000..5270b3103 --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/EntityGroupingMode.cs @@ -0,0 +1,10 @@ +namespace SwqlStudio +{ + internal enum EntityGroupingMode + { + Flat = 1, + ByNamespace = 2, + ByBaseType = 3, + ByHierarchy = 4 + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/ObjectExplorer/ImageKeys.cs b/Src/SwqlStudio/ObjectExplorer/ImageKeys.cs new file mode 100644 index 000000000..def13677d --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/ImageKeys.cs @@ -0,0 +1,53 @@ +using SwqlStudio.Metadata; + +namespace SwqlStudio +{ + internal class ImageKeys + { + internal const string Database = "Database"; + internal const string Namespace = "Namespace"; + internal const string Verb = "Verb"; + internal const string Argument = "Argument"; + + internal const string BaseTypeAbstract = "BaseTypeAbstract"; + internal const string BaseType = "BaseType"; + + internal const string Indication = "Indication"; + internal const string TableAbstract = "TableAbstract"; + internal const string TableCrud = "TableCrud"; + internal const string Table = "Table"; + + internal const string Column = "Column"; + internal const string Link = "Link"; + internal const string KeyColumn = "KeyColumn"; + internal const string InheritedColumn = "InheritedColumn"; + + public static string GetImageKey(Entity entity) + { + if (entity.IsIndication) + return Indication; + + if (entity.IsAbstract) + return TableAbstract; + + if (entity.CanCreate || entity.CanDelete || entity.CanUpdate) + { + return TableCrud; + } + + return Table; + } + + public static string GetImageKey(Property property) + { + if (property.IsNavigable) + return Link; + if (property.IsKey) + return KeyColumn; + if (property.IsInherited) + return InheritedColumn; + + return Column; + } + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs index d7cc3feb2..9b66e815e 100644 --- a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.cs @@ -17,21 +17,13 @@ namespace SwqlStudio { - enum EntityGroupingMode - { - Flat = 1, - ByNamespace = 2, - ByBaseType = 3, - ByHierarchy = 4 - } - - class ObjectExplorer : Control + internal class ObjectExplorer : Control { private static readonly Log log = new Log(); private readonly SearchTextBox _treeSearch; private readonly TreeView _tree; - private readonly TreeView _treeData; + private TreeView _treeData; private TreeNodeUtils.TreeNodeBindings _treeBindings = new TreeNodeUtils.TreeNodeBindings(); // default value, so this field is never null private TreeNode _contextMenuNode; private readonly Dictionary _tableContextMenuItems; @@ -42,15 +34,18 @@ class ObjectExplorer : Control private string _filter; private bool _treeIsUnderUpdate; private Point _lastLocation; + private ImageList objectExplorerImageList; + private System.ComponentModel.IContainer components; private TreeNode _dragNode; - + private readonly TreeNodesBuilder treeNodesBuilder = new TreeNodesBuilder(); + public event TreeViewEventHandler SelectionChanged; public ITabsFactory TabsFactory { get; set; } - public EntityGroupingMode EntityGroupingMode { get; set; } - public ObjectExplorer() { + InitializeComponent(); + _treeSearch = new SearchTextBox { Dock = DockStyle.Top @@ -63,18 +58,41 @@ public ObjectExplorer() ShowNodeToolTips = true }; + InitializeTreeview(); + + _treeSearch.TextChangedWithDebounce += (sender, e) => { SetFilter(((TextBox) sender).Text); }; + _treeSearch.CueText = "Search (Ctrl + \\)"; + _treeSearch.DebounceLimit = TimeSpan.FromMilliseconds(400); + + _tableContextMenuItems = new Dictionary(); + _serverContextMenuItems = new Dictionary(); + _tableCrudContextMenuItems = new Dictionary(); + + _verbContextMenu = new ContextMenu(); + _verbContextMenu.MenuItems.Add("Invoke...", (s, e) => OpenInvokeTab()); + + Controls.Add(_tree); + Controls.Add(_treeSearch); + } + + private void InitializeTreeview() + { _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.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 + // 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); @@ -91,19 +109,13 @@ public ObjectExplorer() }; _tree.NodeMouseDoubleClick += _tree_NodeMouseDoubleClick; - _treeSearch.TextChangedWithDebounce += (sender, e) => { SetFilter(((TextBox) sender).Text); }; - _treeSearch.CueText = "Search (Ctrl + \\)"; - _treeSearch.DebounceLimit = TimeSpan.FromMilliseconds(400); - - _tableContextMenuItems = new Dictionary(); - _serverContextMenuItems = new Dictionary(); - _tableCrudContextMenuItems = new Dictionary(); - - _verbContextMenu = new ContextMenu(); - _verbContextMenu.MenuItems.Add("Invoke...", (s, e) => OpenInvokeTab()); + _tree.AfterSelect += OnTreeOnAfterSelect; + _tree.ImageList = this.objectExplorerImageList; + } - Controls.Add(_tree); - Controls.Add(_treeSearch); + private void OnTreeOnAfterSelect(object sender, TreeViewEventArgs args) + { + this.SelectionChanged?.Invoke(this, args); } public void FocusSearch() @@ -293,23 +305,15 @@ private void TreeMouseMove(object sender, MouseEventArgs e) void _tree_BeforeExpand(object sender, TreeViewCancelEventArgs e) { - if (e.Node.Tag is Verb verb) + var verbNode = e.Node; + if (verbNode.Tag is Verb) { - e.Node.Nodes.Clear(); - - foreach (var arg in FindProvider(e.Node).GetVerbArguments(verb)) - { - string text = $"{arg.Name} ({arg.Type})"; - var argNode = new TreeNode(text) { SelectedImageKey = "Argument" }; - argNode.ImageKey = argNode.SelectedImageKey; - argNode.Tag = arg; - if (!string.IsNullOrEmpty(arg.Summary)) - argNode.ToolTipText = arg.Summary; - e.Node.Nodes.Add(argNode); - } + var provider = FindProvider(verbNode); + TreeNodesBuilder.RebuildVerbArguments(verbNode, provider); } } + void _tree_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) { if (e.Node.Tag != null) @@ -334,14 +338,11 @@ void _tree_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) private IMetadataProvider FindProvider(TreeNode node) { - var provider = node.Tag as IMetadataProvider; - if (provider != null) - return provider; + var providerNode = node as TreeNodeWithConnectionInfo; + if (providerNode?.Provider != null) + return providerNode.Provider; - if (node.Parent == null) - throw new InvalidOperationException("No IMetadataProvider found in tree."); - - return FindProvider(node.Parent); + throw new InvalidOperationException("No IMetadataProvider found in tree."); } public void RefreshAllServers() @@ -377,12 +378,11 @@ private void RefreshServer(TreeNode node) provider.Refresh(); BeginInvoke(new Action(() => { - node.Nodes.Clear(); var treeNodeWithConnectionInfo = node as TreeNodeWithConnectionInfo; if (treeNodeWithConnectionInfo != null) - AddTablesToNode(node, provider, treeNodeWithConnectionInfo.Connection); + this.treeNodesBuilder.RebuildDatabaseNode(node, provider); else - AddTablesToNode(node, provider, null); + node.Nodes.Clear(); UpdateDrawnNodes(); })); @@ -497,12 +497,6 @@ private string GenerateSwql(Entity table, bool includeInheritedProperties) return sb.ToString(); } - public ImageList ImageList - { - get { return _tree.ImageList; } - set { _tree.ImageList = value; } - } - public void AddServer(IMetadataProvider provider, ConnectionInfo connection) { //Check if the current connection can create subscription @@ -558,16 +552,11 @@ public void AddServer(IMetadataProvider provider, ConnectionInfo connection) _serverContextMenuItems.Add(connection.Title, serverContextMenu); - - TreeNode node = CreateDatabaseNode(provider, connection); - - TreeNode[] existingNodes = _treeData.Nodes.Find(node.Name, false); + TreeNode[] existingNodes = _treeData.Nodes.Find(provider.Name, false); if (existingNodes.Length == 0) { - // Node doesn't already exist. Add it - _treeData.Nodes.Add(node); - _treeData.SelectedNode = node; - RefreshServer(node); + TreeNode databaseNode = TreeNodesBuilder.CreateDatabaseNode(_treeData, provider, connection); + RefreshServer(databaseNode); } else { @@ -617,215 +606,6 @@ private void RemoveFromMenus(ConnectionInfo connection) serverContextMenu.Dispose(); } - private static TreeNode CreateDatabaseNode(IMetadataProvider provider, ConnectionInfo connection) - { - TreeNode node = new TreeNodeWithConnectionInfo(provider.Name, connection); - node.SelectedImageKey = "Database"; - node.ImageKey = "Database"; - node.Tag = provider; - node.Name = node.Text; - - return node; - } - - private void AddTablesToNode(TreeNode parent, IMetadataProvider provider, ConnectionInfo connection) - { - switch (EntityGroupingMode) - { - case EntityGroupingMode.Flat: - parent.Nodes.AddRange(MakeEntityTreeNodes(provider, connection, provider.Tables.OrderBy(e => e.FullName))); - break; - case EntityGroupingMode.ByNamespace: - foreach (var group in provider.Tables.GroupBy(e => e.Namespace).OrderBy(g => g.Key)) - { - TreeNode[] childNodes = MakeEntityTreeNodes(provider, connection, group.OrderBy(e => e.FullName)); - - int countChilds = childNodes.Length; - var namespaceNode = new TreeNode(string.Format("{0} ({1} item{2})", group.Key, countChilds, countChilds > 1 ? "s" : string.Empty)) - { - Tag = group.Key, - ImageKey = "Namespace" - }; - namespaceNode.SelectedImageKey = namespaceNode.ImageKey; - - namespaceNode.Nodes.AddRange(childNodes); - parent.Nodes.Add(namespaceNode); - } - break; - case SwqlStudio.EntityGroupingMode.ByBaseType: - foreach (var group in provider.Tables.Where(e => e.BaseEntity != null).GroupBy( - e => e.BaseEntity, - (key, group) => new { Key = key, Entities = group }).OrderBy(item => item.Key.FullName)) - { - TreeNode[] childNodes = MakeEntityTreeNodes(provider, connection, group.Entities.OrderBy(e => e.FullName)); - - int countChilds = childNodes.Length; - var baseTypeNode = new TreeNodeWithConnectionInfo( - string.Format("{0} ({1} item{2})", group.Key.FullName, countChilds, countChilds > 1 ? "s" : string.Empty), - connection) - { - Tag = group.Key - }; - baseTypeNode.ImageKey = !group.Key.IsAbstract ? "BaseType" : "BaseTypeAbstract"; - baseTypeNode.SelectedImageKey = baseTypeNode.ImageKey; - - baseTypeNode.Nodes.AddRange(childNodes); - parent.Nodes.Add(baseTypeNode); - } - break; - case SwqlStudio.EntityGroupingMode.ByHierarchy: - GroupByHierarchy(provider, connection, parent); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - private static void GroupByHierarchy(IMetadataProvider provider, ConnectionInfo connection, TreeNode baseNode) - { - Entity baseEntity = baseNode != null ? baseNode.Tag as Entity : null; - - var entities = provider.Tables.Where(e => baseEntity == null ? e.BaseEntity == null : e.BaseEntity == baseEntity); - - if (entities.Any()) - { - TreeNode[] childNodes = MakeEntityTreeNodes(provider, connection, entities.OrderBy(e => e.FullName)); - - baseNode.Nodes.AddRange(childNodes); - - if (baseEntity != null) - { - int countChilds = childNodes.Length; - baseNode.Text = string.Format("{0} ({1} derived entit{2})", baseNode.Text, countChilds, countChilds > 1 ? "ies" : "y"); - } - - foreach (var node in childNodes) - { - GroupByHierarchy(provider, connection, node); - } - - if (baseEntity == null) - { - foreach (var node in childNodes) - { - node.Expand(); - } - baseNode.Expand(); - } - } - } - - private static TreeNode[] MakeEntityTreeNodes(IMetadataProvider provider, ConnectionInfo connection, IEnumerable entities) - { - return entities.Select(e => MakeEntityTreeNode(provider, connection, e)).ToArray(); - } - - private static TreeNodeWithConnectionInfo MakeEntityTreeNode(IMetadataProvider provider, ConnectionInfo connection, Entity table) - { - var node = new TreeNodeWithConnectionInfo(table.FullName, connection); - node.ImageKey = GetImageKey(table); - node.SelectedImageKey = node.ImageKey; - node.Tag = table; - if (table.IsIndication) - { - node.ToolTipText += $@"{table.FullName} -{(string.IsNullOrEmpty(table.Summary) ? string.Empty : table.Summary + Environment.NewLine)}Base type: {table.BaseType} -CanSubscribe: {connection.CanCreateSubscription}"; - } - else - { - - node.ToolTipText = $@"{table.FullName} -{(string.IsNullOrEmpty(table.Summary) ? string.Empty : table.Summary + Environment.NewLine)}Base type: {table.BaseType} -CanCreate: {table.CanCreate} -CanUpdate: {table.CanUpdate} -CanDelete: {table.CanDelete}"; - } - - // Add keys - AddPropertiesToNode(node, table.Properties.Where(c => c.IsKey)); - - // Add the simple Properties - AddPropertiesToNode(node, table.Properties.Where(c => !c.IsInherited && !c.IsNavigable && !c.IsKey)); - - // Add the inherited Properties - AddPropertiesToNode(node, table.Properties.Where(c => c.IsInherited && !c.IsNavigable && !c.IsKey)); - - // Add the Navigation Properties - AddPropertiesToNode(node, table.Properties.Where(c => c.IsNavigable)); - - AddVerbsToNode(node, table, provider); - return node; - } - - private static string GetImageKey(Entity table) - { - if (table.IsIndication) - return "Indication"; - else if (table.IsAbstract) - return "TableAbstract"; - else if (table.CanCreate || table.CanDelete || table.CanUpdate) - return "TableCrud"; - - return "Table"; - } - - private static void AddVerbsToNode(TreeNode parent, Entity table, IMetadataProvider provider) - { - foreach (var verb in table.Verbs.OrderBy(v => v.Name)) - { - TreeNode verbNode = new TreeNode(verb.Name); - verbNode.SelectedImageKey = "Verb"; - verbNode.ImageKey = verbNode.SelectedImageKey; - verbNode.Tag = verb; - verbNode.ToolTipText = verb.Name + Environment.NewLine + verb.Summary; - - parent.Nodes.Add(verbNode); - - verbNode.Nodes.Add(new ObjectExplorer.ArgumentsPlaceholderTreeNode(verb, provider)); - } - } - - private class ArgumentsPlaceholderTreeNode : TreeNode - { - public Verb Verb { get; set; } - public IMetadataProvider Provider { get; set; } - - public ArgumentsPlaceholderTreeNode(Verb verb, IMetadataProvider provider) - { - Verb = verb; - Provider = provider; - } - } - - private static void AddPropertiesToNode(TreeNode parent, IEnumerable properties) - { - foreach (Property column in properties.OrderBy(c => c.Name)) - { - string text = $"{column.Name} ({column.Type})"; - TreeNode node = new TreeNode(text); - node.SelectedImageKey = GetColumnIcon(column); - node.ImageKey = node.SelectedImageKey; - node.Tag = column; - if (!string.IsNullOrEmpty(column.Summary)) - node.ToolTipText = text + Environment.NewLine + column.Summary; - - parent.Nodes.Add(node); - } - } - - private static string GetColumnIcon(Property column) - { - if (column.IsNavigable) - return "Link"; - if (column.IsKey) - return "KeyColumn"; - if (column.IsInherited) - return "InheritedColumn"; - - return "Column"; - } - private void Crud(Entity entity, CrudOperation operation) { var provider = FindProvider(_contextMenuNode); @@ -850,5 +630,39 @@ private void AddTextEditor(string query) TabsFactory.OpenQueryTab(query, node.Connection); } } + + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ObjectExplorer)); + this.objectExplorerImageList = new System.Windows.Forms.ImageList(this.components); + this.SuspendLayout(); + // + // objectExplorerImageList + // + this.objectExplorerImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("objectExplorerImageList.ImageStream"))); + this.objectExplorerImageList.TransparentColor = System.Drawing.Color.Transparent; + this.objectExplorerImageList.Images.SetKeyName(0, ImageKeys.Column); + this.objectExplorerImageList.Images.SetKeyName(1, ImageKeys.Database); + this.objectExplorerImageList.Images.SetKeyName(2, ImageKeys.Link); + this.objectExplorerImageList.Images.SetKeyName(3, ImageKeys.Table); + this.objectExplorerImageList.Images.SetKeyName(4, ImageKeys.InheritedColumn); + this.objectExplorerImageList.Images.SetKeyName(5, ImageKeys.KeyColumn); + this.objectExplorerImageList.Images.SetKeyName(6, ImageKeys.Verb); + this.objectExplorerImageList.Images.SetKeyName(7, ImageKeys.Argument); + this.objectExplorerImageList.Images.SetKeyName(8, ImageKeys.Indication); + this.objectExplorerImageList.Images.SetKeyName(9, ImageKeys.Namespace); + this.objectExplorerImageList.Images.SetKeyName(10, ImageKeys.BaseType); + this.objectExplorerImageList.Images.SetKeyName(11, ImageKeys.BaseTypeAbstract); + this.objectExplorerImageList.Images.SetKeyName(12, ImageKeys.TableAbstract); + this.objectExplorerImageList.Images.SetKeyName(13, ImageKeys.TableCrud); + this.ResumeLayout(false); + + } + + public void SetGroupingMode(EntityGroupingMode mode) + { + this.treeNodesBuilder.EntityGroupingMode = mode; + } } } diff --git a/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.resx b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.resx new file mode 100644 index 000000000..be952d99c --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/ObjectExplorer.resx @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAD8 + LwAAAk1TRnQBSQFMAgEBDgEAAZwBAgGcAQIBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABQAMAAQEBAAEgBgABQBIAgP+AAAT/Az4B/wPAAf8D9AH/A9YB/wMpTf8DAAH/AwAB/wE3AVoBuRH/ + gAAE/wO0Af8DBwH/AwcB/wMHAf8Dok3/AwAB/wMAAf8BNwFaAbkB/wMADf+AAAT/A/IB/wMgAf8D6AH/ + AyIB/wPoAf8BBAIAAf8BBAIAAf8BBAIAAf8BBAIAAf8BBAIAAf8BBAIAAf8BBAIAAf8BBAIAEf8BtwGi + AZMB/wFDASkBFQH/AUMBKQEVAf8BQwEpARUB/wFDASkBFQn/AwAB/wE3AVoBuQH/ATcBWgG5Af8BQwEp + ARUB/wMACf+AAAT/A/kB/wONAf8DRwH/A1EB/wP3Af8B3wHOAcMB/wHdAcgBuwH/AdsBvwGtAf8B2wG7 + AacB/wHbAbsBpwH/AdsBuwGnAf8BzwG0AaMB/wEEAgAR/wG3AaIBkwH/Af0B+wH5Af8B4QHcAdgB/wHg + AdcB0gH/Ad8BzgHDAf8B3QHIAbsJ/wMAAf8DXwH/AUMBKQEVAf8BQwEpARUB/wMABf+AAAT/A/0B/wPb + Af8DBwH/A8kB/wP7Af8B+wHsAeMB/wGkAY0BHwH/AZoBgwETAf8B9gHWAcIB/wGIARIBAAH/AYMBDAEA + Af8BzwG0AaMB/wEEAgAR/wG3AaIBkwH/A/4B/wG6AaYBmAH/AbUBoAGRAf8B+wHsAeMB/wGkAY0BXgH/ + AZoBgwFSCf8DAAH/A18B/wFDASkBFQH/AUMBKQEVAf8DAAH/gAAI/wG6AaUBlgH/A/4B/wP+Af8D/gH/ + Af0B+wH5Af8B/QH3AfMB/wH7AewB4wH/AfoB5wHbAf8B+AHhAdIB/wH3AdsByQH/AdABuQGrAf8BBAIA + Ef8BugGlAZYB/wP+Af8D/gH/A/4B/wH9AfsB+QH/Af0B9wHzAf8B+wHsAeMB/wH6AecB2wn/AwAB/wNf + Af8BQwEpARUB/wFDASkBFQH/gAAI/wG+AakBmgH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaMBjgEf + Af8BmgGDARMB/wH7AewB4wH/AYkBEgEAAf8BgwEMAQAB/wHRAcEBtgH/AQQCABH/Ab4BqQGaAf8D/gH/ + AboBpgGYAf8BtAGgAZEB/wP+Af8BowGOAV4B/wGaAYMBUgH/AfsB7AHjAf8BiQFRAT8J/wMAAf8DXwH/ + AUMBKQEVAf+AAAj/AcMBrgGeAf8D/gH/A/4B/wP+Af8D/gH/A/4B/wH9AfcB8wH/AfwB8gHsAf8B+wHs + AeMB/wH6AecB2wH/AdEBwQG2Af8BBAIAEf8BwwGuAZ4B/wP+Af8D/gH/A/4B/wP+Af8D/gH/Af0B9wHz + Af8B/AHyAewB/wH7AewB4wH/AfoB5wHbCf8DAAH/A18B/4AACP8ByAGyAaMB/wP+Af8BugGmAZgB/wG0 + AaABkQH/A/4B/wGkAY4BHwH/AZkBhAETAf8B/QH3AfMB/wGIARIBAAH/AYMBDAEAAf8B0QHBAbYB/wEE + AgAR/wHIAbIBowH/A/4B/wG6AaYBmAH/AbQBoAGRAf8D/gH/AaQBjgFeAf8BmQGEAVIB/wH9AfcB8wH/ + AYgBUQE+Af8BgwFLATgB/wHRAcEBtgn/AUMBKQEVAf+AAAj/AcwBtgGnAf8D/gH/A/4B/wP+Af8D/gH/ + A/4B/wP+Af8B/QH7AfkB/wH9AfcB8wH/AfwB8gHsAf8B+wHsAeMB/wEEAgAR/wHMAbYBpwH/A/4B/wP+ + Af8D/gH/A/4B/wP+Af8D/gH/Af0B+wH5Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8BQwEpARUJ/4AA + CP8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGlAYQB/wHnAZcBDwH/AeYBjgEDAf8B4wEeAQAB/wHj + ARcBAAH/AeIBEwEAAf8B4gETAQAB/wHiARMBAAH/AcgBAwEAEf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGL + Af8B6QGlAYQB/wHnAZcBTgH/AeYBjgFCAf8B4wFdASoB/wHjAVYBIAH/AeIBUgEZAf8B4gFSARkB/wHi + AVIBGQH/AcgBQgEPCf+AAAj/AeoBqgGLAv8BwgGiAf8B/gHAAZ8B/wH9Ab0BmgH/AfsBtQGQAf8B+gGw + AYsB/wH4AacBHgH/AfYBogEYAf8B9QGdARIB/wH1AZkBCwH/AfMBlQEGAf8BzQEGAQAR/wHqAaoBiwL/ + AcIBogH/Af4BwAGfAf8B/QG9AZoB/wH7AbUBkAH/AfoBsAGLAf8B+AGnAV0B/wH2AaIBVwH/AfUBnQFR + Af8B9QGZAUoB/wHzAZUBRQH/Ac0BRQERCf+AAAj/AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGL + Af8B6QGhASAB/wHoAZsBFwH/AeYBjgEDAf8B5QGHAQAB/wHkAYEBAAH/AeQBHAEAAf8B4wEXAQAB/wHi + ARMBABH/AeoBqgGLAf8B6gGqAYsB/wHqAaoBiwH/AeoBqgGLAf8B6QGhAV8B/wHoAZsBVgH/AeYBjgFC + Af8B5QGHATgB/wHkAYEBLgH/AeQBWwEmAf8B4wFWAR4B/wHiAVIBGQn/gACA/4AAgP//ACkAAdMB3wHr + Af8B6AH0Av8B6AH0Av8B0wHfAesB/wgAA/QB/wP0Af8D9QX/A/YB/wP0Af8D9A3/A/4B/wP2Af8D9QH/ + A/0J/xAAAe8B5gHcAf8BzgG1AZMB/wG4AZMBHwH/AbIBiAENAf8BuAGSAR4B/wHOAbQBkAH/Ae4B5gHb + Af94AAPfAf8B6AH0Av8BmAGkAbAB/wGYAaQBsAH/AegB9AL/A98B/wQAA/YB/wM9Af8DwAH/A/QB/wPW + Af8DKAH/A/UJ/wP+Af8D9gH/AU4BrgHbAf8BTgGuAdsB/wP1Af8D/QX/CAAB/QH7AfoB/wHIAawBhAH/ + AaEBLgEAAf8BnQEoAQAB/wGcASYBAAH/AaQBNAEAAf8BnQEnAQAB/wGdAScBAAH/AZ8BLQEAAf8BxwGq + AYEB/wH8AfsB+QH/HAADhgH/AwAB/w8AAf8DhgH/NAAD3wH/A/QB/wErAagB5gH/AQABSQG2Af8BAAFJ + Ab4B/wEjAagB7gH/AegB9AL/AdMB3wHrAf8D+gH/A7QB/wMGAf8DBgH/AwYB/wOiAf8D+gX/A/4B/wP2 + Af8BTgGuAdsB/wEAAUwBxwH/AQABTAHHAf8BTgGuAdsB/wP1Af8D/QH/BAAB/AH7AfkB/wG8AZYBJAH/ + AaABKwEAAf8BoQEsAQAB/wGeAScBAAH/AcoBqgE1Af8B9gHxAegB/wHNAa8BPwH/AZ4BJwEAAf8BoQEs + AQAB/wGhASsBAAH/AboBlAEgAf8B/AH6AfgB/xQAA4YB/wMAAf8XAAH/A4YB/zgAASsBqAHmAf8BAAFJ + AbYB/wEAAUkBvgH/AQABSQG+Af8BmAGkAbAB/wHoAfQC/wP+Af8D8gH/Ax8B/wPoAf8DIQH/A+gB/wP+ + Af8D9AH/A/QB/wP0Af8BlAG9AeAB/wEAAUwBxwH/AQABTAHHAf8BAAFMAccB/wFOAa4B2wH/A/UB/wQA + AcwBrwGIAf8BpQEwAQAB/wGlATABAAH/AaUBMQEAAf8BogErAQAB/wHmAdYBuwX/AesB3gHIAf8BowEt + AQAB/wGlATABAAH/AaUBMAEAAf8BpQEwAQAB/wHKAa0BhAH/FAADFQH/AwAB/xcAAf8DFQH/MAABBAFJ + Aa4B/wEEAUkBrgH/ARwBRQGdAf8BHAFFAZ0B/wEAAUkBtgH/AQABSQG2Af8BmAGkAbAB/wHoAfQG/wP5 + Af8DjQH/A0YB/wNQAf8D9wX/A/QB/wEAAUwBxwH/AQABTAHHAf8BAAFMAccB/wGUAb0B4AH/AQABTAHH + Af8BAAFMAccB/wGUAb0B4AH/A/YB/wHyAeoB4QH/AakBNwEAAf8BqgE1AQAB/wGqATUBAAH/AaoBNQEA + Af8BpwEwAQAB/wHlAdMBtgX/AeoB3AHDAf8BqAEyAQAB/wGqATQBAAH/AaoBNQEAAf8BqgE1AQAB/wGp + ATYBAAH/AfAB6QHeAf8QAAMVAf8DAAH/FwAB/wMVAf8cAAPfAf8D3wH/DAABBAFJAa4B/wG1AfoC/wHN + AfYC/wHNAfYC/wErAagB5gH/ASsBqAHmAf8B6AH0Av8B0wHfAesF/wP9Af8D2wH/AwYB/wPJAf8D+wX/ + A/QB/wEAAUwBxwH/A/QB/wP0Af8D9AH/AZQBvQHgAf8BlAG9AeAB/wP2Af8D/gH/AdYBvgGdAf8BsAE8 + AQAB/wGuATkBAAH/Aa8BOgEAAf8BrwE6AQAB/wGsATUBAAH/AeYB1QG2Bf8B6wHcAcQB/wGtATcBAAH/ + Aa8BOQEAAf8BrwE6AQAB/wGuAToBAAH/Aa8BOQEAAf8B0wG5AZYB/xMAAf8DwAH/FAADwAH/AwAB/xgA + AdMB3wHrAf8B6AH0Av8B6AH0Av8B0wHfAesB/wgAARwBRQGdAf8BzQH2Av8ByQH2Av8BSAGkAdEB/wFI + AaQB0QH/AckB9gL/A+UB/wQACP8D9gH/A/QB/wP0Af8D/QX/A/QB/wEAAUwBxwH/A/QB/wP2Af8BTgGu + AdsB/wFOAa4B2wH/A/QB/wP8Bf8BygGpATwB/wHAAY4BAAH/AbUBQQEAAf8BswE9AQAB/wG0AT8BAAH/ + AbIBOwEAAf8B6AHWAbgF/wHsAd4BxQH/AbIBPAEAAf8BtAE+AQAB/wG0AT8BAAH/AbQBPwEAAf8BtQE/ + AQAB/wHEAZ8BKQH/DwAB/wMuAf8cAAMuAf8DAAH/EAAD3wH/AegB9AL/AZgBpAGwAf8BmAGkAbAB/wHo + AfQC/wPfAf8EAAEcAUUBnQH/Ac0B9gL/AUgBpAHRAf8BGAFFAaEB/wEYAUUBoQH/AUgBpAHRAf8D9AH/ + A98F/wP+Af8D9gH/AU4BrgHbAf8BTgGuAdsB/wP1Af8D/QH/A/QB/wEAAUwBxwH/A/QB/wFOAa4B2wH/ + AQABTAHHAf8BAAFMAccB/wFOAa4B2wH/A/UB/wP9Af8ByQGmATMB/wHJAZsBCgH/AcUBlAEDAf8BvgGJ + AQAB/wG6AYABAAH/AbcBPwEAAf8B6wHZAbsF/wHvAeEByAH/AbcBQQEAAf8BuQFDAQAB/wG5AUMBAAH/ + AbkBQwEAAf8BugFDAQAB/wHDAZoBHQH/EwAB/wPAAf8UAAPAAf8DAAH/EAAB0wHfAesB/wHoAfQC/wEj + AagB7gH/AQABSQG+Af8BAAFJAb4B/wEjAagB7gH/Ac0B9gL/Ac0B9gL/AQQBSQGuAf8BtQH6Av8BIwGo + Ae4B/wEAAUkBvgH/AQABSQHHAf8BAAFJAccB/wGMAaQBvQH/AdwB9AL/A/4B/wP2Af8BTgGuAdsB/wEA + AUwBxwH/AQABTAHHAf8BTgGuAdsB/wP0Af8D9AH/AQABTAHHAf8D9AH/AZQBvQHgAf8BAAFMAccB/wEA + AUwBxwH/AQABTAHHAf8BTgGuAdsB/wP1Af8B0AGvAYEB/wHOAaABDwH/AcsBnAEOAf8BzAGcAQ4B/wHK + AZkBBgH/AcMBjQEAAf8B5QHUAbUF/wHnAdgBvAH/Ab4BgwEAAf8BwAGHAQAB/wHBAYgBAAH/AcIBigEA + Af8BxgGQAQAB/wHMAagBNgH/EAADFQH/AwAB/xcAAf8DFQH/EAAB6AH0Av8BmAGkAbAB/wEAAUkBvgH/ + AQABSQG+Af8BAAFJAb4B/wEAAUkBvgH/ARwBRQGdAf8BHAFFAZ0B/wEEAUkBrgH/AQQBSQGuAf8BAAFJ + Ab4B/wEAAUkBvgH/AQABSQHHAf8BAAFJAccB/wGMAaQBvQH/AdwB9AL/A/YB/wFOAa4B2wH/AQABTAHH + Af8BAAFMAccB/wEAAUwBxwH/AQABTAHHAf8BTgGuAdsB/wEAAUwBxwH/AQABTAHHAf8BAAFMAccB/wEA + AUwBxwH/AZQBvQHgAf8BAAFMAccB/wEAAUwBxwH/AZQBvQHgAf8D9gH/Ad0BxwGrAf8B0wGmARgB/wHQ + AaIBEQH/AdABoQESAf8B0AGhARIB/wHQAZ8BDQH/AcsBpAEiAf8B1AHDAaUB/wHKAaQBIgH/Ac0BmwEF + Af8BzgGcAQgB/wHOAZwBCAH/Ac4BnAEHAf8BzwGdAQcB/wHaAcMBogH/EAADFQH/AwAB/xcAAf8DFQH/ + EAAB6AH0Av8BmAGkAbAB/wEAAUkBvgH/AQABSQG+Af8BAAFJAccB/wEAAUkBxwH/AQABSQG+Af8BIwGo + Ae4B/wHqAfYC/wHqAfYC/wP2Af8D9gH/AYwBpAG9Af8BjAGkAb0B/wP0Af8D3wH/A/cB/wGUAb0B4AH/ + AQABTAHHAf8BAAFMAccB/wEAAUwBxwH/AQABTAHHAf8BAAFMAccB/wFOAa4B2wH/A/QB/wP0Af8D9AH/ + A/QB/wGUAb0B4AH/AZQBvQHgAf8D9gH/A/4B/wH1Ae8B5wH/AdEBqAEmAf8B2AGpARgB/wHVAaYBGAH/ + AdUBpgEWAf8B1AGjAREB/wHlAccBkQH/AfMB6gHYAf8B5wHLAZkB/wHTAaEBDQH/AdMBogEQAf8B0wGh + AQ4B/wHVAaMBDQH/Ac0BnQERAf8B9AHtAeQB/xAAA4YB/wMAAf8XAAH/A4YB/xAAAdMB3wHrAf8B6AH0 + Av8BIwGoAe4B/wEAAUkBvgH/AQABSQHHAf8BAAFJAccB/wEAAUkBvgH/AQABSQG+Af8BmAGkAbAB/wHo + AfQC/wPfAf8D3wH/AdwB9AL/AdwB9AL/A98B/wQAA/4B/wP3Af8BlAG9AeAB/wEAAUwBxwH/AQABTAHH + Af8BAAFMAccB/wEAAUwBxwH/AQABTAHHAf8BTgGuAdsB/wP1Af8D/QH/A/4B/wP3Af8D9gH/A/4F/wQA + Ad0ByAGqAf8B3QGyAScB/wHaAasBGwH/AdkBqwEcAf8B1wGnARUB/wHxAeYB0wX/AfUB7gHhAf8B1wGm + ARUB/wHXAacBFQH/AdgBpwETAf8B2QGqARgB/wHbAcEBngH/GAADhgH/AwAB/w8AAf8DhgH/GAAD3wH/ + AegB9AL/AZgBpAGwAf8BAAFJAb4B/wEAAUkBvgH/AQABSQG+Af8BAAFJAb4B/wGYAaQBsAH/AegB9AL/ + A98B/wQAA98B/wPfAf8IAAT/A/4B/wP3Af8BlAG9AeAB/wEAAUwBxwH/AQABTAHHAf8BAAFMAccB/wEA + AUwBxwH/AZQBvQHgAf8D9gH/A/4F/wP+Af8D/gn/BAAB/gL9Af8B2QG/AZoB/wHgAbYBLQH/Ad8BsQEg + Af8B3AGtARsB/wHXAbUBPgH/AeIB1QG+Af8B1wG3AYAB/wHbAaoBFwH/Ad4BrgEaAf8B3gGxASIB/wHW + AbgBjQH/Af4B/QH8Af9QAAHTAd8B6wH/AegB9AL/ASMBqAHuAf8BAAFJAb4B/wEAAUkBvgH/ASMBqAHu + Af8B6AH0Av8B0wHfAesB/xgACP8D/gH/A/cB/wGUAb0B4AH/AQABTAHHAf8BAAFMAccB/wGUAb0B4AH/ + A/YB/wP+Gf8MAAHfAcsBsQH/AdwBuAE+Af8B4wG4AS8B/wHjAbQBIwH/Ad0BrgEbAf8B4QGyAR8B/wHi + AbYBKQH/AdsBswE1Af8B3gHIAaoB/wL+Af0B/1gAA98B/wHoAfQC/wGYAaQBsAH/AZgBpAGwAf8B6AH0 + Av8D3wH/HAAM/wP+Af8D9wH/AZQBvQHgAf8BlAG9AeAB/wP2Af8D/h3/EAAB9gHxAesB/wHkAdQBvwH/ + Ad4BxQGjAf8B3gHEAZwB/wHeAcQBoQH/AeQB0wG8Af8B9QHvAekB/2QAAdMB3wHrAf8B6AH0Av8B6AH0 + Av8B0wHfAesB/yAAEP8D/gH/A/cB/wP2Af8D/iH/WQABCwG5Af8CAAEsAf8CAAEOAf/1AAEsAccB/wEA + Ac0B/AH/AQABDQGHAf+0AAM7AWUBAAECAQAB/wM6AWA1AAEsAccB/wEAAaAB0gH/AQABAwEjAf8cAAMB + AQIDAAEBGwABAQwAASIBIQEiATEDAAEBXAADPgFqAQABpwEAAf8BAAEGAQAB/wEAAQIBAAH/AzYBWDEA + ASwBxwH/AQAB0QH8Af8BAAENAYcB/zMAAQEDAAEBEAAB7AHSAewB/wEjAQABIgH/AeYBzAHmAf8DAgED + AxIBGRAAASABKgEsAf8BFgEeASEB/wENARIBFQH/AQMBBgEJAf8DAAH/AwAB/wMAAf8DAAH/AwAB/xwA + Az4BagEAAacBAAH/ARoBuwEOAf8BAAEKAQAB/wEAAQcBAAH/AQABAgEAAf8DNQFXLQABLAHHAf8BAAGh + AdEB/wEAAQMBIwH/PwABAQQAAe0B2AHtAf8BqQEBAagB/wGAAQABMAH/ASYBAAEmAf8B6wHRAesB/xQA + ASkBggGDAf8BlwHbAfUB/wEMAakBygH/AQwBqQHKAf8BCwGnAckB/wEDAZ8BwgH/AQABlgG5Af8BAAGN + AbAB/wMAAf8dAAGkAQAB/wEaAbsBDgH/ARoBuwEOAf8BAAEJAQAB/wEAAQoBAAH/AQABBwEAAf8BAAEC + AQAB/wMwAUwpAAEsAccB/wECAeIB/QH/AQABCQGAAf8jAAEBAwABAQMAAQEDAAEBAwABAQMAAQEDAAEB + BAAB6AHRAegB/wGqAQEBqQH/AcwBGAHLAf8BLwEAAS8B/wGWAQABlQH/ASwBAAErAf8B8AHVAfAB/xAA + ATECjAH/AaAB4AH3Af8BIgHNAfEB/wEVAccB7gH/AQkBwQHrAf8BAAG8AegB/wEAAbcB5gH/AQABkgG2 + Af8DAAH/HQABpwEAAf8BGgG7AQ4B/wEaAbsBDgH/AaoB1AGiAf8BAAGgAQAB/wEAAQoBAAH/AQABBwEA + Af8BAAEBAQAB/ykAASwBxwH/AQkB1wH8Af8BAAEJAYAB/yQAAasB8AH3Af8BqwHiAeUB/wGsAc4BzAH/ + Aa0BuwG1Af8BrgGnAZwB/wQAAeQBygHkAf8BqQEBAagB/wHTARwB0gH/AdQBHwHTAf8BMAEAAS8B/wGf + AQABnwH/AY4BAAGNAf8BLgEAAS0B/xAAAYUClAH/AacB4wH4Af8BLQHTAfQB/wEiAc4B8QH/ARYByAHu + Af8BCQHCAesB/wEAAbwB6AH/AQABmQG8Af8DAAH/GAADAgEDAQABqwEAAf8BGgG7AQ4B/wGqAdQBogH/ + AbcB2gGwAf8BqgHUAaIB/wEAAZMBAAH/AQABCgEAAf8BAAECAQAB/yUAAREBkAH/AQABLAHHAf8BHwHe + AfwB/wEAAQkBgAH/AgABKwH/OAABqgEDAakB/wHSARsB0QH/AdUBIAHVAf8BvQEhAbwB/wHeAZgB3QH/ + AY8BAAGOAf8BnQEAAZwB/wEvAQABLwH/EAABjAKbAf8BrgHmAfoB/wGGAdgB9gH/AS0B1AH0Af8BIgHN + AfEB/wEWAccB7gH/AQkBwgHrAf8BBAGgAcEB/wMAAf8YAAMEAQUBFAG4AQcB/wG0AdkBrQH/AcUB4gHA + Af8BtwHaAbAB/wG3AdoBsAH/AaoB1AGiAf8BAAGIAQAB/wEAAQIBAAH/IQABIAGgAf8BAAGHAccB/wEM + AcAB8AH/AQEBywH+Af8BAgGzAd0B/wIAARcB/wIAASsB/xgAAasB8AH3Af8BqwHlAekB/wGsAtUB/wGs + AcQBwQH/Aa0BtQGsAf8BrgGkAZgB/wQAAagBAAGnAf8B0gEeAdEB/wG8ASABuwH/Ae8BpQHuAf8B+wGf + AfoB/wHvAZ0B7gH/AZcBAwGWAf8BLQEAAS0B/xAAAZEBogGhAf8BsgHoAfwB/wGgAeIB+gH/AYYB2AH2 + Af8BLgHTAfMB/wEiAc4B8QH/ARUByAHuAf8BCAGlAccB/wIAAQMB/xgAAwIBAwNEAXoBjgHGAYQB/wG5 + AdwBswH/AcMB4QG+Af8BwwHhAb4B/wG3AdoBsAH/AaoB1AGiAf8BAAEYAQAB/x0AAYABsQH/AQABhwHI + Af8BAwG6AfcB/wEFAcIB+QH/AQABtwH5Af8BGQHWAfsB/wEAAaYB6AH/AgABFQH/AQABAgGDAf8wAAGn + AQEBpgH/AbwBIAG7Af8B7wGlAe4B/wH7AZsB+gH/AfsBmAH6Af8B+wGZAfoB/wHnAZgB5gH/AZEBAAGQ + Af8QAAGUAaYBpQH/Ab0B7AH8Af8BpQHlAfsB/wGfAeIB+gH/AYYB2AH2Af8BLgHUAfQB/wEiAc0B8QH/ + AQwBqQHKAf8BBQEJAQwB/yAAA0YBfgGQAccBhgH/Ab4B3gG4Af8BwwHhAb4B/wGzAdkBrAH/AZABxwGG + Af8DPQFpHQABLAG4Af8BBQHBAfkB/wEBAbcB+QH/AZMB7gH+Af8BjwHsAf4B/wEDAbQB8wH/AY0B4wH+ + Af8BAAG6AeIB/wIAARwB/xwAAasB8AH3Af8BrALVAf8BrgG0AawB/wGuAZkBigH/A/0B/wHPAYgBzwH/ + AeIBrwHiAf8B+wGrAfoB/wH7AZgB+gH/AfsBmAH6Af8B6gGQAekB/wHPAYgBzwH/AfQB5gH0Af8QAAGU + AaYBpQH/Ab0B7AH8Af8BvQHsAfwB/wGyAegB/AH/Aa4B5gH6Af8BpwHkAfkB/wGgAeAB9wH/AZcB2wH1 + Af8BDgETARcB/yQAA0cBgQGUAckBigH/Ab0B3gG3Af8BjgHGAYQB/wMwAUshAAGDAbsB/wEKAcYB+QH/ + ARoBigGsAf8BGgGKAawB/wEaAYoBrAH/ARoBigGsAf8BGgGKAawB/wETAdUB+gH/AgABGQH/MAAB8AHU + AfAB/wHPAYgBzwH/Ae4BvgHuAf8B+wGuAfoB/wHsAZEB6wH/Ac8BiAHPAf8B8wHgAfIB/xQAAZQBpgGl + Af8BlAGmAaUB/wGTAqUB/wGPAZ8BngH/AYgClwH/AYECjgH/ASoChAH/ASABKgEsAf8BFwEeASAB/ygA + AzwBZgGUAckBigH/AyUBNyUAAYMBvAH/AQ0B0gH6Af8BAAEVAYQB/w0AAZABwQH/AQQBuwHhAf8CAAEW + Af80AAHyAdsB8gH/Ac8BiAHPAf8B4wGsAeMB/wHPAYgBzwH/AfMB4wHzAf9gAAMBAQIEAAMBAQIpAAGI + AcEB/wEAAZ0B0AH/ASsB4wH6Af8BAAGFAZ4B/wECARUBhwH/AQIBJwGcAf8BAwG/AfQB/wEAAYwBqgH/ + AQABCQErAf84AAHyAdsB8gH/Ac8BiAHPAf8B8AHjAfAB/5kAAZQBxgH/AQABigHBAf8BAAGaAc0B/wEf + AdUB9QH/ASIB6QH+Af8BHgHUAfMB/wEAAZIBsgH/AQABFQGMAf8BAAEhAaIB/zwAAf4B+wH+Af+hAAGU + AcYB/wEAAY0BwwH/AQABiwG6Af8BAAGLAboB/wEAAYgBtwH/AQABJAGgAf8BAAGCAbIB//8AqQADNgFY + AZkCAAH/AzMBU/AAAzgBXQHXAZoBAAH/AZkCAAH/AZkCAAH/Ay8BSiwAAx4BKwNUAa4BWQJkAewBAAGD + AZYB/wEAARcBjQH/AQABDgGMAf8BTgJdAfADVgGzAyUBN5gAAzoBYQHXAZoBAAH/AdgBmwEAAf8BmQIA + Af8BmQIAAf8BmQIAAf8DLwFKKAABWwJeAdABAAGwAdEB/wGEAdUB6AH/AaEB6wH2Af8BFAHkAv8BAAG+ + AfMB/wEAAZ8B3gH/AQABiwG+Af8BWwJeAdlUAAG3AaIBkwH/AQQCAAH/AQQCAAH/AQQCAAH/AQQCAAH/ + AQQCAAH/AQQCAAH/AQQCAAH/AQQCAAH/AQQCAAH/AQQCAAH/AQQCAAH/FAAB2AGbAQAB/wHYAZsBAAH/ + AdgBmwEAAf8BmQIAAf8BmQIAAf8BmQIAAf8BmQIAAf8DLwFKJQABjwGqAf8BAAHXAv8BkAHqAfoB/wGh + AesB9gH/ARIB2QH0Af8BAAG8AfIB/wEAAacB6AH/AQABnAHaAf8BAAEEAYQB/xQAAzEBTQJSAVEBoQFf + AlgB4wFfAlgB4wFSAlEBoQExAjABTQQAAzEBTQJSAVEBoQFfAlgB4wFfAlgB4wFSAlEBoQExAjABTQwA + AbcBogGTAf8B/QH7AfkB/wHhAdwB2AH/AeAB1wHSAf8B3wHOAcMB/wHdAcgBuwH/AdsBvwGtAf8B2wG7 + AacB/wHbAbsBpwH/AdsBuwGnAf8BzwG0AaMB/wEEAgAB/xQAAdgBmwEAAf8B2AGbAQAB/wHpAbQBHQH/ + AfwB1gGvAf8BtQEEAQAB/wGZAgAB/wGZAgAB/wGZAgAB/wMvAUohAAGRAa4B/wEAAdIB+gH/AY0B5AH2 + Af8BoQHrAfYB/wERAdcB8wH/AQABuQHvAf8BAAGnAegB/wEAAZwB2gH/AQABBgGGAf8QAAM1AVUDZAHn + Ac8BuAGpAf8B6wHWAcgB/wHlAcsBuwH/AbMBlQEgAf8BZAJcAecDSwGOA2QB5wHPAbgBqQH/AesB1gHI + Af8B5QHLAbsB/wGzAZUBIAH/AWQCXAHnATUCNAFVCAABtwGiAZMB/wP+Af8BugGmAZgB/wG1AaABkQH/ + AfsB7AHjAf8BpAGNAR8B/wGaAYMBEwH/AfYB1gHCAf8BiAESAQAB/wGDAQwBAAH/Ac8BtAGjAf8BBAIA + Af8UAAHYAZsBAAH/AeoBtwGCAf8B+wHYAbIB/wH+AdEBowH/AfsB2AGyAf8BrwIAAf8BmQIAAf8BmQIA + Af8BmQIAAf8DKgFBHQABlQGwAf8BAAHSAfoB/wGNAeQB9AH/AaEB6wH2Af8BEQHXAfIB/wEAAbkB7gH/ + AQABpwHoAf8BAAGcAdoB/wEAAQkBiAH/EAADVQGyAeYB1gHLAf8DWQHCAmABXAHUA2AB1AFMASoBIQH7 + AwAB/wMAAf8DAAH/AWECWAHmAmABXAHUA2AB1ANZAcIBuQGcAYgB/wNVAbIIAAG6AaUBlgH/A/4B/wP+ + Af8D/gH/Af0B+wH5Af8B/QH3AfMB/wH7AewB4wH/AfoB5wHbAf8B+AHhAdIB/wH3AdsByQH/AdABuQGr + Af8BBAIAAf8UAAHnAbMBHQH/AfEBwwGRAf8B/gHPAZ0C/wHNAZkB/wH+AdABnwH/AfsB2AGyAf8BqQIA + Af8BmQIAAf8BmQIAAf8BmQIAAf8DBAEFGQABmQG1Af8BAAHRAfsB/wGOAeQB9QH/AaEB6wH2Af8BEQHX + AfIB/wEAAbkB7gH/AQABpwHoAf8BAAGcAdoB/wEAAQwBigH/EAADZQH0BP8DVwHfAx0BKgNcAc0F/wH+ + AfcC/wHxAeYB/wH6AeMB1AH/AfMB1wHHAf8DSgGNAx0BKgNcAd8B7wHWAccB/wFkAlIB9AgAAb4BqQGa + Af8D/gH/AboBpgGYAf8BtAGgAZEB/wP+Af8BowGOAR8B/wGaAYMBEwH/AfsB7AHjAf8BiQESAQAB/wGD + AQwBAAH/AdEBwQG2Af8BBAIAAf8UAANFAXwB5QGyARwB/wH0AcABiwL/Ac0BmQL/Ac0BmQH/Af4B0AGh + Af8B+wHYAbIB/wGpAgAB/wGZAgAB/wGZAgAB/x0AAZsBtwH/AQAB0AH5Af8BjQHjAfUB/wGhAesB9gH/ + ARMB2QHyAf8BAAG5Ae4B/wEAAacB6AH/AQABnAHaAf8BAAEOAY0B/xAAA1UBsgHyAeYB3gH/A1kBwgNc + AdQBYAJcAdQDYQHiAdMBtQGiAf8DTQH6AdoBwAGvAf8DXwHzA1sB1gFgAlwB1ANZAcIBywGxAaEB/wNV + AbIIAAHDAa4BngH/A/4B/wP+Af8D/gH/A/4B/wP+Af8B/QH3AfMB/wH8AfIB7AH/AfsB7AHjAf8B+gHn + AdsB/wHRAcEBtgH/AQQCAAH/GAADRgF/AeQBsAEaAf8B9gHEAZAC/wHNAZkC/wHNAZkB/wH+AdABoQH/ + AfsB2AGyAf8BqQIAAf8BmQIAAf8dAAGeAboB/wEAAdAB+QH/AY0B4wH0Af8BoQHrAfYB/wEQAdcB8gH/ + AQABtwHuAf8BAAGnAegB/wEAAZwB2gH/AQABEAGPAf8QAAM1AVUDZAHnAe0B4QHXA/8B/QL/AfcB8QH/ + AdgBxAG3Af8DZAHnA0sBjgNkAecB7QHhAdcD/wH9Av8B9wHxAf8B2AHEAbcB/wNkAecDNQFVCAAByAGy + AaMB/wP+Af8BugGmAZgB/wG0AaABkQH/A/4B/wGkAY4BHwH/AZkBhAETAf8B/QH3AfMB/wGIARIBAAH/ + AYMBDAEAAf8B0QHBAbYB/wEEAgAB/xwAA0kBhwHjAa8BGQH/AfYBxAGQAv8BzQGZAv8BzQGZAf8B/gHQ + AaEB/wHyAckBnQH/AbACAAH/HQABogG8Af8BAAHOAfcB/wGLAeMB9AH/AaEB6wH2Af8BDwHWAfIB/wEA + AbcB7gH/AQABpwHoAf8BAAGcAdoB/wEAAREBkgH/FAADMQFNA1IBoQNfAeMDXwHjA1IBoQMxAU0EAAMx + AU0DUgGhA18B4wNfAeMDUgGhAzEBTQwAAcwBtgGnAf8D/gH/A/4B/wP+Af8D/gH/A/4B/wP+Af8B/QH7 + AfkB/wH9AfcB8wH/AfwB8gHsAf8B+wHsAeMB/wEEAgAB/yAAA0kBhwHjAa8BGQH/AfYBxAGQAv8BzQGZ + Af8B8wHCAY4B/wHjAbABGgH/A0MBeBwAAQwBqQHAAf8BAAHUAfoB/wGcAewB+gH/AasB7wH6Af8BpgHt + AfgB/wGUAecB+AH/ARIB2QH2Af8BAAG9AekB/wEAAR0BlwH/VAAB6gGqAYsB/wHqAaoBiwH/AeoBqgGL + Af8B6QGlAYQB/wHnAZcBDwH/AeYBjgEDAf8B4wEeAQAB/wHjARcBAAH/AeIBEwEAAf8B4gETAQAB/wHi + ARMBAAH/AcgBAwEAAf8kAANJAYcB4wGvARkB/wHuAb0BigH/AeMBsAEaAf8DNAFUIAABgAGzAcUB/wGb + Ad4B6wH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BxQH5Af0B/wGgAd8B6gH/AQcBkQGi + Af9UAAHqAaoBiwL/AcIBogH/Af4BwAGfAf8B/QG9AZoB/wH7AbUBkAH/AfoBsAGLAf8B+AGnAR4B/wH2 + AaIBGAH/AfUBnQESAf8B9QGZAQsB/wHzAZUBBgH/Ac0BBgEAAf8oAANAAW4B5QGyAR4B/wMmATgkAAM7 + AWMDYAHWARcBqwG6Af8BEQGjAbMB/wENAZ0BrwH/AQwBmwGuAf8BEAGiAbQB/wNeAdkDQAFvVAAB6gGq + AYsB/wHqAaoBiwH/AeoBqgGLAf8B6gGqAYsB/wHpAaEBIAH/AegBmwEXAf8B5gGOAQMB/wHlAYcBAAH/ + AeQBgQEAAf8B5AEcAQAB/wHjARcBAAH/AeIBEwEAAf//AP8ACgABQgFNAT4HAAE+AwABKAMAAUADAAFA + AwABAQEAAQEGAAECFgAD/4EABf8BwwIAAfABHwP/AYECAAHAAQcB8wGfAf8DAAGAAQMB5wHPAf8BwAIA + AYABAwHnAc8B/wQAAQEB5wHPAecEAAEBAecBzwHDAQEDAAEBAc8B5wGBBAABAQHnAc8FAAEBAecBzwUA + AQEB5wHPBQABAQHnAc8BAAEBAgABgAEDAfMBnwGAARMCAAGAAQMC/wHAAT8CAAHgAQcC/wHgAX8CAAHw + AR8C/wHwAf8CAAL/AfwBfwb/AfwBfwT/AfwBfwH8AX8BPwFzAv8B+AE/AfwBfwH5AeAB8AEHAfABHwH8 + AX8B/wFBAfABBwHwAQ8B/AF/AoAB8AEHAfABDwH8AX8BwQEAAfABBwHgAQ8B+AE/Af8BAAHwAQcB4AEP + AfABHwGBAQAB8AEHAeABDwHgAQ8B/wEAAfABBwH4AQ8B4AEPAeABAAHwAQcB/AEfAeABDwH/AQEB8AEH + Af4BPwHjAY8B/wGDAv8B/QF/AeABDwH/AccE/wHgAQ8B/wHvBP8B8AEfDP8B+Af/AfABfwHwAQcE/wHg + AT8B8AEHAv8BwAEDAeABHwHwAQcBwAGBAcABAwHgAQ8B8AEHAYABAAHAAQMB4AEHAfABBwGAAQABwAED + AeABAwHwAQcBgAEAAcABAwHgAQcB8AEHAYABAAHAAQMB8AEHAfABBwGAAQABwAEDAfgBBwHwAQcBwAGB + AcABAwH8AQcB8AEHAv8BwAEDAf4BDwHwAQcC/wHAAQMB/wEfAfABBwL/AcABAxD/Cw== + + + + False + + \ No newline at end of file diff --git a/Src/SwqlStudio/ObjectExplorer/StringBuilderExtensions.cs b/Src/SwqlStudio/ObjectExplorer/StringBuilderExtensions.cs new file mode 100644 index 000000000..aa23abfe8 --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/StringBuilderExtensions.cs @@ -0,0 +1,49 @@ +using System; +using System.Text; +using SwqlStudio.Metadata; + +namespace SwqlStudio +{ + internal static class StringBuilderExtensions + { + public static void AppendName(this StringBuilder builder, string name) + { + builder.AppendFormat("Name: {0}\r\n", name); + } + + public static void AppendType(this StringBuilder builder, string metadataType) + { + builder.AppendFormat("Type: {0}\r\n", metadataType); + } + + public static void AppendSummaryParagraph(this StringBuilder builder,string summary) + { + builder.Append("\r\n\r\n"); + builder.AppendSummary(summary); + } + + public static void AppendSummary(this StringBuilder builder,string summary) + { + if (String.IsNullOrEmpty(summary)) + return; + + var trimmed = summary.Trim(); + builder.AppendFormat(trimmed); + } + + public static void AppendAccessControl(this StringBuilder builder, ConnectionInfo connection, Entity entity) + { + if (entity.IsIndication) + { + builder.Append($@"Can Subscribe: {connection.CanCreateSubscription}"); + } + else + { + builder.Append($"Can Read: {entity.CanRead}\r\n"); + builder.Append($"Can Create: {entity.CanCreate}\r\n"); + builder.Append($"Can Update: {entity.CanUpdate}\r\n"); + builder.Append($"Can Delete: {entity.CanDelete}\r\n"); + } + } + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs b/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs index 4c1610259..122752ef2 100644 --- a/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs +++ b/Src/SwqlStudio/ObjectExplorer/TreeNodeUtils.cs @@ -60,23 +60,28 @@ private static void CopyTree(TreeNodeCollection source, TreeNodeCollection targe 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; + CopyContent(node, treeNode); return treeNode; } + internal static void CopyContent(TreeNode source, TreeNode target) + { + target.Text = source.Text; + target.Name = source.Name; + target.ImageIndex = source.ImageIndex; + target.SelectedImageIndex = source.SelectedImageIndex; + target.StateImageIndex = source.StateImageIndex; + + target.SelectedImageKey = source.SelectedImageKey; + target.ImageKey = source.ImageKey; + target.Tag = source.Tag; + + target.ToolTipText = source.ToolTipText; + target.ContextMenu = source.ContextMenu; + target.ContextMenuStrip = source.ContextMenuStrip; + target.Checked = source.Checked; + } + /// /// Used in filtering of the nodes. /// diff --git a/Src/SwqlStudio/ObjectExplorer/TreeNodeWithConnectionInfo.cs b/Src/SwqlStudio/ObjectExplorer/TreeNodeWithConnectionInfo.cs index 6554102d3..1b03d001b 100644 --- a/Src/SwqlStudio/ObjectExplorer/TreeNodeWithConnectionInfo.cs +++ b/Src/SwqlStudio/ObjectExplorer/TreeNodeWithConnectionInfo.cs @@ -1,35 +1,26 @@ using System; using System.Windows.Forms; +using SwqlStudio.Metadata; namespace SwqlStudio { - public class TreeNodeWithConnectionInfo : TreeNode, ICloneable + internal class TreeNodeWithConnectionInfo : TreeNode { - public TreeNodeWithConnectionInfo(string text, ConnectionInfo connection) : base(text) + public IMetadataProvider Provider { get; } + + public ConnectionInfo Connection => this.Provider.ConnectionInfo; + + + public TreeNodeWithConnectionInfo(string text, IMetadataProvider provider) : base(text) { - Connection = connection; + Provider = provider; } 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; + var treeNode = new TreeNodeWithConnectionInfo(this.Text, this.Provider); + TreeNodeUtils.CopyContent(this, treeNode); return treeNode; } - - public ConnectionInfo Connection { get; private set; } } } diff --git a/Src/SwqlStudio/ObjectExplorer/TreeNodesBuilder.cs b/Src/SwqlStudio/ObjectExplorer/TreeNodesBuilder.cs new file mode 100644 index 000000000..02ddde71c --- /dev/null +++ b/Src/SwqlStudio/ObjectExplorer/TreeNodesBuilder.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using SwqlStudio.Metadata; + +namespace SwqlStudio +{ + internal class TreeNodesBuilder + { + public EntityGroupingMode EntityGroupingMode { get; set; } + + private static TreeNodeWithConnectionInfo MakeEntityTreeNode(IMetadataProvider provider, Entity entity) + { + var entityNode = CreateEntityNode(provider, entity); + + // Add keys + AddPropertiesToNode(provider, entityNode, entity.Properties.Where(c => c.IsKey)); + + // Add the simple Properties + AddPropertiesToNode(provider, entityNode, entity.Properties.Where(c => !c.IsInherited && !c.IsNavigable && !c.IsKey)); + + // Add the inherited Properties + AddPropertiesToNode(provider, entityNode, entity.Properties.Where(c => c.IsInherited && !c.IsNavigable && !c.IsKey)); + + // Add the Navigation Properties + AddPropertiesToNode(provider, entityNode, entity.Properties.Where(c => c.IsNavigable)); + + AddVerbsToNode(entityNode, entity, provider); + return entityNode; + } + + private static void AddVerbsToNode(TreeNode entityNode, Entity entity, IMetadataProvider provider) + { + foreach (var verb in entity.Verbs.OrderBy(v => v.Name)) + { + TreeNode verbNode = CreateNode(provider, verb.Name, ImageKeys.Verb, verb); + verbNode.ToolTipText = DocumentationBuilder.ToToolTip(verb); + + var argumentsPlaceholder = new ArgumentsPlaceholderTreeNode(verb, provider); + verbNode.Nodes.Add(argumentsPlaceholder); + + entityNode.Nodes.Add(verbNode); + } + } + + private static void AddPropertiesToNode(IMetadataProvider provider, TreeNode entityNode, IEnumerable properties) + { + foreach (Property property in properties.OrderBy(c => c.Name)) + { + string name = DocumentationBuilder.ToNodeText(property); + var imageKey = ImageKeys.GetImageKey(property); + TreeNode node = CreateNode(provider, name, imageKey, property); + node.ToolTipText = DocumentationBuilder.ToToolTip(property); + entityNode.Nodes.Add(node); + } + } + + public static void RebuildVerbArguments(TreeNode verbNode, IMetadataProvider provider) + { + verbNode.Nodes.Clear(); + var verb = verbNode.Tag as Verb; + + foreach (var argument in provider.GetVerbArguments(verb)) + { + var argNode = CreateVerbArgumentNode(provider, argument); + verbNode.Nodes.Add(argNode); + } + } + + private static TreeNodeWithConnectionInfo[] MakeEntityTreeNodes(IMetadataProvider provider, IEnumerable entities) + { + return entities.Select(e => MakeEntityTreeNode(provider, e)).ToArray(); + } + + public void RebuildDatabaseNode(TreeNode databaseNode, IMetadataProvider provider) + { + databaseNode.Nodes.Clear(); + + switch (this.EntityGroupingMode) + { + case EntityGroupingMode.Flat: + databaseNode.Nodes.AddRange(MakeEntityTreeNodes(provider, provider.Tables.OrderBy(e => e.FullName))); + break; + case EntityGroupingMode.ByNamespace: + foreach (var group in provider.Tables.GroupBy(e => e.Namespace).OrderBy(g => g.Key)) + { + TreeNode[] entityNodes = MakeEntityTreeNodes(provider, group.OrderBy(e => e.FullName)); + var namespaceNode = CreateNamespaceNode(provider, entityNodes, group.Key); + databaseNode.Nodes.Add(namespaceNode); + } + break; + case EntityGroupingMode.ByBaseType: + foreach (var group in provider.Tables.Where(e => e.BaseEntity != null).GroupBy( + e => e.BaseEntity, + (key, group) => new { Key = key, Entities = group }).OrderBy(item => item.Key.FullName)) + { + TreeNode[] childNodes = MakeEntityTreeNodes(provider, group.Entities.OrderBy(e => e.FullName)); + var entityNode = CreateEntityNode(provider, group.Key, childNodes); + databaseNode.Nodes.Add(entityNode); + } + break; + case EntityGroupingMode.ByHierarchy: + GroupByHierarchy(provider, databaseNode); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private static void GroupByHierarchy(IMetadataProvider provider, TreeNode baseNode) + { + Entity baseEntity = baseNode != null ? baseNode.Tag as Entity : null; + + var entities = provider.Tables.Where(e => baseEntity == null ? e.BaseEntity == null : e.BaseEntity == baseEntity); + + if (entities.Any()) + { + TreeNode[] childNodes = MakeEntityTreeNodes(provider, entities.OrderBy(e => e.FullName)); + + baseNode.Nodes.AddRange(childNodes); + + if (baseEntity != null) + { + baseNode.Text = DocumentationBuilder.ToBaseNodeText(baseNode, childNodes.Length); + } + + foreach (var node in childNodes) + { + GroupByHierarchy(provider, node); + } + + if (baseEntity == null) + { + foreach (var node in childNodes) + { + node.Expand(); + } + baseNode.Expand(); + } + } + } + + public static TreeNodeWithConnectionInfo CreateDatabaseNode(TreeView treeView, IMetadataProvider provider, + ConnectionInfo connection) + { + TreeNodeWithConnectionInfo node = CreateNode(provider, provider.Name, ImageKeys.Database, provider); + node.Name = node.Text; + treeView.Nodes.Add(node); + treeView.SelectedNode = node; + return node; + } + + public static TreeNodeWithConnectionInfo CreateNamespaceNode(IMetadataProvider provider, TreeNode[] entityNodes, string namespaceName) + { + var name = DocumentationBuilder.ToNodeText(namespaceName, entityNodes.Length); + var namespaceNode = CreateNode(provider, name, ImageKeys.Namespace, namespaceName); + namespaceNode.Nodes.AddRange(entityNodes); + return namespaceNode; + } + + private static TreeNodeWithConnectionInfo CreateEntityNode(IMetadataProvider provider, Entity entity, TreeNode[] childNodes) + { + var imageKey = !entity.IsAbstract ? ImageKeys.BaseType : ImageKeys.BaseTypeAbstract; + var name = DocumentationBuilder.ToNodeText(entity.FullName, childNodes.Length); + var entityNode = CreateNode(provider, name, imageKey, entity); + + entityNode.Nodes.AddRange(childNodes); + return entityNode; + } + + private static TreeNodeWithConnectionInfo CreateEntityNode(IMetadataProvider provider, Entity entity) + { + var imageKey = ImageKeys.GetImageKey(entity); + var node = CreateNode(provider, entity.FullName, imageKey, entity); + node.ToolTipText = DocumentationBuilder.ToToolTip(provider.ConnectionInfo, entity); + return node; + } + + private static TreeNodeWithConnectionInfo CreateVerbArgumentNode(IMetadataProvider provider, VerbArgument argument) + { + string text = DocumentationBuilder.ToNodeText(argument); + var argNode = CreateNode(provider, text, ImageKeys.Argument, argument); + argNode.ToolTipText = DocumentationBuilder.ToToolTip(argument); + return argNode; + } + + private static TreeNodeWithConnectionInfo CreateNode(IMetadataProvider provider, string name, string imageKey, object data) + { + var node = new TreeNodeWithConnectionInfo(name, provider); + node.ImageKey = imageKey; + node.SelectedImageKey = imageKey; + node.Tag = data; + return node; + } + } +} \ No newline at end of file diff --git a/Src/SwqlStudio/QueriesDockPanel.cs b/Src/SwqlStudio/QueriesDockPanel.cs index 023380080..342531d47 100644 --- a/Src/SwqlStudio/QueriesDockPanel.cs +++ b/Src/SwqlStudio/QueriesDockPanel.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using ScintillaNET; using SolarWinds.InformationService.Contract2; +using SwqlStudio.Metadata; using WeifenLuo.WinFormsUI.Docking; namespace SwqlStudio @@ -15,6 +16,7 @@ public partial class QueriesDockPanel : DockPanel private ObjectExplorer objectExplorer; private DockContent objectExplorerContent; private QueryParameters queryParametersContent; + private DocumentationContent documentationContent; public PropertyBag QueryParameters { @@ -55,6 +57,7 @@ public QueriesDockPanel() InitializeDockPanel(); InitializeObjectExplorer(); InitializeQueryParameters(); + InitializeDocumentation(); } public void CreateTabFromPrevious() @@ -83,11 +86,6 @@ private bool HasActiveContent() return this.lastActiveContent != null; } - internal void SetObjectExplorerImageList(ImageList imageList) - { - this.objectExplorer.ImageList = imageList; - } - private void InitializeDockPanel() { // Workaround for crash, when form is MDI @@ -103,7 +101,7 @@ private void InitializeObjectExplorer() { this.objectExplorer = new ObjectExplorer(); this.objectExplorer.Dock = DockStyle.Fill; - this.objectExplorer.EntityGroupingMode = EntityGroupingMode.Flat; + this.objectExplorer.SetGroupingMode(EntityGroupingMode.Flat); this.objectExplorer.Location = new System.Drawing.Point(0, 0); this.objectExplorer.Name = "objectExplorer"; this.objectExplorer.Size = new System.Drawing.Size(191, 571); @@ -123,6 +121,19 @@ private void InitializeQueryParameters() this.queryParametersContent.Show(this, DockState.DockRightAutoHide); } + private void InitializeDocumentation() + { + this.documentationContent = new DocumentationContent(); + ConfigureBuildInToolbox(this.documentationContent); + this.objectExplorer.SelectionChanged += ObjectExplorer_SelectionChanged; + this.documentationContent.Show(this.objectExplorerContent.Pane, DockAlignment.Bottom, 0.25); + } + + private void ObjectExplorer_SelectionChanged(object sender, TreeViewEventArgs e) + { + this.documentationContent.UpdateDocumentation(e.Node); + } + private void ConfigureBuildInToolbox(DockContent content) { content.CloseButton = false; @@ -141,6 +152,7 @@ private void FilesDock_ActiveContentChanged(object sender, EventArgs e) if (newContent != null && newContent != this.objectExplorerContent && newContent != this.queryParametersContent && + newContent != this.documentationContent && newContent != this.lastActiveContent) { this.ActiveQueryTab?.PutParameters(); @@ -168,7 +180,7 @@ internal void ShowParametersToolbox() internal void SetEntityGroupingMode(EntityGroupingMode mode) { - objectExplorer.EntityGroupingMode = mode; + objectExplorer.SetGroupingMode(mode); objectExplorer.RefreshAllServers(); } diff --git a/Src/SwqlStudio/QueryTab.cs b/Src/SwqlStudio/QueryTab.cs index 397f637f1..7fa26347d 100644 --- a/Src/SwqlStudio/QueryTab.cs +++ b/Src/SwqlStudio/QueryTab.cs @@ -11,6 +11,7 @@ using System.Xml; using System.Xml.Linq; using SolarWinds.InformationService.Contract2; +using SwqlStudio.Metadata; using SwqlStudio.Playback; using SwqlStudio.Properties; using SwqlStudio.Subscriptions; diff --git a/Src/SwqlStudio/SciTextEditorControl.cs b/Src/SwqlStudio/SciTextEditorControl.cs index 4eeefa97d..987fd3021 100644 --- a/Src/SwqlStudio/SciTextEditorControl.cs +++ b/Src/SwqlStudio/SciTextEditorControl.cs @@ -3,6 +3,7 @@ using System.Windows.Forms; using ScintillaNET; using System.Linq; +using SwqlStudio.Metadata; using SwqlStudio.Properties; namespace SwqlStudio diff --git a/Src/SwqlStudio/ServerList.cs b/Src/SwqlStudio/ServerList.cs index 34cc416cf..af907f0f7 100644 --- a/Src/SwqlStudio/ServerList.cs +++ b/Src/SwqlStudio/ServerList.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using SwqlStudio.Metadata; namespace SwqlStudio { diff --git a/Src/SwqlStudio/SwqlStudio.csproj b/Src/SwqlStudio/SwqlStudio.csproj index bffc57968..505d4ee82 100644 --- a/Src/SwqlStudio/SwqlStudio.csproj +++ b/Src/SwqlStudio/SwqlStudio.csproj @@ -181,6 +181,12 @@ + + Form + + + DocumentationContent.cs + Form @@ -205,13 +211,21 @@ + + + + + Component + + + @@ -249,11 +263,11 @@ NewConnection.cs - + Component - + @@ -324,6 +338,9 @@ CrudTab.cs Designer + + DocumentationContent.cs + EntityClassGraphForm.cs Designer @@ -334,6 +351,9 @@ MainForm.cs + + ObjectExplorer.cs + ResXFileCodeGenerator Designer