diff --git a/.gitignore b/.gitignore
index 55a2d688..d05d3c09 100755
--- a/.gitignore
+++ b/.gitignore
@@ -70,3 +70,5 @@ SuiteCRMAddIn/Documentation/latex/
*.psess
*.vsp
+
+SuiteCRMAddIn/Images/*_old\.png
diff --git a/Doxyfile b/Doxyfile
index 1e5d478c..a411bdf8 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = "SuiteCRM Outlook Add-in"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 3.0.19.48
+PROJECT_NUMBER = 3.0.19.75
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/README.md b/README.md
index 0199f155..25a89d2d 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
### What's in this repository
-SuiteCRM Outlook Plug-In v 3.0.19.48
+SuiteCRM Outlook Plug-In v 3.0.19.75
This repository has been created to allow community members to collaborate and contribute to the project.
diff --git a/SuiteCRMAddIn/Dialogs/ManualSyncContactForm.Designer.cs b/SuiteCRMAddIn/Dialogs/ManualSyncContactForm.Designer.cs
new file mode 100644
index 00000000..3e9e32f7
--- /dev/null
+++ b/SuiteCRMAddIn/Dialogs/ManualSyncContactForm.Designer.cs
@@ -0,0 +1,139 @@
+namespace SuiteCRMAddIn.Dialogs
+{
+ partial class ManualSyncContactForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ManualSyncContactForm));
+ this.useLabel = new System.Windows.Forms.Label();
+ this.resultsTree = new System.Windows.Forms.TreeView();
+ this.cancelButton = new System.Windows.Forms.Button();
+ this.saveButton = new System.Windows.Forms.Button();
+ this.searchText = new System.Windows.Forms.TextBox();
+ this.searchButton = new System.Windows.Forms.Button();
+ this.SuspendLayout();
+ //
+ // useLabel
+ //
+ this.useLabel.AutoSize = true;
+ this.useLabel.Location = new System.Drawing.Point(12, 9);
+ this.useLabel.Name = "useLabel";
+ this.useLabel.Size = new System.Drawing.Size(230, 13);
+ this.useLabel.TabIndex = 0;
+ this.useLabel.Text = "Use the form below to find records in SuiteCRM";
+ //
+ // resultsTree
+ //
+ this.resultsTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.resultsTree.CheckBoxes = true;
+ this.resultsTree.Location = new System.Drawing.Point(15, 56);
+ this.resultsTree.Name = "resultsTree";
+ this.resultsTree.Size = new System.Drawing.Size(257, 165);
+ this.resultsTree.TabIndex = 3;
+ this.resultsTree.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.resultsTree_ItemClick);
+ //
+ // cancelButton
+ //
+ this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.cancelButton.Location = new System.Drawing.Point(197, 227);
+ this.cancelButton.Name = "cancelButton";
+ this.cancelButton.Size = new System.Drawing.Size(75, 23);
+ this.cancelButton.TabIndex = 5;
+ this.cancelButton.Text = "Cancel";
+ this.cancelButton.UseVisualStyleBackColor = true;
+ this.cancelButton.Click += new System.EventHandler(this.cancelButton_click);
+ //
+ // saveButton
+ //
+ this.saveButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.saveButton.DialogResult = System.Windows.Forms.DialogResult.OK;
+ this.saveButton.Enabled = false;
+ this.saveButton.Location = new System.Drawing.Point(116, 227);
+ this.saveButton.Name = "saveButton";
+ this.saveButton.Size = new System.Drawing.Size(75, 23);
+ this.saveButton.TabIndex = 4;
+ this.saveButton.Text = "Save";
+ this.saveButton.UseVisualStyleBackColor = true;
+ this.saveButton.Click += new System.EventHandler(this.saveButton_click);
+ //
+ // searchText
+ //
+ this.searchText.Location = new System.Drawing.Point(15, 30);
+ this.searchText.Name = "searchText";
+ this.searchText.Size = new System.Drawing.Size(176, 20);
+ this.searchText.TabIndex = 1;
+ this.searchText.Leave += new System.EventHandler(this.searchButton_click);
+ this.searchText.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.seachText_PreviewKeyDown);
+ //
+ // searchButton
+ //
+ this.searchButton.Location = new System.Drawing.Point(197, 30);
+ this.searchButton.Name = "searchButton";
+ this.searchButton.Size = new System.Drawing.Size(75, 23);
+ this.searchButton.TabIndex = 2;
+ this.searchButton.Text = "Search";
+ this.searchButton.UseVisualStyleBackColor = true;
+ this.searchButton.Click += new System.EventHandler(this.searchButton_click);
+ //
+ // ManualSyncContactForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.CancelButton = this.cancelButton;
+ this.ClientSize = new System.Drawing.Size(284, 262);
+ this.Controls.Add(this.searchButton);
+ this.Controls.Add(this.searchText);
+ this.Controls.Add(this.saveButton);
+ this.Controls.Add(this.cancelButton);
+ this.Controls.Add(this.resultsTree);
+ this.Controls.Add(this.useLabel);
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(300, 300);
+ this.Name = "ManualSyncContactForm";
+ this.Text = "Manually Sync a Contact";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormClosingEvent);
+ this.Load += new System.EventHandler(this.manualSyncContactsForm_Load);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label useLabel;
+ private System.Windows.Forms.TreeView resultsTree;
+ private System.Windows.Forms.Button cancelButton;
+ private System.Windows.Forms.Button saveButton;
+ private System.Windows.Forms.TextBox searchText;
+ private System.Windows.Forms.Button searchButton;
+ }
+}
\ No newline at end of file
diff --git a/SuiteCRMAddIn/Dialogs/ManualSyncContactForm.cs b/SuiteCRMAddIn/Dialogs/ManualSyncContactForm.cs
new file mode 100644
index 00000000..ef90a0c0
--- /dev/null
+++ b/SuiteCRMAddIn/Dialogs/ManualSyncContactForm.cs
@@ -0,0 +1,270 @@
+/**
+ * Outlook integration for SuiteCRM.
+ * @package Outlook integration for SuiteCRM
+ * @copyright SalesAgility Ltd http://www.salesagility.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU LESSER GENERAL PUBLIC LICENCE as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENCE
+ * along with this program; if not, see http://www.gnu.org/licenses
+ * or write to the Free Software Foundation,Inc., 51 Franklin Street,
+ * Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @author SalesAgility
+ */
+
+#region
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+using Microsoft.Office.Interop.Outlook;
+using SuiteCRMAddIn.BusinessLogic;
+using SuiteCRMAddIn.Extensions;
+using SuiteCRMAddIn.Helpers;
+using SuiteCRMAddIn.Properties;
+using SuiteCRMClient.RESTObjects;
+using System.Text;
+
+#endregion
+
+namespace SuiteCRMAddIn.Dialogs
+{
+ public partial class ManualSyncContactForm : Form
+ {
+ ///
+ /// The key for the create node.
+ ///
+ private static readonly string CreateNodeKey = "Create";
+
+ ///
+ /// The key for the contacts node.
+ ///
+ private static readonly string ContactsNodeKey = "Contacts";
+
+ private Dictionary searchResults = new Dictionary();
+
+ private bool dontClose = false;
+
+ ///
+ /// The contact we're going to operate on.
+ ///
+ ContactItem contactItem = Globals.ThisAddIn.SelectedContacts.First();
+
+ public ManualSyncContactForm(string searchString)
+ {
+ if (contactItem != null)
+ {
+ InitializeComponent();
+ this.Text = $"Manually sync {contactItem.FullName}";
+ searchText.Text = searchString;
+ }
+ else
+ {
+ throw new System.Exception("No contact selected in ManualSyncContactForm");
+ }
+ }
+
+ private void ClearAndSearch(string target)
+ {
+ using (WaitCursor.For(this, true))
+ {
+ searchResults = new Dictionary();
+
+ resultsTree.Nodes.Clear();
+ resultsTree.Nodes.Add(CreateNodeKey, "Create a new Contact");
+
+ if (!string.IsNullOrWhiteSpace(target))
+ {
+ var contactsNode = resultsTree.Nodes.Add(ContactsNodeKey, "Contacts");
+
+ SearchAddChildren(target, contactsNode);
+
+ if (contactsNode.Nodes.Count == 0)
+ {
+ resultsTree.Nodes.Remove(contactsNode);
+ resultsTree.Nodes[CreateNodeKey].Checked = true;
+ saveButton.Enabled = true;
+ }
+ }
+ }
+ }
+
+ private void SearchAddChildren(string target, TreeNode contactsNode)
+ {
+ var tokens = target.Split(" ;:,".ToCharArray());
+
+ foreach (var token in tokens.Where(x => !string.IsNullOrEmpty(x)))
+ foreach (var crmContact in SearchHelper.SearchContacts(token))
+ searchResults[crmContact.id] = crmContact;
+
+ foreach (var result in searchResults.Values.OrderBy(
+ x => $"{x.GetValueAsString("last_name")} {x.GetValueAsString("first_name")}"))
+ {
+ TreeNode node = contactsNode.Nodes.Add(result.id, CanonicalString(result));
+ var contactItem = Globals.ThisAddIn.SelectedContacts.First();
+
+ if (IsProbablySameItem(result, contactItem))
+ {
+ node.BackColor = ColorTranslator.FromHtml("#a9ea56");
+ }
+ else if (IsPreviouslySyncedItem(result))
+ {
+ node.BackColor = ColorTranslator.FromHtml("#ea6556");
+ }
+ else if (SyncStateManager.Instance.GetExistingSyncState(result) != null)
+ {
+ node.BackColor = ColorTranslator.FromHtml("#ea6556");
+ }
+
+ contactsNode.Expand();
+ }
+ }
+
+ private bool IsPreviouslySyncedItem(string crmId)
+ {
+ return !string.IsNullOrEmpty(crmId) &&
+ searchResults.ContainsKey(crmId) &&
+ IsPreviouslySyncedItem(searchResults[crmId]);
+ }
+
+ private bool IsPreviouslySyncedItem(EntryValue result)
+ {
+ return !string.IsNullOrEmpty(result.GetValueAsString("outlook_id")) ||
+ !string.IsNullOrEmpty(result.GetValueAsString("sync_contact")) ||
+ SyncStateManager.Instance.GetExistingSyncState(result) != null;
+ }
+
+ private bool IsProbablySameItem(EntryValue result, ContactItem contactItem)
+ {
+ return result != null &&
+ (result.id.Equals(contactItem.UserProperties[SyncStateManager.CrmIdPropertyName]?.Value) ||
+ result.GetValueAsString("outlook_id")?.Equals(contactItem.EntryID));
+ }
+
+ private static string CanonicalString(EntryValue result)
+ {
+ return
+ $"{result.GetValueAsString("first_name")} {result.GetValueAsString("last_name")} ({result.GetValueAsString("email1")})";
+ }
+
+ private void searchButton_click(object sender, EventArgs e)
+ {
+ ClearAndSearch(searchText.Text);
+ }
+
+ private void saveButton_click(object sender, EventArgs e)
+ {
+ var crmId = contactItem.GetCrmId().ToString();
+ string selectedId = resultsTree.GetAllNodes().FirstOrDefault(x => x.Checked)?.Name;
+ EntryValue selectedItem = searchResults.ContainsKey(selectedId) ? searchResults[selectedId] : null;
+ List problems = new List();
+
+ if (contactItem.Sensitivity == OlSensitivity.olPrivate)
+ {
+ problems.Add($"Contact {contactItem.FullName} is marked 'private'. Are you sure?");
+ }
+
+ if (resultsTree.Nodes["create"].Checked && IsPreviouslySyncedItem(crmId))
+ {
+ problems.Add($"A record for contact {contactItem.FullName} already exists in CRM. Are you sure you want to create a new record?");
+ }
+ if (selectedItem != null &&
+ !IsProbablySameItem(selectedItem, contactItem))
+ {
+ problems.Add($"The record for {selectedItem.GetValueAsString("first_name")} {selectedItem.GetValueAsString("last_name")} will be overwritten with the details of {contactItem.FullName}.");
+ }
+ if (IsPreviouslySyncedItem(crmId) && selectedItem != null)
+ {
+ problems.Add($"Contact {selectedItem.GetValueAsString("first_name")} {selectedItem.GetValueAsString("last_name")} has previously been synced and will be overwritten.");
+ }
+
+ if (resultsTree.Nodes["create"].Checked &&
+ IsPreviouslySyncedItem(crmId) )
+ {
+ problems.Add($"Contact {contactItem.FullName} has previously been synced. Are you sure you want to create another copy?");
+ }
+
+ if (problems.Count == 0 || MessageBox.Show(
+ string.Join("\n", problems.Select(p => $"• {p}\n").ToArray()),
+ "Problems found: are you sure?",
+ MessageBoxButtons.OKCancel,
+ MessageBoxIcon.Warning) ==
+ DialogResult.OK)
+ {
+ if (resultsTree.Nodes["create"].Checked)
+ {
+ contactItem.ClearCrmId();
+ contactItem.SetManualOverride();
+ }
+ else
+ {
+ try
+ {
+ contactItem.ChangeCrmId(resultsTree.GetAllNodes().FirstOrDefault(x => x.Checked).Name);
+ }
+ finally
+ {
+ contactItem.SetManualOverride();
+ }
+ }
+ }
+ else
+ {
+ dontClose = true;
+ }
+ }
+
+ private void cancelButton_click(object sender, EventArgs e)
+ {
+ Close();
+ }
+
+ private void resultsTree_ItemClick(object sender, TreeNodeMouseClickEventArgs e)
+ {
+ var contactsNode = resultsTree.Nodes[ContactsNodeKey];
+ var createNode = resultsTree.Nodes[CreateNodeKey];
+
+ if (e.Node == contactsNode)
+ {
+ e.Node.Checked = false;
+ // You can't check the 'Contacts' node.
+ }
+ else
+ {
+ foreach (var node in resultsTree.GetAllNodes().Where( n => n != e.Node))
+ node.Checked = false;
+ }
+
+ saveButton.Enabled = resultsTree.GetAllNodes().Any(x => x.Checked);
+ }
+
+ private void manualSyncContactsForm_Load(object sender, EventArgs e)
+ {
+ if (Settings.Default.AutomaticSearch)
+ BeginInvoke((MethodInvoker) delegate { ClearAndSearch(searchText.Text); });
+ }
+
+ private void seachText_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
+ {
+ if (e.KeyCode == Keys.Enter && !string.IsNullOrWhiteSpace(searchText.Text))
+ ClearAndSearch(searchText.Text);
+ }
+
+ private void FormClosingEvent(object sender, FormClosingEventArgs e)
+ {
+ e.Cancel = dontClose;
+ dontClose = false;
+ }
+ }
+}
diff --git a/SuiteCRMAddIn/Dialogs/ManualSyncContactForm.resx b/SuiteCRMAddIn/Dialogs/ManualSyncContactForm.resx
new file mode 100644
index 00000000..45f9e24c
--- /dev/null
+++ b/SuiteCRMAddIn/Dialogs/ManualSyncContactForm.resx
@@ -0,0 +1,408 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/AAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAA6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/AAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/wAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/wAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAADqVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/wAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/wAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADqVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+lWaL0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADqVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP9VAFUDAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADpVmib6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAA6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAQEAE6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/pVmi9AAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AADqVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP8AAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/4AA
+ gAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/AAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAADqVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pWaP/qVmj/6lZo/+pW
+ aP/qVmj/6lZo/1UAVQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRhXf/kYV3/5GFd/+RhXf/AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AABWZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/AAD/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkYV3/5GF
+ d/+RhXf/kYV3/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAFZl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/AAD/AgAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAJGFd/+RhXf/kYV3/5GFd/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAD/AVZl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRhXf/kYV3/5GFd/+RhXf/AAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkYV3/5GFd/+RhXf/kYV3/wAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/AAD/AgAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJGF
+ d/+RhXf/kYV3/5GFd/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACRhXf/kYV3/5GFd/+RhXf/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAABWZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/AAD/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkYV3/5GFd/+RhXf/kYV3/wAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v8AAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAACRhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GF
+ d/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/wAAAAAAAAAAVmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GF
+ d/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/8AAAAAAAAAAFZl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJGFd/+RhXf/kYV3/5GF
+ d/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GF
+ d/+RhXf/AAAAAAAAAABWZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AACRhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GF
+ d/+RhXf/kYV3/5GFd/+RhXf/kYV3/wAAAAAAAAAAVmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAkYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GF
+ d/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/+RhXf/kYV3/5GFd/8AAAAAAAAAAFZl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAkYV3/5GFd/+RhXf/kYV3/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAVmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJGFd/+RhXf/kYV3/5GFd/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRhXf/kYV3/5GFd/+RhXf/AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkYV3/5GF
+ d/+RhXf/kYV3/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAJGFd/+RhXf/kYV3/5GFd/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAVmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/AAD/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRhXf/kYV3/5GFd/+RhXf/AAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWZer/VmXq/1Zl6v9WZer/VmXq/1Zl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkYV3/5GFd/+RhXf/kYV3/wAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZl
+ 6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/VmXq/1Zl6v9WZer/AAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJGF
+ d/+RhXf/kYV3/5GFd/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWZer/VmXq/1Zl6v9WZer/VmXq/wAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA/////////////////////////////////////////////////////////gAAAP/////AAAAA
+ A////gAAAAAAf//8AAAAAAAf//gAAAAAAA//+AAAAAAAD//4AAAAAAAP//gAAAAAAA//+AAAAAAAD//4
+ AAAAAAAP//wAAAAAAA///AAAAAAAH//8AAAAAAAf//4AAAAAAB///gAAAAAAP///AAAAAAA///8AAAAA
+ AH///4AAAAAA////wAAAAAD////AAAAAAf///+AAAAAD////8AAAAAf////4AAAAD/////4AAAA/////
+ /wAAAH//////wAAB///////4AA////////////////D//4B/////8P/+AB/////w//gAD/////D/+AAH
+ ////8P/wAAP////w/+AAA/////D/4AAB////8P/gAAH///AAAMAAAf//8AAAwAAB///wAADAAAH///AA
+ AMAAAf//8AAAwAAB////8P/gAAH////w/+AAA/////D/4AAD////8P/wAAf////w//gAB/////D//AAf
+ ////8P/+AD/////w///B////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////8=
+
+
+
\ No newline at end of file
diff --git a/SuiteCRMAddIn/Extensions/ContactItemExtensions.cs b/SuiteCRMAddIn/Extensions/ContactItemExtensions.cs
index a9cb919d..42178ca5 100644
--- a/SuiteCRMAddIn/Extensions/ContactItemExtensions.cs
+++ b/SuiteCRMAddIn/Extensions/ContactItemExtensions.cs
@@ -24,7 +24,10 @@ namespace SuiteCRMAddIn.Extensions
{
using BusinessLogic;
using SuiteCRMClient;
+ using System;
+ using System.Globalization;
using System.Runtime.InteropServices;
+ using System.Xml.Serialization;
using Outlook = Microsoft.Office.Interop.Outlook;
///
@@ -35,6 +38,16 @@ namespace SuiteCRMAddIn.Extensions
///
public static class ContactItemExtensions
{
+ ///
+ /// Name of the override property.
+ ///
+ private const string OverridePropertyName = "UserOverride";
+
+ ///
+ /// The duration of the override window in minutes.
+ ///
+ private const int OverrideWindowMinutes = 10;
+
///
/// Remove all the synchronisation properties from this item.
///
@@ -70,6 +83,89 @@ public static CrmId GetCrmId(this Outlook.ContactItem olItem)
return result;
}
+ ///
+ /// True if the override window is open for this item.
+ ///
+ /// In order to allow manual sync, we need to be able to override the disablement of syncing -
+ /// but only briefly.
+ /// The item which we wish to sync.
+ /// True if the manual sync window is open for this item.
+ public static bool IsManualOverride(this Outlook.ContactItem olItem)
+ {
+ bool result = false;
+ if (olItem.UserProperties[OverridePropertyName] != null)
+ {
+ DateTime value = olItem.UserProperties[OverridePropertyName].Value;
+
+ if ((DateTime.UtcNow - value).Minutes < OverrideWindowMinutes)
+ {
+ result = true;
+ }
+ else
+ {
+ /* no point holding on to a timed-out manual override property */
+ olItem.ClearManualOverride();
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Set this item as manually syncable, briefly. As a side effect of making the change triggers sync.
+ ///
+ /// In order to allow manual sync, we need to be able to override the disablement of syncing -
+ /// but only briefly.
+ /// The item which may be synced despite syncing being disabled
+ public static void SetManualOverride(this Outlook.ContactItem olItem)
+ {
+ var p = olItem.UserProperties.Add(OverridePropertyName, Outlook.OlUserPropertyType.olDateTime);
+ p.Value = DateTime.UtcNow;
+ olItem.Save();
+ }
+
+ ///
+ /// Clear the manually syncability of this item; does not break is manual sync was not set.
+ ///
+ /// In order to allow manual sync, we need to be able to override the disablement of syncing -
+ /// but only briefly.
+ /// The item which may be synced despite syncing being disabled
+ public static void ClearManualOverride(this Outlook.ContactItem olItem)
+ {
+ olItem.UserProperties[OverridePropertyName]?.Delete();
+ }
+
+ public static void ClearCrmId(this Outlook.ContactItem olItem)
+ {
+ var state = SyncStateManager.Instance.GetExistingSyncState(olItem);
+
+ olItem.ClearUserProperty(SyncStateManager.CrmIdPropertyName);
+
+ if (state != null)
+ {
+ state.CrmEntryId = null;
+ }
+
+ olItem.Save();
+ }
+
+ public static void ChangeCrmId(this Outlook.ContactItem olItem, string text)
+ {
+ var crmId = new CrmId(text);
+ var state = SyncStateManager.Instance.GetExistingSyncState(olItem);
+ var userProperty = olItem.UserProperties.Find(SyncStateManager.CrmIdPropertyName) ??
+ olItem.UserProperties.Add(SyncStateManager.CrmIdPropertyName,
+ Outlook.OlUserPropertyType.olText);
+ userProperty.Value = crmId.ToString();
+
+ if (state != null)
+ {
+ state.CrmEntryId = crmId;
+ }
+
+ olItem.Save();
+ }
+
///
/// Am I actually a valid Outlook item at all?
diff --git a/SuiteCRMAddIn/Extensions/TreeNodeExtensions.cs b/SuiteCRMAddIn/Extensions/TreeNodeExtensions.cs
new file mode 100644
index 00000000..1f081c33
--- /dev/null
+++ b/SuiteCRMAddIn/Extensions/TreeNodeExtensions.cs
@@ -0,0 +1,48 @@
+/**
+ * Outlook integration for SuiteCRM.
+ * @package Outlook integration for SuiteCRM
+ * @copyright SalesAgility Ltd http://www.salesagility.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU LESSER GENERAL PUBLIC LICENCE as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENCE
+ * along with this program; if not, see http://www.gnu.org/licenses
+ * or write to the Free Software Foundation,Inc., 51 Franklin Street,
+ * Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @author SalesAgility
+ */
+
+#region
+
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+#endregion
+
+namespace SuiteCRMAddIn.Extensions
+{
+ ///
+ /// Stolen shamelessly from
+ /// https://stackoverflow.com/questions/4702051/get-a-list-of-all-tree-nodes-in-all-levels-in-treeview-controls
+ ///
+ public static class TreeNodeExtensions
+ {
+ public static List GetAllNodes(this TreeNode _self)
+ {
+ var result = new List();
+ result.Add(_self);
+ foreach (TreeNode child in _self.Nodes)
+ result.AddRange(child.GetAllNodes());
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SuiteCRMAddIn/Extensions/TreeViewExtensions.cs b/SuiteCRMAddIn/Extensions/TreeViewExtensions.cs
new file mode 100644
index 00000000..4d92a7ef
--- /dev/null
+++ b/SuiteCRMAddIn/Extensions/TreeViewExtensions.cs
@@ -0,0 +1,47 @@
+/**
+ * Outlook integration for SuiteCRM.
+ * @package Outlook integration for SuiteCRM
+ * @copyright SalesAgility Ltd http://www.salesagility.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU LESSER GENERAL PUBLIC LICENCE as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENCE
+ * along with this program; if not, see http://www.gnu.org/licenses
+ * or write to the Free Software Foundation,Inc., 51 Franklin Street,
+ * Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @author SalesAgility
+ */
+
+#region
+
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+#endregion
+
+namespace SuiteCRMAddIn.Extensions
+{
+ ///
+ /// Stolen shamelessly from
+ /// https://stackoverflow.com/questions/4702051/get-a-list-of-all-tree-nodes-in-all-levels-in-treeview-controls
+ ///
+ public static class TreeViewExtensions
+ {
+ public static List GetAllNodes(this TreeView _self)
+ {
+ var result = new List();
+ foreach (TreeNode child in _self.Nodes)
+ result.AddRange(child.GetAllNodes());
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SuiteCRMAddIn/Helpers/SearchHelper.cs b/SuiteCRMAddIn/Helpers/SearchHelper.cs
new file mode 100644
index 00000000..77b94a99
--- /dev/null
+++ b/SuiteCRMAddIn/Helpers/SearchHelper.cs
@@ -0,0 +1,85 @@
+/**
+ * Outlook integration for SuiteCRM.
+ * @package Outlook integration for SuiteCRM
+ * @copyright SalesAgility Ltd http://www.salesagility.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU LESSER GENERAL PUBLIC LICENCE as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENCE
+ * along with this program; if not, see http://www.gnu.org/licenses
+ * or write to the Free Software Foundation,Inc., 51 Franklin Street,
+ * Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @author SalesAgility
+ */
+
+#region
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using SuiteCRMAddIn.BusinessLogic;
+using SuiteCRMAddIn.Exceptions;
+using SuiteCRMClient;
+using SuiteCRMClient.RESTObjects;
+
+#endregion
+
+namespace SuiteCRMAddIn.Helpers
+{
+ ///
+ /// We do search (differently) in too many places. This is an attempt to rationalise it.
+ ///
+ public class SearchHelper
+ {
+ public static IEnumerable SearchContacts(string token)
+ {
+ return Search(ContactSynchroniser.CrmModule, token,
+ new[] {"first_name", "last_name", "email1" , "sync_contact", "outlook_id" });
+ }
+
+ public static IEnumerable Search(string module, string token, IEnumerable fields,
+ string logicalOperator = "OR")
+ {
+ var bob = new StringBuilder("(");
+ var fieldsArray = fields.ToArray();
+
+ foreach (var field in fieldsArray)
+ {
+ switch (field)
+ {
+ case "first_name":
+ case "last_name":
+ case "name":
+ if (field != fieldsArray.First())
+ bob.Append($"{logicalOperator} ");
+ bob.Append($"{module.ToLower()}.{field} ").Append(token.Length < 4
+ ? $"= '{token}' "
+ : $"LIKE '%{token}%' ");
+ break;
+ case "email1":
+ if (field != fieldsArray.First())
+ bob.Append($"{logicalOperator} ");
+ bob.Append(
+ $"({module.ToLower()}.id in (select eabr.bean_id from email_addr_bean_rel eabr INNER JOIN email_addresses ea on eabr.email_address_id = ea.id where eabr.bean_module = '{module}' and ea.email_address ");
+ bob.Append(token.Length < 4 ? $"= '{token}'))" : $"LIKE '%{token}%'))");
+ break;
+ }
+ }
+ bob.Append(")");
+
+ var result = RestAPIWrapper.GetEntryList(module, bob.ToString(), 1000, "date_entered DESC", 0, false, fieldsArray)
+ .entry_list;
+
+ return result;
+ }
+ }
+}
diff --git a/SuiteCRMAddIn/Images/Cancel.png b/SuiteCRMAddIn/Images/Cancel.png
index 3d19d8a2..1caee068 100644
Binary files a/SuiteCRMAddIn/Images/Cancel.png and b/SuiteCRMAddIn/Images/Cancel.png differ
diff --git a/SuiteCRMAddIn/Images/Cancel.svg b/SuiteCRMAddIn/Images/Cancel.svg
new file mode 100644
index 00000000..e421e0f1
--- /dev/null
+++ b/SuiteCRMAddIn/Images/Cancel.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/SuiteCRMAddIn/Images/Cancel_old.png b/SuiteCRMAddIn/Images/Cancel_old.png
new file mode 100644
index 00000000..3d19d8a2
Binary files /dev/null and b/SuiteCRMAddIn/Images/Cancel_old.png differ
diff --git a/SuiteCRMAddIn/Images/Check.png b/SuiteCRMAddIn/Images/Check.png
index 89bba903..10dd3ea9 100644
Binary files a/SuiteCRMAddIn/Images/Check.png and b/SuiteCRMAddIn/Images/Check.png differ
diff --git a/SuiteCRMAddIn/Images/Check.svg b/SuiteCRMAddIn/Images/Check.svg
new file mode 100644
index 00000000..69a9c35c
--- /dev/null
+++ b/SuiteCRMAddIn/Images/Check.svg
@@ -0,0 +1,68 @@
+
+
+
+
diff --git a/SuiteCRMAddIn/Images/Check_old.png b/SuiteCRMAddIn/Images/Check_old.png
new file mode 100644
index 00000000..89bba903
Binary files /dev/null and b/SuiteCRMAddIn/Images/Check_old.png differ
diff --git a/SuiteCRMAddIn/Images/Search.svg b/SuiteCRMAddIn/Images/Search.svg
new file mode 100644
index 00000000..554d4bc1
--- /dev/null
+++ b/SuiteCRMAddIn/Images/Search.svg
@@ -0,0 +1,60 @@
+
+
diff --git a/SuiteCRMAddIn/Images/Search_Button.png b/SuiteCRMAddIn/Images/Search_Button.png
index 3b3f443c..1fb0b20e 100644
Binary files a/SuiteCRMAddIn/Images/Search_Button.png and b/SuiteCRMAddIn/Images/Search_Button.png differ
diff --git a/SuiteCRMAddIn/Images/Settings.png b/SuiteCRMAddIn/Images/Settings.png
index f36cc1de..98522261 100644
Binary files a/SuiteCRMAddIn/Images/Settings.png and b/SuiteCRMAddIn/Images/Settings.png differ
diff --git a/SuiteCRMAddIn/Images/Settings.svg b/SuiteCRMAddIn/Images/Settings.svg
new file mode 100644
index 00000000..d19194fd
--- /dev/null
+++ b/SuiteCRMAddIn/Images/Settings.svg
@@ -0,0 +1,74 @@
+
+
diff --git a/SuiteCRMAddIn/Images/Settings_old.png b/SuiteCRMAddIn/Images/Settings_old.png
new file mode 100644
index 00000000..f36cc1de
Binary files /dev/null and b/SuiteCRMAddIn/Images/Settings_old.png differ
diff --git a/SuiteCRMAddIn/Images/manualSyncContact.png b/SuiteCRMAddIn/Images/manualSyncContact.png
new file mode 100644
index 00000000..4249f4e8
Binary files /dev/null and b/SuiteCRMAddIn/Images/manualSyncContact.png differ
diff --git a/SuiteCRMAddIn/Images/manualSyncContact.xcf b/SuiteCRMAddIn/Images/manualSyncContact.xcf
new file mode 100644
index 00000000..e823be45
Binary files /dev/null and b/SuiteCRMAddIn/Images/manualSyncContact.xcf differ
diff --git a/SuiteCRMAddIn/Menus/General.xml b/SuiteCRMAddIn/Menus/General.xml
new file mode 100644
index 00000000..4276280b
--- /dev/null
+++ b/SuiteCRMAddIn/Menus/General.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SuiteCRMAddIn/Menus/General2007.xml b/SuiteCRMAddIn/Menus/General2007.xml
new file mode 100644
index 00000000..04ab12a3
--- /dev/null
+++ b/SuiteCRMAddIn/Menus/General2007.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SuiteCRMAddIn/Menus/MailCompose.xml b/SuiteCRMAddIn/Menus/MailCompose.xml
index 405f899c..1dbf1151 100644
--- a/SuiteCRMAddIn/Menus/MailCompose.xml
+++ b/SuiteCRMAddIn/Menus/MailCompose.xml
@@ -5,9 +5,9 @@
-
-
-
+
+
+
diff --git a/SuiteCRMAddIn/Menus/MailRead.xml b/SuiteCRMAddIn/Menus/MailRead.xml
index 605eed67..9a9ff24e 100644
--- a/SuiteCRMAddIn/Menus/MailRead.xml
+++ b/SuiteCRMAddIn/Menus/MailRead.xml
@@ -5,16 +5,19 @@
-
-
+
+
-
-
+
+
+
+
+
diff --git a/SuiteCRMAddIn/Menus/MailRead2007.xml b/SuiteCRMAddIn/Menus/MailRead2007.xml
index 3f4d0a77..3ed7d224 100644
--- a/SuiteCRMAddIn/Menus/MailRead2007.xml
+++ b/SuiteCRMAddIn/Menus/MailRead2007.xml
@@ -5,8 +5,8 @@
-
-
+
+
diff --git a/SuiteCRMAddIn/Menus/RibbonImageHelper.cs b/SuiteCRMAddIn/Menus/RibbonImageHelper.cs
index a5e3aa6a..7b1e1567 100644
--- a/SuiteCRMAddIn/Menus/RibbonImageHelper.cs
+++ b/SuiteCRMAddIn/Menus/RibbonImageHelper.cs
@@ -35,7 +35,7 @@ private RibbonImageHelper()
public static IPictureDisp Convert(Image image)
{
- return (IPictureDisp) AxHost.GetIPictureDispFromPicture(image);
+ return (IPictureDisp) GetIPictureDispFromPicture(image);
}
}
}
diff --git a/SuiteCRMAddIn/Menus/SuiteCRMRibbon.cs b/SuiteCRMAddIn/Menus/SuiteCRMRibbon.cs
index 53124362..841ff295 100644
--- a/SuiteCRMAddIn/Menus/SuiteCRMRibbon.cs
+++ b/SuiteCRMAddIn/Menus/SuiteCRMRibbon.cs
@@ -35,7 +35,9 @@
using Office = Microsoft.Office.Core;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Collections.Generic;
+using SuiteCRMAddIn.BusinessLogic;
using SuiteCRMAddIn.Dialogs;
+using SuiteCRMAddIn.Helpers;
// TODO: Follow these steps to enable the Ribbon (XML) item:
@@ -94,6 +96,11 @@ public IPictureDisp GetImage(IRibbonControl control)
case "btnAddressBook":
result = RibbonImageHelper.Convert(Resources.AddressBook);
break;
+ case "manualSyncButton":
+ case "manualSyncMultiButton":
+ case "manualSyncToolbar":
+ result = RibbonImageHelper.Convert(Resources.manualSyncContact);
+ break;
default:
result = RibbonImageHelper.Convert(Resources.Archive);
break;
@@ -113,8 +120,8 @@ public string GetCustomUI(string ribbonID)
case "Microsoft.Outlook.Mail.Read":
case "Microsoft.Outlook.Explorer":
result = (Globals.ThisAddIn.OutlookVersion <= OutlookMajorVersion.Outlook2007) ?
- GetResourceText("SuiteCRMAddIn.Menus.MailRead2007.xml") :
- GetResourceText("SuiteCRMAddIn.Menus.MailRead.xml");
+ GetResourceText("SuiteCRMAddIn.Menus.MailRead.xml") :
+ GetResourceText("SuiteCRMAddIn.Menus.MailRead2007.xml");
break;
case "Microsoft.Outlook.Mail.Compose":
result = GetResourceText("SuiteCRMAddIn.Menus.MailCompose.xml");
@@ -142,7 +149,17 @@ public void Ribbon_Load(Office.IRibbonUI ribbonUI)
public bool btnArchive_Enabled()
{
- return Globals.ThisAddIn.SelectedEmails.Select(x => x.UserProperties[MailItemExtensions.CrmIdPropertyName] == null).ToList().Count() > 0;
+ return Globals.ThisAddIn.HasCrmUserSession &&
+ Globals.ThisAddIn.Application.ActiveInspector().CurrentItem is Outlook.MailItem;
+
+// Globals.ThisAddIn.SelectedEmails.Select(x => x.UserProperties[MailItemExtensions.CrmIdPropertyName] == null).ToList().Any();
+ }
+
+ public bool manualSyncButton_Enabled(IRibbonControl control)
+ {
+ return Globals.ThisAddIn.HasCrmUserSession &&
+ Globals.ThisAddIn.SelectedContacts.Count() == 1 &&
+ Settings.Default.SyncContacts == SyncDirection.Direction.Neither;
}
#region Click Events
@@ -152,6 +169,11 @@ public void btnArchive_Action(IRibbonControl control)
Globals.ThisAddIn.ManualArchive());
}
+ public void manualSyncButton_Action(IRibbonControl control)
+ {
+ DoOrLogError(() => Globals.ThisAddIn.ManualSyncContact());
+ }
+
public void btnSettings_Action(IRibbonControl control)
{
DoOrLogError(() =>
diff --git a/SuiteCRMAddIn/Properties/AssemblyInfo.cs b/SuiteCRMAddIn/Properties/AssemblyInfo.cs
index 86fb31c2..afc175eb 100644
--- a/SuiteCRMAddIn/Properties/AssemblyInfo.cs
+++ b/SuiteCRMAddIn/Properties/AssemblyInfo.cs
@@ -33,6 +33,6 @@
// 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("3.0.19.48")]
+[assembly: AssemblyVersion("3.0.19.75")]
[assembly: AssemblyFileVersion("3.0.1")]
diff --git a/SuiteCRMAddIn/Properties/Resources.Designer.cs b/SuiteCRMAddIn/Properties/Resources.Designer.cs
index 9af93311..8f9fa491 100644
--- a/SuiteCRMAddIn/Properties/Resources.Designer.cs
+++ b/SuiteCRMAddIn/Properties/Resources.Designer.cs
@@ -100,6 +100,16 @@ internal static System.Drawing.Bitmap Check {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap manualSyncContact {
+ get {
+ object obj = ResourceManager.GetObject("manualSyncContact", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
diff --git a/SuiteCRMAddIn/Properties/Resources.resx b/SuiteCRMAddIn/Properties/Resources.resx
index 6451b93b..9eac4227 100644
--- a/SuiteCRMAddIn/Properties/Resources.resx
+++ b/SuiteCRMAddIn/Properties/Resources.resx
@@ -145,4 +145,7 @@
..\images\suitecrm.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
-
\ No newline at end of file
+
+ ..\Images\manualSyncContact.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
diff --git a/SuiteCRMAddIn/SuiteCRMAddIn.csproj b/SuiteCRMAddIn/SuiteCRMAddIn.csproj
index 0e97eff4..45712dff 100644
--- a/SuiteCRMAddIn/SuiteCRMAddIn.csproj
+++ b/SuiteCRMAddIn/SuiteCRMAddIn.csproj
@@ -215,6 +215,12 @@
+
+ Form
+
+
+ ManualSyncContactForm.cs
+
Form
@@ -283,6 +289,8 @@
+
+
True
True
@@ -354,6 +362,7 @@
Code
+
@@ -371,6 +380,9 @@
ConfirmRearchiveAlreadyArchivedEmails.cs
+
+ ManualSyncContactForm.cs
+
ShuttingDownDialog.cs
@@ -440,11 +452,13 @@
+
+
diff --git a/SuiteCRMAddIn/ThisAddIn.cs b/SuiteCRMAddIn/ThisAddIn.cs
index 939654e0..7da20a67 100644
--- a/SuiteCRMAddIn/ThisAddIn.cs
+++ b/SuiteCRMAddIn/ThisAddIn.cs
@@ -28,6 +28,7 @@ namespace SuiteCRMAddIn
using Daemon;
using Dialogs;
using Extensions;
+ using Helpers;
using Microsoft.Office.Core;
using NGettext;
using Properties;
@@ -67,11 +68,13 @@ public partial class ThisAddIn
///
/// #2246: Discriminate between calls and meetings when adding and updating.
///
- internal CallsSynchroniser CallsSynchroniser { get { return callSynchroniser; } }
+ internal CallsSynchroniser CallsSynchroniser => this.callSynchroniser;
///
/// #2246: Discriminate between calls and meetings when adding and updating.
///
- internal MeetingsSynchroniser MeetingsSynchroniser { get { return meetingSynchroniser; } }
+ internal MeetingsSynchroniser MeetingsSynchroniser => this.meetingSynchroniser;
+
+ internal ContactSynchroniser ContactsSynchroniser => this.contactSynchroniser;
///
/// Internationalisation (118n) strings dictionary
@@ -130,8 +133,8 @@ public bool HasCrmUserSession
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
- /* we need logging before we start the daemon */
- StartLogging();
+ /* we need logging before we start the daemon */
+ StartLogging();
DaemonWorker.Instance.AddTask(new DeferredStartupAction());
}
@@ -199,6 +202,11 @@ private void Prepare()
}
}
+ internal void ManualSyncContact()
+ {
+ new ManualSyncContactForm(string.Join("; ", SelectedContacts.Select(x => $"{x.FullName}, {x.Email1Address}"))).ShowDialog();
+ }
+
///
/// Check whether an upgrade of settings is required, and if so, do it.
///
@@ -417,7 +425,7 @@ private IEnumerable GetLogHeader()
private IEnumerable GetKeySettings()
{
- yield return catalogue.GetString("Auto-archiving: ") +
+ yield return catalogue.GetString("Auto-archiving: ") +
(Settings.Default.AutoArchive ? catalogue.GetString("ON") : catalogue.GetString("off"));
yield return catalogue.GetString("Logging level: {0}", Settings.Default.LogLevel);
}
@@ -467,12 +475,12 @@ public void StopUnconfiguredSynchronisationProcesses()
/// The synchroniser to start.
private void StartSynchroniserIfConfigured(Synchroniser synchroniser)
{
- if (synchroniser != null &&
+ if (synchroniser != null &&
synchroniser.Direction != SyncDirection.Direction.Neither &&
!synchroniser.IsActive)
{
- DoOrLogError(() =>
- synchroniser.Start(),
+ DoOrLogError(() =>
+ synchroniser.Start(),
catalogue.GetString("Starting {0}", new object[] { synchroniser.GetType().Name }));
}
}
@@ -689,7 +697,7 @@ private void UnregisterEvents()
try
{
Log.Info(catalogue.GetString("{0}: Removing context menu display event handler", methodName));
- this.Application.ItemContextMenuDisplay -=
+ this.Application.ItemContextMenuDisplay -=
new Outlook.ApplicationEvents_11_ItemContextMenuDisplayEventHandler(this.Application_ItemContextMenuDisplay);
}
catch (Exception ex)
@@ -704,7 +712,7 @@ private void UnregisterEvents()
{
Log.Info(catalogue.GetString("{0}: Removing new mail event handler", methodName));
- Outlook.ApplicationEvents_11_NewMailExEventHandler handler =
+ Outlook.ApplicationEvents_11_NewMailExEventHandler handler =
new Outlook.ApplicationEvents_11_NewMailExEventHandler(this.Application_NewMail);
if (handler != null)
@@ -847,7 +855,7 @@ private void Application_NewMail(string EntryID)
if (item is Outlook.MailItem && Properties.Settings.Default.AutoArchive)
{
- ProcessNewMailItem( EmailArchiveReason.Inbound,
+ ProcessNewMailItem(EmailArchiveReason.Inbound,
item as Outlook.MailItem,
Settings.Default.ExcludedEmails);
}
@@ -917,12 +925,12 @@ public bool Authenticate()
{
if (Properties.Settings.Default.Host != String.Empty)
{
- SuiteCRMUserSession =
+ SuiteCRMUserSession =
new SuiteCRMClient.UserSession(
Properties.Settings.Default.Host,
Properties.Settings.Default.Username,
- Properties.Settings.Default.Password,
- Properties.Settings.Default.LDAPKey,
+ Properties.Settings.Default.Password,
+ Properties.Settings.Default.LDAPKey,
ThisAddIn.AddInTitle,
log,
Properties.Settings.Default.RestTimeout);
@@ -955,10 +963,10 @@ public bool Authenticate()
// We don't have a URL to connect to, dummy the connection.
SuiteCRMUserSession =
new SuiteCRMClient.UserSession(
- String.Empty,
- String.Empty,
- String.Empty,
- String.Empty,
+ String.Empty,
+ String.Empty,
+ String.Empty,
+ String.Empty,
ThisAddIn.AddInTitle,
log,
Properties.Settings.Default.RestTimeout);
diff --git a/SuiteCRMAddInWixSetup/Product.wxs b/SuiteCRMAddInWixSetup/Product.wxs
index 2571d3a6..b7fe3d6d 100644
--- a/SuiteCRMAddInWixSetup/Product.wxs
+++ b/SuiteCRMAddInWixSetup/Product.wxs
@@ -4,7 +4,7 @@
Id="A784C437-58CF-4495-BE4A-F77657600001"
Name="SuiteCRMAddIn"
Language="1033"
- Version="3.0.19.48"
+ Version="3.0.19.75"
Manufacturer="SalesAgility"
UpgradeCode="F50E9CEB-D641-4FC6-8E16-483505C3455A">
diff --git a/SuiteCRMClient/Properties/AssemblyInfo.cs b/SuiteCRMClient/Properties/AssemblyInfo.cs
index 3679dff6..79edff93 100644
--- a/SuiteCRMClient/Properties/AssemblyInfo.cs
+++ b/SuiteCRMClient/Properties/AssemblyInfo.cs
@@ -31,5 +31,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("3.0.19.48")]
+[assembly: AssemblyVersion("3.0.19.75")]
[assembly: AssemblyFileVersion("1.0.0.0")]