diff --git a/Source/Libraries/GSF.SortedTreeStore/Properties/AssemblyInfo.cs b/Source/Libraries/GSF.SortedTreeStore/Properties/AssemblyInfo.cs index 3d440f5cf5..93791201d8 100755 --- a/Source/Libraries/GSF.SortedTreeStore/Properties/AssemblyInfo.cs +++ b/Source/Libraries/GSF.SortedTreeStore/Properties/AssemblyInfo.cs @@ -44,4 +44,5 @@ [assembly: InternalsVisibleTo("GSF.SortedTreeStore.Test")] [assembly: InternalsVisibleTo("openHistorian.Adapters")] [assembly: InternalsVisibleTo("openHistorian.PerformanceTests")] -[assembly: InternalsVisibleTo("ArchiveIntegrityChecker")] \ No newline at end of file +[assembly: InternalsVisibleTo("ArchiveIntegrityChecker")] +[assembly: InternalsVisibleTo("OHTransfer")] \ No newline at end of file diff --git a/Source/Libraries/GSF.SortedTreeStore/Snap/Services/Reader/SequentialReaderStream'2.cs b/Source/Libraries/GSF.SortedTreeStore/Snap/Services/Reader/SequentialReaderStream'2.cs index d63c7ae4ea..fdbe5ffb08 100755 --- a/Source/Libraries/GSF.SortedTreeStore/Snap/Services/Reader/SequentialReaderStream'2.cs +++ b/Source/Libraries/GSF.SortedTreeStore/Snap/Services/Reader/SequentialReaderStream'2.cs @@ -202,9 +202,20 @@ private bool ReadCatchAll(TKey key, TValue value) m_pointCount = 0; } - TryAgain: + long retries = 0; + + TryAgain: if (!m_timedOut) { + retries++; + + if (retries >= 10000) + { + m_workerThreadSynchronization.PulseSafeToCallback(); + Interlocked.Add(ref Stats.PointsScanned, retries); + retries = 0; + } + if (m_keyMatchIsUniverse) { if (m_firstTableScanner is null) diff --git a/Source/Tools/OHTransfer/App.config b/Source/Tools/OHTransfer/App.config new file mode 100644 index 0000000000..193aecc675 --- /dev/null +++ b/Source/Tools/OHTransfer/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Source/Tools/OHTransfer/OHTransfer.Designer.cs b/Source/Tools/OHTransfer/OHTransfer.Designer.cs new file mode 100644 index 0000000000..f0cccb4dfc --- /dev/null +++ b/Source/Tools/OHTransfer/OHTransfer.Designer.cs @@ -0,0 +1,417 @@ +namespace OHTransfer +{ + partial class OHTransfer + { + /// + /// 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() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(OHTransfer)); + this.groupBoxMessages = new System.Windows.Forms.GroupBox(); + this.textBoxMessageOutput = new System.Windows.Forms.TextBox(); + this.groupBoxTransferConfiguration = new System.Windows.Forms.GroupBox(); + this.textBoxSourceFiles = new System.Windows.Forms.TextBox(); + this.labelSourceFilesLocation = new System.Windows.Forms.Label(); + this.buttonOpenSourceFilesLocation = new System.Windows.Forms.Button(); + this.labelToUTC = new System.Windows.Forms.Label(); + this.labelFromUTC = new System.Windows.Forms.Label(); + this.labelToDate = new System.Windows.Forms.Label(); + this.dateTimePickerTo = new System.Windows.Forms.DateTimePicker(); + this.labelFromDate = new System.Windows.Forms.Label(); + this.dateTimePickerFrom = new System.Windows.Forms.DateTimePicker(); + this.textBoxDestinationCSVMeasurements = new System.Windows.Forms.TextBox(); + this.labelDestinationCSVMeasurements = new System.Windows.Forms.Label(); + this.buttonOpenDestinationCSVMeasurementsFile = new System.Windows.Forms.Button(); + this.textBoxSourceCSVMeasurements = new System.Windows.Forms.TextBox(); + this.labelSourceCSVMeasurements = new System.Windows.Forms.Label(); + this.buttonOpenSourceCSVMeasurementsFile = new System.Windows.Forms.Button(); + this.textBoxDestinationFiles = new System.Windows.Forms.TextBox(); + this.labelDestinationFilesLocation = new System.Windows.Forms.Label(); + this.buttonOpenDestinationFilesLocation = new System.Windows.Forms.Button(); + this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.progressBar = new System.Windows.Forms.ProgressBar(); + this.buttonGo = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.groupBoxMessages.SuspendLayout(); + this.groupBoxTransferConfiguration.SuspendLayout(); + this.SuspendLayout(); + // + // groupBoxMessages + // + this.groupBoxMessages.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.groupBoxMessages.Controls.Add(this.textBoxMessageOutput); + this.groupBoxMessages.Location = new System.Drawing.Point(15, 196); + this.groupBoxMessages.Name = "groupBoxMessages"; + this.groupBoxMessages.Size = new System.Drawing.Size(777, 304); + this.groupBoxMessages.TabIndex = 3; + this.groupBoxMessages.TabStop = false; + this.groupBoxMessages.Text = "Messages"; + // + // textBoxMessageOutput + // + this.textBoxMessageOutput.BackColor = System.Drawing.SystemColors.WindowText; + this.textBoxMessageOutput.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBoxMessageOutput.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textBoxMessageOutput.ForeColor = System.Drawing.SystemColors.Window; + this.textBoxMessageOutput.Location = new System.Drawing.Point(3, 16); + this.textBoxMessageOutput.Multiline = true; + this.textBoxMessageOutput.Name = "textBoxMessageOutput"; + this.textBoxMessageOutput.ReadOnly = true; + this.textBoxMessageOutput.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textBoxMessageOutput.Size = new System.Drawing.Size(771, 285); + this.textBoxMessageOutput.TabIndex = 0; + this.textBoxMessageOutput.TabStop = false; + // + // groupBoxTransferConfiguration + // + this.groupBoxTransferConfiguration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBoxTransferConfiguration.Controls.Add(this.textBoxSourceFiles); + this.groupBoxTransferConfiguration.Controls.Add(this.labelSourceFilesLocation); + this.groupBoxTransferConfiguration.Controls.Add(this.buttonOpenSourceFilesLocation); + this.groupBoxTransferConfiguration.Controls.Add(this.labelToUTC); + this.groupBoxTransferConfiguration.Controls.Add(this.labelFromUTC); + this.groupBoxTransferConfiguration.Controls.Add(this.labelToDate); + this.groupBoxTransferConfiguration.Controls.Add(this.dateTimePickerTo); + this.groupBoxTransferConfiguration.Controls.Add(this.labelFromDate); + this.groupBoxTransferConfiguration.Controls.Add(this.dateTimePickerFrom); + this.groupBoxTransferConfiguration.Controls.Add(this.textBoxDestinationCSVMeasurements); + this.groupBoxTransferConfiguration.Controls.Add(this.labelDestinationCSVMeasurements); + this.groupBoxTransferConfiguration.Controls.Add(this.buttonOpenDestinationCSVMeasurementsFile); + this.groupBoxTransferConfiguration.Controls.Add(this.textBoxSourceCSVMeasurements); + this.groupBoxTransferConfiguration.Controls.Add(this.labelSourceCSVMeasurements); + this.groupBoxTransferConfiguration.Controls.Add(this.buttonOpenSourceCSVMeasurementsFile); + this.groupBoxTransferConfiguration.Controls.Add(this.textBoxDestinationFiles); + this.groupBoxTransferConfiguration.Controls.Add(this.labelDestinationFilesLocation); + this.groupBoxTransferConfiguration.Controls.Add(this.buttonOpenDestinationFilesLocation); + this.groupBoxTransferConfiguration.Location = new System.Drawing.Point(18, 12); + this.groupBoxTransferConfiguration.Name = "groupBoxTransferConfiguration"; + this.groupBoxTransferConfiguration.Size = new System.Drawing.Size(775, 178); + this.groupBoxTransferConfiguration.TabIndex = 1; + this.groupBoxTransferConfiguration.TabStop = false; + this.groupBoxTransferConfiguration.Text = "Transfer Configuration"; + // + // textBoxSourceFiles + // + this.textBoxSourceFiles.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxSourceFiles.Location = new System.Drawing.Point(178, 25); + this.textBoxSourceFiles.Name = "textBoxSourceFiles"; + this.textBoxSourceFiles.Size = new System.Drawing.Size(547, 20); + this.textBoxSourceFiles.TabIndex = 1; + // + // labelSourceFilesLocation + // + this.labelSourceFilesLocation.AutoSize = true; + this.labelSourceFilesLocation.Location = new System.Drawing.Point(73, 28); + this.labelSourceFilesLocation.Name = "labelSourceFilesLocation"; + this.labelSourceFilesLocation.Size = new System.Drawing.Size(105, 13); + this.labelSourceFilesLocation.TabIndex = 0; + this.labelSourceFilesLocation.Text = "&Source files location:"; + this.labelSourceFilesLocation.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // buttonOpenSourceFilesLocation + // + this.buttonOpenSourceFilesLocation.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOpenSourceFilesLocation.Font = new System.Drawing.Font("Arial", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonOpenSourceFilesLocation.Location = new System.Drawing.Point(726, 22); + this.buttonOpenSourceFilesLocation.Name = "buttonOpenSourceFilesLocation"; + this.buttonOpenSourceFilesLocation.Size = new System.Drawing.Size(28, 23); + this.buttonOpenSourceFilesLocation.TabIndex = 2; + this.buttonOpenSourceFilesLocation.Text = "..."; + this.buttonOpenSourceFilesLocation.TextAlign = System.Drawing.ContentAlignment.TopCenter; + this.buttonOpenSourceFilesLocation.UseVisualStyleBackColor = true; + this.buttonOpenSourceFilesLocation.Click += new System.EventHandler(this.buttonOpenSourceFilesLocation_Click); + // + // labelToUTC + // + this.labelToUTC.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.labelToUTC.AutoSize = true; + this.labelToUTC.Location = new System.Drawing.Point(727, 144); + this.labelToUTC.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.labelToUTC.Name = "labelToUTC"; + this.labelToUTC.Size = new System.Drawing.Size(29, 13); + this.labelToUTC.TabIndex = 17; + this.labelToUTC.Text = "UTC"; + this.labelToUTC.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelFromUTC + // + this.labelFromUTC.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.labelFromUTC.AutoSize = true; + this.labelFromUTC.Location = new System.Drawing.Point(517, 144); + this.labelFromUTC.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.labelFromUTC.Name = "labelFromUTC"; + this.labelFromUTC.Size = new System.Drawing.Size(29, 13); + this.labelFromUTC.TabIndex = 16; + this.labelFromUTC.Text = "UTC"; + this.labelFromUTC.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelToDate + // + this.labelToDate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.labelToDate.AutoSize = true; + this.labelToDate.Location = new System.Drawing.Point(559, 144); + this.labelToDate.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.labelToDate.Name = "labelToDate"; + this.labelToDate.Size = new System.Drawing.Size(23, 13); + this.labelToDate.TabIndex = 14; + this.labelToDate.Text = "&To:"; + this.labelToDate.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // dateTimePickerTo + // + this.dateTimePickerTo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.dateTimePickerTo.CustomFormat = "yyyy-MM-dd HH:mm:ss"; + this.dateTimePickerTo.Format = System.Windows.Forms.DateTimePickerFormat.Custom; + this.dateTimePickerTo.Location = new System.Drawing.Point(584, 141); + this.dateTimePickerTo.Name = "dateTimePickerTo"; + this.dateTimePickerTo.Size = new System.Drawing.Size(142, 20); + this.dateTimePickerTo.TabIndex = 15; + // + // labelFromDate + // + this.labelFromDate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.labelFromDate.AutoSize = true; + this.labelFromDate.Location = new System.Drawing.Point(339, 144); + this.labelFromDate.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.labelFromDate.Name = "labelFromDate"; + this.labelFromDate.Size = new System.Drawing.Size(33, 13); + this.labelFromDate.TabIndex = 12; + this.labelFromDate.Text = "&From:"; + this.labelFromDate.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // dateTimePickerFrom + // + this.dateTimePickerFrom.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.dateTimePickerFrom.CustomFormat = "yyyy-MM-dd HH:mm:ss"; + this.dateTimePickerFrom.Format = System.Windows.Forms.DateTimePickerFormat.Custom; + this.dateTimePickerFrom.Location = new System.Drawing.Point(375, 141); + this.dateTimePickerFrom.Name = "dateTimePickerFrom"; + this.dateTimePickerFrom.Size = new System.Drawing.Size(142, 20); + this.dateTimePickerFrom.TabIndex = 13; + // + // textBoxDestinationCSVMeasurements + // + this.textBoxDestinationCSVMeasurements.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxDestinationCSVMeasurements.Location = new System.Drawing.Point(179, 109); + this.textBoxDestinationCSVMeasurements.Name = "textBoxDestinationCSVMeasurements"; + this.textBoxDestinationCSVMeasurements.Size = new System.Drawing.Size(547, 20); + this.textBoxDestinationCSVMeasurements.TabIndex = 10; + // + // labelDestinationCSVMeasurements + // + this.labelDestinationCSVMeasurements.AutoSize = true; + this.labelDestinationCSVMeasurements.Location = new System.Drawing.Point(19, 112); + this.labelDestinationCSVMeasurements.Name = "labelDestinationCSVMeasurements"; + this.labelDestinationCSVMeasurements.Size = new System.Drawing.Size(159, 13); + this.labelDestinationCSVMeasurements.TabIndex = 9; + this.labelDestinationCSVMeasurements.Text = "&Destination CSV Measurements:"; + this.labelDestinationCSVMeasurements.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // buttonOpenDestinationCSVMeasurementsFile + // + this.buttonOpenDestinationCSVMeasurementsFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOpenDestinationCSVMeasurementsFile.Font = new System.Drawing.Font("Arial", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonOpenDestinationCSVMeasurementsFile.Location = new System.Drawing.Point(726, 108); + this.buttonOpenDestinationCSVMeasurementsFile.Name = "buttonOpenDestinationCSVMeasurementsFile"; + this.buttonOpenDestinationCSVMeasurementsFile.Size = new System.Drawing.Size(28, 23); + this.buttonOpenDestinationCSVMeasurementsFile.TabIndex = 11; + this.buttonOpenDestinationCSVMeasurementsFile.Text = "..."; + this.buttonOpenDestinationCSVMeasurementsFile.TextAlign = System.Drawing.ContentAlignment.TopCenter; + this.buttonOpenDestinationCSVMeasurementsFile.UseVisualStyleBackColor = true; + this.buttonOpenDestinationCSVMeasurementsFile.Click += new System.EventHandler(this.buttonOpenDestinationCSVMeasurementsFile_Click); + // + // textBoxSourceCSVMeasurements + // + this.textBoxSourceCSVMeasurements.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxSourceCSVMeasurements.Location = new System.Drawing.Point(179, 80); + this.textBoxSourceCSVMeasurements.Name = "textBoxSourceCSVMeasurements"; + this.textBoxSourceCSVMeasurements.Size = new System.Drawing.Size(547, 20); + this.textBoxSourceCSVMeasurements.TabIndex = 7; + // + // labelSourceCSVMeasurements + // + this.labelSourceCSVMeasurements.AutoSize = true; + this.labelSourceCSVMeasurements.Location = new System.Drawing.Point(38, 83); + this.labelSourceCSVMeasurements.Name = "labelSourceCSVMeasurements"; + this.labelSourceCSVMeasurements.Size = new System.Drawing.Size(140, 13); + this.labelSourceCSVMeasurements.TabIndex = 6; + this.labelSourceCSVMeasurements.Text = "&Source CSV Measurements:"; + this.labelSourceCSVMeasurements.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // buttonOpenSourceCSVMeasurementsFile + // + this.buttonOpenSourceCSVMeasurementsFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOpenSourceCSVMeasurementsFile.Font = new System.Drawing.Font("Arial", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonOpenSourceCSVMeasurementsFile.Location = new System.Drawing.Point(726, 79); + this.buttonOpenSourceCSVMeasurementsFile.Name = "buttonOpenSourceCSVMeasurementsFile"; + this.buttonOpenSourceCSVMeasurementsFile.Size = new System.Drawing.Size(28, 23); + this.buttonOpenSourceCSVMeasurementsFile.TabIndex = 8; + this.buttonOpenSourceCSVMeasurementsFile.Text = "..."; + this.buttonOpenSourceCSVMeasurementsFile.TextAlign = System.Drawing.ContentAlignment.TopCenter; + this.buttonOpenSourceCSVMeasurementsFile.UseVisualStyleBackColor = true; + this.buttonOpenSourceCSVMeasurementsFile.Click += new System.EventHandler(this.buttonOpenSourceCSVMeasurementsFile_Click); + // + // textBoxDestinationFiles + // + this.textBoxDestinationFiles.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxDestinationFiles.Location = new System.Drawing.Point(178, 53); + this.textBoxDestinationFiles.Name = "textBoxDestinationFiles"; + this.textBoxDestinationFiles.Size = new System.Drawing.Size(547, 20); + this.textBoxDestinationFiles.TabIndex = 4; + // + // labelDestinationFilesLocation + // + this.labelDestinationFilesLocation.AutoSize = true; + this.labelDestinationFilesLocation.Location = new System.Drawing.Point(54, 56); + this.labelDestinationFilesLocation.Name = "labelDestinationFilesLocation"; + this.labelDestinationFilesLocation.Size = new System.Drawing.Size(124, 13); + this.labelDestinationFilesLocation.TabIndex = 3; + this.labelDestinationFilesLocation.Text = "&Destination files location:"; + this.labelDestinationFilesLocation.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // buttonOpenDestinationFilesLocation + // + this.buttonOpenDestinationFilesLocation.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOpenDestinationFilesLocation.Font = new System.Drawing.Font("Arial", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonOpenDestinationFilesLocation.Location = new System.Drawing.Point(726, 50); + this.buttonOpenDestinationFilesLocation.Name = "buttonOpenDestinationFilesLocation"; + this.buttonOpenDestinationFilesLocation.Size = new System.Drawing.Size(28, 23); + this.buttonOpenDestinationFilesLocation.TabIndex = 5; + this.buttonOpenDestinationFilesLocation.Text = "..."; + this.buttonOpenDestinationFilesLocation.TextAlign = System.Drawing.ContentAlignment.TopCenter; + this.buttonOpenDestinationFilesLocation.UseVisualStyleBackColor = true; + this.buttonOpenDestinationFilesLocation.Click += new System.EventHandler(this.buttonOpenDestinationFilesLocation_Click); + // + // toolTip + // + this.toolTip.AutomaticDelay = 200; + this.toolTip.AutoPopDelay = 20000; + this.toolTip.InitialDelay = 200; + this.toolTip.ReshowDelay = 40; + // + // openFileDialog + // + this.openFileDialog.DefaultExt = "csv"; + this.openFileDialog.Filter = "\"CSV files|*.csv|All files|*.*"; + // + // progressBar + // + this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar.Location = new System.Drawing.Point(15, 506); + this.progressBar.Name = "progressBar"; + this.progressBar.Size = new System.Drawing.Size(697, 23); + this.progressBar.TabIndex = 4; + // + // buttonGo + // + this.buttonGo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonGo.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonGo.Location = new System.Drawing.Point(718, 506); + this.buttonGo.Name = "buttonGo"; + this.buttonGo.Size = new System.Drawing.Size(75, 23); + this.buttonGo.TabIndex = 2; + this.buttonGo.Text = "&Go!"; + this.buttonGo.UseVisualStyleBackColor = true; + this.buttonGo.Click += new System.EventHandler(this.buttonGo_Click); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonCancel.Location = new System.Drawing.Point(718, 506); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 5; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // OHTransfer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(804, 541); + this.Controls.Add(this.progressBar); + this.Controls.Add(this.buttonGo); + this.Controls.Add(this.groupBoxTransferConfiguration); + this.Controls.Add(this.groupBoxMessages); + this.Controls.Add(this.buttonCancel); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MinimumSize = new System.Drawing.Size(720, 480); + this.Name = "OHTransfer"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "openHistorian Data Transfer"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OHTransfer_FormClosing); + this.Load += new System.EventHandler(this.OHTransfer_Load); + this.groupBoxMessages.ResumeLayout(false); + this.groupBoxMessages.PerformLayout(); + this.groupBoxTransferConfiguration.ResumeLayout(false); + this.groupBoxTransferConfiguration.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.GroupBox groupBoxMessages; + private System.Windows.Forms.TextBox textBoxMessageOutput; + private System.Windows.Forms.GroupBox groupBoxTransferConfiguration; + private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog; + private System.Windows.Forms.ToolTip toolTip; + private System.Windows.Forms.TextBox textBoxDestinationCSVMeasurements; + private System.Windows.Forms.Label labelDestinationCSVMeasurements; + private System.Windows.Forms.Button buttonOpenDestinationCSVMeasurementsFile; + private System.Windows.Forms.TextBox textBoxSourceCSVMeasurements; + private System.Windows.Forms.Label labelSourceCSVMeasurements; + private System.Windows.Forms.OpenFileDialog openFileDialog; + private System.Windows.Forms.ProgressBar progressBar; + private System.Windows.Forms.Button buttonGo; + private System.Windows.Forms.Button buttonOpenSourceCSVMeasurementsFile; + private System.Windows.Forms.TextBox textBoxDestinationFiles; + private System.Windows.Forms.Label labelDestinationFilesLocation; + private System.Windows.Forms.Button buttonOpenDestinationFilesLocation; + private System.Windows.Forms.DateTimePicker dateTimePickerFrom; + private System.Windows.Forms.Label labelToDate; + private System.Windows.Forms.DateTimePicker dateTimePickerTo; + private System.Windows.Forms.Label labelFromDate; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Label labelToUTC; + private System.Windows.Forms.Label labelFromUTC; + private System.Windows.Forms.TextBox textBoxSourceFiles; + private System.Windows.Forms.Label labelSourceFilesLocation; + private System.Windows.Forms.Button buttonOpenSourceFilesLocation; + } +} + diff --git a/Source/Tools/OHTransfer/OHTransfer.cs b/Source/Tools/OHTransfer/OHTransfer.cs new file mode 100644 index 0000000000..2b98f3bb9e --- /dev/null +++ b/Source/Tools/OHTransfer/OHTransfer.cs @@ -0,0 +1,690 @@ +//****************************************************************************************************** +// OHTransfer.cs - Gbtc +// +// Copyright © 2025, Grid Protection Alliance. All Rights Reserved. +// +// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See +// the NOTICE file distributed with this work for additional information regarding copyright ownership. +// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this +// file except in compliance with the License. You may obtain a copy of the License at: +// +// http://opensource.org/licenses/MIT +// +// Unless agreed to in writing, the subject software distributed under the License is distributed on an +// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the +// License for the specific language governing permissions and limitations. +// +// Code Modification History: +// ---------------------------------------------------------------------------------------------------- +// 08/12/2025 - J. Ritchie Carroll +// Generated original version of source code. +// +//****************************************************************************************************** +// ReSharper disable AccessToModifiedClosure +// ReSharper disable AccessToDisposedClosure + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using GSF; +using GSF.Configuration; +using GSF.IO; +using GSF.Snap; +using GSF.Snap.Filters; +using GSF.Snap.Services; +using GSF.Snap.Services.Reader; +using GSF.Snap.Storage; +using GSF.Threading; +using GSF.Units; +using GSF.Units.EE; +using GSF.Windows.Forms; +using openHistorian.Net; +using openHistorian.Snap; +using openHistorian.Snap.Definitions; +using CancellationToken = System.Threading.CancellationToken; + +namespace OHTransfer +{ + public partial class OHTransfer : Form + { + private CancellationTokenSource m_cancellationTokenSource; + private bool m_formClosing; + + private const int MonitoringInterval = 2000; // 2 seconds + private const int FeedbackInterval = 4000; // 4 seconds + + public OHTransfer() + { + InitializeComponent(); + + DateTime nowFromTopOfHour = DateTime.UtcNow.BaselinedTimestamp(BaselineTimeInterval.Hour); + dateTimePickerFrom.Value = nowFromTopOfHour.AddDays(-30); + dateTimePickerTo.Value = nowFromTopOfHour; + } + + private void OHTransfer_Load(object sender, EventArgs e) + { + CategorizedSettingsElementCollection settings = ConfigurationFile.Current.Settings["systemSettings"]; + + settings.Add("sourceFiles", textBoxSourceFiles.Text, "openHistorian 2.0 source files location", false, SettingScope.User); + settings.Add("destinationFiles", textBoxDestinationFiles.Text, "openHistorian 2.0 destination files location", false, SettingScope.User); + settings.Add("sourceCSVMeasurements", textBoxSourceCSVMeasurements.Text, "openHistorian 2.0 source CSV measurements export file", false, SettingScope.User); + settings.Add("destinationCSVMeasurements", textBoxDestinationCSVMeasurements.Text, "openHistorian 2.0 destination CSV measurements export file", false, SettingScope.User); + settings.Add("fromDate", dateTimePickerFrom.Value.ToString(dateTimePickerFrom.CustomFormat), "Start date for transfer", false, SettingScope.User); + settings.Add("toDate", dateTimePickerTo.Value.ToString(dateTimePickerTo.CustomFormat), "End date for transfer", false, SettingScope.User); + + textBoxSourceFiles.Text = settings["sourceFiles"].Value; + textBoxDestinationFiles.Text = settings["destinationFiles"].Value; + textBoxSourceCSVMeasurements.Text = settings["sourceCSVMeasurements"].Value; + textBoxDestinationCSVMeasurements.Text = settings["destinationCSVMeasurements"].Value; + dateTimePickerFrom.Value = DateTime.ParseExact(settings["fromDate"].Value, dateTimePickerFrom.CustomFormat, null, DateTimeStyles.AssumeUniversal); + dateTimePickerTo.Value = DateTime.ParseExact(settings["toDate"].Value, dateTimePickerTo.CustomFormat, null, DateTimeStyles.AssumeUniversal); + + this.RestoreLocation(); + } + + private void OHTransfer_FormClosing(object sender, FormClosingEventArgs e) + { + CategorizedSettingsElementCollection settings = ConfigurationFile.Current.Settings["systemSettings"]; + + m_formClosing = true; + + this.SaveLocation(); + + settings["sourceFiles"].Value = textBoxSourceFiles.Text; + settings["destinationFiles"].Value = textBoxDestinationFiles.Text; + settings["sourceCSVMeasurements"].Value = textBoxSourceCSVMeasurements.Text; + settings["destinationCSVMeasurements"].Value = textBoxDestinationCSVMeasurements.Text; + settings["fromDate"].Value = dateTimePickerFrom.Value.ToString(dateTimePickerFrom.CustomFormat); + settings["toDate"].Value = dateTimePickerTo.Value.ToString(dateTimePickerTo.CustomFormat); + + ConfigurationFile.Current.Save(); + + if (m_cancellationTokenSource is null) + return; + + Hide(); + m_cancellationTokenSource?.Cancel(); + Thread.Sleep((int)(MonitoringInterval * 1.5D)); + } + + private void buttonOpenSourceFilesLocation_Click(object sender, EventArgs e) + { + folderBrowserDialog.Description = "Find source location for existing openHistorian 2.0 archive files"; + + if (Directory.Exists(textBoxSourceFiles.Text)) + folderBrowserDialog.SelectedPath = textBoxSourceFiles.Text; + + if (folderBrowserDialog.ShowDialog(this) == DialogResult.OK) + textBoxSourceFiles.Text = folderBrowserDialog.SelectedPath; + + if (!textBoxSourceFiles.Text.EndsWith(Path.DirectorySeparatorChar.ToString())) + textBoxSourceFiles.Text += Path.DirectorySeparatorChar; + } + + private void buttonOpenDestinationFilesLocation_Click(object sender, EventArgs e) + { + folderBrowserDialog.Description = "Find destination location for new openHistorian 2.0 archive files"; + + if (Directory.Exists(textBoxDestinationFiles.Text)) + folderBrowserDialog.SelectedPath = textBoxDestinationFiles.Text; + + if (folderBrowserDialog.ShowDialog(this) == DialogResult.OK) + textBoxDestinationFiles.Text = folderBrowserDialog.SelectedPath; + + if (!textBoxDestinationFiles.Text.EndsWith(Path.DirectorySeparatorChar.ToString())) + textBoxDestinationFiles.Text += Path.DirectorySeparatorChar; + + if (!Directory.Exists(textBoxDestinationFiles.Text)) + Directory.CreateDirectory(textBoxDestinationFiles.Text); + } + + private void buttonOpenSourceCSVMeasurementsFile_Click(object sender, EventArgs e) + { + openFileDialog.Title = "Find source openHistorian 2.0 CSV measurements export file"; + openFileDialog.FileName = File.Exists(textBoxSourceCSVMeasurements.Text) ? textBoxSourceCSVMeasurements.Text : string.Empty; + + if (openFileDialog.ShowDialog(this) == DialogResult.OK) + textBoxSourceCSVMeasurements.Text = openFileDialog.FileName; + } + + private void buttonOpenDestinationCSVMeasurementsFile_Click(object sender, EventArgs e) + { + openFileDialog.Title = "Find destination openHistorian 2.0 CSV measurements export file"; + openFileDialog.FileName = File.Exists(textBoxDestinationCSVMeasurements.Text) ? textBoxDestinationCSVMeasurements.Text : string.Empty; + + if (openFileDialog.ShowDialog(this) == DialogResult.OK) + textBoxDestinationCSVMeasurements.Text = openFileDialog.FileName; + } + + private void buttonGo_Click(object sender, EventArgs e) + { + ClearUpdateMessages(); + UpdateProgressBar(0); + + if (string.IsNullOrWhiteSpace(textBoxSourceFiles.Text)) + { + MessageBox.Show("Please select a source location for existing openHistorian 2.0 archive files.", "Missing Source Location", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + if (string.IsNullOrWhiteSpace(textBoxDestinationFiles.Text)) + { + MessageBox.Show("Please select a destination location for new openHistorian 2.0 archive files.", "Missing Destination Location", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + if (string.IsNullOrWhiteSpace(textBoxSourceCSVMeasurements.Text)) + { + MessageBox.Show("Please select a source openHistorian 2.0 CSV measurements export file.", "Missing Source File", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + if (string.IsNullOrWhiteSpace(textBoxDestinationCSVMeasurements.Text)) + { + MessageBox.Show("Please select a destination openHistorian 2.0 CSV measurements export file.", "Missing Destination File", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + if (!Directory.Exists(textBoxDestinationFiles.Text)) + { + MessageBox.Show("The specified destination location does not exist.", "Invalid Destination Location", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + if (!File.Exists(textBoxSourceCSVMeasurements.Text)) + { + MessageBox.Show("The specified source openHistorian 2.0 CSV measurements export file does not exist.", "Invalid Source File", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + if (!File.Exists(textBoxDestinationCSVMeasurements.Text)) + { + MessageBox.Show("The specified destination openHistorian 2.0 CSV measurements export file does not exist.", "Invalid Destination File", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + DateTime startTime = dateTimePickerFrom.Value; + DateTime endTime = dateTimePickerTo.Value; + + if (endTime <= startTime) + { + MessageBox.Show("The end time must be greater than the start time.", "Invalid Time Range", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + long processStartTime = DateTime.UtcNow.Ticks; + string[] csvLines; + + // Read CSV measurements from source file + ShowUpdateMessage("Reading source CSV measurements file: {0}...", textBoxSourceCSVMeasurements.Text); + + try + { + csvLines = File.ReadAllLines(textBoxSourceCSVMeasurements.Text); + } + catch (Exception ex) + { + ShowUpdateMessage("Error reading source CSV measurements file: {0}", ex.Message); + return; + } + + // Parse ID and SignalReference columns from CSV lines into a dictionary using header row + (Dictionary sourceCSVData, string deviceName) = ParseCSVMeasurements(csvLines); + + if (sourceCSVData.Count == 0) + { + ShowUpdateMessage("No valid measurements found in source CSV file -- operation cancelled."); + return; + } + + // Read CSV measurements from destination file + ShowUpdateMessage("Reading destination CSV measurements file: {0}...", textBoxDestinationCSVMeasurements.Text); + + try + { + csvLines = File.ReadAllLines(textBoxDestinationCSVMeasurements.Text); + } + catch (Exception ex) + { + ShowUpdateMessage("Error reading destination CSV measurements file: {0}", ex.Message); + return; + } + + // Parse ID and SignalReference columns from CSV lines ulong a dictionary using header row + (Dictionary destinationCSVData, _) = ParseCSVMeasurements(csvLines); + + if (destinationCSVData.Count == 0) + { + ShowUpdateMessage("No valid measurements found in destination CSV file -- operation cancelled."); + return; + } + + // Find measurements by SignalReference.Kind + SignalReference.Index in source CSV that also exist in destination CSV + // where the result is source CSV historian ID to destination CSV historian ID mapping + Dictionary historianIDMapping = new(); + + // Pre-index destination signals for O(1) lookup by match key + Dictionary<(SignalKind Kind, int Index), ulong> signalReferenceIDMap = []; + Dictionary<(SignalKind Kind, int Index, string Acronym), ulong> calculatedSignalReferenceIDMap = []; + + foreach (KeyValuePair destinationEntry in destinationCSVData) + { + SignalReference destinationSignal = destinationEntry.Value; + + if (destinationSignal.Kind == SignalKind.Calculation) + calculatedSignalReferenceIDMap[(destinationSignal.Kind, destinationSignal.Index, destinationSignal.Acronym ?? string.Empty)] = destinationEntry.Key; + else + signalReferenceIDMap[(destinationSignal.Kind, destinationSignal.Index)] = destinationEntry.Key; + } + + foreach (KeyValuePair sourceEntry in sourceCSVData) + { + SignalReference sourceSignal = sourceEntry.Value; + + if (sourceSignal.Kind == SignalKind.Calculation) + { + if (calculatedSignalReferenceIDMap.TryGetValue((sourceSignal.Kind, sourceSignal.Index, sourceSignal.Acronym ?? string.Empty), out ulong destID)) + historianIDMapping[sourceEntry.Key] = destID; + } + else + { + if (signalReferenceIDMap.TryGetValue((sourceSignal.Kind, sourceSignal.Index), out ulong destID)) + historianIDMapping[sourceEntry.Key] = destID; + } + } + + if (historianIDMapping.Count == 0) + { + ShowUpdateMessage("No matching measurements found between source and destination CSV files -- operation cancelled."); + return; + } + + ShowUpdateMessage("Found {0:N0} matching measurements between source and destination CSV files.", historianIDMapping.Count); + + string sourcePath = textBoxSourceFiles.Text.Trim(); + string destinationPath = textBoxDestinationFiles.Text.Trim(); + bool processCompleted = false; + + m_cancellationTokenSource = new CancellationTokenSource(); + ICancellationToken monitorCancellationToken = null; + + new Thread(() => + { + try + { + EnableGoButton(false); + + CancellationToken cancellationToken = m_cancellationTokenSource.Token; + + int totalDays = (int)(endTime - startTime).TotalDays; + SetProgressMaximum(totalDays); + Stats.Clear(); + + const string InstanceName = "PPA"; + + // Establish archive information for this historian instance + HistorianServerDatabaseConfig archiveInfo = new(InstanceName, sourcePath, false) + { + TargetFileSize = (long)(1.5D * SI.Giga), + DirectoryMethod = ArchiveDirectoryMethod.YearThenMonth + }; + + HistorianServer server = new(archiveInfo); + SnapClient client = SnapClient.Connect(server.Host); + ClientDatabaseBase database = client.GetDatabase(InstanceName); + Dictionary attachedFiles = database.GetAllAttachedFiles() + .Where(file => file.EndTime > startTime && file.EndTime <= endTime) + .ToDictionary(file => file.Id); + + using ArchiveList archiveList = new(); + + archiveList.LoadFiles(attachedFiles.Values + .OrderBy(file => file.EndTime) + .Select(file => file.FileName)); + + ShowUpdateMessage("Found {0:N0} archives in source location covering specified time range.", attachedFiles.Count); + + SeekFilterBase timeFilter = TimestampSeekFilter.CreateFromRange(startTime, endTime); + MatchFilterBase pointFilter = PointIdMatchFilter.CreateFromList(historianIDMapping.Keys); + + using WorkerThreadSynchronization workerThreadSynchronization = new(); + using TranslatingStreamReader reader = new(archiveList, historianIDMapping, SortedTreeEngineReaderOptions.Default, timeFilter, pointFilter, workerThreadSynchronization); + + long lastStatusMessage = DateTime.UtcNow.Ticks; + + void readingMonitor() + { + if (cancellationToken.IsCancellationRequested || processCompleted) + { + reader.CancelReader(); + return; + } + + if (DateTime.UtcNow.Ticks - lastStatusMessage < FeedbackInterval * Ticks.PerMillisecond) + { + workerThreadSynchronization.RequestCallback(() => + { + lastStatusMessage = DateTime.UtcNow.Ticks; + + if (Stats.PointsReturned == 0L) + { + ShowUpdateMessage("\r\nScanning archives for points in specified time range, processing {0:N0} cache miss retries per second...", Stats.PointsScanned / ((DateTime.UtcNow.Ticks - processStartTime) / Ticks.PerSecond)); + } + else + { + ShowUpdateMessage("\r\nProcessed {0:N0} points so far, scanning at {1:N0} points per second:", Stats.PointsReturned, Stats.PointsReturned / ((DateTime.UtcNow.Ticks - processStartTime) / Ticks.PerSecond)); + + double processedDays = (reader.LastKey.TimestampAsDate - startTime).TotalDays; + + UpdateProgressBar((int)processedDays); + ShowUpdateMessage(" {0:0.00%} complete...", processedDays / totalDays); + } + }); + } + + monitorCancellationToken = new Action(readingMonitor).DelayAndExecute(MonitoringInterval); + } + + monitorCancellationToken = new Action(readingMonitor).DelayAndExecute(MonitoringInterval); + + string completeFileName = Path.Combine(destinationPath, $"{deviceName}-Exported.d2"); + string pendingFileName = Path.Combine(destinationPath, $"{FilePath.GetFileNameWithoutExtension(completeFileName)}.~d2i"); + + if (File.Exists(pendingFileName)) + File.Delete(pendingFileName); + + if (File.Exists(completeFileName)) + File.Delete(completeFileName); + + SortedTreeFileSimpleWriter.Create(pendingFileName, completeFileName, 4096, null, HistorianFileEncodingDefinition.TypeGuid, reader, FileFlags.GetStage(3)); + + Ticks processDuration = DateTime.UtcNow.Ticks - processStartTime; + processCompleted = true; + + ShowUpdateMessage("\r\nData transfer completed in {0}", processDuration.ToElapsedTimeString(2)); + UpdateProgressBar(totalDays); + } + catch (Exception ex) + { + ShowUpdateMessage("\r\nError during transfer: {0}", ex.Message); + } + finally + { + monitorCancellationToken?.Cancel(); + EnableGoButton(true); + } + }) + { + IsBackground = true + } + .Start(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + m_cancellationTokenSource.Cancel(); + ShowUpdateMessage("Transfer operation cancelled by user."); + } + + private (Dictionary csvData, string deviceName) ParseCSVMeasurements(string[] csvLines) + { + Dictionary csvData = new(); + + if (csvLines is null || csvLines.Length <= 1) + return (csvData, ""); + + // Parse header to find column indices using robust CSV parser + string[] headers = ParseCSVLine(csvLines[0]); + + int deviceIndex = Array.FindIndex(headers, header => header.Trim().Equals("Device", StringComparison.OrdinalIgnoreCase)); + + if (deviceIndex < 0) + { + ShowUpdateMessage("CSV header must contain 'Device' column."); + return (csvData, ""); + } + + // Validate that device names in all rows are the same + string firstDeviceName = null; + + for (int i = 1; i < csvLines.Length; i++) + { + if (string.IsNullOrWhiteSpace(csvLines[i])) + continue; + + string[] columns = ParseCSVLine(csvLines[i]); + + if (columns.Length <= deviceIndex) + continue; + + string deviceName = columns[deviceIndex].Trim(); + + if (string.IsNullOrEmpty(firstDeviceName)) + { + firstDeviceName = deviceName; + } + else if (!string.Equals(firstDeviceName, deviceName, StringComparison.OrdinalIgnoreCase)) + { + ShowUpdateMessage("All rows in CSV file must have the same 'Device' name. Export is designed to transfer one device at a time."); + return (csvData, ""); + } + } + + int idIndex = Array.FindIndex(headers, header => header.Trim().Equals("ID", StringComparison.OrdinalIgnoreCase)); + int signalRefIndex = Array.FindIndex(headers, header => header.Trim().Equals("SignalReference", StringComparison.OrdinalIgnoreCase)); + + if (idIndex < 0 || signalRefIndex < 0) + { + ShowUpdateMessage("CSV header must contain 'ID' and 'SignalReference' columns."); + return (csvData, ""); + } + + int maxColumnIndex = Math.Max(Math.Max(deviceIndex, idIndex), signalRefIndex); + int calcIndex = 1; + + // Parse data rows using robust CSV parser + for (int i = 1; i < csvLines.Length; i++) + { + if (string.IsNullOrWhiteSpace(csvLines[i])) + continue; + + string[] columns = ParseCSVLine(csvLines[i]); + + if (columns.Length <= maxColumnIndex) + continue; + + string idValue = columns[idIndex].Trim(); + + if (string.IsNullOrEmpty(idValue)) + continue; + + string[] parts = idValue.Split(':'); + + if (parts.Length != 2 || !ulong.TryParse(parts[1], out ulong id)) + { + ShowUpdateMessage("Invalid ID format in row {0}: {1}. Expected format is 'Source:ID'.", i + 1, idValue); + continue; + } + + string signalReferenceValue = columns[signalRefIndex].Trim(); + + if (string.IsNullOrEmpty(signalReferenceValue)) + continue; + + SignalReference signalReference = new(signalReferenceValue); + + if (signalReference.Kind == SignalKind.Unknown) + { + parts = signalReferenceValue.Split('-'); + + if (parts.Length > 1) + { + // Track matching acronyms for Calculation signals + signalReference.Acronym = parts[parts.Length - 1].Trim(); + signalReference.Kind = SignalKind.Calculation; + signalReference.Index = calcIndex++; + } + else + { + continue; // Skip invalid SignalReference + } + } + + csvData[id] = signalReference; + } + + return (csvData, firstDeviceName ?? ""); + } + + private static string[] ParseCSVLine(string line) + { + if (string.IsNullOrEmpty(line)) + return []; + + List fields = []; + StringBuilder current = new(); + bool inQuotes = false; + + for (int i = 0; i < line.Length; i++) + { + char c = line[i]; + + if (inQuotes) + { + if (c == '"') + { + // Check for escaped quote ("") + if (i + 1 < line.Length && line[i + 1] == '"') + { + current.Append('"'); + i++; // Skip the next quote + } + else + { + inQuotes = false; + } + } + else + { + current.Append(c); + } + } + else + { + switch (c) + { + case ',': + fields.Add(current.ToString()); + current.Clear(); + break; + case '"': + inQuotes = true; + break; + default: + current.Append(c); + break; + } + } + } + + fields.Add(current.ToString()); + + return fields.ToArray(); + } + + private void EnableGoButton(bool enabled) + { + if (m_formClosing) + return; + + if (InvokeRequired) + { + BeginInvoke(new Action(EnableGoButton), enabled); + } + else + { + buttonGo.Enabled = enabled; + buttonGo.Visible = enabled; + } + } + + private void UpdateProgressBar(int value) + { + if (m_formClosing) + return; + + if (InvokeRequired) + { + BeginInvoke(new Action(UpdateProgressBar), value); + } + else + { + if (value < progressBar.Minimum) + value = progressBar.Minimum; + + if (value > progressBar.Maximum) + progressBar.Maximum = value; + + progressBar.Value = value; + } + } + + private void SetProgressMaximum(int maximum) + { + if (m_formClosing) + return; + + if (InvokeRequired) + { + BeginInvoke(new Action(SetProgressMaximum), maximum); + } + else + { + progressBar.Maximum = maximum; + } + } + + private void ClearUpdateMessages() + { + if (m_formClosing) + return; + + if (InvokeRequired) + { + BeginInvoke(new Action(ClearUpdateMessages)); + } + else + { + lock (textBoxMessageOutput) + textBoxMessageOutput.Text = ""; + } + } + + private void ShowUpdateMessage(string message, params object[] args) + { + if (m_formClosing) + return; + + if (InvokeRequired) + { + BeginInvoke(new Action(ShowUpdateMessage), message, args); + } + else + { + StringBuilder outputText = new(); + + outputText.AppendFormat(message, args); + outputText.AppendLine(); + + lock (textBoxMessageOutput) + textBoxMessageOutput.AppendText(outputText.ToString()); + } + } + } +} diff --git a/Source/Tools/OHTransfer/OHTransfer.csproj b/Source/Tools/OHTransfer/OHTransfer.csproj new file mode 100644 index 0000000000..0549002286 --- /dev/null +++ b/Source/Tools/OHTransfer/OHTransfer.csproj @@ -0,0 +1,115 @@ + + + + + Debug + AnyCPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC} + WinExe + OHTransfer + OHTransfer + v4.8 + 512 + true + true + latest + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + OHTransfer.ico + + + + ..\..\Dependencies\GSF\GSF.Core.dll + + + ..\..\Dependencies\GSF\GSF.Windows.dll + + + + + + + + + + + + + + + + + Form + + + OHTransfer.cs + + + + + + OHTransfer.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + + {040e2ae7-021b-435a-adbf-06d07ee0a67d} + GSF.SortedTreeStore + + + {7b53c942-e891-461c-b09c-49faba82f19d} + openHistorian.Core + + + + + + + + \ No newline at end of file diff --git a/Source/Tools/OHTransfer/OHTransfer.ico b/Source/Tools/OHTransfer/OHTransfer.ico new file mode 100644 index 0000000000..e074a5092a Binary files /dev/null and b/Source/Tools/OHTransfer/OHTransfer.ico differ diff --git a/Source/Tools/OHTransfer/OHTransfer.resx b/Source/Tools/OHTransfer/OHTransfer.resx new file mode 100644 index 0000000000..d278b50a58 --- /dev/null +++ b/Source/Tools/OHTransfer/OHTransfer.resx @@ -0,0 +1,1165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + 24, 17 + + + 185, 17 + + + 277, 17 + + + + + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgADAABAAsJERwNgTCMEfdO9RX/UP0V/1D8Ff9Q/RX/TvQV/ylx + EO4MCwxMEBsNAAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAQsAAQALCBAbDYEvhxH2TvMV/1D9 + Ff9R/hX/OKcS/xAcDYcAAAoDCwcMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAALAAEA + CwgPGAyCLX8Q9E3xFP9J4xT/HUYOzAUACx4LCAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAcACwABAAsHDhUMbCp1EOssfhD7DREMYhIiDQAMCwwAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAsAAAAKBA0QDFQPFgx/CgYMEwsJDAAAAAAAAAAAAAAA + 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 + + + \ No newline at end of file diff --git a/Source/Tools/OHTransfer/OHTransfer.sln b/Source/Tools/OHTransfer/OHTransfer.sln new file mode 100644 index 0000000000..ff8aa0a553 --- /dev/null +++ b/Source/Tools/OHTransfer/OHTransfer.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36401.2 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OHTransfer", "OHTransfer.csproj", "{FE351919-B4A6-4D81-91CC-64BC1D588ECC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {365C2FB8-B1C5-4D4E-A5EA-2F8F759AC740} + EndGlobalSection +EndGlobal diff --git a/Source/Tools/OHTransfer/OHTransfer.sln.DotSettings b/Source/Tools/OHTransfer/OHTransfer.sln.DotSettings new file mode 100644 index 0000000000..7dbc342733 --- /dev/null +++ b/Source/Tools/OHTransfer/OHTransfer.sln.DotSettings @@ -0,0 +1,2 @@ + + CSV \ No newline at end of file diff --git a/Source/Tools/OHTransfer/Program.cs b/Source/Tools/OHTransfer/Program.cs new file mode 100644 index 0000000000..c290b1316b --- /dev/null +++ b/Source/Tools/OHTransfer/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace OHTransfer +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new OHTransfer()); + } + } +} diff --git a/Source/Tools/OHTransfer/Properties/AssemblyInfo.cs b/Source/Tools/OHTransfer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..5cfa672c5a --- /dev/null +++ b/Source/Tools/OHTransfer/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OHTransfer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OHTransfer")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fe351919-b4a6-4d81-91cc-64bc1d588ecc")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/Tools/OHTransfer/Properties/Resources.Designer.cs b/Source/Tools/OHTransfer/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..db3b947816 --- /dev/null +++ b/Source/Tools/OHTransfer/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace OHTransfer.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OHTransfer.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Source/Tools/OHTransfer/Properties/Resources.resx b/Source/Tools/OHTransfer/Properties/Resources.resx new file mode 100644 index 0000000000..af7dbebbac --- /dev/null +++ b/Source/Tools/OHTransfer/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Tools/OHTransfer/Properties/Settings.Designer.cs b/Source/Tools/OHTransfer/Properties/Settings.Designer.cs new file mode 100644 index 0000000000..e8cafbbd4b --- /dev/null +++ b/Source/Tools/OHTransfer/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace OHTransfer.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Source/Tools/OHTransfer/Properties/Settings.settings b/Source/Tools/OHTransfer/Properties/Settings.settings new file mode 100644 index 0000000000..39645652af --- /dev/null +++ b/Source/Tools/OHTransfer/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Source/Tools/OHTransfer/TranslatingStreamReader.cs b/Source/Tools/OHTransfer/TranslatingStreamReader.cs new file mode 100644 index 0000000000..c1993f6910 --- /dev/null +++ b/Source/Tools/OHTransfer/TranslatingStreamReader.cs @@ -0,0 +1,69 @@ +//****************************************************************************************************** +// TranslatingStreamReader.cs - Gbtc +// +// Copyright © 2025, Grid Protection Alliance. All Rights Reserved. +// +// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See +// the NOTICE file distributed with this work for additional information regarding copyright ownership. +// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this +// file except in compliance with the License. You may obtain a copy of the License at: +// +// http://opensource.org/licenses/MIT +// +// Unless agreed to in writing, the subject software distributed under the License is distributed on an +// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the +// License for the specific language governing permissions and limitations. +// +// Code Modification History: +// ---------------------------------------------------------------------------------------------------- +// 08/13/2025 - J. Ritchie Carroll +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.Collections.Generic; +using GSF.Snap.Filters; +using GSF.Snap.Services; +using GSF.Snap.Services.Reader; +using GSF.Threading; +using openHistorian.Snap; + +namespace OHTransfer; + +/// +/// Represents a sequential reader stream for reading historian data from an archive list that +/// translates source IDs to destination IDs using the . +/// +/// +/// We derive a specific implementation of this class so we can translate source IDs to +/// destination IDs and also track last processed key in the stream for progress reporting. +/// +internal class TranslatingStreamReader( + ArchiveList archiveList, + Dictionary historianIDMapping, + SortedTreeEngineReaderOptions readerOptions = null, + SeekFilterBase keySeekFilter = null, + MatchFilterBase keyMatchFilter = null, + WorkerThreadSynchronization workerThreadSynchronization = null) : + SequentialReaderStream( + archiveList, + readerOptions, + keySeekFilter, + keyMatchFilter, + workerThreadSynchronization) +{ + public HistorianKey LastKey = new(); + + /// + protected override bool ReadNext(HistorianKey key, HistorianValue value) + { + bool result = base.ReadNext(key, value); + + if (historianIDMapping.TryGetValue(key.PointID, out ulong destinationPointID)) + key.PointID = destinationPointID; + + LastKey = key; + + return result; + } +} \ No newline at end of file diff --git a/Source/Tools/OHTransfer/openHistorian.ico b/Source/Tools/OHTransfer/openHistorian.ico new file mode 100644 index 0000000000..9efe34e937 Binary files /dev/null and b/Source/Tools/OHTransfer/openHistorian.ico differ diff --git a/Source/openHistorian.sln b/Source/openHistorian.sln index 80a7c3120c..03cb2fd8ea 100755 --- a/Source/openHistorian.sln +++ b/Source/openHistorian.sln @@ -537,6 +537,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docker", "Docker", "{7F01BE DockerReadMe.md = DockerReadMe.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OHTransfer", "Tools\OHTransfer\OHTransfer.csproj", "{FE351919-B4A6-4D81-91CC-64BC1D588ECC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1200,6 +1202,24 @@ Global {7F5BBF4C-A27D-4367-9D1E-95AEA45EC58B}.Release|x64.Build.0 = Release|Any CPU {7F5BBF4C-A27D-4367-9D1E-95AEA45EC58B}.Release|x86.ActiveCfg = Release|Any CPU {7F5BBF4C-A27D-4367-9D1E-95AEA45EC58B}.Release|x86.Build.0 = Release|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Debug|x64.ActiveCfg = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Debug|x64.Build.0 = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Debug|x86.ActiveCfg = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Debug|x86.Build.0 = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Mono|Any CPU.ActiveCfg = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Mono|Any CPU.Build.0 = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Mono|x64.ActiveCfg = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Mono|x64.Build.0 = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Mono|x86.ActiveCfg = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Mono|x86.Build.0 = Debug|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Release|Any CPU.Build.0 = Release|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Release|x64.ActiveCfg = Release|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Release|x64.Build.0 = Release|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Release|x86.ActiveCfg = Release|Any CPU + {FE351919-B4A6-4D81-91CC-64BC1D588ECC}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1260,6 +1280,7 @@ Global {D61BBB31-74A7-498D-8C36-FB18C72609F8} = {880E5A69-EE1E-46EC-838F-783F188D8B49} {9DE89239-FEDC-4218-8770-1167A22EC999} = {550621C3-C903-4405-971A-DC4BAA286BA0} {7F5BBF4C-A27D-4367-9D1E-95AEA45EC58B} = {3A952272-B64C-48E0-9CB2-0130AC28D72E} + {FE351919-B4A6-4D81-91CC-64BC1D588ECC} = {3A952272-B64C-48E0-9CB2-0130AC28D72E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {CA73B94E-45F7-4272-BCA2-4B4386CC92B2}