From 9d52c5938969f0c0e979c6ac96d408046e08af94 Mon Sep 17 00:00:00 2001 From: Jonas Rapp Date: Sun, 14 Oct 2018 00:14:09 +0200 Subject: [PATCH 1/7] Packages updated --- BulkDataUpdater/BulkDataUpdater.csproj | 39 ++++++++++++-------------- BulkDataUpdater/packages.config | 14 ++++----- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/BulkDataUpdater/BulkDataUpdater.csproj b/BulkDataUpdater/BulkDataUpdater.csproj index 103b624..f844a2f 100644 --- a/BulkDataUpdater/BulkDataUpdater.csproj +++ b/BulkDataUpdater/BulkDataUpdater.csproj @@ -33,8 +33,8 @@ 4 - - ..\packages\Cinteros.Xrm.CRMWinForm.2018.2.11.1\lib\net452\Cinteros.Xrm.CRMWinForm.dll + + ..\packages\Cinteros.Xrm.CRMWinForm.2018.9.6.1\lib\net452\Cinteros.Xrm.CRMWinForm.dll False @@ -43,14 +43,14 @@ ..\packages\ILMerge.2.14.1208\tools\ILMerge.exe - - ..\packages\MscrmTools.Xrm.Connection.1.2018.6.17\lib\net462\McTools.Xrm.Connection.dll + + ..\packages\MscrmTools.Xrm.Connection.1.2018.7.19\lib\net462\McTools.Xrm.Connection.dll - - ..\packages\MscrmTools.Xrm.Connection.1.2018.6.17\lib\net462\McTools.Xrm.Connection.WinForms.dll + + ..\packages\MscrmTools.Xrm.Connection.1.2018.7.19\lib\net462\McTools.Xrm.Connection.WinForms.dll - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.3\lib\net452\Microsoft.Crm.Sdk.Proxy.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.5\lib\net452\Microsoft.Crm.Sdk.Proxy.dll ..\packages\Microsoft.IdentityModel.6.1.7600.16394\lib\net35\Microsoft.IdentityModel.dll @@ -63,25 +63,22 @@ ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.29.0\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.2.3\lib\net452\Microsoft.Rest.ClientRuntime.dll + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.2.5\lib\net452\Microsoft.Rest.ClientRuntime.dll ..\packages\Microsoft.Web.Xdt.2.1.2\lib\net40\Microsoft.Web.XmlTransform.dll - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.3\lib\net452\Microsoft.Xrm.Sdk.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.5\lib\net452\Microsoft.Xrm.Sdk.dll - ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.3\lib\net452\Microsoft.Xrm.Sdk.Deployment.dll + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.5\lib\net452\Microsoft.Xrm.Sdk.Deployment.dll - ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.3\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.5\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.2.3\lib\net452\Microsoft.Xrm.Tooling.Connector.dll - - - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.2.3\lib\net452\Newtonsoft.Json.dll + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.2.5\lib\net452\Microsoft.Xrm.Tooling.Connector.dll ..\packages\NuGet.Core.2.14.0\lib\net40-Client\NuGet.Core.dll @@ -119,14 +116,14 @@ ..\packages\DockPanelSuite.ThemeVS2015.3.0.4\lib\net40\WeifenLuo.WinFormsUI.Docking.ThemeVS2015.dll - - ..\packages\XrmToolBoxPackage.1.2018.6.25\lib\net462\XrmToolBox.exe + + ..\packages\XrmToolBoxPackage.1.2018.7.28\lib\net462\XrmToolBox.exe - - ..\packages\XrmToolBoxPackage.1.2018.6.25\lib\net462\XrmToolBox.Extensibility.dll + + ..\packages\XrmToolBoxPackage.1.2018.7.28\lib\net462\XrmToolBox.Extensibility.dll - - ..\packages\XrmToolBoxPackage.1.2018.6.25\lib\net462\XrmToolBox.PluginsStore.dll + + ..\packages\XrmToolBoxPackage.1.2018.7.28\lib\net462\XrmToolBox.PluginsStore.dll diff --git a/BulkDataUpdater/packages.config b/BulkDataUpdater/packages.config index c67bc20..58ea8fe 100644 --- a/BulkDataUpdater/packages.config +++ b/BulkDataUpdater/packages.config @@ -1,18 +1,18 @@  - + - - - - + + + + - + - + \ No newline at end of file From 82ba45f14d8b8c580897b55015c4fffa74336724 Mon Sep 17 00:00:00 2001 From: Jonas Rapp Date: Sun, 14 Oct 2018 00:14:36 +0200 Subject: [PATCH 2/7] #21 Form redesign to prepare for Delete and SetState tabs --- BulkDataUpdater/MainControl.Designer.cs | 268 +++++++++++++++------ BulkDataUpdater/MainControl.cs | 41 +++- BulkDataUpdater/MainControl.resx | 266 +++++++++++++------- BulkDataUpdater/PluginDescription.cs | 2 +- BulkDataUpdater/Properties/AssemblyInfo.cs | 6 +- 5 files changed, 409 insertions(+), 174 deletions(-) diff --git a/BulkDataUpdater/MainControl.Designer.cs b/BulkDataUpdater/MainControl.Designer.cs index 87d0e08..6602e76 100644 --- a/BulkDataUpdater/MainControl.Designer.cs +++ b/BulkDataUpdater/MainControl.Designer.cs @@ -30,6 +30,7 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BulkDataUpdater)); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); this.imageList1 = new System.Windows.Forms.ImageList(this.components); this.toolStripMain = new System.Windows.Forms.ToolStrip(); this.tsbCloseThisTab = new System.Windows.Forms.ToolStripButton(); @@ -52,7 +53,7 @@ private void InitializeComponent() this.tsmiAttributesOnlyValidAF = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); this.tslAbout = new System.Windows.Forms.ToolStripLabel(); - this.btnGetRecords = new System.Windows.Forms.Button(); + this.btnGetEdit = new System.Windows.Forms.Button(); this.lblRecords = new System.Windows.Forms.Label(); this.cmbAttribute = new System.Windows.Forms.ComboBox(); this.rbSetNull = new System.Windows.Forms.RadioButton(); @@ -61,7 +62,9 @@ private void InitializeComponent() this.cmbValue = new System.Windows.Forms.ComboBox(); this.chkOnlyChange = new System.Windows.Forms.CheckBox(); this.gb1select = new System.Windows.Forms.GroupBox(); - this.cmbSource = new System.Windows.Forms.ComboBox(); + this.btnGetFile = new System.Windows.Forms.Button(); + this.btnGetView = new System.Windows.Forms.Button(); + this.btnGetFXB = new System.Windows.Forms.Button(); this.gb2attribute = new System.Windows.Forms.GroupBox(); this.pan2value = new System.Windows.Forms.Panel(); this.btnAdd = new System.Windows.Forms.Button(); @@ -72,6 +75,8 @@ private void InitializeComponent() this.groupBox5 = new System.Windows.Forms.GroupBox(); this.crmGridView1 = new Cinteros.Xrm.CRMWinForm.CRMGridView(); this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabUpdate = new System.Windows.Forms.TabPage(); this.gb3attributes = new System.Windows.Forms.GroupBox(); this.lvAttributes = new System.Windows.Forms.ListView(); this.logicalname = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -79,6 +84,10 @@ private void InitializeComponent() this.value = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.onlychange = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.btnRemove = new System.Windows.Forms.Button(); + this.tabSetState = new System.Windows.Forms.TabPage(); + this.label1 = new System.Windows.Forms.Label(); + this.tabDelete = new System.Windows.Forms.TabPage(); + this.lblDeleteHeader = new System.Windows.Forms.Label(); this.toolStripMain.SuspendLayout(); this.gb1select.SuspendLayout(); this.gb2attribute.SuspendLayout(); @@ -90,7 +99,11 @@ private void InitializeComponent() this.splitContainer1.Panel1.SuspendLayout(); this.splitContainer1.Panel2.SuspendLayout(); this.splitContainer1.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabUpdate.SuspendLayout(); this.gb3attributes.SuspendLayout(); + this.tabSetState.SuspendLayout(); + this.tabDelete.SuspendLayout(); this.SuspendLayout(); // // imageList1 @@ -109,7 +122,7 @@ private void InitializeComponent() this.tslAbout}); this.toolStripMain.Location = new System.Drawing.Point(0, 0); this.toolStripMain.Name = "toolStripMain"; - this.toolStripMain.Size = new System.Drawing.Size(729, 31); + this.toolStripMain.Size = new System.Drawing.Size(909, 31); this.toolStripMain.TabIndex = 23; this.toolStripMain.Text = "toolStrip1"; // @@ -145,14 +158,14 @@ private void InitializeComponent() // this.tsmiFriendly.CheckOnClick = true; this.tsmiFriendly.Name = "tsmiFriendly"; - this.tsmiFriendly.Size = new System.Drawing.Size(156, 22); + this.tsmiFriendly.Size = new System.Drawing.Size(180, 22); this.tsmiFriendly.Text = "Friendly names"; this.tsmiFriendly.Click += new System.EventHandler(this.tsmiFriendly_Click); // // toolStripSeparator12 // this.toolStripSeparator12.Name = "toolStripSeparator12"; - this.toolStripSeparator12.Size = new System.Drawing.Size(153, 6); + this.toolStripSeparator12.Size = new System.Drawing.Size(177, 6); // // tsmiShowAttributes // @@ -170,7 +183,7 @@ private void InitializeComponent() this.toolStripSeparator16, this.tsmiAttributesOnlyValidAF}); this.tsmiShowAttributes.Name = "tsmiShowAttributes"; - this.tsmiShowAttributes.Size = new System.Drawing.Size(156, 22); + this.tsmiShowAttributes.Size = new System.Drawing.Size(180, 22); this.tsmiShowAttributes.Text = "Show attributes"; // // tsmiAttributesAll @@ -281,7 +294,7 @@ private void InitializeComponent() // toolStripSeparator7 // this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(153, 6); + this.toolStripSeparator7.Size = new System.Drawing.Size(177, 6); // // tslAbout // @@ -293,22 +306,26 @@ private void InitializeComponent() this.tslAbout.Text = "by Jonas Rapp"; this.tslAbout.Click += new System.EventHandler(this.tslAbout_Click); // - // btnGetRecords - // - this.btnGetRecords.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnGetRecords.Enabled = false; - this.btnGetRecords.Location = new System.Drawing.Point(193, 18); - this.btnGetRecords.Name = "btnGetRecords"; - this.btnGetRecords.Size = new System.Drawing.Size(109, 23); - this.btnGetRecords.TabIndex = 24; - this.btnGetRecords.Text = "Get records"; - this.btnGetRecords.UseVisualStyleBackColor = true; - this.btnGetRecords.Click += new System.EventHandler(this.btnGetRecords_Click); + // btnGetEdit + // + this.btnGetEdit.Image = ((System.Drawing.Image)(resources.GetObject("btnGetEdit.Image"))); + this.btnGetEdit.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnGetEdit.Location = new System.Drawing.Point(150, 19); + this.btnGetEdit.Name = "btnGetEdit"; + this.btnGetEdit.Padding = new System.Windows.Forms.Padding(5, 0, 0, 0); + this.btnGetEdit.Size = new System.Drawing.Size(114, 39); + this.btnGetEdit.TabIndex = 20; + this.btnGetEdit.Tag = "Edit"; + this.btnGetEdit.Text = "Edit FetchXML"; + this.btnGetEdit.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnGetEdit.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnGetEdit.UseVisualStyleBackColor = true; + this.btnGetEdit.Click += new System.EventHandler(this.btnGetRecords_Click); // // lblRecords // this.lblRecords.AutoSize = true; - this.lblRecords.Location = new System.Drawing.Point(12, 43); + this.lblRecords.Location = new System.Drawing.Point(12, 69); this.lblRecords.Name = "lblRecords"; this.lblRecords.Size = new System.Drawing.Size(100, 13); this.lblRecords.TabIndex = 25; @@ -323,7 +340,7 @@ private void InitializeComponent() this.cmbAttribute.FormattingEnabled = true; this.cmbAttribute.Location = new System.Drawing.Point(15, 19); this.cmbAttribute.Name = "cmbAttribute"; - this.cmbAttribute.Size = new System.Drawing.Size(287, 21); + this.cmbAttribute.Size = new System.Drawing.Size(312, 21); this.cmbAttribute.Sorted = true; this.cmbAttribute.TabIndex = 26; this.cmbAttribute.Tag = "attribute"; @@ -372,7 +389,7 @@ private void InitializeComponent() this.cmbValue.FormattingEnabled = true; this.cmbValue.Location = new System.Drawing.Point(9, 26); this.cmbValue.Name = "cmbValue"; - this.cmbValue.Size = new System.Drawing.Size(287, 21); + this.cmbValue.Size = new System.Drawing.Size(312, 21); this.cmbValue.TabIndex = 32; this.cmbValue.Tag = "value"; this.cmbValue.SelectedIndexChanged += new System.EventHandler(this.cmbValue_SelectedIndexChanged); @@ -389,45 +406,78 @@ private void InitializeComponent() // // gb1select // - this.gb1select.Controls.Add(this.cmbSource); - this.gb1select.Controls.Add(this.btnGetRecords); + this.gb1select.Controls.Add(this.btnGetFile); + this.gb1select.Controls.Add(this.btnGetView); + this.gb1select.Controls.Add(this.btnGetFXB); + this.gb1select.Controls.Add(this.btnGetEdit); this.gb1select.Controls.Add(this.lblRecords); this.gb1select.Dock = System.Windows.Forms.DockStyle.Top; this.gb1select.Location = new System.Drawing.Point(0, 0); this.gb1select.Name = "gb1select"; - this.gb1select.Size = new System.Drawing.Size(319, 66); + this.gb1select.Size = new System.Drawing.Size(547, 91); this.gb1select.TabIndex = 34; this.gb1select.TabStop = false; this.gb1select.Text = "1. Select records to update"; // - // cmbSource - // - this.cmbSource.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.cmbSource.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.cmbSource.FormattingEnabled = true; - this.cmbSource.Items.AddRange(new object[] { - "Edit FetchXML", - "Use FetchXML Builder", - "Open File", - "Open View"}); - this.cmbSource.Location = new System.Drawing.Point(15, 19); - this.cmbSource.Name = "cmbSource"; - this.cmbSource.Size = new System.Drawing.Size(172, 21); - this.cmbSource.TabIndex = 26; - this.cmbSource.SelectedIndexChanged += new System.EventHandler(this.cmbSource_SelectedIndexChanged); + // btnGetFile + // + this.btnGetFile.Image = ((System.Drawing.Image)(resources.GetObject("btnGetFile.Image"))); + this.btnGetFile.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnGetFile.Location = new System.Drawing.Point(390, 19); + this.btnGetFile.Name = "btnGetFile"; + this.btnGetFile.Padding = new System.Windows.Forms.Padding(5, 0, 0, 0); + this.btnGetFile.Size = new System.Drawing.Size(114, 39); + this.btnGetFile.TabIndex = 40; + this.btnGetFile.Tag = "File"; + this.btnGetFile.Text = "Open File"; + this.btnGetFile.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnGetFile.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnGetFile.UseVisualStyleBackColor = true; + this.btnGetFile.Click += new System.EventHandler(this.btnGetRecords_Click); + // + // btnGetView + // + this.btnGetView.Image = ((System.Drawing.Image)(resources.GetObject("btnGetView.Image"))); + this.btnGetView.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnGetView.Location = new System.Drawing.Point(270, 19); + this.btnGetView.Name = "btnGetView"; + this.btnGetView.Padding = new System.Windows.Forms.Padding(5, 0, 0, 0); + this.btnGetView.Size = new System.Drawing.Size(114, 39); + this.btnGetView.TabIndex = 30; + this.btnGetView.Tag = "View"; + this.btnGetView.Text = "Open View"; + this.btnGetView.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnGetView.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnGetView.UseVisualStyleBackColor = true; + this.btnGetView.Click += new System.EventHandler(this.btnGetRecords_Click); + // + // btnGetFXB + // + this.btnGetFXB.Image = ((System.Drawing.Image)(resources.GetObject("btnGetFXB.Image"))); + this.btnGetFXB.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnGetFXB.Location = new System.Drawing.Point(15, 19); + this.btnGetFXB.Name = "btnGetFXB"; + this.btnGetFXB.Padding = new System.Windows.Forms.Padding(5, 0, 0, 0); + this.btnGetFXB.Size = new System.Drawing.Size(129, 39); + this.btnGetFXB.TabIndex = 10; + this.btnGetFXB.Tag = "FXB"; + this.btnGetFXB.Text = "FetchXML Builder"; + this.btnGetFXB.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnGetFXB.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnGetFXB.UseVisualStyleBackColor = true; + this.btnGetFXB.Click += new System.EventHandler(this.btnGetRecords_Click); // // gb2attribute // this.gb2attribute.Controls.Add(this.pan2value); this.gb2attribute.Controls.Add(this.cmbAttribute); this.gb2attribute.Dock = System.Windows.Forms.DockStyle.Top; - this.gb2attribute.Location = new System.Drawing.Point(0, 66); + this.gb2attribute.Location = new System.Drawing.Point(3, 3); this.gb2attribute.Name = "gb2attribute"; - this.gb2attribute.Size = new System.Drawing.Size(319, 149); + this.gb2attribute.Size = new System.Drawing.Size(344, 154); this.gb2attribute.TabIndex = 35; this.gb2attribute.TabStop = false; - this.gb2attribute.Text = "2. Select attribute to update"; + this.gb2attribute.Text = "Select attribute to update"; // // pan2value // @@ -441,13 +491,13 @@ private void InitializeComponent() this.pan2value.Controls.Add(this.rbSetValue); this.pan2value.Location = new System.Drawing.Point(6, 46); this.pan2value.Name = "pan2value"; - this.pan2value.Size = new System.Drawing.Size(307, 121); + this.pan2value.Size = new System.Drawing.Size(332, 105); this.pan2value.TabIndex = 3; // // btnAdd // this.btnAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnAdd.Location = new System.Drawing.Point(187, 75); + this.btnAdd.Location = new System.Drawing.Point(212, 75); this.btnAdd.Name = "btnAdd"; this.btnAdd.Size = new System.Drawing.Size(109, 23); this.btnAdd.TabIndex = 35; @@ -471,12 +521,12 @@ private void InitializeComponent() this.gb4update.Controls.Add(this.btnUpdate); this.gb4update.Controls.Add(this.chkIgnoreErrors); this.gb4update.Dock = System.Windows.Forms.DockStyle.Bottom; - this.gb4update.Location = new System.Drawing.Point(0, 401); + this.gb4update.Location = new System.Drawing.Point(3, 424); this.gb4update.Name = "gb4update"; - this.gb4update.Size = new System.Drawing.Size(319, 89); + this.gb4update.Size = new System.Drawing.Size(344, 89); this.gb4update.TabIndex = 37; this.gb4update.TabStop = false; - this.gb4update.Text = "4. Execute update"; + this.gb4update.Text = "Execute update"; // // lblUpdateStatus // @@ -490,7 +540,7 @@ private void InitializeComponent() // btnUpdate // this.btnUpdate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnUpdate.Location = new System.Drawing.Point(193, 29); + this.btnUpdate.Location = new System.Drawing.Point(218, 29); this.btnUpdate.Name = "btnUpdate"; this.btnUpdate.Size = new System.Drawing.Size(109, 23); this.btnUpdate.TabIndex = 0; @@ -502,9 +552,9 @@ private void InitializeComponent() // this.groupBox5.Controls.Add(this.crmGridView1); this.groupBox5.Dock = System.Windows.Forms.DockStyle.Fill; - this.groupBox5.Location = new System.Drawing.Point(0, 0); + this.groupBox5.Location = new System.Drawing.Point(0, 91); this.groupBox5.Name = "groupBox5"; - this.groupBox5.Size = new System.Drawing.Size(406, 490); + this.groupBox5.Size = new System.Drawing.Size(547, 451); this.groupBox5.TabIndex = 38; this.groupBox5.TabStop = false; this.groupBox5.Text = "Records"; @@ -515,52 +565,79 @@ private void InitializeComponent() this.crmGridView1.AllowUserToDeleteRows = false; this.crmGridView1.AllowUserToOrderColumns = true; this.crmGridView1.AllowUserToResizeRows = false; + dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); + this.crmGridView1.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle1; this.crmGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.crmGridView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.crmGridView1.FilterColumns = ""; this.crmGridView1.Location = new System.Drawing.Point(3, 16); this.crmGridView1.Name = "crmGridView1"; this.crmGridView1.ReadOnly = true; + this.crmGridView1.RowHeadersVisible = false; this.crmGridView1.ShowFriendlyNames = true; this.crmGridView1.ShowIdColumn = false; - this.crmGridView1.Size = new System.Drawing.Size(400, 471); + this.crmGridView1.Size = new System.Drawing.Size(541, 432); this.crmGridView1.TabIndex = 2; // // splitContainer1 // this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; - this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1; + this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; this.splitContainer1.Location = new System.Drawing.Point(0, 31); this.splitContainer1.Name = "splitContainer1"; // // splitContainer1.Panel1 // - this.splitContainer1.Panel1.Controls.Add(this.gb3attributes); - this.splitContainer1.Panel1.Controls.Add(this.gb2attribute); + this.splitContainer1.Panel1.Controls.Add(this.groupBox5); this.splitContainer1.Panel1.Controls.Add(this.gb1select); - this.splitContainer1.Panel1.Controls.Add(this.gb4update); this.splitContainer1.Panel1.RightToLeft = System.Windows.Forms.RightToLeft.No; this.splitContainer1.Panel1MinSize = 100; // // splitContainer1.Panel2 // - this.splitContainer1.Panel2.Controls.Add(this.groupBox5); + this.splitContainer1.Panel2.Controls.Add(this.tabControl1); this.splitContainer1.Panel2.RightToLeft = System.Windows.Forms.RightToLeft.No; this.splitContainer1.RightToLeft = System.Windows.Forms.RightToLeft.No; - this.splitContainer1.Size = new System.Drawing.Size(729, 490); - this.splitContainer1.SplitterDistance = 319; + this.splitContainer1.Size = new System.Drawing.Size(909, 542); + this.splitContainer1.SplitterDistance = 547; this.splitContainer1.TabIndex = 39; // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabUpdate); + this.tabControl1.Controls.Add(this.tabSetState); + this.tabControl1.Controls.Add(this.tabDelete); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 0); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(358, 542); + this.tabControl1.TabIndex = 39; + // + // tabUpdate + // + this.tabUpdate.Controls.Add(this.gb3attributes); + this.tabUpdate.Controls.Add(this.gb2attribute); + this.tabUpdate.Controls.Add(this.gb4update); + this.tabUpdate.Location = new System.Drawing.Point(4, 22); + this.tabUpdate.Name = "tabUpdate"; + this.tabUpdate.Padding = new System.Windows.Forms.Padding(3); + this.tabUpdate.Size = new System.Drawing.Size(350, 516); + this.tabUpdate.TabIndex = 1; + this.tabUpdate.Text = "Update"; + this.tabUpdate.UseVisualStyleBackColor = true; + // // gb3attributes // this.gb3attributes.Controls.Add(this.lvAttributes); this.gb3attributes.Controls.Add(this.btnRemove); this.gb3attributes.Dock = System.Windows.Forms.DockStyle.Fill; - this.gb3attributes.Location = new System.Drawing.Point(0, 215); + this.gb3attributes.Location = new System.Drawing.Point(3, 157); this.gb3attributes.Name = "gb3attributes"; - this.gb3attributes.Size = new System.Drawing.Size(319, 186); + this.gb3attributes.Size = new System.Drawing.Size(344, 267); this.gb3attributes.TabIndex = 38; this.gb3attributes.TabStop = false; - this.gb3attributes.Text = "3. Verify attributes to update"; + this.gb3attributes.Text = "Verify attributes to update"; // // lvAttributes // @@ -575,7 +652,7 @@ private void InitializeComponent() this.lvAttributes.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; this.lvAttributes.Location = new System.Drawing.Point(15, 19); this.lvAttributes.Name = "lvAttributes"; - this.lvAttributes.Size = new System.Drawing.Size(287, 132); + this.lvAttributes.Size = new System.Drawing.Size(312, 213); this.lvAttributes.TabIndex = 2; this.lvAttributes.UseCompatibleStateImageBehavior = false; this.lvAttributes.View = System.Windows.Forms.View.Details; @@ -604,7 +681,7 @@ private void InitializeComponent() // btnRemove // this.btnRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnRemove.Location = new System.Drawing.Point(193, 157); + this.btnRemove.Location = new System.Drawing.Point(218, 238); this.btnRemove.Name = "btnRemove"; this.btnRemove.Size = new System.Drawing.Size(109, 23); this.btnRemove.TabIndex = 1; @@ -612,15 +689,58 @@ private void InitializeComponent() this.btnRemove.UseVisualStyleBackColor = true; this.btnRemove.Click += new System.EventHandler(this.btnRemove_Click); // + // tabSetState + // + this.tabSetState.Controls.Add(this.label1); + this.tabSetState.Location = new System.Drawing.Point(4, 22); + this.tabSetState.Name = "tabSetState"; + this.tabSetState.Padding = new System.Windows.Forms.Padding(3); + this.tabSetState.Size = new System.Drawing.Size(350, 516); + this.tabSetState.TabIndex = 3; + this.tabSetState.Text = "Set State"; + this.tabSetState.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(77, 246); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(195, 24); + this.label1.TabIndex = 1; + this.label1.Text = "Soon to be released..."; + // + // tabDelete + // + this.tabDelete.Controls.Add(this.lblDeleteHeader); + this.tabDelete.Location = new System.Drawing.Point(4, 22); + this.tabDelete.Name = "tabDelete"; + this.tabDelete.Padding = new System.Windows.Forms.Padding(3); + this.tabDelete.Size = new System.Drawing.Size(350, 516); + this.tabDelete.TabIndex = 2; + this.tabDelete.Text = "Delete"; + this.tabDelete.UseVisualStyleBackColor = true; + // + // lblDeleteHeader + // + this.lblDeleteHeader.AutoSize = true; + this.lblDeleteHeader.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblDeleteHeader.Location = new System.Drawing.Point(16, 21); + this.lblDeleteHeader.Name = "lblDeleteHeader"; + this.lblDeleteHeader.Size = new System.Drawing.Size(196, 24); + this.lblDeleteHeader.TabIndex = 0; + this.lblDeleteHeader.Text = "Delete [nn] [collection]"; + // // BulkDataUpdater // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Window; this.Controls.Add(this.splitContainer1); this.Controls.Add(this.toolStripMain); this.Name = "BulkDataUpdater"; this.PluginIcon = ((System.Drawing.Icon)(resources.GetObject("$this.PluginIcon"))); - this.Size = new System.Drawing.Size(729, 521); + this.Size = new System.Drawing.Size(909, 573); this.TabIcon = ((System.Drawing.Image)(resources.GetObject("$this.TabIcon"))); this.ConnectionUpdated += new XrmToolBox.Extensibility.PluginControlBase.ConnectionUpdatedHandler(this.DataUpdater_ConnectionUpdated); this.Load += new System.EventHandler(this.DataUpdater_Load); @@ -639,7 +759,13 @@ private void InitializeComponent() this.splitContainer1.Panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); this.splitContainer1.ResumeLayout(false); + this.tabControl1.ResumeLayout(false); + this.tabUpdate.ResumeLayout(false); this.gb3attributes.ResumeLayout(false); + this.tabSetState.ResumeLayout(false); + this.tabSetState.PerformLayout(); + this.tabDelete.ResumeLayout(false); + this.tabDelete.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -668,7 +794,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripSeparator toolStripSeparator16; internal System.Windows.Forms.ToolStripMenuItem tsmiAttributesOnlyValidAF; private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; - private System.Windows.Forms.Button btnGetRecords; + private System.Windows.Forms.Button btnGetEdit; private System.Windows.Forms.Label lblRecords; private System.Windows.Forms.ComboBox cmbAttribute; private System.Windows.Forms.RadioButton rbSetNull; @@ -683,7 +809,6 @@ private void InitializeComponent() private System.Windows.Forms.Button btnUpdate; private System.Windows.Forms.GroupBox groupBox5; private System.Windows.Forms.SplitContainer splitContainer1; - private System.Windows.Forms.ComboBox cmbSource; private Xrm.CRMWinForm.CRMGridView crmGridView1; private System.Windows.Forms.CheckBox chkIgnoreErrors; private System.Windows.Forms.GroupBox gb3attributes; @@ -696,5 +821,14 @@ private void InitializeComponent() private System.Windows.Forms.ColumnHeader value; private System.Windows.Forms.ColumnHeader onlychange; private System.Windows.Forms.ToolStripLabel tslAbout; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabUpdate; + private System.Windows.Forms.TabPage tabDelete; + private System.Windows.Forms.Label lblDeleteHeader; + private System.Windows.Forms.TabPage tabSetState; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button btnGetFile; + private System.Windows.Forms.Button btnGetView; + private System.Windows.Forms.Button btnGetFXB; } } diff --git a/BulkDataUpdater/MainControl.cs b/BulkDataUpdater/MainControl.cs index 7a42c4d..9c39de4 100644 --- a/BulkDataUpdater/MainControl.cs +++ b/BulkDataUpdater/MainControl.cs @@ -168,7 +168,10 @@ private void tsmiAttributes_Click(object sender, EventArgs e) private void btnGetRecords_Click(object sender, EventArgs e) { - GetRecords(); + if (sender is Button btn) + { + GetRecords(btn.Tag?.ToString()); + } } private void cmbAttribute_SelectedIndexChanged(object sender, EventArgs e) @@ -258,11 +261,6 @@ private void lvAttributes_SelectedIndexChanged(object sender, EventArgs e) } } - private void cmbSource_SelectedIndexChanged(object sender, EventArgs e) - { - btnGetRecords.Enabled = cmbSource.SelectedIndex >= 0; - } - private void cmbValue_SelectedIndexChanged(object sender, EventArgs e) { EnableControls(true); @@ -406,14 +404,14 @@ private void OpenView() EnableControls(true); } - private void GetRecords() + private void GetRecords(string tag) { - switch (cmbSource.SelectedIndex) + switch (tag) { - case 0: // Edit + case "Edit": // Edit GetFromEditor(); break; - case 1: // FXB + case "FXB": // FXB try { GetFromFXB(); @@ -429,17 +427,17 @@ private void GetRecords() MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } break; - case 2: // File + case "File": // File FetchUpdated(OpenFile()); break; - case 3: // View + case "View": // View OpenView(); break; default: MessageBox.Show("Select record source.", "Get Records", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); break; } - LogUse(cmbSource.Text, records?.Entities?.Count); + LogUse(tag, records?.Entities?.Count); } private void GetFromEditor() @@ -475,9 +473,20 @@ private void RetrieveRecordsReady() { if (records != null) { + var entityName = records.EntityName; + if (NeedToLoadEntity(entityName)) + { + if (!working) + { + LoadEntityDetails(entityName, RetrieveRecordsReady); + } + return; + } lblRecords.Text = records.Entities.Count.ToString() + " records of entity " + records.EntityName; + lblDeleteHeader.Text = $"Delete {records.Entities.Count} {entities.FirstOrDefault(e => e.Key == records.EntityName).Value.DisplayCollectionName.UserLocalizedLabel.Label}"; crmGridView1.OrganizationService = Service; crmGridView1.DataSource = records; + crmGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); } RefreshAttributes(); } @@ -522,6 +531,7 @@ private void RefreshAttributes() } } crmGridView1.ShowFriendlyNames = useFriendlyNames; + crmGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); EnableControls(true); } @@ -564,6 +574,10 @@ private AttributeMetadata[] GetDisplayAttributes(string entityName) { continue; } + if (attribute.LogicalName=="statecode" || attribute.LogicalName == "statuscode") + { + continue; + } if (!showAttributesAll) { if (!string.IsNullOrEmpty(attribute.AttributeOf)) { continue; } @@ -1288,5 +1302,6 @@ private bool UpdateRecord(Entity record, List attributes) } #endregion Async SDK methods + } } diff --git a/BulkDataUpdater/MainControl.resx b/BulkDataUpdater/MainControl.resx index 8cecf90..fcd399c 100644 --- a/BulkDataUpdater/MainControl.resx +++ b/BulkDataUpdater/MainControl.resx @@ -125,7 +125,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAC0 - KAAAAk1TRnQBSQFMAwEBAAHoAQIB6AECAVABAAFQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAEB + KAAAAk1TRnQBSQFMAwEBAAH4AQIB+AECAVABAAFQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAEB AgABUAMAAQEBAAEgBgABkAEB/wD/AP8A/wD/ALYAA0YBgAM5AWD/AP8A/wD/APgAA0sBjwMAAf8DWAHv AzkBYP8A/wD/AP8A8AADRgGAAwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AOgAA0ABcAMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AOAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA @@ -308,91 +308,177 @@ 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 + Y5nvPusUIv8DXoHPiI5TPQAAAAAASUVORK5CYII= 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 - VzAtrb8BS+3/5E9BLNwAAAAASUVORK5CYII= + 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 + VJz/r7pVhjgAAAAASUVORK5CYII= - iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAACvAAAArwAUKsNJgAAAAHdElNRQfiBgwULDBWCQqfAAAE70lEQVRIS31Ve1DUVRT+ - pW7qTEz4zgkfWVb2YLIsdEbMTPCBkZiaxoQTEo9CwAcgIDsKQkoQiCkoIQjGS1ZMMZBgXJa3KIqwBNvg - IrK6Ls+VImXFr3uv7WV/rOMf3+6993z3fOd37rnnCoD8mVDeqUF8cQvc025j7REtw9bUDsRcVOHqrVo8 - fizH0/YZ8dRFuimv7gYWRvZgXmgTduZE41T1Vyj58xNcal6KrMsbESSLwPywOljv1SOtUolHQ08XMlvQ - 3S+H4+F7xHkVipuWkQgFeMe7Yo7zEYa5Xx/G6qBgXG5+lTgUUN1qA7ufivBxVDfauqrMRESTVl0V3tyj - R3h+CIloFHNA4RzpAzt/KTo6J0DZZoU1wUGYuSmR22kQRy95YnZgH66114pE+KCrv5w5T61w4RuNcIv2 - xIZ9O/k8KssREz9PZePBR2P4/4Ubq5mI6ZewH4r1CVpIz+5l5AO/B0LiYcB4rwGoO2exFFmsScci7whY - u0Vj1KencThvFeO+uK0PYz0fYPPxDDZPkHvA9mA3PxPmvEh5nR2Y4dFoRoov3sYEKFp1rzCBj747gLPl - HyJXYQMnaQBmbU7Ag8ExsPC+z3guySfZXpquFbGFOFnRNCywPKYLv137jBEokhRuXEDTO90sReUNb0BY - JkNz+3RM8OlhPPe0Y9x+Wb0Ab0v1rISF9u5KzAq4BcPQk+gp6DkYBe72TYNzhC9LTUrhUhzPXw5b33BY - fXkMg4bRmLJdx3i+WbF8P8WC8FoidAVCepUSbqlJIiOtc6NAz9+WCE9fDwdSObR6VgaGYGPYDty4OYNx - p+3QMl7Imf0iH6F5YYgq+AvCbpma5dzUKLvqxAW0vZNYeozwiHVHRslicl5Pyngm+XrKCz+/R+Tj9JUv - sOWEBgK99jRiU2N+vQMX0OktWb5dfvBG4nk7BCdvxqS1KeyLhoaGBaIK/UU+FCpbrD6kg/BNiuaZAjTP - VCBHvojbaXokdtnII1U1N1jFeLF/+Ip8lLbYwoEKBJ9RmxlNBehcYp+Fc5UfiDj0oL3ivsXrIS2MF1/i - LbLToGnwQkZNI8lVisg4UmDcykwzgeW7pNj6oxcXiC3yE9l3yyIRU6SCcKevAlb+GnLVJdw4UkBYlovc - 0oXc3q1/ARYOp5Bwzp4LHCgI4HYK673XWV8iM7lAc5Vdu4EbTauof2AcO4PIX53QqLaCon4elviFsc7a - PzCWC+wnDdK4X6FajPfD+sj4/5usUNXhrVAlufrPM8LFRnsucOXmu6xqpq9PwtR1JzDZ6QQcQwKhvjsF - Dw0SWPr0Mp7xHIceP4clB0uRU9s4LEBBa3Z7dgwjqbSvcQGnIzJo9VPZuim6+ifCNzOO885ec2TrUYW7 - SC/q5C8dF9D/W4b5+/pwqNiHNSx61Y2bJR6D7MbSmqeY7NdpYjOwNP3zcDwyazaRstWT9lLBnIsEKDS9 - FXiPiOzMjsbNztlwTUnGSzvuipyZYoZ/OzzSEnG752VEXghizlu01dw5hUiAQj9Qhi3JGrwjbWDXnbZw - 2o/ukK5qBG2ANGKa74KGFbCJqGbP7D39cORGiCamkDfXYVWcDjMCbsM19Rf8XPI9cq+uw5m6teRR8YRX - +lHMCWrFEvIWn6+v5zkfCbOFkejorQTtuIG5bSRlHex27sppQ3JZE0mj+SMvhlz4D3iwKuKIr0j5AAAA - AElFTkSuQmCC + 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 @@ -425,19 +511,19 @@ - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAACvAAAArwAUKsNJgAAAAHdElNRQfiBgoVHjcBtP6mAAACbElEQVQ4T2VTXUiTYRT+ - jDQqrLwpu+yugi4iqKgoKKKLCJZWStSsm5z9EdmPF5EV1dLEi2gus63S0cJVoJk2+3F/NaciqVuObJmC - GUHNac79uD2974Hvtc9dPPCd8z7nec97zvNJgE2BiYgDRtdnHH34HQUGDwqM7ThiHES13Y+xsBOz+YrA - 7PEit+otXvbsxlRsHiOzNEM0ng6rdycO3HuFGkc/kkmbEBLF15sGUNZyHolkmiicjWRSgr5NgwuWgBBh - JzbJ0tUHbXMJfv/NwpZbTtb6o5TikmdabK94B+/IauhthbjPOiGBcMyOvTo7Eok0hMKZSC+MY01pb4rA - njuNdNY1uI46yatuQnDSCcnc4UV95z4iRWIZRFp7rTtFIEf3nM54Bzx+49vBnuOHpKkbpptlYoYmivU3 - PCKWkVtlIYHArxUUx6bnsg19g6Q2eBXEzBPj2Kx1KXIc+dVmEhgJLhc5tcEN6dADn4K45FQQW8v5hGdy - HAdrTCTwM7RU5NSGdkhFpmE2jMUiuehkiKYtxzIOGx6TwI9gNsXcG9xgtMInnnxB5AIbb7pFLEN+wujY - Mopb+nbRKqVI3A6V7gOmE3PoYOWlfswvCqPNv43WxXO+kVXIPjuKBccn6Wae36+3YnyKrZGbofFTLy43 - XCWytvki3cTBu8k6/UfE5yzlxKlsPYPaj3x2/1m5svULShuuUCfuwAbcfl3MLFtG4BZ3DWwim1dYixnv - KxUrBDgaWCequy487chTeGMishAvulXIqXrP5sXXPlMjPmREmLXrO73Q1A2xf6KXmaUHx2qHYHL7MBl1 - KIoBm/QP6UzdApLSv4MAAAAASUVORK5CYII= + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAK + 8AAACvABQqw0mAAAAAd0SU1FB+IGChUeNwG0/qYAAAJsSURBVDhPZVNdSJNhFP6MNCqsvCm77K6CLiKo + qCgooosIllZK1KybnP0R2Y8XkRXV0sSLaC6zrdLRwlWgmTb7cX81pyKpW45smYIZQc1pzv24Pb3vge+1 + z1088J3zPud5z3vO80mATYGJiANG12ccffgdBQYPCoztOGIcRLXdj7GwE7P5isDs8SK36i1e9uzGVGwe + I7M0QzSeDqt3Jw7ce4UaRz+SSZsQEsXXmwZQ1nIeiWSaKJyNZFKCvk2DC5aAEGEnNsnS1Qdtcwl+/83C + lltO1vqjlOKSZ1psr3gH78hq6G2FuM86IYFwzI69OjsSiTSEwplIL4xjTWlvisCeO4101jW4jjrJq25C + cNIJydzhRX3nPiJFYhlEWnutO0UgR/eczngHPH7j28Ge44ekqRumm2VihiaK9Tc8IpaRW2UhgcCvFRTH + pueyDX2DpDZ4FcTME+PYrHUpchz51WYSGAkuFzm1wQ3p0AOfgrjkVBBby/mEZ3IcB2tMJPAztFTk1IZ2 + SEWmYTaMxSK56GSIpi3HMg4bHpPAj2A2xdwb3GC0wieefEHkAhtvukUsQ37C6Ngyilv6dtEqpUjcDpXu + A6YTc+hg5aV+zC8Ko82/jdbFc76RVcg+O4oFxyfpZp7fr7difIqtkZuh8VMvLjdcJbK2+SLdxMG7yTr9 + R8TnLOXEqWw9g9qPfHb/Wbmy9QtKG65QJ+7ABtx+XcwsW0bgFncNbCKbV1iLGe8rFSsEOBpYJ6q7Ljzt + yFN4YyKyEC+6Vcipes/mxdc+UyM+ZESYtes7vdDUDbF/opeZpQfHaodgcvswGXUoigGb9A/pTN0CktK/ + gwAAAABJRU5ErkJggg== \ No newline at end of file diff --git a/BulkDataUpdater/PluginDescription.cs b/BulkDataUpdater/PluginDescription.cs index 0231509..191a88a 100644 --- a/BulkDataUpdater/PluginDescription.cs +++ b/BulkDataUpdater/PluginDescription.cs @@ -6,7 +6,7 @@ [Export(typeof(IXrmToolBoxPlugin)), ExportMetadata("Name", "Bulk Data Updater"), - ExportMetadata("Description", "Update or touch attributes on a set of records"), + ExportMetadata("Description", "Update or touch attributes on a set of records, or bulk delete records"), ExportMetadata("SmallImageBase64", "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfiBgwUIyQeSiFdAAAAB3RJTUUH4gYMFCwT9G577QAAAAlwSFlzAAAK8AAACvABQqw0mAAAAv1QTFRF/v7A4OzHr87Sjrraf7Hei7jbqsvU2OfI5O7GgLHdKn3yBWf6DGvzLX/SQIq/QYy9MYLOEG3vIHf0c6rg7vTDbqfiCmr5JHragbJ+y98z+/wE/v4A/P0B1OUqjLlyMIHOBmf6XJzm4+7GvNbPHXb1InjcpchZ7PMS3eoh5O4a9fgJttNIEm/3psjUmcDYB2j6ZaGa8/cLu9VEU5asFXHqHHXjWJqmwdk9+vsEfrCBBmf5eq7fmsHXkbxukr1shrV5rMxSeK3fCGn6kLtu9/oHEm/tZaGZeK2Gea2FdKqKYZ+dN4XIrs5QBmj4n8XWHnb1Y6CcxNs6jbpxu9ZDCWr2hLR6Dmz43OnIcanhIXjeo8db6u8OF1OcIluVG1aaOm2Fpr07VpiobKaS/P0COIbGUJTp5e/Flb5pTZKx7fELAEKsEE6hbJJjcZZgYotpGFScgaFUgbJ9X56fyt7MgrPdk71rWJmn9/kFOGyGKmGQAUOry9giYJ7lLX/xm8JkPG6DussuZo1nn8Rf+PrBx903CkmlRHR9+vwCBUWoMmeKaKOW6PEVxNvNs9DR+fsFDUujbqeRkbzZJ3vYA0SqQHGB3uYWT3x3SZC1OofEVJeq+foCXYdtpbw8grN8XJujgLLdO4jD8PQJJF2UxdQmsMQ1THp4PnCCXZyhX57lKXzVl8Bn6O4PDUyjaZBk8vUIb6jhsM/SCmr0j7tvQoy82eIZzOAyibd1dZlc4OgU7fQRv9jPJ3vyeJtbVoFyfp9XS3p5pshY9vnC/f4A1uEaWJnn3uvHr85PdqyIMoLNiqhPWINx0d0eY6CbLoDRz+EvwdnOZaHk+PoGbKWTK37Tk69JmLNFlbBHN2uHRY65RI3s5/DFFnH2c6qLYJ6fIHff0uPKyt80q8xTw9o7s8czrMI3Q3R/sM9Ov9hAhbXcJV2Te66EeZxanbZBzdohNGiJ+/3AqcrUOWyF4u3Gzd4rosZcRo7r1OXKaaTjH3bgQ427R4+3EG74mcHXaaPjdKvgmMrzHwAAAAF0Uk5TAEDm2GYAAALFSURBVHjabZN3PJVRGMdfo/koDVEeM9FS0hBXixKlobhCVErkSCmjjHZWGi5JaUqlKyqhPV1Jk7ZSSUtbe+vTOa97L+L54/38zu/5vp/nOec8h+Nqoyrwj1V19V9R8QqusSj/XgY/fnqG/NKA3/qrG6Q/FYBXxmeJRJLri3FfSuHrt/r5D8ZFjoj+hMVHCWJejrpS3XyQ4LU5Ir4hb5PeBZD3VGJwdkmVPP/SyYh5GEDS6PdVIr+otCmR5RX13PBxRcUTvEiepqQ+i3mOeUYvCrEyW1rlftkDxIcAN/EW30OkBB0AHiH6qJfzQIn4OuKNGiDr9p2sxLv5FEigVUrvsfx560KqLwAU0RKsh0vk8hWAq1RdExRTwFKcT7UdgL20ySgiiWcrGskFFDghZFII4IUnyamA02dILFJAlblnnc9xCpDH5GFmHYn088uMjDrKgFnMPSY4zh3M1mTyEEBOdBqN3Gi6sgXw5A9DrMSJxLzKoP/s43eZmbWfdZTO28kHuO07eLWYAqlkZ1r4rt1kjxYFHHg7fS+nvFEGbEohC5ncTLZsBVjF29siOFGCDAjBxPVMJpENdE/xNSVcuDVOa+VAZBTvrguVAxoizhtW/gdEx8QKpSXigI7WIgs5ELaEyaVkmVDa5HJjOp5BhuwggimwgG/SNzQsnAJmDGgdQY/aW92NSh+6TV/iN9t/zlwSgPMA5lNzAgSy63RxNUV0A3Cd7O7hMcV96jRET4DpiDO8ZvLzoDbegcEAE1Eajk4AOvQCnSfVjJSB9XAcYUMJ3ZG2dnajRttTKdDGMWPHyYZykMlgHAL1YigOU7GqHfveJn1M+/brL8sOMBtobiGwrPswDLoYGmli124suvdA7Klr3Kv+01LroK7RsRM/GlraOrp6+p0bvM7mLVqCSqvWqm3aQrv2zRp935yCopKycpOm9bL/AP/t+dUgJ+R0AAAAAElFTkSuQmCC"), // null for "no logo" image or base64 image content ExportMetadata("BigImageBase64", "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"), // null for "no logo" image or base64 image content ExportMetadata("BackgroundColor", "#FFFFC0"), diff --git a/BulkDataUpdater/Properties/AssemblyInfo.cs b/BulkDataUpdater/Properties/AssemblyInfo.cs index f0e2696..76b52e4 100644 --- a/BulkDataUpdater/Properties/AssemblyInfo.cs +++ b/BulkDataUpdater/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ [assembly: AssemblyDescription("XrmToolBox plugin to update or touch attributes on a set of records.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jonas Rapp, Sweden")] -[assembly: AssemblyProduct("Cinteros.XTB.BulkDataUpdater")] +[assembly: AssemblyProduct("BulkDataUpdater")] [assembly: AssemblyCopyright("Copyright © Jonas Rapp 2016-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.2018.6.1003")] -[assembly: AssemblyFileVersion("1.2018.6.1003")] +[assembly: AssemblyVersion("1.2018.10.1004")] +[assembly: AssemblyFileVersion("1.2018.10.1004")] From b70692fd476042208d39a9d2cdc86ff5a8a0bc79 Mon Sep 17 00:00:00 2001 From: Jonas Rapp Date: Mon, 15 Oct 2018 22:39:32 +0200 Subject: [PATCH 3/7] #21 First working bulk delete --- BulkDataUpdater/MainControl.Designer.cs | 124 ++++++- BulkDataUpdater/MainControl.cs | 99 +++++- BulkDataUpdater/MainControl.resx | 430 +++++++++++++----------- BulkDataUpdater/Settings.cs | 1 + 4 files changed, 441 insertions(+), 213 deletions(-) diff --git a/BulkDataUpdater/MainControl.Designer.cs b/BulkDataUpdater/MainControl.Designer.cs index 6602e76..7757848 100644 --- a/BulkDataUpdater/MainControl.Designer.cs +++ b/BulkDataUpdater/MainControl.Designer.cs @@ -30,7 +30,7 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BulkDataUpdater)); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); this.imageList1 = new System.Windows.Forms.ImageList(this.components); this.toolStripMain = new System.Windows.Forms.ToolStrip(); this.tsbCloseThisTab = new System.Windows.Forms.ToolStripButton(); @@ -87,7 +87,14 @@ private void InitializeComponent() this.tabSetState = new System.Windows.Forms.TabPage(); this.label1 = new System.Windows.Forms.Label(); this.tabDelete = new System.Windows.Forms.TabPage(); + this.label3 = new System.Windows.Forms.Label(); + this.chkDelIgnoreErrors = new System.Windows.Forms.CheckBox(); + this.btnDelete = new System.Windows.Forms.Button(); + this.cmbDelBatchSize = new System.Windows.Forms.ComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); this.lblDeleteHeader = new System.Windows.Forms.Label(); + this.lblDelStatus = new System.Windows.Forms.Label(); this.toolStripMain.SuspendLayout(); this.gb1select.SuspendLayout(); this.gb2attribute.SuspendLayout(); @@ -158,14 +165,14 @@ private void InitializeComponent() // this.tsmiFriendly.CheckOnClick = true; this.tsmiFriendly.Name = "tsmiFriendly"; - this.tsmiFriendly.Size = new System.Drawing.Size(180, 22); + this.tsmiFriendly.Size = new System.Drawing.Size(156, 22); this.tsmiFriendly.Text = "Friendly names"; this.tsmiFriendly.Click += new System.EventHandler(this.tsmiFriendly_Click); // // toolStripSeparator12 // this.toolStripSeparator12.Name = "toolStripSeparator12"; - this.toolStripSeparator12.Size = new System.Drawing.Size(177, 6); + this.toolStripSeparator12.Size = new System.Drawing.Size(153, 6); // // tsmiShowAttributes // @@ -183,7 +190,7 @@ private void InitializeComponent() this.toolStripSeparator16, this.tsmiAttributesOnlyValidAF}); this.tsmiShowAttributes.Name = "tsmiShowAttributes"; - this.tsmiShowAttributes.Size = new System.Drawing.Size(180, 22); + this.tsmiShowAttributes.Size = new System.Drawing.Size(156, 22); this.tsmiShowAttributes.Text = "Show attributes"; // // tsmiAttributesAll @@ -294,7 +301,7 @@ private void InitializeComponent() // toolStripSeparator7 // this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(177, 6); + this.toolStripSeparator7.Size = new System.Drawing.Size(153, 6); // // tslAbout // @@ -565,8 +572,8 @@ private void InitializeComponent() this.crmGridView1.AllowUserToDeleteRows = false; this.crmGridView1.AllowUserToOrderColumns = true; this.crmGridView1.AllowUserToResizeRows = false; - dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); - this.crmGridView1.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle1; + dataGridViewCellStyle2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); + this.crmGridView1.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle2; this.crmGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.crmGridView1.Dock = System.Windows.Forms.DockStyle.Fill; this.crmGridView1.FilterColumns = ""; @@ -712,6 +719,13 @@ private void InitializeComponent() // // tabDelete // + this.tabDelete.Controls.Add(this.lblDelStatus); + this.tabDelete.Controls.Add(this.label3); + this.tabDelete.Controls.Add(this.chkDelIgnoreErrors); + this.tabDelete.Controls.Add(this.btnDelete); + this.tabDelete.Controls.Add(this.cmbDelBatchSize); + this.tabDelete.Controls.Add(this.label2); + this.tabDelete.Controls.Add(this.textBox1); this.tabDelete.Controls.Add(this.lblDeleteHeader); this.tabDelete.Location = new System.Drawing.Point(4, 22); this.tabDelete.Name = "tabDelete"; @@ -720,6 +734,86 @@ private void InitializeComponent() this.tabDelete.TabIndex = 2; this.tabDelete.Text = "Delete"; this.tabDelete.UseVisualStyleBackColor = true; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(19, 281); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(66, 13); + this.label3.TabIndex = 36; + this.label3.Text = "Ignore errors"; + // + // chkDelIgnoreErrors + // + this.chkDelIgnoreErrors.AutoSize = true; + this.chkDelIgnoreErrors.Location = new System.Drawing.Point(120, 280); + this.chkDelIgnoreErrors.Name = "chkDelIgnoreErrors"; + this.chkDelIgnoreErrors.Size = new System.Drawing.Size(15, 14); + this.chkDelIgnoreErrors.TabIndex = 35; + this.chkDelIgnoreErrors.UseVisualStyleBackColor = true; + // + // btnDelete + // + this.btnDelete.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.btnDelete.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnDelete.ForeColor = System.Drawing.Color.Red; + this.btnDelete.Image = ((System.Drawing.Image)(resources.GetObject("btnDelete.Image"))); + this.btnDelete.Location = new System.Drawing.Point(50, 412); + this.btnDelete.Name = "btnDelete"; + this.btnDelete.Size = new System.Drawing.Size(252, 50); + this.btnDelete.TabIndex = 4; + this.btnDelete.Text = "Delete"; + this.btnDelete.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.btnDelete.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnDelete.UseVisualStyleBackColor = true; + this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click); + // + // cmbDelBatchSize + // + this.cmbDelBatchSize.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.cmbDelBatchSize.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cmbDelBatchSize.FormattingEnabled = true; + this.cmbDelBatchSize.Items.AddRange(new object[] { + "1", + "5", + "10", + "50", + "100", + "200", + "500", + "1000"}); + this.cmbDelBatchSize.Location = new System.Drawing.Point(120, 253); + this.cmbDelBatchSize.Name = "cmbDelBatchSize"; + this.cmbDelBatchSize.Size = new System.Drawing.Size(205, 21); + this.cmbDelBatchSize.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(19, 256); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(56, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Batch size"; + // + // textBox1 + // + this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textBox1.ForeColor = System.Drawing.Color.Red; + this.textBox1.Location = new System.Drawing.Point(35, 69); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(277, 178); + this.textBox1.TabIndex = 1; + this.textBox1.Text = "This action will delete all records in the list to the left.\r\n\r\nThis action can N" + + "OT be undone.\r\n\r\nWhen the Delete button is clicked, there is one confirmation qu" + + "estion, and then point of no return."; // // lblDeleteHeader // @@ -731,6 +825,15 @@ private void InitializeComponent() this.lblDeleteHeader.TabIndex = 0; this.lblDeleteHeader.Text = "Delete [nn] [collection]"; // + // lblDelStatus + // + this.lblDelStatus.AutoSize = true; + this.lblDelStatus.Location = new System.Drawing.Point(19, 480); + this.lblDelStatus.Name = "lblDelStatus"; + this.lblDelStatus.Size = new System.Drawing.Size(82, 13); + this.lblDelStatus.TabIndex = 37; + this.lblDelStatus.Text = "Nothing deleted"; + // // BulkDataUpdater // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -830,5 +933,12 @@ private void InitializeComponent() private System.Windows.Forms.Button btnGetFile; private System.Windows.Forms.Button btnGetView; private System.Windows.Forms.Button btnGetFXB; + private System.Windows.Forms.ComboBox cmbDelBatchSize; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button btnDelete; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.CheckBox chkDelIgnoreErrors; + private System.Windows.Forms.Label lblDelStatus; } } diff --git a/BulkDataUpdater/MainControl.cs b/BulkDataUpdater/MainControl.cs index 9c39de4..ae5d6b8 100644 --- a/BulkDataUpdater/MainControl.cs +++ b/BulkDataUpdater/MainControl.cs @@ -288,7 +288,8 @@ private void SaveSetting() AttributesUncustomizable = tsmiAttributesUncustomizable.Checked, AttributesCustom = tsmiAttributesCustom.Checked, AttributesStandard = tsmiAttributesStandard.Checked, - AttributesOnlyValidAF = tsmiAttributesOnlyValidAF.Checked + AttributesOnlyValidAF = tsmiAttributesOnlyValidAF.Checked, + DeleteBatchSize = int.TryParse(cmbDelBatchSize.Text, out int size) ? size : 1 }; SettingsManager.Instance.Save(typeof(BulkDataUpdater), settings, "Settings"); } @@ -318,6 +319,7 @@ private void LoadSetting() tsmiAttributesCustom.Checked = settings.AttributesCustom; tsmiAttributesStandard.Checked = settings.AttributesStandard; tsmiAttributesOnlyValidAF.Checked = settings.AttributesOnlyValidAF; + cmbDelBatchSize.SelectedItem = cmbDelBatchSize.Items.Cast().FirstOrDefault(i => i == settings.DeleteBatchSize.ToString()); tsmiFriendly_Click(null, null); tsmiAttributes_Click(null, null); } @@ -574,7 +576,7 @@ private AttributeMetadata[] GetDisplayAttributes(string entityName) { continue; } - if (attribute.LogicalName=="statecode" || attribute.LogicalName == "statuscode") + if (attribute.LogicalName == "statecode" || attribute.LogicalName == "statuscode") { continue; } @@ -1121,10 +1123,10 @@ private void UpdateRecords() bgworker.ReportProgress(pct, "Updating record " + current.ToString()); try { - if (UpdateState(record, attributes)) - { - updated++; - } + //if (UpdateState(record, attributes)) + //{ + // updated++; + //} if (UpdateRecord(record, attributes)) { updated++; @@ -1303,5 +1305,90 @@ private bool UpdateRecord(Entity record, List attributes) #endregion Async SDK methods + private void btnDelete_Click(object sender, EventArgs e) + { + DeleteRecords(); + } + + private void DeleteRecords() + { + if (working) + { + return; + } + if (MessageBox.Show("All selected records will unconditionally be deleted.\nUI defined rules will NOT be enforced.\nPlugins and workflows WILL trigger.\n\nConfirm delete!", + "Confirm", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk) != DialogResult.OK) + { + return; + } + working = true; + if (!int.TryParse(cmbDelBatchSize.Text, out int batchsize)) + { + batchsize = 1; + } + WorkAsync(new WorkAsyncInfo() + { + Message = "Deleting records", + IsCancelable = true, + Work = (bgworker, workargs) => + { + var sw = Stopwatch.StartNew(); + var total = records.Entities.Count; + var current = 0; + var deleted = 0; + var failed = 0; + foreach (var record in records.Entities) + { + current++; + var pct = 100 * current / total; + bgworker.ReportProgress(pct, "Deleting record " + current.ToString()); + try + { + if (batchsize == 1) + { + Service.Delete(record.LogicalName, record.Id); + deleted++; + } + else + { + MessageBox.Show("Not implemented yet, try batch size = 1"); + return; + } + } + catch (Exception ex) + { + failed++; + if (!chkIgnoreErrors.Checked) + { + throw ex; + } + } + } + sw.Stop(); + workargs.Result = new Tuple(deleted, failed, sw.ElapsedMilliseconds); + }, + PostWorkCallBack = (completedargs) => + { + working = false; + if (completedargs.Error != null) + { + MessageBox.Show(completedargs.Error.Message, "Delete", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + else if (completedargs.Result is Tuple result) + { + lblDelStatus.Text = $"{result.Item1} records deleted, {result.Item2} records failed."; + LogUse("Deleted", result.Item1, result.Item3); + if (result.Item2 > 0) + { + LogUse("Failed", result.Item2); + } + } + }, + ProgressChanged = (changeargs) => + { + SetWorkingMessage(changeargs.UserState.ToString()); + } + }); + } } } diff --git a/BulkDataUpdater/MainControl.resx b/BulkDataUpdater/MainControl.resx index fcd399c..ed590f2 100644 --- a/BulkDataUpdater/MainControl.resx +++ b/BulkDataUpdater/MainControl.resx @@ -124,181 +124,181 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAC0 - KAAAAk1TRnQBSQFMAwEBAAH4AQIB+AECAVABAAFQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAEB - AgABUAMAAQEBAAEgBgABkAEB/wD/AP8A/wD/ALYAA0YBgAM5AWD/AP8A/wD/APgAA0sBjwMAAf8DWAHv - AzkBYP8A/wD/AP8A8AADRgGAAwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AOgAA0ABcAMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AOAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AzkBYP8A/wD/AP8A2AADSwGPAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - A1gB7wM5AWD/AP8A/wD/ANAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMqAUD/AP8A/wD/AMgAA0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AyoBQP8A/wD/AP8AwAADRgGAAwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A/wD/ALgA - A0sBjwMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/A1gB7wM5AWD/AP8A/wD/ALAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AyoBQP8A - /wD/AP8AqAADQAFwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AKAAA0YBgAMA + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACy + KAAAAk1TRnQBSQFMAwECAAEDAQABAwFQAQABUAEABP8BIQEACP8BQgFNATYHAAE2AwABKAMAAUABAQIA + AVADAAEBAQABIAYAAZABAf8A/wD/AP8A/wC2AANGAYADOQFg/wD/AP8A/wD4AANLAY8DAAH/A1gB7wM5 + AWD/AP8A/wD/APAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wDoAANAAXADAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wDgAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wM5AWD/AP8A/wD/ANgAA0sBjwMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNY + Ae8DOQFg/wD/AP8A/wDQAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DKgFA/wD/AP8A/wDIAANAAXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AMAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DOQFg/wD/AP8A/wC4AANL + AY8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wNYAe8DOQFg/wD/AP8A/wCwAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A + /wD/AKgAA0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wCgAANGAYADAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DOQFg/wD/AP8A/wCYAANLAY8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A/wD/AJgAA0sBjwMAAf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1gB7wM5AWD/AP8A/wD/AJAAA0YBgAMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHvAzkBYP8A/wD/AP8AkAADRgGAAwAB/wMA + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wCIAANA + AXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AIgA - A0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + Af8DKgFA/wD/AP8A/wCAAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMqAUD/AP8A/wD/AIAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A/wD/AHgAA0sBjwMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AzkBYP8A/wD/AP8AeAADSwGPAwAB/wMAAf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNY + Ae8DOQFg/wD/AP8A/wBwAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wBoAANA + AXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AGAAA0YEgAH/A4AB/wOA + Af8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOA + Af8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOA + Af8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/AzkBYP8A/wD/AP8AWAADSwGPAwCh/wNYAe8DOQFg + /wD/AP8A/wBQAANGAYADAAH/AwCh/wMAAf8DAAH/AyoBQP8A/wD/AP8ASAADQAFwAwAB/wMAAf8DAKH/ + AwAB/wMAAf8DAAH/AyoBQP8A/wD/AP8AQAADRgGAAwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMA + Af8DOQFg/wD/AP8A/wA4AANLAY8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DWAHv + AzkBYP8A/wD/AP8AMAADRgGAAwAB/wMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AyoBQP8A/wD/AP8AKAADQAFwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wAgAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AzkBYP8A/wD/AP8AGAADSwGP + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DWAHvAzkBYP8A/wD/AP8AEAADRgGAAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A + /wAIAANAAXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wO/Af8DvwH/ + A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/ + A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wADRgGAAwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - A1gB7wM5AWD/AP8A/wD/AHAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AGgA - A0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AyoBQP8A/wD/AP8AYAADRgSAAf8DgAH/ - A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/ - A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/ - A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DOQFg/wD/AP8A/wBYAANLAY8DAKH/A1gB7wM5 - AWD/AP8A/wD/AFAAA0YBgAMAAf8DAKH/AwAB/wMAAf8DKgFA/wD/AP8A/wBIAANAAXADAAH/AwAB/wMA - of8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wBAAANGAYADAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/ - AwAB/wM5AWD/AP8A/wD/ADgAA0sBjwMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wNY - Ae8DOQFg/wD/AP8A/wAwAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DKgFA/wD/AP8A/wAoAANAAXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/ACAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DOQFg/wD/AP8A/wAYAANL - AY8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wNYAe8DOQFg/wD/AP8A/wAQAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A - /wD/AAgAA0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/A78B/wO/ - Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/ - Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AANGAYADAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A/wD3AANLAY8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DWAHvAzkBYP8A/wD/AO8AA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wDnAANAAXADAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wDfAANGAYADAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AzkBYP8A - /wD/ANcAA0sBjwMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/A1gB7wM5AWD/AP8A/wDPAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMq - AUD/AP8A/wDHAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHP/wD/AP8AywADKgFAA1cB3wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wNYAcADFwEg/wD/AP8AzwADIQEwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHPAxcBIP8A/wD/AN4AAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DOQFg/wD/AP8A9wADSwGPAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf//AP8A - /wDjAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/A1gB7wM5AWD/AP8A/wDvAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - A1kBz/8A/wD/AOsAAyoBQANXAd8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A5wADQAFwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - A1gBwAMXASD/AP8A/wDvAAMhATADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHP - AxcBIP8A/wD/AP4AAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH//wD/AP8A/wAEAAMhATADVwHf - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A3wADRgGAAwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/AAwAAyoBQANXAd8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A - /wD/AP8AEAADIQEwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHPAxcBIP8A/wD/AP8AHwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8AJAADIQEwA1cB3wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/ACwA - AyoBQANXAd8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1gBwAMXASD/AP8A - /wD/ADAAAyEBMAMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wNZAc8DFwEg/wD/AP8A - /wA/AAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8ARAADIQEwA1cB3wMAAf8DAKH/ - AwAB/wMAAf8DWQHP/wD/AP8A/wBMAAMqAUADVwHfAwCh/wMAAf8DWAHAAxcBIP8A/wD/AP8AUAADIQEw - AwCh/wNZAc8DFwEg/wD/AP8A/wBfAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A + /wDXAANLAY8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - /wD/AP8A/wBkAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBz/8A/wD/AP8AbAADKgFA - A1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wNYAe8DOQFg/wD/AP8AzwADRgGAAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA + /wD/AP8AxwADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBz/8A/wD/AMsAAyoBQANXAd8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8AcAADIQEwAwAB/wMAAf8DAAH/AwAB/wMA + AwAB/wMAAf8DWAHAAxcBIP8A/wD/AM8AAyEBMAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBzwMXASD/AP8A/wDeAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH//wD/AP8A + 4wADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZ + Ac//AP8A/wDrAAMqAUADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNY + AcADFwEg/wD/AP8A7wADIQEwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBzwMX - ASD/AP8A/wD/AH8AAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + ASD/AP8A/wD+AAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8ABAADIQEwA1cB3wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH//wD/AP8A/wCEAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DWQHP/wD/AP8A/wAMAAMqAUADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1gBwAMXASD/AP8A + /wD/ABAAAyEBMAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/A1kBzwMXASD/AP8A/wD/AB8AAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf//AP8A/wD/ACQAAyEBMANXAd8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHP/wD/AP8A/wAsAAMq + AUADVwHfAwAB/wMAAf8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wNYAcADFwEg/wD/AP8A + /wAwAAMhATADAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DWQHPAxcBIP8A/wD/AP8A + PwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf//AP8A/wD/AEQAAyEBMANXAd8DAAH/AwCh/wMA + Af8DAAH/A1kBz/8A/wD/AP8ATAADKgFAA1cB3wMAof8DAAH/A1gBwAMXASD/AP8A/wD/AFAAAyEBMAMA + of8DWQHPAxcBIP8A/wD/AP8AXwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A + /wD/AP8AZAADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/AIwAAyoBQANXAd8DAAH/AwAB/wMA + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/AGwAAyoBQANX + Ad8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNYAcADFwEg/wD/AP8A/wCQAAMhATADAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/A1gBwAMXASD/AP8A/wD/AHAAAyEBMAMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc8DFwEg + /wD/AP8A/wB/AAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBzwMXASD/AP8A/wD/AJ8AAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8AhAADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHP/wD/AP8A/wCMAAMqAUADVwHfAwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8ApAADIQEwA1cB3wMAAf8DAAH/AwAB/wMA + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8AkAADIQEwAwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/A1kBz/8A/wD/AP8ArAADKgFAA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNYAcADFwEg/wD/AP8A/wCwAAMh - ATADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wNZAc8DFwEg/wD/AP8A/wC/AAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH//wD/AP8A/wDEAAMhATADVwHfAwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBz/8A/wD/AP8AzAADKgFAA1cB3wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8A0AADIQEw - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBzwMXASD/AP8A/wD/AN8AAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH//wD/AP8A/wDkAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wNZ - Ac//AP8A/wD/AOwAAyoBQANXAd8DAAH/AwAB/wNYAcADFwEg/wD/AP8A/wDwAAMhATADAAH/A1kBzwMX - ASD/AP8A/wD/AP8A/wD/AP8A/wBdAAFCAU0BPgcAAT4DAAEoAwABQAEBAgABUAMAAQEBAAEBBQABgAEM - FgAD/wEACv8eAAX/AT8E/x4ABP8B/gEfBP8eAAT/AfwBDwT/HgAE/wH4AQcE/x4ABP8B8AEDBP8eAAT/ - AeABAQT/HgAE/wHAAQAE/x4ABP8BgAEAAX8D/x4ABP8CAAE/A/8eAAP/Af4CAAEfA/8eAAP/AfwCAAEP - A/8eAAP/AfgCAAEHA/8eAAP/AfACAAEDA/8eAAP/AeACAAEBA/8eAAP/AcADAAP/HgAD/wGAAwABfwL/ - HgAD/wQAAT8C/x4AAv8B/gQAAR8C/x4AAv8B/AQAAQ8C/x4AAv8B+AQAAQcC/x4AAv8B8AQAAQMC/x4A - Av8B4AQAAQEC/x4AAv8BwAUAAv8eAAL/AYAFAAF/Af8eAAL/BgABPwH/HgAB/wH+BgABHwH/HgAB/wH8 - BgABDwH/HgAB/wH4BgABBwH/HgAB/wHwBgABAwH/HgAB/wHgBgABAQH/HgAB/wHABwAB/x4AAf8BgAcA - AX8eAAH/CAABPx4AAf4IAAEfHgAB/AgAAQ8eAAH4CAABBx4AAfAIAAEDHgAB4AgAAQEeAAHAJwABgCcA - AcAnAAHgCAABAR4AAfgIAAEHHgAB+AgAAQ8eAAH8CAABDx4AAf4IAAEfHgAB/wGABwABfx4AAf8BgAcA - Af8eAAH/AcAHAAH/HgAB/wHgBgABAQH/HgAB/wH4BgABBwH/HgAB/wH4BgABDwH/HgAB/wH8BgABDwH/ - HgAB/wH+BgABHwH/HgAC/wGABQABfwH/HgAC/wGABQAC/x4AAv8BwAUAAv8eAAL/AeAEAAEBAv8eAAL/ - AfgEAAEHAv8eAAL/AfgEAAEPAv8eAAL/AfwEAAEPAv8eAAL/Af4EAAEfAv8eAAP/AYADAAF/Av8eAAP/ - AYADAAP/HgAD/wHAAwAD/x4AA/8B4AIAAQED/x4AA/8B+AIAAQcD/x4AA/8B+AIAAQ8D/x4AA/8B/AIA - AQ8D/x4AA/8B/gIAAR8D/x4ABP8BgAEAAX8D/x4ABP8BgAEABP8eAAT/AcABAAT/HgAE/wHgAQEE/x4A - BP8B+AEHBP8eAAT/AfgBDwT/HgAE/wH8AQ8E/x4ABP8B/gEfBP8eAAr/HgAL + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc8DFwEg/wD/AP8A/wCfAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf//AP8A/wD/AKQAAyEBMANXAd8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wNZAc//AP8A/wD/AKwAAyoBQANXAd8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8AsAADIQEw + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DWQHPAxcBIP8A/wD/AP8AvwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8AxAADIQEwA1cB3wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/AMwAAyoBQANXAd8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1gBwAMXASD/AP8A/wD/ANAAAyEBMAMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc8DFwEg/wD/AP8A/wDfAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8A5AADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DWQHP + /wD/AP8A/wDsAAMqAUADVwHfAwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8A8AADIQEwAwAB/wNZAc8DFwEg + /wD/AP8A/wD/AP8A/wD/AP8AXQABQgFNAT4HAAE+AwABKAMAAUABAQIAAVADAAEBAQABAQUAAYABDBYA + A/8BAAr/HgAF/wE/BP8eAAT/Af4BHwT/HgAE/wH8AQ8E/x4ABP8B+AEHBP8eAAT/AfABAwT/HgAE/wHg + AQEE/x4ABP8BwAEABP8eAAT/AYABAAF/A/8eAAT/AgABPwP/HgAD/wH+AgABHwP/HgAD/wH8AgABDwP/ + HgAD/wH4AgABBwP/HgAD/wHwAgABAwP/HgAD/wHgAgABAQP/HgAD/wHAAwAD/x4AA/8BgAMAAX8C/x4A + A/8EAAE/Av8eAAL/Af4EAAEfAv8eAAL/AfwEAAEPAv8eAAL/AfgEAAEHAv8eAAL/AfAEAAEDAv8eAAL/ + AeAEAAEBAv8eAAL/AcAFAAL/HgAC/wGABQABfwH/HgAC/wYAAT8B/x4AAf8B/gYAAR8B/x4AAf8B/AYA + AQ8B/x4AAf8B+AYAAQcB/x4AAf8B8AYAAQMB/x4AAf8B4AYAAQEB/x4AAf8BwAcAAf8eAAH/AYAHAAF/ + HgAB/wgAAT8eAAH+CAABHx4AAfwIAAEPHgAB+AgAAQceAAHwCAABAx4AAeAIAAEBHgABwCcAAYAnAAHA + JwAB4AgAAQEeAAH4CAABBx4AAfgIAAEPHgAB/AgAAQ8eAAH+CAABHx4AAf8BgAcAAX8eAAH/AYAHAAH/ + HgAB/wHABwAB/x4AAf8B4AYAAQEB/x4AAf8B+AYAAQcB/x4AAf8B+AYAAQ8B/x4AAf8B/AYAAQ8B/x4A + Af8B/gYAAR8B/x4AAv8BgAUAAX8B/x4AAv8BgAUAAv8eAAL/AcAFAAL/HgAC/wHgBAABAQL/HgAC/wH4 + BAABBwL/HgAC/wH4BAABDwL/HgAC/wH8BAABDwL/HgAC/wH+BAABHwL/HgAD/wGAAwABfwL/HgAD/wGA + AwAD/x4AA/8BwAMAA/8eAAP/AeACAAEBA/8eAAP/AfgCAAEHA/8eAAP/AfgCAAEPA/8eAAP/AfwCAAEP + A/8eAAP/Af4CAAEfA/8eAAT/AYABAAF/A/8eAAT/AYABAAT/HgAE/wHAAQAE/x4ABP8B4AEBBP8eAAT/ + AfgBBwT/HgAE/wH4AQ8E/x4ABP8B/AEPBP8eAAT/Af4BHwT/HgAK/x4ACw== @@ -308,63 +308,63 @@ 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 - Y5nvPusUIv8DXoHPiI5TPQAAAAAASUVORK5CYII= + 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 - VJz/r7pVhjgAAAAASUVORK5CYII= + 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 + vb8B5HT/l7ekK9QAAAAASUVORK5CYII= @@ -479,6 +479,36 @@ +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 diff --git a/BulkDataUpdater/Settings.cs b/BulkDataUpdater/Settings.cs index d85ee32..aeffd63 100644 --- a/BulkDataUpdater/Settings.cs +++ b/BulkDataUpdater/Settings.cs @@ -14,6 +14,7 @@ public class Settings public List EntityAttributes { get; set; } public string FetchXML { get; set; } public bool Friendly { get; set; } = false; + public int DeleteBatchSize { get; set; } = 1; } public class KeyValuePair From 528616fa9190746554aeba3c9aadd37cdeee641e Mon Sep 17 00:00:00 2001 From: Jonas Rapp Date: Mon, 15 Oct 2018 22:54:01 +0200 Subject: [PATCH 4/7] CodeMaid reorg --- BulkDataUpdater/MainControl.cs | 2004 ++++++++++++++++---------------- 1 file changed, 1014 insertions(+), 990 deletions(-) diff --git a/BulkDataUpdater/MainControl.cs b/BulkDataUpdater/MainControl.cs index ae5d6b8..ff6f28d 100644 --- a/BulkDataUpdater/MainControl.cs +++ b/BulkDataUpdater/MainControl.cs @@ -20,53 +20,77 @@ public partial class BulkDataUpdater : PluginControlBase, IGitHubPlugin, IPayPalPlugin, IMessageBusHost, IAboutPlugin { + #region Internal Fields + + internal static bool useFriendlyNames = false; + internal static Dictionary> views; + internal List entityShitList = new List(); + + #endregion Internal Fields + + #region Private Fields + private const string aiEndpoint = "https://dc.services.visualstudio.com/v2/track"; - //private const string aiKey = "cc7cb081-b489-421d-bb61-2ee53495c336"; // jonas@rappen.net tenant, TestAI + + //private const string aiKey = "cc7cb081-b489-421d-bb61-2ee53495c336"; // jonas@rappen.net tenant, TestAI private const string aiKey = "eed73022-2444-45fd-928b-5eebd8fa46a6"; // jonas@rappen.net tenant, XrmToolBox - private AppInsights ai = new AppInsights(new AiConfig(aiEndpoint, aiKey) { PluginName = "Bulk Data Updater" }); + private static Dictionary entities; private static string fetchTemplate = ""; - + private AppInsights ai = new AppInsights(new AiConfig(aiEndpoint, aiKey) { PluginName = "Bulk Data Updater" }); + private Dictionary entityAttributes = new Dictionary(); private string fetchXml = fetchTemplate; private EntityCollection records; - private bool working = false; - private static Dictionary entities; - internal List entityShitList = new List(); // Oops, did I name that one?? - internal static Dictionary> views; - private Entity view; - internal static bool useFriendlyNames = false; private bool showAttributesAll = true; - private bool showAttributesManaged = true; - private bool showAttributesUnmanaged = true; - private bool showAttributesCustomizable = true; - private bool showAttributesUncustomizable = true; private bool showAttributesCustom = true; - private bool showAttributesStandard = true; + private bool showAttributesCustomizable = true; + private bool showAttributesManaged = true; private bool showAttributesOnlyValidAF = true; - private Dictionary entityAttributes = new Dictionary(); + private bool showAttributesStandard = true; + private bool showAttributesUncustomizable = true; + private bool showAttributesUnmanaged = true; + + // Oops, did I name that one?? + private Entity view; + + private bool working = false; + + #endregion Private Fields + + #region Public Constructors public BulkDataUpdater() { InitializeComponent(); } - #region Interface implementation + #endregion Public Constructors - public override void ClosingPlugin(PluginCloseInfo info) - { - SaveSetting(); - LogUse("Close"); - } + #region Public Events - public string RepositoryName => "BulkDataUpdater"; + public event EventHandler OnOutgoingMessage; - public string UserName => "rappen"; + #endregion Public Events + + #region Public Properties public string DonationDescription => "Donation to Bulk Data Updater for XrmToolBox"; public string EmailAccount => "jonas@rappen.net"; - public event EventHandler OnOutgoingMessage; + public string RepositoryName => "BulkDataUpdater"; + + public string UserName => "rappen"; + + #endregion Public Properties + + #region Public Methods + + public override void ClosingPlugin(PluginCloseInfo info) + { + SaveSetting(); + LogUse("Close"); + } public void OnIncomingMessage(XrmToolBox.Extensibility.MessageBusEventArgs message) { @@ -82,246 +106,325 @@ public void ShowAboutDialog() tslAbout_Click(null, null); } - #endregion interface implementation - - #region Event handlers - - private void DataUpdater_Load(object sender, EventArgs e) - { - EnableControls(false); - LoadSetting(); - LogUse("Load"); - EnableControls(true); - } - - private void DataUpdater_ConnectionUpdated(object sender, XrmToolBox.Extensibility.PluginControlBase.ConnectionUpdatedEventArgs e) - { - crmGridView1.DataSource = null; - entities = null; - entityShitList.Clear(); - EnableControls(true); - } - - private void tsbCloseThisTab_Click(object sender, EventArgs e) - { - CloseTool(); - } - - private void tsmiOpenFile_Click(object sender, EventArgs e) - { - OpenFile(); - } - - private void tsmiOpenView_Click(object sender, EventArgs e) - { - OpenView(); - } + #endregion Public Methods - private void tsmiFriendly_Click(object sender, EventArgs e) - { - useFriendlyNames = tsmiFriendly.Checked; - RefreshAttributes(); - } + #region Internal Methods - private void tsmiAttributes_Click(object sender, EventArgs e) + internal static string GetAttributeDisplayName(AttributeMetadata attribute) { - if (sender != tsmiAttributesAll) + string attributeName = attribute.LogicalName; + if (useFriendlyNames) { - tsmiAttributesAll.Checked = - tsmiAttributesManaged.Checked && - tsmiAttributesUnmanaged.Checked && - tsmiAttributesCustomizable.Checked && - tsmiAttributesUncustomizable.Checked && - tsmiAttributesCustom.Checked && - tsmiAttributesStandard.Checked && - !tsmiAttributesOnlyValidAF.Checked; - } - if (!tsmiAttributesManaged.Checked && !tsmiAttributesUnmanaged.Checked) - { // Neither managed nor unmanaged is not such a good idea... - tsmiAttributesUnmanaged.Checked = true; - } - if (!tsmiAttributesCustomizable.Checked && !tsmiAttributesUncustomizable.Checked) - { // Neither customizable nor uncustomizable is not such a good idea... - tsmiAttributesCustomizable.Checked = true; - } - if (!tsmiAttributesCustom.Checked && !tsmiAttributesStandard.Checked) - { // Neither custom nor standard is not such a good idea... - tsmiAttributesStandard.Checked = true; + if (attribute.DisplayName.UserLocalizedLabel != null) + { + attributeName = attribute.DisplayName.UserLocalizedLabel.Label; + } + if (attributeName == attribute.LogicalName && attribute.DisplayName.LocalizedLabels.Count > 0) + { + attributeName = attribute.DisplayName.LocalizedLabels[0].Label; + } + attributeName += " (" + attribute.LogicalName + ")"; } - tsmiAttributesManaged.Enabled = !tsmiAttributesAll.Checked; - tsmiAttributesUnmanaged.Enabled = !tsmiAttributesAll.Checked; - tsmiAttributesCustomizable.Enabled = !tsmiAttributesAll.Checked; - tsmiAttributesUncustomizable.Enabled = !tsmiAttributesAll.Checked; - tsmiAttributesCustom.Enabled = !tsmiAttributesAll.Checked; - tsmiAttributesStandard.Enabled = !tsmiAttributesAll.Checked; - tsmiAttributesOnlyValidAF.Enabled = !tsmiAttributesAll.Checked; - showAttributesAll = tsmiAttributesAll.Checked; - showAttributesManaged = tsmiAttributesManaged.Checked; - showAttributesUnmanaged = tsmiAttributesUnmanaged.Checked; - showAttributesCustomizable = tsmiAttributesCustomizable.Checked; - showAttributesUncustomizable = tsmiAttributesUncustomizable.Checked; - showAttributesCustom = tsmiAttributesCustom.Checked; - showAttributesStandard = tsmiAttributesStandard.Checked; - showAttributesOnlyValidAF = tsmiAttributesOnlyValidAF.Checked; - RefreshAttributes(); + return attributeName; } - private void btnGetRecords_Click(object sender, EventArgs e) + internal static Dictionary GetDisplayEntities() { - if (sender is Button btn) + var result = new Dictionary(); + if (entities != null) { - GetRecords(btn.Tag?.ToString()); + foreach (var entity in entities) + { + //if (!showEntitiesAll) + //{ + // if (!showEntitiesManaged && entity.Value.IsManaged == true) { continue; } + // if (!showEntitiesUnmanaged && entity.Value.IsManaged == false) { continue; } + // if (!showEntitiesCustomizable && entity.Value.IsCustomizable.Value) { continue; } + // if (!showEntitiesUncustomizable && !entity.Value.IsCustomizable.Value) { continue; } + // if (!showEntitiesStandard && entity.Value.IsCustomEntity == false) { continue; } + // if (!showEntitiesCustom && entity.Value.IsCustomEntity == true) { continue; } + // if (!showEntitiesIntersect && entity.Value.IsIntersect == true) { continue; } + // if (showEntitiesOnlyValidAF && entity.Value.IsValidForAdvancedFind == false) { continue; } + //} + result.Add(entity.Key, entity.Value); + } } + return result; } - private void cmbAttribute_SelectedIndexChanged(object sender, EventArgs e) - { - UpdateValueField(); - } - - private void cmbAttribute_TextChanged(object sender, EventArgs e) - { - EnableControls(true); - } - - private void rbSet_CheckedChanged(object sender, EventArgs e) + internal static string GetEntityDisplayName(string entityName) { - cmbValue.Enabled = rbSetValue.Checked; - chkOnlyChange.Enabled = !rbSetTouch.Checked; - if (rbSetTouch.Checked) + if (!useFriendlyNames) { - chkOnlyChange.Checked = false; + return entityName; } - EnableControls(true); - } - - private void btnUpdate_Click(object sender, EventArgs e) - { - UpdateRecords(); - } - - private void tslAbout_Click(object sender, EventArgs e) - { - LogUse("OpenAbout"); - var about = new About(this); - about.StartPosition = FormStartPosition.CenterParent; - about.lblVersion.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - about.ShowDialog(); - } - - private void btnAdd_Click(object sender, EventArgs e) - { - AddAttribute(); + if (entities != null && entities.ContainsKey(entityName)) + { + entityName = GetEntityDisplayName(entities[entityName]); + } + return entityName; } - private void btnRemove_Click(object sender, EventArgs e) + internal static string GetEntityDisplayName(EntityMetadata entity) { - RemoveAttribute(); + var result = entity.LogicalName; + if (useFriendlyNames) + { + if (entity.DisplayName.UserLocalizedLabel != null) + { + result = entity.DisplayName.UserLocalizedLabel.Label; + } + if (result == entity.LogicalName && entity.DisplayName.LocalizedLabels.Count > 0) + { + result = entity.DisplayName.LocalizedLabels[0].Label; + } + } + return result; } - private void lvAttributes_SelectedIndexChanged(object sender, EventArgs e) + internal void LoadViews(Action viewsLoaded) { - if (lvAttributes.SelectedItems.Count == 0) + if (working) { return; } - if (lvAttributes.SelectedItems[0].Tag is BulkActionItem attribute) + if (entities == null || entities.Count == 0) { - cmbAttribute.Text = attribute.Attribute.ToString(); - switch (attribute.Action) + LoadEntities(viewsLoaded); + return; + } + working = true; + WorkAsync(new WorkAsyncInfo("Loading views...", + (bgworker, workargs) => { - case BulkActionAction.SetValue: - rbSetValue.Checked = true; - if (attribute.Value is OptionSetValue osv) + EnableControls(false); + if (views == null || views.Count == 0) + { + if (Service == null) { - foreach (var option in cmbValue.Items.Cast().Where(i => i is OptionsetItem).Select(i => i as OptionsetItem)) - { - if (option.meta.Value == osv.Value) - { - cmbValue.SelectedItem = option; - break; - } - } + throw new Exception("Need a connection to load views."); } - else - { - cmbValue.Text = attribute.Value.ToString(); + var qex = new QueryExpression("savedquery"); + qex.ColumnSet = new ColumnSet("name", "returnedtypecode", "fetchxml"); + qex.Criteria.AddCondition("statecode", ConditionOperator.Equal, 0); + qex.Criteria.AddCondition("querytype", ConditionOperator.In, 0, 32); + qex.AddOrder("name", OrderType.Ascending); + bgworker.ReportProgress(33, "Loading system views..."); + var sysviews = Service.RetrieveMultiple(qex); + foreach (var view in sysviews.Entities) + { + var entityname = view["returnedtypecode"].ToString(); + if (!string.IsNullOrWhiteSpace(entityname) && entities.ContainsKey(entityname)) + { + if (views == null) + { + views = new Dictionary>(); + } + if (!views.ContainsKey(entityname + "|S")) + { + views.Add(entityname + "|S", new List()); + } + views[entityname + "|S"].Add(view); + } } - break; - case BulkActionAction.Touch: - rbSetTouch.Checked = true; - cmbValue.Text = string.Empty; - break; - case BulkActionAction.Null: - rbSetNull.Checked = true; - cmbValue.Text = string.Empty; - break; + qex.EntityName = "userquery"; + bgworker.ReportProgress(66, "Loading user views..."); + var userviews = Service.RetrieveMultiple(qex); + foreach (var view in userviews.Entities) + { + var entityname = view["returnedtypecode"].ToString(); + if (!string.IsNullOrWhiteSpace(entityname) && entities.ContainsKey(entityname)) + { + if (views == null) + { + views = new Dictionary>(); + } + if (!views.ContainsKey(entityname + "|U")) + { + views.Add(entityname + "|U", new List()); + } + views[entityname + "|U"].Add(view); + } + } + bgworker.ReportProgress(100, "Finalizing..."); + } + }) + { + PostWorkCallBack = (completedargs) => + { + working = false; + EnableControls(true); + if (completedargs.Error != null) + { + MessageBox.Show(completedargs.Error.Message); + } + else + { + viewsLoaded(); + } + }, + ProgressChanged = (changeargs) => + { + SetWorkingMessage(changeargs.UserState.ToString()); } - chkOnlyChange.Checked = attribute.DontTouch; - } + }); } - private void cmbValue_SelectedIndexChanged(object sender, EventArgs e) + internal void LogUse(string action, double? count = null, double? duration = null) { - EnableControls(true); + ai.WriteEvent(action, count, duration, HandleAIResult); } - #endregion Event handlers + #endregion Internal Methods - #region Methods + #region Private Methods - private void SaveSetting() + private static bool CheckAllUpdateAttributesExistOnRecord(Entity record, List attributes) { - //var entattrstr = ""; - //foreach (var entattr in entityAttributes) - //{ - // entattrstr += entattr.Key + ":" + entattr.Value + "|"; - //} - var settings = new Settings() + var allattributesexist = true; + foreach (var attribute in attributes + .Where(a => a.Action == BulkActionAction.Touch || (a.Action == BulkActionAction.SetValue && a.DontTouch)) + .Select(a => a.Attribute.Metadata.LogicalName)) { - FetchXML = fetchXml, - EntityAttributes = entityAttributes.Select(p => new KeyValuePair() { key = p.Key, value = p.Value }).ToList(), - Friendly = tsmiFriendly.Checked, - AttributesManaged = tsmiAttributesManaged.Checked, - AttributesUnmanaged = tsmiAttributesUnmanaged.Checked, - AttributesCustomizable = tsmiAttributesCustomizable.Checked, - AttributesUncustomizable = tsmiAttributesUncustomizable.Checked, - AttributesCustom = tsmiAttributesCustom.Checked, - AttributesStandard = tsmiAttributesStandard.Checked, - AttributesOnlyValidAF = tsmiAttributesOnlyValidAF.Checked, - DeleteBatchSize = int.TryParse(cmbDelBatchSize.Text, out int size) ? size : 1 - }; - SettingsManager.Instance.Save(typeof(BulkDataUpdater), settings, "Settings"); + if (!record.Contains(attribute)) + { + allattributesexist = false; + break; + } + if (attribute == "statuscode" && !record.Contains("statecode")) + { + allattributesexist = false; + break; + } + } + return allattributesexist; } - private void LoadSetting() + private static OptionSetValue GetCurrentStateCodeFromStatusCode(IEnumerable attributes) { - Settings settings; - if (!SettingsManager.Instance.TryLoad(typeof(BulkDataUpdater), out settings, "Settings")) + var statusattribute = attributes.Where(a => a.Attribute.Metadata is StatusAttributeMetadata && a.Value is OptionSetValue).FirstOrDefault(); + if (statusattribute != null && + statusattribute.Attribute.Metadata is StatusAttributeMetadata statusmeta && + statusattribute.Value is OptionSetValue osv) { - settings = new Settings(); + foreach (var statusoption in statusmeta.OptionSet.Options) + { + if (statusoption is StatusOptionMetadata && statusoption.Value == osv.Value) + { + return new OptionSetValue((int)((StatusOptionMetadata)statusoption).State); + } + } } + return null; + } - fetchXml = settings.FetchXML; - if (settings.EntityAttributes != null) + private void AddAttribute() + { + if (!(GetAttributeItemFromUI() is BulkActionItem bai)) { - entityAttributes = settings.EntityAttributes.ToDictionary(i => i.key, i => i.value); + return; } - else + if (lvAttributes.Items + .Cast() + .Select(i => i.Tag as BulkActionItem) + .Any(i => i.Attribute.Metadata.LogicalName == bai.Attribute.Metadata.LogicalName)) { - entityAttributes = new Dictionary(); + if (MessageBox.Show($"Replace already added attribute {bai.Attribute} ?", "Attribute added", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) == DialogResult.Cancel) + { + return; + } + var removeitem = lvAttributes.Items + .Cast() + .FirstOrDefault(i => (i.Tag as BulkActionItem).Attribute.Metadata.LogicalName == bai.Attribute.Metadata.LogicalName); + lvAttributes.Items.Remove(removeitem); } - tsmiFriendly.Checked = settings.Friendly; - tsmiAttributesManaged.Checked = settings.AttributesManaged; - tsmiAttributesUnmanaged.Checked = settings.AttributesUnmanaged; - tsmiAttributesCustomizable.Checked = settings.AttributesCustomizable; - tsmiAttributesUncustomizable.Checked = settings.AttributesUncustomizable; - tsmiAttributesCustom.Checked = settings.AttributesCustom; - tsmiAttributesStandard.Checked = settings.AttributesStandard; - tsmiAttributesOnlyValidAF.Checked = settings.AttributesOnlyValidAF; - cmbDelBatchSize.SelectedItem = cmbDelBatchSize.Items.Cast().FirstOrDefault(i => i == settings.DeleteBatchSize.ToString()); - tsmiFriendly_Click(null, null); - tsmiAttributes_Click(null, null); + var item = lvAttributes.Items.Add(bai.Attribute.ToString()); + item.Tag = bai; + item.SubItems.Add(bai.Action.ToString()); + item.SubItems.Add(bai.Action == BulkActionAction.SetValue ? bai.StringValue : string.Empty); + item.SubItems.Add(bai.DontTouch ? "Yes" : "No"); + EnableControls(true); + } + + private void DeleteRecords() + { + if (working) + { + return; + } + if (MessageBox.Show("All selected records will unconditionally be deleted.\nUI defined rules will NOT be enforced.\nPlugins and workflows WILL trigger.\n\nConfirm delete!", + "Confirm", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk) != DialogResult.OK) + { + return; + } + working = true; + if (!int.TryParse(cmbDelBatchSize.Text, out int batchsize)) + { + batchsize = 1; + } + WorkAsync(new WorkAsyncInfo() + { + Message = "Deleting records", + IsCancelable = true, + Work = (bgworker, workargs) => + { + var sw = Stopwatch.StartNew(); + var total = records.Entities.Count; + var current = 0; + var deleted = 0; + var failed = 0; + foreach (var record in records.Entities) + { + current++; + var pct = 100 * current / total; + bgworker.ReportProgress(pct, "Deleting record " + current.ToString()); + try + { + if (batchsize == 1) + { + Service.Delete(record.LogicalName, record.Id); + deleted++; + } + else + { + MessageBox.Show("Not implemented yet, try batch size = 1"); + return; + } + } + catch (Exception ex) + { + failed++; + if (!chkIgnoreErrors.Checked) + { + throw ex; + } + } + } + sw.Stop(); + workargs.Result = new Tuple(deleted, failed, sw.ElapsedMilliseconds); + }, + PostWorkCallBack = (completedargs) => + { + working = false; + if (completedargs.Error != null) + { + MessageBox.Show(completedargs.Error.Message, "Delete", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + else if (completedargs.Result is Tuple result) + { + lblDelStatus.Text = $"{result.Item1} records deleted, {result.Item2} records failed."; + LogUse("Deleted", result.Item1, result.Item3); + if (result.Item2 > 0) + { + LogUse("Failed", result.Item2); + } + } + }, + ProgressChanged = (changeargs) => + { + SetWorkingMessage(changeargs.UserState.ToString()); + } + }); } private void EnableControls(bool enabled) @@ -352,58 +455,98 @@ private void EnableControls(bool enabled) } } - private string OpenFile() + private void FetchUpdated(string fetch) { - var result = ""; - var ofd = new OpenFileDialog + if (!string.IsNullOrWhiteSpace(fetch)) { - Title = "Select an XML file containing FetchXML", - Filter = "XML file (*.xml)|*.xml" - }; + fetchXml = fetch; + RetrieveRecords(fetchXml, RetrieveRecordsReady); + } + } - if (ofd.ShowDialog() == DialogResult.OK) + private BulkActionItem GetAttributeItemFromUI() + { + if (!(cmbAttribute.SelectedItem is AttributeItem)) { - EnableControls(false); - var fetchDoc = new XmlDocument(); - fetchDoc.Load(ofd.FileName); + MessageBox.Show("Select an attribute to update from the list."); + return null; + } + var bai = new BulkActionItem + { + Attribute = (AttributeItem)cmbAttribute.SelectedItem, + DontTouch = chkOnlyChange.Checked, + Action = rbSetValue.Checked ? BulkActionAction.SetValue : rbSetNull.Checked ? BulkActionAction.Null : BulkActionAction.Touch + }; + var logicalname = bai.Attribute.GetValue(); + bai.Value = null; + try + { + bai.Value = bai.Action == BulkActionAction.SetValue ? GetValue(bai.Attribute.Metadata.AttributeType) : null; + bai.StringValue = bai.Action == BulkActionAction.SetValue ? cmbValue.Text : string.Empty; + } + catch (Exception e) + { + MessageBox.Show("Value error:\n" + e.Message, "Set value", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + return bai; + } - if (fetchDoc.DocumentElement.Name != "fetch" || - fetchDoc.DocumentElement.ChildNodes.Count > 0 && - fetchDoc.DocumentElement.ChildNodes[0].Name == "fetch") - { - MessageBox.Show(this, "Invalid Xml: Definition XML root must be fetch!", "Error", - MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else + private AttributeMetadata[] GetDisplayAttributes(string entityName) + { + var result = new List(); + AttributeMetadata[] attributes = null; + if (entities != null && entities.ContainsKey(entityName)) + { + attributes = entities[entityName].Attributes; + if (attributes != null) { - result = fetchDoc.OuterXml; - EnableControls(true); + foreach (var attribute in attributes) + { + if (!attribute.IsValidForUpdate.Value == true) + { + continue; + } + if (attribute.LogicalName == "statecode" || attribute.LogicalName == "statuscode") + { + continue; + } + if (!showAttributesAll) + { + if (!string.IsNullOrEmpty(attribute.AttributeOf)) { continue; } + if (!showAttributesManaged && attribute.IsManaged == true) { continue; } + if (!showAttributesUnmanaged && attribute.IsManaged == false) { continue; } + if (!showAttributesCustomizable && attribute.IsCustomizable.Value) { continue; } + if (!showAttributesUncustomizable && !attribute.IsCustomizable.Value) { continue; } + if (!showAttributesStandard && attribute.IsCustomAttribute == false) { continue; } + if (!showAttributesCustom && attribute.IsCustomAttribute == true) { continue; } + if (showAttributesOnlyValidAF && attribute.IsValidForAdvancedFind.Value == false) { continue; } + } + result.Add(attribute); + } } } - return result; + return result.ToArray(); } - private void OpenView() + private void GetFromEditor() { - EnableControls(false); - if (views == null || views.Count == 0) + var fetchwin = new XmlContentDisplayDialog(fetchXml, "Enter FetchXML to retrieve records to update", true, true); + fetchwin.StartPosition = FormStartPosition.CenterParent; + if (fetchwin.ShowDialog() == DialogResult.OK) { - LoadViews(OpenView); - return; + FetchUpdated(fetchwin.txtXML.Text); } - var viewselector = new SelectViewDialog(this); - viewselector.StartPosition = FormStartPosition.CenterParent; - if (viewselector.ShowDialog() == DialogResult.OK) + } + + private void GetFromFXB() + { + var messageBusEventArgs = new MessageBusEventArgs("FetchXML Builder") { - view = viewselector.View; - var fetchDoc = new XmlDocument(); - if (view.Contains("fetchxml")) - { - fetchDoc.LoadXml(view["fetchxml"].ToString()); - FetchUpdated(fetchDoc.OuterXml); - } - } - EnableControls(true); + //SourcePlugin = "Bulk Data Updater" + }; + messageBusEventArgs.TargetArgument = fetchXml; + OnOutgoingMessage(this, messageBusEventArgs); } private void GetRecords(string tag) @@ -442,479 +585,520 @@ private void GetRecords(string tag) LogUse(tag, records?.Entities?.Count); } - private void GetFromEditor() + private object GetValue(AttributeTypeCode? type) { - var fetchwin = new XmlContentDisplayDialog(fetchXml, "Enter FetchXML to retrieve records to update", true, true); - fetchwin.StartPosition = FormStartPosition.CenterParent; - if (fetchwin.ShowDialog() == DialogResult.OK) + switch (type) { - FetchUpdated(fetchwin.txtXML.Text); + case AttributeTypeCode.String: + case AttributeTypeCode.Memo: + return cmbValue.Text; + + case AttributeTypeCode.BigInt: + case AttributeTypeCode.Integer: + return int.Parse(cmbValue.Text); + + case AttributeTypeCode.Decimal: + return decimal.Parse(cmbValue.Text); + + case AttributeTypeCode.Double: + return double.Parse(cmbValue.Text); + + case AttributeTypeCode.Picklist: + case AttributeTypeCode.State: + case AttributeTypeCode.Status: + var value = ((OptionsetItem)cmbValue.SelectedItem).meta.Value; + return new OptionSetValue((int)value); + + case AttributeTypeCode.DateTime: + return DateTime.Parse(cmbValue.Text); + + case AttributeTypeCode.Boolean: + { + // Is checking the cmbAttribute ok? I hope so... + var attr = (BooleanAttributeMetadata)((AttributeItem)cmbAttribute.SelectedItem).Metadata; + return ((OptionsetItem)cmbValue.SelectedItem).meta == attr.OptionSet.TrueOption; + } + case AttributeTypeCode.Money: + return new Money(decimal.Parse(cmbValue.Text)); + + // The following allows to specify an entity reference in the following form: + // attribute_name,attribute_guid + // eg: account,08e943f8-1ff0-41ea-89c0-5478dd465806 + // As a security check, the attribute_name MUST be in the targets + // specified by the lookup attribute metadata targets + case AttributeTypeCode.Lookup: + case AttributeTypeCode.Customer: + { + // Get the attribute metadata for the lookup type: + var attr = (LookupAttributeMetadata)((AttributeItem)cmbAttribute.SelectedItem).Metadata; + + // split the text: first part: attribute meta name, second part: attribute guid to update + var t = cmbValue.Text.Split(',', ';', '/', '\\', ':').ToArray(); + // get the first target + string attrname = (attr.Targets != null && attr.Targets.Length > 0) ? attr.Targets[0] : null; + if (attr.Targets != null && t.Length > 1) + attrname = attr.Targets.FirstOrDefault(x => t.First().Equals(x, StringComparison.OrdinalIgnoreCase)); + + if (String.IsNullOrEmpty(attrname)) + throw new Exception("Target entity: '" + t.First() + "' is null or not found"); + + return new EntityReference(attrname, new Guid(t.Last())); + } + + default: + throw new Exception("Attribute of type " + type.ToString() + " is currently not supported."); } } - private void GetFromFXB() + private void HandleAIResult(string result) { - var messageBusEventArgs = new MessageBusEventArgs("FetchXML Builder") + if (!string.IsNullOrEmpty(result)) { - //SourcePlugin = "Bulk Data Updater" - }; - messageBusEventArgs.TargetArgument = fetchXml; - OnOutgoingMessage(this, messageBusEventArgs); + LogError("Failed to write to Application Insights:\n{0}", result); + } } - private void FetchUpdated(string fetch) + private void LoadEntities(Action AfterLoad) { - if (!string.IsNullOrWhiteSpace(fetch)) + if (working) { - fetchXml = fetch; - RetrieveRecords(fetchXml, RetrieveRecordsReady); + return; } - } - - private void RetrieveRecordsReady() - { - if (records != null) + entities = null; + entityShitList = new List(); + working = true; + WorkAsync(new WorkAsyncInfo("Loading entities metadata...", + (eventargs) => + { + EnableControls(false); + var req = new RetrieveAllEntitiesRequest() + { + EntityFilters = EntityFilters.Entity, + RetrieveAsIfPublished = true + }; + eventargs.Result = Service.Execute(req); + }) { - var entityName = records.EntityName; - if (NeedToLoadEntity(entityName)) + PostWorkCallBack = (completedargs) => { - if (!working) + working = false; + if (completedargs.Error != null) { - LoadEntityDetails(entityName, RetrieveRecordsReady); + MessageBox.Show(completedargs.Error.Message); + } + else + { + if (completedargs.Result is RetrieveAllEntitiesResponse) + { + entities = new Dictionary(); + foreach (var entity in ((RetrieveAllEntitiesResponse)completedargs.Result).EntityMetadata) + { + entities.Add(entity.LogicalName, entity); + } + } + } + EnableControls(true); + if (AfterLoad != null) + { + AfterLoad(); } - return; } - lblRecords.Text = records.Entities.Count.ToString() + " records of entity " + records.EntityName; - lblDeleteHeader.Text = $"Delete {records.Entities.Count} {entities.FirstOrDefault(e => e.Key == records.EntityName).Value.DisplayCollectionName.UserLocalizedLabel.Label}"; - crmGridView1.OrganizationService = Service; - crmGridView1.DataSource = records; - crmGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); - } - RefreshAttributes(); + }); } - private bool NeedToLoadEntity(string entityName) + private void LoadEntityDetails(string entityName, Action detailsLoaded) { - return - !string.IsNullOrEmpty(entityName) && - !entityShitList.Contains(entityName) && - Service != null && - (entities == null || - !entities.ContainsKey(entityName) || - entities[entityName].Attributes == null); - } - - private void RefreshAttributes() - { - EnableControls(false); - cmbAttribute.Items.Clear(); - if (records != null) + if (working) { - var entityName = records.EntityName; - if (NeedToLoadEntity(entityName)) + return; + } + working = true; + WorkAsync(new WorkAsyncInfo("Loading " + GetEntityDisplayName(entityName) + " metadata...", + (eventargs) => { - if (!working) + var req = new RetrieveEntityRequest() { - LoadEntityDetails(entityName, RefreshAttributes); - } - return; - } - var attributes = GetDisplayAttributes(entityName); - foreach (var attribute in attributes) - { - AttributeItem.AddAttributeToComboBox(cmbAttribute, attribute, true); - } - if (entityAttributes.ContainsKey(records.EntityName)) + LogicalName = entityName, + EntityFilters = EntityFilters.Attributes | EntityFilters.Relationships, + RetrieveAsIfPublished = true + }; + eventargs.Result = Service.Execute(req); + }) + { + PostWorkCallBack = (completedargs) => { - var attr = entityAttributes[records.EntityName]; - var coll = new Dictionary(); - coll.Add("attribute", attr); - ControlUtils.FillControl(coll, cmbAttribute); + working = false; + if (completedargs.Error != null) + { + entityShitList.Add(entityName); + MessageBox.Show(completedargs.Error.Message, "Load attribute metadata", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + else + { + if (completedargs.Result is RetrieveEntityResponse) + { + var resp = (RetrieveEntityResponse)completedargs.Result; + if (entities == null) + { + entities = new Dictionary(); + } + if (entities.ContainsKey(entityName)) + { + entities[entityName] = resp.EntityMetadata; + } + else + { + entities.Add(entityName, resp.EntityMetadata); + } + } + detailsLoaded(); + } + working = false; } - } - crmGridView1.ShowFriendlyNames = useFriendlyNames; - crmGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); - EnableControls(true); + }); } - internal static Dictionary GetDisplayEntities() + private void LoadMissingAttributesForRecord(Entity record, string entity, IEnumerable attributes) { - var result = new Dictionary(); - if (entities != null) + var newcols = new ColumnSet(attributes.Select(a => a.Attribute.Metadata.LogicalName).ToArray()); + if (newcols.Columns.Contains("statuscode")) { - foreach (var entity in entities) + newcols.AddColumn("statecode"); + } + var newrecord = Service.Retrieve(entity, record.Id, newcols); + foreach (var attribute in newrecord.Attributes.Keys) + { + if (newrecord.Contains(attribute) && !record.Contains(attribute)) { - //if (!showEntitiesAll) - //{ - // if (!showEntitiesManaged && entity.Value.IsManaged == true) { continue; } - // if (!showEntitiesUnmanaged && entity.Value.IsManaged == false) { continue; } - // if (!showEntitiesCustomizable && entity.Value.IsCustomizable.Value) { continue; } - // if (!showEntitiesUncustomizable && !entity.Value.IsCustomizable.Value) { continue; } - // if (!showEntitiesStandard && entity.Value.IsCustomEntity == false) { continue; } - // if (!showEntitiesCustom && entity.Value.IsCustomEntity == true) { continue; } - // if (!showEntitiesIntersect && entity.Value.IsIntersect == true) { continue; } - // if (showEntitiesOnlyValidAF && entity.Value.IsValidForAdvancedFind == false) { continue; } - //} - result.Add(entity.Key, entity.Value); + record.Attributes.Add(attribute, newrecord[attribute]); } } - return result; } - private AttributeMetadata[] GetDisplayAttributes(string entityName) + private void LoadSetting() { - var result = new List(); - AttributeMetadata[] attributes = null; - if (entities != null && entities.ContainsKey(entityName)) + Settings settings; + if (!SettingsManager.Instance.TryLoad(typeof(BulkDataUpdater), out settings, "Settings")) { - attributes = entities[entityName].Attributes; - if (attributes != null) - { - foreach (var attribute in attributes) - { - if (!attribute.IsValidForUpdate.Value == true) - { - continue; - } - if (attribute.LogicalName == "statecode" || attribute.LogicalName == "statuscode") - { - continue; - } - if (!showAttributesAll) - { - if (!string.IsNullOrEmpty(attribute.AttributeOf)) { continue; } - if (!showAttributesManaged && attribute.IsManaged == true) { continue; } - if (!showAttributesUnmanaged && attribute.IsManaged == false) { continue; } - if (!showAttributesCustomizable && attribute.IsCustomizable.Value) { continue; } - if (!showAttributesUncustomizable && !attribute.IsCustomizable.Value) { continue; } - if (!showAttributesStandard && attribute.IsCustomAttribute == false) { continue; } - if (!showAttributesCustom && attribute.IsCustomAttribute == true) { continue; } - if (showAttributesOnlyValidAF && attribute.IsValidForAdvancedFind.Value == false) { continue; } - } - result.Add(attribute); - } - } + settings = new Settings(); } - return result.ToArray(); - } - internal static string GetEntityDisplayName(string entityName) - { - if (!useFriendlyNames) + fetchXml = settings.FetchXML; + if (settings.EntityAttributes != null) { - return entityName; + entityAttributes = settings.EntityAttributes.ToDictionary(i => i.key, i => i.value); } - if (entities != null && entities.ContainsKey(entityName)) + else { - entityName = GetEntityDisplayName(entities[entityName]); + entityAttributes = new Dictionary(); } - return entityName; + tsmiFriendly.Checked = settings.Friendly; + tsmiAttributesManaged.Checked = settings.AttributesManaged; + tsmiAttributesUnmanaged.Checked = settings.AttributesUnmanaged; + tsmiAttributesCustomizable.Checked = settings.AttributesCustomizable; + tsmiAttributesUncustomizable.Checked = settings.AttributesUncustomizable; + tsmiAttributesCustom.Checked = settings.AttributesCustom; + tsmiAttributesStandard.Checked = settings.AttributesStandard; + tsmiAttributesOnlyValidAF.Checked = settings.AttributesOnlyValidAF; + cmbDelBatchSize.SelectedItem = cmbDelBatchSize.Items.Cast().FirstOrDefault(i => i == settings.DeleteBatchSize.ToString()); + tsmiFriendly_Click(null, null); + tsmiAttributes_Click(null, null); } - internal static string GetEntityDisplayName(EntityMetadata entity) + private bool NeedToLoadEntity(string entityName) { - var result = entity.LogicalName; - if (useFriendlyNames) + return + !string.IsNullOrEmpty(entityName) && + !entityShitList.Contains(entityName) && + Service != null && + (entities == null || + !entities.ContainsKey(entityName) || + entities[entityName].Attributes == null); + } + + private string OpenFile() + { + var result = ""; + var ofd = new OpenFileDialog { - if (entity.DisplayName.UserLocalizedLabel != null) + Title = "Select an XML file containing FetchXML", + Filter = "XML file (*.xml)|*.xml" + }; + + if (ofd.ShowDialog() == DialogResult.OK) + { + EnableControls(false); + var fetchDoc = new XmlDocument(); + fetchDoc.Load(ofd.FileName); + + if (fetchDoc.DocumentElement.Name != "fetch" || + fetchDoc.DocumentElement.ChildNodes.Count > 0 && + fetchDoc.DocumentElement.ChildNodes[0].Name == "fetch") { - result = entity.DisplayName.UserLocalizedLabel.Label; + MessageBox.Show(this, "Invalid Xml: Definition XML root must be fetch!", "Error", + MessageBoxButtons.OK, MessageBoxIcon.Error); } - if (result == entity.LogicalName && entity.DisplayName.LocalizedLabels.Count > 0) + else { - result = entity.DisplayName.LocalizedLabels[0].Label; + result = fetchDoc.OuterXml; + EnableControls(true); } } return result; } - internal static string GetAttributeDisplayName(AttributeMetadata attribute) + private void OpenView() { - string attributeName = attribute.LogicalName; - if (useFriendlyNames) + EnableControls(false); + if (views == null || views.Count == 0) { - if (attribute.DisplayName.UserLocalizedLabel != null) - { - attributeName = attribute.DisplayName.UserLocalizedLabel.Label; - } - if (attributeName == attribute.LogicalName && attribute.DisplayName.LocalizedLabels.Count > 0) + LoadViews(OpenView); + return; + } + var viewselector = new SelectViewDialog(this); + viewselector.StartPosition = FormStartPosition.CenterParent; + if (viewselector.ShowDialog() == DialogResult.OK) + { + view = viewselector.View; + var fetchDoc = new XmlDocument(); + if (view.Contains("fetchxml")) { - attributeName = attribute.DisplayName.LocalizedLabels[0].Label; + fetchDoc.LoadXml(view["fetchxml"].ToString()); + FetchUpdated(fetchDoc.OuterXml); } - attributeName += " (" + attribute.LogicalName + ")"; } - return attributeName; + EnableControls(true); } - private bool ValuesEqual(object value1, object value2) + private void RefreshAttributes() { - if (value1 != null && value2 != null) + EnableControls(false); + cmbAttribute.Items.Clear(); + if (records != null) { - if (value1 is OptionSetValue && value2 is OptionSetValue) + var entityName = records.EntityName; + if (NeedToLoadEntity(entityName)) { - return ((OptionSetValue)value1).Value == ((OptionSetValue)value2).Value; + if (!working) + { + LoadEntityDetails(entityName, RefreshAttributes); + } + return; } - else + var attributes = GetDisplayAttributes(entityName); + foreach (var attribute in attributes) { - return value1.ToString().Equals(value2.ToString()); + AttributeItem.AddAttributeToComboBox(cmbAttribute, attribute, true); + } + if (entityAttributes.ContainsKey(records.EntityName)) + { + var attr = entityAttributes[records.EntityName]; + var coll = new Dictionary(); + coll.Add("attribute", attr); + ControlUtils.FillControl(coll, cmbAttribute); } } - else - { - return value1 == null && value2 == null; - } + crmGridView1.ShowFriendlyNames = useFriendlyNames; + crmGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); + EnableControls(true); } - private object GetValue(AttributeTypeCode? type) + private void RemoveAttribute() { - switch (type) + var items = lvAttributes.SelectedItems; + foreach (ListViewItem item in items) { - case AttributeTypeCode.String: - case AttributeTypeCode.Memo: - return cmbValue.Text; - - case AttributeTypeCode.BigInt: - case AttributeTypeCode.Integer: - return int.Parse(cmbValue.Text); - - case AttributeTypeCode.Decimal: - return decimal.Parse(cmbValue.Text); - - case AttributeTypeCode.Double: - return double.Parse(cmbValue.Text); - - case AttributeTypeCode.Picklist: - case AttributeTypeCode.State: - case AttributeTypeCode.Status: - var value = ((OptionsetItem)cmbValue.SelectedItem).meta.Value; - return new OptionSetValue((int)value); - - case AttributeTypeCode.DateTime: - return DateTime.Parse(cmbValue.Text); - - case AttributeTypeCode.Boolean: - { - // Is checking the cmbAttribute ok? I hope so... - var attr = (BooleanAttributeMetadata)((AttributeItem)cmbAttribute.SelectedItem).Metadata; - return ((OptionsetItem)cmbValue.SelectedItem).meta == attr.OptionSet.TrueOption; - } - case AttributeTypeCode.Money: - return new Money(decimal.Parse(cmbValue.Text)); - - // The following allows to specify an entity reference in the following form: - // attribute_name,attribute_guid - // eg: account,08e943f8-1ff0-41ea-89c0-5478dd465806 - // As a security check, the attribute_name MUST be in the targets - // specified by the lookup attribute metadata targets - case AttributeTypeCode.Lookup: - case AttributeTypeCode.Customer: - { - // Get the attribute metadata for the lookup type: - var attr = (LookupAttributeMetadata)((AttributeItem)cmbAttribute.SelectedItem).Metadata; - - // split the text: first part: attribute meta name, second part: attribute guid to update - var t = cmbValue.Text.Split(',', ';', '/', '\\', ':').ToArray(); - // get the first target - string attrname = (attr.Targets != null && attr.Targets.Length > 0) ? attr.Targets[0] : null; - if (attr.Targets != null && t.Length > 1) - attrname = attr.Targets.FirstOrDefault(x => t.First().Equals(x, StringComparison.OrdinalIgnoreCase)); - - if (String.IsNullOrEmpty(attrname)) - throw new Exception("Target entity: '" + t.First() + "' is null or not found"); - - return new EntityReference(attrname, new Guid(t.Last())); - } - - default: - throw new Exception("Attribute of type " + type.ToString() + " is currently not supported."); + lvAttributes.Items.Remove(item); } + EnableControls(true); } - private void UpdateValueField() + private void RetrieveRecords(string fetch, Action AfterRetrieve) { - var attribute = (AttributeItem)cmbAttribute.SelectedItem; - rbSetNull.Enabled = attribute != null && attribute.Metadata.LogicalName != "statecode" && attribute.Metadata.LogicalName != "statuscode"; - cmbValue.Items.Clear(); - if (attribute != null) + if (working) { - if (attribute.Metadata is EnumAttributeMetadata) + return; + } + lblRecords.Text = "Retrieving records..."; + records = null; + working = true; + WorkAsync(new WorkAsyncInfo("Retrieving records...", + (eventargs) => { - var options = ((EnumAttributeMetadata)attribute.Metadata).OptionSet; - if (options != null) + eventargs.Result = Service.RetrieveMultiple(new FetchExpression(fetch)); + }) + { + PostWorkCallBack = (completedargs) => + { + working = false; + if (completedargs.Error != null) { - foreach (var option in options.Options) - { - cmbValue.Items.Add(new OptionsetItem(option)); - } + MessageBox.Show(completedargs.Error.Message, "Retrieve Records", MessageBoxButtons.OK, MessageBoxIcon.Error); } - cmbValue.DropDownStyle = ComboBoxStyle.DropDownList; - } - else if (attribute.Metadata is BooleanAttributeMetadata) - { - var options = ((BooleanAttributeMetadata)attribute.Metadata).OptionSet; - if (options != null) + else if (completedargs.Result is EntityCollection) { - cmbValue.Items.Add(new OptionsetItem(options.TrueOption)); - cmbValue.Items.Add(new OptionsetItem(options.FalseOption)); + records = (EntityCollection)completedargs.Result; } - cmbValue.DropDownStyle = ComboBoxStyle.DropDownList; - } - else - { - cmbValue.DropDownStyle = ComboBoxStyle.Simple; - } - if (entityAttributes.ContainsKey(records.EntityName)) - { - entityAttributes[records.EntityName] = attribute.GetValue(); - } - else - { - entityAttributes.Add(records.EntityName, attribute.GetValue()); + AfterRetrieve(); } - } - if (attribute.Metadata.LogicalName == "statecode") - { - MessageBox.Show("You selected to update the statecode. In most cases this will probably not work.\n" + - "But if you select to update the statuscode instead, the statecode will be fixed automatically!", - "Statecode", MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - EnableControls(true); + }); } - private void AddAttribute() + private void RetrieveRecordsReady() { - if (!(GetAttributeItemFromUI() is BulkActionItem bai)) - { - return; - } - if (lvAttributes.Items - .Cast() - .Select(i => i.Tag as BulkActionItem) - .Any(i => i.Attribute.Metadata.LogicalName == bai.Attribute.Metadata.LogicalName)) + if (records != null) { - if (MessageBox.Show($"Replace already added attribute {bai.Attribute} ?", "Attribute added", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) == DialogResult.Cancel) + var entityName = records.EntityName; + if (NeedToLoadEntity(entityName)) { + if (!working) + { + LoadEntityDetails(entityName, RetrieveRecordsReady); + } return; } - var removeitem = lvAttributes.Items - .Cast() - .FirstOrDefault(i => (i.Tag as BulkActionItem).Attribute.Metadata.LogicalName == bai.Attribute.Metadata.LogicalName); - lvAttributes.Items.Remove(removeitem); + lblRecords.Text = records.Entities.Count.ToString() + " records of entity " + records.EntityName; + lblDeleteHeader.Text = $"Delete {records.Entities.Count} {entities.FirstOrDefault(e => e.Key == records.EntityName).Value.DisplayCollectionName.UserLocalizedLabel.Label}"; + crmGridView1.OrganizationService = Service; + crmGridView1.DataSource = records; + crmGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); } - var item = lvAttributes.Items.Add(bai.Attribute.ToString()); - item.Tag = bai; - item.SubItems.Add(bai.Action.ToString()); - item.SubItems.Add(bai.Action == BulkActionAction.SetValue ? bai.StringValue : string.Empty); - item.SubItems.Add(bai.DontTouch ? "Yes" : "No"); - EnableControls(true); + RefreshAttributes(); } - private void RemoveAttribute() + private void SaveSetting() { - var items = lvAttributes.SelectedItems; - foreach (ListViewItem item in items) + //var entattrstr = ""; + //foreach (var entattr in entityAttributes) + //{ + // entattrstr += entattr.Key + ":" + entattr.Value + "|"; + //} + var settings = new Settings() { - lvAttributes.Items.Remove(item); - } - EnableControls(true); - } - - internal void LogUse(string action, double? count = null, double? duration = null) - { - ai.WriteEvent(action, count, duration, HandleAIResult); + FetchXML = fetchXml, + EntityAttributes = entityAttributes.Select(p => new KeyValuePair() { key = p.Key, value = p.Value }).ToList(), + Friendly = tsmiFriendly.Checked, + AttributesManaged = tsmiAttributesManaged.Checked, + AttributesUnmanaged = tsmiAttributesUnmanaged.Checked, + AttributesCustomizable = tsmiAttributesCustomizable.Checked, + AttributesUncustomizable = tsmiAttributesUncustomizable.Checked, + AttributesCustom = tsmiAttributesCustom.Checked, + AttributesStandard = tsmiAttributesStandard.Checked, + AttributesOnlyValidAF = tsmiAttributesOnlyValidAF.Checked, + DeleteBatchSize = int.TryParse(cmbDelBatchSize.Text, out int size) ? size : 1 + }; + SettingsManager.Instance.Save(typeof(BulkDataUpdater), settings, "Settings"); } - private void HandleAIResult(string result) + private bool UpdateRecord(Entity record, List attributes) { - if (!string.IsNullOrEmpty(result)) + if (attributes.Count == 0) { - LogError("Failed to write to Application Insights:\n{0}", result); + return false; + } + var updaterecord = new Entity(record.LogicalName, record.Id); + foreach (var bai in attributes.Where(a => !(a.Attribute.Metadata is StateAttributeMetadata))) + { + var attribute = bai.Attribute.Metadata.LogicalName; + var currentvalue = record.Contains(attribute) ? record[attribute] : null; + if (bai.Action == BulkActionAction.Touch) + { + bai.Value = currentvalue; + } + if (!bai.DontTouch || !ValuesEqual(bai.Value, currentvalue)) + { + updaterecord.Attributes.Add(attribute, bai.Value); + if (record.Contains(attribute)) + { + record[attribute] = bai.Value; + } + else + { + record.Attributes.Add(attribute, bai.Value); + } + } } + Service.Update(updaterecord); + return true; } - #endregion Methods - - #region Async SDK methods - - internal void LoadViews(Action viewsLoaded) + private void UpdateRecords() { if (working) { return; } - if (entities == null || entities.Count == 0) + if (MessageBox.Show("All selected records will unconditionally be updated.\nUI defined rules will NOT be enforced.\n\nConfirm update!", + "Confirm", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk) != DialogResult.OK) { - LoadEntities(viewsLoaded); return; } + var selectedattributes = lvAttributes.Items.Cast().Select(i => i.Tag as BulkActionItem).ToList(); + var entity = records.EntityName; working = true; - WorkAsync(new WorkAsyncInfo("Loading views...", - (bgworker, workargs) => + WorkAsync(new WorkAsyncInfo() + { + Message = "Updating records", + IsCancelable = true, + AsyncArgument = selectedattributes, + Work = (bgworker, workargs) => { - EnableControls(false); - if (views == null || views.Count == 0) + var sw = Stopwatch.StartNew(); + var total = records.Entities.Count; + var current = 0; + var updated = 0; + var failed = 0; + var attributes = workargs.Argument as List; + foreach (var record in records.Entities) { - if (Service == null) + current++; + var pct = 100 * current / total; + if (!CheckAllUpdateAttributesExistOnRecord(record, attributes)) { - throw new Exception("Need a connection to load views."); + //if ((bai.DontTouch || bai.Action == BulkActionAction.Touch) && !attributesexists) + bgworker.ReportProgress(pct, "Reloading record " + current.ToString()); + LoadMissingAttributesForRecord(record, entity, attributes); } - var qex = new QueryExpression("savedquery"); - qex.ColumnSet = new ColumnSet("name", "returnedtypecode", "fetchxml"); - qex.Criteria.AddCondition("statecode", ConditionOperator.Equal, 0); - qex.Criteria.AddCondition("querytype", ConditionOperator.In, 0, 32); - qex.AddOrder("name", OrderType.Ascending); - bgworker.ReportProgress(33, "Loading system views..."); - var sysviews = Service.RetrieveMultiple(qex); - foreach (var view in sysviews.Entities) + bgworker.ReportProgress(pct, "Updating record " + current.ToString()); + try { - var entityname = view["returnedtypecode"].ToString(); - if (!string.IsNullOrWhiteSpace(entityname) && entities.ContainsKey(entityname)) + //if (UpdateState(record, attributes)) + //{ + // updated++; + //} + if (UpdateRecord(record, attributes)) { - if (views == null) - { - views = new Dictionary>(); - } - if (!views.ContainsKey(entityname + "|S")) - { - views.Add(entityname + "|S", new List()); - } - views[entityname + "|S"].Add(view); + updated++; } } - qex.EntityName = "userquery"; - bgworker.ReportProgress(66, "Loading user views..."); - var userviews = Service.RetrieveMultiple(qex); - foreach (var view in userviews.Entities) + catch (Exception ex) { - var entityname = view["returnedtypecode"].ToString(); - if (!string.IsNullOrWhiteSpace(entityname) && entities.ContainsKey(entityname)) + failed++; + if (!chkIgnoreErrors.Checked) { - if (views == null) - { - views = new Dictionary>(); - } - if (!views.ContainsKey(entityname + "|U")) - { - views.Add(entityname + "|U", new List()); - } - views[entityname + "|U"].Add(view); + throw ex; } } - bgworker.ReportProgress(100, "Finalizing..."); } - }) - { + sw.Stop(); + workargs.Result = new Tuple(updated, failed, sw.ElapsedMilliseconds); + }, PostWorkCallBack = (completedargs) => { working = false; - EnableControls(true); if (completedargs.Error != null) { - MessageBox.Show(completedargs.Error.Message); + MessageBox.Show(completedargs.Error.Message, "Update", MessageBoxButtons.OK, MessageBoxIcon.Error); } else { - viewsLoaded(); + var result = completedargs.Result as Tuple; + lblUpdateStatus.Text = $"{result.Item1} records updated, {result.Item2} records failed."; + LogUse("Updated", result.Item1, result.Item3); + if (result.Item2 > 0) + { + LogUse("Failed", result.Item2); + } } }, ProgressChanged = (changeargs) => @@ -924,471 +1108,311 @@ internal void LoadViews(Action viewsLoaded) }); } - private void LoadEntities(Action AfterLoad) + private bool UpdateState(Entity record, List attributes) { - if (working) + var attribute = attributes.FirstOrDefault(a => a.Attribute.Metadata is StateAttributeMetadata); + if (attribute == null) { - return; + return false; } - entities = null; - entityShitList = new List(); - working = true; - WorkAsync(new WorkAsyncInfo("Loading entities metadata...", - (eventargs) => + var statevalue = GetCurrentStateCodeFromStatusCode(attributes); + var statusvalue = attribute.Value as OptionSetValue; + var currentstate = record.Contains("statecode") ? record["statecode"] : new OptionSetValue(-1); + var currentstatus = record.Contains("statuscode") ? record["statuscode"] : new OptionSetValue(-1); + if (attribute.Action == BulkActionAction.Touch) + { + statevalue = (OptionSetValue)currentstate; + statusvalue = (OptionSetValue)currentstatus; + } + if (!attribute.DontTouch || !ValuesEqual(currentstate, statevalue) || !ValuesEqual(currentstatus, statusvalue)) + { + var req = new SetStateRequest() { - EnableControls(false); - var req = new RetrieveAllEntitiesRequest() - { - EntityFilters = EntityFilters.Entity, - RetrieveAsIfPublished = true - }; - eventargs.Result = Service.Execute(req); - }) + EntityMoniker = record.ToEntityReference(), + State = statevalue, + Status = statusvalue + }; + var resp = Service.Execute(req); + if (record.Contains("statecode")) + { + record["statecode"] = statevalue; + } + else + { + record.Attributes.Add("statecode", statevalue); + } + if (record.Contains("statuscode")) + { + record["statuscode"] = currentstatus; + } + else + { + record.Attributes.Add("statuscode", currentstatus); + } + return true; + } + return false; + } + + private void UpdateValueField() + { + var attribute = (AttributeItem)cmbAttribute.SelectedItem; + rbSetNull.Enabled = attribute != null && attribute.Metadata.LogicalName != "statecode" && attribute.Metadata.LogicalName != "statuscode"; + cmbValue.Items.Clear(); + if (attribute != null) { - PostWorkCallBack = (completedargs) => + if (attribute.Metadata is EnumAttributeMetadata) { - working = false; - if (completedargs.Error != null) - { - MessageBox.Show(completedargs.Error.Message); - } - else + var options = ((EnumAttributeMetadata)attribute.Metadata).OptionSet; + if (options != null) { - if (completedargs.Result is RetrieveAllEntitiesResponse) + foreach (var option in options.Options) { - entities = new Dictionary(); - foreach (var entity in ((RetrieveAllEntitiesResponse)completedargs.Result).EntityMetadata) - { - entities.Add(entity.LogicalName, entity); - } + cmbValue.Items.Add(new OptionsetItem(option)); } } - EnableControls(true); - if (AfterLoad != null) + cmbValue.DropDownStyle = ComboBoxStyle.DropDownList; + } + else if (attribute.Metadata is BooleanAttributeMetadata) + { + var options = ((BooleanAttributeMetadata)attribute.Metadata).OptionSet; + if (options != null) { - AfterLoad(); + cmbValue.Items.Add(new OptionsetItem(options.TrueOption)); + cmbValue.Items.Add(new OptionsetItem(options.FalseOption)); } + cmbValue.DropDownStyle = ComboBoxStyle.DropDownList; } - }); + else + { + cmbValue.DropDownStyle = ComboBoxStyle.Simple; + } + if (entityAttributes.ContainsKey(records.EntityName)) + { + entityAttributes[records.EntityName] = attribute.GetValue(); + } + else + { + entityAttributes.Add(records.EntityName, attribute.GetValue()); + } + } + if (attribute.Metadata.LogicalName == "statecode") + { + MessageBox.Show("You selected to update the statecode. In most cases this will probably not work.\n" + + "But if you select to update the statuscode instead, the statecode will be fixed automatically!", + "Statecode", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + EnableControls(true); } - private void LoadEntityDetails(string entityName, Action detailsLoaded) + private bool ValuesEqual(object value1, object value2) { - if (working) + if (value1 != null && value2 != null) { - return; - } - working = true; - WorkAsync(new WorkAsyncInfo("Loading " + GetEntityDisplayName(entityName) + " metadata...", - (eventargs) => + if (value1 is OptionSetValue && value2 is OptionSetValue) { - var req = new RetrieveEntityRequest() - { - LogicalName = entityName, - EntityFilters = EntityFilters.Attributes | EntityFilters.Relationships, - RetrieveAsIfPublished = true - }; - eventargs.Result = Service.Execute(req); - }) - { - PostWorkCallBack = (completedargs) => + return ((OptionSetValue)value1).Value == ((OptionSetValue)value2).Value; + } + else { - working = false; - if (completedargs.Error != null) - { - entityShitList.Add(entityName); - MessageBox.Show(completedargs.Error.Message, "Load attribute metadata", MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - else - { - if (completedargs.Result is RetrieveEntityResponse) - { - var resp = (RetrieveEntityResponse)completedargs.Result; - if (entities == null) - { - entities = new Dictionary(); - } - if (entities.ContainsKey(entityName)) - { - entities[entityName] = resp.EntityMetadata; - } - else - { - entities.Add(entityName, resp.EntityMetadata); - } - } - detailsLoaded(); - } - working = false; + return value1.ToString().Equals(value2.ToString()); } - }); + } + else + { + return value1 == null && value2 == null; + } } - private void RetrieveRecords(string fetch, Action AfterRetrieve) + #endregion Private Methods + + #region Form Event Handlers + + private void btnAdd_Click(object sender, EventArgs e) { - if (working) + AddAttribute(); + } + + private void btnDelete_Click(object sender, EventArgs e) + { + DeleteRecords(); + } + + private void btnGetRecords_Click(object sender, EventArgs e) + { + if (sender is Button btn) { - return; + GetRecords(btn.Tag?.ToString()); } - lblRecords.Text = "Retrieving records..."; - records = null; - working = true; - WorkAsync(new WorkAsyncInfo("Retrieving records...", - (eventargs) => - { - eventargs.Result = Service.RetrieveMultiple(new FetchExpression(fetch)); - }) - { - PostWorkCallBack = (completedargs) => - { - working = false; - if (completedargs.Error != null) - { - MessageBox.Show(completedargs.Error.Message, "Retrieve Records", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else if (completedargs.Result is EntityCollection) - { - records = (EntityCollection)completedargs.Result; - } - AfterRetrieve(); - } - }); } - private BulkActionItem GetAttributeItemFromUI() + private void btnRemove_Click(object sender, EventArgs e) { - if (!(cmbAttribute.SelectedItem is AttributeItem)) - { - MessageBox.Show("Select an attribute to update from the list."); - return null; - } - var bai = new BulkActionItem - { - Attribute = (AttributeItem)cmbAttribute.SelectedItem, - DontTouch = chkOnlyChange.Checked, - Action = rbSetValue.Checked ? BulkActionAction.SetValue : rbSetNull.Checked ? BulkActionAction.Null : BulkActionAction.Touch - }; - var logicalname = bai.Attribute.GetValue(); - bai.Value = null; - try - { - bai.Value = bai.Action == BulkActionAction.SetValue ? GetValue(bai.Attribute.Metadata.AttributeType) : null; - bai.StringValue = bai.Action == BulkActionAction.SetValue ? cmbValue.Text : string.Empty; - } - catch (Exception e) - { - MessageBox.Show("Value error:\n" + e.Message, "Set value", MessageBoxButtons.OK, MessageBoxIcon.Error); - return null; - } - return bai; + RemoveAttribute(); } - private void UpdateRecords() + private void btnUpdate_Click(object sender, EventArgs e) { - if (working) - { - return; - } - if (MessageBox.Show("All selected records will unconditionally be updated.\nUI defined rules will NOT be enforced.\n\nConfirm update!", - "Confirm", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk) != DialogResult.OK) + UpdateRecords(); + } + + private void cmbAttribute_SelectedIndexChanged(object sender, EventArgs e) + { + UpdateValueField(); + } + + private void cmbAttribute_TextChanged(object sender, EventArgs e) + { + EnableControls(true); + } + + private void cmbValue_SelectedIndexChanged(object sender, EventArgs e) + { + EnableControls(true); + } + + private void DataUpdater_ConnectionUpdated(object sender, XrmToolBox.Extensibility.PluginControlBase.ConnectionUpdatedEventArgs e) + { + crmGridView1.DataSource = null; + entities = null; + entityShitList.Clear(); + EnableControls(true); + } + + private void DataUpdater_Load(object sender, EventArgs e) + { + EnableControls(false); + LoadSetting(); + LogUse("Load"); + EnableControls(true); + } + + private void lvAttributes_SelectedIndexChanged(object sender, EventArgs e) + { + if (lvAttributes.SelectedItems.Count == 0) { return; } - var selectedattributes = lvAttributes.Items.Cast().Select(i => i.Tag as BulkActionItem).ToList(); - var entity = records.EntityName; - working = true; - WorkAsync(new WorkAsyncInfo() + if (lvAttributes.SelectedItems[0].Tag is BulkActionItem attribute) { - Message = "Updating records", - IsCancelable = true, - AsyncArgument = selectedattributes, - Work = (bgworker, workargs) => + cmbAttribute.Text = attribute.Attribute.ToString(); + switch (attribute.Action) { - var sw = Stopwatch.StartNew(); - var total = records.Entities.Count; - var current = 0; - var updated = 0; - var failed = 0; - var attributes = workargs.Argument as List; - foreach (var record in records.Entities) - { - current++; - var pct = 100 * current / total; - if (!CheckAllUpdateAttributesExistOnRecord(record, attributes)) - { - //if ((bai.DontTouch || bai.Action == BulkActionAction.Touch) && !attributesexists) - bgworker.ReportProgress(pct, "Reloading record " + current.ToString()); - LoadMissingAttributesForRecord(record, entity, attributes); - } - bgworker.ReportProgress(pct, "Updating record " + current.ToString()); - try - { - //if (UpdateState(record, attributes)) - //{ - // updated++; - //} - if (UpdateRecord(record, attributes)) - { - updated++; - } - } - catch (Exception ex) + case BulkActionAction.SetValue: + rbSetValue.Checked = true; + if (attribute.Value is OptionSetValue osv) { - failed++; - if (!chkIgnoreErrors.Checked) + foreach (var option in cmbValue.Items.Cast().Where(i => i is OptionsetItem).Select(i => i as OptionsetItem)) { - throw ex; + if (option.meta.Value == osv.Value) + { + cmbValue.SelectedItem = option; + break; + } } } - } - sw.Stop(); - workargs.Result = new Tuple(updated, failed, sw.ElapsedMilliseconds); - }, - PostWorkCallBack = (completedargs) => - { - working = false; - if (completedargs.Error != null) - { - MessageBox.Show(completedargs.Error.Message, "Update", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else - { - var result = completedargs.Result as Tuple; - lblUpdateStatus.Text = $"{result.Item1} records updated, {result.Item2} records failed."; - LogUse("Updated", result.Item1, result.Item3); - if (result.Item2 > 0) + else { - LogUse("Failed", result.Item2); + cmbValue.Text = attribute.Value.ToString(); } - } - }, - ProgressChanged = (changeargs) => - { - SetWorkingMessage(changeargs.UserState.ToString()); + break; + case BulkActionAction.Touch: + rbSetTouch.Checked = true; + cmbValue.Text = string.Empty; + break; + case BulkActionAction.Null: + rbSetNull.Checked = true; + cmbValue.Text = string.Empty; + break; } - }); + chkOnlyChange.Checked = attribute.DontTouch; + } } - private static bool CheckAllUpdateAttributesExistOnRecord(Entity record, List attributes) + private void rbSet_CheckedChanged(object sender, EventArgs e) { - var allattributesexist = true; - foreach (var attribute in attributes - .Where(a => a.Action == BulkActionAction.Touch || (a.Action == BulkActionAction.SetValue && a.DontTouch)) - .Select(a => a.Attribute.Metadata.LogicalName)) + cmbValue.Enabled = rbSetValue.Checked; + chkOnlyChange.Enabled = !rbSetTouch.Checked; + if (rbSetTouch.Checked) { - if (!record.Contains(attribute)) - { - allattributesexist = false; - break; - } - if (attribute == "statuscode" && !record.Contains("statecode")) - { - allattributesexist = false; - break; - } + chkOnlyChange.Checked = false; } - return allattributesexist; + EnableControls(true); } - private void LoadMissingAttributesForRecord(Entity record, string entity, IEnumerable attributes) + private void tsbCloseThisTab_Click(object sender, EventArgs e) { - var newcols = new ColumnSet(attributes.Select(a => a.Attribute.Metadata.LogicalName).ToArray()); - if (newcols.Columns.Contains("statuscode")) - { - newcols.AddColumn("statecode"); - } - var newrecord = Service.Retrieve(entity, record.Id, newcols); - foreach (var attribute in newrecord.Attributes.Keys) - { - if (newrecord.Contains(attribute) && !record.Contains(attribute)) - { - record.Attributes.Add(attribute, newrecord[attribute]); - } - } + CloseTool(); } - private static OptionSetValue GetCurrentStateCodeFromStatusCode(IEnumerable attributes) + private void tslAbout_Click(object sender, EventArgs e) { - var statusattribute = attributes.Where(a => a.Attribute.Metadata is StatusAttributeMetadata && a.Value is OptionSetValue).FirstOrDefault(); - if (statusattribute != null && - statusattribute.Attribute.Metadata is StatusAttributeMetadata statusmeta && - statusattribute.Value is OptionSetValue osv) - { - foreach (var statusoption in statusmeta.OptionSet.Options) - { - if (statusoption is StatusOptionMetadata && statusoption.Value == osv.Value) - { - return new OptionSetValue((int)((StatusOptionMetadata)statusoption).State); - } - } - } - return null; + LogUse("OpenAbout"); + var about = new About(this); + about.StartPosition = FormStartPosition.CenterParent; + about.lblVersion.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + about.ShowDialog(); } - private bool UpdateState(Entity record, List attributes) + private void tsmiAttributes_Click(object sender, EventArgs e) { - var attribute = attributes.FirstOrDefault(a => a.Attribute.Metadata is StateAttributeMetadata); - if (attribute == null) + if (sender != tsmiAttributesAll) { - return false; + tsmiAttributesAll.Checked = + tsmiAttributesManaged.Checked && + tsmiAttributesUnmanaged.Checked && + tsmiAttributesCustomizable.Checked && + tsmiAttributesUncustomizable.Checked && + tsmiAttributesCustom.Checked && + tsmiAttributesStandard.Checked && + !tsmiAttributesOnlyValidAF.Checked; } - var statevalue = GetCurrentStateCodeFromStatusCode(attributes); - var statusvalue = attribute.Value as OptionSetValue; - var currentstate = record.Contains("statecode") ? record["statecode"] : new OptionSetValue(-1); - var currentstatus = record.Contains("statuscode") ? record["statuscode"] : new OptionSetValue(-1); - if (attribute.Action == BulkActionAction.Touch) - { - statevalue = (OptionSetValue)currentstate; - statusvalue = (OptionSetValue)currentstatus; + if (!tsmiAttributesManaged.Checked && !tsmiAttributesUnmanaged.Checked) + { // Neither managed nor unmanaged is not such a good idea... + tsmiAttributesUnmanaged.Checked = true; } - if (!attribute.DontTouch || !ValuesEqual(currentstate, statevalue) || !ValuesEqual(currentstatus, statusvalue)) - { - var req = new SetStateRequest() - { - EntityMoniker = record.ToEntityReference(), - State = statevalue, - Status = statusvalue - }; - var resp = Service.Execute(req); - if (record.Contains("statecode")) - { - record["statecode"] = statevalue; - } - else - { - record.Attributes.Add("statecode", statevalue); - } - if (record.Contains("statuscode")) - { - record["statuscode"] = currentstatus; - } - else - { - record.Attributes.Add("statuscode", currentstatus); - } - return true; + if (!tsmiAttributesCustomizable.Checked && !tsmiAttributesUncustomizable.Checked) + { // Neither customizable nor uncustomizable is not such a good idea... + tsmiAttributesCustomizable.Checked = true; } - return false; + if (!tsmiAttributesCustom.Checked && !tsmiAttributesStandard.Checked) + { // Neither custom nor standard is not such a good idea... + tsmiAttributesStandard.Checked = true; + } + tsmiAttributesManaged.Enabled = !tsmiAttributesAll.Checked; + tsmiAttributesUnmanaged.Enabled = !tsmiAttributesAll.Checked; + tsmiAttributesCustomizable.Enabled = !tsmiAttributesAll.Checked; + tsmiAttributesUncustomizable.Enabled = !tsmiAttributesAll.Checked; + tsmiAttributesCustom.Enabled = !tsmiAttributesAll.Checked; + tsmiAttributesStandard.Enabled = !tsmiAttributesAll.Checked; + tsmiAttributesOnlyValidAF.Enabled = !tsmiAttributesAll.Checked; + showAttributesAll = tsmiAttributesAll.Checked; + showAttributesManaged = tsmiAttributesManaged.Checked; + showAttributesUnmanaged = tsmiAttributesUnmanaged.Checked; + showAttributesCustomizable = tsmiAttributesCustomizable.Checked; + showAttributesUncustomizable = tsmiAttributesUncustomizable.Checked; + showAttributesCustom = tsmiAttributesCustom.Checked; + showAttributesStandard = tsmiAttributesStandard.Checked; + showAttributesOnlyValidAF = tsmiAttributesOnlyValidAF.Checked; + RefreshAttributes(); } - private bool UpdateRecord(Entity record, List attributes) + private void tsmiFriendly_Click(object sender, EventArgs e) { - if (attributes.Count == 0) - { - return false; - } - var updaterecord = new Entity(record.LogicalName, record.Id); - foreach (var bai in attributes.Where(a => !(a.Attribute.Metadata is StateAttributeMetadata))) - { - var attribute = bai.Attribute.Metadata.LogicalName; - var currentvalue = record.Contains(attribute) ? record[attribute] : null; - if (bai.Action == BulkActionAction.Touch) - { - bai.Value = currentvalue; - } - if (!bai.DontTouch || !ValuesEqual(bai.Value, currentvalue)) - { - updaterecord.Attributes.Add(attribute, bai.Value); - if (record.Contains(attribute)) - { - record[attribute] = bai.Value; - } - else - { - record.Attributes.Add(attribute, bai.Value); - } - } - } - Service.Update(updaterecord); - return true; + useFriendlyNames = tsmiFriendly.Checked; + RefreshAttributes(); } - #endregion Async SDK methods - - private void btnDelete_Click(object sender, EventArgs e) + private void tsmiOpenFile_Click(object sender, EventArgs e) { - DeleteRecords(); + OpenFile(); } - private void DeleteRecords() + private void tsmiOpenView_Click(object sender, EventArgs e) { - if (working) - { - return; - } - if (MessageBox.Show("All selected records will unconditionally be deleted.\nUI defined rules will NOT be enforced.\nPlugins and workflows WILL trigger.\n\nConfirm delete!", - "Confirm", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk) != DialogResult.OK) - { - return; - } - working = true; - if (!int.TryParse(cmbDelBatchSize.Text, out int batchsize)) - { - batchsize = 1; - } - WorkAsync(new WorkAsyncInfo() - { - Message = "Deleting records", - IsCancelable = true, - Work = (bgworker, workargs) => - { - var sw = Stopwatch.StartNew(); - var total = records.Entities.Count; - var current = 0; - var deleted = 0; - var failed = 0; - foreach (var record in records.Entities) - { - current++; - var pct = 100 * current / total; - bgworker.ReportProgress(pct, "Deleting record " + current.ToString()); - try - { - if (batchsize == 1) - { - Service.Delete(record.LogicalName, record.Id); - deleted++; - } - else - { - MessageBox.Show("Not implemented yet, try batch size = 1"); - return; - } - } - catch (Exception ex) - { - failed++; - if (!chkIgnoreErrors.Checked) - { - throw ex; - } - } - } - sw.Stop(); - workargs.Result = new Tuple(deleted, failed, sw.ElapsedMilliseconds); - }, - PostWorkCallBack = (completedargs) => - { - working = false; - if (completedargs.Error != null) - { - MessageBox.Show(completedargs.Error.Message, "Delete", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else if (completedargs.Result is Tuple result) - { - lblDelStatus.Text = $"{result.Item1} records deleted, {result.Item2} records failed."; - LogUse("Deleted", result.Item1, result.Item3); - if (result.Item2 > 0) - { - LogUse("Failed", result.Item2); - } - } - }, - ProgressChanged = (changeargs) => - { - SetWorkingMessage(changeargs.UserState.ToString()); - } - }); + OpenView(); } + + #endregion Form Event Handlers } -} +} \ No newline at end of file From d61b0d56f76308da2ae82af513775e5c34031ee8 Mon Sep 17 00:00:00 2001 From: Jonas Rapp Date: Tue, 16 Oct 2018 23:47:54 +0200 Subject: [PATCH 5/7] Closed #21 Bulk Delete records Adding ExecuteMultiple support for deletes Closed #22 Possibility to cancel operations --- BulkDataUpdater/MainControl.Designer.cs | 38 ++- BulkDataUpdater/MainControl.cs | 78 ++++- BulkDataUpdater/MainControl.resx | 426 +++++++++++++----------- 3 files changed, 319 insertions(+), 223 deletions(-) diff --git a/BulkDataUpdater/MainControl.Designer.cs b/BulkDataUpdater/MainControl.Designer.cs index 7757848..4df596c 100644 --- a/BulkDataUpdater/MainControl.Designer.cs +++ b/BulkDataUpdater/MainControl.Designer.cs @@ -30,7 +30,7 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BulkDataUpdater)); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); this.imageList1 = new System.Windows.Forms.ImageList(this.components); this.toolStripMain = new System.Windows.Forms.ToolStrip(); this.tsbCloseThisTab = new System.Windows.Forms.ToolStripButton(); @@ -87,6 +87,7 @@ private void InitializeComponent() this.tabSetState = new System.Windows.Forms.TabPage(); this.label1 = new System.Windows.Forms.Label(); this.tabDelete = new System.Windows.Forms.TabPage(); + this.lblDelStatus = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); this.chkDelIgnoreErrors = new System.Windows.Forms.CheckBox(); this.btnDelete = new System.Windows.Forms.Button(); @@ -94,7 +95,7 @@ private void InitializeComponent() this.label2 = new System.Windows.Forms.Label(); this.textBox1 = new System.Windows.Forms.TextBox(); this.lblDeleteHeader = new System.Windows.Forms.Label(); - this.lblDelStatus = new System.Windows.Forms.Label(); + this.tsbCancel = new System.Windows.Forms.ToolStripButton(); this.toolStripMain.SuspendLayout(); this.gb1select.SuspendLayout(); this.gb2attribute.SuspendLayout(); @@ -126,7 +127,8 @@ private void InitializeComponent() this.tsbCloseThisTab, this.toolStripSeparator4, this.tsbOptions, - this.tslAbout}); + this.tslAbout, + this.tsbCancel}); this.toolStripMain.Location = new System.Drawing.Point(0, 0); this.toolStripMain.Name = "toolStripMain"; this.toolStripMain.Size = new System.Drawing.Size(909, 31); @@ -572,8 +574,8 @@ private void InitializeComponent() this.crmGridView1.AllowUserToDeleteRows = false; this.crmGridView1.AllowUserToOrderColumns = true; this.crmGridView1.AllowUserToResizeRows = false; - dataGridViewCellStyle2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); - this.crmGridView1.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle2; + dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); + this.crmGridView1.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle1; this.crmGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.crmGridView1.Dock = System.Windows.Forms.DockStyle.Fill; this.crmGridView1.FilterColumns = ""; @@ -735,6 +737,16 @@ private void InitializeComponent() this.tabDelete.Text = "Delete"; this.tabDelete.UseVisualStyleBackColor = true; // + // lblDelStatus + // + this.lblDelStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.lblDelStatus.AutoSize = true; + this.lblDelStatus.Location = new System.Drawing.Point(19, 480); + this.lblDelStatus.Name = "lblDelStatus"; + this.lblDelStatus.Size = new System.Drawing.Size(82, 13); + this.lblDelStatus.TabIndex = 37; + this.lblDelStatus.Text = "Nothing deleted"; + // // label3 // this.label3.AutoSize = true; @@ -825,14 +837,15 @@ private void InitializeComponent() this.lblDeleteHeader.TabIndex = 0; this.lblDeleteHeader.Text = "Delete [nn] [collection]"; // - // lblDelStatus + // tsbCancel // - this.lblDelStatus.AutoSize = true; - this.lblDelStatus.Location = new System.Drawing.Point(19, 480); - this.lblDelStatus.Name = "lblDelStatus"; - this.lblDelStatus.Size = new System.Drawing.Size(82, 13); - this.lblDelStatus.TabIndex = 37; - this.lblDelStatus.Text = "Nothing deleted"; + this.tsbCancel.Enabled = false; + this.tsbCancel.Image = ((System.Drawing.Image)(resources.GetObject("tsbCancel.Image"))); + this.tsbCancel.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsbCancel.Name = "tsbCancel"; + this.tsbCancel.Size = new System.Drawing.Size(71, 28); + this.tsbCancel.Text = "Cancel"; + this.tsbCancel.Click += new System.EventHandler(this.tsbCancel_Click); // // BulkDataUpdater // @@ -940,5 +953,6 @@ private void InitializeComponent() private System.Windows.Forms.Label label3; private System.Windows.Forms.CheckBox chkDelIgnoreErrors; private System.Windows.Forms.Label lblDelStatus; + private System.Windows.Forms.ToolStripButton tsbCancel; } } diff --git a/BulkDataUpdater/MainControl.cs b/BulkDataUpdater/MainControl.cs index ff6f28d..7614aeb 100644 --- a/BulkDataUpdater/MainControl.cs +++ b/BulkDataUpdater/MainControl.cs @@ -352,12 +352,19 @@ private void DeleteRecords() { return; } - if (MessageBox.Show("All selected records will unconditionally be deleted.\nUI defined rules will NOT be enforced.\nPlugins and workflows WILL trigger.\n\nConfirm delete!", + if (MessageBox.Show("All selected records will unconditionally be deleted.\n" + + "UI defined rules will NOT be enforced.\n" + + "Plugins and workflows WILL trigger.\n" + + "User privileges WILL be respected.\n\n" + + "Confirm delete!", "Confirm", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk) != DialogResult.OK) { return; } + tsbCancel.Enabled = true; + btnDelete.Enabled = false; working = true; + var ignoreerrors = chkDelIgnoreErrors.Checked; if (!int.TryParse(cmbDelBatchSize.Text, out int batchsize)) { batchsize = 1; @@ -373,28 +380,44 @@ private void DeleteRecords() var current = 0; var deleted = 0; var failed = 0; + var batch = new ExecuteMultipleRequest + { + Settings = new ExecuteMultipleSettings { ContinueOnError = ignoreerrors }, + Requests = new OrganizationRequestCollection() + }; foreach (var record in records.Entities) { + if (bgworker.CancellationPending) + { + workargs.Cancel = true; + break; + } current++; var pct = 100 * current / total; - bgworker.ReportProgress(pct, "Deleting record " + current.ToString()); try { if (batchsize == 1) { + bgworker.ReportProgress(pct, $"Deleting record {current} of {total}"); Service.Delete(record.LogicalName, record.Id); deleted++; } else { - MessageBox.Show("Not implemented yet, try batch size = 1"); - return; + batch.Requests.Add(new DeleteRequest { Target = record.ToEntityReference() }); + if (batch.Requests.Count == batchsize || current == total) + { + bgworker.ReportProgress(pct, $"Deleting records {current - batch.Requests.Count + 1}-{current} of {total}"); + Service.Execute(batch); + deleted += batch.Requests.Count; + batch.Requests.Clear(); + } } } catch (Exception ex) { failed++; - if (!chkIgnoreErrors.Checked) + if (!ignoreerrors) { throw ex; } @@ -406,10 +429,18 @@ private void DeleteRecords() PostWorkCallBack = (completedargs) => { working = false; + tsbCancel.Enabled = false; if (completedargs.Error != null) { MessageBox.Show(completedargs.Error.Message, "Delete", MessageBoxButtons.OK, MessageBoxIcon.Error); } + else if (completedargs.Cancelled) + { + if (MessageBox.Show("Operation cancelled!\nRun query to get records again, to verify remaining records.", "Cancel", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) + { + RetrieveRecords(fetchXml, RetrieveRecordsReady); + } + } else if (completedargs.Result is Tuple result) { lblDelStatus.Text = $"{result.Item1} records deleted, {result.Item2} records failed."; @@ -418,7 +449,12 @@ private void DeleteRecords() { LogUse("Failed", result.Item2); } + if (MessageBox.Show("Delete completed!\nRun query to get records again?", "Bulk Data Updater", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes) + { + RetrieveRecords(fetchXml, RetrieveRecordsReady); + } } + btnDelete.Enabled = true; }, ProgressChanged = (changeargs) => { @@ -1033,6 +1069,8 @@ private void UpdateRecords() { return; } + tsbCancel.Enabled = true; + btnUpdate.Enabled = false; var selectedattributes = lvAttributes.Items.Cast().Select(i => i.Tag as BulkActionItem).ToList(); var entity = records.EntityName; working = true; @@ -1051,6 +1089,11 @@ private void UpdateRecords() var attributes = workargs.Argument as List; foreach (var record in records.Entities) { + if (bgworker.CancellationPending) + { + workargs.Cancel = true; + break; + } current++; var pct = 100 * current / total; if (!CheckAllUpdateAttributesExistOnRecord(record, attributes)) @@ -1062,10 +1105,6 @@ private void UpdateRecords() bgworker.ReportProgress(pct, "Updating record " + current.ToString()); try { - //if (UpdateState(record, attributes)) - //{ - // updated++; - //} if (UpdateRecord(record, attributes)) { updated++; @@ -1086,20 +1125,32 @@ private void UpdateRecords() PostWorkCallBack = (completedargs) => { working = false; + tsbCancel.Enabled = false; if (completedargs.Error != null) { MessageBox.Show(completedargs.Error.Message, "Update", MessageBoxButtons.OK, MessageBoxIcon.Error); } - else + else if (completedargs.Cancelled) + { + if (MessageBox.Show("Operation cancelled!\nRun query to get records again, to verify updated values.", "Cancel", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) + { + RetrieveRecords(fetchXml, RetrieveRecordsReady); + } + } + else if (completedargs.Result is Tuple result) { - var result = completedargs.Result as Tuple; lblUpdateStatus.Text = $"{result.Item1} records updated, {result.Item2} records failed."; LogUse("Updated", result.Item1, result.Item3); if (result.Item2 > 0) { LogUse("Failed", result.Item2); } + if (MessageBox.Show("Update completed!\nRun query to show updated records?", "Bulk Data Updater", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes) + { + RetrieveRecords(fetchXml, RetrieveRecordsReady); + } } + btnUpdate.Enabled = true; }, ProgressChanged = (changeargs) => { @@ -1340,6 +1391,11 @@ private void rbSet_CheckedChanged(object sender, EventArgs e) EnableControls(true); } + private void tsbCancel_Click(object sender, EventArgs e) + { + CancelWorker(); + } + private void tsbCloseThisTab_Click(object sender, EventArgs e) { CloseTool(); diff --git a/BulkDataUpdater/MainControl.resx b/BulkDataUpdater/MainControl.resx index ed590f2..e1abad1 100644 --- a/BulkDataUpdater/MainControl.resx +++ b/BulkDataUpdater/MainControl.resx @@ -124,181 +124,181 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACy - KAAAAk1TRnQBSQFMAwECAAEDAQABAwFQAQABUAEABP8BIQEACP8BQgFNATYHAAE2AwABKAMAAUABAQIA - AVADAAEBAQABIAYAAZABAf8A/wD/AP8A/wC2AANGAYADOQFg/wD/AP8A/wD4AANLAY8DAAH/A1gB7wM5 - AWD/AP8A/wD/APAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wDoAANAAXADAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wDgAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wM5AWD/AP8A/wD/ANgAA0sBjwMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNY - Ae8DOQFg/wD/AP8A/wDQAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DKgFA/wD/AP8A/wDIAANAAXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AMAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DOQFg/wD/AP8A/wC4AANL - AY8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wNYAe8DOQFg/wD/AP8A/wCwAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A - /wD/AKgAA0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wCgAANGAYADAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DOQFg/wD/AP8A/wCYAANLAY8DAAH/AwAB/wMA + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAC0 + KAAAAk1TRnQBSQFMAwEBAAEIAQMBCAEDAVABAAFQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAEB + AgABUAMAAQEBAAEgBgABkAEB/wD/AP8A/wD/ALYAA0YBgAM5AWD/AP8A/wD/APgAA0sBjwMAAf8DWAHv + AzkBYP8A/wD/AP8A8AADRgGAAwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AOgAA0ABcAMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AOAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AzkBYP8A/wD/AP8A2AADSwGPAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + A1gB7wM5AWD/AP8A/wD/ANAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMqAUD/AP8A/wD/AMgAA0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AyoBQP8A/wD/AP8AwAADRgGAAwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A/wD/ALgA + A0sBjwMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/A1gB7wM5AWD/AP8A/wD/ALAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AyoBQP8A + /wD/AP8AqAADQAFwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AKAAA0YBgAMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1gB7wM5AWD/AP8A/wD/AJAAA0YBgAMAAf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A/wD/AJgAA0sBjwMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wCIAANA - AXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHvAzkBYP8A/wD/AP8AkAADRgGAAwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DKgFA/wD/AP8A/wCAAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AIgA + A0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A/wD/AHgAA0sBjwMAAf8DAAH/AwAB/wMA + AwAB/wMqAUD/AP8A/wD/AIAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNY - Ae8DOQFg/wD/AP8A/wBwAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wBoAANA - AXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AGAAA0YEgAH/A4AB/wOA - Af8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOA - Af8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOA - Af8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/AzkBYP8A/wD/AP8AWAADSwGPAwCh/wNYAe8DOQFg - /wD/AP8A/wBQAANGAYADAAH/AwCh/wMAAf8DAAH/AyoBQP8A/wD/AP8ASAADQAFwAwAB/wMAAf8DAKH/ - AwAB/wMAAf8DAAH/AyoBQP8A/wD/AP8AQAADRgGAAwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMA - Af8DOQFg/wD/AP8A/wA4AANLAY8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DWAHv - AzkBYP8A/wD/AP8AMAADRgGAAwAB/wMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AyoBQP8A/wD/AP8AKAADQAFwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wAgAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AzkBYP8A/wD/AP8AGAADSwGP - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DWAHvAzkBYP8A/wD/AP8AEAADRgGAAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A - /wAIAANAAXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wO/Af8DvwH/ - A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/ - A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wADRgGAAwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DOQFg/wD/AP8A9wADSwGPAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/A1gB7wM5AWD/AP8A/wDvAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A5wADQAFwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A3wADRgGAAwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A - /wDXAANLAY8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wNYAe8DOQFg/wD/AP8AzwADRgGAAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AzkBYP8A/wD/AP8AeAADSwGPAwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DKgFA - /wD/AP8AxwADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBz/8A/wD/AMsAAyoBQANXAd8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DWAHAAxcBIP8A/wD/AM8AAyEBMAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBzwMXASD/AP8A/wDeAAH/AwAB/wMA + A1gB7wM5AWD/AP8A/wD/AHAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AGgA + A0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AyoBQP8A/wD/AP8AYAADRgSAAf8DgAH/ + A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/ + A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/ + A4AB/wOAAf8DgAH/A4AB/wOAAf8DgAH/A4AB/wOAAf8DOQFg/wD/AP8A/wBYAANLAY8DAKH/A1gB7wM5 + AWD/AP8A/wD/AFAAA0YBgAMAAf8DAKH/AwAB/wMAAf8DKgFA/wD/AP8A/wBIAANAAXADAAH/AwAB/wMA + of8DAAH/AwAB/wMAAf8DKgFA/wD/AP8A/wBAAANGAYADAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/ + AwAB/wM5AWD/AP8A/wD/ADgAA0sBjwMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wNY + Ae8DOQFg/wD/AP8A/wAwAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DKgFA/wD/AP8A/wAoAANAAXADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/ACAAA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DOQFg/wD/AP8A/wAYAANL + AY8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wNYAe8DOQFg/wD/AP8A/wAQAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A + /wD/AAgAA0ABcAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/A78B/wO/ + Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/ + Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DvwH/A78B/wO/Af8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wD/AANGAYADAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wM5AWD/AP8A/wD3AANLAY8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DWAHvAzkBYP8A/wD/AO8AA0YBgAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wDnAANAAXADAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMqAUD/AP8A/wDfAANGAYADAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH//wD/AP8A - 4wADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AzkBYP8A + /wD/ANcAA0sBjwMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/A1gB7wM5AWD/AP8A/wDPAANGAYADAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMq + AUD/AP8A/wDHAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHP/wD/AP8AywADKgFAA1cB3wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZ - Ac//AP8A/wDrAAMqAUADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNY - AcADFwEg/wD/AP8A7wADIQEwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wNYAcADFwEg/wD/AP8AzwADIQEwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBzwMX - ASD/AP8A/wD+AAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHPAxcBIP8A/wD/AN4AAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8ABAADIQEwA1cB3wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf//AP8A + /wDjAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMALf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + A1kBz/8A/wD/AOsAAyoBQANXAd8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + A1gBwAMXASD/AP8A/wDvAAMhATADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAC3/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHP + AxcBIP8A/wD/AP4AAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DWQHP/wD/AP8A/wAMAAMqAUADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1gBwAMXASD/AP8A - /wD/ABAAAyEBMAMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/A1kBzwMXASD/AP8A/wD/AB8AAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAKH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf//AP8A/wD/ACQAAyEBMANXAd8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHP/wD/AP8A/wAsAAMq - AUADVwHfAwAB/wMAAf8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wNYAcADFwEg/wD/AP8A - /wAwAAMhATADAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DWQHPAxcBIP8A/wD/AP8A - PwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf//AP8A/wD/AEQAAyEBMANXAd8DAAH/AwCh/wMA - Af8DAAH/A1kBz/8A/wD/AP8ATAADKgFAA1cB3wMAof8DAAH/A1gBwAMXASD/AP8A/wD/AFAAAyEBMAMA - of8DWQHPAxcBIP8A/wD/AP8AXwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A - /wD/AP8AZAADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH//wD/AP8A/wAEAAMhATADVwHf + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAt/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/AGwAAyoBQANX - Ad8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/A1gBwAMXASD/AP8A/wD/AHAAAyEBMAMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc8DFwEg - /wD/AP8A/wB/AAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/AAwAAyoBQANXAd8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A + /wD/AP8AEAADIQEwAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHPAxcBIP8A/wD/AP8AHwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAof8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8AJAADIQEwA1cB3wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/ACwA + AyoBQANXAd8DAAH/AwAB/wMAAf8DAAH/AwCh/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1gBwAMXASD/AP8A + /wD/ADAAAyEBMAMAAf8DAAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB/wNZAc8DFwEg/wD/AP8A + /wA/AAH/AwAB/wMAAf8DAKH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8ARAADIQEwA1cB3wMAAf8DAKH/ + AwAB/wMAAf8DWQHP/wD/AP8A/wBMAAMqAUADVwHfAwCh/wMAAf8DWAHAAxcBIP8A/wD/AP8AUAADIQEw + AwCh/wNZAc8DFwEg/wD/AP8A/wBfAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8AhAADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + /wD/AP8A/wBkAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWQHP/wD/AP8A/wCMAAMqAUADVwHfAwAB/wMAAf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBz/8A/wD/AP8AbAADKgFA + A1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8AkAADIQEwAwAB/wMA + AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8AcAADIQEwAwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBzwMX + ASD/AP8A/wD/AH8AAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc8DFwEg/wD/AP8A/wCfAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH//wD/AP8A/wCEAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/AIwAAyoBQANXAd8DAAH/AwAB/wMA Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf//AP8A/wD/AKQAAyEBMANXAd8DAAH/AwAB/wMAAf8DAAH/ + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNYAcADFwEg/wD/AP8A/wCQAAMhATADAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wNZAc//AP8A/wD/AKwAAyoBQANXAd8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8AsAADIQEw + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBzwMXASD/AP8A/wD/AJ8AAf8DAAH/ AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DWQHPAxcBIP8A/wD/AP8AvwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8AxAADIQEwA1cB3wMAAf8DAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc//AP8A/wD/AMwAAyoBQANXAd8DAAH/ - AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1gBwAMXASD/AP8A/wD/ANAAAyEBMAMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNZAc8DFwEg/wD/AP8A/wDfAAH/AwAB/wMA - Af8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8A5AADIQEwA1cB3wMAAf8DAAH/AwAB/wMAAf8DWQHP - /wD/AP8A/wDsAAMqAUADVwHfAwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8A8AADIQEwAwAB/wNZAc8DFwEg - /wD/AP8A/wD/AP8A/wD/AP8AXQABQgFNAT4HAAE+AwABKAMAAUABAQIAAVADAAEBAQABAQUAAYABDBYA - A/8BAAr/HgAF/wE/BP8eAAT/Af4BHwT/HgAE/wH8AQ8E/x4ABP8B+AEHBP8eAAT/AfABAwT/HgAE/wHg - AQEE/x4ABP8BwAEABP8eAAT/AYABAAF/A/8eAAT/AgABPwP/HgAD/wH+AgABHwP/HgAD/wH8AgABDwP/ - HgAD/wH4AgABBwP/HgAD/wHwAgABAwP/HgAD/wHgAgABAQP/HgAD/wHAAwAD/x4AA/8BgAMAAX8C/x4A - A/8EAAE/Av8eAAL/Af4EAAEfAv8eAAL/AfwEAAEPAv8eAAL/AfgEAAEHAv8eAAL/AfAEAAEDAv8eAAL/ - AeAEAAEBAv8eAAL/AcAFAAL/HgAC/wGABQABfwH/HgAC/wYAAT8B/x4AAf8B/gYAAR8B/x4AAf8B/AYA - AQ8B/x4AAf8B+AYAAQcB/x4AAf8B8AYAAQMB/x4AAf8B4AYAAQEB/x4AAf8BwAcAAf8eAAH/AYAHAAF/ - HgAB/wgAAT8eAAH+CAABHx4AAfwIAAEPHgAB+AgAAQceAAHwCAABAx4AAeAIAAEBHgABwCcAAYAnAAHA - JwAB4AgAAQEeAAH4CAABBx4AAfgIAAEPHgAB/AgAAQ8eAAH+CAABHx4AAf8BgAcAAX8eAAH/AYAHAAH/ - HgAB/wHABwAB/x4AAf8B4AYAAQEB/x4AAf8B+AYAAQcB/x4AAf8B+AYAAQ8B/x4AAf8B/AYAAQ8B/x4A - Af8B/gYAAR8B/x4AAv8BgAUAAX8B/x4AAv8BgAUAAv8eAAL/AcAFAAL/HgAC/wHgBAABAQL/HgAC/wH4 - BAABBwL/HgAC/wH4BAABDwL/HgAC/wH8BAABDwL/HgAC/wH+BAABHwL/HgAD/wGAAwABfwL/HgAD/wGA - AwAD/x4AA/8BwAMAA/8eAAP/AeACAAEBA/8eAAP/AfgCAAEHA/8eAAP/AfgCAAEPA/8eAAP/AfwCAAEP - A/8eAAP/Af4CAAEfA/8eAAT/AYABAAF/A/8eAAT/AYABAAT/HgAE/wHAAQAE/x4ABP8B4AEBBP8eAAT/ - AfgBBwT/HgAE/wH4AQ8E/x4ABP8B/AEPBP8eAAT/Af4BHwT/HgAK/x4ACw== + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB//8A/wD/AP8ApAADIQEwA1cB3wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/A1kBz/8A/wD/AP8ArAADKgFAA1cB3wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wNYAcADFwEg/wD/AP8A/wCwAAMh + ATADAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wNZAc8DFwEg/wD/AP8A/wC/AAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH//wD/AP8A/wDEAAMhATADVwHfAwAB/wMAAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBz/8A/wD/AP8AzAADKgFAA1cB3wMA + Af8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DWAHAAxcBIP8A/wD/AP8A0AADIQEw + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/A1kBzwMXASD/AP8A/wD/AN8AAf8DAAH/ + AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH//wD/AP8A/wDkAAMhATADVwHfAwAB/wMAAf8DAAH/AwAB/wNZ + Ac//AP8A/wD/AOwAAyoBQANXAd8DAAH/AwAB/wNYAcADFwEg/wD/AP8A/wDwAAMhATADAAH/A1kBzwMX + ASD/AP8A/wD/AP8A/wD/AP8A/wBdAAFCAU0BPgcAAT4DAAEoAwABQAEBAgABUAMAAQEBAAEBBQABgAEM + FgAD/wEACv8eAAX/AT8E/x4ABP8B/gEfBP8eAAT/AfwBDwT/HgAE/wH4AQcE/x4ABP8B8AEDBP8eAAT/ + AeABAQT/HgAE/wHAAQAE/x4ABP8BgAEAAX8D/x4ABP8CAAE/A/8eAAP/Af4CAAEfA/8eAAP/AfwCAAEP + A/8eAAP/AfgCAAEHA/8eAAP/AfACAAEDA/8eAAP/AeACAAEBA/8eAAP/AcADAAP/HgAD/wGAAwABfwL/ + HgAD/wQAAT8C/x4AAv8B/gQAAR8C/x4AAv8B/AQAAQ8C/x4AAv8B+AQAAQcC/x4AAv8B8AQAAQMC/x4A + Av8B4AQAAQEC/x4AAv8BwAUAAv8eAAL/AYAFAAF/Af8eAAL/BgABPwH/HgAB/wH+BgABHwH/HgAB/wH8 + BgABDwH/HgAB/wH4BgABBwH/HgAB/wHwBgABAwH/HgAB/wHgBgABAQH/HgAB/wHABwAB/x4AAf8BgAcA + AX8eAAH/CAABPx4AAf4IAAEfHgAB/AgAAQ8eAAH4CAABBx4AAfAIAAEDHgAB4AgAAQEeAAHAJwABgCcA + AcAnAAHgCAABAR4AAfgIAAEHHgAB+AgAAQ8eAAH8CAABDx4AAf4IAAEfHgAB/wGABwABfx4AAf8BgAcA + Af8eAAH/AcAHAAH/HgAB/wHgBgABAQH/HgAB/wH4BgABBwH/HgAB/wH4BgABDwH/HgAB/wH8BgABDwH/ + HgAB/wH+BgABHwH/HgAC/wGABQABfwH/HgAC/wGABQAC/x4AAv8BwAUAAv8eAAL/AeAEAAEBAv8eAAL/ + AfgEAAEHAv8eAAL/AfgEAAEPAv8eAAL/AfwEAAEPAv8eAAL/Af4EAAEfAv8eAAP/AYADAAF/Av8eAAP/ + AYADAAP/HgAD/wHAAwAD/x4AA/8B4AIAAQED/x4AA/8B+AIAAQcD/x4AA/8B+AIAAQ8D/x4AA/8B/AIA + AQ8D/x4AA/8B/gIAAR8D/x4ABP8BgAEAAX8D/x4ABP8BgAEABP8eAAT/AcABAAT/HgAE/wHgAQEE/x4A + BP8B+AEHBP8eAAT/AfgBDwT/HgAE/wH8AQ8E/x4ABP8B/gEfBP8eAAr/HgAL @@ -308,63 +308,63 @@ iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAWPSURBVEhLdVYJUFVlGP2u7yHCgwcKiMBjEVAEgQQXkMAF - FBBQ4YFpmkqkBbgNiTaametU44yNOTVl5ZLVtGi2TC4tLtWQo4xOaS7kWI4pNi2o4PjoPe7p/PcJ4gDf - zBnm3fvf85//fMuP9BT1IpnfiryeJhLMn73dT7vGVyKhn4scf0ektkTExkdqrWa87C5+FZl2SuT86aQo - vSFtMLaKbObjaMLDWNAp9otYvxA59VduNC4l+OOgSbv1vsiOlSKj+NqLeHAjks+vjwvXsb0G2FYNbCzD - UQ9Tc7xIBV/3Jzo+OCJiJvn+a+NjgPJEoDQKsNtwJdUfH4g0cclwwmIsbo+TIsdcWyuBLfNIPgNYa8c/ - 9lRsETnI13TLUGXENyLbGkaGA08NB8pi0TbFhtv5Ifg+1oJlxuFkERFmLG6PQyIr/ihOAzbPAdaVAauL - iUL8EGrVi0VWc0kkYTousuFkfLCORQ8Djw4BSqLgKAjDmYwAMBeNTMJOrlOnVvm7H+tEhp4M9nNhSzmw - xg48OxlYOQn/VWXiPZErISLFn4isqhsYqKNmHDA7Cfq0WLimRqIxbwD2+Jj1YSK7SbWWSCU8FW/n8OTZ - DjuWk1htsKIQeCYfqM3BtewYvC1y8VhkgI7abKBimKFeL41Bc2EYjsT4KGtogrxGFBJ9iS7VpG0XmXch - jYlbX+ImfzoHWEy1S7Lw+9hYYBl/z6PvsxKA6YPROjUcP2UEqs2v0ppd5HiSiCBMirBLjBUJZF1fx3M8 - xbJcEpN8cRZQPRpYkAHMHwk8xqqZGY82ezSu5oVgXx+Ta5AI7ZfnCbrU1ZrOYeYpNvw2Lg5YPhFYRPIq - kiviilRgThLVx9P7QWgqsuFgqDdmiezld68QeYQf0XOjqbCzsT7TpAlL6XX1PdWKfG4ylSdApzWOKRE4 - keSPF9j0ZNvBz+YQqiy7t6Y9VAN9xII64G9xOhfSnkqWbTu58n1GnFE5TnpfF+oFGs5+M6xJJHocKUZ8 - J5K8T+TE+XQmeSUTrDyvSHHbQuWKHGUx0IsjoU9hk0214WiYl76GFrFlk0nRvfdnuTPra+1h3z6OlifY - PMoaZUv5Q0zoUCOhRkN1kNugF4bCNSkEKOiP+igvbGJ5J7lr/8EZxLP14kSsbxgdzaohcRUtUcSzVaVQ - 9UwS03PdPpCKI4DJNrSR3DlpAFpzg9A6IQjOvABcjLeowXihVKSItL5Exybakd7mW6jJBB4n8axOipUl - 9NtBO1QzqXnTxpHgzHeTOyYE4m5OP9wZ5w/HeD80jrBgp1lrXijCnpNAwki4pnzX2fYGKdUqUkxjHjhj - 7haF41xWEHZomn45pS/0IpLnPUjeMsaK5iwf3M70wS+Jnqh1D8cJhFW+FKnc52FuaZ1O1Y+QmKQoiaTa - cLRQ9an0AOzWtNspIu++KHLmcoofXLmBcHQib8nyRVOGBddGeWNPv15Iv1+2QfKhyI+uskEkp2KWnk6P - nfT4Jju0jnX+lsifvKZUl24KEKnm7fNzQ5IPHNl90TLWStW++He0BTfSvPF1pBmrRE7T/De4voDwU5Np - 6YU4K8npbUEI7nCmX83pjwM2LyjFVvd84aCVHCJiCKfJS7zFzsV7U70vrpP8bLInDtnMqukus1yVmBoi - ljBLPu/RjzVpvJkdhBsTg3A80YpdnibnXJFPmSF1VJUwnlr8CZU0S4xIBjc5URflQUtMWM/LsIrXM8k5 - ZYQ3powkOi4njwUipa+KXNqmaX8v4WXFua+IXya4jyQQ6uprLzv115szIZ0y944QefOeJeqU6pJRveBD - 3C9TQg2oMcRSgo0plUQWEUp01/7qG6VwKMHRpYwwhKgbrA/RQd4evQi1azih/oMYQHgT6nlPoUjUaOhH - qMYy33vWKUT+Bw8nz3qDL0hVAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAWPSURBVEhLdVYLTJVlGH5/z0GEAwcUUIHDRUARBBK8gASK + oICACgdM07xEWoCiI9GmmXldNTebuVpZqWWXlaldlmkXsVzm0NFK80LOcqbYuqCC89A5/E/P9x9BHPBu + z9j5/+9/vud73suH9BanRDK+EXk1VWQQf/Z1P+0eX4qEfCpy4m2R2hIRGx+ptZrxsqf4VWRGg8i5hsRI + vTF1GLaLbOXjKMLDWNAlDopYPxNp+Cs3Chfj/XHIpN18T2TXapGxfO1F3L8RyRedjA3TsbMG2FEFbC7D + UQ9TS5xIOV8PJDo/qBMxk/zg1YnRwIIEoDQSsNtwOcUf74s0c8kowmIs7oiTIt+6tlcA2xaSfBaw3o5/ + 7CnYJnKIr+mWocqIr0V2NI4JA54YBZTFoH2aDbfyg3EsxoIVxuGkmgg1FnfEYZFVfxSnAlvnARvKgLXF + RCGOhVj1YpG1XBJBmE6IbKqPG6Sj+kHg4eFASSQcBaE4nR4A5qKJSdjNderUKn/3YoPIiJOD/FzYtgBY + ZweengqsnoL/KjPwrsjlYJHi/SJrvh8SqKMmC5ibCH1GDFzTI9CUNxh7fcz6SJE9pFpPpBCeirdrePJs + RxwrSaw2WFUIPJUP1ObganY03hS5cDQiQEdtNlA+0lCvl0ajpTAUddE+yhqaIK8QhUR/ols1aTtFFp5P + ZeI2lrjJn8wBllLtskz8PiEGWMHfC+n7nHhg5jC0TQ/DT+mBavMrtOYtcjxOhBMmRdgtJogEsq6v4Rme + YkUuiUm+NBOoGgcsTgcWjQEeYdXMjkO7PQpX8oJxoJ/JNVSE9suzBF3qbk3XMPMUm37LigVWTgaqSV5J + ckVcngLMS6T6OHo/FM1FNhwK8cYckX387iUij/Ajem80FXY21ieaNGM5va66q1qRz0+i8njotMYxLRz1 + if54jk1Ptl38bB6hyrJnazpCNdCHLKiD/hancwntqWDZdpAr32fFGpXjpPfHQ7xAw9lvhjUJRK8jxYjv + RJIOiNSfS2OSVzPByvPyZLctVK7IURYNvTgC+jQ22XQb6kK99HW0iC2bRIqevT/DnVlf64/49nO0Psbm + UdYoWxY8wISOMBJqNFQnuQ16YQhcU4KBgoE4FemFLSzvRHft3z+DeLY+nIinGsdFsWpIXElLFPFcVSlU + PZvE9Fy3D6HicGCqDe0kd04ZjLbcILRNCoIzLwAX4ixqMJ4vFSkirS/RuYlW19d8EzUZwKMkntNFsbKE + fjtoh2omNW/aORKc+W5yx6RA3MkZgNtZ/nBM9EPTaAt2mbWWJSLsOQkkjIRrynedbW+QUq0ixQzmgTPm + TlEYzmYGYaem6ZeS+0MvInne/eSt461oyfTBrQwf/JLgiVr3cJxEWOVzkYr9HubWtplU/RCJSYqSCKoN + QytVN6QFYI+m3UoWeed5kdOXkv3gyg2Eowt5a6YvmtMtuDrWGx8N6IO0e2UbJB+I/OAqG0pyKmbp6fTY + SY9vsEOPs87fEPmT15Tq0i0BIlW8fX5uTPSBI7s/WidYqdoX/46z4HqqN76KMGONyI80/zWuLyD81GRa + fj7WSnJ6WxCM25zpV3IG4gubF5Riq3u+cNBKDhE+nNPkBd5iZ+O8qd4X10h+JskTh21m1XSXWK5KTA0R + Q5gln/foXk2abmQH4frkIJxIsGK3p8k5X+RjZkgdVSWMpxZ/QiXNEi2Szk3qj0d60BITNvIyrOT1THJO + GeGNKWOIzsvJY7FI6csiF3do2t/LeFlx7iviFwnuI/GEuvo6yk799eZMSKPMfaNFXr9riTqlumRUL/gQ + 98qUUANqPLGcYGNKBZFJhBA9tb/6RikcQXB0KSMMIeoG60d0kndEH0LtGkao/yAGE96Eet5bKBI1GgYQ + qrHMd591CZH/Ab++z2z1oAjxAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAYASURBVEhLlVULTJNXFAYZdg6G23AacT6ywZQlTh4xQwQx - qJgMXERnhGlAxlQWZC1SjDK2GhwRcLAKSqcSBCGAtAMy3q+CvN9QBeTdlvJqeUodzm327JzLzGI2jZ7k - y9+e/97vvL57f73n2eXLBZyoqLKr4eFFdwWCX6TLlpmaoZtD74KDxY7+/olh9vYe5FuK0Cf/K1lkZKVF - amorzM09guxsGbi786LRbc7nZ1qFhkpmJJI24HKTx11d+V7oX45YQvtexigb/dDQnI1paa0wNfUbjI7O - w/nzxb8HBqbL+PyMiaamYejrm8bAHeDqykvD9fYII9r8XIuN7XCOiKhpCAsriuZykz4LCcm+fvt2G2g0 - D2Fk5AGMj8+DUjmLxFPQ06OBzk4NJCbWwJYte5JxuwfCFMGSQzxrQmH1usjIEo1Go4X29hEQizugpmYI - ZmYewd27E1BeLoeKCjlUVtJzCN8p4d49NaSk1IOLC7fSzs4j4vDhKJGnp1C8fv0nG5CSZvVvIIGg4POi - oi7Qah/D9PQCg1qthdLSAejoGAeFYgaGhqYx+0m4f18DbW1jLFBr6xhkZrbCtWsVIJG0Q0xMITg4fHkF - KT9E0PAXLTAwdXN0dO6fg4Pz2BIttkMLxcUDrCWExQAz0Ns7ia2ZAJlsggWpqpJDY6MK6upUWNUwPkfh - wIHzM4aGRkeQdsUi+6ItPXgwxI/Pz3lMQ62royFOITGRz2GW7RAXVw3p6d3Q1fWAta25eQTJh1mQ6mol - VqSA2NgK8PD44S9DQ04YclogFpV15kyWpY/P5fCLF3OfqNUPWb8pa6VyDqKj82D3br7W2np/vo3NfomX - V0x/Xl4ntLSMQkPDMGaugNraYYiIyAdv7yvg7PxNM1JGITYhluhxuemV4eHZutxcGQwOzrDMGxpU0N8/ - jQHmUf8CnbHxu6m4OA7B43A4/iEhaV1EWlurZNXSUyDIBEfHk+36+vopuM4fsQahr8fj3ZpVqxdALp9l - pJ2dahagp2cSA84CVraAmxJx8X4EKcQsJqYyXSqVs+zr6pRMXVlZHRAQEKfbtu1kw9q1VnT43mEBvL3j - VSrVPAwMTCGmmcZJhl1daujunoTr1yth714/samp6U7c8EZ29tinYvGgltYQMQ2Z1FZSMgBSqQISEmrB - xuZIKa7dSuv1Dh26mJqa2oOa7gShUIrEGlayTDbOJEoDzchoA5GofiE9vX9KIunVEfmdO3IGalFx8SAU - FfVDQUEvG7Sdnf8Ykp9ErNZzdQ3aefRo9P3jx4WPjh27ikppQOIJVgXpnIbZ0jLCVPN0qERM2dM7OoSX - LhVAcnIXVjIJ8fGNYGm5rwLJv0WsR2AZrJwlgXgq6zMzm1Hj42wO1N/6etK3kgWsqlIwYvpNQak1OTmd - cOLEDfD0/JEkqnNzE/yxYoV5EnLSoOm2ZUfaeNcurte5c4k6mUzD+trUNMLI6+uVLHPSPPmpkupqBbal - HwoL+7D3ctiz5+yT5cvNUvX1DRJREHSSv0c4I95ELJq7e2RBeXkvEo8yYpGoEklGMWMVy1oqHcJ2DEF+ - fg8kJTVBbm4f5OX1sv77+ETqTEzMbiANqccW8QHiLYQBYtFcXM4FiUTFSNANPF4K+PklwIUL+Sg/FZIP - Q1nZAA6yD06dSkLN/4oBxpFcxYIIhWWwcaNbHtK4IYj4vzeqhYXdGienoMbTp29hLy/oHBy+ajY3d8zc - sYOnKSsbYxIUCkvxrhHonJz4amfnoFmJRIE3bx9LBgMUIs0xxEpG+D9maGS08mNb2y9SVq3a9DP+j0eE - 2Noezbp5s5Xp29f3KmzefFCK/jQOx+Qna2vvzoCAJLC29ps2MVmbgP4XBqCyliEsEfsQuxEWW7f6fhcc - nAFnz4oBFYLXxmpSSBDCnsMx2rNhw06RgcHrsfifBuuIMEa80Ogep28sLXxt3TqH97dv/3rAysp30NLS - tQR9REYKMflnDSW0C7EF8Tbipb/NT40CfoQgXdPhobv+PQQRUdWGCAr07FfsFexp6+h2pJNJPSbSlzA9 - vb8B5HT/l7ekK9QAAAAASUVORK5CYII= + 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 + N3ea/4GOBpxJAAAAAElFTkSuQmCC @@ -392,6 +392,32 @@ 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 From 253744f048432698592a74b3a4e88a3e57e24b40 Mon Sep 17 00:00:00 2001 From: Jonas Rapp Date: Tue, 16 Oct 2018 23:48:25 +0200 Subject: [PATCH 6/7] Adding test project to easily create batches of contacts (to delete) --- BulkDataUpdater.sln | 6 + .../BulkDataUpdaterTests.csproj | 112 ++++++++++++++++++ BulkDataUpdaterTests/CreatePersons.cs | 33 ++++++ .../Properties/AssemblyInfo.cs | 20 ++++ BulkDataUpdaterTests/packages.config | 11 ++ 5 files changed, 182 insertions(+) create mode 100644 BulkDataUpdaterTests/BulkDataUpdaterTests.csproj create mode 100644 BulkDataUpdaterTests/CreatePersons.cs create mode 100644 BulkDataUpdaterTests/Properties/AssemblyInfo.cs create mode 100644 BulkDataUpdaterTests/packages.config diff --git a/BulkDataUpdater.sln b/BulkDataUpdater.sln index 1f71ebe..5884412 100644 --- a/BulkDataUpdater.sln +++ b/BulkDataUpdater.sln @@ -10,6 +10,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution BulkDataUpdater.nuspec = BulkDataUpdater.nuspec EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BulkDataUpdaterTests", "BulkDataUpdaterTests\BulkDataUpdaterTests.csproj", "{3387CDCD-F34D-4BFA-92CA-703EC041A943}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -20,6 +22,10 @@ Global {B80A491A-2072-47E6-9018-8C3EF90E3053}.Debug|Any CPU.Build.0 = Debug|Any CPU {B80A491A-2072-47E6-9018-8C3EF90E3053}.Release|Any CPU.ActiveCfg = Release|Any CPU {B80A491A-2072-47E6-9018-8C3EF90E3053}.Release|Any CPU.Build.0 = Release|Any CPU + {3387CDCD-F34D-4BFA-92CA-703EC041A943}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3387CDCD-F34D-4BFA-92CA-703EC041A943}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3387CDCD-F34D-4BFA-92CA-703EC041A943}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3387CDCD-F34D-4BFA-92CA-703EC041A943}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BulkDataUpdaterTests/BulkDataUpdaterTests.csproj b/BulkDataUpdaterTests/BulkDataUpdaterTests.csproj new file mode 100644 index 0000000..5c0ad7a --- /dev/null +++ b/BulkDataUpdaterTests/BulkDataUpdaterTests.csproj @@ -0,0 +1,112 @@ + + + + + + Debug + AnyCPU + {3387CDCD-F34D-4BFA-92CA-703EC041A943} + Library + Properties + BulkDataUpdaterTests + BulkDataUpdaterTests + v4.6.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.5\lib\net452\Microsoft.Crm.Sdk.Proxy.dll + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.2.5\lib\net452\Microsoft.Rest.ClientRuntime.dll + + + ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll + + + ..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll + + + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.5\lib\net452\Microsoft.Xrm.Sdk.dll + + + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.4\lib\net452\Microsoft.Xrm.Sdk.Deployment.dll + + + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.4\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.2.5\lib\net452\Microsoft.Xrm.Tooling.Connector.dll + + + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/BulkDataUpdaterTests/CreatePersons.cs b/BulkDataUpdaterTests/CreatePersons.cs new file mode 100644 index 0000000..4622b63 --- /dev/null +++ b/BulkDataUpdaterTests/CreatePersons.cs @@ -0,0 +1,33 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Messages; +using Microsoft.Xrm.Tooling.Connector; + +namespace BulkDataUpdaterTests +{ + [TestClass] + public class CreatePersons + { + private string connstr = "AuthType=Office365;Url=https://jonassandbox2.crm4.dynamics.com/;Username=somethingsomething;Password=somethingelse"; + + [TestMethod] + public void Create100Persons() + { + var req = new ExecuteMultipleRequest + { + Settings = new ExecuteMultipleSettings(), + Requests = new OrganizationRequestCollection() + }; + for (var i = 1; i <= 100; i++) + { + var contact = new Entity("contact"); + contact["firstname"] = "Test" + i; + contact["lastname"] = "Testson" + i; + contact["importsequencenumber"] = 100; + req.Requests.Add(new CreateRequest { Target = contact }); + } + var client = new CrmServiceClient(connstr); + var res = client.Execute(req) as ExecuteMultipleResponse; + } + } +} diff --git a/BulkDataUpdaterTests/Properties/AssemblyInfo.cs b/BulkDataUpdaterTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..722f916 --- /dev/null +++ b/BulkDataUpdaterTests/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("BulkDataUpdaterTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BulkDataUpdaterTests")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("3387cdcd-f34d-4bfa-92ca-703ec041a943")] + +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BulkDataUpdaterTests/packages.config b/BulkDataUpdaterTests/packages.config new file mode 100644 index 0000000..283fe4b --- /dev/null +++ b/BulkDataUpdaterTests/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file From df03436c2207826ce5fbb03941ea2bb4fb667fc6 Mon Sep 17 00:00:00 2001 From: Jonas Rapp Date: Tue, 16 Oct 2018 23:52:50 +0200 Subject: [PATCH 7/7] NuSpec update with new features --- BulkDataUpdater.nuspec | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/BulkDataUpdater.nuspec b/BulkDataUpdater.nuspec index 0c6bdcd..af79422 100644 --- a/BulkDataUpdater.nuspec +++ b/BulkDataUpdater.nuspec @@ -9,12 +9,11 @@ https://github.com/rappen/BulkDataUpdater https://raw.githubusercontent.com/Innofactor/XrmToolBox.BulkDataUpdater/master/images/BDU-150-tsp.png false - This tool is useful to trigger workflows or plugins, as well as bulk updating any number of records with fixed values. - Update or touch attributes on a set of records. + This tool is useful to trigger workflows or plugins, as well as bulk updating any number of records with fixed values. It can also delete records by the filter specified. + Update or touch attributes on a set of records, or delete the data set completely. -#14 Do not reload records when not needed -#17 Add support for attribute types Decimal, Double and Customer -Rebranding +#21 Bulk Data Updater can now Bulk Delete too! +#22 Added possibility to cancel long running operations Copyright 2016-2018 Jonas Rapp XrmToolBox Plugins BulkDataUpdater