diff --git a/.gitignore b/.gitignore index 03900605..9416d3cc 100644 --- a/.gitignore +++ b/.gitignore @@ -233,4 +233,4 @@ readme.txt **/src/OpenSEE/NUglify.dll **/src/OpenSEE/web.config.backup -**/src/OpenSee/scripts/*.js \ No newline at end of file +**/src/OpenSee/wwwroot/scripts/*.js \ No newline at end of file diff --git a/src/Libraries/FaultAlgorithms/Conductor.cs b/src/Libraries/FaultAlgorithms/Conductor.cs new file mode 100644 index 00000000..5b5a24fe --- /dev/null +++ b/src/Libraries/FaultAlgorithms/Conductor.cs @@ -0,0 +1,122 @@ +//********************************************************************************************************************* +// Conductor.cs +// Version 1.1 and subsequent releases +// +// Copyright © 2013, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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. +// +// -------------------------------------------------------------------------------------------------------------------- +// +// Version 1.0 +// +// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. +// +// openFLE ("this software") is licensed under BSD 3-Clause license. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// • Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// • Neither the name of the Electric Power Research Institute, Inc. (“EPRI”) nor the names of its contributors +// may be used to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// +// This software incorporates work covered by the following copyright and permission notice: +// +// • TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov +// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved. +// +// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); +// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may +// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. +// +// TVA Code Library is provided by the copyright holders and contributors "as is" and any express +// or implied warranties, including, but not limited to, the implied warranties of merchantability +// and fitness for a particular purpose are disclaimed. +// +//********************************************************************************************************************* +// +// Code Modification History: +// ------------------------------------------------------------------------------------------------------------------- +// 06/14/2012 - Stephen C. Wills, Grid Protection Alliance +// Generated original version of source code. +// +//********************************************************************************************************************* + +namespace FaultAlgorithms +{ + /// + /// Contains data for both the voltage + /// and current on a conductor. + /// + public class Conductor + { + #region [ Members ] + + // Fields + + /// + /// One cycle of voltage data. + /// + public Cycle V; + + /// + /// One cycle of current data. + /// + public Cycle I; + + #endregion + + #region [ Constructors ] + + /// + /// Creates a new instance of the class. + /// + public Conductor() + { + V = new Cycle(); + I = new Cycle(); + } + + /// + /// Creates a new instance of the class. + /// + /// The index of the cycle to be calculated. + /// The value to divide from the sample rate to determine the starting location of the cycle. + /// The frequency of the sine wave during this cycle. + /// The voltage data points. + /// The current data points. + public Conductor(int cycleIndex, int sampleRateDivisor, double frequency, MeasurementData voltageData, MeasurementData currentData) + { + int vStart = cycleIndex * (voltageData.SampleRate / sampleRateDivisor); + int iStart = cycleIndex * (currentData.SampleRate / sampleRateDivisor); + V = new Cycle(vStart, frequency, voltageData); + I = new Cycle(iStart, frequency, currentData); + } + + #endregion + } +} diff --git a/src/Libraries/FaultAlgorithms/Cycle.cs b/src/Libraries/FaultAlgorithms/Cycle.cs new file mode 100644 index 00000000..91db47e8 --- /dev/null +++ b/src/Libraries/FaultAlgorithms/Cycle.cs @@ -0,0 +1,200 @@ +//********************************************************************************************************************* +// Cycle.cs +// Version 1.1 and subsequent releases +// +// Copyright 2013, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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. +// +// -------------------------------------------------------------------------------------------------------------------- +// +// Version 1.0 +// +// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. +// +// openFLE ("this software") is licensed under BSD 3-Clause license. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// Neither the name of the Electric Power Research Institute, Inc. (EPRI) nor the names of its contributors +// may be used to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// +// This software incorporates work covered by the following copyright and permission notice: +// +// TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov +// No copyright is claimed pursuant to 17 USC 105. All Other Rights Reserved. +// +// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); +// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may +// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. +// +// TVA Code Library is provided by the copyright holders and contributors "as is" and any express +// or implied warranties, including, but not limited to, the implied warranties of merchantability +// and fitness for a particular purpose are disclaimed. +// +//********************************************************************************************************************* +// +// Code Modification History: +// ------------------------------------------------------------------------------------------------------------------- +// 05/23/2012 - J. Ritchie Carroll, Grid Protection Alliance +// Generated original version of source code. +// +//********************************************************************************************************************* + +using Gemstone; +using Gemstone.Numeric; +using Gemstone.Numeric.Analysis; +using Gemstone.Units; + +namespace FaultAlgorithms +{ + /// + /// Represents a cycle of single phase power frequency-domain data. + /// + public class Cycle + { + #region [ Members ] + + // Constants + private const double PiOverTwo = Math.PI / 2.0D; + + // Fields + + /// + /// The actual frequency of the cycle in hertz. + /// + public double Frequency; + + /// + /// The complex number representation of the RMS phasor. + /// + public ComplexNumber Complex; + + /// + /// The most extreme data point in the cycle. + /// + public double Peak; + + /// + /// The error between the sine fit and the given data values. + /// + public double Error; + + #endregion + + #region [ Constructors ] + + /// + /// Creates a new instance of the class. + /// + public Cycle() + { + } + + /// + /// Creates a new instance of the class. + /// + /// The index of the start of the cycle. + /// The frequency of the measured system, in Hz. + /// The time-domain data to be used to calculate frequency-domain values. + public Cycle(int startSample, double frequency, MeasurementData waveFormData) + { + long timeStart; + double[] timeInSeconds; + double[] measurements; + SineWave sineFit; + + if (startSample < 0) + throw new ArgumentOutOfRangeException("startSample"); + + if (startSample + waveFormData.SampleRate > waveFormData.Times.Length) + throw new ArgumentOutOfRangeException("startSample"); + + if (startSample + waveFormData.SampleRate > waveFormData.Measurements.Length) + throw new ArgumentOutOfRangeException("startSample"); + + timeStart = waveFormData.Times[startSample]; + timeInSeconds = new double[waveFormData.SampleRate]; + measurements = new double[waveFormData.SampleRate]; + + for (int i = 0; i < waveFormData.SampleRate; i++) + { + timeInSeconds[i] = Ticks.ToSeconds(waveFormData.Times[i + startSample] - timeStart); + measurements[i] = waveFormData.Measurements[i + startSample]; + } + + sineFit = WaveFit.SineFit(measurements, timeInSeconds, frequency); + + RMS = Math.Sqrt(measurements.Select(vi => vi * vi).Average()); + Phase = sineFit.Phase - PiOverTwo; + Peak = sineFit.Amplitude; + Frequency = frequency; + + Error = timeInSeconds + .Select(time => sineFit.CalculateY(time)) + .Zip(measurements, (calc, measurement) => Math.Abs(calc - measurement)) + .Sum(); + } + + #endregion + + #region [ Properties ] + + /// + /// Root-mean-square of the in the cycle. + /// + public double RMS + { + get + { + return Complex.Magnitude; + } + set + { + Complex.Magnitude = value; + } + } + + /// + /// Phase angle of the start of the cycle, relative to the reference angle. + /// + public Angle Phase + { + get + { + return Complex.Angle; + } + set + { + Complex.Angle = value; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Libraries/FaultAlgorithms/CycleData.cs b/src/Libraries/FaultAlgorithms/CycleData.cs new file mode 100644 index 00000000..610d5960 --- /dev/null +++ b/src/Libraries/FaultAlgorithms/CycleData.cs @@ -0,0 +1,177 @@ +//********************************************************************************************************************* +// CycleData.cs +// Version 1.1 and subsequent releases +// +// Copyright © 2013, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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. +// +// -------------------------------------------------------------------------------------------------------------------- +// +// Version 1.0 +// +// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. +// +// openFLE ("this software") is licensed under BSD 3-Clause license. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// • Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// • Neither the name of the Electric Power Research Institute, Inc. (“EPRI”) nor the names of its contributors +// may be used to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// +// This software incorporates work covered by the following copyright and permission notice: +// +// • TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov +// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved. +// +// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); +// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may +// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. +// +// TVA Code Library is provided by the copyright holders and contributors "as is" and any express +// or implied warranties, including, but not limited to, the implied warranties of merchantability +// and fitness for a particular purpose are disclaimed. +// +//********************************************************************************************************************* +// +// Code Modification History: +// ------------------------------------------------------------------------------------------------------------------- +// 06/14/2012 - Stephen C. Wills, Grid Protection Alliance +// Generated original version of source code. +// +//********************************************************************************************************************* + +using Gemstone.Numeric; + +namespace FaultAlgorithms +{ + /// + /// Contains data for a single cycle over all three line-to-neutral conductors. + /// + public class CycleData + { + #region [ Members ] + + // Constants + + /// + /// 2 * pi + /// + public const double TwoPI = 2.0D * Math.PI; + + // a = e^((2/3) * pi * i) + private const double Rad120 = TwoPI / 3.0D; + private static readonly ComplexNumber a = new ComplexNumber(Math.Cos(Rad120), Math.Sin(Rad120)); + private static readonly ComplexNumber aSq = a * a; + + // Fields + + /// + /// A-to-neutral conductor + /// + public Conductor AN; + + /// + /// B-to-neutral conductor + /// + public Conductor BN; + + /// + /// C-to-neutral conductor + /// + public Conductor CN; + + /// + /// Timestamp of the start of the cycle. + /// + public DateTime StartTime; + + #endregion + + #region [ Constructors ] + + /// + /// Creates a new instance of the class. + /// + public CycleData() + { + AN = new Conductor(); + BN = new Conductor(); + CN = new Conductor(); + } + + /// + /// Creates a new instance of the class. + /// + /// The index of the cycle being created. + /// The value to divide from the sample rate to determine the index of the sample at the start of the cycle. + /// The frequency of the measured system, in Hz. + /// The data set containing voltage measurements. + /// The data set containing current measurements. + public CycleData(int cycleIndex, int sampleRateDivisor, double frequency, MeasurementDataSet voltageDataSet, MeasurementDataSet currentDataSet) + { + int sampleIndex; + + AN = new Conductor(cycleIndex, sampleRateDivisor, frequency, voltageDataSet.AN, currentDataSet.AN); + BN = new Conductor(cycleIndex, sampleRateDivisor, frequency, voltageDataSet.BN, currentDataSet.BN); + CN = new Conductor(cycleIndex, sampleRateDivisor, frequency, voltageDataSet.CN, currentDataSet.CN); + + sampleIndex = cycleIndex * (voltageDataSet.AN.SampleRate / sampleRateDivisor); + StartTime = new DateTime(voltageDataSet.AN.Times[sampleIndex]); + } + + #endregion + + #region [ Methods ] + + /// + /// Calculates the positive, negative, and zero sequence components + /// and returns them in an array with indexes 1, 2, and 0 respectively. + /// + /// The cycle of A-to-neutral data to be used. + /// The cycle of B-to-neutral data to be used. + /// The cycle of C-to-neutral data to be used. + /// An array of size 3 containing the zero sequence, positive sequence, and negative sequence components in that order. + public static ComplexNumber[] CalculateSequenceComponents(Cycle anCycle, Cycle bnCycle, Cycle cnCycle) + { + ComplexNumber an = anCycle.Complex; + ComplexNumber bn = bnCycle.Complex; + ComplexNumber cn = cnCycle.Complex; + + ComplexNumber[] sequenceComponents = new ComplexNumber[3]; + + sequenceComponents[0] = (an + bn + cn) / 3.0D; + sequenceComponents[1] = (an + a * bn + aSq * cn) / 3.0D; + sequenceComponents[2] = (an + aSq * bn + a * cn) / 3.0D; + + return sequenceComponents; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Libraries/FaultAlgorithms/CycleDataSet.cs b/src/Libraries/FaultAlgorithms/CycleDataSet.cs new file mode 100644 index 00000000..34b810b7 --- /dev/null +++ b/src/Libraries/FaultAlgorithms/CycleDataSet.cs @@ -0,0 +1,303 @@ +//********************************************************************************************************************* +// CycleDataSet.cs +// Version 1.1 and subsequent releases +// +// Copyright © 2013, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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. +// +// -------------------------------------------------------------------------------------------------------------------- +// +// Version 1.0 +// +// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. +// +// openFLE ("this software") is licensed under BSD 3-Clause license. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// • Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// • Neither the name of the Electric Power Research Institute, Inc. (“EPRI”) nor the names of its contributors +// may be used to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// +// This software incorporates work covered by the following copyright and permission notice: +// +// • TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov +// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved. +// +// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); +// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may +// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. +// +// TVA Code Library is provided by the copyright holders and contributors "as is" and any express +// or implied warranties, including, but not limited to, the implied warranties of merchantability +// and fitness for a particular purpose are disclaimed. +// +//********************************************************************************************************************* +// +// Code Modification History: +// ------------------------------------------------------------------------------------------------------------------- +// 06/14/2012 - Stephen C. Wills, Grid Protection Alliance +// Generated original version of source code. +// +//********************************************************************************************************************* + +using System.Collections; +using Gemstone.Numeric; +using Gemstone.Numeric.Analysis; + +namespace FaultAlgorithms +{ + /// + /// Represents a collection of all the cycles extracted from a given data set. + /// + public class CycleDataSet : IEnumerable + { + #region [ Members ] + + // Fields + private List m_cycles; + + #endregion + + #region [ Constructors ] + + /// + /// Creates a new instance of the class. + /// + public CycleDataSet() + { + m_cycles = new List(); + } + + /// + /// Creates a new instance of the class. + /// + /// The frequency of the measured system, in Hz. + /// The data set containing voltage data points. + /// The data set containing current data points. + public CycleDataSet(double frequency, MeasurementDataSet voltageDataSet, MeasurementDataSet currentDataSet) + { + Populate(frequency, voltageDataSet, currentDataSet); + } + + #endregion + + #region [ Properties ] + + /// + /// Gets or sets the data structure containing a + /// full cycle of data at the given index. + /// + /// The index of the cycle. + /// The cycle of data at the given index. + public CycleData this[int i] + { + get + { + return m_cycles[i]; + } + set + { + while(i >= m_cycles.Count) + m_cycles.Add(null); + + m_cycles[i] = value; + } + } + + /// + /// Gets the size of the cycle data set. + /// + public int Count + { + get + { + return m_cycles.Count; + } + } + + #endregion + + #region [ Methods ] + + /// + /// Populates the cycle data set by calculating cycle + /// data based on the given measurement data sets. + /// + /// The frequency of the measured system, in Hz. + /// Data set containing voltage waveform measurements. + /// Data set containing current waveform measurements. + public void Populate(double frequency, MeasurementDataSet voltageDataSet, MeasurementDataSet currentDataSet) + { + List measurementDataList; + int sampleRateDivisor; + int numberOfCycles; + + measurementDataList = new List() + { + voltageDataSet.AN, voltageDataSet.BN, voltageDataSet.CN, + currentDataSet.AN, currentDataSet.BN, currentDataSet.CN + }; + + sampleRateDivisor = measurementDataList + .Select(measurementData => measurementData.SampleRate) + .GreatestCommonDenominator(); + + numberOfCycles = measurementDataList + .Select(measurementData => (measurementData.Measurements.Length - measurementData.SampleRate + 1) / (measurementData.SampleRate / sampleRateDivisor)) + .Min(); + + for (int i = 0; i < numberOfCycles; i++) + m_cycles.Add(new CycleData(i, sampleRateDivisor, frequency, voltageDataSet, currentDataSet)); + } + + /// + /// Returns the index of the cycle with the largest total current. + /// + /// The index of the cycle with the largest total current. + public int GetLargestCurrentIndex() + { + int index = 0; + int bestFaultIndex = -1; + double largestCurrent = 0.0D; + + foreach (CycleData cycle in m_cycles) + { + double totalCurrent = cycle.AN.I.RMS + cycle.BN.I.RMS + cycle.CN.I.RMS; + + if (totalCurrent > largestCurrent) + { + bestFaultIndex = index; + largestCurrent = totalCurrent; + } + + index++; + } + + return bestFaultIndex; + } + + /// + /// Clears the cycle data set so that it can be repopulated. + /// + public void Clear() + { + m_cycles.Clear(); + } + + /// + /// Returns an enumerator that iterates through the collection of cycles. + /// + /// An object that can be used to iterate through the collection. + public IEnumerator GetEnumerator() + { + foreach (CycleData cycle in m_cycles) + { + yield return cycle; + } + } + + /// + /// Returns an enumerator that iterates through the collection of cycles. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + #region [ Static ] + + // Static Methods + + /// + /// Exports the given to a CSV file. + /// + /// The name of the CSV file. + /// The cycle data set to be exported. + public static void ExportToCSV(string fileName, CycleDataSet cycles) + { + const string Header = + "AN V RMS,AN V Phase,AN V Peak," + + "BN V RMS,BN V Phase,BN V Peak," + + "CN V RMS,CN V Phase,CN V Peak," + + "Pos V Magnitude,Pos V Angle," + + "Neg V Magnitude,Neg V Angle," + + "Zero V Magnitude,Zero V Angle," + + "AN I RMS,AN I Phase,AN I Peak," + + "BN I RMS,BN I Phase,BN I Peak," + + "CN I RMS,CN I Phase,CN I Peak," + + "Pos I Magnitude,Pos I Angle," + + "Neg I Magnitude,Neg I Angle," + + "Zero I Magnitude,Zero I Angle"; + + using (FileStream fileStream = File.OpenWrite(fileName)) + { + using (TextWriter fileWriter = new StreamWriter(fileStream)) + { + // Write the CSV header to the file + fileWriter.WriteLine(Header); + + // Write data to the file + foreach (CycleData cycleData in cycles.m_cycles) + fileWriter.WriteLine(ToCSV(cycleData)); + } + } + } + + // Converts the cycle data to a row of CSV data. + private static string ToCSV(CycleData cycleData) + { + ComplexNumber[] vSeq = CycleData.CalculateSequenceComponents(cycleData.AN.V, cycleData.BN.V, cycleData.CN.V); + ComplexNumber[] iSeq = CycleData.CalculateSequenceComponents(cycleData.AN.I, cycleData.BN.I, cycleData.CN.I); + + string vCsv = string.Format("{0},{1},{2}", ToCSV(cycleData.AN.V), ToCSV(cycleData.BN.V), ToCSV(cycleData.CN.V)); + string vSeqCsv = string.Format("{0},{1},{2}", ToCSV(vSeq[1]), ToCSV(vSeq[2]), ToCSV(vSeq[0])); + string iCsv = string.Format("{0},{1},{2}", ToCSV(cycleData.AN.I), ToCSV(cycleData.BN.I), ToCSV(cycleData.CN.I)); + string iSeqCsv = string.Format("{0},{1},{2}", ToCSV(iSeq[1]), ToCSV(iSeq[2]), ToCSV(iSeq[0])); + + return string.Format("{0},{1},{2},{3}", vCsv, vSeqCsv, iCsv, iSeqCsv); + } + + // Converts the cycle to CSV data. + private static string ToCSV(Cycle cycle) + { + return string.Format("{0},{1},{2}", cycle.RMS, cycle.Phase.ToDegrees(), cycle.Peak); + } + + // Converts the sequence component to CSV data. + private static string ToCSV(ComplexNumber sequenceComponent) + { + return string.Format("{0},{1}", sequenceComponent.Magnitude, sequenceComponent.Angle.ToDegrees()); + } + + #endregion + } +} diff --git a/src/Libraries/FaultAlgorithms/FaultAlgorithms.csproj b/src/Libraries/FaultAlgorithms/FaultAlgorithms.csproj new file mode 100644 index 00000000..bc767802 --- /dev/null +++ b/src/Libraries/FaultAlgorithms/FaultAlgorithms.csproj @@ -0,0 +1,13 @@ + + + + net9.0 + enable + enable + + + + + + + diff --git a/src/Libraries/FaultAlgorithms/MeasurementData.cs b/src/Libraries/FaultAlgorithms/MeasurementData.cs new file mode 100644 index 00000000..04da176a --- /dev/null +++ b/src/Libraries/FaultAlgorithms/MeasurementData.cs @@ -0,0 +1,97 @@ +//********************************************************************************************************************* +// MeasurementData.cs +// Version 1.1 and subsequent releases +// +// Copyright 2013, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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. +// +// -------------------------------------------------------------------------------------------------------------------- +// +// Version 1.0 +// +// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. +// +// openFLE ("this software") is licensed under BSD 3-Clause license. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// Neither the name of the Electric Power Research Institute, Inc. (EPRI) nor the names of its contributors +// may be used to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// +// This software incorporates work covered by the following copyright and permission notice: +// +// TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov +// No copyright is claimed pursuant to 17 USC 105. All Other Rights Reserved. +// +// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); +// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may +// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. +// +// TVA Code Library is provided by the copyright holders and contributors "as is" and any express +// or implied warranties, including, but not limited to, the implied warranties of merchantability +// and fitness for a particular purpose are disclaimed. +// +//********************************************************************************************************************* +// +// Code Modification History: +// ------------------------------------------------------------------------------------------------------------------- +// 05/23/2012 - J. Ritchie Carroll, Grid Protection Alliance +// Generated original version of source code. +// +//********************************************************************************************************************* + +namespace FaultAlgorithms +{ + /// + /// Represents a set of single phase power time-domain data. + /// + public class MeasurementData + { + #region [ Members ] + + // Fields + + /// + /// Array of times in ticks (100 nanosecond intervals). + /// + public long[] Times; + + /// + /// Array of measured values. + /// + public double[] Measurements; + + /// + /// The number of measured samples per cycle of data. + /// + public int SampleRate; + + #endregion + } +} \ No newline at end of file diff --git a/src/Libraries/FaultAlgorithms/MeasurementDataSet.cs b/src/Libraries/FaultAlgorithms/MeasurementDataSet.cs new file mode 100644 index 00000000..1a6c0fb0 --- /dev/null +++ b/src/Libraries/FaultAlgorithms/MeasurementDataSet.cs @@ -0,0 +1,272 @@ +//********************************************************************************************************************* +// MeasurementDataSet.cs +// Version 1.1 and subsequent releases +// +// Copyright 2013, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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. +// +// -------------------------------------------------------------------------------------------------------------------- +// +// Version 1.0 +// +// Copyright 2012 ELECTRIC POWER RESEARCH INSTITUTE, INC. All rights reserved. +// +// openFLE ("this software") is licensed under BSD 3-Clause license. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list of conditions and +// the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +// the following disclaimer in the documentation and/or other materials provided with the distribution. +// +// Neither the name of the Electric Power Research Institute, Inc. (EPRI) nor the names of its contributors +// may be used to endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL EPRI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// +// This software incorporates work covered by the following copyright and permission notice: +// +// TVA Code Library 4.0.4.3 - Tennessee Valley Authority, tvainfo@tva.gov +// No copyright is claimed pursuant to 17 USC 105. All Other Rights Reserved. +// +// Licensed under TVA Custom License based on NASA Open Source Agreement (TVA Custom NOSA); +// you may not use TVA Code Library except in compliance with the TVA Custom NOSA. You may +// obtain a copy of the TVA Custom NOSA at http://tvacodelibrary.codeplex.com/license. +// +// TVA Code Library is provided by the copyright holders and contributors "as is" and any express +// or implied warranties, including, but not limited to, the implied warranties of merchantability +// and fitness for a particular purpose are disclaimed. +// +//********************************************************************************************************************* +// +// Code Modification History: +// ------------------------------------------------------------------------------------------------------------------- +// 05/23/2012 - J. Ritchie Carroll, Grid Protection Alliance +// Generated original version of source code. +// +//********************************************************************************************************************* + +using Gemstone; + +namespace FaultAlgorithms +{ + /// + /// Represents a set of 3-phase line-to-neutral and line-to-line time-domain power data. + /// + public class MeasurementDataSet + { + #region [ Members ] + + // Constants + + private const string DateTimeFormat = "yyyy-MM-dd HH:mm:ss.ffffff"; + + // Fields + + /// + /// Line-to-neutral A-phase data. + /// + public MeasurementData AN; + + /// + /// Line-to-neutral B-phase data. + /// + public MeasurementData BN; + + /// + /// Line-to-neutral C-phase data. + /// + public MeasurementData CN; + + #endregion + + #region [ Constructors ] + + /// + /// Creates a new . + /// + public MeasurementDataSet() + { + AN = new MeasurementData(); + BN = new MeasurementData(); + CN = new MeasurementData(); + } + + #endregion + + #region [ Methods ] + + /// + /// Uses system frequency to calculate the sample rate for each set + /// of in this measurement data set. + /// + /// The frequency of the measured system, in Hz. + public void CalculateSampleRates(double frequency) + { + CalculateSampleRate(frequency, AN); + CalculateSampleRate(frequency, BN); + CalculateSampleRate(frequency, CN); + } + + /// + /// Explicitly sets the sample rate for each set of + /// in this measurement data set. + /// + /// The sample rate. + public void SetSampleRate(int sampleRate) + { + AN.SampleRate = sampleRate; + BN.SampleRate = sampleRate; + CN.SampleRate = sampleRate; + } + + /// + /// Writes all voltage measurement data to a CSV file. + /// + /// Export file name. + public void ExportVoltageDataToCSV(string fileName) + { + const string Header = "Time,AN,BN,CN,AB,BC,CA"; + + using (FileStream fileStream = File.OpenWrite(fileName)) + { + using (TextWriter fileWriter = new StreamWriter(fileStream)) + { + // Write the CSV header to the file + fileWriter.WriteLine(Header); + + // Write the data to the file + for (int i = 0; i < AN.Times.Length; i++) + { + string time = new DateTime(AN.Times[i]).ToString(DateTimeFormat); + + double an = AN.Measurements[i]; + double bn = BN.Measurements[i]; + double cn = CN.Measurements[i]; + + fileWriter.Write("{0},{1},{2},{3},", time, an, bn, cn); + fileWriter.WriteLine("{0},{1},{2}", an - bn, bn - cn, cn - an); + } + } + } + } + + /// + /// Writes all current measurement data to a CSV file. + /// + /// Export file name. + public void ExportCurrentDataToCSV(string fileName) + { + const string Header = "Time,AN,BN,CN"; + + using (FileStream fileStream = File.OpenWrite(fileName)) + { + using (TextWriter fileWriter = new StreamWriter(fileStream)) + { + // Write the CSV header to the file + fileWriter.WriteLine(Header); + + // Write the data to the file + for (int i = 0; i < AN.Times.Length; i++) + { + string time = new DateTime(AN.Times[i]).ToString(DateTimeFormat); + + double an = AN.Measurements[i]; + double bn = BN.Measurements[i]; + double cn = CN.Measurements[i]; + + fileWriter.WriteLine("{0},{1},{2},{3}", time, an, bn, cn); + } + } + } + } + + private void CalculateSampleRate(double frequency, MeasurementData measurementData) + { + long[] times; + long startTicks; + long endTicks; + double cycles; + + // Get the collection of measurement timestamps + times = measurementData.Times; + + // Determine the start and end time of the data set + startTicks = times[0]; + endTicks = times[times.Length - 1]; + + // Determine the number of cycles in the file, + // based on the system frequency + cycles = frequency * Ticks.ToSeconds(endTicks - startTicks); + + // Calculate the number of samples per cycle + measurementData.SampleRate = (int)Math.Round(times.Length / cycles); + } + + #endregion + + #region [ Static ] + + // Static Methods + + /// + /// Writes all measurement data to a CSV file. + /// + /// Export file name. + /// The voltage measurement data to be written to the file. + /// The current measurement data to be written to the file. + public static void ExportToCSV(string fileName, MeasurementDataSet voltageData, MeasurementDataSet currentData) + { + const string Header = "Time,AN V,BN V,CN V,AB V,BC V,CA V,AN I,BN I,CN I"; + + using (FileStream fileStream = File.Create(fileName)) + { + using (TextWriter fileWriter = new StreamWriter(fileStream)) + { + // Write the CSV header to the file + fileWriter.WriteLine(Header); + + // Write the data to the file + for (int i = 0; i < voltageData.AN.Times.Length; i++) + { + string time = new DateTime(voltageData.AN.Times[i]).ToString(DateTimeFormat); + + double vAN = voltageData.AN.Measurements[i]; + double vBN = voltageData.BN.Measurements[i]; + double vCN = voltageData.CN.Measurements[i]; + + double iAN = currentData.AN.Measurements[i]; + double iBN = currentData.BN.Measurements[i]; + double iCN = currentData.CN.Measurements[i]; + + fileWriter.Write("{0},{1},{2},{3},", time, vAN, vBN, vCN); + fileWriter.Write("{0},{1},{2},", vAN - vBN, vBN - vCN, vCN - vAN); + fileWriter.WriteLine("{0},{1},{2}", iAN, iBN, iCN); + } + } + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Libraries/FaultData/DataAnalysis/CycleDataGroup.cs b/src/Libraries/FaultData/DataAnalysis/CycleDataGroup.cs new file mode 100644 index 00000000..3129dd76 --- /dev/null +++ b/src/Libraries/FaultData/DataAnalysis/CycleDataGroup.cs @@ -0,0 +1,115 @@ +//****************************************************************************************************** +// CycleDataGroup.cs - Gbtc +// +// Copyright © 2014, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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/29/2014 - Stephen C. Wills +// Generated original version of source code. +// +//****************************************************************************************************** + +using openXDA.Model; + +namespace FaultData.DataAnalysis +{ + public class CycleDataGroup + { + #region [ Members ] + + // Constants + private const int RMSIndex = 0; + private const int PhaseIndex = 1; + private const int PeakIndex = 2; + private const int ErrorIndex = 3; + private Asset m_asset; + // Fields + private DataGroup m_dataGroup; + + #endregion + + #region [ Constructors ] + + public CycleDataGroup(DataGroup dataGroup, Asset asset) + { + m_dataGroup = dataGroup; + m_asset = asset; + } + + #endregion + + #region [ Properties ] + + public DataSeries RMS + { + get + { + return m_dataGroup[RMSIndex]; + } + } + + public DataSeries Phase + { + get + { + return m_dataGroup[PhaseIndex]; + } + } + + public DataSeries Peak + { + get + { + return m_dataGroup[PeakIndex]; + } + } + + public DataSeries Error + { + get + { + return m_dataGroup[ErrorIndex]; + } + } + + public Asset Asset + { + get + { + return m_asset; + } + } + #endregion + + #region [ Methods ] + + public DataGroup ToDataGroup() + { + return m_dataGroup; + } + + public CycleDataGroup ToSubGroup(int startIndex, int endIndex) + { + return new CycleDataGroup(m_dataGroup.ToSubGroup(startIndex, endIndex), m_asset); + } + + public CycleDataGroup ToSubGroup(DateTime startTime, DateTime endTime) + { + return new CycleDataGroup(m_dataGroup.ToSubGroup(startTime, endTime), m_asset); + } + + #endregion + } +} diff --git a/src/Libraries/FaultData/DataAnalysis/DataGroup.cs b/src/Libraries/FaultData/DataAnalysis/DataGroup.cs new file mode 100644 index 00000000..20d91b75 --- /dev/null +++ b/src/Libraries/FaultData/DataAnalysis/DataGroup.cs @@ -0,0 +1,662 @@ +//****************************************************************************************************** +// DataGroup.cs - Gbtc +// +// Copyright © 2014, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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: +// ---------------------------------------------------------------------------------------------------- +// 05/19/2014 - Stephen C. Wills +// Generated original version of source code. +// 12/23/2019 - C. Lackner +// Adjusted to read data from blob for each dataseries. +// +//****************************************************************************************************** + +using System.Data; +using Gemstone; +using Gemstone.Data.Model; +using Ionic.Zlib; +using Microsoft.Data.SqlClient; +using openXDA.Model; + +namespace FaultData.DataAnalysis +{ + public enum DataClassification + { + Trend, + Event, + FastRMS, + Unknown + } + + public class DataGroup + { + #region [ Members ] + + // Constants + + /// + /// Maximum sample rate, in samples per minute, of data classified as . + /// + public const double TrendThreshold = 1.0D; + + // Fields + private Asset m_asset; + private DateTime m_startTime; + private DateTime m_endTime; + private int m_samples; + + private List m_dataSeries; + private List m_disturbances; + private DataClassification m_classification; + + #endregion + + #region [ Constructors ] + + /// + /// Creates a new instance of the class. + /// + public DataGroup() + { + m_dataSeries = new List(); + m_disturbances = new List(); + m_classification = DataClassification.Unknown; + m_asset = null; + } + + /// + /// Creates a new instance of the class. + /// + /// Asset associated with this datagroup + public DataGroup(Asset asset) + { + m_dataSeries = new List(); + m_disturbances = new List(); + m_classification = DataClassification.Unknown; + m_asset = asset; + } + + /// + /// Creates a new instance of the class. + /// + /// Collection of data series to be added to the data group. + public DataGroup(IEnumerable dataSeries) + : this() + { + foreach (DataSeries series in dataSeries) + Add(series); + } + + /// + /// Creates a new instance of the class. + /// + /// Collection of data series to be added to the data group. + /// Asset associated with this datagroup + public DataGroup(IEnumerable dataSeries, Asset asset) + : this(asset) + { + foreach (DataSeries series in dataSeries) + Add(series); + } + + #endregion + + #region [ Properties ] + + /// + /// Gets the line from which measurements were taken to create the group of data. + /// + public Asset Asset + { + get + { + return m_asset; + } + } + + /// + /// Gets the start time of the group of data. + /// + public DateTime StartTime + { + get + { + return m_startTime; + } + } + + /// + /// Gets the end time of the group of data. + /// + public DateTime EndTime + { + get + { + return m_endTime; + } + } + + /// + /// Gets the number of samples in each series. + /// + public int Samples + { + get + { + return m_samples; + } + } + + /// + /// Gets the sample rate, in samples per second, + /// of the data series in this data group. + /// + public double SamplesPerSecond + { + get + { + if (!m_dataSeries.Any()) + return double.NaN; + + return m_dataSeries[0].SampleRate; + } + } + + /// + /// Gets the duration, in seconds, + /// of the data series in this data group. + /// + public double Duration + { + get + { + if (!m_dataSeries.Any()) + return double.NaN; + + return m_dataSeries[0].Duration; + } + } + + /// + /// Gets the sample rate, in samples per hour, + /// of the data series in this data group. + /// + public double SamplesPerHour + { + get + { + return (m_samples - 1) / (m_endTime - m_startTime).TotalHours; + } + } + + /// + /// Gets flag that indicates whether the data series + /// in this data group are marked as trend channels. + /// + public bool Trend => + m_dataSeries.Any(dataSeries => dataSeries.SeriesInfo?.Channel.Trend == true); + + /// + /// Gets the channels contained in this data group. + /// + public IReadOnlyList DataSeries + { + get + { + return m_dataSeries.AsReadOnly(); + } + } + + /// + /// Gets the disturbances contained in this data group. + /// + public IReadOnlyList Disturbances + { + get + { + return m_disturbances.AsReadOnly(); + } + } + + /// + /// Gets the classification of this group of data as of the last call to . + /// + public DataClassification Classification + { + get + { + if (m_classification == DataClassification.Unknown) + Classify(); + + return m_classification; + } + } + + public DataSeries this[int index] + { + get + { + return m_dataSeries[index]; + } + } + + #endregion + + #region [ Methods ] + + /// + /// Adds a channel to the group of data. + /// + /// The channel to be added to the group. + /// + /// True if the channel was successfully added. False if the channel was excluded + /// because the channel does not match the other channels already in the data group. + /// + public bool Add(DataSeries dataSeries) + { + Asset asset; + DateTime startTime; + DateTime endTime; + int samples; + bool trend; + + // Unable to add null data series + if ((object)dataSeries == null) + return false; + + // Data series without data is irrelevant to data grouping + if (!dataSeries.DataPoints.Any()) + return false; + + // Do not add the same data series twice + if (m_dataSeries.Contains(dataSeries)) + return false; + + // Get information about the line this data is associated with + if ((object)dataSeries.SeriesInfo != null) + asset = dataSeries.SeriesInfo.Channel.Asset; + else + asset = null; + + // Get the start time, end time, number of samples, and + // trend flag for the data series passed into this function + startTime = dataSeries.DataPoints[0].Time; + endTime = dataSeries.DataPoints[dataSeries.DataPoints.Count - 1].Time; + samples = dataSeries.DataPoints.Count; + trend = dataSeries.SeriesInfo?.Channel.Trend == true; + + // If there are any disturbances in this data group that do not overlap + // with the data series, do not include the data series in the data group + if (m_disturbances.Select(disturbance => disturbance.ToRange()).Any(range => range.Start > endTime || range.End < startTime)) + return false; + + // If there are any disturbances associated with the data in this group and the data + // to be added is trending data, do not include the trending data in the data group + if (m_disturbances.Any() && CalculateSamplesPerMinute(startTime, endTime, samples) <= TrendThreshold) + return false; + + // At this point, if there is no existing data in the data + // group, add the data as the first series in the data group + if (m_dataSeries.Count == 0) + { + if (m_asset == null) + { + m_asset = asset; + } + m_startTime = startTime; + m_endTime = endTime; + m_samples = samples; + + m_dataSeries.Add(dataSeries); + m_classification = DataClassification.Unknown; + + return true; + } + + // If the data being added matches the parameters for this data group, add the data to the data group + // Note that it does not have to match Asset + if (startTime == m_startTime && endTime == m_endTime && samples == m_samples && trend == Trend) + { + m_dataSeries.Add(dataSeries); + return true; + } + + return false; + } + + /// + /// Adds a disturbance to the group of data. + /// + /// The disturbance to be added to the group. + /// True if the disturbance was successfully added. + public bool Add(ReportedDisturbance disturbance) + { + // Unable to add null disturbance + if ((object)disturbance == null) + return false; + + // Do not add the same disturbance twice + if (m_disturbances.Contains(disturbance)) + return false; + + // If the data in this data group is trending data, + // do not add the disturbance to the data group + if (Classification == DataClassification.Trend) + return false; + + // Get the start time and end time of the disturbance. + DateTime startTime = disturbance.Time; + DateTime endTime = startTime + disturbance.Duration; + + // If there are no data series and no other disturbances, + // make this the first piece of data to be added to the data group + if (!m_dataSeries.Any() && !m_disturbances.Any()) + { + m_startTime = startTime; + m_endTime = endTime; + m_disturbances.Add(disturbance); + m_classification = DataClassification.Event; + return true; + } + + // If the disturbance overlaps with + // this data group, add the disturbance + if (startTime <= m_endTime && m_startTime <= endTime) + { + // If the only data in the data group is disturbances, + // adjust the start time and end time + if (!m_dataSeries.Any() && startTime < m_startTime) + m_startTime = startTime; + + if (!m_dataSeries.Any() && endTime > m_endTime) + m_endTime = endTime; + + m_disturbances.Add(disturbance); + return true; + } + + return false; + } + + /// + /// Removes a channel from the data group. + /// + /// The channel to be removed from the data group. + /// True if the channel existed in the group and was removed; false otherwise. + public bool Remove(DataSeries dataSeries) + { + if (m_dataSeries.Remove(dataSeries)) + { + m_classification = m_disturbances.Any() + ? DataClassification.Event + : DataClassification.Unknown; + + return true; + } + + return false; + } + + /// + /// Removes a disturbance from the data group. + /// + /// THe disturbance to be removed from the data group. + /// True if the disturbance existed in the group and was removed; false otherwise. + public bool Remove(ReportedDisturbance disturbance) + { + if (m_disturbances.Remove(disturbance)) + { + if (!m_disturbances.Any()) + m_classification = DataClassification.Unknown; + + return true; + } + + return false; + } + + public DataGroup ToSubGroup(int startIndex, int endIndex) + { + DataGroup subGroup = new DataGroup(); + + foreach (DataSeries dataSeries in m_dataSeries) + subGroup.Add(dataSeries.ToSubSeries(startIndex, endIndex)); + + return subGroup; + } + + public DataGroup ToSubGroup(DateTime startTime, DateTime endTime) + { + DataGroup subGroup = new DataGroup(); + + foreach (DataSeries dataSeries in m_dataSeries) + subGroup.Add(dataSeries.ToSubSeries(startTime, endTime)); + + return subGroup; + } + + // Overwrite To Data to save Data into ChannelBlob instead of File Blob + // This needs to be done to avoid data duplication + public Dictionary ToData() + { + Dictionary result = new Dictionary(); + + var timeSeries = m_dataSeries[0].DataPoints + .Select(dataPoint => new { Time = dataPoint.Time.Ticks, Compressed = false }) + .ToList(); + + for (int i = 1; i < timeSeries.Count; i++) + { + long previousTimestamp = m_dataSeries[0][i - 1].Time.Ticks; + long timestamp = timeSeries[i].Time; + long diff = timestamp - previousTimestamp; + + if (diff >= 0 && diff <= ushort.MaxValue) + timeSeries[i] = new { Time = diff, Compressed = true }; + + + } + + int timeSeriesByteLength = timeSeries.Sum(obj => obj.Compressed ? sizeof(ushort) : sizeof(int) + sizeof(long)); + int dataSeriesByteLength = sizeof(int) + (2 * sizeof(double)) + (m_samples * sizeof(ushort)); + int totalByteLength = sizeof(int) + timeSeriesByteLength + dataSeriesByteLength; + + foreach (DataSeries dataSeries in m_dataSeries) + { + byte[] data = new byte[totalByteLength]; + int offset = 0; + + offset += LittleEndian.CopyBytes(m_samples, data, offset); + + List uncompressedIndexes = timeSeries + .Select((obj, Index) => new { obj.Compressed, Index }) + .Where(obj => !obj.Compressed) + .Select(obj => obj.Index) + .ToList(); + + for (int i = 0; i < uncompressedIndexes.Count; i++) + { + int index = uncompressedIndexes[i]; + int nextIndex = (i + 1 < uncompressedIndexes.Count) ? uncompressedIndexes[i + 1] : timeSeries.Count; + + offset += LittleEndian.CopyBytes(nextIndex - index, data, offset); + offset += LittleEndian.CopyBytes(timeSeries[index].Time, data, offset); + + for (int j = index + 1; j < nextIndex; j++) + offset += LittleEndian.CopyBytes((ushort)timeSeries[j].Time, data, offset); + } + + + if (dataSeries.Calculated) continue; + + const ushort NaNValue = ushort.MaxValue; + const ushort MaxCompressedValue = ushort.MaxValue - 1; + int seriesID = dataSeries.SeriesInfo?.ID ?? 0; + double range = dataSeries.Maximum - dataSeries.Minimum; + double decompressionOffset = dataSeries.Minimum; + double decompressionScale = range / MaxCompressedValue; + double compressionScale = (decompressionScale != 0.0D) ? 1.0D / decompressionScale : 0.0D; + + offset += LittleEndian.CopyBytes(seriesID, data, offset); + offset += LittleEndian.CopyBytes(decompressionOffset, data, offset); + offset += LittleEndian.CopyBytes(decompressionScale, data, offset); + + foreach (DataPoint dataPoint in dataSeries.DataPoints) + { + ushort compressedValue = (ushort)Math.Round((dataPoint.Value - decompressionOffset) * compressionScale); + + if (compressedValue == NaNValue) + compressedValue--; + + if (double.IsNaN(dataPoint.Value)) + compressedValue = NaNValue; + + offset += LittleEndian.CopyBytes(compressedValue, data, offset); + } + byte[] returnArray = GZipStream.CompressBuffer(data); + returnArray[0] = 0x44; + returnArray[1] = 0x33; + + int dataSeriesID = dataSeries.SeriesInfo?.ID ?? 0; + result.Add(dataSeriesID, returnArray); + } + + return result ; + } + + public void FromData(List data) + { + FromData(null, data); + } + + public void FromData(Meter meter, List dataList) + { + var decompressed = dataList.SelectMany(d => ChannelData.Decompress(d)); + + foreach (Tuple> tuple in decompressed) + { + DataSeries dataSeries = new DataSeries(); + + if (tuple.Item1 > 0 && !(meter is null)) + dataSeries.SeriesInfo = meter.Series.FirstOrDefault(s => s.ID == tuple.Item1); + + dataSeries.DataPoints = tuple.Item2; + + Add(dataSeries); + } + } + + private void Classify() + { + if (IsTrend()) + m_classification = DataClassification.Trend; + else if (IsEvent()) + m_classification = DataClassification.Event; + else if (IsFastRMS()) + m_classification = DataClassification.FastRMS; + else + m_classification = DataClassification.Unknown; + } + + private bool IsTrend() + { + if (!m_dataSeries.Any() || m_disturbances.Any()) + return false; + + double samplesPerMinute = CalculateSamplesPerMinute(m_startTime, m_endTime, m_samples); + return samplesPerMinute <= TrendThreshold; + } + + private bool IsEvent() + { + if (m_disturbances.Any()) + return true; + + return m_dataSeries + .Where(dataSeries => (object)dataSeries.SeriesInfo != null) + .Where(IsInstantaneous) + .Where(dataSeries => dataSeries.SeriesInfo.Channel.MeasurementType.Name != "Digital") + .Any(); + } + + private bool IsInstantaneous(DataSeries dataSeries) + { + string characteristicName = dataSeries.SeriesInfo.Channel.MeasurementCharacteristic.Name; + string seriesTypeName = dataSeries.SeriesInfo.SeriesType.Name; + + return (characteristicName == "Instantaneous") && + (seriesTypeName == "Values" || seriesTypeName == "Instantaneous"); + } + + private bool IsFastRMS() + { + return m_dataSeries + .Where(dataSeries => (object)dataSeries.SeriesInfo != null) + .Where(IsRMS) + .Any(); + } + + private bool IsRMS(DataSeries dataSeries) + { + string characteristicName = dataSeries.SeriesInfo.Channel.MeasurementCharacteristic.Name; + string seriesTypeName = dataSeries.SeriesInfo.SeriesType.Name; + + return (characteristicName == "RMS") && + (seriesTypeName == "Values" || seriesTypeName == "Instantaneous"); + } + + private double CalculateSamplesPerMinute(DateTime startTime, DateTime endTime, int samples) + { + return (samples - 1) / (endTime - startTime).TotalMinutes; + } + + #endregion + } + + public static partial class TableOperationsExtensions + { + public static Event GetEvent(this TableOperations eventTable, FileGroup fileGroup, DataGroup dataGroup) + { + int fileGroupID = fileGroup.ID; + int assetID = dataGroup.Asset.ID; + DateTime startTime = dataGroup.StartTime; + DateTime endTime = dataGroup.EndTime; + int samples = dataGroup.Samples; + + IDbDataParameter startTimeParameter = new SqlParameter() + { + ParameterName = nameof(dataGroup.StartTime), + DbType = DbType.DateTime2, + Value = startTime + }; + + IDbDataParameter endTimeParameter = new SqlParameter() + { + ParameterName = nameof(dataGroup.EndTime), + DbType = DbType.DateTime2, + Value = endTime + }; + + RecordRestriction recordRestriction = + new RecordRestriction("FileGroupID = {0}", fileGroupID) & + new RecordRestriction("AssetID = {0}", assetID) & + new RecordRestriction("StartTime = {0}", startTimeParameter) & + new RecordRestriction("EndTime = {0}", endTimeParameter) & + new RecordRestriction("Samples = {0}", samples); + + return eventTable.QueryRecord(recordRestriction); + } + } +} diff --git a/src/Libraries/FaultData/DataAnalysis/DataSeries.cs b/src/Libraries/FaultData/DataAnalysis/DataSeries.cs new file mode 100644 index 00000000..cbc7d9d1 --- /dev/null +++ b/src/Libraries/FaultData/DataAnalysis/DataSeries.cs @@ -0,0 +1,588 @@ +//****************************************************************************************************** +// DataSeries.cs - Gbtc +// +// Copyright © 2014, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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: +// ---------------------------------------------------------------------------------------------------- +// 05/15/2014 - Stephen C. Wills +// Generated original version of source code. +// 07/09/2019 - Christoph Lackner +// Added length property and Threshhold method. +// +//****************************************************************************************************** + +using Gemstone; +using Gemstone.Numeric.Interpolation; +using Ionic.Zlib; +using openXDA.Model; + +namespace FaultData.DataAnalysis +{ + /// + /// Represents a series of data points. + /// + public class DataSeries + { + #region [ Members ] + + // Fields + private Series m_seriesInfo; + private List m_dataPoints; + + private double? m_duration; + private double? m_sampleRate; + private double? m_minimum; + private double? m_maximum; + private double? m_average; + + #endregion + + #region [ Constructors ] + + public DataSeries() + { + m_dataPoints = new List(); + } + + #endregion + + #region [ Properties ] + + /// + /// Gets or sets the configuration information + /// that defines the data in this series. + /// + public Series SeriesInfo + { + get + { + return m_seriesInfo; + } + set + { + m_seriesInfo = value; + } + } + + /// + /// Gets or sets the data points that make up the series. + /// + public List DataPoints + { + get + { + return m_dataPoints; + } + set + { + m_dataPoints = value ?? new List(); + m_duration = null; + m_sampleRate = null; + m_minimum = null; + m_maximum = null; + m_average = null; + } + } + + /// + /// Gets the duration of the series, in seconds. + /// + public double Duration + { + get + { + if (m_duration.HasValue) + return m_duration.Value; + + if (!m_dataPoints.Any()) + return double.NaN; + + m_duration = m_dataPoints.Last().Time.Subtract(m_dataPoints.First().Time).TotalSeconds; + + return m_duration.Value; + } + } + + /// + /// Gets the Start Time of the dataseries. + /// + public DateTime StartTime + { + get + { + if (!m_dataPoints.Any()) + return DateTime.MinValue; + return m_dataPoints.First().Time; + } + } + + /// + /// Gets the End Time of the dataseries. + /// + public DateTime EndTime + { + get + { + if (!m_dataPoints.Any()) + return DateTime.MinValue; + return m_dataPoints.Last().Time; + } + } + + + /// + /// Gets the Length of the series, in datapoints. + /// + public int Length + { + get + { + + if (!m_dataPoints.Any()) + return 0; + + return m_dataPoints.Count; + } + } + + /// + /// Gets the sample rate of the series, in samples per second. + /// + public double SampleRate + { + get + { + if (m_sampleRate.HasValue) + return m_sampleRate.Value; + + if (!m_dataPoints.Any()) + return double.NaN; + + int index = (m_dataPoints.Count > 128) ? 128 : m_dataPoints.Count - 1; + + m_sampleRate = (Duration != 0.0D) + ? index / (m_dataPoints[index].Time - m_dataPoints[0].Time).TotalSeconds + : double.NaN; + + return m_sampleRate.Value; + } + } + + /// + /// Gets the maximum value in the series. + /// + public double Maximum + { + get + { + if (m_maximum.HasValue) + return m_maximum.Value; + + if (!m_dataPoints.Any(dataPoint => !double.IsNaN(dataPoint.Value))) + return double.NaN; + + m_maximum = m_dataPoints + .Select(point => point.Value) + .Where(value => !double.IsNaN(value)) + .Max(); + + return m_maximum.Value; + } + } + + /// + /// Gets the minimum value in the series. + /// + public double Minimum + { + get + { + if (m_minimum.HasValue) + return m_minimum.Value; + + if (!m_dataPoints.Any(dataPoint => !double.IsNaN(dataPoint.Value))) + return double.NaN; + + m_minimum = m_dataPoints + .Select(dataPoint => dataPoint.Value) + .Where(value => !double.IsNaN(value)) + .Min(); + + return m_minimum.Value; + } + } + + /// + /// Gets the average value in the series. + /// + public double Average + { + get + { + if (m_average.HasValue) + return m_average.Value; + + if (!m_dataPoints.Any(dataPoint => !double.IsNaN(dataPoint.Value))) + return double.NaN; + + m_average = m_dataPoints + .Select(dataPoint => dataPoint.Value) + .Where(value => !double.IsNaN(value)) + .Average(); + + return m_average.Value; + } + } + + public DataPoint this[int index] + { + get + { + return m_dataPoints[index]; + } + } + + /// + /// Flag that tells the DataGroup .ToData function not to add to data blob because this value is calculated. + /// + public bool Calculated { get; set; } = false; + + #endregion + + #region [ Methods ] + + + /// + /// Creates a new that is a subset. + /// + /// The index at which the new DataSeries starts. + /// The index at which the new DataSeries ends. + /// a new + public DataSeries ToSubSeries(int startIndex, int endIndex) + { + DataSeries subSeries = new DataSeries(); + int count; + + subSeries.SeriesInfo = m_seriesInfo; + + if (startIndex < 0) + startIndex = 0; + + if (endIndex >= m_dataPoints.Count) + endIndex = m_dataPoints.Count - 1; + + count = endIndex - startIndex + 1; + + if (count > 0) + subSeries.DataPoints = m_dataPoints.Skip(startIndex).Take(count).ToList(); + + return subSeries; + } + + /// + /// Creates a new that is a subset. + /// + /// The index at which the new DataSeries starts. + /// a new + public DataSeries ToSubSeries(int startSeries) => ToSubSeries(startSeries, this.Length); + + public DataSeries ToSubSeries(DateTime startTime, DateTime endTime) + { + DataSeries subSeries = new DataSeries(); + + subSeries.SeriesInfo = m_seriesInfo; + + subSeries.DataPoints = m_dataPoints + .SkipWhile(point => point.Time < startTime) + .TakeWhile(point => point.Time <= endTime) + .ToList(); + + return subSeries; + } + + /// + /// Creates a new that is a subset. + /// + /// The time at which the new DataSeries starts. + /// a new + public DataSeries ToSubSeries(DateTime startTime) => ToSubSeries(startTime, this[this.Length - 1].Time); + + public DataSeries Shift(TimeSpan timeShift) + { + DataSeries shifted = new DataSeries(); + + shifted.SeriesInfo = m_seriesInfo; + + shifted.DataPoints = m_dataPoints + .Select(dataPoint => dataPoint.Shift(timeShift)) + .ToList(); + + return shifted; + } + + public DataSeries Negate() + { + DataSeries negatedDataSeries = new DataSeries(); + + negatedDataSeries.DataPoints = m_dataPoints + .Select(point => point.Negate()) + .ToList(); + + return negatedDataSeries; + } + + public DataSeries Add(DataSeries operand) + { + DataSeries sum = new DataSeries(); + + if (m_dataPoints.Count != operand.DataPoints.Count) + throw new InvalidOperationException("Cannot take the sum of series with mismatched time values"); + + sum.DataPoints = m_dataPoints + .Zip(operand.DataPoints, Add) + .ToList(); + + return sum; + } + + public DataSeries Subtract(DataSeries operand) + { + return Add(operand.Negate()); + } + + public DataSeries Multiply(double value) + { + DataSeries result = new DataSeries(); + + result.DataPoints = m_dataPoints + .Select(point => point.Multiply(value)) + .ToList(); + + return result; + } + + public DataSeries Copy() + { + return Multiply(1.0D); + } + + public int Threshhold(double value) + { + return m_dataPoints.FindIndex(x => x.LargerThan(value)); + } + + /// + /// Downsamples the current DataSeries to requested sample count, if the + /// + /// + public void Downsample(int maxSampleCount) + { + // don't actually downsample, if it doesn't need it. + if (DataPoints.Count <= maxSampleCount) return; + + DateTime epoch = new DateTime(1970, 1, 1); + double startTime = StartTime.Subtract(epoch).TotalMilliseconds; + double endTime = EndTime.Subtract(epoch).TotalMilliseconds; + List data = new List(); + + // milliseconds per returned sampled size + int step = (int)(Duration*1000) / maxSampleCount; + if (step < 1) + step = 1; + + int index = 0; + for (double n = startTime * 1000; n <= endTime * 1000; n += 2 * step) + { + DataPoint min = null; + DataPoint max = null; + + while (index < DataPoints.Count() && DataPoints[index].Time.Subtract(epoch).TotalMilliseconds * 1000 < n + 2 * step) + { + if (min == null || min.Value > DataPoints[index].Value) + min = DataPoints[index]; + + if (max == null || max.Value <= DataPoints[index].Value) + max = DataPoints[index]; + + ++index; + } + + if (min != null) + { + if (min.Time < max.Time) + { + data.Add(min); + data.Add(max); + } + else if (min.Time > max.Time) + { + data.Add(max); + data.Add(min); + } + else + { + data.Add(min); + } + } + } + DataPoints = data; + } + + /// + /// Upsamples the current DataSeries to requested sample count, assuming the requested rate is larger than the current + /// + /// + public void Upsample(int minSamplesPerCycle, double systemFrequency) + { + // don't actually upsample, if it doesn't need it. + if (minSamplesPerCycle <= 0) + return; + TimeSpan duration = EndTime - StartTime; + double cycles = duration.TotalSeconds * systemFrequency; + int minSampleCount = (int)Math.Round(cycles * minSamplesPerCycle); + if (minSampleCount <= DataPoints.Count) + return; + + // Creating spline fit to perform upsampling + List xValues = DataPoints + .Select(point => (double) point.Time.Subtract(StartTime).Ticks) + .ToList(); + List yValues= DataPoints + .Select(point => point.Value) + .ToList(); + SplineFit splineFit = SplineFit.ComputeCubicSplines(xValues, yValues); + + List data = Enumerable + .Range(0, minSampleCount) + .Select(sample => sample * duration.Ticks / minSampleCount) + .Select(sampleTicks => + new DataPoint() + { + Time = StartTime.AddTicks(sampleTicks), + Value = splineFit.CalculateY(sampleTicks) + } + ).ToList(); + + DataPoints = data; + } + + #endregion + + #region [ Static ] + + // Static Methods + + public static DataSeries Merge(IEnumerable dataSeriesList) + { + if (dataSeriesList == null) + throw new ArgumentNullException(nameof(dataSeriesList)); + + DataSeries mergedSeries = new DataSeries(); + DateTime lastTime = default(DateTime); + + IEnumerable dataPoints = dataSeriesList + .Where(dataSeries => dataSeries != null) + .Where(dataSeries => dataSeries.DataPoints.Count != 0) + .OrderBy(dataSeries => dataSeries[0].Time) + .SelectMany(series => series.DataPoints); + + foreach (DataPoint next in dataPoints) + { + if (mergedSeries.DataPoints.Count == 0 || next.Time > lastTime) + { + mergedSeries.DataPoints.Add(next); + lastTime = next.Time; + } + } + + return mergedSeries; + } + + private static DataPoint Add(DataPoint point1, DataPoint point2) + { + return point1.Add(point2); + } + + public static DataSeries FromData(Meter meter, byte[] data) + { + + if (data == null) + return null; + + // Restore the GZip header before uncompressing + data[0] = 0x1F; + data[1] = 0x8B; + + byte[] uncompressedData = GZipStream.UncompressBuffer(data); + int offset = 0; + + int samples = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + List times = new List(); + + while (times.Count < samples) + { + int timeValues = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + long currentValue = LittleEndian.ToInt64(uncompressedData, offset); + offset += sizeof(long); + times.Add(new DateTime(currentValue)); + + for (int i = 1; i < timeValues; i++) + { + currentValue += LittleEndian.ToUInt16(uncompressedData, offset); + offset += sizeof(ushort); + times.Add(new DateTime(currentValue)); + } + } + + DataSeries dataSeries = new DataSeries(); + int seriesID = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + if (seriesID > 0 && !(meter is null)) + dataSeries.SeriesInfo = meter.Series.FirstOrDefault(s => s.ID == seriesID); + + const ushort NaNValue = ushort.MaxValue; + double decompressionOffset = LittleEndian.ToDouble(uncompressedData, offset); + double decompressionScale = LittleEndian.ToDouble(uncompressedData, offset + sizeof(double)); + offset += 2 * sizeof(double); + + for (int i = 0; i < samples; i++) + { + ushort compressedValue = LittleEndian.ToUInt16(uncompressedData, offset); + offset += sizeof(ushort); + + double decompressedValue = decompressionScale * compressedValue + decompressionOffset; + + if (compressedValue == NaNValue) + decompressedValue = double.NaN; + + dataSeries.DataPoints.Add(new DataPoint() + { + Time = times[i], + Value = decompressedValue + }); + } + + return dataSeries; + + } + + #endregion + } +} diff --git a/src/Libraries/FaultData/DataAnalysis/ReportedDisturbance.cs b/src/Libraries/FaultData/DataAnalysis/ReportedDisturbance.cs new file mode 100644 index 00000000..a078eb5b --- /dev/null +++ b/src/Libraries/FaultData/DataAnalysis/ReportedDisturbance.cs @@ -0,0 +1,58 @@ +//****************************************************************************************************** +// ReportedDisturbance.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 12/06/2017 - Stephen C. Wills +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone; +using Gemstone.PQDIF.Logical; + +namespace FaultData.DataAnalysis +{ + public class ReportedDisturbance + { + public ReportedDisturbance(Phase phase, DateTime time, double max, double min, double avg, TimeSpan duration, QuantityUnits units) + { + Phase = phase; + Time = time; + Maximum = max; + Minimum = min; + Average = avg; + Duration = duration; + Units = units; + } + + public Phase Phase { get; } + public DateTime Time { get; } + public double Maximum { get; } + public double Minimum { get; } + public double Average { get; } + public TimeSpan Duration { get; } + public QuantityUnits Units { get; } + + public ReportedDisturbance ShiftTimestampTo(DateTime shiftedTime) => + new ReportedDisturbance(Phase, shiftedTime, Maximum, Minimum, Average, Duration, Units); + + public Range ToRange() + { + return new Range(Time, Time + Duration); + } + } +} diff --git a/src/Libraries/FaultData/DataAnalysis/Transform.cs b/src/Libraries/FaultData/DataAnalysis/Transform.cs new file mode 100644 index 00000000..9e4aa28d --- /dev/null +++ b/src/Libraries/FaultData/DataAnalysis/Transform.cs @@ -0,0 +1,358 @@ +//****************************************************************************************************** +// Transform.cs - Gbtc +// +// Copyright © 2014, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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/28/2014 - Stephen C. Wills +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Numeric.Analysis; +using openXDA.Model; + +namespace FaultData.DataAnalysis +{ + public static class Transform + { + public static DataGroup Combine(params DataGroup[] dataGroups) + { + DataGroup combination = new DataGroup(); + + foreach (DataGroup dataGroup in dataGroups) + { + foreach (DataSeries dataSeries in dataGroup.DataSeries) + combination.Add(dataSeries); + } + + return combination; + } + + public static VICycleDataGroup ToVICycleDataGroup(VIDataGroup dataGroup, double frequency, bool compress = false) + { + DataSeries[] cycleSeries = dataGroup.Data; + + return new VICycleDataGroup(cycleSeries + .Where(dataSeries => (object)dataSeries != null) + .Select(dataSeries => ToCycleDataGroup(dataSeries, frequency, compress)) + .ToList(), dataGroup.Asset); + } + + public static CycleDataGroup ToCycleDataGroup(DataSeries dataSeries, double frequency, bool compress=false) + { + if (dataSeries is null) + return null; + + DataSeries rmsSeries = new DataSeries(); + DataSeries phaseSeries = new DataSeries(); + DataSeries peakSeries = new DataSeries(); + DataSeries errorSeries = new DataSeries(); + + // Set series info to the source series info + rmsSeries.SeriesInfo = dataSeries.SeriesInfo; + phaseSeries.SeriesInfo = dataSeries.SeriesInfo; + peakSeries.SeriesInfo = dataSeries.SeriesInfo; + errorSeries.SeriesInfo = dataSeries.SeriesInfo; + + // Get samples per cycle of the data series based on the given frequency + int samplesPerCycle = CalculateSamplesPerCycle(dataSeries, frequency); + + //preinitialize size of SeriesInfo + int ncycleData = dataSeries.DataPoints.Count - samplesPerCycle + 1; + + if (ncycleData <= 0) + return null; + + rmsSeries.DataPoints.Capacity = ncycleData; + phaseSeries.DataPoints.Capacity = ncycleData; + peakSeries.DataPoints.Capacity = ncycleData; + errorSeries.DataPoints.Capacity = ncycleData; + + // Initialize arrays of y-values and t-values for calculating cycle data as necessary + double[] yValues = new double[samplesPerCycle]; + double[] tValues = new double[samplesPerCycle]; + + void CaptureCycle(int cycleIndex) + { + DateTime startTime = dataSeries.DataPoints[0].Time; + + for (int i = 0; i < samplesPerCycle; i++) + { + DateTime time = dataSeries.DataPoints[cycleIndex + i].Time; + double value = dataSeries.DataPoints[cycleIndex + i].Value; + tValues[i] = time.Subtract(startTime).TotalSeconds; + yValues[i] = value; + } + } + + // Obtain a list of time gaps in the data series + List gapIndexes = Enumerable.Range(0, dataSeries.DataPoints.Count - 1) + .Where(index => + { + DataPoint p1 = dataSeries[index]; + DataPoint p2 = dataSeries[index + 1]; + double cycleDiff = (p2.Time - p1.Time).TotalSeconds * frequency; + + // Detect gaps larger than a quarter cycle. + // Tolerance of 0.000062 calculated + // assuming 3.999 samples per cycle + return (cycleDiff > 0.250062); + }) + .ToList(); + + double sum = 0; + + if (dataSeries.DataPoints.Count >= samplesPerCycle) + { + CaptureCycle(0); + sum = yValues.Sum(y => y * y); + + DateTime cycleTime = dataSeries.DataPoints[0].Time; + SineWave sineFit = WaveFit.SineFit(yValues, tValues, frequency); + double phase = sineFit.Phase; + + double ComputeSineError() => tValues + .Select(sineFit.CalculateY) + .Zip(yValues, (estimate, value) => Math.Abs(estimate - value)) + .Sum(); + + double sineError = ComputeSineError(); + double previousSineError = sineError; + + rmsSeries.DataPoints.Add(new DataPoint() + { + Time = cycleTime, + Value = Math.Sqrt(sum / samplesPerCycle) + }); + + phaseSeries.DataPoints.Add(new DataPoint() + { + Time = cycleTime, + Value = phase + }); + + peakSeries.DataPoints.Add(new DataPoint() + { + Time = cycleTime, + Value = sineFit.Amplitude + }); + + errorSeries.DataPoints.Add(new DataPoint() + { + Time = cycleTime, + Value = sineError + }); + + // Reduce RMS to max 2 pt per cycle to get half cycle RMS + int step = 1; + if (compress) + step = (int)Math.Floor(samplesPerCycle / 2.0D); + if (step == 0) + step = 1; + + for (int cycleIndex = step; cycleIndex < dataSeries.DataPoints.Count - samplesPerCycle + 1; cycleIndex += step) + { + for (int j = 0; j < step; j++) + { + int oldIndex = cycleIndex - step + j; + int newIndex = oldIndex + samplesPerCycle; + double oldValue = dataSeries.DataPoints[oldIndex].Value; + double newValue = dataSeries.DataPoints[newIndex].Value; + sum += newValue * newValue - oldValue * oldValue; + } + + // If the cycle following i contains a data gap, do not calculate cycle data + if (gapIndexes.Any(index => cycleIndex <= index && (cycleIndex + samplesPerCycle - 1) > index)) + continue; + + phase += 2 * Math.PI * frequency * (dataSeries.DataPoints[cycleIndex].Time - cycleTime).TotalSeconds; + + // Use the time of the first data point in the cycle as the time of the cycle + cycleTime = dataSeries.DataPoints[cycleIndex].Time; + + CaptureCycle(cycleIndex); + + if (compress) + sineError = ComputeSineError(); + + if (!compress || Math.Abs(previousSineError - sineError) > sineError * 0.0001) + { + sineFit = WaveFit.SineFit(yValues, tValues, frequency); + phase = sineFit.Phase; + sineError = ComputeSineError(); + } + + previousSineError = sineError; + + rmsSeries.DataPoints.Add(new DataPoint() + { + Time = cycleTime, + Value = Math.Sqrt(sum / samplesPerCycle) + }); + + phaseSeries.DataPoints.Add(new DataPoint() + { + Time = cycleTime, + Value = phase + }); + + peakSeries.DataPoints.Add(new DataPoint() + { + Time = cycleTime, + Value = sineFit.Amplitude + }); + + errorSeries.DataPoints.Add(new DataPoint() + { + Time = cycleTime, + Value = sineError + }); + } + } + + // Add a series to the data group for each series of cycle data + DataGroup dataGroup = new DataGroup(); + dataGroup.Add(rmsSeries); + dataGroup.Add(phaseSeries); + dataGroup.Add(peakSeries); + dataGroup.Add(errorSeries); + + return new CycleDataGroup(dataGroup, dataSeries.SeriesInfo.Channel.Asset); + } + + public static DataSeries ToRMS(DataSeries dataSeries, double frequency, bool compress = false) + { + DataSeries rmsSeries = new DataSeries(); + + int samplesPerCycle; + double[] yValues; + double[] tValues; + double sum; + + DateTime cycleTime; + + if ((object)dataSeries == null) + return null; + + // Set series info to the source series info + rmsSeries.SeriesInfo = dataSeries.SeriesInfo; + + + // Get samples per cycle of the data series based on the given frequency + samplesPerCycle = Transform.CalculateSamplesPerCycle(dataSeries, frequency); + + //preinitialize size of SeriesInfo + int ncycleData = dataSeries.DataPoints.Count - samplesPerCycle; + rmsSeries.DataPoints = new List(ncycleData); + + + + // Initialize arrays of y-values and t-values for calculating cycle data as necessary + yValues = new double[samplesPerCycle]; + tValues = new double[samplesPerCycle]; + + // Obtain a list of time gaps in the data series + List gapIndexes = Enumerable.Range(0, dataSeries.DataPoints.Count - 1) + .Where(index => + { + DataPoint p1 = dataSeries[index]; + DataPoint p2 = dataSeries[index + 1]; + double cycleDiff = (p2.Time - p1.Time).TotalSeconds * frequency; + + // Detect gaps larger than a quarter cycle. + // Tolerance of 0.000062 calculated + // assuming 3.999 samples per cycle + return (cycleDiff > 0.250062); + }) + .ToList(); + + sum = 0; + + if (dataSeries.DataPoints.Count > samplesPerCycle) + { + sum = dataSeries.DataPoints.Take(samplesPerCycle).Sum(pt => pt.Value * pt.Value); + + rmsSeries.DataPoints.Add(new DataPoint() + { + Time = dataSeries.DataPoints[0].Time, + Value = Math.Sqrt(sum / samplesPerCycle) + }); + + cycleTime = dataSeries.DataPoints[0].Time; + + // Reduce RMS to max 2 pt per cycle to get half cycle RMS + int step = 1; + if (compress) + step = (int)Math.Floor(samplesPerCycle / 2.0D); + if (step == 0) + step = 1; + + for (int i = step; i < dataSeries.DataPoints.Count - samplesPerCycle; i = i + step) + { + + for (int j = 0; j < step; j++) + { + sum = sum - dataSeries.DataPoints[i - step + j].Value * dataSeries.DataPoints[i - step + j].Value; + sum = sum + dataSeries.DataPoints[i - step + j + samplesPerCycle].Value * dataSeries.DataPoints[i - step + j + samplesPerCycle].Value; + } + + // If the cycle following i contains a data gap, do not calculate cycle data + if (gapIndexes.Any(index => i <= index && (i + samplesPerCycle - 1) > index)) + continue; + + // Use the time of the first data point in the cycle as the time of the cycle + cycleTime = dataSeries.DataPoints[i].Time; + + rmsSeries.DataPoints.Add(new DataPoint() + { + Time = cycleTime, + Value = Math.Sqrt(sum / samplesPerCycle) + }); + + } + } + + return rmsSeries; + } + + public static List ToValues(DataSeries series) + { + return series.DataPoints + .Select(dataPoint => dataPoint.Value) + .ToList(); + } + + public static int CalculateSamplesPerCycle(DataSeries dataSeries, double frequency) + { + return CalculateSamplesPerCycle(dataSeries.SampleRate, frequency); + } + + public static int CalculateSamplesPerCycle(double samplesPerSecond, double frequency) + { + int[] commonSampleRates = + { + 4, 8, 16, 32, + 80, 96, 100, 200, + 64, 128, 256, 512, 1024 + }; + + int calculatedRate = (int)Math.Round(samplesPerSecond / frequency); + int nearestCommonRate = commonSampleRates.MinBy(rate => Math.Abs(calculatedRate - rate)); + int diff = Math.Abs(calculatedRate - nearestCommonRate); + return (diff < nearestCommonRate * 0.1D) ? nearestCommonRate : calculatedRate; + } + } +} diff --git a/src/Libraries/FaultData/DataAnalysis/VICycleDataGroup.cs b/src/Libraries/FaultData/DataAnalysis/VICycleDataGroup.cs new file mode 100644 index 00000000..d913f052 --- /dev/null +++ b/src/Libraries/FaultData/DataAnalysis/VICycleDataGroup.cs @@ -0,0 +1,476 @@ +//****************************************************************************************************** +// VICycleDataGroup.cs - Gbtc +// +// Copyright © 2014, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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/29/2014 - Stephen C. Wills +// Generated original version of source code. +// +//****************************************************************************************************** + +using FaultAlgorithms; +using openXDA.Model; + +namespace FaultData.DataAnalysis +{ + public class VICycleDataGroup + { + #region [ Members ] + + // Fields + private List m_vIndices; + private Asset m_asset; + + private int m_iaIndex; + private int m_ibIndex; + private int m_icIndex; + private int m_irIndex; + + private List m_cycleDataGroups; + + private class VIndices + { + public int Va; + public int Vb; + public int Vc; + + public int Vab; + public int Vbc; + public int Vca; + + public int distance; + public VIndices() + { + Va = -1; + Vb = -1; + Vc = -1; + Vab = -1; + Vbc = -1; + Vca = -1; + + distance = -1; + } + + public int DefinedNeutralVoltages + { + get + { + return ((Va > -1) ? 1 : 0) + ((Vb > -1) ? 1 : 0) + ((Vc > -1) ? 1 : 0); + } + } + + public int DefinedLineVoltages + { + get + { + return ((Vab > -1) ? 1 : 0) + ((Vbc > -1) ? 1 : 0) + ((Vca > -1) ? 1 : 0); + } + } + + public bool allVoltagesDefined + { + get + { + return ((Vab > -1) && (Vbc > -1) && (Vca > -1) && + (Va > -1) && (Vb > -1) && (Vc > -1)); + } + } + + } + + + public double VBase => m_asset.VoltageKV; + + #endregion + + #region [ Constructors ] + + public VICycleDataGroup(DataGroup dataGroup) + { + m_vIndices = new List(); + m_asset = dataGroup.Asset; + + m_cycleDataGroups = dataGroup.DataSeries + .Select((dataSeries, index) => new { DataSeries = dataSeries, Index = index }) + .GroupBy(obj => obj.Index / 4) + .Where(grouping => grouping.Count() >= 4) + .Select(grouping => grouping.Select(obj => obj.DataSeries)) + .Select(grouping => new CycleDataGroup(new DataGroup(grouping, dataGroup.Asset), dataGroup.Asset)) + .ToList(); + + MapIndexes(); + } + + public VICycleDataGroup(List cycleDataGroups, Asset asset) + { + m_vIndices = new List(); + m_cycleDataGroups = new List(cycleDataGroups); + m_asset = asset; + MapIndexes(); + } + + #endregion + + #region [ Properties ] + + public CycleDataGroup VA + { + get + { + return (m_vIndices.Count > 0 && m_vIndices[0].Va >= 0) ? m_cycleDataGroups[m_vIndices[0].Va] : null; + } + } + + public CycleDataGroup VB + { + get + { + return (m_vIndices.Count > 0 && m_vIndices[0].Vb >= 0) ? m_cycleDataGroups[m_vIndices[0].Vb] : null; + } + } + + public CycleDataGroup VC + { + get + { + return (m_vIndices.Count > 0 && m_vIndices[0].Vc >= 0) ? m_cycleDataGroups[m_vIndices[0].Vc] : null; + } + } + + public CycleDataGroup VAB + { + get + { + return (m_vIndices.Count > 0 && m_vIndices[0].Vab >= 0) ? m_cycleDataGroups[m_vIndices[0].Vab] : null; + } + } + + public CycleDataGroup VBC + { + get + { + return (m_vIndices.Count > 0 && m_vIndices[0].Vbc >= 0) ? m_cycleDataGroups[m_vIndices[0].Vbc] : null; + } + } + + public CycleDataGroup VCA + { + get + { + return (m_vIndices.Count > 0 && m_vIndices[0].Vca >= 0) ? m_cycleDataGroups[m_vIndices[0].Vca] : null; + } + } + + public CycleDataGroup IA + { + get + { + return (m_iaIndex >= 0) ? m_cycleDataGroups[m_iaIndex] : null; + } + } + + public CycleDataGroup IB + { + get + { + return (m_ibIndex >= 0) ? m_cycleDataGroups[m_ibIndex] : null; + } + } + + public CycleDataGroup IC + { + get + { + return (m_icIndex >= 0) ? m_cycleDataGroups[m_icIndex] : null; + } + } + + public CycleDataGroup IR + { + get + { + return (m_irIndex >= 0) ? m_cycleDataGroups[m_irIndex] : null; + } + } + + public List CycleDataGroups { + get { + return m_cycleDataGroups; + } + } + + #endregion + + #region [ Methods ] + + public DataGroup ToDataGroup() + { + return Transform.Combine(m_cycleDataGroups + .Select(cycleDataGroup => cycleDataGroup.ToDataGroup()) + .ToArray()); + } + + public VICycleDataGroup ToSubSet(int startIndex, int endIndex) + { + return new VICycleDataGroup(m_cycleDataGroups + .Select(cycleDataGroup => cycleDataGroup.ToSubGroup(startIndex, endIndex)) + .ToList(), m_asset); + } + + public VICycleDataGroup ToSubSet(DateTime startTime, DateTime endTime) + { + return new VICycleDataGroup(m_cycleDataGroups + .Select(cycleDataGroup => cycleDataGroup.ToSubGroup(startTime, endTime)) + .ToList(), m_asset); + } + + public void PushDataTo(CycleDataSet cycleDataSet) + { + FaultAlgorithms.CycleData cycleData; + Cycle[] cycles; + CycleDataGroup[] cycleDataGroups; + + cycleDataGroups = new CycleDataGroup[] { VA, VB, VC, IA, IB, IC }; + cycles = new Cycle[cycleDataGroups.Length]; + + for (int i = 0; i < VA.ToDataGroup().Samples; i++) + { + cycleData = new FaultAlgorithms.CycleData(); + + cycles[0] = cycleData.AN.V; + cycles[1] = cycleData.BN.V; + cycles[2] = cycleData.CN.V; + cycles[3] = cycleData.AN.I; + cycles[4] = cycleData.BN.I; + cycles[5] = cycleData.CN.I; + + for (int j = 0; j < cycles.Length; j++) + { + if (cycleDataGroups[j] == null) + continue; + + cycles[j].RMS = cycleDataGroups[j].RMS[i].Value; + cycles[j].Phase = cycleDataGroups[j].Phase[i].Value; + cycles[j].Peak = cycleDataGroups[j].Peak[i].Value; + cycles[j].Error = cycleDataGroups[j].Error[i].Value; + } + + cycleDataSet[i] = cycleData; + } + } + + private void MapIndexes() + { + + m_iaIndex = -1; + m_ibIndex = -1; + m_icIndex = -1; + m_irIndex = -1; + + List vaIndices = new List(); + List vbIndices = new List(); + List vcIndices = new List(); + List vabIndices = new List(); + List vbcIndices = new List(); + List vcaIndices = new List(); + + for (int i = 0; i < m_cycleDataGroups.Count; i++) + { + if (isVoltage("AN", m_cycleDataGroups[i])) + vaIndices.Add(i); + else if (isVoltage("BN", m_cycleDataGroups[i])) + vbIndices.Add(i); + else if (isVoltage("CN", m_cycleDataGroups[i])) + vcIndices.Add(i); + else if (isVoltage("AB", m_cycleDataGroups[i])) + vabIndices.Add(i); + else if (isVoltage("BC", m_cycleDataGroups[i])) + vbcIndices.Add(i); + else if (isVoltage("CA", m_cycleDataGroups[i])) + vcaIndices.Add(i); + + } + + //Walk through all Va and try to get corresponding Vb and Vc... + List ProcessedIndices = new List(); + foreach (int? VaIndex in vaIndices) + { + int assetID = m_cycleDataGroups[(int)VaIndex].Asset.ID; + + int VbIndex = vbIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + int VcIndex = vcIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + int VabIndex = vabIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + int VbcIndex = vbcIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + int VcaIndex = vcaIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + + VIndices set = new VIndices(); + ProcessedIndices.Add(VaIndex); + set.Va = (int)VaIndex; + + if (VbIndex > -1) + { + ProcessedIndices.Add(VbIndex); + set.Vb = VbIndex; + } + if (VcIndex > -1) + { + ProcessedIndices.Add(VcIndex); + set.Vc = VcIndex; + } + + if (VabIndex > -1) + { + ProcessedIndices.Add(VabIndex); + set.Vab = VabIndex; + } + if (VbcIndex > -1) + { + ProcessedIndices.Add(VbcIndex); + set.Vbc = VbcIndex; + } + if (VcaIndex > -1) + { + ProcessedIndices.Add(VcaIndex); + set.Vca = VcaIndex; + } + + + if (assetID == m_asset.ID) + { + set.distance = 0; + } + else + { + set.distance = m_asset.DistanceToAsset(assetID); + } + + m_vIndices.Add(set); + } + + // Also walk though all Vab to catch Leftover Cases where Va is not present + foreach (int? VabIndex in vabIndices) + { + int assetID = m_cycleDataGroups[(int)VabIndex].Asset.ID; + + int VaIndex = vaIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + int VbIndex = vbIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + int VcIndex = vcIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + + int VbcIndex = vbcIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + int VcaIndex = vcaIndices.Cast().FirstOrDefault(i => m_cycleDataGroups[(int)i].Asset.ID == assetID && !ProcessedIndices.Contains(i)) ?? -1; + + VIndices set = new VIndices(); + ProcessedIndices.Add(VabIndex); + set.Vab = (int)VabIndex; + + if (VbIndex > -1) + { + ProcessedIndices.Add(VbIndex); + set.Vb = VbIndex; + } + if (VcIndex > -1) + { + ProcessedIndices.Add(VcIndex); + set.Vc = VcIndex; + } + + if (VaIndex > -1) + { + ProcessedIndices.Add(VaIndex); + set.Va = VaIndex; + } + if (VbcIndex > -1) + { + ProcessedIndices.Add(VbcIndex); + set.Vbc = VbcIndex; + } + if (VcaIndex > -1) + { + ProcessedIndices.Add(VcaIndex); + set.Vca = VcaIndex; + } + + + if (assetID == m_asset.ID) + { + set.distance = 0; + } + else + { + set.distance = m_asset.DistanceToAsset(assetID); + } + + m_vIndices.Add(set); + } + + for (int i = 0; i < m_cycleDataGroups.Count; i++) + { + string measurementType = m_cycleDataGroups[i].RMS.SeriesInfo.Channel.MeasurementType.Name; + string phase = m_cycleDataGroups[i].RMS.SeriesInfo.Channel.Phase.Name; + + + if (measurementType == "Current" && phase == "AN") + m_iaIndex = i; + else if (measurementType == "Current" && phase == "BN") + m_ibIndex = i; + else if (measurementType == "Current" && phase == "CN") + m_icIndex = i; + else if (measurementType == "Current" && phase == "RES") + m_irIndex = i; + } + } + + #endregion + + #region [ Static ] + + // Static Methods + + private static bool isVoltage(string phase, CycleDataGroup dataGroup) + { + + string measurementType = dataGroup.RMS.SeriesInfo.Channel.MeasurementType.Name; + string seriesPhase = dataGroup.RMS.SeriesInfo.Channel.Phase.Name; + + if (measurementType != "Voltage") + return false; + + if (seriesPhase != phase) + return false; + + return true; + + } + + private static bool isCurrent(string phase, CycleDataGroup dataGroup) + { + string measurementType = dataGroup.RMS.SeriesInfo.Channel.MeasurementType.Name; + string seriesPhase = dataGroup.RMS.SeriesInfo.Channel.Phase.Name; + + if (measurementType != "Current") + return false; + + if (seriesPhase != phase) + return false; + + return true; + + } + + #endregion + + } +} diff --git a/src/Libraries/FaultData/DataAnalysis/VIDataGroup.cs b/src/Libraries/FaultData/DataAnalysis/VIDataGroup.cs new file mode 100644 index 00000000..ae088e05 --- /dev/null +++ b/src/Libraries/FaultData/DataAnalysis/VIDataGroup.cs @@ -0,0 +1,521 @@ +//****************************************************************************************************** +// VIDataGroup.cs - Gbtc +// +// Copyright © 2014, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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/29/2014 - Stephen C. Wills +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Data; +using openXDA.Model; + +namespace FaultData.DataAnalysis +{ + public class VIDataGroup + { + #region [ Members ] + + // Fields + private List m_vIndices; + + private int m_iaIndex; + private int m_ibIndex; + private int m_icIndex; + private int m_irIndex; + + private DataGroup m_dataGroup; + + private class VIndices + { + public int Va { get; set; } = -1; + public int Vb { get; set; } = -1; + public int Vc { get; set; } = -1; + + public int Vab { get; set; } = -1; + public int Vbc { get; set; } = -1; + public int Vca { get; set; } = -1; + + public int Distance { get; set; } = -1; + + public int DefinedNeutralVoltages => + (Va >= 0 ? 1 : 0) + + (Vb >= 0 ? 1 : 0) + + (Vc >= 0 ? 1 : 0); + + public int DefinedLineVoltages => + (Vab >= 0 ? 1 : 0) + + (Vbc >= 0 ? 1 : 0) + + (Vca >= 0 ? 1 : 0); + + public bool AllVoltagesDefined => + (Va >= 0) && (Vb >= 0) && (Vc >= 0) && + (Vab >= 0) && (Vbc >= 0) && (Vca >= 0); + } + + #endregion + + #region [ Constructors ] + + public VIDataGroup(DataGroup dataGroup) + { + + // Initialize each of + // the indexes to -1 + m_vIndices = new List(); + + m_iaIndex = -1; + m_ibIndex = -1; + m_icIndex = -1; + m_irIndex = -1; + + // Initialize the data group + m_dataGroup = new DataGroup(dataGroup.DataSeries, dataGroup.Asset); + + HashSet connectedAssets = new HashSet(dataGroup.Asset.ConnectedAssets.Select(item => item.ID)); + + var groupings = dataGroup.DataSeries + .Select((DataSeries, Index) => new { DataSeries, Index }) + .Where(item => !(item.DataSeries.SeriesInfo is null)) + .Where(item => item.DataSeries.SeriesInfo.Channel.MeasurementCharacteristic.Name == "Instantaneous") + .Where(item => new[] { "Instantaneous", "Values" }.Contains(item.DataSeries.SeriesInfo.SeriesType.Name)) + .GroupBy(item => item.DataSeries.SeriesInfo.Channel.AssetID) + .OrderBy(grouping => grouping.Key == dataGroup.Asset.ID ? 0 : 1) + .ThenBy(grouping => connectedAssets.Contains(grouping.Key) ? 0 : 1) + .ToList(); + + foreach (var grouping in groupings) + { + VIndices set = new VIndices() { Distance = 0 }; + + int assetID = grouping.Key; + + if (assetID != dataGroup.Asset.ID) + set.Distance = dataGroup.Asset.DistanceToAsset(assetID); + + foreach (var item in grouping) + { + string measurementType = item.DataSeries.SeriesInfo.Channel.MeasurementType.Name; + string phase = item.DataSeries.SeriesInfo.Channel.Phase.Name; + + if (measurementType == "Voltage" && phase == "AN") + set.Va = item.Index; + + if (measurementType == "Voltage" && phase == "BN") + set.Vb = item.Index; + + if (measurementType == "Voltage" && phase == "CN") + set.Vc = item.Index; + + if (measurementType == "Voltage" && phase == "AB") + set.Vab = item.Index; + + if (measurementType == "Voltage" && phase == "BC") + set.Vbc = item.Index; + + if (measurementType == "Voltage" && phase == "CA") + set.Vca = item.Index; + + if (m_iaIndex < 0 && measurementType == "Current" && phase == "AN") + m_iaIndex = item.Index; + + if (m_ibIndex < 0 && measurementType == "Current" && phase == "BN") + m_ibIndex = item.Index; + + if (m_icIndex < 0 && measurementType == "Current" && phase == "CN") + m_icIndex = item.Index; + + if (m_irIndex < 0 && measurementType == "Current" && phase == "RES") + m_irIndex = item.Index; + } + + if (set.DefinedLineVoltages + set.DefinedNeutralVoltages > 0) + m_vIndices.Add(set); + } + + if (m_vIndices.Count() == 0) + m_vIndices.Add(new VIndices()); + + CalculateMissingCurrentChannel(); + CalculateMissingLLVoltageChannels(); + + m_vIndices.Sort((a, b) => + { + if (b.AllVoltagesDefined && !a.AllVoltagesDefined) + return 1; + if (a.AllVoltagesDefined && !b.AllVoltagesDefined) + return -1; + if (!(a.Distance >= 0 && b.Distance >= 0)) + return b.Distance.CompareTo(a.Distance); + return a.Distance.CompareTo(b.Distance); + }); + } + + private VIDataGroup() + { + } + + #endregion + + #region [ Properties ] + + public DataSeries VA => (m_vIndices[0].Va >= 0) + ? m_dataGroup[m_vIndices[0].Va] + : null; + + public DataSeries VB => (m_vIndices[0].Vb >= 0) + ? m_dataGroup[m_vIndices[0].Vb] + : null; + + public DataSeries VC => (m_vIndices[0].Vc >= 0) + ? m_dataGroup[m_vIndices[0].Vc] + : null; + + public DataSeries VAB => (m_vIndices[0].Vab >= 0) + ? m_dataGroup[m_vIndices[0].Vab] + : null; + + public DataSeries VBC => (m_vIndices[0].Vbc >= 0) + ? m_dataGroup[m_vIndices[0].Vbc] + : null; + + public DataSeries VCA => (m_vIndices[0].Vca >= 0) + ? m_dataGroup[m_vIndices[0].Vca] + : null; + + public DataSeries IA => (m_iaIndex >= 0) + ? m_dataGroup[m_iaIndex] + : null; + + public DataSeries IB => (m_ibIndex >= 0) + ? m_dataGroup[m_ibIndex] + : null; + + public DataSeries IC => (m_icIndex >= 0) + ? m_dataGroup[m_icIndex] + : null; + + public DataSeries IR => (m_irIndex >= 0) + ? m_dataGroup[m_irIndex] + : null; + + public int DefinedNeutralVoltages => m_vIndices + .Select(item => item.DefinedNeutralVoltages) + .FirstOrDefault(); + + public int DefinedLineVoltages => m_vIndices + .Select(item => item.DefinedLineVoltages) + .FirstOrDefault(); + + public int DefinedCurrents => + CurrentIndexes.Count(index => index >= 0); + + public int DefinedPhaseCurrents => + PhaseCurrentIndexes.Count(index => index >= 0); + + public bool AllVIChannelsDefined => + m_vIndices[0].AllVoltagesDefined && + CurrentIndexes.All(index => index >= 0); + + private int[] CurrentIndexes => + new int[] { m_iaIndex, m_ibIndex, m_icIndex, m_irIndex }; + + private int[] PhaseCurrentIndexes => + new int[] { m_iaIndex, m_ibIndex, m_icIndex }; + + public Asset Asset => m_dataGroup.Asset; + + public DataSeries[] Data + { + get + { + List result = new List(); + + foreach (VIndices Vindex in m_vIndices) + { + if (Vindex.Va > -1) + result.Add(m_dataGroup[Vindex.Va]); + if (Vindex.Vb > -1) + result.Add(m_dataGroup[Vindex.Vb]); + if (Vindex.Vc > -1) + result.Add(m_dataGroup[Vindex.Vc]); + + if (Vindex.Vab > -1) + result.Add(m_dataGroup[Vindex.Vab]); + if (Vindex.Vbc > -1) + result.Add(m_dataGroup[Vindex.Vbc]); + if (Vindex.Vca > -1) + result.Add(m_dataGroup[Vindex.Vca]); + } + + if (m_iaIndex > -1) + result.Add(m_dataGroup[m_iaIndex]); + if (m_ibIndex > -1) + result.Add(m_dataGroup[m_ibIndex]); + if (m_icIndex > -1) + result.Add(m_dataGroup[m_icIndex]); + if (m_irIndex > -1) + result.Add(m_dataGroup[m_irIndex]); + + return result.ToArray(); + } + } + + #endregion + + #region [ Methods ] + + /// + /// Given three of the four current channels, calculates the + /// missing channel based on the relationship IR = IA + IB + IC. + /// + private void CalculateMissingCurrentChannel() + { + Meter meter; + DataSeries missingSeries; + + // If the data group does not have exactly 3 channels, + // then there is no missing channel or there is not + // enough data to calculate the missing channel + if (DefinedCurrents != 3) + return; + + // Get the meter associated with the channels in this data group + meter = (IA ?? IB).SeriesInfo.Channel.Meter; + + if (m_iaIndex == -1) + { + // Calculate IA = IR - IB - IC + missingSeries = IR.Add(IB.Negate()).Add(IC.Negate()); + missingSeries.SeriesInfo = GetSeriesInfo(meter, IR.SeriesInfo.Channel.Asset, "Current", "AN", m_dataGroup.SamplesPerHour); + missingSeries.Calculated = true; + m_iaIndex = m_dataGroup.DataSeries.Count; + m_dataGroup.Add(missingSeries); + } + else if (m_ibIndex == -1) + { + // Calculate IB = IR - IA - IC + missingSeries = IR.Add(IA.Negate()).Add(IC.Negate()); + missingSeries.SeriesInfo = GetSeriesInfo(meter, IR.SeriesInfo.Channel.Asset, "Current", "BN", m_dataGroup.SamplesPerHour); + missingSeries.Calculated = true; + m_ibIndex = m_dataGroup.DataSeries.Count; + m_dataGroup.Add(missingSeries); + } + else if (m_icIndex == -1) + { + // Calculate IC = IR - IA - IB + missingSeries = IR.Add(IA.Negate()).Add(IB.Negate()); + missingSeries.SeriesInfo = GetSeriesInfo(meter, IR.SeriesInfo.Channel.Asset, "Current", "CN", m_dataGroup.SamplesPerHour); + missingSeries.Calculated = true; + m_icIndex = m_dataGroup.DataSeries.Count; + m_dataGroup.Add(missingSeries); + } + else + { + // Calculate IR = IA + IB + IC + missingSeries = IA.Add(IB).Add(IC); + missingSeries.SeriesInfo = GetSeriesInfo(meter, IA.SeriesInfo.Channel.Asset, "Current", "RES", m_dataGroup.SamplesPerHour); + missingSeries.Calculated = true; + m_irIndex = m_dataGroup.DataSeries.Count; + m_dataGroup.Add(missingSeries); + } + } + + private void CalculateMissingLLVoltageChannels() + { + Meter meter; + DataSeries missingSeries; + + //Do this for every Voltage set + for (int i = 0; i < m_vIndices.Count(); i++) + { + // If all line voltages are already present or there are not + // at least 2 lines we will not perform line to line calculations + if (m_vIndices[i].DefinedLineVoltages == 3 || m_vIndices[i].DefinedNeutralVoltages < 2) + continue; + + // Get the meter associated with the channels in this data group + DataSeries VA = null; + DataSeries VB = null; + DataSeries VC = null; + + if (m_vIndices[i].Va > -1) + VA = m_dataGroup[m_vIndices[i].Va]; + if (m_vIndices[i].Vb > -1) + VB = m_dataGroup[m_vIndices[i].Vb]; + if (m_vIndices[i].Vc > -1) + VC = m_dataGroup[m_vIndices[i].Vc]; + + meter = (VA ?? VB ?? VC).SeriesInfo.Channel.Meter; + + if (m_vIndices[i].Vab == -1 && !(VA is null) && !(VB is null)) + { + // Calculate VAB = VA - VB + missingSeries = VA.Add(VB.Negate()); + missingSeries.SeriesInfo = GetSeriesInfo(meter, VA.SeriesInfo.Channel.Asset, "Voltage", "AB", m_dataGroup.SamplesPerHour); + missingSeries.Calculated = true; + m_vIndices[i].Vab = m_dataGroup.DataSeries.Count; + m_dataGroup.Add(missingSeries); + } + + if (m_vIndices[i].Vbc == -1 && !(VB is null) && !(VC is null)) + { + // Calculate VBC = VB - VC + missingSeries = VB.Add(VC.Negate()); + missingSeries.SeriesInfo = GetSeriesInfo(meter, VB.SeriesInfo.Channel.Asset, "Voltage", "BC", m_dataGroup.SamplesPerHour); + missingSeries.Calculated = true; + m_vIndices[i].Vbc = m_dataGroup.DataSeries.Count; + m_dataGroup.Add(missingSeries); + } + + if (m_vIndices[i].Vca == -1 && !(VC is null) && !(VA is null)) + { + // Calculate VCA = VC - VA + missingSeries = VC.Add(VA.Negate()); + missingSeries.SeriesInfo = GetSeriesInfo(meter, VC.SeriesInfo.Channel.Asset, "Voltage", "CA", m_dataGroup.SamplesPerHour); + missingSeries.Calculated = true; + m_vIndices[i].Vca = m_dataGroup.DataSeries.Count; + m_dataGroup.Add(missingSeries); + } + } + } + + public DataGroup ToDataGroup() + { + return new DataGroup(m_dataGroup.DataSeries, m_dataGroup.Asset); + } + + public VIDataGroup ToSubGroup(int startIndex, int endIndex) + { + VIDataGroup subGroup = new VIDataGroup(); + + subGroup.m_vIndices = m_vIndices; + subGroup.m_iaIndex = m_iaIndex; + subGroup.m_ibIndex = m_ibIndex; + subGroup.m_icIndex = m_icIndex; + subGroup.m_irIndex = m_irIndex; + + subGroup.m_dataGroup = m_dataGroup.ToSubGroup(startIndex, endIndex); + + return subGroup; + } + + public VIDataGroup ToSubGroup(DateTime startTime, DateTime endTime) + { + VIDataGroup subGroup = new VIDataGroup(); + + subGroup.m_vIndices = m_vIndices; + subGroup.m_iaIndex = m_iaIndex; + subGroup.m_ibIndex = m_ibIndex; + subGroup.m_icIndex = m_icIndex; + subGroup.m_irIndex = m_irIndex; + + subGroup.m_dataGroup = m_dataGroup.ToSubGroup(startTime, endTime); + + return subGroup; + } + + #endregion + + #region [ Static ] + + // Static Methods + private static Series GetSeriesInfo(Meter meter, Asset asset, string measurementTypeName, string phaseName, double samplesPerHour) + { + string measurementCharacteristicName = "Instantaneous"; + string seriesTypeName = "Values"; + + char typeDesignation = (measurementTypeName == "Current") ? 'I' : measurementTypeName[0]; + string phaseDesignation = (phaseName == "RES") ? "R" : phaseName.TrimEnd('N'); + string channelName = string.Concat(typeDesignation, phaseDesignation); + + ChannelKey channelKey = new ChannelKey(asset.ID, 0, channelName, measurementTypeName, measurementCharacteristicName, phaseName); + SeriesKey seriesKey = new SeriesKey(channelKey, seriesTypeName); + + Channel dbChannel = (meter.ConnectionFactory is null) + ? meter.Channels.FirstOrDefault(channel => channelKey.Equals(new ChannelKey(channel))) + : FastSearch(meter, channelKey); + + Series dbSeries = dbChannel?.Series + .FirstOrDefault(series => seriesKey.Equals(new SeriesKey(series))); + + if (dbSeries is null) + { + if (dbChannel is null) + { + MeasurementType measurementType = new MeasurementType() { Name = measurementTypeName }; + MeasurementCharacteristic measurementCharacteristic = new MeasurementCharacteristic() { Name = measurementCharacteristicName }; + Phase phase = new Phase() { Name = phaseName }; + + dbChannel = new Channel() + { + MeterID = meter.ID, + AssetID = asset.ID, + MeasurementTypeID = measurementType.ID, + MeasurementCharacteristicID = measurementCharacteristic.ID, + PhaseID = phase.ID, + Name = channelKey.Name, + SamplesPerHour = samplesPerHour, + Description = string.Concat(measurementCharacteristicName, " ", measurementTypeName, " ", phaseName), + Enabled = true, + + Meter = meter, + Asset = asset, + MeasurementType = measurementType, + MeasurementCharacteristic = measurementCharacteristic, + Phase = phase, + Series = new List() + }; + + meter.Channels.Add(dbChannel); + } + + SeriesType seriesType = new SeriesType() { Name = seriesTypeName }; + + dbSeries = new Series() + { + ChannelID = dbChannel.ID, + SeriesTypeID = seriesType.ID, + SourceIndexes = string.Empty, + + Channel = dbChannel, + SeriesType = seriesType + }; + + dbChannel.Series.Add(dbSeries); + } + + return dbSeries; + } + + private static Channel FastSearch(Meter meter, ChannelKey channelKey) + { + using (AdoDataConnection connection = meter.ConnectionFactory()) + { + Channel search = channelKey.Find(connection, meter.ID); + + if (search is null) + return null; + + return meter.Channels + .FirstOrDefault(channel => channel.ID == search.ID); + } + } + + #endregion + } +} diff --git a/src/Libraries/FaultData/FaultData.csproj b/src/Libraries/FaultData/FaultData.csproj new file mode 100644 index 00000000..f4297a8d --- /dev/null +++ b/src/Libraries/FaultData/FaultData.csproj @@ -0,0 +1,19 @@ + + + + net9.0 + enable + enable + + + + + + + + + + + + + diff --git a/src/Libraries/PQDS/DataSeries.cs b/src/Libraries/PQDS/DataSeries.cs new file mode 100644 index 00000000..5767e178 --- /dev/null +++ b/src/Libraries/PQDS/DataSeries.cs @@ -0,0 +1,94 @@ +//****************************************************************************************************** +// DataSeries.cs - Gbtc +// +// Copyright © 2020, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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: +// ---------------------------------------------------------------------------------------------------- +// 03/06/2020 - Christoph Lackner +// Generated original version of source code. +// +//****************************************************************************************************** + + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PQDS +{ + /// + /// Represents a channel in a PQDS File. + /// + public class DataSeries + { + #region[Properties] + + private List m_series; + private string m_label; + + /// + /// A collection of DataPoints. + /// + public List Series + { + get { return m_series; } + set { m_series = value; } + } + + /// + /// Label of the + /// + public string Label { get { return m_label; } } + + /// + /// length in number of points + /// + public int Length => m_series.Count(); + + #endregion[Properties] + + /// + /// Creates a new . + /// + /// Label of the DataSeries + public DataSeries(string label) + { + m_label = label; + m_series = new List(); + + } + #region[methods] + + #endregion[methods] + } + + /// + /// Represents a single Point in the . + /// + public class DataPoint + { + /// + /// Timestamp of the point. + /// + public DateTime Time; + + /// + /// Value of the point. + /// + public double Value; + } + + +} diff --git a/src/Libraries/PQDS/MetaDataTag.cs b/src/Libraries/PQDS/MetaDataTag.cs new file mode 100644 index 00000000..d08fc836 --- /dev/null +++ b/src/Libraries/PQDS/MetaDataTag.cs @@ -0,0 +1,421 @@ +//****************************************************************************************************** +// MetaDataTag.cs - Gbtc +// +// Copyright © 2020, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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: +// ---------------------------------------------------------------------------------------------------- +// 03/06/2020 - Christoph Lackner +// Generated original version of source code. +// +//****************************************************************************************************** + +using System; +using System.Collections.Generic; + +namespace PQDS +{ + /// + /// PQDS metadata tag Datatypes according to PQDS spec. + /// + public enum PQDSMetaDataType + { + /// + /// An integer representing a single value selected + /// from among a custom, finite set of possibilities + /// + Enumeration = 0, + + /// + /// A number + /// + Numeric = 1, + + /// + /// Text consisting only of alphabetical characters and digits + /// + AlphaNumeric = 2, + + /// + /// Freeform text + /// + Text = 3, + + /// + /// A Boolean value (true/false) + /// + Binary = 4 + + } + + /// + /// Abstract Class of MetaData Tags for a . + /// + public abstract class MetaDataTag + { + #region[Properties] + + /// + /// The key that identifies the metadata tag. + /// + protected string m_key; + + /// + /// The unit of measurement. + /// + protected string m_unit; + + /// + /// The data type the parser expects to encounter for the value of the metdata. + /// + protected PQDSMetaDataType m_expectedDataType; + + /// + /// Additional notes about the metadata field. + /// + protected string m_note; + + #endregion[Properties] + + #region[Methods] + + /// + /// the Metadata Tag key. + /// + public String Key { get { return (this.m_key); } } + + /// + /// Converst the Metadata tag into a line of a PQDS file + /// + /// The metadataTag as a String + public abstract String Write(); + + /// + /// Returns the PQDS datatype + /// + /// The PQDS Datatype + public abstract PQDSMetaDataType Type(); + + #endregion[Methods] + } + + /// + /// Class of MetaData Tags for a . + /// + public class MetaDataTag : MetaDataTag + { + #region[Properties] + + private DataType m_value; + + /// + /// Value of the MetadataTag. + /// + public DataType Value { get { return m_value; } } + + #endregion[Properties] + + #region[Constructor] + + /// + /// Creates a . + /// + /// key of the MetadataTag + /// Value of the MetadataTag + public MetaDataTag(String key, DataType value) + { + this.m_value = value; + + this.m_key = key; + if (!keyToDataTypeLookup.TryGetValue(key, out this.m_expectedDataType)) + this.m_expectedDataType = PQDSMetaDataType.Text; + + if (!keyToUnitLookup.TryGetValue(key, out this.m_unit)) + this.m_unit = null; + + if (!keyToNoteLookup.TryGetValue(key, out this.m_note)) + this.m_note = null; + + //Check to ensure a string does not end up being a number etc... + if (this.m_expectedDataType == PQDSMetaDataType.AlphaNumeric) + { + if (!((value is string) | (value is Guid))) + { throw new InvalidCastException("Can not cast object to Alphanumeric Type"); } + } + else if (this.m_expectedDataType == PQDSMetaDataType.Numeric) + { + if (!((value is int) | (value is double))) + { throw new InvalidCastException("Can not cast object to Numeric Type"); } + } + else if (this.m_expectedDataType == PQDSMetaDataType.Enumeration) + { + if (!((value is int))) + { throw new InvalidCastException("Can not cast object to Numeric Type"); } + } + else if (this.m_expectedDataType == PQDSMetaDataType.Binary) + { + if (!((value is int) | (value is Boolean))) + { throw new InvalidCastException("Can not cast object to Numeric Type"); } + } + + } + + /// + /// Creates a custom . + /// + /// key of the MetadataTag + /// Value of the MetadataTag + /// The of the metadata tag + /// The unit of the metadata tag + /// a describtion of the metadata tag + public MetaDataTag(String key, DataType value, PQDSMetaDataType valueType, String unit, String description) + { + this.m_value = value; + + this.m_key = key; + this.m_expectedDataType = valueType; + + if (unit.Trim('"') == "") { this.m_unit = null; } + else { this.m_unit = unit.Trim('"'); } + + if (description.Trim('"') == "") { this.m_note = null; } + else { this.m_note = description.Trim('"'); } + + } + + #endregion[Constructor] + + #region[Methods] + + /// + /// Converst the Metadata tag into a line of a PQDS file + /// + /// The metadataTag as a String + public override string Write() + { + string result = String.Format("{0},\"{1}\",{2},{3},\"{4}\"", + this.m_key, this.m_value, this.m_unit, DataTypeToCSV(this.m_expectedDataType), this.m_note); + + return result; + } + + /// + /// Returns the PQDS datatype + /// + /// The PQDS Datatype + public override PQDSMetaDataType Type() + { + return this.m_expectedDataType; + } + + #endregion[Methods] + + #region[Statics] + + private static readonly Dictionary keyToDataTypeLookup = new Dictionary() + { + {"DeviceName", PQDSMetaDataType.Text }, + {"DeviceAlias", PQDSMetaDataType.Text }, + {"DeviceLocation", PQDSMetaDataType.Text }, + {"DeviceLocationAlias", PQDSMetaDataType.Text }, + {"DeviceLatitude", PQDSMetaDataType.Text }, + {"DeviceLongitude", PQDSMetaDataType.Text }, + {"Accountname", PQDSMetaDataType.Text }, + {"AccountNameAlias", PQDSMetaDataType.Text }, + {"DeviceDistanceToXFMR", PQDSMetaDataType.Numeric }, + {"DeviceConnectionTypeCode", PQDSMetaDataType.Enumeration }, + {"DeviceOwner", PQDSMetaDataType.Text }, + {"NominalVoltage-LG", PQDSMetaDataType.Numeric }, + {"NominalFrequency", PQDSMetaDataType.Numeric }, + {"UpstreamXFMR-kVA", PQDSMetaDataType.Numeric }, + {"LineLength", PQDSMetaDataType.Numeric }, + {"AssetName", PQDSMetaDataType.Text }, + {"EventGUID", PQDSMetaDataType.AlphaNumeric }, + {"EventID", PQDSMetaDataType.Text }, + {"EventYear", PQDSMetaDataType.Enumeration }, + {"EventMonth", PQDSMetaDataType.Enumeration }, + {"EventDay", PQDSMetaDataType.Enumeration }, + {"EventHour", PQDSMetaDataType.Enumeration }, + {"EventMinute", PQDSMetaDataType.Enumeration }, + {"EventSecond", PQDSMetaDataType.Enumeration }, + {"EventNanoSecond", PQDSMetaDataType.Numeric }, + {"EventDate", PQDSMetaDataType.Text }, + {"EventTime", PQDSMetaDataType.Text }, + {"EventTypeCode", PQDSMetaDataType.Enumeration }, + {"EventFaultTypeCode", PQDSMetaDataType.Enumeration }, + {"EventPeakCurrent", PQDSMetaDataType.Numeric }, + {"EventPeakVoltage", PQDSMetaDataType.Numeric }, + {"EventMaxVA", PQDSMetaDataType.Numeric }, + {"EventMaxVB", PQDSMetaDataType.Numeric }, + {"EventMaxVC", PQDSMetaDataType.Numeric }, + {"EventMinVA", PQDSMetaDataType.Numeric }, + {"EventMinVB", PQDSMetaDataType.Numeric }, + {"EventMinVC", PQDSMetaDataType.Numeric }, + {"EventMaxIA", PQDSMetaDataType.Numeric }, + {"EventMaxIB", PQDSMetaDataType.Numeric }, + {"EventMaxIC", PQDSMetaDataType.Numeric }, + {"EventPreEventCurrent", PQDSMetaDataType.Numeric }, + {"EventPreEventVoltage", PQDSMetaDataType.Numeric }, + {"EventDuration", PQDSMetaDataType.Numeric }, + {"EventFaultI2T", PQDSMetaDataType.Numeric }, + {"DistanceToFault", PQDSMetaDataType.Numeric }, + {"EventCauseCode", PQDSMetaDataType.Enumeration }, + {"WaveformDataType", PQDSMetaDataType.Enumeration }, + {"WaveFormSensitivityCode", PQDSMetaDataType.Enumeration }, + {"WaveFormSensitivityNote", PQDSMetaDataType.Text }, + {"Utility", PQDSMetaDataType.Text }, + {"ContactEmail", PQDSMetaDataType.Text } + }; + + private static readonly Dictionary keyToUnitLookup = new Dictionary() + { + {"DeviceName", null }, + {"DeviceAlias", null }, + {"DeviceLocation", null }, + {"DeviceLocationAlias", null }, + {"DeviceLatitude", null }, + {"DeviceLongitude", null }, + {"Accountname", null }, + {"AccountNameAlias", null }, + {"DeviceDistanceToXFMR", "feet" }, + {"DeviceConnectionTypeCode", null }, + {"DeviceOwner", null }, + {"NominalVoltage-LG", "Volts" }, + {"NominalFrequency", "Hz" }, + {"UpstreamXFMR-kVA", "kVA" }, + {"LineLength", "miles" }, + {"AssetName", null }, + {"EventGUID", null }, + {"EventID", null }, + {"EventYear", null }, + {"EventMonth", null }, + {"EventDay", null }, + {"EventHour", null }, + {"EventMinute", null }, + {"EventSecond", null }, + {"EventNanoSecond", null }, + {"EventDate", null }, + {"EventTime", null }, + {"EventTypeCode", null }, + {"EventFaultTypeCode", null }, + {"EventPeakCurrent", "Amps" }, + {"EventPeakVoltage", "Volts" }, + {"EventMaxVA", "Volts" }, + {"EventMaxVB", "Volts" }, + {"EventMaxVC", "Volts" }, + {"EventMinVA", "Volts" }, + {"EventMinVB", "Volts" }, + {"EventMinVC", "Volts" }, + {"EventMaxIA", "Amps" }, + {"EventMaxIB", "Amps" }, + {"EventMaxIC", "Amps" }, + {"EventPreEventCurrent", "Amps" }, + {"EventPreEventVoltage", "Volts" }, + {"EventDuration", "ms" }, + {"EventFaultI2T", "A2s" }, + {"DistanceToFault", "miles" }, + {"EventCauseCode", null }, + {"WaveformDataType", null }, + {"WaveFormSensitivityCode", null }, + {"WaveFormSensitivityNote", null }, + {"Utility", null }, + {"ContactEmail", null } + }; + + private static readonly Dictionary keyToNoteLookup = new Dictionary() + { + {"DeviceName", "Meter or measurement device name" }, + {"DeviceAlias", "Alternate meter or measurement device name" }, + {"DeviceLocation", "Meter or measurment device location name" }, + {"DeviceLocationAlias", "Alternate meter or device location name" }, + {"DeviceLatitude", "Latitude" }, + {"DeviceLongitude", "Longtitude" }, + {"Accountname", "Name of customer or account" }, + {"AccountNameAlias", "Alternate name of customer or account" }, + {"DeviceDistanceToXFMR", "Distance to the upstream transformer" }, + {"DeviceConnectionTypeCode", "PQDS code for meter connection type" }, + {"DeviceOwner", "Utility name" }, + {"NominalVoltage-LG", "Nominal Line to Ground Voltage" }, + {"NominalFrequency", "Nominal System frequency" }, + {"UpstreamXFMR-kVA", "Upstream Transformer size" }, + {"LineLength", "Length of the Line" }, + {"AssetName", "Asset name" }, + {"EventGUID", "Globally Unique Event Identifier" }, + {"EventID", "A user defined Event Name" }, + {"EventYear", "Year" }, + {"EventMonth", "Month" }, + {"EventDay", "Day" }, + {"EventHour", "Hour" }, + {"EventMinute", "Minute" }, + {"EventSecond", "Second" }, + {"EventNanoSecond", "Nanosconds" }, + {"EventDate", "Event Date" }, + {"EventTime", "Event Time" }, + {"EventTypeCode", "PQDS Event Type Code" }, + {"EventFaultTypeCode", "PQDS Fault Type Code" }, + {"EventPeakCurrent", "Peak Current"}, + {"EventPeakVoltage", "Peak Voltage" }, + {"EventMaxVA", "RMS Maximum A Phase Voltage" }, + {"EventMaxVB", "RMS Maximum B Phase Voltage" }, + {"EventMaxVC", "RMS Maximum C Phase Voltage" }, + {"EventMinVA", "RMS Minimum A Phase Voltage" }, + {"EventMinVB", "RMS Minimum B Phase Voltage" }, + {"EventMinVC", "RMS Minimum C Phase Voltage" }, + {"EventMaxIA", "RMS Maximum A Phase Current" }, + {"EventMaxIB", "RMS Maximum B Phase Current" }, + {"EventMaxIC", "RMS Maximum C Phase Current" }, + {"EventPreEventCurrent", "Pre Event Current" }, + {"EventPreEventVoltage", "pre Event Voltage" }, + {"EventDuration", "Event Duration" }, + {"EventFaultI2T", "I2(t) during Fault duration" }, + {"DistanceToFault", "Distance to Fault" }, + {"EventCauseCode", "PQDS Event Cause Code" }, + { "WaveformDataType", "PQDS Data Type Code"}, + {"WaveFormSensitivityCode", "PQDS Data Sensitivity Code" }, + {"WaveFormSensitivityNote", "Notes on the PQDS Data Sensitivity Code" }, + {"Utility", "Utility that Generated this Dataset" }, + {"ContactEmail", "Contact for Utility that Created this Dataset" } + }; + + private static string DataTypeToCSV(PQDSMetaDataType dataType) + { + switch (dataType) + { + case (PQDSMetaDataType.Text): + return "T"; + case (PQDSMetaDataType.Numeric): + return "N"; + case (PQDSMetaDataType.Enumeration): + return "E"; + case (PQDSMetaDataType.AlphaNumeric): + return "A"; + case (PQDSMetaDataType.Binary): + return "B"; + default: + return "T"; + } + } + + + #endregion[Statics] + + + + + + + } + + +} diff --git a/src/Libraries/PQDS/PQDS.csproj b/src/Libraries/PQDS/PQDS.csproj new file mode 100644 index 00000000..c29cf134 --- /dev/null +++ b/src/Libraries/PQDS/PQDS.csproj @@ -0,0 +1,23 @@ + + + netstandard2.0 + Library + PQDS + PQDS + Copyright © 2020 + 3.0.5.69 + 3.0.5.69 + + + ..\..\..\Build\Output\Debug\Libraries\ + ..\..\..\Build\Output\Debug\Libraries\PQDS.xml + + + ..\..\..\Build\Output\Release\Libraries\ + ..\..\..\Build\Output\Release\Libraries\PQDS.xml + + + + + + \ No newline at end of file diff --git a/src/Libraries/PQDS/PQDSFile.cs b/src/Libraries/PQDS/PQDSFile.cs new file mode 100644 index 00000000..17f3cc52 --- /dev/null +++ b/src/Libraries/PQDS/PQDSFile.cs @@ -0,0 +1,541 @@ +//****************************************************************************************************** +// PQDSFile.cs - Gbtc +// +// Copyright © 2020, 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 Eclipse Public License -v 1.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a copy of the License at: +// +// http://www.opensource.org/licenses/eclipse-1.0.php +// +// 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: +// ---------------------------------------------------------------------------------------------------- +// 03/06/2020 - Christoph Lackner +// Generated original version of source code. +// +//****************************************************************************************************** + + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; + +namespace PQDS +{ + /// + /// Class that represents a PQDS file. + /// + public class PQDSFile + { + #region[Properties] + + private List m_metaData; + private List m_Data; + private DateTime m_initialTS; + + #endregion[Properties] + + #region[Constructors] + /// + /// Creates a new PQDS file. + /// + /// Measurment data to be included as + /// Timestamp used as the beginning of the PQDS file + /// List of MetaData to be included in the PQDS file as + public PQDSFile(List metaData, List dataSeries, DateTime initialTimeStamp) + { + if (metaData is null) { this.m_metaData = new List(); } + else { this.m_metaData = metaData; } + + this.m_initialTS = initialTimeStamp; + this.m_Data = dataSeries; + } + + /// + /// Creates a new PQDS file. + /// + public PQDSFile() + { + this.m_metaData = new List(); + this.m_Data = new List(); + } + + #endregion[Constructors] + + #region[Methods] + + private void GetStartTime() + { + DateTime result; + int? day = null; + int? month = null; + int? year = null; + + if (this.m_metaData.Select(item => item.Key).Contains("eventdate")) + { + string val = ((MetaDataTag)this.m_metaData.Find(item => item.Key == "eventdate")).Value; + if (DateTime.TryParseExact(val, "MM/dd/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out result)) + { + day = result.Day; + month = result.Month; + year = result.Year; + } + } + if (day is null) + { + if (this.m_metaData.Select(item => item.Key).Contains("eventday")) + { + day = ((MetaDataTag)this.m_metaData.Find(item => item.Key == "eventday")).Value; + } + else + { + day = DateTime.Now.Day; + } + } + if (month is null) + { + if (this.m_metaData.Select(item => item.Key).Contains("eventmonth")) + { + month = ((MetaDataTag)this.m_metaData.Find(item => item.Key == "eventmonth")).Value; + } + else + { + month = DateTime.Now.Month; + } + } + if (year is null) + { + if (this.m_metaData.Select(item => item.Key).Contains("eventyear")) + { + year = ((MetaDataTag)this.m_metaData.Find(item => item.Key == "eventyear")).Value; + } + else + { + year = DateTime.Now.Year; + } + } + + int? hour = null; + int? minute = null; + int? second = null; + + if (this.m_metaData.Select(item => item.Key).Contains("eventtime")) + { + string val = ((MetaDataTag)this.m_metaData.Find(item => item.Key == "eventtime")).Value; + if (DateTime.TryParseExact(val, "HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out result)) + { + hour = result.Hour; + minute = result.Minute; + second = result.Second; + } + } + if (hour is null) + { + if (this.m_metaData.Select(item => item.Key).Contains("eventhour")) + { + hour = ((MetaDataTag)this.m_metaData.Find(item => item.Key == "eventhour")).Value; + } + else + { + hour = DateTime.Now.Hour; + } + } + if (minute is null) + { + if (this.m_metaData.Select(item => item.Key).Contains("eventminute")) + { + minute = ((MetaDataTag)this.m_metaData.Find(item => item.Key == "eventminute")).Value; + } + else + { + minute = DateTime.Now.Minute; + } + } + if (second is null) + { + if (this.m_metaData.Select(item => item.Key).Contains("eventsecond")) + { + second = ((MetaDataTag)this.m_metaData.Find(item => item.Key == "eventsecond")).Value; + } + else + { + second = DateTime.Now.Second; + } + } + + + result = new DateTime((int)year, (int)month, (int)day, (int)hour, (int)minute, (int)second); + + this.m_initialTS = result; + } + + private MetaDataTag CreateMetaData(string[] flds) + { + + string dataTypeString = flds[3].Trim().ToUpper(); + PQDSMetaDataType dataType; + + switch (dataTypeString) + { + case "N": + { + dataType = PQDSMetaDataType.Numeric; + break; + } + case "E": + { + dataType = PQDSMetaDataType.Enumeration; + break; + } + case "B": + { + dataType = PQDSMetaDataType.Binary; + break; + } + case "A": + { + dataType = PQDSMetaDataType.AlphaNumeric; + break; + } + default: + { + dataType = PQDSMetaDataType.Text; + break; + } + } + + string key = flds[0].Trim().ToLower(); + string note = flds[4].Trim('"'); + string unit = flds[2].Trim('"'); + + switch (dataType) + { + case (PQDSMetaDataType.AlphaNumeric): + { + string value = flds[1].Trim('"'); + return new MetaDataTag(key, value, dataType, unit, note); + } + case (PQDSMetaDataType.Text): + { + string value = flds[1].Trim('"'); + return new MetaDataTag(key, value, dataType, unit, note); + } + case (PQDSMetaDataType.Enumeration): + { + int value = Convert.ToInt32(flds[1].Trim('"')); + return new MetaDataTag(key, value, dataType, unit, note); + } + case (PQDSMetaDataType.Numeric): + { + double value = Convert.ToDouble(flds[1].Trim('"')); + return new MetaDataTag(key, value, dataType, unit, note); + } + case (PQDSMetaDataType.Binary): + { + Boolean value = Convert.ToBoolean(flds[1].Trim('"')); + return new MetaDataTag(key, value, dataType, unit, note); + } + default: + { + string value = flds[1].Trim('"'); + return new MetaDataTag(key, value, dataType, unit, note); + } + } + + + } + + private Boolean IsDataHeader(string line) + { + if (!line.Contains(",")) + return false; + String[] flds = line.Split(','); + + if (flds[0].ToLower().Trim() == "waveform-data") + return true; + + return false; + } + + /// + /// List of included Metadata tags. + /// + public List MetaData + { + get { return this.m_metaData; } + } + + /// + /// List of data included in PQDS file as . + /// + public List Data + { + get { return this.m_Data; } + } + + /// + /// Writes the content to a .csv file. + /// + /// The to write the data to. + /// Progress Token + public void WriteToStream(StreamWriter stream, IProgress progress) + { + int n_data = this.Data.Select((item) => item.Length).Max(); + int n_total = n_data + n_data + this.m_metaData.Count() + 1; + + //create the metadata header + List lines = new List(); + lines = this.m_metaData.Select(item => item.Write()).ToList(); + + lines.AddRange(DataLines(n_total, progress)); + + for (int i = 0; i < lines.Count(); i++) + { + stream.WriteLine(lines[i]); + progress.Report((double)(n_data + i) / n_total); + } + + + } + + /// + /// Writes the content to a .csv file. + /// + /// file name + /// Progress Token + public void WriteToFile(string file, IProgress progress) + { + // Open the file and write in each line + using (StreamWriter fileWriter = new StreamWriter(File.OpenWrite(file))) + { + WriteToStream(fileWriter, progress); + } + + } + /// + /// Writes the content to a .csv file. + /// + /// file name + public void WriteToFile(string file) + { + Progress prog = new Progress(); + WriteToFile(file, prog); + } + + /// + /// Writes the content to an output Stream. + /// + /// The to write the data to. + public void WriteToStream(StreamWriter stream) + { + Progress prog = new Progress(); + WriteToStream(stream, prog); + } + + + + /// + /// Reads the content from a PQDS File. + /// + /// file name + public void ReadFromFile(string filename) + { + Progress prog = new Progress(); + ReadFromFile(filename, prog); + } + + + /// + /// Reads the content from a PQDS File. + /// + /// file name + /// Progress Token + public void ReadFromFile(string filename, IProgress progress) + { + List lines = new List(); + // Open the file and read each line + using (StreamReader fileReader = new StreamReader(File.OpenRead(filename))) + { + while (!fileReader.EndOfStream) + { + lines.Add(fileReader.ReadLine().Trim()); + } + } + + int index = 0; + String[] flds; + // Parse MetaData Section + this.m_metaData = new List(); + + while (!(IsDataHeader(lines[index]))) + { + if (!lines[index].Contains(",")) + { + index++; + continue; + } + + flds = lines[index].Split(','); + + if (flds.Count() < 5) + { + index++; + continue; + } + this.m_metaData.Add(CreateMetaData(flds)); + index++; + + if (index == lines.Count()) + { throw new InvalidDataException("PQDS File not valid"); } + progress.Report((double)index / (double)lines.Count()); + } + + //Parse Data Header + flds = lines[index].Split(','); + + if (flds.Count() < 2) + { + throw new InvalidDataException("PQDS File has invalid data section or no data"); + } + + this.m_Data = new List(); + List signals = new List(); + List> data = new List>(); + + + for (int i = 1; i < flds.Count(); i++) + { + if (signals.Contains(flds[i].Trim().ToLower())) + { + continue; + } + this.m_Data.Add(new DataSeries(flds[i].Trim().ToLower())); + signals.Add(flds[i].Trim().ToLower()); + data.Add(new List()); + } + + index++; + //Parse Data + GetStartTime(); + + while (index < lines.Count()) + { + if (!lines[index].Contains(",")) + { + index++; + continue; + } + + flds = lines[index].Split(','); + + if (flds.Count() != (this.m_Data.Count() + 1)) + { + index++; + continue; + } + DateTime TS; + try + { + double ticks = Convert.ToDouble(flds[0].Trim()); + TS = this.m_initialTS + new TimeSpan((Int64)(ticks * 100)); + } + catch + { + index++; + continue; + } + + for (int i = 0; i < signals.Count(); i++) + { + try + { + double value = Convert.ToDouble(flds[i + 1].Trim()); + data[i].Add(new DataPoint() { Time = TS, Value = value }); + } + catch + { + continue; + } + } + + progress.Report((double)index / (double)lines.Count()); + index++; + } + + for (int i = 0; i < signals.Count(); i++) + { + int j = this.m_Data.FindIndex(item => item.Label == signals[i]); + this.m_Data[j].Series = data[j]; + } + } + + private List DataLines(int n_total, IProgress progress) + { + List result = new List(); + + //ensure they all start at the same Time + List measurements = this.m_Data.Select(item => item.Label).ToList(); + DateTime initalStart = this.m_Data.Select(item => item.Series[0].Time).Min(); + List startTime = this.m_Data.Select(item => item.Series[0].Time - initalStart).ToList(); + + //1 ms difference is ok + if (startTime.Max().TotalMilliseconds > 1) + { + throw new Exception("The measurements start at different times"); + } + + //write the header + result.Add("waveform-data," + String.Join(",", measurements)); + + + //write the Data + // Logic for skipping datapoints if they don't have the same sampling rate + List samplingRates = m_Data.Select(item => item.Length).Distinct().ToList(); + + int n_data = samplingRates.Max(); + + Dictionary> reSampling = new Dictionary>(); + + if (samplingRates.Any(f => ((double)n_data / (double)f) % 1 != 0)) + throw new Exception("Sampling Rates in this File do not match and are not multiples of each other."); + + reSampling = samplingRates.Select(item => new KeyValuePair>(item, (int index, DataSeries ds) => { + int n = n_data / item; + if (index % n == 0) + return ds.Series[index / n].Value; + else + return double.NaN; + })) + .ToDictionary(item => item.Key, item => item.Value); + + for (int i = 0; i < n_data; i++) + { + TimeSpan dT = m_Data[0].Series[i].Time - m_initialTS; + result.Add(Convert.ToString(dT.TotalMilliseconds) + "," + + String.Join(",", m_Data.Select(item => { + double v = reSampling[item.Length](i, item); + if (double.IsNaN(v)) + return "NaN".PadLeft(12); + return String.Format("{0:F12}", v); + }).ToList())); + progress.Report((double)i / (double)n_total); + } + + return result; + + } + + #endregion[Methods] + + } + + +} diff --git a/src/Libraries/PQDS/Properties/AssemblyInfo.cs b/src/Libraries/PQDS/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..b6c46133 --- /dev/null +++ b/src/Libraries/PQDS/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +[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("c6e64ba2-dca7-4a34-973a-2306a1f9effc")] diff --git a/src/Libraries/openXDA.Model/Channels/Channel.cs b/src/Libraries/openXDA.Model/Channels/Channel.cs new file mode 100644 index 00000000..491748e4 --- /dev/null +++ b/src/Libraries/openXDA.Model/Channels/Channel.cs @@ -0,0 +1,580 @@ +//****************************************************************************************************** +// Channel.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Transactions; +using Gemstone.Data; +using Gemstone.Data.Model; +using Newtonsoft.Json; +using IsolationLevel = System.Transactions.IsolationLevel; + +namespace openXDA.Model +{ + public class ChannelKey : IEquatable + { + #region [ Constructors ] + + public ChannelKey(int assetID, int harmonicGroup, string name, string measurementType, string measurementCharacteristic, string phase) + { + LineID = assetID; + HarmonicGroup = harmonicGroup; + Name = name; + MeasurementType = measurementType; + MeasurementCharacteristic = measurementCharacteristic; + Phase = phase; + } + + public ChannelKey(Channel channel) + : this(channel.AssetID, channel.HarmonicGroup, channel.Name, channel.MeasurementType.Name, channel.MeasurementCharacteristic.Name, channel.Phase.Name) + { + } + + #endregion + + #region [ Properties ] + + public int LineID { get; } + public int HarmonicGroup { get; } + public string Name { get; } + public string MeasurementType { get; } + public string MeasurementCharacteristic { get; } + public string Phase { get; } + + #endregion + + #region [ Methods ] + + public Channel Find(AdoDataConnection connection, int meterID) + { + const string QueryFormat = + "SELECT Channel.* " + + "FROM " + + " Channel JOIN " + + " MeasurementType ON Channel.MeasurementTypeID = MeasurementType.ID JOIN " + + " MeasurementCharacteristic ON Channel.MeasurementCharacteristicID = MeasurementCharacteristic.ID JOIN " + + " Phase ON Channel.PhaseID = Phase.ID " + + "WHERE " + + " Channel.MeterID = {0} AND " + + " Channel.AssetID = {1} AND " + + " Channel.HarmonicGroup = {2} AND " + + " Channel.Name = {3} AND " + + " MeasurementType.Name = {4} AND " + + " MeasurementCharacteristic.Name = {5} AND " + + " Phase.Name = {6}"; + + object[] parameters = + { + meterID, + LineID, + HarmonicGroup, + Name, + MeasurementType, + MeasurementCharacteristic, + Phase + }; + + using (DataTable table = connection.RetrieveData(QueryFormat, parameters)) + { + if (table.Rows.Count == 0) + return null; + + TableOperations channelTable = new TableOperations(connection); + return channelTable.LoadRecord(table.Rows[0]); + } + } + + public override int GetHashCode() + { + StringComparer stringComparer = StringComparer.OrdinalIgnoreCase; + + int hash = 1009; + hash = 9176 * hash + LineID.GetHashCode(); + hash = 9176 * hash + HarmonicGroup.GetHashCode(); + hash = 9176 * hash + stringComparer.GetHashCode(Name); + hash = 9176 * hash + stringComparer.GetHashCode(MeasurementType); + hash = 9176 * hash + stringComparer.GetHashCode(MeasurementCharacteristic); + hash = 9176 * hash + stringComparer.GetHashCode(Phase); + return hash; + } + + public override bool Equals(object obj) + { + return Equals(obj as ChannelKey); + } + + public bool Equals(ChannelKey other) + { + if (other is null) + return false; + + StringComparison stringComparison = StringComparison.OrdinalIgnoreCase; + + return + LineID.Equals(other.LineID) && + HarmonicGroup.Equals(other.HarmonicGroup) && + Name.Equals(other.Name, stringComparison) && + MeasurementType.Equals(other.MeasurementType, stringComparison) && + MeasurementCharacteristic.Equals(other.MeasurementCharacteristic, stringComparison) && + Phase.Equals(other.Phase, stringComparison); + } + + #endregion + } + + [TableName("Channel")] + public class ChannelBase + { + [PrimaryKey(true)] + public int ID { get; set; } + + [ParentKey(typeof(Meter))] + public int MeterID { get; set; } + + public int AssetID { get; set; } + + public int MeasurementTypeID { get; set; } + + public int MeasurementCharacteristicID { get; set; } + + public int PhaseID { get; set; } + + [StringLength(200)] + public string Name { get; set; } + + public double Adder { get; set; } + + [DefaultValue(1.0D)] + public double Multiplier { get; set; } = 1.0D; + + public double SamplesPerHour { get; set; } + + public double? PerUnitValue { get; set; } + + public int HarmonicGroup { get; set; } + + public string Description { get; set; } + + public bool Enabled { get; set; } + + [DefaultValue(false)] + public bool Trend { get; set; } + + [DefaultValue(0)] + public int ConnectionPriority { get; set; } = 0; + } + + public class Channel : ChannelBase + { + #region [ Members ] + + // Fields + private MeasurementType m_measurementType; + private MeasurementCharacteristic m_measurementCharacteristic; + private Phase m_phase; + private Meter m_meter; + private Asset m_asset; + private List m_series; + + #endregion + + #region [ Properties ] + + [JsonIgnore] + [NonRecordField] + public MeasurementType MeasurementType + { + get + { + if (m_measurementType is null) + m_measurementType = LazyContext.GetMeasurementType(MeasurementTypeID); + + if (m_measurementType is null) + m_measurementType = QueryMeasurementType(); + + return m_measurementType; + } + set => m_measurementType = value; + } + + [JsonIgnore] + [NonRecordField] + public MeasurementCharacteristic MeasurementCharacteristic + { + get + { + if (m_measurementCharacteristic is null) + m_measurementCharacteristic = LazyContext.GetMeasurementCharacteristic(MeasurementCharacteristicID); + + if (m_measurementCharacteristic is null) + m_measurementCharacteristic = QueryMeasurementCharacteristic(); + + return m_measurementCharacteristic; + } + set => m_measurementCharacteristic = value; + } + + [JsonIgnore] + [NonRecordField] + public Phase Phase + { + get + { + if (m_phase is null) + m_phase = LazyContext.GetPhase(PhaseID); + + if (m_phase is null) + m_phase = QueryPhase(); + + return m_phase; + } + set => m_phase = value; + } + + [JsonIgnore] + [NonRecordField] + public Meter Meter + { + get + { + if (m_meter is null) + m_meter = LazyContext.GetMeter(MeterID); + + if (m_meter is null) + m_meter = QueryMeter(); + + return m_meter; + } + set => m_meter = value; + } + + [JsonIgnore] + [NonRecordField] + public Asset Asset + { + get + { + if (m_asset is null) + m_asset = LazyContext.GetAsset(AssetID); + + if (m_asset is null) + m_asset = QueryAsset(); + + return m_asset; + } + set => m_asset = value; + } + + [JsonIgnore] + [NonRecordField] + public List Series + { + get => m_series ?? (m_series = QuerySeries()); + set => m_series = value; + } + + [JsonIgnore] + [NonRecordField] + public Func ConnectionFactory + { + get => LazyContext.ConnectionFactory; + set => LazyContext.ConnectionFactory = value; + } + + [JsonIgnore] + [NonRecordField] + internal LazyContext LazyContext { get; set; } = new LazyContext(); + + #endregion + + #region [ Methods ] + + public MeasurementType GetMeasurementType(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations measurementTypeTable = new TableOperations(connection); + return measurementTypeTable.QueryRecordWhere("ID = {0}", MeasurementTypeID); + } + + public MeasurementCharacteristic GetMeasurementCharacteristic(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations measurementCharacteristicTable = new TableOperations(connection); + return measurementCharacteristicTable.QueryRecordWhere("ID = {0}", MeasurementCharacteristicID); + } + + public Phase GetPhase(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations phaseTable = new TableOperations(connection); + return phaseTable.QueryRecordWhere("ID = {0}", PhaseID); + } + + public Meter GetMeter(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations meterTable = new TableOperations(connection); + return meterTable.QueryRecordWhere("ID = {0}", MeterID); + } + + public Asset GetAsset(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations assetTable = new TableOperations(connection); + return assetTable.QueryRecordWhere("ID = {0}", AssetID); + } + + public IEnumerable GetSeries(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations seriesTable = new TableOperations(connection); + return seriesTable.QueryRecordsWhere("ChannelID = {0}", ID); + } + + private MeasurementType QueryMeasurementType() + { + MeasurementType measurementType; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + measurementType = GetMeasurementType(connection); + } + + return LazyContext.GetMeasurementType(measurementType); + } + + private MeasurementCharacteristic QueryMeasurementCharacteristic() + { + MeasurementCharacteristic measurementCharacteristic; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + measurementCharacteristic = GetMeasurementCharacteristic(connection); + } + + return LazyContext.GetMeasurementCharacteristic(measurementCharacteristic); + } + + private Phase QueryPhase() + { + Phase phase; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + phase = GetPhase(connection); + } + + return LazyContext.GetPhase(phase); + } + + private Meter QueryMeter() + { + Meter meter; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + meter = GetMeter(connection); + } + + if ((object)meter != null) + meter.LazyContext = LazyContext; + + return LazyContext.GetMeter(meter); + } + + private Asset QueryAsset() + { + Asset asset; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + asset = GetAsset(connection); + } + + if ((object)asset != null) + asset.LazyContext = LazyContext; + + return LazyContext.GetAsset(asset); + } + + private List QuerySeries() + { + List seriesList; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + seriesList = GetSeries(connection)? + .Select(LazyContext.GetSeries) + .ToList(); + } + + if ((object)seriesList != null) + { + foreach (Series series in seriesList) + { + series.Channel = this; + series.LazyContext = LazyContext; + } + } + + return seriesList; + } + + #endregion + } + + public class ChannelComparer : IEqualityComparer + { + public bool Equals(Channel x, Channel y) + { + if (Object.ReferenceEquals(x, y)) return true; + + //Check whether any of the compared objects is null. + if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) + return false; + + //Check whether the channels are equal. + return x.ID == y.ID; + } + + public int GetHashCode(Channel obj) + { + return obj.ID; + } + } + + public class ChannelInfo + { + [PrimaryKey(true)] + public int ChannelID { get; set; } + + public string ChannelName { get; set; } + + public string ChannelDescription { get; set; } + + public string MeasurementType { get; set; } + + public string MeasurementCharacteristic { get; set; } + + public string Phase { get; set; } + + public string SeriesType { get; set; } + + public string Orientation { get; set; } + + public string Phasing { get; set; } + } + + public static partial class TableOperationsExtensions + { + public static DashSettings GetOrAdd(this TableOperations table, string name, string value, bool enabled = true) + { + TransactionScopeOption required = TransactionScopeOption.Required; + + TransactionOptions transactionOptions = new TransactionOptions() + { + IsolationLevel = IsolationLevel.ReadCommitted, + Timeout = TransactionManager.MaximumTimeout + }; + + DashSettings dashSettings; + + using (TransactionScope transactionScope = new TransactionScope(required, transactionOptions)) + { + if (value.Contains(",")) + dashSettings = table.QueryRecordWhere("Name = {0} AND SUBSTRING(Value, 0, CHARINDEX(',', Value)) = {1}", name, value.Split(',').First()); + else + dashSettings = table.QueryRecordWhere("Name = {0} AND Value = {1}", name, value); + + if ((object)dashSettings == null) + { + dashSettings = new DashSettings(); + dashSettings.Name = name; + dashSettings.Value = value; + dashSettings.Enabled = enabled; + + table.AddNewRecord(dashSettings); + + dashSettings.ID = table.Connection.ExecuteScalar("SELECT @@IDENTITY"); + } + + transactionScope.Complete(); + } + + return dashSettings; + } + + public static UserDashSettings GetOrAdd(this TableOperations table, string name, Guid user, string value, bool enabled = true) + { + TransactionScopeOption required = TransactionScopeOption.Required; + + TransactionOptions transactionOptions = new TransactionOptions() + { + IsolationLevel = IsolationLevel.ReadCommitted, + Timeout = TransactionManager.MaximumTimeout + }; + + UserDashSettings dashSettings; + + using (TransactionScope transactionScope = new TransactionScope(required, transactionOptions)) + { + if (value.Contains(",")) + dashSettings = table.QueryRecordWhere("Name = {0} AND SUBSTRING(Value, 0, CHARINDEX(',', Value)) = {1} AND UserAccountID = {2}", name, value.Split(',').First(), user); + else + dashSettings = table.QueryRecordWhere("Name = {0} AND Value = {1} AND UserAccountID = {2}", name, value, user); + + if ((object)dashSettings == null) + { + dashSettings = new UserDashSettings(); + dashSettings.Name = name; + dashSettings.Value = value; + dashSettings.Enabled = enabled; + dashSettings.UserAccountID = user; + + table.AddNewRecord(dashSettings); + + dashSettings.ID = table.Connection.ExecuteScalar("SELECT @@IDENTITY"); + } + + transactionScope.Complete(); + } + + return dashSettings; + } + + } + +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/Channels/ChannelData.cs b/src/Libraries/openXDA.Model/Channels/ChannelData.cs new file mode 100644 index 00000000..2ce28f94 --- /dev/null +++ b/src/Libraries/openXDA.Model/Channels/ChannelData.cs @@ -0,0 +1,649 @@ +//****************************************************************************************************** +// ChannelData.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 12/12/2019 - C. Lackner +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.Data; +using Gemstone; +using Gemstone.Data; +using Gemstone.Data.DataExtensions; +using Gemstone.Data.Model; +using Ionic.Zlib; + +namespace openXDA.Model +{ + [TableName("ChannelData")] + public class ChannelData + { + #region [ Members ] + + // Nested Types + private class DigitalSection + { + public DateTime Start { get; set; } + public DateTime End { get; set; } + public int NumPoints { get; set; } + public double Value { get; set; } + public static int Size => 2 * sizeof(long) + sizeof(ushort) + sizeof(int); + + public int CopyBytes(byte[] byteArray, int offset, double compressionScale, double compressionOffset) + { + ushort compressedValue = (ushort)Math.Round((Value - compressionOffset) * compressionScale); + const ushort NaNValue = ushort.MaxValue; + + if (compressedValue == NaNValue) + compressedValue--; + + if (double.IsNaN(Value)) + compressedValue = NaNValue; + + int startOffset = offset; + offset += LittleEndian.CopyBytes(Start.Ticks, byteArray, offset); + offset += LittleEndian.CopyBytes(End.Ticks, byteArray, offset); + offset += LittleEndian.CopyBytes(compressedValue, byteArray, offset); + offset += LittleEndian.CopyBytes(NumPoints, byteArray, offset); + return offset - startOffset; + } + + public static DigitalSection FromBytes(byte[] bytes, int offset, double decompressionOffset, double decompressionScale) + { + DigitalSection section = new DigitalSection(); + + section.Start = new DateTime(LittleEndian.ToInt64(bytes, offset)); + offset += sizeof(long); + + section.End = new DateTime(LittleEndian.ToInt64(bytes, offset)); + offset += sizeof(long); + + ushort compressedValue = LittleEndian.ToUInt16(bytes, offset); + section.Value = decompressionScale * compressedValue + decompressionOffset; + offset += sizeof(ushort); + + section.NumPoints = LittleEndian.ToInt32(bytes, offset); + + return section; + } + } + #endregion + + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + public int SeriesID { get; set; } + + public int EventID { get; set; } + + public byte[] TimeDomainData { get; set; } + + public int MarkedForDeletion { get; set; } + + #endregion + + #region [ Methods ] + + /// + /// Adjusts the TimeDomain Data by Moving it a certain ammount of Time + /// + /// The number of Ticks the Data is moved. For moving it backwards in Time this needs to be < 0 + public void AdjustData(Ticks ticks) + { + // Initially we assume Data is already migrated... + if (TimeDomainData == null) + return; + + Tuple> decompressed = Decompress(TimeDomainData)[0]; + List data = decompressed.Item2; + + foreach (DataPoint dataPoint in data) + dataPoint.Time = dataPoint.Time.AddTicks(ticks); + + TimeDomainData = ToData(data, decompressed.Item1); + } + + #endregion + + #region [ Static ] + + public static List DataFromEvent(int eventID, Func connectionFactory) + { + using (AdoDataConnection connection = connectionFactory()) + { + TableOperations eventTable = new TableOperations(connection); + Event evt = eventTable.QueryRecordWhere("ID = {0}", eventID); + + TableOperations assetTable = new TableOperations(connection); + Asset asset = assetTable.QueryRecordWhere("ID = {0}", evt.AssetID); + asset.ConnectionFactory = connectionFactory; + + List channels = asset.DirectChannels + .Concat(asset.ConnectedChannels) + .Where(channel => channel.MeterID == evt.MeterID) + .ToList(); + + if (!channels.Any()) + return new List(); + + IEnumerable assetIDs = channels + .Select(channel => channel.AssetID) + .Distinct(); + + foreach (int assetID in assetIDs) + MigrateLegacyBlob(connection, evt.FileGroupID, assetID, evt.StartTime); + + // Optimization to avoid individually querying channels that don't have any data + HashSet channelsWithData = QueryChannelsWithData(connection, evt); + channels.RemoveAll(channel => !channelsWithData.Contains(channel.ID)); + + List eventData = new List(); + + foreach (Channel channel in channels) + { + const string DataQueryFormat = + "SELECT ChannelData.TimeDomainData " + + "FROM " + + " ChannelData JOIN " + + " Series ON ChannelData.SeriesID = Series.ID JOIN " + + " Event ON ChannelData.EventID = Event.ID " + + "WHERE " + + " Event.FileGroupID = {0} AND " + + " Series.ChannelID = {1} AND " + + " Event.StartTime = {2}"; + + object startTime2 = ToDateTime2(connection, evt.StartTime); + byte[] timeDomainData = connection.ExecuteScalar(DataQueryFormat, evt.FileGroupID, channel.ID, startTime2); + + if (timeDomainData is null) + continue; + + eventData.Add(timeDomainData); + } + + return eventData; + } + } + + public static byte[] DataFromEvent(int eventID, int channelID, Func connectionFactory) + { + using (AdoDataConnection connection = connectionFactory()) + { + TableOperations eventTable = new TableOperations(connection); + Event evt = eventTable.QueryRecordWhere("ID = {0}", eventID); + MigrateLegacyBlob(connection, evt); + + const string QueryFormat = + "SELECT ChannelData.TimeDomainData " + + "FROM " + + " ChannelData JOIN " + + " Series ON ChannelData.SeriesID = Series.ID " + + "WHERE " + + " ChannelData.EventID = {0} AND " + + " Series.ChannelID = {1}"; + + return connection.ExecuteScalar(QueryFormat, eventID, channelID); + } + } + + private static void MigrateLegacyBlob(AdoDataConnection connection, int fileGroupID, int assetID, DateTime startTime) + { + const string AssetQueryFilter = "FileGroupID = {0} AND AssetID = {1} AND StartTime = {2}"; + object startTime2 = ToDateTime2(connection, startTime); + + TableOperations eventTable = new TableOperations(connection); + Event evt = eventTable.QueryRecordWhere(AssetQueryFilter, fileGroupID, assetID, startTime2); + MigrateLegacyBlob(connection, evt); + } + + private static void MigrateLegacyBlob(AdoDataConnection connection, Event evt) + { + if (evt is null || evt.EventDataID is null) + return; + + int eventDataID = evt.EventDataID.GetValueOrDefault(); + byte[] timeDomainData = connection.ExecuteScalar("SELECT TimeDomainData FROM EventData WHERE ID = {0}", eventDataID); + List>> decompressedData = Decompress(timeDomainData); + + TableOperations channelDataTable = new TableOperations(connection); + + foreach (Tuple> tuple in decompressedData) + { + int seriesID = tuple.Item1; + List data = tuple.Item2; + + ChannelData channelData = new ChannelData(); + channelData.SeriesID = seriesID; + channelData.EventID = evt.ID; + channelData.TimeDomainData = ToData(data, seriesID); + channelDataTable.AddNewRecord(channelData); + } + + connection.ExecuteNonQuery("UPDATE Event SET EventDataID = NULL WHERE ID = {0}", evt.ID); + connection.ExecuteNonQuery("DELETE FROM EventData WHERE ID = {0}", eventDataID); + } + + /// + /// Turns a list of DataPoints into a blob to be saved in the database. + /// + /// The data as a + /// The SeriesID to be encoded into the blob + /// The byte array to be saved as a blob in the database. + public static byte[] ToData(List data, int seriesID) + { + // We can use Digital compression if the data changes no more than 10% of the time. + bool useDigitalCompression = data + .Skip(1) + .Zip(data, (p2, p1) => new { p1, p2 }) + .Where(obj => obj.p1.Value != obj.p2.Value) + .Select((_, index) => index + 1) + .All(nChanges => nChanges <= 0.1 * data.Count); + + if (useDigitalCompression) + return ToDigitalData(data, seriesID); + + var timeSeries = data.Select(dataPoint => new { Time = dataPoint.Time.Ticks, Compressed = false }).ToList(); + + for (int i = 1; i < timeSeries.Count; i++) + { + long previousTimestamp = data[i - 1].Time.Ticks; + long timestamp = timeSeries[i].Time; + long diff = timestamp - previousTimestamp; + + if (diff >= 0 && diff <= ushort.MaxValue) + timeSeries[i] = new { Time = diff, Compressed = true }; + } + + int timeSeriesByteLength = timeSeries.Sum(obj => obj.Compressed ? sizeof(ushort) : sizeof(int) + sizeof(long)); + int dataSeriesByteLength = sizeof(int) + (2 * sizeof(double)) + (data.Count * sizeof(ushort)); + int totalByteLength = sizeof(int) + timeSeriesByteLength + dataSeriesByteLength; + + byte[] result = new byte[totalByteLength]; + int offset = 0; + + offset += LittleEndian.CopyBytes(data.Count, result, offset); + + List uncompressedIndexes = timeSeries + .Select((obj, Index) => new { obj.Compressed, Index }) + .Where(obj => !obj.Compressed) + .Select(obj => obj.Index) + .ToList(); + + for (int i = 0; i < uncompressedIndexes.Count; i++) + { + int index = uncompressedIndexes[i]; + int nextIndex = (i + 1 < uncompressedIndexes.Count) ? uncompressedIndexes[i + 1] : timeSeries.Count; + + offset += LittleEndian.CopyBytes(nextIndex - index, result, offset); + offset += LittleEndian.CopyBytes(timeSeries[index].Time, result, offset); + + for (int j = index + 1; j < nextIndex; j++) + offset += LittleEndian.CopyBytes((ushort)timeSeries[j].Time, result, offset); + } + + const ushort NaNValue = ushort.MaxValue; + const ushort MaxCompressedValue = ushort.MaxValue - 1; + double range = data.Select(item => item.Value).Max() - data.Select(item => item.Value).Min(); + double decompressionOffset = data.Select(item => item.Value).Min(); + double decompressionScale = range / MaxCompressedValue; + double compressionScale = (decompressionScale != 0.0D) ? 1.0D / decompressionScale : 0.0D; + + offset += LittleEndian.CopyBytes(seriesID, result, offset); + offset += LittleEndian.CopyBytes(decompressionOffset, result, offset); + offset += LittleEndian.CopyBytes(decompressionScale, result, offset); + + foreach (DataPoint dataPoint in data) + { + ushort compressedValue = (ushort)Math.Round((dataPoint.Value - decompressionOffset) * compressionScale); + + if (compressedValue == NaNValue) + compressedValue--; + + if (double.IsNaN(dataPoint.Value)) + compressedValue = NaNValue; + + offset += LittleEndian.CopyBytes(compressedValue, result, offset); + } + + byte[] returnArray = GZipStream.CompressBuffer(result); + returnArray[0] = 0x44; + returnArray[1] = 0x33; + + return returnArray; + } + + private static byte[] ToDigitalData(List data, int seriesID) + { + List digitalData = new List(); + DigitalSection currentSection = null; + foreach (DataPoint dataPoint in data) + { + if (currentSection is null) + { + currentSection = new DigitalSection() + { + Start = dataPoint.Time, + End = dataPoint.Time, + Value = dataPoint.Value, + NumPoints = 1 + }; + } + else if (currentSection.Value != dataPoint.Value) + { + digitalData.Add(currentSection); + currentSection = new DigitalSection() + { + Start = dataPoint.Time, + End = dataPoint.Time, + Value = dataPoint.Value, + NumPoints = 1 + }; + } + else + { + currentSection.NumPoints++; + currentSection.End = dataPoint.Time; + } + } + + if (!(currentSection is null)) + digitalData.Add(currentSection); + + int totalByteLength = sizeof(int) + 2 * sizeof(double) + digitalData.Count * DigitalSection.Size; + byte[] result = new byte[totalByteLength]; + int offset = 0; + + const ushort MaxCompressedValue = ushort.MaxValue - 1; + double range = data.Select(item => item.Value).Max() - data.Select(item => item.Value).Min(); + double decompressionOffset = data.Select(item => item.Value).Min(); + double decompressionScale = range / MaxCompressedValue; + double compressionScale = (decompressionScale != 0.0D) ? 1.0D / decompressionScale : 0.0D; + + offset += LittleEndian.CopyBytes(seriesID, result, offset); + offset += LittleEndian.CopyBytes(decompressionOffset, result, offset); + offset += LittleEndian.CopyBytes(decompressionScale, result, offset); + + foreach (DigitalSection digitalSection in digitalData) + offset += digitalSection.CopyBytes(result, offset, compressionScale, decompressionOffset); + + byte[] returnArray = GZipStream.CompressBuffer(result); + returnArray[0] = DigitalHeader[0]; + returnArray[1] = DigitalHeader[1]; + return returnArray; + } + + /// + /// Decompresses a byte array into a List of DataPoints + /// + /// The byte array filled with compressed data + /// List of data series consisting of series ID and data points. + public static List>> Decompress(byte[] data) + { + List>> result = new List>>(); + + if (data == null) + return result; + // If the blob contains the GZip header, + // use the legacy deserialization algorithm + if (data[0] == LegacyHeader[0] && data[1] == LegacyHeader[1]) + { + return Decompress_Legacy(data); + } + // If this blob uses digital decompression use that algorithm + if (data[0] == DigitalHeader[0] && data[1] == DigitalHeader[1]) + { + return Decompress_Digital(data); + } + + // Restore the GZip header before uncompressing + data[0] = LegacyHeader[0]; + data[1] = LegacyHeader[1]; + + byte[] uncompressedData; + int offset; + + uncompressedData = GZipStream.UncompressBuffer(data); + offset = 0; + + int m_samples = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + List times = new List(); + + while (times.Count < m_samples) + { + int timeValues = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + long currentValue = LittleEndian.ToInt64(uncompressedData, offset); + offset += sizeof(long); + times.Add(new DateTime(currentValue)); + + for (int i = 1; i < timeValues; i++) + { + currentValue += LittleEndian.ToUInt16(uncompressedData, offset); + offset += sizeof(ushort); + times.Add(new DateTime(currentValue)); + } + } + + while (offset < uncompressedData.Length) + { + List dataSeries = new List(); + int seriesID = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + + const ushort NaNValue = ushort.MaxValue; + double decompressionOffset = LittleEndian.ToDouble(uncompressedData, offset); + double decompressionScale = LittleEndian.ToDouble(uncompressedData, offset + sizeof(double)); + offset += 2 * sizeof(double); + + for (int i = 0; i < m_samples; i++) + { + ushort compressedValue = LittleEndian.ToUInt16(uncompressedData, offset); + offset += sizeof(ushort); + + double decompressedValue = decompressionScale * compressedValue + decompressionOffset; + + if (compressedValue == NaNValue) + decompressedValue = double.NaN; + + dataSeries.Add(new DataPoint() + { + Time = times[i], + Value = decompressedValue + }); + } + + result.Add(new Tuple>(seriesID, dataSeries)); + } + + return result; + } + + private static List>> Decompress_Legacy(byte[] data) + { + List>> result = new List>>(); + byte[] uncompressedData; + int offset; + DateTime[] times; + int seriesID; + + uncompressedData = GZipStream.UncompressBuffer(data); + offset = 0; + + int m_samples = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + times = new DateTime[m_samples]; + + for (int i = 0; i < m_samples; i++) + { + times[i] = new DateTime(LittleEndian.ToInt64(uncompressedData, offset)); + offset += sizeof(long); + } + + while (offset < uncompressedData.Length) + { + seriesID = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + List points = new List(); + + for (int i = 0; i < m_samples; i++) + { + points.Add(new DataPoint() + { + Time = times[i], + Value = LittleEndian.ToDouble(uncompressedData, offset) + }); + + offset += sizeof(double); + } + + result.Add(new Tuple>(seriesID, points)); + } + return result; + } + + /// + /// Decompresses a Digital stored as compresed series of changes + /// + /// The compressed + /// a Dictionary mapping a SeriesID to a decopmressed + private static List>> Decompress_Digital(byte[] data) + { + List>> result = new List>>(); + byte[] uncompressedData; + int offset; + int seriesID; + List points = new List(); + + // Restore the GZip header before uncompressing + data[0] = LegacyHeader[0]; + data[1] = LegacyHeader[1]; + + uncompressedData = GZipStream.UncompressBuffer(data); + offset = 0; + + seriesID = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + double decompressionOffset = LittleEndian.ToDouble(uncompressedData, offset); + double decompressionScale = LittleEndian.ToDouble(uncompressedData, offset + sizeof(double)); + offset += 2 * sizeof(double); + + while(offset < uncompressedData.Length) + { + DigitalSection section = DigitalSection.FromBytes(uncompressedData, offset, decompressionOffset, decompressionScale); + offset += DigitalSection.Size; + + points.Add(new DataPoint() + { + Time = section.Start, + Value = section.Value + }); + + if (section.NumPoints == 1) + continue; + + // Use a fixed-point offset with 6 bits of additional + // precision to help avoid accumulation of rounding errors + long diff = (section.End - section.Start).Ticks << 6; + long step = diff / (section.NumPoints - 1); + long lastOffset = step; + + for (int i = 1; i < section.NumPoints - 1; i++) + { + points.Add(new DataPoint() + { + Time = section.Start.AddTicks(lastOffset >> 6), + Value = section.Value + }); + + lastOffset += step; + } + + points.Add(new DataPoint() + { + Time = section.End, + Value = section.Value + }); + } + + result.Add(new Tuple>(seriesID, points)); + + return result; + } + + private static HashSet QueryChannelsWithData(AdoDataConnection connection, Event evt) + { + const string FilterQueryFormat = + "SELECT Series.ChannelID " + + "FROM " + + " ChannelData JOIN " + + " Series ON ChannelData.SeriesID = Series.ID JOIN " + + " Event ON ChannelData.EventID = Event.ID " + + "WHERE " + + " Event.FileGroupID = {0} AND " + + " Event.StartTime = {1}"; + + object startTime2 = ToDateTime2(connection, evt.StartTime); + + using (DataTable table = connection.RetrieveData(FilterQueryFormat, evt.FileGroupID, startTime2)) + { + IEnumerable channelsWithData = table + .AsEnumerable() + .Select(row => row.ConvertField("ChannelID")); + + return new HashSet(channelsWithData); + } + } + + private static object ToDateTime2(AdoDataConnection connection, DateTime dateTime) + { + using (IDbCommand command = connection.Connection.CreateCommand()) + { + IDbDataParameter parameter = command.CreateParameter(); + parameter.DbType = DbType.DateTime2; + parameter.Value = dateTime; + return parameter; + } + } + + /// + /// The header of a datablob compressed as analog Data + /// + public static readonly byte[] AnalogHeader = { 0x11, 0x11 }; + + /// + /// The header of a datablob compressed as Digital State Changes + /// + public static readonly byte[] DigitalHeader = { 0x22, 0x22 }; + + /// + /// The header of a datablob compressed as Legacy Data + /// + public static readonly byte[] LegacyHeader = { 0x1F, 0x8B }; + + #endregion + } +} diff --git a/src/Libraries/openXDA.Model/Channels/DataPoint.cs b/src/Libraries/openXDA.Model/Channels/DataPoint.cs new file mode 100644 index 00000000..88c39332 --- /dev/null +++ b/src/Libraries/openXDA.Model/Channels/DataPoint.cs @@ -0,0 +1,110 @@ +//****************************************************************************************************** +// DataPoint.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: +// ---------------------------------------------------------------------------------------------------- +// 05/15/2025 - C. Lackner +// Generated original version of source code. +// +//****************************************************************************************************** + +namespace openXDA.Model +{ + /// + /// Represents a single data point in a time series. + /// + public class DataPoint + { + #region [ Properties ] + + public DateTime Time { get; set; } + public double Value { get; set; } + + #endregion + + #region [ Methods ] + + public DataPoint Shift(TimeSpan timeShift) + { + return new DataPoint() + { + Time = Time.Add(timeShift), + Value = Value + }; + } + + public DataPoint Negate() + { + return new DataPoint() + { + Time = Time, + Value = -Value + }; + } + + public DataPoint Add(DataPoint point) + { + if (Time != point.Time) + throw new InvalidOperationException("Cannot add datapoints with mismatched times"); + + return new DataPoint() + { + Time = Time, + Value = Value + point.Value + }; + } + + public DataPoint Subtract(DataPoint point) + { + return Add(point.Negate()); + } + + public DataPoint Add(double value) + { + return new DataPoint() + { + Time = Time, + Value = Value + value + }; + } + + public DataPoint Subtract(double value) + { + return Add(-value); + } + + public DataPoint Multiply(double value) + { + return new DataPoint() + { + Time = Time, + Value = Value * value + }; + } + + public bool LargerThan(double comparison) + { + return Value > comparison; + } + + public bool LargerThan(DataPoint point) + { + return LargerThan(point.Value); + } + + #endregion + } +} diff --git a/src/Libraries/openXDA.Model/Channels/MeasurementCharacteristic.cs b/src/Libraries/openXDA.Model/Channels/MeasurementCharacteristic.cs new file mode 100644 index 00000000..a3e49898 --- /dev/null +++ b/src/Libraries/openXDA.Model/Channels/MeasurementCharacteristic.cs @@ -0,0 +1,45 @@ +//****************************************************************************************************** +// MeasurementCharacteristic.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.ComponentModel.DataAnnotations; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [PostRoles("Administrator, Transmission SME")] + [DeleteRoles("Administrator, Transmission SME")] + [PatchRoles("Administrator, Transmission SME")] + public class MeasurementCharacteristic + { + [PrimaryKey(true)] + public int ID { get; set; } + + [StringLength(200)] + [DefaultSortOrder] + public string Name { get; set; } + + public string Description { get; set; } + + public bool Display { get; set; } + } +} diff --git a/src/Libraries/openXDA.Model/Channels/MeasurementType.cs b/src/Libraries/openXDA.Model/Channels/MeasurementType.cs new file mode 100644 index 00000000..20d3ea30 --- /dev/null +++ b/src/Libraries/openXDA.Model/Channels/MeasurementType.cs @@ -0,0 +1,44 @@ +//****************************************************************************************************** +// MeasurementType.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System; +using System.ComponentModel.DataAnnotations; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [PostRoles("Administrator, Transmission SME")] + [DeleteRoles("Administrator, Transmission SME")] + [PatchRoles("Administrator, Transmission SME")] + public class MeasurementType + { + [PrimaryKey(true)] + public int ID { get; set; } + + [StringLength(200)] + [DefaultSortOrder] + public string Name { get; set; } + + public string Description { get; set; } + } +} diff --git a/src/Libraries/openXDA.Model/Channels/Phase.cs b/src/Libraries/openXDA.Model/Channels/Phase.cs new file mode 100644 index 00000000..705ec274 --- /dev/null +++ b/src/Libraries/openXDA.Model/Channels/Phase.cs @@ -0,0 +1,43 @@ +//****************************************************************************************************** +// Phase.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.ComponentModel.DataAnnotations; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [PostRoles("Administrator, Transmission SME")] + [DeleteRoles("Administrator, Transmission SME")] + [PatchRoles("Administrator, Transmission SME")] + public class Phase + { + [PrimaryKey(true)] + public int ID { get; set; } + + [StringLength(200)] + [DefaultSortOrder] + public string Name { get; set; } + + public string Description { get; set; } + } +} diff --git a/src/Libraries/openXDA.Model/Channels/Series.cs b/src/Libraries/openXDA.Model/Channels/Series.cs new file mode 100644 index 00000000..d6c96a6c --- /dev/null +++ b/src/Libraries/openXDA.Model/Channels/Series.cs @@ -0,0 +1,248 @@ +//****************************************************************************************************** +// Series.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 06/20/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.Data; +using Gemstone.Data; +using Gemstone.Data.Model; +using Newtonsoft.Json; + +namespace openXDA.Model +{ + public class SeriesKey : IEquatable + { + #region [ Constructors ] + + public SeriesKey(ChannelKey channelKey, string seriesType) + { + ChannelKey = channelKey; + SeriesType = seriesType; + } + + public SeriesKey(Series series) + : this(new ChannelKey(series.Channel), series.SeriesType.Name) + { + } + + #endregion + + #region [ Properties ] + + public ChannelKey ChannelKey { get; } + public string SeriesType { get; } + + #endregion + + #region [ Methods ] + + public Series Find(AdoDataConnection connection, int meterID) + { + const string QueryFormat = + "SELECT Series.* " + + "FROM " + + " Series JOIN " + + " Channel ON Series.ChannelID = Channel.ID JOIN " + + " MeasurementType ON Channel.MeasurementTypeID = MeasurementType.ID JOIN " + + " MeasurementCharacteristic ON Channel.MeasurementCharacteristicID = MeasurementCharacteristic.ID JOIN " + + " Phase ON Channel.PhaseID = Phase.ID JOIN " + + " SeriesType ON Series.SeriesTypeID = SeriesType.ID " + + "WHERE " + + " Channel.MeterID = {0} AND " + + " Channel.AssetID = {1} AND " + + " Channel.HarmonicGroup = {2} AND " + + " Channel.Name = {3} AND " + + " MeasurementType.Name = {4} AND " + + " MeasurementCharacteristic.Name = {5} AND " + + " Phase.Name = {6} AND " + + " SeriesType.Name = {7}"; + + object[] parameters = + { + meterID, + ChannelKey.LineID, + ChannelKey.HarmonicGroup, + ChannelKey.Name, + ChannelKey.MeasurementType, + ChannelKey.MeasurementCharacteristic, + ChannelKey.Phase, + SeriesType + }; + + using (DataTable table = connection.RetrieveData(QueryFormat, parameters)) + { + if (table.Rows.Count == 0) + return null; + + TableOperations seriesTable = new TableOperations(connection); + return seriesTable.LoadRecord(table.Rows[0]); + } + } + + public override int GetHashCode() + { + StringComparer stringComparer = StringComparer.OrdinalIgnoreCase; + + int hash = 1009; + hash = 9176 * hash + ChannelKey.GetHashCode(); + hash = 9176 * hash + stringComparer.GetHashCode(SeriesType); + return hash; + } + + public override bool Equals(object obj) + { + return Equals(obj as SeriesKey); + } + + public bool Equals(SeriesKey other) + { + if (other is null) + return false; + + StringComparison stringComparison = StringComparison.OrdinalIgnoreCase; + + return + ChannelKey.Equals(other.ChannelKey) && + SeriesType.Equals(other.SeriesType, stringComparison); + } + + #endregion + } + + public class Series + { + #region [ Members ] + + // Fields + private SeriesType m_seriesType; + private Channel m_channel; + + #endregion + + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + public int ChannelID { get; set; } + + public int SeriesTypeID { get; set; } + + public string SourceIndexes { get; set; } + + [JsonIgnore] + [NonRecordField] + public SeriesType SeriesType + { + get + { + if (m_seriesType is null) + m_seriesType = LazyContext.GetSeriesType(SeriesTypeID); + + if (m_seriesType is null) + m_seriesType = QuerySeriesType(); + + return m_seriesType; + } + set => m_seriesType = value; + } + + [JsonIgnore] + [NonRecordField] + public Channel Channel + { + get + { + if (m_channel is null) + m_channel = LazyContext.GetChannel(ChannelID); + + if (m_channel is null) + m_channel = QueryChannel(); + + return m_channel; + } + set => m_channel = value; + } + + [JsonIgnore] + [NonRecordField] + public Func ConnectionFactory + { + get => LazyContext.ConnectionFactory; + set => LazyContext.ConnectionFactory = value; + } + + [JsonIgnore] + [NonRecordField] + internal LazyContext LazyContext { get; set; } = new LazyContext(); + + #endregion + + #region [ Methods ] + + public SeriesType GetSeriesType(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations seriesTypeTable = new TableOperations(connection); + return seriesTypeTable.QueryRecordWhere("ID = {0}", SeriesTypeID); + } + + public Channel GetChannel(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations channelTable = new TableOperations(connection); + return channelTable.QueryRecordWhere("ID = {0}", ChannelID); + } + + private SeriesType QuerySeriesType() + { + SeriesType seriesType; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + seriesType = GetSeriesType(connection); + } + + return LazyContext.GetSeriesType(seriesType); + } + + private Channel QueryChannel() + { + Channel channel; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + channel = GetChannel(connection); + } + + if ((object)channel != null) + channel.LazyContext = LazyContext; + + return LazyContext.GetChannel(channel); + } + + #endregion + } +} diff --git a/src/Libraries/openXDA.Model/Channels/SeriesType.cs b/src/Libraries/openXDA.Model/Channels/SeriesType.cs new file mode 100644 index 00000000..c7621b5d --- /dev/null +++ b/src/Libraries/openXDA.Model/Channels/SeriesType.cs @@ -0,0 +1,40 @@ +//****************************************************************************************************** +// SeriesType.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.ComponentModel.DataAnnotations; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [TableName("SeriesType")] + public class SeriesType + { + [PrimaryKey(true)] + public int ID { get; set; } + + [StringLength(200)] + public string Name { get; set; } + + public string Description { get; set; } + } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/Events/BreakerRestrike.cs b/src/Libraries/openXDA.Model/Events/BreakerRestrike.cs new file mode 100644 index 00000000..e76661d5 --- /dev/null +++ b/src/Libraries/openXDA.Model/Events/BreakerRestrike.cs @@ -0,0 +1,65 @@ +//****************************************************************************************************** +// BreakerRestrike.cs - Gbtc +// +// Copyright © 2019, 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/30/2019 - Stephen C. Wills +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.Data; +using Gemstone.Data; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + public class BreakerRestrike + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int EventID { get; set; } + + public int PhaseID { get; set; } + + public int InitialExtinguishSample { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime InitialExtinguishTime { get; set; } + public double InitialExtinguishVoltage { get; set; } + public int RestrikeSample { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime RestrikeTime { get; set; } + public double RestrikeVoltage { get; set; } + public double RestrikeCurrentPeak { get; set; } + public double RestrikeVoltageDip { get; set; } + public int TransientPeakSample { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime TransientPeakTime { get; set; } + public double TransientPeakVoltage { get; set; } + public double PerUnitTransientPeakVoltage { get; set; } + public int FinalExtinguishSample { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime FinalExtinguishTime { get; set; } + public double FinalExtinguishVoltage { get; set; } + public double I2t { get; set; } + + } +} diff --git a/src/Libraries/openXDA.Model/Events/Disturbances/Disturbance.cs b/src/Libraries/openXDA.Model/Events/Disturbances/Disturbance.cs new file mode 100644 index 00000000..c83ce0e6 --- /dev/null +++ b/src/Libraries/openXDA.Model/Events/Disturbances/Disturbance.cs @@ -0,0 +1,67 @@ +//****************************************************************************************************** +// Disturbance.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + public class Disturbance + { + [PrimaryKey(true)] + public int ID { get; set; } + public int EventID { get; set; } + public int EventTypeID { get; set; } + public int PhaseID { get; set; } + public double Magnitude { get; set; } + public double PerUnitMagnitude { get; set; } + + [FieldDataType(System.Data.DbType.DateTime2, Gemstone.Data.DatabaseType.SQLServer)] + public DateTime StartTime { get; set; } + + [FieldDataType(System.Data.DbType.DateTime2, Gemstone.Data.DatabaseType.SQLServer)] + public DateTime EndTime { get; set; } + + public double DurationSeconds { get; set; } + public double DurationCycles { get; set; } + public int StartIndex { get; set; } + public int EndIndex { get; set; } + public string UpdatedBy { get; set; } + } + + [TableName("DisturbanceView")] + public class DisturbanceView: Disturbance + { + public int MeterID { get; set; } + public int LineID { get; set; } + public int? SeverityCode { get; set; } + public string MeterName { get; set; } + public string PhaseName { get; set; } + } + + [TableName("DisturbanceView")] + public class DisturbancesForDay : DisturbanceView { } + + [TableName("DisturbanceView")] + public class DisturbancesForMeter : DisturbanceView { } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/Events/Event.cs b/src/Libraries/openXDA.Model/Events/Event.cs new file mode 100644 index 00000000..992ad47e --- /dev/null +++ b/src/Libraries/openXDA.Model/Events/Event.cs @@ -0,0 +1,91 @@ +//****************************************************************************************************** +// Event.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.Data; +using Gemstone.Data; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [TableName("Event")] + public class Event + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int FileGroupID { get; set; } + + public int MeterID { get; set; } + + public int AssetID { get; set; } + + public int EventTypeID { get; set; } + + public int? EventDataID { get; set; } + + public string Name { get; set; } + + public string Alias { get; set; } + + public string ShortName { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime StartTime { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime EndTime { get; set; } + + public int Samples { get; set; } + + public int TimeZoneOffset { get; set; } + + public int SamplesPerSecond { get; set; } + + public int SamplesPerCycle { get; set; } + + public string Description { get; set; } + + public int FileVersion { get; set; } + + public string UpdatedBy { get; set; } + } + + [TableName("EventView")] + public class EventView : Event + { + [PrimaryKey(true)] + public new int ID + { + get => base.ID; + set => base.ID = value; + } + + public string AssetName { get; set; } + + public string MeterName { get; set; } + + public string StationName { get; set; } + + public string EventTypeName { get; set; } + } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/Events/EventStat.cs b/src/Libraries/openXDA.Model/Events/EventStat.cs new file mode 100644 index 00000000..6e004a3e --- /dev/null +++ b/src/Libraries/openXDA.Model/Events/EventStat.cs @@ -0,0 +1,57 @@ +//****************************************************************************************************** +// EventStat.cs - Gbtc +// +// Copyright © 2018, 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: +// ---------------------------------------------------------------------------------------------------- +// 11/07/2018 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + public class EventStat + { + [PrimaryKey(true)] + public int ID { get; set; } + public int EventID { get; set; } + public double? VPeak { get; set; } + public double? VAMax { get; set; } + public double? VBMax { get; set; } + public double? VCMax { get; set; } + public double? VABMax { get; set; } + public double? VBCMax { get; set; } + public double? VCAMax { get; set; } + public double? VAMin { get; set; } + public double? VBMin { get; set; } + public double? VCMin { get; set; } + public double? VABMin { get; set; } + public double? VBCMin { get; set; } + public double? VCAMin { get; set; } + public double? IPeak { get; set; } + public double? IAMax { get; set; } + public double? IBMax { get; set; } + public double? ICMax { get; set; } + public double? IA2t { get; set; } + public double? IB2t { get; set; } + public double? IC2t { get; set; } + public double? InitialMW { get; set; } + public double? FinalMW { get; set; } + public int? PQViewID { get; set; } + } +} diff --git a/src/Libraries/openXDA.Model/Events/Faults/Fault.cs b/src/Libraries/openXDA.Model/Events/Faults/Fault.cs new file mode 100644 index 00000000..dbf8b955 --- /dev/null +++ b/src/Libraries/openXDA.Model/Events/Faults/Fault.cs @@ -0,0 +1,137 @@ +//****************************************************************************************************** +// Fault.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [TableName("FaultSummary")] + public class Fault + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int EventID { get; set; } + + public string Algorithm { get; set; } + + public int FaultNumber { get; set; } + + public int CalculationCycle { get; set; } + + public double Distance { get; set; } + + public int PathNumber { get; set; } + + public int LineSegmentID { get; set; } + + public double LineSegmentDistance { get; set; } + + public double CurrentMagnitude { get; set; } + + public double CurrentLag { get; set; } + + public double PrefaultCurrent { get; set; } + + public double PostfaultCurrent { get; set; } + + public double ReactanceRatio { get; set; } + + [FieldDataType(System.Data.DbType.DateTime2, Gemstone.Data.DatabaseType.SQLServer)] + public DateTime Inception { get; set; } + + public double DurationSeconds { get; set; } + + public double DurationCycles { get; set; } + + public string FaultType { get; set; } + + public bool IsSelectedAlgorithm { get; set; } + + public bool IsValid { get; set; } + + public bool IsSuppressed { get; set; } + } + + public class FaultSummary : Fault { } + + [TableName("FaultView")] + public class FaultView : Fault + { + public string MeterName { get; set; } + + public string ShortName { get; set; } + + public string LocationName { get; set; } + + public int MeterID { get; set; } + + public int LineID { get; set; } + + public string LineName { get; set; } + + public int Voltage { get; set; } + + public DateTime InceptionTime { get; set; } + + public double CurrentDistance { get; set; } + + public int RK { get; set; } + } + + [TableName("FaultView")] + public class FaultForMeter: FaultView { } + + public class FaultsDetailsByDate + { + public int thefaultid { get; set; } + + public string thesite { get; set; } + + public string locationname { get; set; } + + public int themeterid { get; set; } + + public int thelineid { get; set; } + + public int theeventid { get; set; } + + public string thelinename { get; set; } + + public int voltage { get; set; } + + public string theinceptiontime { get; set; } + + public string thefaulttype { get; set; } + + public double thecurrentdistance { get; set; } + + public int notecount { get; set; } + + public int rk { get; set; } + + [NonRecordField] + public string theeventtype { get; set; } + } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/Events/Faults/FaultCurve.cs b/src/Libraries/openXDA.Model/Events/Faults/FaultCurve.cs new file mode 100644 index 00000000..02268fa2 --- /dev/null +++ b/src/Libraries/openXDA.Model/Events/Faults/FaultCurve.cs @@ -0,0 +1,250 @@ +//****************************************************************************************************** +// FaultCurve.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 09/06/2017 - Stephen C. Wills +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.ComponentModel.DataAnnotations; +using Gemstone; +using Gemstone.Data.Model; +using Ionic.Zlib; + +namespace openXDA.Model +{ + public class FaultCurve + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int EventID { get; set; } + + public int PathNumber { get; set; } + + [StringLength(200)] + public string Algorithm { get; set; } + + public byte[] Data { get; set; } + + public byte[] AngleData { get; set; } + + #region [Private Class] + private class DataPoint + { + public DateTime Time; + public double Value; + } + + #endregion + + #region [Methods] + + public void Adjust(Ticks ticks) + { + // If the blob contains the GZip header, + // move from Legacy Compression to normal Compression + if (this.Data[0] == 0x1F && this.Data[1] == 0x8B) + { + this.Data = MigrateCompression(this.Data); + } + + // If the blob contains the GZip header, + // move from Legacy Compression to normal Compression + if (this.AngleData[0] == 0x1F && this.AngleData[1] == 0x8B) + { + this.AngleData = MigrateCompression(this.AngleData); + } + + this.Data = ChangeTS(this.Data, ticks); + this.AngleData = ChangeTS(this.AngleData, ticks); + + + } + + private static byte[] ChangeTS(byte[] data, Ticks ticks) + { + data[0] = 0x1F; + data[1] = 0x8B; + + byte[] uncompressedData = GZipStream.UncompressBuffer(data); + byte[] resultData = new byte[uncompressedData.Length]; + + uncompressedData.CopyTo(resultData,0); + + int offset = 0; + + int m_samples = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + int timeValues = LittleEndian.ToInt32(uncompressedData, offset); + + int startTS = offset; + + offset += sizeof(int); + + long currentValue = LittleEndian.ToInt64(uncompressedData, offset); + + DateTime startTime = new DateTime(currentValue); + startTime = startTime.AddTicks(ticks); + + LittleEndian.CopyBytes(startTime.Ticks, resultData, startTS); + + resultData = GZipStream.CompressBuffer(resultData); + resultData[0] = 0x44; + resultData[1] = 0x33; + return resultData; + } + + private static byte[] MigrateCompression(byte[] data) + { + byte[] uncompressedData; + int offset; + DateTime[] times; + List series; + int seriesID = 0; + + uncompressedData = GZipStream.UncompressBuffer(data); + offset = 0; + + int m_samples = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + times = new DateTime[m_samples]; + + for (int i = 0; i < m_samples; i++) + { + times[i] = new DateTime(LittleEndian.ToInt64(uncompressedData, offset)); + offset += sizeof(long); + } + + series = new List(); + + while (offset < uncompressedData.Length) + { + + seriesID = LittleEndian.ToInt32(uncompressedData, offset); + offset += sizeof(int); + + + for (int i = 0; i < m_samples; i++) + { + series.Add(new DataPoint() + { + Time = times[i], + Value = LittleEndian.ToDouble(uncompressedData, offset) + }); + + offset += sizeof(double); + } + } + + var timeSeries = series.Select(dataPoint => new { Time = dataPoint.Time.Ticks, Compressed = false }).ToList(); + + for (int i = 1; i < timeSeries.Count; i++) + { + long previousTimestamp = series[i - 1].Time.Ticks; + long timestamp = timeSeries[i].Time; + long diff = timestamp - previousTimestamp; + + if (diff >= 0 && diff <= ushort.MaxValue) + timeSeries[i] = new { Time = diff, Compressed = true }; + + + } + + int timeSeriesByteLength = timeSeries.Sum(obj => obj.Compressed ? sizeof(ushort) : sizeof(int) + sizeof(long)); + int dataSeriesByteLength = sizeof(int) + (2 * sizeof(double)) + (m_samples * sizeof(ushort)); + int totalByteLength = sizeof(int) + timeSeriesByteLength + dataSeriesByteLength; + + + byte[] result = new byte[totalByteLength]; + offset = 0; + + offset += LittleEndian.CopyBytes(m_samples, result, offset); + + List uncompressedIndexes = timeSeries + .Select((obj, Index) => new { obj.Compressed, Index }) + .Where(obj => !obj.Compressed) + .Select(obj => obj.Index) + .ToList(); + + for (int i = 0; i < uncompressedIndexes.Count; i++) + { + int index = uncompressedIndexes[i]; + int nextIndex = (i + 1 < uncompressedIndexes.Count) ? uncompressedIndexes[i + 1] : timeSeries.Count; + + offset += LittleEndian.CopyBytes(nextIndex - index, result, offset); + offset += LittleEndian.CopyBytes(timeSeries[index].Time, result, offset); + + for (int j = index + 1; j < nextIndex; j++) + offset += LittleEndian.CopyBytes((ushort)timeSeries[j].Time, result, offset); + } + + const ushort NaNValue = ushort.MaxValue; + const ushort MaxCompressedValue = ushort.MaxValue - 1; + double range = series.Select(item => item.Value).Max() - series.Select(item => item.Value).Min(); + double decompressionOffset = series.Select(item => item.Value).Min(); + double decompressionScale = range / MaxCompressedValue; + double compressionScale = (decompressionScale != 0.0D) ? 1.0D / decompressionScale : 0.0D; + + offset += LittleEndian.CopyBytes(seriesID, result, offset); + offset += LittleEndian.CopyBytes(decompressionOffset, result, offset); + offset += LittleEndian.CopyBytes(decompressionScale, result, offset); + + foreach (DataPoint dataPoint in series) + { + ushort compressedValue = (ushort)Math.Round((dataPoint.Value - decompressionOffset) * compressionScale); + + if (compressedValue == NaNValue) + compressedValue--; + + if (double.IsNaN(dataPoint.Value)) + compressedValue = NaNValue; + + offset += LittleEndian.CopyBytes(compressedValue, result, offset); + } + + byte[] returnArray = GZipStream.CompressBuffer(result); + returnArray[0] = 0x44; + returnArray[1] = 0x33; + + return returnArray; + + } + #endregion + } + + public class FaultCurveStatistic + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int FaultCurveID { get; set; } + + public int FaultNumber { get; set; } + + public double Maximum { get; set; } + + public double Minimum { get; set; } + + public double Average { get; set; } + + public double StandardDeviation { get; set; } + } +} diff --git a/src/Libraries/openXDA.Model/Events/RelayPerformance.cs b/src/Libraries/openXDA.Model/Events/RelayPerformance.cs new file mode 100644 index 00000000..4950235e --- /dev/null +++ b/src/Libraries/openXDA.Model/Events/RelayPerformance.cs @@ -0,0 +1,63 @@ +//****************************************************************************************************** +// RelayPerformance.cs - Gbtc +// +// Copyright © 2019, 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: +// ---------------------------------------------------------------------------------------------------- +// 07/10/2019 - Christoph Lackner +// Generated original version of source code. +// 08/20/2021 - Christoph Lackner +// Added additional Trip Coil Curve points. +// +//****************************************************************************************************** + +using System.Data; +using Gemstone.Data; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + public class RelayPerformance + { + [PrimaryKey(true)] + public int ID { get; set; } + public int EventID { get; set; } + public int ChannelID { get; set; } + public double? Imax1 { get; set; } + public int? Tmax1 { get; set; } + public double? Imax2 { get; set; } + public int? TplungerLatch { get; set; } + public double IplungerLatch { get; set; } + public double? Idrop { get; set; } + public int? TiDrop { get; set; } + public int? Tend { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime? TripInitiate { get; set; } + public int? TripTime { get; set; } + public int? PickupTime { get; set; } + public double? TripTimeCurrent { get; set;} + public double? PickupTimeCurrent { get; set; } + public double? TripCoilCondition { get; set; } + public int TripCoilConditionTime { get; set; } + public int? ExtinctionTimeA { get; set; } + public int? ExtinctionTimeB { get; set; } + public int? ExtinctionTimeC { get; set; } + public double? I2CA { get; set; } + public double? I2CB { get; set; } + public double? I2CC { get; set; } + + } +} diff --git a/src/Libraries/openXDA.Model/Files/DataFile.cs b/src/Libraries/openXDA.Model/Files/DataFile.cs new file mode 100644 index 00000000..10b9d4b5 --- /dev/null +++ b/src/Libraries/openXDA.Model/Files/DataFile.cs @@ -0,0 +1,93 @@ +//****************************************************************************************************** +// DataFile.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.Text; +using Gemstone.Data.Model; +using Gemstone.IO.Checksums; +using Newtonsoft.Json; + +namespace openXDA.Model +{ + [Serializable] + public class DataFile + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int FileGroupID { get; set; } + + public string FilePath { get; set; } + + public int FilePathHash { get; set; } + + public long FileSize { get; set; } + + public DateTime CreationTime { get; set; } + + public DateTime LastWriteTime { get; set; } + + public DateTime LastAccessTime { get; set; } + + [NonRecordField] + [JsonIgnore] + public FileBlob FileBlob { get; set; } + + public static int GetHash(string filePath) + { + Encoding utf8 = new UTF8Encoding(false); + byte[] pathData = utf8.GetBytes(filePath); + return unchecked((int)Crc32.Compute(pathData, 0, pathData.Length)); + } + } + + [TableName("DataFile")] + public class DataFileDb : DataFile { } + + public static partial class TableOperationsExtensions + { + public static DataFile QueryDataFile(this TableOperations dataFileTable, string filePath) + { + int hashCode = DataFile.GetHash(filePath); + DataFile dataFile = QueryDataFile(dataFileTable, filePath, hashCode); + + if (dataFile != null) + return dataFile; + + int legacyHashCode = filePath.GetHashCode(); + dataFile = QueryDataFile(dataFileTable, filePath, legacyHashCode); + + if (dataFile == null) + return null; + + dataFile.FilePathHash = hashCode; + dataFileTable.UpdateRecord(dataFile); + return dataFile; + } + + private static DataFile QueryDataFile(TableOperations dataFileTable, string filePath, int hashCode) + { + IEnumerable dataFiles = dataFileTable.QueryRecordsWhere("FilePathHash = {0}", hashCode); + return dataFiles.FirstOrDefault(dataFile => dataFile.FilePath == filePath); + } + } +} diff --git a/src/Libraries/openXDA.Model/Files/FileBlob.cs b/src/Libraries/openXDA.Model/Files/FileBlob.cs new file mode 100644 index 00000000..00beeef8 --- /dev/null +++ b/src/Libraries/openXDA.Model/Files/FileBlob.cs @@ -0,0 +1,38 @@ +//****************************************************************************************************** +// FileBlob.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [Serializable] + public class FileBlob + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int DataFileID { get; set; } + + public byte[] Blob { get; set; } + } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/Files/FileGroup.cs b/src/Libraries/openXDA.Model/Files/FileGroup.cs new file mode 100644 index 00000000..d6c50ab2 --- /dev/null +++ b/src/Libraries/openXDA.Model/Files/FileGroup.cs @@ -0,0 +1,102 @@ +//****************************************************************************************************** +// FileGroup.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Data; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [Serializable] + public class FileGroup + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int MeterID { get; set; } + + [FieldDataType(System.Data.DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime DataStartTime { get; set; } + + [FieldDataType(System.Data.DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime DataEndTime { get; set; } + + [FieldDataType(System.Data.DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime ProcessingStartTime { get; set; } + + [FieldDataType(System.Data.DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime ProcessingEndTime { get; set; } + + public int ProcessingVersion { get; set; } + + public int ProcessingStatus { get; set; } + + [NonRecordField] + public List DataFiles { get; set; } = new List(); + + public void AddFieldValue(AdoDataConnection connection, string name, string value, string description = null) + { + TableOperations fileGroupFieldTable = new TableOperations(connection); + FileGroupField fileGroupField = fileGroupFieldTable.GetOrAdd(name, description); + + TableOperations fileGroupFieldValueTable = new TableOperations(connection); + FileGroupFieldValue fileGroupFieldValue = new FileGroupFieldValue(); + fileGroupFieldValue.FileGroupID = ID; + fileGroupFieldValue.FileGroupFieldID = fileGroupField.ID; + fileGroupFieldValue.Value = value; + fileGroupFieldValueTable.AddNewRecord(fileGroupFieldValue); + } + + public void AddOrUpdateFieldValue(AdoDataConnection connection, string name, string value, string description = null) + { + TableOperations fileGroupFieldTable = new TableOperations(connection); + FileGroupField fileGroupField = fileGroupFieldTable.GetOrAdd(name, description); + + TableOperations fileGroupFieldValueTable = new TableOperations(connection); + RecordRestriction fileGroupRestriction = new RecordRestriction("FileGroupID = {0}", ID); + RecordRestriction fileGroupFieldRestriction = new RecordRestriction("FileGroupFieldID = {0}", fileGroupField.ID); + RecordRestriction queryRestriction = fileGroupRestriction & fileGroupFieldRestriction; + + FileGroupFieldValue fileGroupFieldValue = fileGroupFieldValueTable.QueryRecord(queryRestriction) ?? new FileGroupFieldValue() + { + FileGroupID = ID, + FileGroupFieldID = fileGroupField.ID + }; + + fileGroupFieldValue.Value = value; + fileGroupFieldValueTable.AddNewOrUpdateRecord(fileGroupFieldValue); + } + } + + /// + /// Number indicating the processing status of a file group. + /// + public enum FileGroupProcessingStatus + { + Created = 0, + Queued = 1, + Processing = 2, + Success = 3, + Failed = 4, + PartialSuccess = 5 + } +} diff --git a/src/Libraries/openXDA.Model/Files/FileGroupField.cs b/src/Libraries/openXDA.Model/Files/FileGroupField.cs new file mode 100644 index 00000000..31021f88 --- /dev/null +++ b/src/Libraries/openXDA.Model/Files/FileGroupField.cs @@ -0,0 +1,61 @@ +//****************************************************************************************************** +// FileGroupField.cs - Gbtc +// +// Copyright © 2019, 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: +// ---------------------------------------------------------------------------------------------------- +// 06/18/2019 - Stephen C. Wills +// Generated original version of source code. +// +//****************************************************************************************************** + +using System; +using System.ComponentModel.DataAnnotations; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + public class FileGroupField + { + [PrimaryKey(true)] + public int ID { get; set; } + + [StringLength(200)] + public string Name { get; set; } + + public string Description { get; set; } + } + + public static partial class TableOperationsExtensions + { + public static FileGroupField GetOrAdd(this TableOperations fileGroupFieldTable, string name, string description = null) + { + FileGroupField fileGroupField = fileGroupFieldTable.QueryRecordWhere("Name = {0}", name); + + if ((object)fileGroupField == null) + { + fileGroupField = new FileGroupField(); + fileGroupField.Name = name; + fileGroupField.Description = description; + + fileGroupFieldTable.AddNewRecord(fileGroupField); + + fileGroupField.ID = fileGroupFieldTable.Connection.ExecuteScalar("SELECT @@IDENTITY"); + } + + return fileGroupField; + } + } +} diff --git a/src/OpenSEE/App_Start/FilterConfig.cs b/src/Libraries/openXDA.Model/Files/FileGroupFieldValue.cs similarity index 73% rename from src/OpenSEE/App_Start/FilterConfig.cs rename to src/Libraries/openXDA.Model/Files/FileGroupFieldValue.cs index 97498ed4..55140bae 100644 --- a/src/OpenSEE/App_Start/FilterConfig.cs +++ b/src/Libraries/openXDA.Model/Files/FileGroupFieldValue.cs @@ -1,7 +1,7 @@ //****************************************************************************************************** -// FilterConfig.cs - Gbtc +// FileGroupFieldValue.cs - Gbtc // -// Copyright © 2020, Grid Protection Alliance. All Rights Reserved. +// Copyright © 2019, 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. @@ -16,21 +16,24 @@ // // Code Modification History: // ---------------------------------------------------------------------------------------------------- -// 02/19/2020 - Billy Ernest +// 06/18/2019 - Stephen C. Wills // Generated original version of source code. // //****************************************************************************************************** -using System.Web; -using System.Web.Mvc; +using Gemstone.Data.Model; -namespace OpenSEE +namespace openXDA.Model { - public class FilterConfig + public class FileGroupFieldValue { - public static void RegisterGlobalFilters(GlobalFilterCollection filters) - { - filters.Add(new HandleErrorAttribute()); - } + [PrimaryKey(true)] + public int ID { get; set; } + + public int FileGroupID { get; set; } + + public int FileGroupFieldID { get; set; } + + public string Value { get; set; } } } diff --git a/src/Libraries/openXDA.Model/LazyContext.cs b/src/Libraries/openXDA.Model/LazyContext.cs new file mode 100644 index 00000000..6f5c7acc --- /dev/null +++ b/src/Libraries/openXDA.Model/LazyContext.cs @@ -0,0 +1,369 @@ +//****************************************************************************************************** +// LazyContext.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 09/04/2017 - Stephen C. Wills +// Generated original version of source code. +// +//****************************************************************************************************** + +using System; +using System.Collections.Generic; +using Gemstone.Data; + +namespace openXDA.Model +{ + internal class LazyContext + { + #region [ Members ] + + // Fields + private Dictionary m_locations; + private Dictionary m_meters; + private Dictionary m_assetLocations; + private Dictionary m_sourceImpedances; + private Dictionary m_meterAssets; + private Dictionary m_channels; + private Dictionary m_series; + private Dictionary m_measurementTypes; + private Dictionary m_measurementCharacteristics; + private Dictionary m_phases; + private Dictionary m_seriesTypes; + + private Dictionary m_assets; + private Dictionary m_assetConnections; + + #endregion + + #region [ Constructors ] + + public LazyContext() + { + m_locations = new Dictionary(); + m_meters = new Dictionary(); + m_assets = new Dictionary(); + m_assetLocations = new Dictionary(); + m_sourceImpedances = new Dictionary(); + m_meterAssets = new Dictionary(); + m_channels = new Dictionary(); + m_series = new Dictionary(); + m_measurementTypes = new Dictionary(); + m_measurementCharacteristics = new Dictionary(); + m_phases = new Dictionary(); + m_seriesTypes = new Dictionary(); + m_assetConnections = new Dictionary(); + } + + #endregion + + #region [ Properties ] + + public Func ConnectionFactory { get; set; } + + #endregion + + #region [ Methods ] + + public Location GetLocation(int locationID) => + m_locations.TryGetValue(locationID, out Location location) + ? location + : null; + + public Location GetLocation(Location location) + { + Location cachedLocation; + + if ((object)location == null) + return null; + + if (location.ID == 0) + return location; + + if (m_locations.TryGetValue(location.ID, out cachedLocation)) + return cachedLocation; + + m_locations.Add(location.ID, location); + return location; + } + + public Meter GetMeter(int meterID) => + m_meters.TryGetValue(meterID, out Meter meter) + ? meter + : null; + + public Meter GetMeter(Meter meter) + { + Meter cachedMeter; + + if ((object)meter == null) + return null; + + if (meter.ID == 0) + return meter; + + if (m_meters.TryGetValue(meter.ID, out cachedMeter)) + return cachedMeter; + + m_meters.Add(meter.ID, meter); + return meter; + } + + public Asset GetAsset(int assetID) => + m_assets.TryGetValue(assetID, out Asset asset) + ? asset + : null; + + public Asset GetAsset(Asset asset) + { + Asset cachedAsset; + + if ((object)asset == null) + return null; + + if (asset.ID == 0) + return asset; + + if (m_assets.TryGetValue(asset.ID, out cachedAsset)) + return cachedAsset; + + m_assets.Add(asset.ID, asset); + return asset; + } + + public AssetLocation GetAssetLocation(int assetLocationID) => + m_assetLocations.TryGetValue(assetLocationID, out AssetLocation assetLocation) + ? assetLocation + : null; + + public AssetLocation GetAssetLocation(AssetLocation assetLocation) + { + AssetLocation cachedAssetLocation; + + if ((object)assetLocation == null) + return null; + + if (assetLocation.ID == 0) + return assetLocation; + + if (m_assetLocations.TryGetValue(assetLocation.ID, out cachedAssetLocation)) + return cachedAssetLocation; + + m_assetLocations.Add(assetLocation.ID, assetLocation); + return assetLocation; + } + + public SourceImpedance GetSourceImpedance(int sourceImpedanceID) => + m_sourceImpedances.TryGetValue(sourceImpedanceID, out SourceImpedance sourceImpedance) + ? sourceImpedance + : null; + + public SourceImpedance GetSourceImpedance(SourceImpedance sourceImpedance) + { + SourceImpedance cachedSourceImpedance; + + if ((object)sourceImpedance == null) + return null; + + if (sourceImpedance.ID == 0) + return sourceImpedance; + + if (m_sourceImpedances.TryGetValue(sourceImpedance.ID, out cachedSourceImpedance)) + return cachedSourceImpedance; + + m_sourceImpedances.Add(sourceImpedance.ID, sourceImpedance); + return sourceImpedance; + } + + public MeterAsset GetMeterAsset(int meterAssetID) => + m_meterAssets.TryGetValue(meterAssetID, out MeterAsset meterAsset) + ? meterAsset + : null; + + public MeterAsset GetMeterAsset(MeterAsset meterAsset) + { + MeterAsset cachedMeterAsset; + + if ((object)meterAsset == null) + return null; + + if (meterAsset.ID == 0) + return meterAsset; + + if (m_meterAssets.TryGetValue(meterAsset.ID, out cachedMeterAsset)) + return cachedMeterAsset; + + m_meterAssets.Add(meterAsset.ID, meterAsset); + return meterAsset; + } + + public Channel GetChannel(int channelID) => + m_channels.TryGetValue(channelID, out Channel channel) + ? channel + : null; + + public Channel GetChannel(Channel channel) + { + Channel cachedChannelLine; + + if ((object)channel == null) + return null; + + if (channel.ID == 0) + return channel; + + if (m_channels.TryGetValue(channel.ID, out cachedChannelLine)) + return cachedChannelLine; + + m_channels.Add(channel.ID, channel); + return channel; + } + + public Series GetSeries(int seriesID) => + m_series.TryGetValue(seriesID, out Series series) + ? series + : null; + + public Series GetSeries(Series series) + { + Series cachedSeriesLine; + + if ((object)series == null) + return null; + + if (series.ID == 0) + return series; + + if (m_series.TryGetValue(series.ID, out cachedSeriesLine)) + return cachedSeriesLine; + + m_series.Add(series.ID, series); + return series; + } + + public MeasurementType GetMeasurementType(int measurementTypeID) => + m_measurementTypes.TryGetValue(measurementTypeID, out MeasurementType measurementType) + ? measurementType + : null; + + public MeasurementType GetMeasurementType(MeasurementType measurementType) + { + MeasurementType cachedMeasurementTypeLine; + + if ((object)measurementType == null) + return null; + + if (measurementType.ID == 0) + return measurementType; + + if (m_measurementTypes.TryGetValue(measurementType.ID, out cachedMeasurementTypeLine)) + return cachedMeasurementTypeLine; + + m_measurementTypes.Add(measurementType.ID, measurementType); + return measurementType; + } + + public MeasurementCharacteristic GetMeasurementCharacteristic(int measurementCharacteristicID) => + m_measurementCharacteristics.TryGetValue(measurementCharacteristicID, out MeasurementCharacteristic measurementCharacteristic) + ? measurementCharacteristic + : null; + + public MeasurementCharacteristic GetMeasurementCharacteristic(MeasurementCharacteristic measurementCharacteristic) + { + MeasurementCharacteristic cachedMeasurementCharacteristicLine; + + if ((object)measurementCharacteristic == null) + return null; + + if (measurementCharacteristic.ID == 0) + return measurementCharacteristic; + + if (m_measurementCharacteristics.TryGetValue(measurementCharacteristic.ID, out cachedMeasurementCharacteristicLine)) + return cachedMeasurementCharacteristicLine; + + m_measurementCharacteristics.Add(measurementCharacteristic.ID, measurementCharacteristic); + return measurementCharacteristic; + } + + public Phase GetPhase(int phaseID) => + m_phases.TryGetValue(phaseID, out Phase phase) + ? phase + : null; + + public Phase GetPhase(Phase phase) + { + Phase cachedPhaseLine; + + if ((object)phase == null) + return null; + + if (phase.ID == 0) + return phase; + + if (m_phases.TryGetValue(phase.ID, out cachedPhaseLine)) + return cachedPhaseLine; + + m_phases.Add(phase.ID, phase); + return phase; + } + + public SeriesType GetSeriesType(int seriesTypeID) => + m_seriesTypes.TryGetValue(seriesTypeID, out SeriesType seriesType) + ? seriesType + : null; + + public SeriesType GetSeriesType(SeriesType seriesType) + { + SeriesType cachedSeriesTypeLine; + + if ((object)seriesType == null) + return null; + + if (seriesType.ID == 0) + return seriesType; + + if (m_seriesTypes.TryGetValue(seriesType.ID, out cachedSeriesTypeLine)) + return cachedSeriesTypeLine; + + m_seriesTypes.Add(seriesType.ID, seriesType); + return seriesType; + } + + public AssetConnection GetAssetConnection(int connectionID) => + m_assetConnections.TryGetValue(connectionID, out AssetConnection connection) + ? connection + : null; + + public AssetConnection GetAssetConnection(AssetConnection connection) + { + AssetConnection cachedConnection; + + if ((object)connection == null) + return null; + + if (connection.ID == 0) + return connection; + + if (m_assetConnections.TryGetValue(connection.ID, out cachedConnection)) + return cachedConnection; + + m_assetConnections.Add(connection.ID, connection); + return connection; + } + + #endregion + } +} diff --git a/src/Libraries/openXDA.Model/Links/AssetConnection.cs b/src/Libraries/openXDA.Model/Links/AssetConnection.cs new file mode 100644 index 00000000..dc03ab97 --- /dev/null +++ b/src/Libraries/openXDA.Model/Links/AssetConnection.cs @@ -0,0 +1,176 @@ +//****************************************************************************************************** +// AssetConnection.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 12/13/2019 - C. Lackner +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Data; +using Gemstone.Data.Model; +using Newtonsoft.Json; + +namespace openXDA.Model +{ + [TableName("AssetRelationship")] + [PostRoles("Administrator, Transmission SME")] + [PatchRoles("Administrator, Transmission SME")] + [DeleteRoles("Administrator, Transmission SME")] + public class AssetConnection + { + #region [ Members ] + + // Fields + private Asset m_parent; + private Asset m_child; + + #endregion + + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + public int AssetRelationshipTypeID { get; set; } + + public int ParentID { get; set; } + + public int ChildID { get; set; } + + [JsonIgnore] + [NonRecordField] + public Asset Parent + { + get + { + if (m_parent is null) + m_parent = LazyContext.GetAsset(ParentID); + + if (m_parent is null) + m_parent = QueryParent(); + + return m_parent; + } + set => m_parent = value; + } + + [JsonIgnore] + [NonRecordField] + public Asset Child + { + get + { + if (m_child is null) + m_child = LazyContext.GetAsset(ChildID); + + if (m_child is null) + m_child = QueryChild(); + + return m_child; + } + set => m_child = value; + } + + [JsonIgnore] + [NonRecordField] + public Func ConnectionFactory + { + get => LazyContext.ConnectionFactory; + set => LazyContext.ConnectionFactory = value; + } + + [JsonIgnore] + [NonRecordField] + internal LazyContext LazyContext { get; set; } = new LazyContext(); + + #endregion + + #region [ Methods ] + + public Asset GetParent(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations assetTable = new TableOperations(connection); + Asset parent = assetTable.QueryRecordWhere("ID = {0}", ParentID); + return parent; + } + + public Asset GetChild(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations assetTable = new TableOperations(connection); + Asset child = assetTable.QueryRecordWhere("ID = {0}", ChildID); + + return child; + } + + public Asset QueryParent() + { + Asset parent; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + parent = GetParent(connection); + } + + if ((object)parent != null) + parent.LazyContext = LazyContext; + + return LazyContext.GetAsset(parent); + } + + public Asset QueryChild() + { + Asset child; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + child = GetChild(connection); + } + + if ((object)child != null) + child.LazyContext = LazyContext; + + return LazyContext.GetAsset(child); + } + + #endregion + } + + public class AssetConnectionDetail + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int AssetRelationshipTypeID { get; set; } + + public int ParentID { get; set; } + + public int ChildID { get; set; } + + public string ChildKey { get; set; } + + public string ParentKey { get; set; } + + public string AssetRelationshipType { get; set; } + } +} diff --git a/src/Libraries/openXDA.Model/Links/MeterLine.cs b/src/Libraries/openXDA.Model/Links/MeterLine.cs new file mode 100644 index 00000000..4d44e704 --- /dev/null +++ b/src/Libraries/openXDA.Model/Links/MeterLine.cs @@ -0,0 +1,174 @@ +//****************************************************************************************************** +// MeterLine.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +// 12/13/2019 - C. Lackner +// Modified to fit new Asset Model Structure. +// +//****************************************************************************************************** + +using System; +using System.ComponentModel.DataAnnotations; +using Gemstone.Data; +using Gemstone.Data.Model; +using Newtonsoft.Json; + +namespace openXDA.Model +{ + public class MeterAsset + { + #region [ Members ] + + // Fields + private Meter m_meter; + private Asset m_asset; + + #endregion + + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + public int MeterID { get; set; } + + public int AssetID { get; set; } + + [JsonIgnore] + [NonRecordField] + public Meter Meter + { + get + { + if (m_meter is null) + m_meter = LazyContext.GetMeter(MeterID); + + if (m_meter is null) + m_meter = QueryMeter(); + + return m_meter; + } + set => m_meter = value; + } + + [JsonIgnore] + [NonRecordField] + public Asset Asset + { + get + { + if (m_asset is null) + m_asset = LazyContext.GetAsset(AssetID); + + if (m_asset is null) + m_asset = QueryAsset(); + + return m_asset; + } + set => m_asset = value; + } + + [JsonIgnore] + [NonRecordField] + public Func ConnectionFactory + { + get => LazyContext.ConnectionFactory; + set => LazyContext.ConnectionFactory = value; + } + + [JsonIgnore] + [NonRecordField] + internal LazyContext LazyContext { get; set; } = new LazyContext(); + + #endregion + + #region [ Methods ] + + public Meter GetMeter(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations meterTable = new TableOperations(connection); + return meterTable.QueryRecordWhere("ID = {0}", MeterID); + } + + public Asset GetAsset(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations assetTable = new TableOperations(connection); + return assetTable.QueryRecordWhere("ID = {0}", AssetID); + } + + public Meter QueryMeter() + { + Meter meter; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + meter = GetMeter(connection); + } + + if ((object)meter != null) + meter.LazyContext = LazyContext; + + return LazyContext.GetMeter(meter); + } + + public Asset QueryAsset() + { + Asset asset; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + asset = GetAsset(connection); + } + + if ((object)asset != null) + asset.LazyContext = LazyContext; + + return LazyContext.GetAsset(asset); + } + + #endregion + } + + public class MeterAssetDetail + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int MeterID { get; set; } + + public int AssetID { get; set; } + + public string MeterKey { get; set; } + + public string AssetKey { get; set; } + + public string AssetName { get; set; } + + public string AssetType { get; set; } + + public string FaultDetectionLogic { get; set; } + } +} diff --git a/src/Libraries/openXDA.Model/Links/MeterLocationLine.cs b/src/Libraries/openXDA.Model/Links/MeterLocationLine.cs new file mode 100644 index 00000000..377ec143 --- /dev/null +++ b/src/Libraries/openXDA.Model/Links/MeterLocationLine.cs @@ -0,0 +1,192 @@ +//****************************************************************************************************** +// MeterLocationLine.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 06/19/2017 - Billy Ernest +// Generated original version of source code. +// 12/13/2019 - C. Lackner +// Update to reflect changes in Location and move from Line to Asset. +// +//****************************************************************************************************** + +using Gemstone.Data; +using Gemstone.Data.Model; +using Newtonsoft.Json; + +namespace openXDA.Model +{ + public class AssetLocation + { + #region [ Members ] + + // Fields + private Location m_location; + private Asset m_asset; + private SourceImpedance m_sourceImpedance; + + #endregion + + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + public int LocationID { get; set; } + + public int AssetID { get; set; } + + [JsonIgnore] + [NonRecordField] + public Location Location + { + get + { + if (m_location is null) + m_location = LazyContext.GetLocation(LocationID); + + if (m_location is null) + m_location = QueryLocation(); + + return m_location; + } + set => m_location = value; + } + + [JsonIgnore] + [NonRecordField] + public Asset Asset + { + get + { + if (m_asset is null) + m_asset = LazyContext.GetAsset(AssetID); + + if (m_asset is null) + m_asset = QueryAsset(); + + return m_asset; + } + set => m_asset = value; + } + + [JsonIgnore] + [NonRecordField] + public SourceImpedance SourceImpedance + { + get => m_sourceImpedance ?? (m_sourceImpedance ?? QuerySourceImpedance()); + set => m_sourceImpedance = value; + } + + [JsonIgnore] + [NonRecordField] + public Func ConnectionFactory + { + get => LazyContext.ConnectionFactory; + set => LazyContext.ConnectionFactory = value; + } + + [JsonIgnore] + [NonRecordField] + internal LazyContext LazyContext { get; set; } = new LazyContext(); + + #endregion + + #region [ Methods ] + + public Location GetLocation(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations locationTable = new TableOperations(connection); + + try + { + return locationTable.QueryRecordWhere("ID = {0}", LocationID); + } + catch + { + return null; + } + } + + public Asset GetAsset(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations assetTable = new TableOperations(connection); + return assetTable.QueryRecordWhere("ID = {0}", AssetID); + } + + public SourceImpedance GetSourceImpedance(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations sourceImpedanceTable = new TableOperations(connection); + return sourceImpedanceTable.QueryRecordWhere("AssetLocationID = {0}", ID); + } + + private Location QueryLocation() + { + Location location; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + location = GetLocation(connection); + } + + if ((object)location != null) + location.LazyContext = LazyContext; + + return LazyContext.GetLocation(location); + } + + private Asset QueryAsset() + { + Asset asset; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + asset = GetAsset(connection); + } + + if ((object)asset != null) + asset.LazyContext = LazyContext; + + return LazyContext.GetAsset(asset); + } + + private SourceImpedance QuerySourceImpedance() + { + SourceImpedance sourceImpedance; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + sourceImpedance = GetSourceImpedance(connection); + } + + if ((object)sourceImpedance != null) + sourceImpedance.LazyContext = LazyContext; + + return LazyContext.GetSourceImpedance(sourceImpedance); + } + + #endregion + } +} diff --git a/src/Libraries/openXDA.Model/Meters/Location.cs b/src/Libraries/openXDA.Model/Meters/Location.cs new file mode 100644 index 00000000..6c8515d1 --- /dev/null +++ b/src/Libraries/openXDA.Model/Meters/Location.cs @@ -0,0 +1,509 @@ +//****************************************************************************************************** +// Location.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// 12/13/2019 - Christoph Lackner +// Updated MeterLocation to more Generic Location. +// +//****************************************************************************************************** + +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Text.RegularExpressions; +using Gemstone.Collections.CollectionExtensions; +using Gemstone.Data; +using Gemstone.Data.DataExtensions; +using Gemstone.Data.Model; +using Newtonsoft.Json; + +namespace openXDA.Model +{ + [PostRoles("Administrator, Transmission SME")] + [DeleteRoles("Administrator, Transmission SME")] + [PatchRoles("Administrator, Transmission SME")] + public class Location + { + #region [ Members ] + + // Nested Types + private delegate void ChannelConnector(int assetID, IEnumerable channels); + private delegate IEnumerable AssetConnectionLookup(int assetID); + + private class AssetConnectionDetail + { + #region [ Constructors ] + + public AssetConnectionDetail(int parentID, int childID, string jumpSQL, string passthroughSQL) + { + ParentID = parentID; + ChildID = childID; + JumpSQL = jumpSQL; + PassthroughSQL = passthroughSQL; + } + + #endregion + + #region [ Properties ] + + public int ParentID { get; } + public int ChildID { get; } + private string JumpSQL { get; } + private string PassthroughSQL { get; } + + private HashSet JumpChannels { get; } = new HashSet(); + private HashSet PassthroughChannels { get; } = new HashSet(); + private bool Populated { get; set; } + + #endregion + + #region [ Methods ] + + public void PopulateChannelSets(AdoDataConnection connection, int locationID, Func channelLookup) + { + if (Populated) + return; + + // lang=regex + const string Pattern = @"\{(?:parentid|childid|channelid)\}"; + string jumpSQL = Regex.Replace(JumpSQL, Pattern, ReplaceFormatParameter, RegexOptions.IgnoreCase); + string passthroughSQL = Regex.Replace(PassthroughSQL, Pattern, ReplaceFormatParameter, RegexOptions.IgnoreCase); + + string queryFormat = + $"SELECT " + + $" SourceChannel.ID ChannelID, " + + $" Jump.Value Jump, " + + $" Passthrough.Value Passthrough " + + $"FROM " + + $" Asset ParentAsset JOIN " + + $" Asset ChildAsset ON " + + $" ParentAsset.ID = {{0}} AND " + + $" ChildAsset.ID = {{1}} JOIN " + + $" Location ON Location.ID = {{2}} JOIN " + + $" Meter ON Meter.LocationID = Location.ID JOIN " + + $" Channel SourceChannel ON SourceChannel.MeterID = Meter.ID CROSS APPLY " + + $" ({jumpSQL}) Jump(Value) CROSS APPLY " + + $" ({passthroughSQL}) Passthrough(Value) " + + $"WHERE " + + $" Jump.Value <> 0 OR " + + $" Passthrough.Value <> 0"; + + using (DataTable table = connection.RetrieveData(queryFormat, ParentID, ChildID, locationID)) + { + foreach (DataRow row in table.AsEnumerable()) + { + int channelID = row.ConvertField("ChannelID"); + bool jump = row.ConvertField("Jump"); + bool passthrough = row.ConvertField("Passthrough"); + Channel channel = channelLookup(channelID); + if (channel is null) continue; + if (jump) JumpChannels.Add(channel); + if (passthrough) PassthroughChannels.Add(channel); + } + } + + Populated = true; + + string ReplaceFormatParameter(Match match) + { + switch (match.Value.ToLowerInvariant()) + { + case "{parentid}": return "ParentAsset.ID"; + case "{childid}": return "ChildAsset.ID"; + case "{channelid}": return "SourceChannel.ID"; + default: return match.Value; + } + } + } + + public bool CanJump(Channel channel) => + JumpChannels.Contains(channel); + + public bool CanPassThrough(Channel channel) => + PassthroughChannels.Contains(channel); + + #endregion + } + + private class TraversalContext + { + public AdoDataConnection Connection { get; } + public HashSet VisitedAssets { get; } + public AssetConnectionLookup FindAssetConnections { get; } + public ChannelConnector ConnectChannels { get; } + + public TraversalContext(AdoDataConnection connection, HashSet visitedAssets, AssetConnectionLookup findAssetConnections, ChannelConnector connectChannels) + { + Connection = connection; + VisitedAssets = visitedAssets; + FindAssetConnections = findAssetConnections; + ConnectChannels = connectChannels; + } + } + + // Fields + private List m_meters; + private List m_assetLocations; + + #endregion + + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + [StringLength(50)] + [Required] + [DefaultSortOrder] + public string LocationKey { get; set; } + + [StringLength(200)] + [Required] + public string Name { get; set; } + + [StringLength(200)] + public string Alias { get; set; } + + [StringLength(50)] + public string ShortName { get; set; } + + [Required] + public double Latitude { get; set; } + + [Required] + public double Longitude { get; set; } + + [StringLength(200)] + public string Description { get; set; } + + [JsonIgnore] + [NonRecordField] + public List Meters + { + get + { + return m_meters ?? (m_meters = QueryMeters()); + } + set + { + m_meters = value; + } + } + + [JsonIgnore] + [NonRecordField] + public List AssetLocations + { + get + { + return m_assetLocations ?? (m_assetLocations = QueryAssetLocations()); + } + set + { + m_assetLocations = value; + } + } + + [JsonIgnore] + [NonRecordField] + public Func ConnectionFactory + { + get + { + return LazyContext.ConnectionFactory; + } + set + { + LazyContext.ConnectionFactory = value; + } + } + + [JsonIgnore] + [NonRecordField] + internal LazyContext LazyContext { get; set; } = new LazyContext(); + + #endregion + + #region [ Methods ] + + public IEnumerable GetMeters(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations meterTable = new TableOperations(connection); + return meterTable.QueryRecordsWhere("MeterLocationID = {0}", ID); + } + + public IEnumerable GetAssetLocations(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations assetLocationTable = new TableOperations(connection); + return assetLocationTable.QueryRecordsWhere("LocationID = {0}", ID); + } + + private List QueryMeters() + { + List meters; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + meters = GetMeters(connection)? + .Select(LazyContext.GetMeter) + .ToList(); + } + + if ((object)meters != null) + { + foreach (Meter meter in meters) + { + meter.Location = this; + meter.LazyContext = LazyContext; + } + } + + return meters; + } + + private List QueryAssetLocations() + { + List assetLocations; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + assetLocations = GetAssetLocations(connection)? + .Select(LazyContext.GetAssetLocation) + .ToList(); + } + + if ((object)assetLocations != null) + { + foreach (AssetLocation assetLocation in assetLocations) + { + assetLocation.Location = this; + assetLocation.LazyContext = LazyContext; + } + } + + return assetLocations; + } + + public void ConnectAllChannels() + { + if (ConnectionFactory is null) + return; + + Dictionary> connectedChannelLookup = new Dictionary>(); + ChannelConnector connectChannels = CreateChannelConnector(connectedChannelLookup); + + using (AdoDataConnection connection = ConnectionFactory()) + { + TraverseAssetConnections(connection, connectChannels); + + TableOperations assetTable = new TableOperations(connection); + + foreach (KeyValuePair> kvp in connectedChannelLookup) + { + int assetID = kvp.Key; + HashSet connectedChannels = kvp.Value; + Asset asset = assetTable.QueryRecordWhere("ID = {0}", assetID); + asset = LazyContext.GetAsset(asset); + asset.ConnectedChannels = connectedChannels.ToList(); + asset.LazyContext = LazyContext; + } + } + + // Assign empty lists to any assets that were missed by the recursive search + foreach (Asset asset in AssetLocations.Select(al => al.Asset)) + EnsureConnectedChannels(asset); + } + + private void TraverseAssetConnections(AdoDataConnection connection, ChannelConnector connectChannels) + { + List allChannels = RetrieveAllChannels(connection).ToList(); + List allAssetConnections = RetrieveAllAssetConnections(connection).ToList(); + AssetConnectionLookup findAssetConnections = CreateAssetConnectionLookup(connection, allChannels, allAssetConnections); + + foreach (IGrouping rootChannels in allChannels.GroupBy(channel => channel.AssetID)) + { + int rootAssetID = rootChannels.Key; + + // Initialize an empty set of connected channels in case the root asset has no connected channels + connectChannels(rootAssetID, Enumerable.Empty()); + + foreach (AssetConnectionDetail assetConnection in findAssetConnections(rootAssetID)) + { + List jumpChannels = rootChannels + .Where(assetConnection.CanJump) + .ToList(); + + if (jumpChannels.Count == 0) + continue; + + int connectedAssetID = assetConnection.ChildID; + connectChannels(connectedAssetID, jumpChannels); + + HashSet visitedAssets = new HashSet() { rootAssetID }; + TraversalContext context = new TraversalContext(connection, visitedAssets, findAssetConnections, connectChannels); + TraverseAssetConnections(context, jumpChannels, connectedAssetID); + } + } + } + + private void TraverseAssetConnections(TraversalContext context, List connectedChannels, int visitedAssetID) + { + AdoDataConnection connection = context.Connection; + HashSet visitedAssets = context.VisitedAssets; + AssetConnectionLookup findAssetConnections = context.FindAssetConnections; + ChannelConnector connectChannels = context.ConnectChannels; + + visitedAssets.Add(visitedAssetID); + + foreach (AssetConnectionDetail assetConnection in findAssetConnections(visitedAssetID)) + { + int connectedAssetID = assetConnection.ChildID; + + if (visitedAssets.Contains(connectedAssetID)) + continue; + + List passthroughChannels = connectedChannels + .Where(assetConnection.CanPassThrough) + .ToList(); + + if (passthroughChannels.Count == 0) + continue; + + connectChannels(connectedAssetID, passthroughChannels); + TraverseAssetConnections(context, passthroughChannels, connectedAssetID); + } + + visitedAssets.Remove(visitedAssetID); + } + + private IEnumerable RetrieveAllChannels(AdoDataConnection connection) + { + const string QueryFormat = + "SELECT Channel.* " + + "FROM " + + " Channel JOIN " + + " Meter ON Channel.MeterID = Meter.ID " + + "WHERE Meter.LocationID = {0}"; + + TableOperations channelTable = new TableOperations(connection); + + using (DataTable table = connection.RetrieveData(QueryFormat, ID)) + { + foreach (DataRow row in table.AsEnumerable()) + { + Channel channel = channelTable.LoadRecord(row); + channel = LazyContext.GetChannel(channel); + yield return channel; + } + } + } + + private IEnumerable RetrieveAllAssetConnections(AdoDataConnection connection) + { + const string QueryFormat = + "SELECT " + + " AssetConnection.ParentID, " + + " AssetConnection.ChildID, " + + " AssetRelationshipType.JumpConnection JumpSQL, " + + " AssetRelationshipType.PassThrough PassthroughSQL " + + "FROM " + + " Location JOIN " + + " AssetConnection ON Location.ID = {0} JOIN " + + " AssetRelationshipType ON AssetConnection.AssetRelationshipTypeID = AssetRelationshipType.ID JOIN " + + " AssetLocation ParentLocation ON " + + " ParentLocation.LocationID = Location.ID AND " + + " ParentLocation.AssetID = AssetConnection.ParentID JOIN " + + " AssetLocation ChildLocation ON " + + " ChildLocation.LocationID = Location.ID AND " + + " ChildLocation.AssetID = AssetConnection.ChildID"; + + using (DataTable table = connection.RetrieveData(QueryFormat, ID)) + { + foreach (DataRow row in table.AsEnumerable()) + { + int parentID = row.ConvertField("ParentID"); + int childID = row.ConvertField("ChildID"); + string jumpSQL = row.ConvertField("JumpSQL"); + string passthroughSQL = row.ConvertField("PassthroughSQL"); + yield return new AssetConnectionDetail(parentID, childID, jumpSQL, passthroughSQL); + yield return new AssetConnectionDetail(childID, parentID, jumpSQL, passthroughSQL); + } + } + } + + private AssetConnectionLookup CreateAssetConnectionLookup(AdoDataConnection connection, List allChannels, List allAssetConnections) + { + Dictionary channelLookup = allChannels.ToDictionary(channel => channel.ID); + ILookup assetConnectionLookup = allAssetConnections.ToLookup(conn => conn.ParentID); + return findAssetConnection; + + Channel findChannel(int channelID) => + channelLookup.TryGetValue(channelID, out Channel channel) + ? channel + : null; + + IEnumerable findAssetConnection(int assetID) + { + foreach (AssetConnectionDetail assetConnection in assetConnectionLookup[assetID]) + { + assetConnection.PopulateChannelSets(connection, ID, findChannel); + yield return assetConnection; + } + } + } + + #endregion + + #region [ Static ] + + // Static Methods + private static ChannelConnector CreateChannelConnector(Dictionary> connectedChannelLookup) + { + return (assetID, channels) => + { + HashSet connectedChannels = connectedChannelLookup.GetOrAdd(assetID, _ => new HashSet()); + connectedChannels.UnionWith(channels); + }; + } + + private static void EnsureConnectedChannels(Asset asset) + { + Func connectionFactory = asset.ConnectionFactory; + + try + { + asset.ConnectionFactory = null; + + if (asset.ConnectedChannels is null) + asset.ConnectedChannels = new List(); + } + finally + { + asset.ConnectionFactory = connectionFactory; + } + } + + #endregion + } +} diff --git a/src/Libraries/openXDA.Model/Meters/Meter.cs b/src/Libraries/openXDA.Model/Meters/Meter.cs new file mode 100644 index 00000000..47c6b517 --- /dev/null +++ b/src/Libraries/openXDA.Model/Meters/Meter.cs @@ -0,0 +1,338 @@ +//****************************************************************************************************** +// Meter.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +// 12/13/2019 - C. Lackner +// Updated to fit in new Asset based model structure. +//****************************************************************************************************** + +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using Gemstone.ComponentModel.DataAnnotations; +using Gemstone.Data; +using Gemstone.Data.Model; +using Newtonsoft.Json; + +namespace openXDA.Model +{ + [PostRoles("Administrator, Transmission SME")] + [DeleteRoles("Administrator, Transmission SME")] + [PatchRoles("Administrator, Transmission SME")] + public class Meter + { + #region [ Members ] + + // Fields + private Location m_location; + private List m_meterAssets; + private List m_channels; + + #endregion + + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + [Required] + [StringLength(50)] + [DefaultSortOrder] + public string AssetKey { get; set; } + + [Required] + [Label("Location")] + public int LocationID { get; set; } + + [Required] + [StringLength(200)] + public string Name { get; set; } + + [StringLength(200)] + public string Alias { get; set; } + + [StringLength(12)] + public string ShortName { get; set; } + + [Required] + [StringLength(200)] + public string Make { get; set; } + + [Required] + [StringLength(200)] + public string Model { get; set; } + + + [StringLength(200)] + public string TimeZone { get; set; } + + public string Description { get; set; } + + [JsonIgnore] + [NonRecordField] + public Location Location + { + get + { + if (m_location is null) + m_location = LazyContext.GetLocation(LocationID); + + if (m_location is null) + m_location = QueryLocation(); + + return m_location; + } + set => m_location = value; + } + + [JsonIgnore] + [NonRecordField] + public List MeterAssets + { + get => m_meterAssets ?? (m_meterAssets = QueryMeterAssets()); + set => m_meterAssets = value; + } + + [JsonIgnore] + [NonRecordField] + public List Channels + { + get => m_channels ?? (m_channels = QueryChannels()); + set => m_channels = value; + } + + public List Series + { + get + { + List channels = Channels; + + if (channels is null) + return null; + + bool IsQueryRequired() + { + var connectionFactory = ConnectionFactory; + + try + { + // Don't trigger individual queries for each channel + ConnectionFactory = null; + return channels.Any(channel => channel.Series is null); + } + finally + { + ConnectionFactory = connectionFactory; + } + } + + if (IsQueryRequired()) + return QuerySeries(); + + return channels + .SelectMany(channel => channel.Series) + .ToList(); + } + } + + [JsonIgnore] + [NonRecordField] + public Func ConnectionFactory + { + get => LazyContext.ConnectionFactory; + set => LazyContext.ConnectionFactory = value; + } + + [JsonIgnore] + [NonRecordField] + internal LazyContext LazyContext { get; set; } = new LazyContext(); + + #endregion + + #region [ Methods ] + + public Location GetLocation(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations locationTable = new TableOperations(connection); + return locationTable.QueryRecordWhere("ID = {0}", LocationID); + } + + public IEnumerable GetMeterAssets(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations meterAssetTable = new TableOperations(connection); + return meterAssetTable.QueryRecordsWhere("MeterID = {0}", ID); + } + + public IEnumerable GetChannels(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations channelTable = new TableOperations(connection); + return channelTable.QueryRecordsWhere("MeterID = {0}", ID); + } + + public IEnumerable GetSeries(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations seriesTable = new TableOperations(connection); + return seriesTable.QueryRecordsWhere("ChannelID IN (SELECT ID FROM Channel WHERE MeterID = {0})", ID); + } + + public TimeZoneInfo GetTimeZoneInfo(TimeZoneInfo defaultTimeZone) + { + if (!string.IsNullOrEmpty(TimeZone)) + return TimeZoneInfo.FindSystemTimeZoneById(TimeZone); + + return defaultTimeZone; + } + + private Location QueryLocation() + { + Location location; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + location = GetLocation(connection); + } + + if ((object)location != null) + location.LazyContext = LazyContext; + + return LazyContext.GetLocation(location); + } + + private List QueryMeterAssets() + { + List meterAssets; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + meterAssets = GetMeterAssets(connection)? + .Select(LazyContext.GetMeterAsset) + .ToList(); + } + + if ((object)meterAssets != null) + { + foreach (MeterAsset meterAsset in meterAssets) + { + meterAsset.Meter = this; + meterAsset.LazyContext = LazyContext; + } + } + + return meterAssets; + } + + private List QueryChannels() + { + List channels; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + channels = GetChannels(connection)? + .Select(LazyContext.GetChannel) + .ToList(); + } + + if ((object)channels != null) + { + foreach (Channel channel in channels) + { + channel.Meter = this; + channel.LazyContext = LazyContext; + } + } + + return channels; + } + + private List QuerySeries() + { + List seriesList; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + seriesList = GetSeries(connection)? + .Select(LazyContext.GetSeries) + .ToList(); + } + + if (!(seriesList is null)) + { + ILookup seriesLookup = seriesList.ToLookup(series => series.ChannelID); + + foreach (Channel channel in Channels) + { + channel.Series = seriesLookup[channel.ID].ToList(); + + foreach (Series series in channel.Series) + { + series.Channel = channel; + series.LazyContext = LazyContext; + } + } + } + + return seriesList; + } + + #endregion + } + + public class MeterDetail : Meter + { + public new string Location { get; set; } + + public string TimeZoneLabel + { + get + { + try + { + if (TimeZone != "UTC") + return TimeZoneInfo.FindSystemTimeZoneById(TimeZone).ToString(); + } + catch + { + // Do not fail if the time zone cannot be found -- + // instead, fall through to the logic below to + // find the label for UTC + } + + return TimeZoneInfo.GetSystemTimeZones() + .Where(info => info.Id == "UTC") + .DefaultIfEmpty(TimeZoneInfo.Utc) + .First() + .ToString(); + } + } + } +} diff --git a/src/OpenSEE/App_Start/BundleConfig.cs b/src/Libraries/openXDA.Model/PQDigest/HomeScreenWidget.cs similarity index 71% rename from src/OpenSEE/App_Start/BundleConfig.cs rename to src/Libraries/openXDA.Model/PQDigest/HomeScreenWidget.cs index 4716bfc5..ee826388 100644 --- a/src/OpenSEE/App_Start/BundleConfig.cs +++ b/src/Libraries/openXDA.Model/PQDigest/HomeScreenWidget.cs @@ -1,5 +1,5 @@ //****************************************************************************************************** -// BundleConfig.cs - Gbtc +// HomeScreenWidget.cs - Gbtc // // Copyright © 2020, Grid Protection Alliance. All Rights Reserved. // @@ -16,26 +16,29 @@ // // Code Modification History: // ---------------------------------------------------------------------------------------------------- -// 02/19/2020 - Billy Ernest +// 08/10/2020 - C. Lackner // Generated original version of source code. // //****************************************************************************************************** -using System.Web; -using System.Web.Optimization; +using Gemstone.Data.Model; -namespace OpenSEE +namespace PQDigest.Model { - public class BundleConfig + /// + /// Defines a widget used in PQDigest Home Screen + /// + [TableName("PQDigest.HomeScreenWidget"), UseEscapedName] + [PostRoles("Administrator")] + [DeleteRoles("Administrator")] + [PatchRoles("Administrator")] + public class HomeScreenWidget : Widget { - // For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862 - public static void RegisterBundles(BundleCollection bundles) - { - // Code removed for clarity. -#if Debug - BundleTable.EnableOptimizations = true; -#endif + #region [ Properties ] - } + public int TimeFrame { get; set; } + + #endregion } -} + +} \ No newline at end of file diff --git a/src/OpenSEE/GlobalSettings.cs b/src/Libraries/openXDA.Model/PQDigest/Widget.cs similarity index 54% rename from src/OpenSEE/GlobalSettings.cs rename to src/Libraries/openXDA.Model/PQDigest/Widget.cs index 6e9401a0..6042dea0 100644 --- a/src/OpenSEE/GlobalSettings.cs +++ b/src/Libraries/openXDA.Model/PQDigest/Widget.cs @@ -1,5 +1,5 @@ //****************************************************************************************************** -// GlobalSettings.cs - Gbtc +// Widget.cs - Gbtc // // Copyright © 2020, Grid Protection Alliance. All Rights Reserved. // @@ -16,31 +16,36 @@ // // Code Modification History: // ---------------------------------------------------------------------------------------------------- -// 02/19/2020 - Billy Ernest +// 08/10/2020 - C. Lackner // Generated original version of source code. // //****************************************************************************************************** -using System.Collections.Generic; +using Gemstone.Data.Model; -namespace OpenSEE +namespace PQDigest.Model { - public class GlobalSettings + /// + /// Defines a widget used in PQDigest + /// + [TableName("PQDigest.EventViewWidget"), UseEscapedName] + [PostRoles("Administrator")] + [DeleteRoles("Administrator")] + [PatchRoles("Administrator")] + public class Widget { - public string CompanyName{ get; set; } - public string CompanyAcronym{ get; set; } - public string ApplicationName{ get; set; } - public string ApplicationDescription{ get; set; } - public string ApplicationKeywords{ get; set; } - public string DateFormat{ get; set; } - public string TimeFormat{ get; set; } - public string DateTimeFormat{ get; set; } - public string PasswordRequirementsRegex{ get; set; } - public string PasswordRequirementsError{ get; set; } - public string BootstrapTheme{ get; set; } - - public readonly Dictionary ApplicationSettings = new Dictionary(); - public readonly Dictionary LayoutSettings = new Dictionary(); - public readonly Dictionary PageDefaults = new Dictionary(); + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + public string Name { get; set; } + + public string Setting { get; set; } + + public string Type { get; set; } + + #endregion } + } \ No newline at end of file diff --git a/src/OpenSEE/Controllers/LoginController.cs b/src/Libraries/openXDA.Model/SEBrowser/Widget.cs similarity index 54% rename from src/OpenSEE/Controllers/LoginController.cs rename to src/Libraries/openXDA.Model/SEBrowser/Widget.cs index 0ddd37aa..dcf2b368 100644 --- a/src/OpenSEE/Controllers/LoginController.cs +++ b/src/Libraries/openXDA.Model/SEBrowser/Widget.cs @@ -1,7 +1,7 @@ //****************************************************************************************************** -// LoginController.cs - Gbtc +// Widget.cs - Gbtc // -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. +// Copyright © 2020, 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. @@ -16,48 +16,46 @@ // // Code Modification History: // ---------------------------------------------------------------------------------------------------- -// 02/26/2023 - J. Ritchie Carroll +// 08/10/2020 - C. Lackner // Generated original version of source code. // //****************************************************************************************************** -using System; -using System.Threading; -using System.Web.Mvc; -using GSF.Web.Security; +using Gemstone.Data.Model; -namespace OpenSEE.Controllers; - -public class LoginController : Controller +namespace SEBrowser.Model { - [AllowAnonymous] - public ActionResult Index() + /// + /// Defines a widget used in SEBrowser + /// + [TableName("SEBrowser.Widget"), UseEscapedName] + [PostRoles("Administrator")] + [DeleteRoles("Administrator")] + [PatchRoles("Administrator")] + public class Widget { - if (!Startup.OwinLoaded) - throw new InvalidOperationException("Owin pipeline not loaded. Try running 'update-package Microsoft.Owin.Host.SystemWeb -reinstall' from NuGet Package Manager Console."); + #region [ Properties ] - return View(); - } + [PrimaryKey(true)] + public int ID { get; set; } - [Route("~/AuthTest")] - [AuthorizeControllerRole] - public ActionResult AuthTest() - { - return View(); - } + public string Name { get; set; } - [Route("~/Logout")] - [AllowAnonymous] - public ActionResult Logout() - { - return View(); + public string Setting { get; set; } + + public string Type { get; set; } + + #endregion } - [Route("~/UserInfo")] - [AuthorizeControllerRole] - public ActionResult UserInfo() + [TableName("SEbrowser.WidgetView"), UseEscapedName] + [PostRoles("Administrator")] + [DeleteRoles("Administrator")] + [PatchRoles("Administrator")] + public class WidgetView : Widget { - Thread.CurrentPrincipal = ViewBag.SecurityPrincipal = User; - return View(); + [ParentKey(typeof (WidgetCategory))] + public int CategoryID { get; set; } } + } \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/SEBrowser/WidgetCategory.cs b/src/Libraries/openXDA.Model/SEBrowser/WidgetCategory.cs new file mode 100644 index 00000000..62faf93e --- /dev/null +++ b/src/Libraries/openXDA.Model/SEBrowser/WidgetCategory.cs @@ -0,0 +1,52 @@ +//****************************************************************************************************** +// WidgetCategory.cs - Gbtc +// +// Copyright © 2020, 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/10/2020 - C. Lackner +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Data.Model; + +namespace SEBrowser.Model +{ + /// + /// Defines the categories of widgets used in SEBrowser + /// + /// + /// Will need to use in SEbrowser ans OpenSEE too. + /// + [TableName("SEBrowser.WidgetCategory"), UseEscapedName] + [PostRoles("Administrator")] + [DeleteRoles("Administrator")] + [PatchRoles("Administrator")] + public class WidgetCategory + { + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + public string Name { get; set; } + + [DefaultSortOrder(true)] + public int OrderBy { get; set; } + + #endregion + } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/Settings/OpenSEESetting.cs b/src/Libraries/openXDA.Model/Settings/OpenSEESetting.cs new file mode 100644 index 00000000..a1e5adc9 --- /dev/null +++ b/src/Libraries/openXDA.Model/Settings/OpenSEESetting.cs @@ -0,0 +1,33 @@ +//****************************************************************************************************** +// OpenSEESetting.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 02/05/2026 - Gabriel Santos +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [TableName("OpenSEE.Setting"), UseEscapedName] + [PostRoles("Administrator")] + [DeleteRoles("Administrator")] + [PatchRoles("Administrator")] + public class OpenSEESetting : Setting { } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/Settings/PQDigestSetting.cs b/src/Libraries/openXDA.Model/Settings/PQDigestSetting.cs new file mode 100644 index 00000000..877bff81 --- /dev/null +++ b/src/Libraries/openXDA.Model/Settings/PQDigestSetting.cs @@ -0,0 +1,33 @@ +//****************************************************************************************************** +// PQDigestSetting.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 10/20/2025 - Gabriel Santos +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [TableName("PQDigest.Setting"), UseEscapedName] + [PostRoles("Administrator")] + [DeleteRoles("Administrator")] + [PatchRoles("Administrator")] + public class PQDigestSetting : Setting { } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/Settings/Setting.cs b/src/Libraries/openXDA.Model/Settings/Setting.cs new file mode 100644 index 00000000..b9f2a866 --- /dev/null +++ b/src/Libraries/openXDA.Model/Settings/Setting.cs @@ -0,0 +1,84 @@ +//****************************************************************************************************** +// Setting.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.ComponentModel.DataAnnotations; +using Gemstone.ComponentModel.DataAnnotations; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + [DeleteRoles("Administrator")] + [PatchRoles("Administrator")] + [PostRoles("Administrator")] + [TableName("Setting")] + [UseEscapedName] + public class Setting + { + [PrimaryKey(true)] + public int ID { get; set; } + + public string Name { get; set; } + + public string Value { get; set; } + + public string DefaultValue { get; set; } + } + + [TableName("DashSettings")] + public class DashSettings + { + [PrimaryKey(true)] + public int ID { get; set; } + + [Required] + [StringLength(500)] + public string Name { get; set; } + + [Required] + [StringLength(500)] + public string Value { get; set; } + + [Required] + public bool Enabled { get; set; } + } + + [PrimaryLabel("Name")] + [TableName("UserDashSettings")] + public class UserDashSettings + { + [PrimaryKey(true)] + public int ID { get; set; } + + [Required] + [Label("User Account")] + public Guid UserAccountID { get; set; } + + [Required] + public string Name { get; set; } + + [Required] + public string Value { get; set; } + + public bool Enabled { get; set; } + } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/TransmissionElements/Asset.cs b/src/Libraries/openXDA.Model/TransmissionElements/Asset.cs new file mode 100644 index 00000000..1d484d37 --- /dev/null +++ b/src/Libraries/openXDA.Model/TransmissionElements/Asset.cs @@ -0,0 +1,615 @@ +//****************************************************************************************************** +// Asset.cs - Gbtc +// +// Copyright © 2019, 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: +// ---------------------------------------------------------------------------------------------------- +// 12/12/2019 - C. Lackner +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Text.RegularExpressions; +using Gemstone.Collections.CollectionExtensions; +using Gemstone.Data; +using Gemstone.Data.DataExtensions; +using Gemstone.Data.Model; +using Gemstone.StringExtensions; +using Newtonsoft.Json; + +namespace openXDA.Model +{ + [PostRoles("Administrator, Transmission SME")] + [DeleteRoles("Administrator, Transmission SME")] + [PatchRoles("Administrator, Transmission SME")] + public class Asset + { + #region [ Members ] + + // Nested Types + private delegate List ConnectedChannelLookup(int parentID, int childID, string traversalSQL); + + private class TraversalContext + { + public AdoDataConnection Connection { get; } + public int LocationID { get; } + + public ConnectedChannelLookup ConnectedChannelLookup { get; } + public HashSet VisitedAssets { get; } + public HashSet ConnectedChannels { get; } + + public TraversalContext(AdoDataConnection connection, int locationID) + { + Connection = connection; + LocationID = locationID; + + ConnectedChannelLookup = GetConnectedChannelLookup(connection, locationID); + VisitedAssets = new HashSet(); + ConnectedChannels = new HashSet(); + } + } + + // Fields + private List m_assetLocations; + private List m_meterAssets; + private List m_directChannels; + private List m_connectedChannels; + private List m_connections; + + #endregion + + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + [Required] + public double VoltageKV { get; set; } + + [Required] + [StringLength(50)] + [DefaultSortOrder] + public string AssetKey { get; set; } + + public string Description { get; set; } + + [DefaultValue("")] + public string AssetName { get; set; } + + [Required] + public int AssetTypeID {get; set; } + + public bool Spare { get; set; } + + [JsonIgnore] + [NonRecordField] + internal LazyContext LazyContext { get; set; } = new LazyContext(); + + + [JsonIgnore] + [NonRecordField] + public List AssetLocations + { + get + { + return m_assetLocations ?? (m_assetLocations = QueryAssetLocations()); + } + set + { + m_assetLocations = value; + } + } + + [JsonIgnore] + [NonRecordField] + public List MeterAssets + { + get + { + return m_meterAssets ?? (m_meterAssets = QueryMeterAssets()); + } + set + { + m_meterAssets = value; + } + } + + [JsonIgnore] + [NonRecordField] + public List DirectChannels + { + get + { + return m_directChannels ?? (m_directChannels = QueryChannels()); + } + set + { + m_directChannels = value; + } + } + + [JsonIgnore] + [NonRecordField] + public List Connections + { + get + { + return m_connections ?? (m_connections = QueryConnections()); + } + set + { + m_connections = value; + } + } + + [JsonIgnore] + [NonRecordField] + public List ConnectedChannels + { + get + { + return m_connectedChannels ?? (m_connectedChannels = QueryConnectedChannels()); + } + set + { + m_connectedChannels = value; + } + } + + [JsonIgnore] + [NonRecordField] + public List ConnectedAssets => Connections? + .SelectMany(connection => new[] { connection.Parent, connection.Child }) + .Where(asset => asset.ID != ID) + .ToList(); + + [JsonIgnore] + [NonRecordField] + public Func ConnectionFactory + { + get + { + return LazyContext.ConnectionFactory; + } + set + { + LazyContext.ConnectionFactory = value; + } + } + + #endregion + + #region [ Methods ] + + public IEnumerable GetAssetLocations(AdoDataConnection connection) + { + if (connection is null) + return null; + + TableOperations assetLocationTable = new TableOperations(connection); + return assetLocationTable.QueryRecordsWhere("AssetID = {0}", ID); + } + + private List QueryAssetLocations() + { + List assetLocations; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + assetLocations = GetAssetLocations(connection)? + .Select(LazyContext.GetAssetLocation) + .ToList(); + } + + if (!(assetLocations is null)) + { + foreach (AssetLocation assetLocation in assetLocations) + { + assetLocation.Asset = this; + assetLocation.LazyContext = LazyContext; + } + } + else + return new List(); + + return assetLocations; + } + + private List QueryMeterAssets() + { + List meterAssets; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + meterAssets = GetMeterAssets(connection)? + .Select(LazyContext.GetMeterAsset) + .ToList(); + } + + if (!(meterAssets is null)) + { + foreach (MeterAsset meterAsset in meterAssets) + { + meterAsset.Asset = this; + meterAsset.LazyContext = LazyContext; + } + } + + return meterAssets; + } + + private List QueryChannels() + { + List channels; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + channels = GetChannels(connection)? + .Select(LazyContext.GetChannel) + .ToList(); + } + + if (!(channels is null)) + { + foreach (Channel channel in channels) + { + channel.Asset = this; + channel.LazyContext = LazyContext; + } + } + + return channels; + } + + private List QueryConnectedChannels() + { + List channels; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + channels = GetConnectedChannels(connection)? + .Select(LazyContext.GetChannel) + .ToList(); + } + + if (!(channels is null)) + { + foreach (Channel channel in channels) + { + channel.LazyContext = LazyContext; + } + } + + return channels; + } + + private List QueryConnections() + { + List connections; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + connections = GetConnections(connection)? + .Select(LazyContext.GetAssetConnection) + .ToList(); + } + + if (!(connections is null)) + { + foreach (AssetConnection connection in connections) + { + connection.LazyContext = LazyContext; + } + } + + return connections; + } + + public IEnumerable GetMeterAssets(AdoDataConnection connection) + { + if (connection is null) + return null; + + TableOperations meterAssetTable = new TableOperations(connection); + return meterAssetTable.QueryRecordsWhere("AssetID = {0}", ID); + } + + public IEnumerable GetChannels(AdoDataConnection connection) + { + if (connection is null) + return null; + + TableOperations channelTable = new TableOperations(connection); + return channelTable.QueryRecordsWhere("AssetID = {0}", ID); + } + + public IEnumerable GetConnections(AdoDataConnection connection) + { + if (connection is null) + return null; + + TableOperations channelTable = new TableOperations(connection); + return channelTable.QueryRecordsWhere("ParentID = {0} OR ChildID = {1}", ID, ID); + } + + // Logic for Channels across Asset Connections + public IEnumerable GetConnectedChannels(AdoDataConnection connection) + { + if (connection is null) + return null; + + return AssetLocations + .SelectMany(assetLocation => TraverseConnectedChannels(connection, assetLocation.LocationID, ID)) + .Distinct(new ChannelComparer()); + } + + private IEnumerable TraverseConnectedChannels(AdoDataConnection connection, int locationID, int assetID) + { + TraversalContext context = new TraversalContext(connection, locationID); + ConnectedChannelLookup channelLookup = context.ConnectedChannelLookup; + context.VisitedAssets.Add(assetID); + + using (DataTable connectionTable = RetrieveConnectedAssets(connection, locationID, assetID)) + { + foreach (DataRow traversalRow in connectionTable.AsEnumerable()) + { + int connectedAssetID = traversalRow.ConvertField("ConnectedAssetID"); + string jumpSQL = traversalRow.ConvertField("JumpSQL"); + + IEnumerable jumpChannels = channelLookup(connectedAssetID, assetID, jumpSQL) + .Where(channel => channel.AssetID == connectedAssetID); + + context.ConnectedChannels.UnionWith(jumpChannels); + } + + foreach (DataRow traversalRow in connectionTable.AsEnumerable()) + { + int connectedAssetID = traversalRow.ConvertField("ConnectedAssetID"); + string passthroughSQL = traversalRow.ConvertField("PassthroughSQL"); + + List pathChannels = channelLookup(connectedAssetID, assetID, passthroughSQL) + .Where(channel => channel.AssetID != assetID) + .Except(context.ConnectedChannels) + .ToList(); + + if (pathChannels.Count == 0) + continue; + + TraverseConnectedChannels(context, pathChannels, connectedAssetID); + } + } + + return context.ConnectedChannels; + } + + private void TraverseConnectedChannels(TraversalContext context, List pathChannels, int visitedAssetID) + { + AdoDataConnection connection = context.Connection; + ConnectedChannelLookup channelLookup = context.ConnectedChannelLookup; + int locationID = context.LocationID; + + context.VisitedAssets.Add(visitedAssetID); + + using (DataTable connectionTable = RetrieveConnectedAssets(connection, locationID, visitedAssetID)) + { + foreach (DataRow traversalRow in connectionTable.AsEnumerable()) + { + int connectedAssetID = traversalRow.ConvertField("ConnectedAssetID"); + + if (context.VisitedAssets.Contains(connectedAssetID)) + continue; + + string jumpSQL = traversalRow.ConvertField("JumpSQL"); + + IEnumerable jumpChannels = channelLookup(connectedAssetID, visitedAssetID, jumpSQL) + .Where(channel => channel.AssetID == connectedAssetID) + .Intersect(pathChannels); + + context.ConnectedChannels.UnionWith(jumpChannels); + } + + HashSet filteredPathChannels = new HashSet(pathChannels); + filteredPathChannels.ExceptWith(context.ConnectedChannels); + + foreach (DataRow traversalRow in connectionTable.AsEnumerable()) + { + if (filteredPathChannels.Count == 0) + break; + + int connectedAssetID = traversalRow.ConvertField("ConnectedAssetID"); + + if (context.VisitedAssets.Contains(connectedAssetID)) + continue; + + string passthroughSQL = traversalRow.ConvertField("PassthroughSQL"); + + List passthroughChannels = channelLookup(connectedAssetID, visitedAssetID, passthroughSQL) + .Intersect(filteredPathChannels) + .ToList(); + + if (passthroughChannels.Count == 0) + continue; + + int connectedCount = context.ConnectedChannels.Count; + TraverseConnectedChannels(context, passthroughChannels, connectedAssetID); + + if (context.ConnectedChannels.Count != connectedCount) + filteredPathChannels.ExceptWith(context.ConnectedChannels); + } + } + + context.VisitedAssets.Remove(visitedAssetID); + } + + private DataTable RetrieveConnectedAssets(AdoDataConnection connection, int locationID, int visitedAssetID) + { + const string TraversalQueryFormat = + "SELECT DISTINCT " + + " ConnectedAsset.ID ConnectedAssetID, " + + " AssetRelationshipType.JumpConnection JumpSQL, " + + " AssetRelationshipType.PassThrough PassthroughSQL " + + "FROM " + + " Location JOIN " + + " Asset VisitedAsset ON " + + " Location.ID = {0} AND " + + " VisitedAsset.ID = {1} JOIN " + + " AssetConnection ON VisitedAsset.ID IN (AssetConnection.ParentID, AssetConnection.ChildID) JOIN " + + " Asset ConnectedAsset ON " + + " ConnectedAsset.ID IN (AssetConnection.ParentID, AssetConnection.ChildID) AND " + + " ConnectedAsset.ID <> VisitedAsset.ID JOIN " + + " AssetRelationshipType ON AssetConnection.AssetRelationshipTypeID = AssetRelationshipType.ID JOIN " + + " AssetLocation ON " + + " AssetLocation.AssetID = ConnectedAsset.ID AND " + + " AssetLocation.LocationID = Location.ID"; + + return connection.RetrieveData(TraversalQueryFormat, locationID, visitedAssetID); + } + + // Logic to find distance between two Assets + public int DistanceToAsset(int assetID) + { + int distance = 0; + HashSet visited = new HashSet(); + List next = new List() { this }; + + while (next.Count > 0) + { + if (next.Any(n => n.ID == assetID)) + return distance; + + foreach (Asset n in next) + visited.Add(n.ID); + + next = next + .SelectMany(n => n.ConnectedAssets) + .DistinctBy(n => n.ID) + .Where(n => !visited.Contains(n.ID)) + .ToList(); + + distance++; + } + + return -1; + } + + public T QueryAs(AdoDataConnection connection = null) where T : Asset, new() + { + if (this is T typedAsset) + return typedAsset; + + if (connection is null && ConnectionFactory is null) + throw new ArgumentNullException(nameof(connection)); + + Lazy lazyConnection = new Lazy(ConnectionFactory); + + try + { + TableOperations table = new TableOperations(connection ?? lazyConnection.Value); + return table.QueryRecordWhere("ID = {0}", ID); + } + finally + { + if (lazyConnection.IsValueCreated) + lazyConnection.Value.Dispose(); + } + } + + [Obsolete("Replaced by GetChannels")] + public IEnumerable GetChannel(AdoDataConnection connection) => GetChannels(connection); + + [Obsolete("Replaced by GetConnections")] + public IEnumerable GetConnection(AdoDataConnection connection) => GetConnections(connection); + + [Obsolete("Replaced by GetConnectedChannels")] + public IEnumerable GetConnectedChannel(AdoDataConnection connection) => GetConnectedChannels(connection); + + #endregion + + #region [ Static ] + + // Static Methods + private static ConnectedChannelLookup GetConnectedChannelLookup(AdoDataConnection connection, int locationID) + { + const string ChannelQueryFormat = + "SELECT SourceChannel.* " + + "FROM " + + " Channel SourceChannel JOIN " + + " Meter ON " + + " SourceChannel.MeterID = Meter.ID AND " + + " Meter.LocationID = {{0}} JOIN " + + " Asset ParentAsset ON ParentAsset.ID = {{1}} JOIN " + + " Asset ChildAsset ON ChildAsset.ID = {{2}} CROSS APPLY " + + " ({TraversalSQL}) Traversal(Traverse) " + + "WHERE Traversal.Traverse <> 0"; + + Dictionary channelLookup = new Dictionary(); + + var connectedChannelLookup = Enumerable + .Empty>() + .ToDictionary(_ => new { ParentID = 0, ChildID = 0, TraversalSQL = "" }); + + return (parentID, childID, traversalSQL) => + { + var key = new { ParentID = parentID, ChildID = childID, TraversalSQL = traversalSQL }; + return connectedChannelLookup.GetOrAdd(key, _ => RetrieveConnectedChannels(parentID, childID, traversalSQL)); + }; + + List RetrieveConnectedChannels(int parentID, int childID, string traversalSQL) + { + TableOperations channelTable = new TableOperations(connection); + + // lang=regex + const string Pattern = @"\{(?:parentid|childid|channelid)\}"; + string replacedSQL = Regex.Replace(traversalSQL, Pattern, ReplaceFormatParameter, RegexOptions.IgnoreCase); + + string channelQuery = ChannelQueryFormat + .Interpolate(new { TraversalSQL = replacedSQL }); + + return RetrieveRows(channelQuery, locationID, parentID, childID) + .Select(channelTable.LoadRecord) + .Select(LookUpChannel) + .ToList(); + } + + Channel LookUpChannel(Channel channel) => + channelLookup.GetOrAdd(channel.ID, _ => channel); + + string ReplaceFormatParameter(Match match) + { + switch (match.Value.ToLowerInvariant()) + { + case "{parentid}": return "ParentAsset.ID"; + case "{childid}": return "ChildAsset.ID"; + case "{channelid}": return "SourceChannel.ID"; + default: return match.Value; + } + } + + IEnumerable RetrieveRows(string query, params object[] args) + { + using (DataTable table = connection.RetrieveData(query, args)) + { + foreach (DataRow row in table.Rows) + yield return row; + } + } + } + + #endregion + } +} diff --git a/src/Libraries/openXDA.Model/TransmissionElements/BreakerOperation.cs b/src/Libraries/openXDA.Model/TransmissionElements/BreakerOperation.cs new file mode 100644 index 00000000..3be64ebe --- /dev/null +++ b/src/Libraries/openXDA.Model/TransmissionElements/BreakerOperation.cs @@ -0,0 +1,107 @@ +//****************************************************************************************************** +// BreakerOperation.cs - Gbtc +// +// Copyright © 2017, 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/29/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System.Data; +using Gemstone.Data; +using Gemstone.Data.Model; + +namespace openXDA.Model +{ + public class BreakerOperation + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int EventID { get; set; } + + public int PhaseID { get; set; } + + public int BreakerOperationTypeID { get; set; } + + public string BreakerNumber { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime TripCoilEnergized { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime StatusBitSet { get; set; } + + public bool StatusBitChatter { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime APhaseCleared { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime BPhaseCleared { get; set; } + + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime CPhaseCleared { get; set; } + + public double BreakerTiming { get; set; } + + public double StatusTiming { get; set; } + + public double APhaseBreakerTiming { get; set; } + + public double BPhaseBreakerTiming { get; set; } + + public double CPhaseBreakerTiming { get; set; } + + public bool DcOffsetDetected { get; set; } + + public double BreakerSpeed { get; set; } + + public string UpdatedBy { get; set; } + } + + [TableName("BreakerOperation")] + public class BreakersForDay : BreakerOperation { } + + public class BreakerView + { + [PrimaryKey(true)] + public int ID { get; set; } + + public int MeterID { get; set; } + + public int EventID { get; set; } + + public string EventType { get; set; } + + public string Energized { get; set; } + + public int BreakerNumber { get; set; } + + public string LineName { get; set; } + + public string PhaseName { get; set; } + + public double Timing { get; set; } + + public int Speed { get; set; } + + public string OperationType { get; set; } + + public string UpdatedBy { get; set; } + } +} \ No newline at end of file diff --git a/src/Libraries/openXDA.Model/TransmissionElements/SourceImpedance.cs b/src/Libraries/openXDA.Model/TransmissionElements/SourceImpedance.cs new file mode 100644 index 00000000..998f1d16 --- /dev/null +++ b/src/Libraries/openXDA.Model/TransmissionElements/SourceImpedance.cs @@ -0,0 +1,114 @@ +//****************************************************************************************************** +// SourceImpedance.cs - Gbtc +// +// Copyright © 2017, 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: +// ---------------------------------------------------------------------------------------------------- +// 06/19/2017 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using Gemstone.Data; +using Gemstone.Data.Model; +using Newtonsoft.Json; + +namespace openXDA.Model +{ + [TableName("SourceImpedance")] + [PostRoles("Administrator, Transmission SME")] + [PatchRoles("Administrator, Transmission SME")] + [DeleteRoles("Administrator, Transmission SME")] + public class SourceImpedance + { + #region [ Members ] + + // Fields + private AssetLocation m_assetLocation; + + #endregion + + #region [ Properties ] + + [PrimaryKey(true)] + public int ID { get; set; } + + [ParentKey(typeof(AssetLocation))] + public int AssetLocationID { get; set; } + + public double RSrc { get; set; } + + public double XSrc { get; set; } + + [JsonIgnore] + [NonRecordField] + public AssetLocation AssetLocation + { + get + { + if (m_assetLocation is null) + m_assetLocation = LazyContext.GetAssetLocation(AssetLocationID); + + if (m_assetLocation is null) + m_assetLocation = QueryAssetLocation(); + + return m_assetLocation; + } + set => m_assetLocation = value; + } + + [JsonIgnore] + [NonRecordField] + public Func ConnectionFactory + { + get => LazyContext.ConnectionFactory; + set => LazyContext.ConnectionFactory = value; + } + + [JsonIgnore] + [NonRecordField] + internal LazyContext LazyContext { get; set; } = new LazyContext(); + + #endregion + + #region [ Methods ] + + public AssetLocation GetAssetLocation(AdoDataConnection connection) + { + if ((object)connection == null) + return null; + + TableOperations assetLocationTable = new TableOperations(connection); + return assetLocationTable.QueryRecordWhere("ID = {0}", AssetLocationID); + } + + private AssetLocation QueryAssetLocation() + { + AssetLocation assetLocation; + + using (AdoDataConnection connection = ConnectionFactory?.Invoke()) + { + assetLocation = GetAssetLocation(connection); + } + + if ((object)assetLocation != null) + assetLocation.LazyContext = LazyContext; + + return LazyContext.GetAssetLocation(assetLocation); + } + + #endregion + } +} diff --git a/src/Libraries/openXDA.Model/openXDA.Model.csproj b/src/Libraries/openXDA.Model/openXDA.Model.csproj new file mode 100644 index 00000000..68b24c0c --- /dev/null +++ b/src/Libraries/openXDA.Model/openXDA.Model.csproj @@ -0,0 +1,15 @@ + + + + net9.0 + enable + enable + + + + + + + + + diff --git a/src/OpenSEE.sln b/src/OpenSEE.sln index 1423d43c..41c023a7 100644 --- a/src/OpenSEE.sln +++ b/src/OpenSEE.sln @@ -10,6 +10,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution OpenSEE\.eslintrc = OpenSEE\.eslintrc EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FaultAlgorithms", "Libraries\FaultAlgorithms\FaultAlgorithms.csproj", "{79E70E44-FB78-B280-97D7-1650186161DF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FaultData", "Libraries\FaultData\FaultData.csproj", "{1C77C616-BE00-A5A0-8109-C0D9F7C0202E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "openXDA.Model", "Libraries\openXDA.Model\openXDA.Model.csproj", "{F463A000-041D-CC7D-0954-3942A5D4A946}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PQDS", "Libraries\PQDS\PQDS.csproj", "{C6E64BA2-DCA7-4A34-973A-2306A1F9EFFC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -20,10 +30,32 @@ Global {845F68F7-4094-4FE6-95E3-1B113BBFAD3F}.Debug|Any CPU.Build.0 = Debug|Any CPU {845F68F7-4094-4FE6-95E3-1B113BBFAD3F}.Release|Any CPU.ActiveCfg = Release|Any CPU {845F68F7-4094-4FE6-95E3-1B113BBFAD3F}.Release|Any CPU.Build.0 = Release|Any CPU + {79E70E44-FB78-B280-97D7-1650186161DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79E70E44-FB78-B280-97D7-1650186161DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79E70E44-FB78-B280-97D7-1650186161DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79E70E44-FB78-B280-97D7-1650186161DF}.Release|Any CPU.Build.0 = Release|Any CPU + {1C77C616-BE00-A5A0-8109-C0D9F7C0202E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C77C616-BE00-A5A0-8109-C0D9F7C0202E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C77C616-BE00-A5A0-8109-C0D9F7C0202E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C77C616-BE00-A5A0-8109-C0D9F7C0202E}.Release|Any CPU.Build.0 = Release|Any CPU + {F463A000-041D-CC7D-0954-3942A5D4A946}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F463A000-041D-CC7D-0954-3942A5D4A946}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F463A000-041D-CC7D-0954-3942A5D4A946}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F463A000-041D-CC7D-0954-3942A5D4A946}.Release|Any CPU.Build.0 = Release|Any CPU + {C6E64BA2-DCA7-4A34-973A-2306A1F9EFFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6E64BA2-DCA7-4A34-973A-2306A1F9EFFC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6E64BA2-DCA7-4A34-973A-2306A1F9EFFC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6E64BA2-DCA7-4A34-973A-2306A1F9EFFC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {79E70E44-FB78-B280-97D7-1650186161DF} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {1C77C616-BE00-A5A0-8109-C0D9F7C0202E} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {F463A000-041D-CC7D-0954-3942A5D4A946} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {C6E64BA2-DCA7-4A34-973A-2306A1F9EFFC} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3E81769A-8E91-4DE2-AD77-438C680437A5} EndGlobalSection diff --git a/src/OpenSEE/App_Start/RouteConfig.cs b/src/OpenSEE/App_Start/RouteConfig.cs deleted file mode 100644 index 8efe6492..00000000 --- a/src/OpenSEE/App_Start/RouteConfig.cs +++ /dev/null @@ -1,70 +0,0 @@ -//****************************************************************************************************** -// RouteConfig.cs - Gbtc -// -// Copyright © 2020, 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: -// ---------------------------------------------------------------------------------------------------- -// 02/19/2020 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; - -namespace OpenSEE -{ - public class RouteConfig - { - public static void RegisterRoutes(RouteCollection routes) - { - routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); - - routes.MapRoute( - name: "LoginRoute", - url: "Login", - defaults: new { controller = "Login", action = "Index" } - ); - - routes.MapRoute( - name: "AuthTestRoute", - url: "AuthTest", - defaults: new { controller = "Login", action = "AuthTest" } - ); - - routes.MapRoute( - name: "LogoutRoute", - url: "Logout", - defaults: new { controller = "Login", action = "Logout" } - ); - - routes.MapRoute( - name: "UserInfoRoute", - url: "UserInfo", - defaults: new { controller = "Login", action = "UserInfo" } - ); - - routes.MapRoute( - name: "Default", - url: "{controller}/{action}/{id}", - defaults: new { controller = "Home", action = "Home", id = UrlParameter.Optional } - ); - } - } -} diff --git a/src/OpenSEE/CSVDownload.ashx b/src/OpenSEE/CSVDownload.ashx deleted file mode 100644 index fb385e0f..00000000 --- a/src/OpenSEE/CSVDownload.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="CSVDownload.ashx.cs" Class="OpenSEE.CSVDownload" %> diff --git a/src/OpenSEE/Common.cs b/src/OpenSEE/Common.cs deleted file mode 100644 index 8742a38c..00000000 --- a/src/OpenSEE/Common.cs +++ /dev/null @@ -1,79 +0,0 @@ -//****************************************************************************************************** -// Common.cs - Gbtc -// -// Copyright © 2023, 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: -// ---------------------------------------------------------------------------------------------------- -// 02/26/2023 - J. Ritchie Carroll -// Generated original version of source code. -// -//****************************************************************************************************** - -using System.IO; -using GSF; -using GSF.Configuration; -using GSF.IO; -using GSF.Reflection; -using GSF.Web.Security; - -namespace OpenSEE; - -public static class Common -{ - private static string s_applicationName; - private static string s_anonymousResourceExpression; - - public static string ApplicationName => s_applicationName ??= GetApplicationName(); - - public static string AnonymousResourceExpression => s_anonymousResourceExpression ??= GetAnonymousResourceExpression(); - - public static bool LogEnabled => GetLogEnabled(); - - public static string LogPath => GetLogPath(); - - public static int MaxLogFiles => GetMaxLogFiles(); - - private static string GetApplicationName() => - // Try database configured application name (if loaded yet) - MvcApplication.DefaultModel.Global.ApplicationName ?? - // Fall back on setting defined in web.config - GetSettingValue("SecurityProvider", "ApplicationName", "GSF Authentication"); - - private static string GetAnonymousResourceExpression() => - GetSettingValue("SystemSettings", "AnonymousResourceExpression", AuthenticationOptions.DefaultAnonymousResourceExpression); - - private static bool GetLogEnabled() => - GetSettingValue("SystemSettings", "LogEnabled", AssemblyInfo.ExecutingAssembly.Debuggable.ToString()).ParseBoolean(); - - private static string GetLogPath() => - GetSettingValue("SystemSettings", "LogPath", string.Format("{0}{1}Logs{1}", FilePath.GetAbsolutePath(""), Path.DirectorySeparatorChar)); - - private static int GetMaxLogFiles() => - int.TryParse(GetSettingValue("SystemSettings", "MaxLogFiles", "300"), out int maxLogFiles) ? maxLogFiles : 300; - - private static string GetSettingValue(string section, string keyName, string defaultValue) - { - try - { - ConfigurationFile config = ConfigurationFile.Current; - CategorizedSettingsElementCollection settings = config.Settings[section]; - return settings[keyName, true].ValueAs(defaultValue); - } - catch - { - return defaultValue; - } - } -} \ No newline at end of file diff --git a/src/OpenSEE/Content/FaultSpecifics.css b/src/OpenSEE/Content/FaultSpecifics.css deleted file mode 100644 index cc9d3137..00000000 --- a/src/OpenSEE/Content/FaultSpecifics.css +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************************************** -// FaultSpecifics.css - Gbtc -// -// Copyright © 2014, 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 Eclipse Public License -v 1.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a copy of the License at: -// -// http://www.opensource.org/licenses/eclipse-1.0.php -// -// 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: -// ---------------------------------------------------------------------------------------------------- -// 04/14/2015 - Jeff Walker -// Generated original version of source code. -// -//******************************************************************************************************/ - - body { - margin: 0; - padding: 0; - height: 100%; - width: 100%; - overflow: hidden; - -webkit-user-select: none; - -moz-user-select: -moz-none; - -ms-user-select: none; - user-select: none; - font-size: 12px; - font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; - } - diff --git a/src/OpenSEE/Controllers/AnalyticController.cs b/src/OpenSEE/Controllers/AnalyticController.cs index b1a9cadf..c78ba366 100644 --- a/src/OpenSEE/Controllers/AnalyticController.cs +++ b/src/OpenSEE/Controllers/AnalyticController.cs @@ -29,21 +29,22 @@ using System.Numerics; using System.Runtime.Caching; using System.Threading.Tasks; -using System.Web.Http; -using FaultData.DataAnalysis; -using GSF; -using GSF.Console; -using GSF.Data; -using GSF.Data.Model; -using GSF.NumericalAnalysis; -using GSF.Web; +using Gemstone.Data; +using Gemstone.Web; using MathNet.Numerics.IntegralTransforms; using OpenSEE.Model; +using Microsoft.AspNetCore.Mvc; +using Gemstone.Data.Model; +using Gemstone.Configuration; using openXDA.Model; +using FaultData.DataAnalysis; +using Microsoft.Extensions.Primitives; +using Gemstone.Data.DataExtensions; +using Gemstone.Numeric.Analysis; namespace OpenSEE { - [RoutePrefix("api/Analytic")] + [Route("api/Analytic")] public class AnalyticController : OpenSEEBaseController { #region [ Members ] @@ -65,7 +66,7 @@ static AnalyticController() { s_memoryCache = new MemoryCache("Analytics"); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { m_cacheSlidingExpiration = connection.ExecuteScalar("SELECT Value FROM [OpenSee.Setting] WHERE Name = 'SlidingCacheExpiration'") ?? 2.0; } @@ -415,15 +416,13 @@ private class SequenceComponents [Route("GetFaultDistanceData"),HttpGet] public JsonReturn GetFaultDistanceData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - - int eventId = int.Parse(query["eventId"]); + int eventId = int.Parse(Request.Query["eventId"].ToString()); Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); Asset asset = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.AssetID); - meter.ConnectionFactory = () => new AdoDataConnection(connection.Connection, typeof(SqlDataAdapter), false); + meter.ConnectionFactory = () => new AdoDataConnection(Settings.Default); List returnList = new List(); @@ -444,7 +443,7 @@ public JsonReturn GetFaultDistanceData() private D3Series QueryFaultDistanceData(int faultCurveID, Meter meter, Asset asset, int evtID) { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { FaultCurve faultCurve = new TableOperations(connection).QueryRecordWhere("ID = {0}", faultCurveID); DataGroup dataGroup = new DataGroup(); @@ -484,21 +483,18 @@ private D3Series QueryFaultDistanceData(int faultCurveID, Meter meter, Asset ass [Route("GetFirstDerivativeData"), HttpGet] public async Task GetFirstDerivativeData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); + int eventId = int.Parse(Request.Query["eventId"].ToString()); List returnList = new List(); - DataTable table = connection.RetrieveData("SELECT ID, StartTime FROM Event WHERE ID = {0}", evt.ID); + DataTable table = connection.RetrieveData("SELECT ID, StartTime FROM Event WHERE ID = {0}", eventId); foreach (DataRow row in table.Rows) { int eventID = row.ConvertField("ID"); - DataGroup dataGroup = await QueryDataGroupAsync(eventId, meter); - VICycleDataGroup viCycleDataGroup = await QueryVICycleDataGroupAsync(eventID, meter); + // ToDo: this logic seems wrong, we look this up every time but it should be the same result, same eventId, unlike the line after... + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); + VICycleDataGroup viCycleDataGroup = await QueryVICycleDataGroupAsync(eventID, connection); returnList = returnList.Concat(GetFirstDerivativeLookup(dataGroup, viCycleDataGroup)).ToList(); } @@ -600,16 +596,11 @@ public static D3Series GetFirstDerivativeSeries(DataSeries dataSeries, string la [Route("GetImpedanceData"), HttpGet] public async Task GetImpedanceData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); + int eventId = int.Parse(Request.Query["eventId"].ToString()); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - VICycleDataGroup viCycleDataGroup = await QueryVICycleDataGroupAsync(evt.ID, meter); + VICycleDataGroup viCycleDataGroup = await QueryVICycleDataGroupAsync(eventId, connection); List returnList = GetImpedanceLookup(viCycleDataGroup); JsonReturn returnDict = new JsonReturn(); @@ -790,15 +781,10 @@ private IEnumerable CalculateImpedance(CycleDataGroup Voltage, CycleDat [Route("GetRemoveCurrentData"), HttpGet] public async Task GetRemoveCurrentData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetRemoveCurrentLookup(dataGroup); JsonReturn returnDict = new JsonReturn(); @@ -945,15 +931,10 @@ public List GetRemoveCurrentLookup(DataGroup dataGroup) [Route("GetI2tData"), HttpGet] public async Task GetI2tData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetI2tLookup(dataGroup); JsonReturn returnDict = new JsonReturn(); @@ -1012,16 +993,10 @@ private IEnumerable ComputeI2T(IEnumerable current, double [Route("GetPowerData"), HttpGet] public async Task GetPowerData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - VICycleDataGroup vICycleDataGroup = await QueryVICycleDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + VICycleDataGroup vICycleDataGroup = await QueryVICycleDataGroupAsync(eventId, connection); List returnList = GetPowerLookup(vICycleDataGroup); JsonReturn returnDict = new JsonReturn(); @@ -1309,15 +1284,10 @@ public List GetPowerLookup(VICycleDataGroup vICycleDataGroup) [Route("GetMissingVoltageData"), HttpGet] public async Task GetMissingVoltageData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetMissingVoltageLookup(dataGroup); JsonReturn returnDict = new JsonReturn(); @@ -1390,15 +1360,10 @@ public List GetMissingVoltageLookup(DataGroup dataGroup) [Route("GetClippedWaveformsData"), HttpGet] public async Task GetClippedWaveformsData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetClippedWaveformsLookup(dataGroup); JsonReturn returnDict = new JsonReturn(); @@ -1532,17 +1497,11 @@ private static D3Series GenerateFixedWaveform(DataSeries dataSeries, string labe [Route("GetLowPassFilterData"), HttpGet] public async Task GetLowPassFilterData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int filterOrder = int.Parse(query["filter"]); - int eventId = int.Parse(query["eventId"]); - - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + int filterOrder = int.Parse(Request.Query["filter"].ToString()); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetLowPassFilterLookup(dataGroup, filterOrder); JsonReturn returnDict = new JsonReturn(); @@ -1607,17 +1566,11 @@ public D3Series FilteredPassSignal(Filter Filt, DataSeries Data) [Route("GetHighPassFilterData"), HttpGet] public async Task GetHighPassFilterData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int filterOrder = int.Parse(query["filter"]); - int eventId = int.Parse(query["eventId"]); - - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + int filterOrder = int.Parse(Request.Query["filter"].ToString()); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetHighPassFilterLookup(dataGroup, filterOrder); JsonReturn returnDict = new JsonReturn(); @@ -1660,15 +1613,10 @@ public List GetHighPassFilterLookup(DataGroup dataGroup, int order) [Route("GetOverlappingWaveformData"), HttpGet] public async Task GetOverlappingWaveformData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetOverlappingWaveformLookup(dataGroup); JsonReturn returnDict = new JsonReturn(); @@ -1756,16 +1704,10 @@ private D3Series GenerateOverlappingWaveform(DataSeries dataSeries) [Route("GetRapidVoltageChangeData"), HttpGet] public async Task GetRapidVoltageChangeData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - VICycleDataGroup vICycleDataGroup = await QueryVICycleDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + VICycleDataGroup vICycleDataGroup = await QueryVICycleDataGroupAsync(eventId, connection); List returnList = GetRapidVoltageChangeLookup(vICycleDataGroup); JsonReturn returnDict = new JsonReturn(); @@ -1838,16 +1780,10 @@ private D3Series GetRapidVoltageChangeFlotSeries(DataSeries dataSeries) [Route("GetSymmetricalComponentsData"), HttpGet] public async Task GetSymmetricalComponentsData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - VICycleDataGroup vICycleDataGroup = await QueryVICycleDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + VICycleDataGroup vICycleDataGroup = await QueryVICycleDataGroupAsync(eventId, connection); List returnList = GetSymmetricalComponentsLookup(vICycleDataGroup); JsonReturn returnDict = new JsonReturn(); @@ -2023,16 +1959,10 @@ private SequenceComponents CalculateSequenceComponents(Complex an, Complex bn, C [Route("GetUnbalanceData"), HttpGet] public async Task GetUnbalanceData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - VICycleDataGroup vICycleDataGroup = await QueryVICycleDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + VICycleDataGroup vICycleDataGroup = await QueryVICycleDataGroupAsync(eventId, connection); List returnList = GetUnbalanceLookup(vICycleDataGroup); JsonReturn returnDict = new JsonReturn(); @@ -2174,17 +2104,11 @@ public List GetUnbalanceLookup(VICycleDataGroup vICycleDataGroup) [Route("GetRectifierData"), HttpGet] public async Task GetRectifierData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - double TRC = double.Parse(query["Trc"]); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - double systemFrequency = connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'SystemFrequency'") ?? 60.0; - VIDataGroup dataGroup = await QueryVIDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + double TRC = double.Parse(Request.Query["Trc"].ToString()); + VIDataGroup dataGroup = await QueryVIDataGroupAsync(eventId, connection); List returnList = GetRectifierLookup(dataGroup, TRC); JsonReturn returnDict = new JsonReturn(); @@ -2271,15 +2195,10 @@ public List GetRectifierLookup(VIDataGroup dataGroup, double RC) [Route("GetFrequencyData"), HttpGet] public async Task GetFrequencyData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - VIDataGroup viDataGroup = await QueryVIDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + VIDataGroup viDataGroup = await QueryVIDataGroupAsync(eventId, connection); List returnList = GetFrequencyLookup(viDataGroup); JsonReturn returnDict = new JsonReturn(); @@ -2440,16 +2359,14 @@ private D3Series MedianFilt(D3Series input) [Route("GetTHDData"), HttpGet] public async Task GetTHDData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - int forceFullRes = int.Parse(query.ContainsKey("fullRes") ? query["fullRes"] : "0"); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + int forceFullRes = 0; + if (Request.Query.TryGetValue("fullRes", out StringValues fullRes)) + forceFullRes = int.Parse(fullRes.ToString()); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetTHDLookup(dataGroup, forceFullRes==1); JsonReturn returnDict = new JsonReturn(); @@ -2542,18 +2459,15 @@ private D3Series GenerateTHD( DataSeries dataSeries, bool fullRes) [Route("GetSpecifiedHarmonicData"), HttpGet] public async Task GetSpecifiedHarmonicData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - int forceFullRes = int.Parse(query.ContainsKey("fullRes") ? query["fullRes"] : "0"); - - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - int specifiedHarmonic = int.Parse(query["specifiedHarmonic"]); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + int forceFullRes = 0; + if (Request.Query.TryGetValue("fullRes", out StringValues fullRes)) + forceFullRes = int.Parse(fullRes.ToString()); + int specifiedHarmonic = int.Parse(Request.Query["specifiedHarmonic"].ToString()); - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetSpecifiedHarmonicLookup(dataGroup, specifiedHarmonic, forceFullRes==1); JsonReturn returnDict = new JsonReturn(); @@ -2667,17 +2581,11 @@ private static IEnumerable GenerateSpecifiedHarmonic( DataSeries dataS [Route("GetBreakerRestrikeData"), HttpGet] public async Task GetBreakerRestrikeData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - - DataGroup dataGroup = await QueryDataGroupAsync(eventId, meter); - List returnList = GetBreakerRestrikeData(evt.ID, dataGroup); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); + List returnList = GetBreakerRestrikeData(eventId, dataGroup); JsonReturn returnDict = new JsonReturn(); returnDict.Data = returnList; @@ -2687,7 +2595,7 @@ public async Task GetBreakerRestrikeData() private List GetBreakerRestrikeData(int eventID, DataGroup dataGroup) { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { List currents; List voltages; @@ -2768,18 +2676,23 @@ private List GetBreakerRestrikeData(int eventID, DataGroup dataGroup) [Route("GetFFTData"), HttpGet] public async Task GetFFTData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - int cycles = query.ContainsKey("cycles") ? int.Parse(query["cycles"]) : 1; + int eventId = int.Parse(Request.Query["eventId"].ToString()); + int cycles = 1; + if (Request.Query.TryGetValue("cycles", out StringValues cycleString)) + cycles = int.Parse(cycleString.ToString()); - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); + double startTime; + if (Request.Query.TryGetValue("startDate", out StringValues start)) + startTime = double.Parse(start.ToString()); + else + { + Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); + startTime = evt.StartTime.Subtract(m_epoch).TotalMilliseconds; + } - double startTime = query.ContainsKey("startDate") ? double.Parse(query["startDate"]) : evt.StartTime.Subtract(m_epoch).TotalMilliseconds; - DataGroup dataGroup = await QueryDataGroupAsync(eventId, meter); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetFFTLookup(dataGroup, startTime, cycles); JsonReturn returnDict = new JsonReturn(); @@ -2792,7 +2705,7 @@ public List GetFFTLookup(DataGroup dataGroup, double startTime, int cy { int maxHarmonic; - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) maxHarmonic = int.Parse(connection.ExecuteScalar("SELECT Value FROM [OpenSee.Setting] WHERE Name = 'maxFFTHarmonic'") ?? "50"); List dataLookup = new List(); diff --git a/src/OpenSEE/CSVDownload.ashx.cs b/src/OpenSEE/Controllers/CSVController.cs similarity index 53% rename from src/OpenSEE/CSVDownload.ashx.cs rename to src/OpenSEE/Controllers/CSVController.cs index 9f4f7d14..ca0a4fc1 100644 --- a/src/OpenSEE/CSVDownload.ashx.cs +++ b/src/OpenSEE/Controllers/CSVController.cs @@ -1,5 +1,5 @@ //****************************************************************************************************** -// OpenSEECSVDownload.ashx.cs - Gbtc +// CSVController.cs - Gbtc // // Copyright © 2018, Grid Protection Alliance. All Rights Reserved. // @@ -18,165 +18,111 @@ // ---------------------------------------------------------------------------------------------------- // 11/06/2018 - Billy Ernest // Generated original version of source code. +// 02/05/2026 - Gabriel Santos +// Refactored code to be in controller format for netcore upgrade. // //****************************************************************************************************** using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.Data; using System.IO; using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using System.Web; using FaultData.DataAnalysis; -using GSF.Collections; -using GSF.Data; -using GSF.Data.Model; -using GSF.Threading; +using Gemstone.Configuration; +using Gemstone.Data; +using Gemstone.Data.Model; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using OpenSEE.Model; using openXDA.Model; -using CancellationToken = System.Threading.CancellationToken; namespace OpenSEE { /// - /// Summary description for OpenSEECSVDownload + /// An MVC controller for downloading /// - public class CSVDownload : IHttpHandler + [Route("api/CSV")] + public class CSVController : Controller { - #region [ Members ] - // Fields private DateTime m_epoch = new DateTime(1970, 1, 1); - // Nested Types - private class HttpResponseCancellationToken : CompatibleCancellationToken - { - private readonly HttpResponse m_reponse; - - public HttpResponseCancellationToken(HttpResponse response) : base(CancellationToken.None) - { - m_reponse = response; - } - - public override bool IsCancelled => !m_reponse.IsClientConnected; - } - - const string CsvContentType = "text/csv"; - - #endregion - #region [ Properties ] - - /// - /// Gets a value indicating whether another request can use the instance. - /// - /// - /// true if the instance is reusable; otherwise, false. - /// - public bool IsReusable => false; + #region [ Methods ] /// - /// Determines if client cache should be enabled for rendered handler content. + /// This is just with slightly different dispose logic. /// /// - /// If rendered handler content does not change often, the server and client will use the - /// to determine if the client needs to refresh the content. + /// MVC owns the so we shouldn't close it. /// - public bool UseClientCache => false; - - public string Filename { get; private set; } - #endregion - - #region [ Methods ] - - public void ProcessRequest(HttpContext context) + private class NoCloseStreamWriter : StreamWriter { - HttpResponse response = HttpContext.Current.Response; - HttpResponseCancellationToken cancellationToken = new HttpResponseCancellationToken(response); - NameValueCollection requestParameters = context.Request.QueryString; + public NoCloseStreamWriter(Stream stream) : base(stream) { } - try + protected override void Dispose(bool disposing) { - Filename = (requestParameters["Meter"] == null? "" : (requestParameters["Meter"] + "_")) + (requestParameters["EventType"] == null? "" : requestParameters["EventType"] + "_") + "Event_" + requestParameters["eventID"] + ".csv"; - if (requestParameters["type"] == "pqds") - Filename = "PQDS_" + Filename; - response.ClearContent(); - response.Clear(); - response.AddHeader("Content-Type", CsvContentType); - response.AddHeader("Content-Disposition", "attachment;filename=" + Filename); - response.BufferOutput = true; - - WriteTableToStream(requestParameters, response.OutputStream, response.Flush, cancellationToken); - } - catch (Exception e) - { - LogExceptionHandler?.Invoke(e); - throw; - } - finally - { - response.End(); + base.Dispose(false); } } - public Task ProcessRequestAsync(HttpRequestMessage request, HttpResponseMessage response, CancellationToken cancellationToken) + [HttpGet, Route("Download")] + public ActionResult GetCSV() { - NameValueCollection requestParameters = request.RequestUri.ParseQueryString(); + IQueryCollection requestParameters = Request.Query; - response.Content = new PushStreamContent((stream, content, context) => - { - try - { - Filename = (requestParameters["Meter"] == null ? "" : (requestParameters["Meter"] + "_")) + (requestParameters["EventType"] == null ? "" : requestParameters["EventType"] + "_") + "Event_" + requestParameters["eventID"] + ".csv"; - if (requestParameters["type"] == "pqds") - Filename = "PQDS_" + Filename; + string fileName = + $"{(requestParameters["type"] == "pqds" ? "PQDS_" : "")}" + + $"{(requestParameters["Meters"].Any() ? (requestParameters["Meter"].ToString() + "_") : "")}" + + $"{(requestParameters["EventType"].Any() ? (requestParameters["EventType"].ToString() + "_") : "")}" + + $"Event_{requestParameters["eventID"].ToString()}.csv"; - WriteTableToStream(requestParameters, stream, null, cancellationToken); - } - catch (Exception e) - { - LogExceptionHandler?.Invoke(e); - throw; - } - finally - { - stream.Close(); - } - }, - new MediaTypeHeaderValue(CsvContentType)); - - response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") + // No using block, asp.net takes care of it for us + MemoryStream stream = new MemoryStream(); + using (StreamWriter writer = new NoCloseStreamWriter(stream)) { - FileName = Filename - }; - - return Task.CompletedTask; + // todo: this can probably be turned async + WriteTableToStream(writer, requestParameters); + stream.Position = 0; + return new FileStreamResult(stream, "text/csv") + { + FileDownloadName = fileName + }; + } } - private void WriteTableToStream(NameValueCollection requestParameters, Stream responseStream, Action flushResponse, CompatibleCancellationToken cancellationToken) + private void WriteTableToStream(StreamWriter writer, IQueryCollection requestParameters) { - if (requestParameters["type"] == "csv") - ExportToCSV(responseStream, requestParameters); - else if (requestParameters["type"] == "pqds") - ExportToPQDS(responseStream, requestParameters); - else if (requestParameters["type"] == "stats") - ExportStatsToCSV(responseStream, requestParameters); - else if (requestParameters["type"] == "harmonics") - ExportHarmonicsToCSV(responseStream, requestParameters); - else if (requestParameters["type"] == "correlatedsags") - ExportCorrelatedSagsToCSV(responseStream, requestParameters); - else if (requestParameters["type"] == "fft") - ExportFFTToCSV(responseStream, requestParameters); + switch (requestParameters["type"].ToString()) + { + case "csv": + ExportToCSV(writer, requestParameters); + return; + case "pqds": + ExportToPQDS(writer, requestParameters); + return; + case "stats": + ExportStatsToCSV(writer, requestParameters); + return; + case "harmonics": + ExportHarmonicsToCSV(writer, requestParameters); + return; + case "correlatedsags": + ExportCorrelatedSagsToCSV(writer, requestParameters); + return; + case "fft": + ExportFFTToCSV(writer, requestParameters); + return; + default: + throw new ArgumentException("Parameter 'type' is not a valid value."); + } } // Converts the data group row of CSV data. private string ToCSV(IEnumerable data, int index) { - DateTime timestamp = this.m_epoch.Add(new TimeSpan((long)(data.First().DataPoints[index][1] * TimeSpan.TicksPerMillisecond))); + DateTime timestamp = m_epoch.Add(new TimeSpan((long)(data.First().DataPoints[index][1] * TimeSpan.TicksPerMillisecond))); IEnumerable row = new List() { timestamp.ToString("MM/dd/yyyy HH:mm:ss.fffffff"), timestamp.ToString("fffffff") }; @@ -198,40 +144,32 @@ private string GetCSVHeader(IEnumerable keys) return string.Join(",", headers); } - public void ExportToCSV(Stream returnStream, NameValueCollection requestParameters) + public void ExportToCSV(StreamWriter writer, IQueryCollection requestParameters) { IEnumerable data = BuildDataSeries(requestParameters); if (data.Count() == 0) return; - using (StreamWriter writer = new StreamWriter(returnStream)) - { - IEnumerable keys = data.Select(item => (item.LegendGroup + "-" + item.ChartLabel)) ; - // Write the CSV header to the file - writer.WriteLine(GetCSVHeader(keys)); + IEnumerable keys = data.Select(item => (item.LegendGroup + "-" + item.ChartLabel)) ; + // Write the CSV header to the file + writer.WriteLine(GetCSVHeader(keys)); - // Write data to the file - for (int i = 0; i < data.First().DataPoints.Count; ++i) - writer.WriteLine(ToCSV(data,i)); - } + // Write data to the file + for (int i = 0; i < data.First().DataPoints.Count; ++i) + writer.WriteLine(ToCSV(data, i)); } - - public void ExportToPQDS(Stream returnStream, NameValueCollection requestParameters) + public void ExportToPQDS(StreamWriter writer, IQueryCollection requestParameters) { - int eventID = int.Parse(requestParameters["eventID"]); + int eventID = int.Parse(requestParameters["eventID"].ToString()); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Event evt = (new TableOperations(connection)).QueryRecordWhere("ID = {0}", eventID); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); - // only get Single Voltage and Single Current Data for This.... List data = new List(); List metaData = new List(); VIDataGroup dataGroup = OpenSEEBaseController - .QueryVIDataGroupAsync(evt.ID, meter) + .QueryVIDataGroupAsync(eventID, connection) .GetAwaiter() .GetResult(); @@ -255,22 +193,22 @@ public void ExportToPQDS(Stream returnStream, NameValueCollection requestParamet return; // Add MetaData Information - metaData = PQDSMetaData(evt, meter); + Event evt = (new TableOperations(connection)).QueryRecordWhere("ID = {0}", eventID); + metaData = PQDSMetaData(evt, connection); PQDS.PQDSFile file = new PQDS.PQDSFile(metaData, data, evt.StartTime); - using (StreamWriter writer = new StreamWriter(returnStream)) - { - file.WriteToStream(writer); - } + file.WriteToStream(writer); } } - private List PQDSMetaData(Event evt, Meter meter) + private List PQDSMetaData(Event evt, AdoDataConnection connection) { List result = new List(); + Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); + Asset asset = (new TableOperations(connection)).QueryRecordWhere("ID = {0}", evt.AssetID); + meter.ConnectionFactory = () => new AdoDataConnection(Settings.Default); - result.Add(new PQDS.MetaDataTag("DeviceName", meter.Name)); result.Add(new PQDS.MetaDataTag("DeviceAlias", meter.ShortName)); result.Add(new PQDS.MetaDataTag("DeviceLocation", meter.Location.Name)); @@ -278,95 +216,80 @@ public void ExportToPQDS(Stream returnStream, NameValueCollection requestParamet result.Add(new PQDS.MetaDataTag("Latitude", Convert.ToString(meter.Location.Latitude))); result.Add(new PQDS.MetaDataTag("Longitude", Convert.ToString(meter.Location.Longitude))); - Asset asset; - double systemFrequency; - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) - { - asset = (new TableOperations(connection)).QueryRecordWhere("ID = {0}", evt.AssetID); - systemFrequency = connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'SystemFrequency'") ?? 60.0; + double systemFrequency = connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'SystemFrequency'") ?? 60.0; - if (asset != null) - { - result.Add(new PQDS.MetaDataTag("NominalVoltage-LG", asset.VoltageKV)); - result.Add(new PQDS.MetaDataTag("NominalFrequency", systemFrequency)); - result.Add(new PQDS.MetaDataTag("AssetName", asset.AssetKey)); + if (asset != null) + { + result.Add(new PQDS.MetaDataTag("NominalVoltage-LG", asset.VoltageKV)); + result.Add(new PQDS.MetaDataTag("NominalFrequency", systemFrequency)); + result.Add(new PQDS.MetaDataTag("AssetName", asset.AssetKey)); - if (asset.AssetTypeID == connection.ExecuteScalar("SELECT ID FROM AssetType WHERE Name = 'Line'")) - result.Add(new PQDS.MetaDataTag("LineLength", connection.ExecuteScalar("SELECT Length FROM LineView WHERE ID = {0}", asset.ID))); - } + if (asset.AssetTypeID == connection.ExecuteScalar("SELECT ID FROM AssetType WHERE Name = 'Line'")) + result.Add(new PQDS.MetaDataTag("LineLength", connection.ExecuteScalar("SELECT Length FROM LineView WHERE ID = {0}", asset.ID))); + } - result.Add(new PQDS.MetaDataTag("EventID", evt.Name)); - result.Add(new PQDS.MetaDataTag("EventGUID", Guid.NewGuid().ToString())); - result.Add(new PQDS.MetaDataTag("EventDuration", (evt.EndTime - evt.StartTime).TotalMilliseconds)); - result.Add(new PQDS.MetaDataTag("EventTypeCode", PQDSEventTypeCode(evt.EventTypeID))); + result.Add(new PQDS.MetaDataTag("EventID", evt.Name)); + result.Add(new PQDS.MetaDataTag("EventGUID", Guid.NewGuid().ToString())); + result.Add(new PQDS.MetaDataTag("EventDuration", (evt.EndTime - evt.StartTime).TotalMilliseconds)); + result.Add(new PQDS.MetaDataTag("EventTypeCode", PQDSEventTypeCode(evt.EventTypeID))); - EventStat stat = (new TableOperations(connection)).QueryRecordWhere("EventID = {0}", evt.ID); + EventStat stat = (new TableOperations(connection)).QueryRecordWhere("EventID = {0}", evt.ID); - if (stat != null) + if (stat != null) + { + if (stat.VAMax != null) { - if (stat.VAMax != null) - { - result.Add(new PQDS.MetaDataTag("EventMaxVA", (double)stat.VAMax)); - } - if (stat.VBMax != null) - { - result.Add(new PQDS.MetaDataTag("EventMaxVB", (double)stat.VBMax)); - } - if (stat.VCMax != null) - { - result.Add(new PQDS.MetaDataTag("EventMaxVC", (double)stat.VCMax)); - } - if (stat.VAMin != null) - { - result.Add(new PQDS.MetaDataTag("EventMinVA", (double)stat.VAMin)); - } - if (stat.VBMin != null) - { - result.Add(new PQDS.MetaDataTag("EventMinVB", (double)stat.VBMin)); - } - if (stat.VCMin != null) - { - result.Add(new PQDS.MetaDataTag("EventMinVC", (double)stat.VCMin)); - } - - if (stat.IAMax != null) - { - result.Add(new PQDS.MetaDataTag("EventMaxIA", (double)stat.IAMax)); - } - if (stat.IBMax != null) - { - result.Add(new PQDS.MetaDataTag("EventMaxIB", (double)stat.IBMax)); - } - if (stat.ICMax != null) - { - result.Add(new PQDS.MetaDataTag("EventMaxIC", (double)stat.ICMax)); - } - - + result.Add(new PQDS.MetaDataTag("EventMaxVA", (double)stat.VAMax)); + } + if (stat.VBMax != null) + { + result.Add(new PQDS.MetaDataTag("EventMaxVB", (double)stat.VBMax)); + } + if (stat.VCMax != null) + { + result.Add(new PQDS.MetaDataTag("EventMaxVC", (double)stat.VCMax)); + } + if (stat.VAMin != null) + { + result.Add(new PQDS.MetaDataTag("EventMinVA", (double)stat.VAMin)); + } + if (stat.VBMin != null) + { + result.Add(new PQDS.MetaDataTag("EventMinVB", (double)stat.VBMin)); + } + if (stat.VCMin != null) + { + result.Add(new PQDS.MetaDataTag("EventMinVC", (double)stat.VCMin)); } - result.Add(new PQDS.MetaDataTag("EventYear", ((DateTime)evt.StartTime).Year)); - - result.Add(new PQDS.MetaDataTag("EventMonth", (evt.StartTime).Month)); - result.Add(new PQDS.MetaDataTag("EventDay", (evt.StartTime).Day)); - result.Add(new PQDS.MetaDataTag("EventHour", (evt.StartTime).Hour)); - result.Add(new PQDS.MetaDataTag("EventMinute", (evt.StartTime).Minute)); - result.Add(new PQDS.MetaDataTag("EventSecond", (evt.StartTime).Second)); - result.Add(new PQDS.MetaDataTag("EventNanoSecond", Get_nanoseconds(evt.StartTime))); - - String date = String.Format("{0:D2}/{1:D2}/{2:D4}", (evt.StartTime).Month, (evt.StartTime).Day, (evt.StartTime).Year); - String time = String.Format("{0:D2}:{1:D2}:{2:D2}", (evt.StartTime).Hour, (evt.StartTime).Minute, (evt.StartTime).Second); - result.Add(new PQDS.MetaDataTag("EventDate", date)); - result.Add(new PQDS.MetaDataTag("EventTime", time)); - - + if (stat.IAMax != null) + { + result.Add(new PQDS.MetaDataTag("EventMaxIA", (double)stat.IAMax)); + } + if (stat.IBMax != null) + { + result.Add(new PQDS.MetaDataTag("EventMaxIB", (double)stat.IBMax)); + } + if (stat.ICMax != null) + { + result.Add(new PQDS.MetaDataTag("EventMaxIC", (double)stat.ICMax)); + } } - - + result.Add(new PQDS.MetaDataTag("EventYear", ((DateTime)evt.StartTime).Year)); + result.Add(new PQDS.MetaDataTag("EventMonth", (evt.StartTime).Month)); + result.Add(new PQDS.MetaDataTag("EventDay", (evt.StartTime).Day)); + result.Add(new PQDS.MetaDataTag("EventHour", (evt.StartTime).Hour)); + result.Add(new PQDS.MetaDataTag("EventMinute", (evt.StartTime).Minute)); + result.Add(new PQDS.MetaDataTag("EventSecond", (evt.StartTime).Second)); + result.Add(new PQDS.MetaDataTag("EventNanoSecond", Get_nanoseconds(evt.StartTime))); + + String date = String.Format("{0:D2}/{1:D2}/{2:D4}", (evt.StartTime).Month, (evt.StartTime).Day, (evt.StartTime).Year); + String time = String.Format("{0:D2}:{1:D2}:{2:D2}", (evt.StartTime).Hour, (evt.StartTime).Minute, (evt.StartTime).Second); + result.Add(new PQDS.MetaDataTag("EventDate", date)); + result.Add(new PQDS.MetaDataTag("EventTime", time)); return result; - } private int Get_nanoseconds(DateTime date) @@ -376,15 +299,11 @@ private int Get_nanoseconds(DateTime date) result = result - (long)day.Hours * (60L * 60L * 10000000L); result = result - (long)day.Minutes * (60L * 10000000L); result = result - (long)day.Seconds * 10000000L; - - return ((int)result * 100); } - private int PQDSEventTypeCode(int XDAevtTypeID) - { - return 0; - } + private int PQDSEventTypeCode(int XDAevtTypeID) => 0; + private PQDS.DataSeries PQDSSeries(DataSeries data, string label) { PQDS.DataSeries result = new PQDS.DataSeries(label); @@ -394,11 +313,10 @@ private PQDS.DataSeries PQDSSeries(DataSeries data, string label) return result; } - public void ExportStatsToCSV(Stream returnStream, NameValueCollection requestParameters) + public void ExportStatsToCSV(StreamWriter writer, IQueryCollection requestParameters) { - int eventId = int.Parse(requestParameters["eventId"]); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) - using (StreamWriter writer = new StreamWriter(returnStream)) + int eventId = int.Parse(requestParameters["eventId"].ToString()); + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { DataTable dataTable = connection.RetrieveData("SELECT * FROM OpenSEEScalarStatView WHERE EventID = {0}", eventId); DataRow row = dataTable.AsEnumerable().First(); @@ -412,12 +330,11 @@ public void ExportStatsToCSV(Stream returnStream, NameValueCollection requestPar } } - public void ExportCorrelatedSagsToCSV(Stream returnStream, NameValueCollection requestParameters) + public void ExportCorrelatedSagsToCSV(StreamWriter writer, IQueryCollection requestParameters) { - int eventID = int.Parse(requestParameters["eventId"]); + int eventID = int.Parse(requestParameters["eventId"].ToString()); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) - using (StreamWriter writer = new StreamWriter(returnStream)) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { double timeTolerance = connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'TimeTolerance'"); DateTime startTime = connection.ExecuteScalar("SELECT StartTime FROM Event WHERE ID = {0}", eventID); @@ -450,24 +367,19 @@ private class PhasorResult { public double Angle; } - public void ExportFFTToCSV(Stream returnStream, NameValueCollection requestParameters) + public void ExportFFTToCSV(StreamWriter writer, IQueryCollection requestParameters) { - int eventId = int.Parse(requestParameters["eventID"]); + int eventId = int.Parse(requestParameters["eventID"].ToString()); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) - using (StreamWriter writer = new StreamWriter(returnStream)) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - double startTime = requestParameters["startDate"] == null ? 0.0 : double.Parse(requestParameters["startDate"]); - int cycles = requestParameters["cycles"] == null ? 0 : int.Parse(requestParameters["cycles"]); - - Event evt = (new TableOperations(connection)).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); + double startTime = requestParameters["startDate"].Any() ? double.Parse(requestParameters["startDate"].ToString()) : 0.0; + int cycles = requestParameters["cycles"].Any() ? int.Parse(requestParameters["cycles"].ToString()) : 0; AnalyticController ctrl = new AnalyticController(); DataGroup dataGroup = OpenSEEBaseController - .QueryDataGroupAsync(evt.ID, meter) + .QueryDataGroupAsync(eventId, connection) .GetAwaiter() .GetResult(); @@ -490,11 +402,10 @@ public void ExportFFTToCSV(Stream returnStream, NameValueCollection requestParam } } - public void ExportHarmonicsToCSV(Stream returnStream, NameValueCollection requestParameters) + public void ExportHarmonicsToCSV(StreamWriter writer, IQueryCollection requestParameters) { - int eventId = int.Parse(requestParameters["eventId"]); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) - using (StreamWriter writer = new StreamWriter(returnStream)) + int eventId = int.Parse(requestParameters["eventId"].ToString()); + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { DataTable dataTable = connection.RetrieveData(@" SELECT @@ -543,46 +454,60 @@ SnapshotHarmonics JOIN } } - public List BuildDataSeries(NameValueCollection requestParameters) + public List BuildDataSeries(IQueryCollection requestParameters) { - int eventID = int.Parse(requestParameters["eventID"]); - bool displayVolt = requestParameters["displayVolt"] == null ? true: bool.Parse(requestParameters["displayVolt"]); - bool displayCur = requestParameters["displayCur"] == null ? true : bool.Parse(requestParameters["displayCur"]); - bool displayTCE = requestParameters["displayTCE"] == null ? false : bool.Parse(requestParameters["displayTCE"]); - bool breakerdigitals = requestParameters["breakerdigitals"] == null ? false : bool.Parse(requestParameters["breakerdigitals"]); - bool displayAnalogs = requestParameters["displayAnalogs"] == null ? false : bool.Parse(requestParameters["displayAnalogs"]); - int lpfOrder = requestParameters["lpfOrder"] == null ? 0 : int.Parse(requestParameters["lpfOrder"]); - int hpfOrder = requestParameters["hpfOrder"] == null ? 0 : int.Parse(requestParameters["hpfOrder"]); - double Trc = requestParameters["Trc"] == null ? 0.0 : double.Parse(requestParameters["Trc"]); - int harmonic = requestParameters["harmonic"] == null ? 1 : int.Parse(requestParameters["harmonic"]); - List displayAnalytics = requestParameters["displayAnalytics"] == null ? new List() : requestParameters["displayAnalytics"].Split(',').ToList(); + int eventID = int.Parse(requestParameters["eventID"].ToString()); + bool displayVolt = requestParameters["displayVolt"].Any() ? bool.Parse(requestParameters["displayVolt"]) : true; + bool displayCur = requestParameters["displayCur"].Any() ? bool.Parse(requestParameters["displayCur"]) : true; + bool displayTCE = requestParameters["displayTCE"].Any() ? bool.Parse(requestParameters["displayTCE"]) : false; + bool breakerdigitals = requestParameters["breakerdigitals"].Any() ? bool.Parse(requestParameters["breakerdigitals"]) : false; + bool displayAnalogs = requestParameters["displayAnalogs"].Any() ? bool.Parse(requestParameters["displayAnalogs"]) : false; + int lpfOrder = requestParameters["lpfOrder"].Any() ? int.Parse(requestParameters["lpfOrder"]) : 0; + int hpfOrder = requestParameters["hpfOrder"].Any() ? int.Parse(requestParameters["hpfOrder"]) : 0; + double Trc = requestParameters["Trc"].Any() ? double.Parse(requestParameters["Trc"]) : 0.0; + int harmonic = requestParameters["harmonic"].Any() ? int.Parse(requestParameters["harmonic"]) : 1; + List displayAnalytics = requestParameters["displayAnalytics"].Any() ? requestParameters["displayAnalytics"].ToString().Split(',').ToList() : new List(); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Event evt = (new TableOperations(connection)).QueryRecordWhere("ID = {0}", eventID); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); + DataGroup dataGroup = OpenSEEBaseController + .QueryDataGroupAsync(eventID, connection) + .GetAwaiter() + .GetResult(); + + VICycleDataGroup viCycleDataGroup = OpenSEEBaseController + .QueryVICycleDataGroupAsync(eventID, connection) + .GetAwaiter() + .GetResult(); + + Lazy lazyVIDataGroup = new Lazy(() => + { + return OpenSEEBaseController + .QueryVIDataGroupAsync(eventID, connection) + .GetAwaiter() + .GetResult(); + }); IEnumerable returnList = new List(); if (displayVolt) - returnList = returnList.Concat(QueryVoltageData(meter, evt)); + returnList = returnList.Concat(QueryVoltageData(dataGroup, viCycleDataGroup)); if(displayCur) - returnList = returnList.Concat(QueryCurrentData(meter, evt)); + returnList = returnList.Concat(QueryCurrentData(dataGroup, viCycleDataGroup)); if(displayTCE) - returnList = returnList.Concat(QueryTCEData(meter, evt)); + returnList = returnList.Concat(QueryTCEData(dataGroup)); if (displayAnalogs) - returnList = returnList.Concat(QueryAnalogData(meter, evt)); + returnList = returnList.Concat(QueryAnalogData(dataGroup)); if (breakerdigitals) - returnList = returnList.Concat(QueryDigitalData(meter, evt)); + returnList = returnList.Concat(QueryDigitalData(dataGroup)); foreach (var analytics in displayAnalytics) { if (!string.IsNullOrEmpty(analytics)) - returnList = returnList.Concat(QueryAnalyticData(meter, evt, analytics, lpfOrder, hpfOrder, Trc, harmonic)); + returnList = returnList.Concat(QueryAnalyticData(dataGroup, viCycleDataGroup, lazyVIDataGroup, analytics, lpfOrder, hpfOrder, Trc, harmonic)); } returnList = AlignData(returnList.ToList()); @@ -591,83 +516,55 @@ public List BuildDataSeries(NameValueCollection requestParameters) } } - private List QueryAnalyticData(Meter meter, Event evt, string analytic, int lowPassOrder, int highPassOrder, double Trc, int harmonic) + private List QueryAnalyticData(DataGroup dataGroup, VICycleDataGroup viCycleData, Lazy lazyVIDataGroup, string analytic, int lowPassOrder, int highPassOrder, double Trc, int harmonic) { - Lazy lazyDataGroup = new Lazy(() => - { - return OpenSEEBaseController - .QueryDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); - }); - - Lazy lazyVIDataGroup = new Lazy(() => - { - return OpenSEEBaseController - .QueryVIDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); - }); - - Lazy lazyVICycleDataGroup = new Lazy(() => - { - return OpenSEEBaseController - .QueryVICycleDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); - }); AnalyticController controller = new AnalyticController(); if (analytic == "FirstDerivative") - return controller.GetFirstDerivativeLookup(lazyDataGroup.Value, lazyVICycleDataGroup.Value); + return controller.GetFirstDerivativeLookup(dataGroup, viCycleData); if (analytic == "ClippedWaveforms") - return controller.GetClippedWaveformsLookup(lazyDataGroup.Value); + return controller.GetClippedWaveformsLookup(dataGroup); if (analytic == "Frequency") return controller.GetFrequencyLookup(lazyVIDataGroup.Value); if (analytic == "Impedance") - return controller.GetImpedanceLookup(lazyVICycleDataGroup.Value); + return controller.GetImpedanceLookup(viCycleData); if (analytic == "Power") - return controller.GetPowerLookup(lazyVICycleDataGroup.Value); + return controller.GetPowerLookup(viCycleData); if (analytic == "RemoveCurrent") - return controller.GetRemoveCurrentLookup(lazyDataGroup.Value); + return controller.GetRemoveCurrentLookup(dataGroup); if (analytic == "MissingVoltage") - return controller.GetMissingVoltageLookup(lazyDataGroup.Value); + return controller.GetMissingVoltageLookup(dataGroup); if (analytic == "LowPassFilter") - return controller.GetLowPassFilterLookup(lazyDataGroup.Value, lowPassOrder); + return controller.GetLowPassFilterLookup(dataGroup, lowPassOrder); if (analytic == "HighPassFilter") - return controller.GetHighPassFilterLookup(lazyDataGroup.Value, highPassOrder); + return controller.GetHighPassFilterLookup(dataGroup, highPassOrder); if (analytic == "SymmetricalComponents") - return controller.GetSymmetricalComponentsLookup(lazyVICycleDataGroup.Value); + return controller.GetSymmetricalComponentsLookup(viCycleData); if (analytic == "Unbalance") - return controller.GetUnbalanceLookup(lazyVICycleDataGroup.Value); + return controller.GetUnbalanceLookup(viCycleData); if (analytic == "Rectifier") return controller.GetRectifierLookup(lazyVIDataGroup.Value, Trc); if (analytic == "RapidVoltageChange") - return controller.GetRapidVoltageChangeLookup(lazyVICycleDataGroup.Value); + return controller.GetRapidVoltageChangeLookup(viCycleData); if (analytic == "THD") - return controller.GetTHDLookup(lazyDataGroup.Value, true); + return controller.GetTHDLookup(dataGroup, true); if (analytic == "SpecifiedHarmonic") - return controller.GetSpecifiedHarmonicLookup(lazyDataGroup.Value, harmonic, true); + return controller.GetSpecifiedHarmonicLookup(dataGroup, harmonic, true); if (analytic == "OverlappingWaveform") - return controller.GetOverlappingWaveformLookup(lazyDataGroup.Value); + return controller.GetOverlappingWaveformLookup(dataGroup); return new List(); } - private List QueryVoltageData(Meter meter, Event evt) + private List QueryVoltageData(DataGroup dataGroup, VICycleDataGroup viCycleDataGroup) { bool useLL; - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - useLL = connection.ExecuteScalar("SELECT Value FROM Settings WHERE Name = 'useLLVoltage'") ?? false; + useLL = bool.Parse(new TableOperations(connection).QueryRecordWhere("Name = {0}", "useLLVoltage")?.Value ?? bool.FalseString); } - DataGroup dataGroup = OpenSEEBaseController - .QueryDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); - List WaveForm = dataGroup.DataSeries.Where(ds => ds.SeriesInfo.Channel.MeasurementType.Name == "Voltage" && ( (useLL && !(ds.SeriesInfo.Channel.Phase.Name == "AB" || ds.SeriesInfo.Channel.Phase.Name == "BC" || ds.SeriesInfo.Channel.Phase.Name == "CA")) || (!useLL && (ds.SeriesInfo.Channel.Phase.Name == "AB" || ds.SeriesInfo.Channel.Phase.Name == "BC" || ds.SeriesInfo.Channel.Phase.Name == "CA"))) @@ -688,11 +585,6 @@ private List QueryVoltageData(Meter meter, Event evt) return a.LegendGroup.CompareTo(b.LegendGroup); }); - VICycleDataGroup viCycleDataGroup = OpenSEEBaseController - .QueryVICycleDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); - List result = new List(); foreach(D3Series w in WaveForm) @@ -724,12 +616,8 @@ private List QueryVoltageData(Meter meter, Event evt) return result; } - private List QueryCurrentData(Meter meter, Event evt) + private List QueryCurrentData(DataGroup dataGroup, VICycleDataGroup viCycleDataGroup) { - DataGroup dataGroup = OpenSEEBaseController - .QueryDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); List WaveForm = dataGroup.DataSeries.Where(ds => ds.SeriesInfo.Channel.MeasurementType.Name == "Current" ).Select( @@ -749,11 +637,6 @@ private List QueryCurrentData(Meter meter, Event evt) return a.LegendGroup.CompareTo(b.LegendGroup); }); - VICycleDataGroup viCycleDataGroup = OpenSEEBaseController - .QueryVICycleDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); - List result = new List(); foreach (D3Series w in WaveForm) @@ -785,44 +668,34 @@ private List QueryCurrentData(Meter meter, Event evt) return result; } - private List QueryTCEData(Meter meter, Event evt) + private List QueryTCEData(DataGroup dataGroup) { - DataGroup dataGroup = OpenSEEBaseController - .QueryDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); - - List result = dataGroup.DataSeries.Where(ds => ds.SeriesInfo.Channel.MeasurementType.Name == "TripCoilCurrent" - ).Select( + return dataGroup.DataSeries + .Where(ds => ds.SeriesInfo.Channel.MeasurementType.Name == "TripCoilCurrent") + .Select( ds => new D3Series() { ChannelID = ds.SeriesInfo.Channel.ID, ChartLabel = OpenSEEBaseController.GetChartLabel(ds.SeriesInfo.Channel), LegendGroup = ds.SeriesInfo.Channel.Asset.AssetName, DataPoints = ds.DataPoints.Select(dataPoint => new double[] { dataPoint.Time.Subtract(m_epoch).TotalMilliseconds, dataPoint.Value }).ToList(), - }).ToList(); - - return result; + }) + .ToList(); } - private List QueryDigitalData(Meter meter, Event evt) + private List QueryDigitalData(DataGroup dataGroup) { - DataGroup dataGroup = OpenSEEBaseController - .QueryDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); - - List result = dataGroup.DataSeries.Where(ds => ds.SeriesInfo.Channel.MeasurementType.Name == "Digital" - ).Select( + return dataGroup.DataSeries + .Where(ds => ds.SeriesInfo.Channel.MeasurementType.Name == "Digital") + .Select( ds => new D3Series() { ChannelID = ds.SeriesInfo.Channel.ID, ChartLabel = OpenSEEController.GetChartLabel(ds.SeriesInfo.Channel), LegendGroup = ds.SeriesInfo.Channel.Asset.AssetName, DataPoints = ds.DataPoints.Select(dataPoint => new double[] { dataPoint.Time.Subtract(m_epoch).TotalMilliseconds, dataPoint.Value }).ToList(), - }).ToList(); - - return result; + }) + .ToList(); } private List AlignData(List data) @@ -854,40 +727,27 @@ private List AlignData(List data) return item; }); - return result.ToList(); - } - private List QueryAnalogData(Meter meter, Event evt) + private List QueryAnalogData(DataGroup dataGroup) { - DataGroup dataGroup = OpenSEEBaseController - .QueryDataGroupAsync(evt.ID, meter) - .GetAwaiter() - .GetResult(); - - List dataLookup = dataGroup.DataSeries.Where(ds => - ds.SeriesInfo.Channel.MeasurementType.Name != "Digital" && - ds.SeriesInfo.Channel.MeasurementType.Name != "Voltage" && - ds.SeriesInfo.Channel.MeasurementType.Name != "Current" && - ds.SeriesInfo.Channel.MeasurementType.Name != "TripCoilCurrent").Select(ds => - new D3Series() - { - ChannelID = ds.SeriesInfo.Channel.ID, - ChartLabel = ds.SeriesInfo.Channel.Description ?? OpenSEEBaseController.GetChartLabel(ds.SeriesInfo.Channel), - LegendGroup = ds.SeriesInfo.Channel.Asset.AssetName, - DataPoints = ds.DataPoints.Select(dataPoint => new double[] { dataPoint.Time.Subtract(m_epoch).TotalMilliseconds, dataPoint.Value }).ToList(), - }).ToList(); - - return dataLookup; + return dataGroup.DataSeries + .Where(ds => + ds.SeriesInfo.Channel.MeasurementType.Name != "Digital" && + ds.SeriesInfo.Channel.MeasurementType.Name != "Voltage" && + ds.SeriesInfo.Channel.MeasurementType.Name != "Current" && + ds.SeriesInfo.Channel.MeasurementType.Name != "TripCoilCurrent").Select(ds => + new D3Series() + { + ChannelID = ds.SeriesInfo.Channel.ID, + ChartLabel = ds.SeriesInfo.Channel.Description ?? OpenSEEBaseController.GetChartLabel(ds.SeriesInfo.Channel), + LegendGroup = ds.SeriesInfo.Channel.Asset.AssetName, + DataPoints = ds.DataPoints.Select(dataPoint => new double[] { dataPoint.Time.Subtract(m_epoch).TotalMilliseconds, dataPoint.Value }).ToList(), + } + ).ToList(); } #endregion - - #region [ Static ] - - public static Action LogExceptionHandler; - - #endregion } } \ No newline at end of file diff --git a/src/OpenSEE/Controllers/FaultSpecificsController.cs b/src/OpenSEE/Controllers/FaultSpecificsController.cs new file mode 100644 index 00000000..6616fc3f --- /dev/null +++ b/src/OpenSEE/Controllers/FaultSpecificsController.cs @@ -0,0 +1,35 @@ +//****************************************************************************************************** +// FaultSpecificsController.cs - Gbtc +// +// Copyright © 2018, 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: +// ---------------------------------------------------------------------------------------------------- +// 02/05/2026 - Gabriel Santos +// Refactored code to be in controller format for netcore upgrade. +// +//****************************************************************************************************** + +using Gemstone.Web.APIController; +using Microsoft.AspNetCore.Mvc; +using OpenSEE.Models; + +namespace OpenSEE +{ + /// + /// Controller to fetch FaultSpecifics for faults. + /// + [Route("api/openSEE/FaultSpecifics")] + public class FaultSpecificsController : ReadOnlyModelController { } +} \ No newline at end of file diff --git a/src/OpenSEE/Controllers/HomeController.cs b/src/OpenSEE/Controllers/HomeController.cs index 4994bd26..f3241c71 100644 --- a/src/OpenSEE/Controllers/HomeController.cs +++ b/src/OpenSEE/Controllers/HomeController.cs @@ -22,12 +22,12 @@ //****************************************************************************************************** using System; -using System.Web.Mvc; -using GSF.Data; -using GSF.Data.Model; -using GSF.Identity; -using GSF.Web.Model; -using OpenSEE.Model; +using Gemstone.Configuration; +using Gemstone.Data; +using Gemstone.Data.Model; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Primitives; using openXDA.Model; namespace OpenSEE.Controllers @@ -35,30 +35,18 @@ namespace OpenSEE.Controllers /// /// Represents a MVC controller for the site's main pages. /// + [Authorize] public class HomeController : Controller { - #region [ Constructors ] - - public HomeController() - { - ViewData.Model = new AppModel(); - } - - #endregion - - #region [ Methods ] - - public ActionResult Home() + public IActionResult Index() { - ViewBag.IsAdmin = User.IsInRole("Administrator"); - int eventID = -1; Event evt; - if (Request.QueryString.Get("eventid") != null) - eventID = int.Parse(Request.QueryString["eventid"]); + if (Request.Query.TryGetValue("eventid", out StringValues evtString)) + eventID = int.Parse(evtString.ToString()); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { TableOperations eventTable = new TableOperations(connection); @@ -75,7 +63,5 @@ public ActionResult Home() ViewBag.Cycles = Math.Floor((evt.EndTime - evt.StartTime).TotalSeconds * 60.0D); return View("Index"); } - - #endregion } } \ No newline at end of file diff --git a/src/OpenSEE/Controllers/OpenSEEController.cs b/src/OpenSEE/Controllers/OpenSEEController.cs index 926e20eb..79f76cc7 100644 --- a/src/OpenSEE/Controllers/OpenSEEController.cs +++ b/src/OpenSEE/Controllers/OpenSEEController.cs @@ -28,22 +28,24 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.SqlClient; using System.Globalization; using System.Linq; using System.Runtime.Caching; using System.Threading.Tasks; -using System.Web.Http; using FaultData.DataAnalysis; -using GSF.Data; -using GSF.Data.Model; -using GSF.Web; +using Gemstone.Configuration; +using Gemstone.Data; +using Gemstone.Data.DataExtensions; +using Gemstone.Data.Model; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Primitives; using OpenSEE.Model; using openXDA.Model; namespace OpenSEE { - [RoutePrefix("api/OpenSEE")] + [Route("api/OpenSEE")] public class OpenSEEController : OpenSEEBaseController { #region [ Members ] @@ -106,7 +108,7 @@ static OpenSEEController() { s_memoryCache = new MemoryCache("openSEE"); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { m_cacheSlidingExpiration = connection.ExecuteScalar("SELECT Value FROM [OpenSee.Setting] WHERE Name = 'SlidingCacheExpiration'") ?? 2.0; } @@ -120,38 +122,34 @@ static OpenSEEController() [Route("GetData"),HttpGet] public async Task GetData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - - int eventId = int.Parse(query["eventId"]); - string type = query["type"]; - string dataType = query["dataType"]; + int eventId = int.Parse(Request.Query["eventId"].ToString()); + string type = Request.Query["type"].ToString(); + string dataType = Request.Query["dataType"].ToString(); bool forceFullRes = - query.TryGetValue("fullRes", out string fullResSetting) && - int.TryParse(fullResSetting, out int fullResNum) && + Request.Query.TryGetValue("fullRes", out StringValues fullResSetting) && + int.TryParse(fullResSetting.ToString(), out int fullResNum) && fullResNum != 0; bool dbgNocompress = - query.TryGetValue("dbgNocompress", out string dbgNocompressSetting) && - int.TryParse(dbgNocompressSetting, out int dbgNocompressNum) && + Request.Query.TryGetValue("dbgNocompress", out StringValues dbgNocompressSetting) && + int.TryParse(dbgNocompressSetting.ToString(), out int dbgNocompressNum) && dbgNocompressNum != 0; Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection("systemSettings"); List returnList = new List(); if (dataType == "Time") { - DataGroup dataGroup = await QueryDataGroupAsync(eventId, meter); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); returnList = GetD3DataLookup(dataGroup, type, evt.ID); } else { - VICycleDataGroup viCycleDataGroup = await QueryVICycleDataGroupAsync(eventId, meter, !dbgNocompress); + VICycleDataGroup viCycleDataGroup = await QueryVICycleDataGroupAsync(eventId, connection, !dbgNocompress); returnList = GetD3FrequencyDataLookup(viCycleDataGroup, type, !forceFullRes); } @@ -178,7 +176,7 @@ private List GetD3DataLookup(DataGroup dataGroup, string type, int evt ds => { if (type == "TripCoilCurrent") { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { RelayPerformance relayPerformance = new TableOperations(connection).QueryRecordWhere("EventID = {0} AND ChannelID = {1}", evtID, ds.SeriesInfo.ChannelID); List dataMarkers = new List(); @@ -282,7 +280,7 @@ private List GetD3FrequencyDataLookup(VICycleDataGroup vICycleDataGrou { //Determine Sbase double Sbase = 0; - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) Sbase = connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'SystemMVABase'"); IEnumerable names = vICycleDataGroup.CycleDataGroups.Where(ds => ds.RMS.SeriesInfo.Channel.MeasurementType.Name == type).Select(ds => ds.RMS.SeriesInfo.Channel.Phase.Name); @@ -348,16 +346,12 @@ private List GetD3FrequencyDataLookup(VICycleDataGroup vICycleDataGrou [Route("GetBreakerData"),HttpGet] public async Task GetBreakerData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) - { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) + {; + int eventId = int.Parse(Request.Query["eventId"].ToString()); Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection(connection.Connection, typeof(SqlDataAdapter), false); - - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, connection); List resultList = GetBreakerLookup(dataGroup); JsonReturn returnDict = new JsonReturn(); @@ -407,16 +401,10 @@ private void AdjustLegendNumbering(List data) [Route("GetAnalogsData"), HttpGet] public async Task GetAnalogsData() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - - Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); - meter.ConnectionFactory = () => new AdoDataConnection(connection.Connection, typeof(SqlDataAdapter), false); - - DataGroup dataGroup = await QueryDataGroupAsync(evt.ID, meter); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + DataGroup dataGroup = await QueryDataGroupAsync(eventId, connection); List returnList = GetAnalogsLookup(dataGroup); JsonReturn returnDict = new JsonReturn(); @@ -455,13 +443,12 @@ private List GetAnalogsLookup(DataGroup dataGroup) [Route("GetHeaderData"),HttpGet] public Dictionary GetHeaderData() { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); - string breakerOperationID = (query.ContainsKey("breakeroperation") ? query["breakeroperation"] : "-1"); + int eventId = int.Parse(Request.Query["eventId"].ToString()); + string breakerOperationID = (Request.Query.ContainsKey("breakeroperation") ? Request.Query["breakeroperation"].ToString() : "-1"); Dictionary returnDict = new Dictionary(); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { EventView theEvent = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); @@ -570,8 +557,7 @@ public Dictionary GetHeaderData() [Route("GetNavData"), HttpGet] public Dictionary> GetNavData() { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); + int eventId = int.Parse(Request.Query["eventId"].ToString()); Dictionary> nextBackLookup = new Dictionary>() { @@ -596,7 +582,7 @@ public Dictionary> GetNavData() }; - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { EventView theEvent = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); using (IDbCommand cmd = connection.Connection.CreateCommand()) @@ -646,14 +632,15 @@ public Dictionary> GetNavData() [Route("GetOverlappingEvents"),HttpGet] public DataTable GetOverlappingEvents() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); + int eventId = int.Parse(Request.Query["eventId"].ToString()); Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventId); - DateTime startTime = ((query.ContainsKey("startDate") && query["startDate"] != "null") ? DateTime.Parse(query["startDate"]) : evt.StartTime); - DateTime endTime = ((query.ContainsKey("endDate") && query["endDate"] != "null") ? DateTime.Parse(query["endDate"]) : evt.EndTime); + DateTime startTime = (Request.Query.ContainsKey("startDate") && Request.Query["startDate"].ToString() != "null") ? + DateTime.Parse(Request.Query["startDate"].ToString()) : evt.StartTime; + DateTime endTime = (Request.Query.ContainsKey("endDate") && Request.Query["endDate"].ToString() != "null") ? + DateTime.Parse(Request.Query["endDate"].ToString()) : evt.EndTime; DataTable dataTable = connection.RetrieveData(@" @@ -710,10 +697,9 @@ FROM Disturbance [Route("GetScalarStats"),HttpGet] public Dictionary GetScalarStats() { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); + int eventId = int.Parse(Request.Query["eventId"].ToString()); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { DataTable dataTable = connection.RetrieveData("SELECT * FROM OpenSEEScalarStatView WHERE EventID = {0}", eventId); if (dataTable.Rows.Count == 0) return new Dictionary(); @@ -727,10 +713,9 @@ public Dictionary GetScalarStats() [Route("GetHarmonics"),HttpGet] public DataTable GetHarmonics() { - Dictionary query = Request.QueryParameters(); - int eventId = int.Parse(query["eventId"]); + int eventId = int.Parse(Request.Query["eventId"].ToString()); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { DataTable dataTable = connection.RetrieveData(@" SELECT @@ -751,11 +736,10 @@ SnapshotHarmonics JOIN [Route("GetTimeCorrelatedSags"), HttpGet] public DataTable GetTimeCorrelatedSags() { - Dictionary query = Request.QueryParameters(); - int eventID = int.Parse(query["eventId"]); + int eventID = int.Parse(Request.Query["eventId"].ToString()); if (eventID <= 0) return new DataTable(); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { double timeTolerance = connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'TimeTolerance'"); DateTime startTime = connection.ExecuteScalar("SELECT StartTime FROM Event WHERE ID = {0}", eventID); @@ -770,10 +754,9 @@ public DataTable GetTimeCorrelatedSags() [Route("GetLightningData"), HttpGet] public IEnumerable GetLightningData() { - Dictionary query = Request.QueryParameters(); - int eventID = int.Parse(query["eventID"]); + int eventID = int.Parse(Request.Query["eventID"].ToString()); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { const string QueryFormat = "SELECT * " + @@ -815,14 +798,12 @@ public IEnumerable GetLightningData() } [Route("GetOutputChannelCount/{eventID}"), HttpGet] - public IHttpActionResult GetOutputChannelCount(int eventID) + public ActionResult GetOutputChannelCount(int eventID) { - try + if (eventID <= 0) return BadRequest("Invalid EventID"); + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { - if (eventID <= 0) return BadRequest("Invalid EventID"); - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) - { - int count = connection.ExecuteScalar(@" + int count = connection.ExecuteScalar(@" SELECT COUNT(*) FROM @@ -833,12 +814,7 @@ Event JOIN WHERE Event.ID = {0} ", eventID); - return Ok(count); - } - } - catch(Exception ex) - { - return InternalServerError(ex); + return Ok(count); } } @@ -848,9 +824,9 @@ Event JOIN #region [ Note Management ] [Route("GetPQBrowser"), HttpGet] - public IHttpActionResult GetPQBrowser() + public ActionResult GetPQBrowser() { - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { string pqBrowserURl = connection.ExecuteScalar(@" SELECT diff --git a/src/OpenSEE/Controllers/OpenSeeControllerBase.cs b/src/OpenSEE/Controllers/OpenSeeControllerBase.cs index dc1e6cd5..990a7484 100644 --- a/src/OpenSEE/Controllers/OpenSeeControllerBase.cs +++ b/src/OpenSEE/Controllers/OpenSeeControllerBase.cs @@ -26,16 +26,18 @@ using System.Linq; using System.Runtime.Caching; using System.Threading.Tasks; -using System.Web.Http; using FaultData.DataAnalysis; -using GSF.Data; -using GSF.NumericalAnalysis; +using Gemstone.Configuration; +using Gemstone.Data; +using Gemstone.Data.Model; +using Gemstone.Numeric.Interpolation; +using Microsoft.AspNetCore.Mvc; using OpenSEE.Model; using openXDA.Model; namespace OpenSEE { - public class OpenSEEBaseController : ApiController + public class OpenSEEBaseController : Controller { #region [ Members ] @@ -59,7 +61,7 @@ public static double Sbase { { if (m_Sbase != null) return (double)m_Sbase; - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) m_Sbase = connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'SystemMVABase'") ?? 100.0; return (double)m_Sbase; } @@ -71,7 +73,7 @@ public static double Fbase { if (m_Fbase != null) return (double)m_Fbase; - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) m_Fbase = connection.ExecuteScalar("SELECT Value FROM Setting WHERE Name = 'SystemFrequency'")?? 60.0; return (double)m_Fbase; } @@ -84,7 +86,7 @@ public static int MaxSampleRate if (m_MaxSampleRate != null) return (int)m_MaxSampleRate; - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) m_MaxSampleRate = int.Parse(connection.ExecuteScalar("SELECT Value FROM [OpenSee.Setting] WHERE Name = 'maxSampleRate'") ?? "-1"); return (int)m_MaxSampleRate; } @@ -97,7 +99,7 @@ public static int MinSampleRate if (m_MinSampleRate != null) return (int)m_MinSampleRate; - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) m_MinSampleRate = int.Parse(connection.ExecuteScalar("SELECT Value FROM [OPenSee.Setting] WHERE Name = 'minSampleRate'") ?? "-1"); return (int)m_MinSampleRate; } @@ -130,7 +132,7 @@ public static string GetColor(Channel channel) return "random"; } - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) + using (AdoDataConnection connection = new AdoDataConnection(Settings.Default)) { if (channel.MeasurementType.Name == "Voltage") @@ -408,7 +410,7 @@ public static void DownSample(JsonReturn dict) #region [ Shared Functions ] - public static async Task QueryDataGroupAsync(int eventID, Meter meter) + public static async Task QueryDataGroupAsync(int eventID, AdoDataConnection connection) { string target = $"DataGroup-{eventID}"; @@ -423,8 +425,14 @@ public static async Task QueryDataGroupAsync(int eventID, Meter meter try { - List data = ChannelData.DataFromEvent(eventID, () => new AdoDataConnection("systemSettings")); - DataGroup dataGroup = ToDataGroup(meter, data); + Event evt = new TableOperations(connection).QueryRecordWhere("ID = {0}", eventID); + Meter meter = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.MeterID); + meter.ConnectionFactory = () => new AdoDataConnection(Settings.Default); + Asset asset = new TableOperations(connection).QueryRecordWhere("ID = {0}", evt.AssetID); + asset.ConnectionFactory = () => new AdoDataConnection(Settings.Default); + + List data = ChannelData.DataFromEvent(eventID, () => new AdoDataConnection(Settings.Default)); + DataGroup dataGroup = ToDataGroup(meter, asset, data); taskCompletionSource.SetResult(dataGroup); return dataGroup; } @@ -436,7 +444,7 @@ public static async Task QueryDataGroupAsync(int eventID, Meter meter } } - public static async Task QueryVIDataGroupAsync(int eventID, Meter meter) + public static async Task QueryVIDataGroupAsync(int eventID, AdoDataConnection connection) { string target = $"VIDataGroup-{eventID}"; @@ -451,7 +459,7 @@ public static async Task QueryVIDataGroupAsync(int eventID, Meter m try { - DataGroup dataGroup = await QueryDataGroupAsync(eventID, meter); + DataGroup dataGroup = await QueryDataGroupAsync(eventID, connection); VIDataGroup viDataGroup = new VIDataGroup(dataGroup); taskCompletionSource.SetResult(viDataGroup); return viDataGroup; @@ -464,7 +472,7 @@ public static async Task QueryVIDataGroupAsync(int eventID, Meter m } } - public static async Task QueryVICycleDataGroupAsync(int eventID, Meter meter, bool compress = true) + public static async Task QueryVICycleDataGroupAsync(int eventID, AdoDataConnection connection, bool compress = true) { string compression = compress ? "compressed" : "uncompressed"; string target = $"VICycleDataGroup-{eventID}-{compression}"; @@ -480,7 +488,7 @@ public static async Task QueryVICycleDataGroupAsync(int eventI try { - VIDataGroup viDataGroup = await QueryVIDataGroupAsync(eventID, meter); + VIDataGroup viDataGroup = await QueryVIDataGroupAsync(eventID, connection); VICycleDataGroup viCycleDataGroup = Transform.ToVICycleDataGroup(viDataGroup, Fbase, compress); taskCompletionSource.SetResult(viCycleDataGroup); return viCycleDataGroup; @@ -493,9 +501,9 @@ public static async Task QueryVICycleDataGroupAsync(int eventI } } - public static DataGroup ToDataGroup(Meter meter, List data) + public static DataGroup ToDataGroup(Meter meter, Asset asset, List data) { - DataGroup dataGroup = new DataGroup(); + DataGroup dataGroup = new DataGroup(asset); dataGroup.FromData(meter, data); VIDataGroup vIDataGroup = new VIDataGroup(dataGroup); return vIDataGroup.ToDataGroup(); diff --git a/src/OpenSEE/FaultSpecifics.aspx b/src/OpenSEE/FaultSpecifics.aspx deleted file mode 100644 index 2398118d..00000000 --- a/src/OpenSEE/FaultSpecifics.aspx +++ /dev/null @@ -1,68 +0,0 @@ -<%@ Page Language="C#" AutoEventWireup="true" CodeFile="FaultSpecifics.aspx.cs" Inherits="FaultSpecifics" %> - - - - - - Fault Specifics - - - - - - - - - - -
- - - - - - - - - - - - - -
<%=postedMeterName %>
Fault Type:    <%=postedFaultType %>
Start Time:    <%=postedStartTime %>
Inception Time:    <%=postedInceptionTime %>
Delta Time:    <%=postedDeltaTime %>
Fault Duration:    <%=postedDurationPeriod %>
Fault Current:    <%=postedFaultCurrent %>
Distance Method:    <%=postedDistanceMethod %>
Single-ended Distance:    <%=postedSingleEndedDistance %>
Double-ended Distance:    <%=postedDoubleEndedDistance %>
Double-ended Angle:    <%=postedDoubleEndedConfidence %>
OpenXDA EventID:    <%=postedEventId %>
-
- - \ No newline at end of file diff --git a/src/OpenSEE/FaultSpecifics.aspx.cs b/src/OpenSEE/FaultSpecifics.aspx.cs deleted file mode 100644 index 9e44f373..00000000 --- a/src/OpenSEE/FaultSpecifics.aspx.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Data; -using System.Data.SqlClient; -using System.Globalization; -using System.Linq; -using GSF.Configuration; -using GSF.Data; -using GSF.Data.Model; -using System.Web.UI; -using openXDA.Model; -public partial class FaultSpecifics : Page -{ - public string postedFaultType = ""; - public string postedDeltaTime = ""; - public string postedStartTime = ""; - public string postedInceptionTime = ""; - public string postedDurationPeriod = ""; - public string postedFaultCurrent = ""; - public string postedDistanceMethod = ""; - public string postedSingleEndedDistance = ""; - public string postedEventId = ""; - public string postedMeterId = ""; - public string postedMeterName = ""; - public string postedDoubleEndedDistance = ""; - public string postedDoubleEndedConfidence = ""; - public string postedExceptionMessage = ""; - - string connectionstring = ConfigurationFile.Current.Settings["systemSettings"]["ConnectionString"].Value; - - protected void Page_Load(object sender, EventArgs e) - { - SqlConnection conn = null; - SqlDataReader rdr = null; - - if (!IsPostBack) - { - if (Request["eventId"] != null) - { - postedEventId = Request["eventId"]; - - using (AdoDataConnection connection = new AdoDataConnection("systemSettings")) - { - try - { - Event theevent = (new TableOperations(connection)).QueryRecordWhere("ID = {0}", Convert.ToInt32(postedEventId)); - FaultSummary thesummary = (new TableOperations(connection)).QueryRecordWhere("EventID = {0} AND IsSelectedAlgorithm = 1", Convert.ToInt32(postedEventId)); - - if ((object)thesummary == null) - { - postedFaultType = "Invalid"; - postedInceptionTime = "Invalid"; - postedDurationPeriod = "Invalid"; - postedFaultCurrent = "Invalid"; - postedDistanceMethod = "Invalid"; - postedSingleEndedDistance = "Invalid"; - postedDeltaTime = "Invalid"; - postedDoubleEndedDistance = "Invalid"; - postedDoubleEndedConfidence = "Invalid"; - return; - } - - postedFaultType = thesummary.FaultType; - postedInceptionTime = thesummary.Inception.TimeOfDay.ToString(); - postedDurationPeriod = (thesummary.DurationSeconds * 1000).ToString("##.###", CultureInfo.InvariantCulture) + "msec (" + thesummary.DurationCycles.ToString("##.##", CultureInfo.InvariantCulture) + " cycles)"; - postedFaultCurrent = thesummary.CurrentMagnitude.ToString("####.#", CultureInfo.InvariantCulture) + " Amps (RMS)"; - postedDistanceMethod = thesummary.Algorithm; - postedSingleEndedDistance = thesummary.Distance.ToString("####.###", CultureInfo.InvariantCulture) + " miles"; - double deltatime = (thesummary.Inception - theevent.StartTime).Ticks / 10000000.0; - postedDeltaTime = deltatime.ToString(); - postedStartTime = theevent.StartTime.TimeOfDay.ToString(); - postedMeterName = connection.ExecuteScalar("SELECT Name From Meter WHERE ID = {0}", theevent.MeterID); - postedMeterId = theevent.MeterID.ToString(); - - conn = new SqlConnection(connectionstring); - conn.Open(); - SqlCommand cmd = new SqlCommand("dbo.selectDoubleEndedFaultDistanceForEventID", conn); - cmd.CommandType = CommandType.StoredProcedure; - cmd.Parameters.Add(new SqlParameter("@EventID", postedEventId)); - cmd.CommandTimeout = 300; - rdr = cmd.ExecuteReader(); - - if (rdr.HasRows) - { - while (rdr.Read()) - { - postedDoubleEndedDistance = ((double)rdr["Distance"]).ToString("####.###", CultureInfo.InvariantCulture) + " miles"; - postedDoubleEndedConfidence = ((double)rdr["Angle"]).ToString("####.####", CultureInfo.InvariantCulture) + " degrees"; - } - } - } - catch (Exception ex) - { - postedExceptionMessage = ex.Message; - } - finally - { - if (rdr != null) - rdr.Dispose(); - - if (conn != null) - conn.Dispose(); - } - } - } - } - } -} \ No newline at end of file diff --git a/src/OpenSEE/Global.asax b/src/OpenSEE/Global.asax deleted file mode 100644 index cc344007..00000000 --- a/src/OpenSEE/Global.asax +++ /dev/null @@ -1 +0,0 @@ -<%@ Application Codebehind="Global.asax.cs" Inherits="OpenSEE.MvcApplication" Language="C#" %> diff --git a/src/OpenSEE/Global.asax.cs b/src/OpenSEE/Global.asax.cs deleted file mode 100644 index aae1a995..00000000 --- a/src/OpenSEE/Global.asax.cs +++ /dev/null @@ -1,186 +0,0 @@ -//****************************************************************************************************** -// Global.asax.cs - Gbtc -// -// Copyright © 2020, 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: -// ---------------------------------------------------------------------------------------------------- -// 02/19/2020 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - -using System; -using System.Collections.Generic; -using System.Data; -using System.IO; -using System.Linq; -using System.Threading; -using System.Web; -using System.Web.Mvc; -using System.Web.Optimization; -using System.Web.Routing; -using GSF; -using GSF.Configuration; -using GSF.Data; -using GSF.Identity; -using GSF.IO; -using GSF.Security; -using GSF.Web.Embedded; -using GSF.Web.Model; -using OpenSEE.Model; - -namespace OpenSEE -{ - public class MvcApplication : HttpApplication - { - /// - /// Gets the default model used for the application. - /// - public static readonly AppModel DefaultModel = new AppModel(); - - protected void Application_Start() - { - Directory.SetCurrentDirectory(FilePath.GetAbsolutePath("")); - - AreaRegistration.RegisterAllAreas(); - FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); - RouteConfig.RegisterRoutes(RouteTable.Routes); - BundleConfig.RegisterBundles(BundleTable.Bundles); - - // Add additional virtual path provider to allow access to embedded resources - EmbeddedResourceProvider.Register(); - - GlobalSettings global = DefaultModel.Global; - - // Make sure LSCVSReport specific default config file service settings exist - CategorizedSettingsElementCollection systemSettings = ConfigurationFile.Current.Settings["systemSettings"]; - CategorizedSettingsElementCollection securityProvider = ConfigurationFile.Current.Settings["securityProvider"]; - - systemSettings.Add("ConnectionString", "Data Source=localhost; Initial Catalog=OpenSee; Integrated Security=SSPI", "Configuration connection string."); - systemSettings.Add("DataProviderString", "AssemblyName={System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}; ConnectionType=System.Data.SqlClient.SqlConnection; AdapterType=System.Data.SqlClient.SqlDataAdapter", "Configuration database ADO.NET data provider assembly type creation string used"); - systemSettings.Add("CompanyName", "Grid Protection Alliance", "The name of the company who owns this instance of the openSee."); - systemSettings.Add("CompanyAcronym", "GPA", "The acronym representing the company who owns this instance of the openSee."); - systemSettings.Add("DateFormat", "MM/dd/yyyy", "The default date format to use when rendering timestamps."); - systemSettings.Add("TimeFormat", "HH:mm.ss.fff", "The default time format to use when rendering timestamps."); - systemSettings.Add("DefaultSecurityRoles", "Administrator, Manager, Engineer", "The default security roles that should exist for the application."); - securityProvider.Add("PasswordRequirementsRegex", AdoSecurityProvider.DefaultPasswordRequirementsRegex, "Regular expression used to validate new passwords for database users."); - securityProvider.Add("PasswordRequirementsError", AdoSecurityProvider.DefaultPasswordRequirementsError, "Error message to be displayed when new database user password fails regular expression test."); - - // Load default configuration file based model settings - global.CompanyName = systemSettings["CompanyName"].Value; - global.CompanyAcronym = systemSettings["CompanyAcronym"].Value; - global.DateFormat = systemSettings["DateFormat"].Value; - global.TimeFormat = systemSettings["TimeFormat"].Value; - global.DateTimeFormat = $"{global.DateFormat} {global.TimeFormat}"; - global.PasswordRequirementsRegex = securityProvider["PasswordRequirementsRegex"].Value; - global.PasswordRequirementsError = securityProvider["PasswordRequirementsError"].Value; - - // Load database driven model settings - using (DataContext dataContext = new DataContext(exceptionHandler: LogException)) - { - - // Load global web settings - Dictionary appSetting = dataContext.LoadDatabaseSettings("app.setting"); - global.ApplicationName = appSetting.TryGetValue("applicationName", out string setting)? setting : "OpenSEE"; - global.ApplicationDescription = appSetting.TryGetValue("applicationDescription", out setting) ? setting : "Event Viewing Engine"; - global.ApplicationKeywords = appSetting.TryGetValue("applicationKeywords", out setting) ? setting : "open source, utility, browser, power quality, management"; - global.BootstrapTheme = appSetting.TryGetValue("bootstrapTheme", out setting) ? setting : "~/Content/bootstrap-theme.css"; - - // Cache application settings - foreach (KeyValuePair item in appSetting) - global.ApplicationSettings.Add(item.Key, item.Value); - } - } - - private void Page_Error(object sender, EventArgs e) - { - Exception exc = Server.GetLastError(); - WriteToErrorLog(exc); - - // Clear the error from the server. - Server.ClearError(); - } - - void Application_Error(object sender, EventArgs e) - { - Exception exc = Server.GetLastError(); - WriteToErrorLog(exc); - } - - /// - /// Logs a status message. - /// - /// Message to log. - /// Type of message to log. - public static void LogStatusMessage(string message, UpdateType type = UpdateType.Information) - { - // TODO: Write message to log with log4net, etc. - } - - /// - /// Logs an exception. - /// - /// Exception to log. - public static void LogException(Exception ex) - { - // TODO: Write exception to log with log4net, etc. -#if DEBUG - ThreadPool.QueueUserWorkItem(state => - { - Thread.Sleep(1500); - }); -#endif - WriteToErrorLog(ex); - } - - private static ReaderWriterLockSlim LogFileReadWriteLock = new ReaderWriterLockSlim(); - - public static void WriteToErrorLog(Exception ex, bool innerException = false) - { - if (ex.InnerException != null) WriteToErrorLog(ex.InnerException, true); - - string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "OpenSee"); - string path = Path.Combine("C:\\Users\\Public\\Documents", "OpenSee.ErrorLog.txt"); - // Set Status to Locked - LogFileReadWriteLock.EnterWriteLock(); - try - { - Directory.CreateDirectory(folderPath); - // Append text to the file - using (StreamWriter sw = File.AppendText(path)) - { - sw.WriteLine($"[{DateTime.Now}] ({(innerException ? "Inner Exception" : "Outer Excpetion")})"); - sw.WriteLine($"Exception Source: {ex.Source}"); - sw.WriteLine($"Exception Message: {ex.Message}"); - sw.WriteLine(); - sw.WriteLine("---- Stack Trace ----"); - sw.WriteLine(); - sw.WriteLine(ex.StackTrace); - sw.WriteLine(); - sw.WriteLine(); - - sw.Close(); - } - } - finally - { - // Release lock - LogFileReadWriteLock.ExitWriteLock(); - } - } - - - } -} diff --git a/src/OpenSEE/Model/AppModel.cs b/src/OpenSEE/Model/AppModel.cs deleted file mode 100644 index 73f2fb6d..00000000 --- a/src/OpenSEE/Model/AppModel.cs +++ /dev/null @@ -1,81 +0,0 @@ -//****************************************************************************************************** -// AppModel.cs - Gbtc -// -// Copyright © 2020, 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: -// ---------------------------------------------------------------------------------------------------- -// 02/19/2020 - Billy Ernest -// Generated original version of source code. -// -//****************************************************************************************************** - - -using GSF; -using GSF.Data.Model; -using GSF.Web; -using GSF.Web.Model; -using System; -using System.Web; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using Path = System.Web.VirtualPathUtility; -using System.Web.Routing; - -namespace OpenSEE.Model -{ - /// - /// Defines a base application model with convenient global settings and functions. - /// - /// - /// Custom view models should inherit from AppModel because the "Global" property is used by _Layout.cshtml. - /// - public class AppModel - { - #region [ Constructors ] - - /// - /// Creates a new . - /// - public AppModel() - { - Global = MvcApplication.DefaultModel != null ? MvcApplication.DefaultModel.Global : new GlobalSettings(); - } - - #endregion - - #region [ Properties ] - - /// - /// Gets global settings for application. - /// - public GlobalSettings Global { get; } - #endregion - - #region [ Methods ] - - public bool IsDebug() - { -#if DEBUG - return true; -#else - return false; -#endif - - } - #endregion - } -} \ No newline at end of file diff --git a/src/OpenSEE/Model/D3Series.cs b/src/OpenSEE/Model/D3Series.cs index 2d5b2db0..39e651e1 100644 --- a/src/OpenSEE/Model/D3Series.cs +++ b/src/OpenSEE/Model/D3Series.cs @@ -21,18 +21,7 @@ // //****************************************************************************************************** - -using GSF; -using GSF.Data.Model; -using GSF.Web; -using GSF.Web.Model; -using System; -using System.Web; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; - namespace OpenSEE.Model { diff --git a/src/OpenSEE/Model/FaultSpecifics.cs b/src/OpenSEE/Model/FaultSpecifics.cs new file mode 100644 index 00000000..86817876 --- /dev/null +++ b/src/OpenSEE/Model/FaultSpecifics.cs @@ -0,0 +1,52 @@ +//****************************************************************************************************** +// SystemSettings.cs - Gbtc +// +// Copyright © 2020, 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: +// ---------------------------------------------------------------------------------------------------- +// 01/23/2026 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System; +using System.Data; +using Gemstone.Data; +using Gemstone.Data.Model; + +namespace OpenSEE.Models +{ + [TableName("openSee.FaultSpecifics"), UseEscapedName] + public class FaultSpecifics + { + [PrimaryKey(true)] + public int ID { get; set; } + public string FaultType { get; set; } + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime Inception { get; set; } + public double DurationMs { get; set; } + public double DurationCycles { get; set; } + public double DeltaTime { get; set; } + public double CurrentMagnitude { get; set; } + public string Algorithm { get; set; } + public double Distance { get; set; } + public double DoubleFaultDistance { get; set; } + public double DoubleFaultAngle { get; set; } + [FieldDataType(DbType.DateTime2, DatabaseType.SQLServer)] + public DateTime StartTime { get; set; } + public string MeterName { get; set; } + + } +} diff --git a/src/OpenSEE/Model/SystemSettings.cs b/src/OpenSEE/Model/SystemSettings.cs new file mode 100644 index 00000000..daa92b8a --- /dev/null +++ b/src/OpenSEE/Model/SystemSettings.cs @@ -0,0 +1,41 @@ +//****************************************************************************************************** +// SystemSettings.cs - Gbtc +// +// Copyright © 2020, 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: +// ---------------------------------------------------------------------------------------------------- +// 01/23/2026 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +namespace OpenSEE.Models +{ + public class SystemSettings + { + public string ConnectionString { get; set; } + public string DataProviderString { get; set; } + public string CompanyName { get; set; } + public string CompanyAcronym { get; set; } + public string DateFormat { get; set; } + public string TimeFormat { get; set; } + public string PasswordRequirementsRegex { get; set; } + public string PasswordRequirementsError { get; set; } + public string ApplicationName { get; set; } + public string ApplicationDescription { get; set; } + public string ApplicationKeywords { get; set; } + public string BootstrapTheme { get; set; } + } +} diff --git a/src/OpenSEE/OpenSEE.csproj b/src/OpenSEE/OpenSEE.csproj index a7f4cdcd..c2804904 100644 --- a/src/OpenSEE/OpenSEE.csproj +++ b/src/OpenSEE/OpenSEE.csproj @@ -1,337 +1,98 @@ - - - - + - Debug - AnyCPU - - - 2.0 - {845F68F7-4094-4FE6-95E3-1B113BBFAD3F} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - OpenSEE - OpenSEE - v4.8 - false - true - - - - enabled - enabled - - - - + Exe Latest true - latest - - - true - full - false - bin\ - DEBUG;TRACE - prompt - 4 - - - true - pdbonly - true + CALL cd "$(ProjectDir)" +if $(ConfigurationName) == Debug npm run build +if $(ConfigurationName) == Release npm run buildrelease + + net9.0 bin\ - TRACE - prompt - 4 + false + true - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - CSVDownload.ashx - - - FaultSpecifics.aspx - ASPXCodeBehind - - - Global.asax - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - ..\Dependencies\openXDA\FaultAlgorithms.dll - - - ..\Dependencies\openXDA\FaultData.dll - - - False - ..\Dependencies\GSF\GSF.Core.dll - - - False - ..\Dependencies\GSF\GSF.PQDIF.dll - - - False - ..\Dependencies\GSF\GSF.Security.dll - - - False - ..\Dependencies\GSF\GSF.Web.dll - - - ..\Dependencies\GSF\Ionic.Zlib.dll - ..\Dependencies\NuGet\MathNet.Numerics.5.0.0-alpha02\lib\net48\MathNet.Numerics.dll - - ..\Dependencies\NuGet\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0\lib\net472\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll - - - - ..\Dependencies\GSF\Microsoft.Owin.dll - - - ..\Dependencies\NuGet\Microsoft.Owin.Host.SystemWeb.3.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll - - - ..\Dependencies\GSF\Microsoft.Owin.Security.dll - - - False - ..\Dependencies\GSF\Newtonsoft.Json.dll - - - ..\Dependencies\openXDA\openXDA.Model.dll - - - ..\Dependencies\GSF\Owin.dll - - - ..\Dependencies\openXDA\PQDS.dll - - - False - ..\Dependencies\GSF\RazorEngine.dll - - - - - - - - - - - - False - ..\Dependencies\GSF\System.Net.Http.Formatting.dll - - - - - - - - - - - - ..\Dependencies\GSF\System.Web.Http.dll - - - ..\Dependencies\GSF\System.Web.Http.Owin.dll - - - ..\Dependencies\GSF\System.Web.Mvc.dll - - - ..\Dependencies\NuGet\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll - - - - - ..\Dependencies\NuGet\WebGrease.1.5.2\lib\WebGrease.dll - - - - - - - - + + + + - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - - - True - True - 58744 - / - http://localhost:44367/openSEE - False - False - - - False - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - CALL cd "$(ProjectDir)" -if $(ConfigurationName) == Debug npm run build -if $(ConfigurationName) == Release npm run buildrelease - - - \ No newline at end of file diff --git a/src/OpenSEE/Program.cs b/src/OpenSEE/Program.cs new file mode 100644 index 00000000..a8678ed5 --- /dev/null +++ b/src/OpenSEE/Program.cs @@ -0,0 +1,137 @@ +//****************************************************************************************************** +// Program.cs - Gbtc +// +// Copyright © 2020, 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: +// ---------------------------------------------------------------------------------------------------- +// 01/23/2026 - Billy Ernest +// Generated original version of source code. +// +//****************************************************************************************************** + +using System; +using System.IO; +using Gemstone.Configuration; +using Gemstone.Data; +using Gemstone.Diagnostics; +using Gemstone.Threading; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Debug; +using OpenSEE.Models; + +namespace OpenSEE +{ + public class Program + { + public static IConfiguration Configuration { get; } = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true) + .Build(); + + public static void Main(string[] args) + { + try + { + ShutdownHandler.Initialize(); + + Settings settings = new() + { + INIFile = ConfigurationOperation.ReadWrite, + SQLite = ConfigurationOperation.Disabled + }; + + DefineSettings(settings); + + // Bind settings to configuration sources + settings.Bind(new ConfigurationBuilder() + .ConfigureGemstoneDefaults(settings) + .AddCommandLine(args, settings.SwitchMappings)); + + HostApplicationBuilderSettings appSettings = new() + { + Args = args, + ApplicationName = nameof(OpenSEE), + DisableDefaults = true, + }; + + CreateHostBuilder(args).Build().Run(); + + #if DEBUG + Settings.Save(forceSave: true); + #else + Settings.Save(); + #endif + } + finally + { + ShutdownHandler.InitiateSafeShutdown(); + } + } + + /// + /// Establishes default settings for the config file. + /// + public static void DefineSettings(Settings settings) + { + using (Logger.SuppressFirstChanceExceptionLogMessages()) + { + DiagnosticsLogger.DefineSettings(settings); + AdoDataConnection.DefineSettings(settings); + } + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }) + .ConfigureServices((hostContext, services) => + { + // load settings from config file + services.Configure(hostContext.Configuration.GetSection("systemSettings")); + }) + .ConfigureLogging(builder => + { + builder.ClearProviders(); + builder.SetMinimumLevel(LogLevel.Information); + + builder.AddFilter("Microsoft", LogLevel.Warning); + builder.AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Error); + builder.AddFilter("", LogLevel.Debug); + builder.AddFilter("", LogLevel.Trace); + + builder.AddConsole(options => options.LogToStandardErrorThreshold = LogLevel.Error); + builder.AddDebug(); + + // Add Gemstone diagnostics logging + builder.AddGemstoneDiagnostics(); + + #if RELEASE + if (OperatingSystem.IsWindows()) + { + builder.AddFilter("Application", LogLevel.Warning); + builder.AddEventLog(); + } + #endif + }); + } +} diff --git a/src/OpenSEE/Properties/launchSettings.json b/src/OpenSEE/Properties/launchSettings.json new file mode 100644 index 00000000..8e259806 --- /dev/null +++ b/src/OpenSEE/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "https://localhost:50951", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "OpenSEE": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:50951" + } + } +} \ No newline at end of file diff --git a/src/OpenSEE/Startup.cs b/src/OpenSEE/Startup.cs index 60e399c3..a9dbe025 100644 --- a/src/OpenSEE/Startup.cs +++ b/src/OpenSEE/Startup.cs @@ -23,95 +23,88 @@ using System; using System.IO; -using System.Reflection; -using System.Web.Http; -using GSF.Diagnostics; -using GSF.IO; -using GSF.Web.Security; -using GSF.Web.Shared; -using Microsoft.Owin; -using Owin; -using static OpenSEE.Common; - -[assembly: OwinStartup(typeof(OpenSEE.Startup))] +using Gemstone.Diagnostics; +using Gemstone.IO; +using Gemstone.Web; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json.Serialization; +using OpenSEE.Security; namespace OpenSEE; public class Startup { - public void Configuration(IAppBuilder app) + public Startup(IConfiguration configuration, IWebHostEnvironment env) { - // Enable GSF role-based security authentication - app.UseAuthentication(s_authenticationOptions); - - OwinLoaded = true; - - // Configure Web API for self-host - HttpConfiguration config = new HttpConfiguration(); - - // Enable GSF session management - config.EnableSessions(s_authenticationOptions); - - // Set configuration to use reflection to setup routes - config.MapHttpAttributeRoutes(); - - app.UseWebApi(config); + SetupTempPath(); + Configuration = configuration; + Env = env; } - private static readonly AuthenticationOptions s_authenticationOptions; + public IWebHostEnvironment Env { get; set; } + public IConfiguration Configuration { get; } - static Startup() + public void ConfigureServices(IServiceCollection services) { - SetupTempPath(); + IMvcBuilder builder = services + .AddControllersWithViews() + .AddNewtonsoftJson(options => + { + options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; + options.SerializerSettings.ContractResolver = new DefaultContractResolver(); + }); - s_authenticationOptions = new AuthenticationOptions - { - LoginPage = "~/Login", - LogoutPage = "~/Security/logout", - LoginHeader = $"

{ApplicationName}

", - AuthTestPage = "~/AuthTest", - AnonymousResourceExpression = AnonymousResourceExpression, - AuthFailureRedirectResourceExpression = @"^/$|^/.+$" - }; + // Todo: Temp Auth + services.AddAuthentication(TestAuthHandler.AuthenticationScheme) + .AddScheme(TestAuthHandler.AuthenticationScheme, (options) => { }); - AuthenticationOptions = CreateInstance(s_authenticationOptions); - if (!LogEnabled) - return; - - // Retrieve application log path as defined in the config file - string logPath = LogPath; + services.AddMvc(); + } - // Make sure log directory exists - try + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) { - if (!Directory.Exists(logPath)) - Directory.CreateDirectory(logPath); + app.UseDeveloperExceptionPage(); } - catch + else { - logPath = FilePath.GetAbsolutePath(""); + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); } - try - { - Logger.FileWriter.SetPath(logPath); - Logger.FileWriter.SetLoggingFileCount(MaxLogFiles); - } - catch + app.UseForwardedHeaders(new ForwardedHeadersOptions() { - // ignored - } - } + ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost + }); - public static bool OwinLoaded { get; private set; } + app.UseStaticFiles(WebExtensions.StaticFileEmbeddedResources()); + app.UseStaticFiles(); - public static ReadonlyAuthenticationOptions AuthenticationOptions { get; } + app.UseRouting(); - private static T CreateInstance(params object[] args) - { - Type type = typeof(T); - object instance = type.Assembly.CreateInstance(type.FullName!, false, BindingFlags.Instance | BindingFlags.NonPublic, null, args, null, null); - return (T)instance; + app.UseAuthentication(); + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller}/{newaction?}/{id?}", + defaults: new + { + controller = "Home", + action = "Index" + }); + + endpoints.MapControllers(); + }); } private static void SetupTempPath() diff --git a/src/OpenSEE/TempAuth.cs b/src/OpenSEE/TempAuth.cs new file mode 100644 index 00000000..f33c224d --- /dev/null +++ b/src/OpenSEE/TempAuth.cs @@ -0,0 +1,30 @@ +using System; +using System.Security.Principal; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace OpenSEE.Security +{ + public class TestAuthHandlerOptions : AuthenticationSchemeOptions { } + + public class TestAuthHandler : AuthenticationHandler + { + public const string AuthenticationScheme = "Test"; + + public TestAuthHandler( IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder) { } + + protected override Task HandleAuthenticateAsync() + { + var identity = new GenericIdentity(AuthenticationScheme); + var principal = new GenericPrincipal(identity, ["Administrator"]); + var ticket = new AuthenticationTicket(principal, AuthenticationScheme); + + var result = AuthenticateResult.Success(ticket); + + return Task.FromResult(result); + } + } +} diff --git a/src/OpenSEE/Views/Home/Index.cshtml b/src/OpenSEE/Views/Home/Index.cshtml index 588e3649..74834390 100644 --- a/src/OpenSEE/Views/Home/Index.cshtml +++ b/src/OpenSEE/Views/Home/Index.cshtml @@ -24,23 +24,17 @@ // Moved OpenSee out of PQ Dashboard // //*****************************************************************************************************@ -@using GSF.IO; -@using GSF.IO.Checksums; +@using Gemstone.IO; +@using Gemstone.IO.Checksums; +@using System.IO +@using Gemstone.Reflection @{ Layout = ""; - Version assemblyVersionInfo = typeof(OpenSEE.MvcApplication).Assembly.GetName().Version; + Version assemblyVersionInfo = AssemblyInfo.EntryAssembly.Version; string applicationVersion = assemblyVersionInfo.Major + "." + assemblyVersionInfo.Minor + "." + assemblyVersionInfo.Build; } - -@helper ReferenceScript(string path) -{ - string fullPath = FilePath.GetAbsolutePath(path.Substring(2)); - byte[] bytes = File.ReadAllBytes(fullPath); - uint checksum = Crc32.Compute(bytes, 0, bytes.Length); - -} @@ -57,8 +51,7 @@ - - + - - - -


-

- Logging out...   -

- Click here if page does not redirect -

- - - - - - - - diff --git a/src/OpenSEE/Views/Login/UserInfo.cshtml b/src/OpenSEE/Views/Login/UserInfo.cshtml deleted file mode 100644 index 812f5b45..00000000 --- a/src/OpenSEE/Views/Login/UserInfo.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@using GSF.Web -@{ - Layout = null; -} -@Html.RenderResource("GSF.Web.Shared.Views.UserInfo.cshtml") \ No newline at end of file diff --git a/src/OpenSEE/Web.config b/src/OpenSEE/Web.config deleted file mode 100644 index 6e836d97..00000000 --- a/src/OpenSEE/Web.config +++ /dev/null @@ -1,737 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/OpenSEE/WebExtensions.cs b/src/OpenSEE/WebExtensions.cs index ae3d8788..2b450b60 100644 --- a/src/OpenSEE/WebExtensions.cs +++ b/src/OpenSEE/WebExtensions.cs @@ -21,32 +21,27 @@ // //****************************************************************************************************** +using System.Reflection; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.FileProviders; - -using GSF.Data.Model; -using GSF.Web.Model; -using System.Collections.Generic; - -namespace OpenSEE +namespace Gesmtone.Web { - - [TableName("OpenSEE.Setting")] - [UseEscapedName] - public class OpenSEESetting : openXDA.Model.Setting { }; - public static class WebExtensions { - public static Dictionary LoadDatabaseSettings(this DataContext dataContext, string scope) + /// + /// Used to create for serving Gemstone.Web embedded javascript and css stylesheets. + /// + /// + public static StaticFileOptions StaticFileEmbeddedResources() { - Dictionary settings = new Dictionary(); - - foreach (OpenSEESetting setting in dataContext.Table().QueryRecords("Name")) + ManifestEmbeddedFileProvider embeddedFileProvider = new(Assembly.GetExecutingAssembly(), "Shared"); + return new StaticFileOptions { - if (!string.IsNullOrEmpty(setting.Name)) - settings.Add(setting.Name, setting.Value); - } - - return settings; + FileProvider = embeddedFileProvider, + RequestPath = new PathString("/@Gemstone") + }; } } } \ No newline at end of file diff --git a/src/OpenSEE/package-lock.json b/src/OpenSEE/package-lock.json index 52d7d0ea..22aac07f 100644 --- a/src/OpenSEE/package-lock.json +++ b/src/OpenSEE/package-lock.json @@ -11,6 +11,7 @@ "@gpa-gemstone/gpa-symbols": "0.0.43", "@gpa-gemstone/react-forms": "1.1.75", "@gpa-gemstone/react-interactive": "1.0.135", + "@popperjs/core": "^2.11.8", "@reduxjs/toolkit": "1.8.3", "@types/d3": "7.0.0", "@types/eonasdan-bootstrap-datetimepicker": "4.17.26", @@ -22,9 +23,9 @@ "@types/react": "^17.0.19", "@types/react-dom": "16.8.3", "@types/react-router-dom": "4.3.1", + "bootstrap": "^4.6.2", "d3": "7.4.2", "history": "4.7.2", - "jquery": "3.7.1", "lodash": "^4.17.21", "moment": "2.30.1", "node": "^14.0.0", @@ -36,7 +37,6 @@ "react-redux": "8.0.2", "react-router-dom": "6.2.1", "reselect": "^4.0.0", - "styled-components": "^5.3.3", "typestyle": "2.0.1" }, "devDependencies": { @@ -57,56 +57,46 @@ "webpack-cli": "^4.7.2" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.8.tgz", - "integrity": "sha512-c4IM7OTg6k1Q+AJ153e2mc2QVTezTwnb4VzquwcyiEzGnW0Kedv4do/TrkU98qPeC5LNiMt/QXwIjzYXLBpyZg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.8.tgz", - "integrity": "sha512-6AWcmZC/MZCO0yKys4uhg5NlxL0ESF3K6IAaoQ+xSXvPyPyxNWRafP+GDbI88Oh68O7QkJgmEtedWPM9U0pZNg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "license": "MIT", "peer": true, "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.8", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.8", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -122,15 +112,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -138,25 +128,26 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -165,17 +156,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", - "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.25.9", + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "engines": { @@ -185,41 +176,50 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -229,35 +229,35 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", - "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -266,78 +266,66 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", - "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", - "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "license": "MIT", "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.8" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -398,12 +386,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -437,12 +425,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -554,12 +542,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -569,14 +557,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", - "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-simple-access": "^7.25.9" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -586,16 +573,16 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.9.tgz", - "integrity": "sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-syntax-typescript": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -605,16 +592,16 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", - "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", - "@babel/plugin-transform-typescript": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -624,56 +611,54 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", - "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -689,37 +674,42 @@ "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/@emotion/is-prop-valid": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", - "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "license": "MIT", "dependencies": { - "@emotion/memoize": "^0.8.1" + "@emotion/memoize": "0.7.4" } }, "node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "license": "MIT" }, "node_modules/@emotion/stylis": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", + "license": "MIT" }, "node_modules/@emotion/unitless": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "license": "MIT" }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -736,9 +726,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { @@ -776,26 +766,10 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -805,19 +779,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/js": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", @@ -896,56 +857,15 @@ "styled-components": "5.3.3" } }, - "node_modules/@gpa-gemstone/react-forms/node_modules/@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "dependencies": { - "@emotion/memoize": "0.7.4" - } - }, - "node_modules/@gpa-gemstone/react-forms/node_modules/@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" - }, "node_modules/@gpa-gemstone/react-forms/node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "license": "MIT", "engines": { "node": "*" } }, - "node_modules/@gpa-gemstone/react-forms/node_modules/styled-components": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", - "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^0.8.8", - "@emotion/stylis": "^0.8.4", - "@emotion/unitless": "^0.7.4", - "babel-plugin-styled-components": ">= 1.12.0", - "css-to-react-native": "^3.0.0", - "hoist-non-react-statics": "^3.0.0", - "shallowequal": "^1.1.0", - "supports-color": "^5.5.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0", - "react-is": ">= 16.8.0" - } - }, "node_modules/@gpa-gemstone/react-interactive": { "version": "1.0.135", "resolved": "https://registry.npmjs.org/@gpa-gemstone/react-interactive/-/react-interactive-1.0.135.tgz", @@ -967,51 +887,6 @@ "styled-components": "5.3.3" } }, - "node_modules/@gpa-gemstone/react-interactive/node_modules/@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "license": "MIT", - "dependencies": { - "@emotion/memoize": "0.7.4" - } - }, - "node_modules/@gpa-gemstone/react-interactive/node_modules/@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", - "license": "MIT" - }, - "node_modules/@gpa-gemstone/react-interactive/node_modules/styled-components": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", - "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^0.8.8", - "@emotion/stylis": "^0.8.4", - "@emotion/unitless": "^0.7.4", - "babel-plugin-styled-components": ">= 1.12.0", - "css-to-react-native": "^3.0.0", - "hoist-non-react-statics": "^3.0.0", - "shallowequal": "^1.1.0", - "supports-color": "^5.5.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0", - "react-is": ">= 16.8.0" - } - }, "node_modules/@gpa-gemstone/react-table": { "version": "1.2.56", "resolved": "https://registry.npmjs.org/@gpa-gemstone/react-table/-/react-table-1.2.56.tgz", @@ -1068,6 +943,7 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", + "license": "MIT", "peerDependencies": { "react": "*" } @@ -1276,15 +1152,6 @@ } } }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", @@ -1301,25 +1168,10 @@ "node": ">=10" } }, - "node_modules/@jest/reporters/node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@jest/reporters/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1328,21 +1180,6 @@ "node": ">=10" } }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -1443,52 +1280,55 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1532,10 +1372,21 @@ "node": ">= 8" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@reduxjs/toolkit": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.3.tgz", "integrity": "sha512-lU/LDIfORmjBbyDLaqFN2JB9YmAT1BElET9y0ZszwhSBa5Ef3t6o5CrHupw5J1iOXwd+o92QfQZ8OJpwXvsssg==", + "license": "MIT", "dependencies": { "immer": "^9.0.7", "redux": "^4.1.2", @@ -1593,9 +1444,9 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -1612,18 +1463,19 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" } }, "node_modules/@types/d3": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.0.0.tgz", "integrity": "sha512-7rMMuS5unvbvFCJXAkQXIxWTo2OUlmVXN5q7sfQFesuVICY55PSP6hhbUhWjTTNpfTTB3iLALsIYDFe7KUNABw==", + "license": "MIT", "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", @@ -1658,14 +1510,16 @@ } }, "node_modules/@types/d3-array": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", - "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" }, "node_modules/@types/d3-axis": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } @@ -1674,6 +1528,7 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } @@ -1681,17 +1536,20 @@ "node_modules/@types/d3-chord": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", - "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==" + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" }, "node_modules/@types/d3-contour": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", "dependencies": { "@types/d3-array": "*", "@types/geojson": "*" @@ -1700,17 +1558,20 @@ "node_modules/@types/d3-delaunay": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==" + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" }, "node_modules/@types/d3-dispatch": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", - "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" }, "node_modules/@types/d3-drag": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } @@ -1718,17 +1579,20 @@ "node_modules/@types/d3-dsv": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", - "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==" + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" }, "node_modules/@types/d3-ease": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" }, "node_modules/@types/d3-fetch": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", "dependencies": { "@types/d3-dsv": "*" } @@ -1736,17 +1600,20 @@ "node_modules/@types/d3-force": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", - "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==" + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" }, "node_modules/@types/d3-format": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", - "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==" + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" }, "node_modules/@types/d3-geo": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", "dependencies": { "@types/geojson": "*" } @@ -1754,81 +1621,95 @@ "node_modules/@types/d3-hierarchy": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", - "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==" + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", "dependencies": { "@types/d3-color": "*" } }, "node_modules/@types/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" }, "node_modules/@types/d3-polygon": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", - "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==" + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" }, "node_modules/@types/d3-quadtree": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", - "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==" + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" }, "node_modules/@types/d3-random": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==" + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" }, "node_modules/@types/d3-scale": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", - "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", "dependencies": { "@types/d3-time": "*" } }, "node_modules/@types/d3-scale-chromatic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.3.tgz", - "integrity": "sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" }, "node_modules/@types/d3-selection": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", - "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" }, "node_modules/@types/d3-shape": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", - "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", "dependencies": { "@types/d3-path": "*" } }, "node_modules/@types/d3-time": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", - "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" }, "node_modules/@types/d3-time-format": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", - "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==" + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" }, "node_modules/@types/d3-timer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" }, "node_modules/@types/d3-transition": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.8.tgz", - "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", "dependencies": { "@types/d3-selection": "*" } @@ -1837,6 +1718,7 @@ "version": "3.0.8", "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" @@ -1846,15 +1728,17 @@ "version": "4.17.26", "resolved": "https://registry.npmjs.org/@types/eonasdan-bootstrap-datetimepicker/-/eonasdan-bootstrap-datetimepicker-4.17.26.tgz", "integrity": "sha512-5kxvfdwAx8esJTC/N6vxESBAjKprGTdLiTBx4776krLwQicANzkTmMeunnBHZqPx6EdUIkWs/+GSJbmsHrEHjg==", + "license": "MIT", "dependencies": { "@types/jquery": "*", "moment": ">=2.14.0" } }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -1864,29 +1748,32 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, "node_modules/@types/flot": { "version": "0.0.31", "resolved": "https://registry.npmjs.org/@types/flot/-/flot-0.0.31.tgz", "integrity": "sha512-X+RcMQCqPlQo8zPT6cUFTd/PoYBShMQlHUeOXf05jWlfYnvLuRmluB9z+2EsOKFgUzqzZve5brx+gnFxBaHEUw==", + "license": "MIT", "dependencies": { "@types/jquery": "*" } }, "node_modules/@types/geojson": { - "version": "7946.0.14", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" }, "node_modules/@types/graceful-fs": { "version": "4.1.9", @@ -1898,21 +1785,21 @@ } }, "node_modules/@types/history": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/history/-/history-5.0.0.tgz", - "integrity": "sha512-hy8b7Y1J8OGe6LbAjj3xniQrj3v6lsivCcrmf4TzSgPzLkhIeKgc5IZnT7ReIqmEuodjfO8EYAuoFvIrHi/+jQ==", - "deprecated": "This is a stub types definition. history provides its own type definitions, so you do not need this installed.", - "dependencies": { - "history": "*" - } + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "license": "MIT" }, "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", - "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz", + "integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==", + "license": "MIT", "dependencies": { - "@types/react": "*", "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "@types/react": "*" } }, "node_modules/@types/istanbul-lib-coverage": { @@ -1943,6 +1830,7 @@ "version": "3.5.6", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.6.tgz", "integrity": "sha512-SmgCQRzGPId4MZQKDj9Hqc6kSXFNWZFHpELkyK8AQhf8Zr6HKfCzFv9ZC1Fv3FyQttJZOlap3qYb12h61iZAIg==", + "license": "MIT", "dependencies": { "@types/sizzle": "*" } @@ -1950,54 +1838,63 @@ "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" }, "node_modules/@types/lodash": { "version": "4.14.172", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.172.tgz", - "integrity": "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==" + "integrity": "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==", + "license": "MIT" }, "node_modules/@types/moment": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/@types/moment/-/moment-2.13.0.tgz", "integrity": "sha512-DyuyYGpV6r+4Z1bUznLi/Y7HpGn4iQ4IVcGn8zrr1P4KotKLdH0sbK1TFR6RGyX6B+G8u83wCzL+bpawKU/hdQ==", "deprecated": "This is a stub types definition for Moment (https://github.com/moment/moment). Moment provides its own type definitions, so you don't need @types/moment installed!", + "license": "MIT", "dependencies": { "moment": "*" } }, "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "version": "25.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", + "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~7.16.0" } }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" }, "node_modules/@types/query-string": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@types/query-string/-/query-string-5.1.0.tgz", - "integrity": "sha512-9/sJK+T04pNq7uwReR0CLxqXj1dhxiTapZ1tIxA0trEsT6FRS0bz09YMcMb7tsVBTm4RJ0NEBYGsAjoEmqoFXg==" + "integrity": "sha512-9/sJK+T04pNq7uwReR0CLxqXj1dhxiTapZ1tIxA0trEsT6FRS0bz09YMcMb7tsVBTm4RJ0NEBYGsAjoEmqoFXg==", + "license": "MIT" }, "node_modules/@types/react": { - "version": "17.0.80", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.80.tgz", - "integrity": "sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA==", + "version": "17.0.90", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.90.tgz", + "integrity": "sha512-P9beVR/x06U9rCJzSxtENnOr4BrbJ6VrsrDTc+73TtHv9XHhryXKbjGRB+6oooB2r0G/pQkD/S4dHo/7jUfwFw==", + "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "^0.16", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { "version": "16.8.3", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.8.3.tgz", "integrity": "sha512-HF5hD5YR3z9Mn6kXcW1VKe4AQ04ZlZj1EdLBae61hzQ3eEWWxMgNLUbIxeZp40BnSxqY1eAYLsH9QopQcxzScA==", + "license": "MIT", "peer": true, "dependencies": { "@types/react": "*" @@ -2007,6 +1904,7 @@ "version": "5.1.20", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "license": "MIT", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*" @@ -2016,33 +1914,31 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-4.3.1.tgz", "integrity": "sha512-GbztJAScOmQ/7RsQfO4cd55RuH1W4g6V1gDW3j4riLlt+8yxYLqqsiMzmyuXBLzdFmDtX/uU2Bpcm0cmudv44A==", + "license": "MIT", "dependencies": { "@types/history": "*", "@types/react": "*", "@types/react-router": "*" } }, - "node_modules/@types/react-router/node_modules/@types/history": { - "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" - }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", + "license": "MIT" }, "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", "dev": true, "license": "MIT" }, "node_modules/@types/sizzle": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", - "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==" + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", + "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", + "license": "MIT" }, "node_modules/@types/stack-utils": { "version": "2.0.3", @@ -2051,19 +1947,21 @@ "license": "MIT" }, "node_modules/@types/styled-components": { - "version": "5.1.34", - "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.34.tgz", - "integrity": "sha512-mmiVvwpYklFIv9E8qfxuPyIt/OuyIrn6gMOAMOFUO3WJfSrSE+sGUoa4PiZj77Ut7bKZpaa6o1fBKS/4TOEvnA==", + "version": "5.1.36", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.36.tgz", + "integrity": "sha512-pGMRNY5G2rNDKEv2DOiFYa7Ft1r0jrhmgBwHhOMzPTgCjO76bCot0/4uEfqj7K0Jf1KdQmDtAuaDk9EAs9foSw==", + "license": "MIT", "dependencies": { "@types/hoist-non-react-statics": "*", "@types/react": "*", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/use-sync-external-store": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", + "license": "MIT" }, "node_modules/@types/webpack": { "version": "5.28.5", @@ -2077,9 +1975,9 @@ } }, "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -2127,9 +2025,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -2257,9 +2155,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -2297,9 +2195,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -2328,9 +2226,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", - "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true, "license": "ISC" }, @@ -2484,6 +2382,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "license": "MIT", "peerDependencies": { "webpack": "4.x.x || 5.x.x", "webpack-cli": "4.x.x" @@ -2493,6 +2392,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "license": "MIT", "dependencies": { "envinfo": "^7.7.3" }, @@ -2504,6 +2404,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "license": "MIT", "peerDependencies": { "webpack-cli": "4.x.x" }, @@ -2530,12 +2431,13 @@ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", "peer": true, "bin": { @@ -2545,6 +2447,18 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -2559,6 +2473,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -2571,10 +2486,50 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } @@ -2594,6 +2549,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2622,6 +2589,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2654,6 +2622,7 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -2661,16 +2630,18 @@ } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" }, "node_modules/assert": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "is-nan": "^1.3.2", @@ -2684,6 +2655,7 @@ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -2769,6 +2741,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz", "integrity": "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==", + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-module-imports": "^7.22.5", @@ -2781,9 +2754,9 @@ } }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -2803,7 +2776,7 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "node_modules/babel-preset-jest": { @@ -2825,7 +2798,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -2845,38 +2819,60 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", "engines": { "node": "*" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true + "node_modules/bootstrap": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", + "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", + "deprecated": "This version of Bootstrap is no longer supported. Please upgrade to the latest version.", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", + "peerDependencies": { + "jquery": "1.9.1 - 3", + "popper.js": "^1.16.1" + } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2886,6 +2882,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -2897,13 +2894,15 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, + "license": "MIT", "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -2918,6 +2917,7 @@ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, + "license": "MIT", "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -2929,6 +2929,7 @@ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -2937,41 +2938,54 @@ } }, "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", "dev": true, + "license": "MIT", "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", "dev": true, + "license": "ISC", "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", + "elliptic": "^6.6.1", "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", + "parse-asn1": "^5.1.9", "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 0.12" + "node": ">= 0.10" } }, + "node_modules/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, "node_modules/browserify-sign/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2986,13 +3000,15 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/browserify-sign/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -3001,21 +3017,23 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/browserify-zlib": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, + "license": "MIT", "dependencies": { "pako": "~1.0.5" } }, "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "funding": [ { "type": "opencollective", @@ -3033,10 +3051,11 @@ "license": "MIT", "peer": true, "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.1" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -3073,6 +3092,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -3081,31 +3101,65 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" }, "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -3118,6 +3172,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -3135,14 +3190,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001683", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001683.tgz", - "integrity": "sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==", + "version": "1.0.30001767", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", + "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", "funding": [ { "type": "opencollective", @@ -3175,27 +3231,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", @@ -3206,33 +3241,26 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, + "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" } }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", "engines": { "node": ">=6.0" } @@ -3253,19 +3281,24 @@ } }, "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" } }, "node_modules/cjs-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", - "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", "license": "MIT" }, "node_modules/cliui": { @@ -3286,6 +3319,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -3306,9 +3340,9 @@ } }, "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "license": "MIT" }, "node_modules/color-convert": { @@ -3330,14 +3364,16 @@ "license": "MIT" }, "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==" + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", "engines": { "node": ">= 10" } @@ -3351,7 +3387,8 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" }, "node_modules/console-browserify": { "version": "1.2.0", @@ -3363,24 +3400,28 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, + "license": "MIT", "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -3406,13 +3447,15 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/cosmiconfig/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -3425,22 +3468,25 @@ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" } }, "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, + "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -3454,6 +3500,7 @@ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, + "license": "MIT", "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -3499,31 +3546,37 @@ } }, "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", "dev": true, + "license": "MIT", "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" }, "engines": { - "node": "*" + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", "engines": { "node": ">=4" } @@ -3533,6 +3586,7 @@ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.2.0.tgz", "integrity": "sha512-/rvHfYRjIpymZblf49w8jYcRo2y9gj6rV8UroHGmBxKrIyGLokpycyKzp9OkitvqT29ZSpzJ0Ic7SpnJX3sC8g==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.2.15", @@ -3555,10 +3609,11 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3570,6 +3625,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", "dependencies": { "camelize": "^1.0.0", "css-color-keywords": "^1.0.0", @@ -3581,6 +3637,7 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -3589,14 +3646,16 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" }, "node_modules/d3": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/d3/-/d3-7.4.2.tgz", "integrity": "sha512-7VK+QBAWtNDbP2EU/ThkXgjd0u1MsXYYgCK2ElQ4BBWh0usE75tHVVeYx47m2pqQEy4isYKAA0tAFSln0l+9EQ==", + "license": "ISC", "dependencies": { "d3-array": "3", "d3-axis": "3", @@ -3637,6 +3696,7 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", "dependencies": { "internmap": "1 - 2" }, @@ -3648,6 +3708,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3656,6 +3717,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -3671,6 +3733,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", "dependencies": { "d3-path": "1 - 3" }, @@ -3682,6 +3745,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3690,6 +3754,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-3.1.0.tgz", "integrity": "sha512-vV3xtwrYK5p1J4vyukr70m57mtFTEQYqoaDC1ylBfht/hkdUF0nfWZ1b3V2EPBUVkUkoqq5/fbRoBImBWJgOsg==", + "license": "ISC", "dependencies": { "d3-array": "2 - 3" }, @@ -3701,6 +3766,7 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", "dependencies": { "delaunator": "5" }, @@ -3712,6 +3778,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3720,6 +3787,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" @@ -3732,6 +3800,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", "dependencies": { "commander": "7", "iconv-lite": "0.6", @@ -3756,6 +3825,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "engines": { "node": ">=12" } @@ -3764,6 +3834,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", "dependencies": { "d3-dsv": "1 - 3" }, @@ -3775,6 +3846,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", @@ -3785,9 +3857,10 @@ } }, "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3796,6 +3869,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", "dependencies": { "d3-array": "2.5.0 - 3" }, @@ -3807,6 +3881,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3815,6 +3890,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3" }, @@ -3826,6 +3902,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3834,6 +3911,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3842,6 +3920,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3850,6 +3929,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3858,6 +3938,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", @@ -3873,6 +3954,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" @@ -3885,6 +3967,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", "peer": true, "engines": { "node": ">=12" @@ -3894,6 +3977,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", "dependencies": { "d3-path": "^3.1.0" }, @@ -3905,6 +3989,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", "dependencies": { "d3-array": "2 - 3" }, @@ -3916,6 +4001,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { "d3-time": "1 - 3" }, @@ -3927,6 +4013,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -3935,6 +4022,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", @@ -3953,6 +4041,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -3965,11 +4054,12 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3984,14 +4074,15 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "license": "MIT", "engines": { "node": ">=0.10" } }, "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", + "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==", "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -4013,6 +4104,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4022,6 +4114,7 @@ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -4039,6 +4132,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -4055,6 +4149,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", "dependencies": { "robust-predicates": "^3.0.2" } @@ -4064,6 +4159,7 @@ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -4092,6 +4188,7 @@ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -4099,10 +4196,11 @@ } }, "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" }, "node_modules/dir-glob": { "version": "3.0.1", @@ -4135,6 +4233,7 @@ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz", "integrity": "sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==", "dev": true, + "license": "Artistic-2.0", "engines": { "node": ">=10" }, @@ -4142,10 +4241,25 @@ "url": "https://bevry.me/fund" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/electron-to-chromium": { - "version": "1.5.64", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz", - "integrity": "sha512-IXEuxU+5ClW2IGEYFC2T7szbyVgehupCWQe5GNh+H065CD6U6IFN0s4KeAMFGNmQolRU4IV7zGBWSYMmZ8uuqQ==", + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "license": "ISC" }, "node_modules/elliptic": { @@ -4165,10 +4279,11 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" }, "node_modules/emittery": { "version": "0.13.1", @@ -4192,27 +4307,29 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" } }, "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "license": "MIT", "bin": { "envinfo": "dist/cli.js" }, @@ -4221,21 +4338,20 @@ } }, "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -4245,16 +4361,30 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -4265,12 +4395,16 @@ } }, "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { @@ -4335,6 +4469,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -4343,14 +4478,6 @@ "node": ">=8.0.0" } }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", @@ -4371,19 +4498,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -4401,6 +4515,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/eslint/node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -4418,39 +4542,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -4476,22 +4571,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -4508,19 +4587,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -4553,9 +4619,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -4565,10 +4631,21 @@ "node": ">=0.10" } }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -4576,10 +4653,20 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { + "node_modules/esrecurse/node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -4598,6 +4685,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", "engines": { "node": ">=0.8.x" } @@ -4607,6 +4695,7 @@ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, + "license": "MIT", "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -4616,6 +4705,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -4661,12 +4751,13 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", "dependencies": { @@ -4674,16 +4765,30 @@ "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -4692,18 +4797,35 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "license": "MIT", "engines": { "node": ">= 4.9.1" } }, "node_modules/fastq": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", - "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, "license": "ISC", "dependencies": { @@ -4736,6 +4858,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4748,6 +4871,7 @@ "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-2.0.2.tgz", "integrity": "sha512-lO3ttPjHZRfjMcxWKb1j1eDhTFsu4meeR3lnMcnBFhk6RuLhvEiuALu2TlfL310ph4lCYYwgF/ElIjdP739tdg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4773,6 +4897,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -4785,6 +4910,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } @@ -4805,30 +4931,38 @@ } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, "license": "ISC" }, "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/fork-ts-checker-webpack-plugin": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", - "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.16.7", "chalk": "^4.1.2", - "chokidar": "^3.5.3", + "chokidar": "^4.0.1", "cosmiconfig": "^8.2.0", "deepmerge": "^4.2.2", "fs-extra": "^10.0.0", @@ -4840,8 +4974,7 @@ "tapable": "^2.2.1" }, "engines": { - "node": ">=12.13.0", - "yarn": ">=1.0.0" + "node": ">=14.21.3" }, "peerDependencies": { "typescript": ">3.6.0", @@ -4853,6 +4986,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -4867,10 +5001,11 @@ } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -4881,13 +5016,15 @@ "node_modules/free-style": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/free-style/-/free-style-2.5.1.tgz", - "integrity": "sha512-X7dtUSTrlS1KRQBtiQ618NWIRDdRgD91IeajKCSh0fgTqArSixv+n3ea6F/OSvrvg14tPLR+yCq2s+O602+pRw==" + "integrity": "sha512-X7dtUSTrlS1KRQBtiQ618NWIRDdRgD91IeajKCSh0fgTqArSixv+n3ea6F/OSvrvg14tPLR+yCq2s+O602+pRw==", + "license": "MIT" }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -4898,10 +5035,11 @@ } }, "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", + "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", + "dev": true, + "license": "Unlicense" }, "node_modules/fs.realpath": { "version": "1.0.0", @@ -4914,6 +5052,7 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -4926,14 +5065,26 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -4948,16 +5099,22 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -4975,10 +5132,25 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -4990,7 +5162,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -5008,28 +5180,38 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globby": { @@ -5054,12 +5236,13 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5068,7 +5251,8 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", @@ -5078,11 +5262,12 @@ "license": "MIT" }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/has-property-descriptors": { @@ -5090,6 +5275,7 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -5097,23 +5283,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5126,6 +5301,7 @@ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -5137,16 +5313,17 @@ } }, "node_modules/hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" }, "engines": { - "node": ">=4" + "node": ">= 0.10" } }, "node_modules/hash.js": { @@ -5154,6 +5331,7 @@ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -5163,6 +5341,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -5174,6 +5353,7 @@ "version": "4.7.2", "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz", "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==", + "license": "MIT", "dependencies": { "invariant": "^2.2.1", "loose-envify": "^1.2.0", @@ -5187,6 +5367,7 @@ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", "dev": true, + "license": "MIT", "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -5197,6 +5378,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", "dependencies": { "react-is": "^16.7.0" } @@ -5204,7 +5386,8 @@ "node_modules/hoist-non-react-statics/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", @@ -5216,12 +5399,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -5230,6 +5415,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -5242,6 +5428,7 @@ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -5267,7 +5454,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "5.3.2", @@ -5283,16 +5471,18 @@ "version": "9.0.21", "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5309,14 +5499,16 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -5354,12 +5546,14 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { "node": ">=12" } @@ -5368,6 +5562,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -5376,18 +5571,20 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", "dependencies": { "loose-envify": "^1.0.0" } }, "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5399,25 +5596,15 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5426,9 +5613,10 @@ } }, "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -5444,6 +5632,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5467,12 +5656,17 @@ } }, "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5486,6 +5680,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -5498,6 +5693,7 @@ "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3" @@ -5513,6 +5709,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5531,6 +5728,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -5538,10 +5736,30 @@ "node": ">=0.10.0" } }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -5550,12 +5768,13 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, + "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -5565,20 +5784,23 @@ } }, "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5622,15 +5844,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/istanbul-lib-report/node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -5647,9 +5860,9 @@ } }, "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -5658,18 +5871,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", @@ -5685,9 +5886,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", @@ -5711,21 +5912,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-changed-files/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-circus": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", @@ -5757,21 +5943,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-cli": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", @@ -5944,56 +6115,17 @@ "fsevents": "^2.3.2" } }, - "node_modules/jest-haste-map/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, "engines": { - "node": ">=8" - } - }, - "node_modules/jest-haste-map/node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils": { @@ -6136,70 +6268,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-runner/node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/jest-runtime": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", @@ -6265,9 +6333,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6342,30 +6410,25 @@ } }, "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", "dependencies": { "@types/node": "*", + "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6380,17 +6443,19 @@ "version": "3.7.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -6401,9 +6466,9 @@ } }, "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -6422,12 +6487,14 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -6440,6 +6507,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -6448,10 +6516,11 @@ } }, "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -6473,6 +6542,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6512,20 +6582,27 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" }, "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "license": "MIT", "engines": { "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/loader-utils": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -6539,6 +6616,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -6547,14 +6625,16 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -6567,6 +6647,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -6578,6 +6659,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } @@ -6609,13 +6691,25 @@ "node_modules/material-colors": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", - "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==", + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, + "license": "MIT", "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -6627,6 +6721,7 @@ "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", "dev": true, + "license": "Unlicense", "dependencies": { "fs-monkey": "^1.0.4" }, @@ -6637,7 +6732,8 @@ "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", @@ -6667,6 +6763,7 @@ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -6676,15 +6773,17 @@ } }, "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6693,6 +6792,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -6704,6 +6804,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", "engines": { "node": ">=6" } @@ -6712,18 +6813,21 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6741,14 +6845,15 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -6756,6 +6861,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -6779,13 +6885,15 @@ "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" }, "node_modules/node": { "version": "14.21.3", "resolved": "https://registry.npmjs.org/node/-/node-14.21.3.tgz", "integrity": "sha512-58OWd3tZhyABy+OwPGawVKmK5tvlM5Z0TATCSLsiVcIp7NFvMahhzABSkBlnvyiISGcxmainzEAv7L9YJI5EMw==", "hasInstallScript": true, + "license": "ISC", "dependencies": { "node-bin-setup": "^1.0.0" }, @@ -6800,12 +6908,14 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-bin-setup": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.3.tgz", - "integrity": "sha512-opgw9iSCAzT2+6wJOETCpeRYAQxSopqQ2z+N6BXwIMsQQ7Zj5M8MaafQY8JMlolRR6R1UXg2WmhKp0p9lSOivg==" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.4.tgz", + "integrity": "sha512-vWNHOne0ZUavArqPP5LJta50+S8R261Fr5SvGul37HbEDcowvLjwdvd0ZeSr0r2lTSrPxl6okq9QUw8BFGiAxA==", + "license": "ISC" }, "node_modules/node-int64": { "version": "0.4.0", @@ -6818,6 +6928,7 @@ "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-1.1.3.tgz", "integrity": "sha512-yMMGIcVDHN/KT4A+jyGBGojdD1Ht5oIho0CFByEcnsuS0u7euL3Sw9a5s+LLJujP4AP8xSjj/wxBnCj+bluI1A==", "dev": true, + "license": "MIT", "dependencies": { "assert": "^2.0.0", "browserify-zlib": "^0.2.0", @@ -6852,15 +6963,16 @@ } }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6869,6 +6981,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -6880,15 +6993,17 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6901,6 +7016,7 @@ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1" @@ -6917,19 +7033,23 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -6952,6 +7072,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -6984,17 +7105,19 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7004,6 +7127,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -7011,10 +7135,26 @@ "node": ">=8" } }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -7023,13 +7163,15 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "dev": true, + "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -7038,16 +7180,16 @@ } }, "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "dev": true, + "license": "ISC", "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", + "pbkdf2": "^3.1.5", "safe-buffer": "^5.2.1" }, "engines": { @@ -7058,6 +7200,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -7076,6 +7219,7 @@ "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", "dev": true, + "license": "MIT", "dependencies": { "process": "^0.11.1", "util": "^0.10.3" @@ -7085,12 +7229,14 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", "engines": { "node": ">=8" } @@ -7108,6 +7254,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { "node": ">=8" } @@ -7115,13 +7262,15 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7130,37 +7279,42 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/path/node_modules/util": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "2.0.3" } }, "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "dev": true, + "license": "MIT", "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" }, "engines": { - "node": ">=0.12" + "node": ">= 0.10" } }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", @@ -7172,6 +7326,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -7180,9 +7335,9 @@ } }, "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "license": "MIT", "engines": { "node": ">= 6" @@ -7192,6 +7347,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -7199,19 +7355,32 @@ "node": ">=8" } }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -7227,11 +7396,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "peer": true, "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -7242,6 +7412,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -7250,13 +7421,14 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.1.0" }, "engines": { @@ -7267,12 +7439,13 @@ } }, "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", "dev": true, + "license": "ISC", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "postcss-selector-parser": "^7.0.0" }, "engines": { "node": "^10 || ^12 || >= 14" @@ -7286,6 +7459,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -7297,10 +7471,11 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", - "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7312,7 +7487,8 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", @@ -7350,11 +7526,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -7363,7 +7546,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prompts": { "version": "2.4.2", @@ -7382,6 +7566,7 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -7391,13 +7576,15 @@ "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -7408,15 +7595,17 @@ } }, "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", "engines": { "node": ">=6" } @@ -7438,12 +7627,13 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", - "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -7456,6 +7646,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "license": "MIT", "dependencies": { "decode-uri-component": "^0.2.0", "object-assign": "^4.1.0", @@ -7499,6 +7690,7 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz", "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==", + "license": "MIT", "dependencies": { "performance-now": "^2.1.0" } @@ -7507,6 +7699,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -7516,6 +7709,7 @@ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, + "license": "MIT", "dependencies": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" @@ -7525,6 +7719,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0" @@ -7537,6 +7732,7 @@ "version": "2.19.3", "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", + "license": "MIT", "dependencies": { "@icons/material": "^0.2.4", "lodash": "^4.17.15", @@ -7554,6 +7750,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0", @@ -7564,15 +7761,16 @@ } }, "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "peer": true + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.4.tgz", + "integrity": "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==", + "license": "MIT" }, "node_modules/react-portal": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/react-portal/-/react-portal-4.2.2.tgz", "integrity": "sha512-vS18idTmevQxyQpnde0Td6ZcUlv+pD8GTyR42n3CHUQq9OHi1C4jDE4ZWEbEsrbrLRhSECYiao58cvocwMtP7Q==", + "license": "MIT", "dependencies": { "prop-types": "^15.5.8" }, @@ -7585,6 +7783,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.2.tgz", "integrity": "sha512-nBwiscMw3NoP59NFCXFf02f8xdo+vSHT/uZ1ldDwF7XaTpzm+Phk97VT4urYBl5TYAPNVaFm12UHAEyzkpNzRA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.1", "@types/hoist-non-react-statics": "^3.3.1", @@ -7619,10 +7818,17 @@ } } }, + "node_modules/react-redux/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, "node_modules/react-router": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz", "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==", + "license": "MIT", "dependencies": { "history": "^5.2.0" }, @@ -7634,6 +7840,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz", "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==", + "license": "MIT", "dependencies": { "history": "^5.2.0", "react-router": "6.2.1" @@ -7647,6 +7854,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.7.6" } @@ -7655,6 +7863,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.7.6" } @@ -7663,6 +7872,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "license": "MIT", "dependencies": { "lodash": "^4.0.1" } @@ -7672,6 +7882,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7682,21 +7893,24 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, + "license": "MIT", "engines": { - "node": ">=8.10.0" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "license": "MIT", "dependencies": { "resolve": "^1.9.0" }, @@ -7708,6 +7922,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "license": "MIT", "peer": true, "dependencies": { "@babel/runtime": "^7.9.2" @@ -7717,15 +7932,11 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "license": "MIT", "peerDependencies": { "redux": "^4" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7735,23 +7946,37 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/reselect": { "version": "4.1.8", "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", - "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==", + "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7760,6 +7985,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -7771,6 +7997,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", "engines": { "node": ">=8" } @@ -7778,21 +8005,22 @@ "node_modules/resolve-pathname": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", - "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==" + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==", + "license": "MIT" }, "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { @@ -7818,19 +8046,87 @@ } }, "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "dev": true, + "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ripemd160/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/ripemd160/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/ripemd160/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" } }, + "node_modules/ripemd160/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" }, "node_modules/run-parallel": { "version": "1.2.0", @@ -7859,7 +8155,8 @@ "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" }, "node_modules/safe-buffer": { "version": "5.2.1", @@ -7878,17 +8175,38 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } @@ -7915,6 +8233,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -7924,6 +8243,7 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -7933,6 +8253,7 @@ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -7949,25 +8270,35 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", "dev": true, + "license": "(MIT AND BSD-3-Clause)", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -7978,12 +8309,14 @@ "node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -7995,20 +8328,79 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -8020,7 +8412,8 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" }, "node_modules/sisteransi": { "version": "1.0.5", @@ -8041,15 +8434,17 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -8059,6 +8454,7 @@ "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.0.tgz", "integrity": "sha512-GKGWqWvYr04M7tn8dryIWvb0s8YM41z82iQv01yBtIylgxax0CwvSy6gc2Y02iuXwEfGWRlMicH0nvms9UZphw==", "dev": true, + "license": "MIT", "dependencies": { "abab": "^2.0.5", "iconv-lite": "^0.6.2", @@ -8080,14 +8476,16 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -8111,11 +8509,21 @@ "node": ">=10" } }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "~2.0.4", "readable-stream": "^3.5.0" @@ -8126,6 +8534,7 @@ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", "dev": true, + "license": "MIT", "dependencies": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.4", @@ -8137,6 +8546,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8146,6 +8556,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } @@ -8202,6 +8613,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -8223,6 +8635,7 @@ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.2.1.tgz", "integrity": "sha512-1k9ZosJCRFaRbY6hH49JFlRB0fVSbmnyq1iTPjNxUmGVjBNEmwrrHPenhlp+Lgo51BojHSf6pl2FcqYaN3PfVg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.13.0" }, @@ -8235,14 +8648,15 @@ } }, "node_modules/styled-components": { - "version": "5.3.11", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", - "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", + "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", + "license": "MIT", "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^1.1.0", + "@emotion/is-prop-valid": "^0.8.8", "@emotion/stylis": "^0.8.4", "@emotion/unitless": "^0.7.4", "babel-plugin-styled-components": ">= 1.12.0", @@ -8264,10 +8678,20 @@ "react-is": ">= 16.8.0" } }, - "node_modules/supports-color": { + "node_modules/styled-components/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/styled-components/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -8275,10 +8699,23 @@ "node": ">=4" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -8287,20 +8724,26 @@ } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/terser": { - "version": "5.31.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", - "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -8316,6 +8759,7 @@ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.3.tgz", "integrity": "sha512-cxGbMqr6+A2hrIB5ehFIF+F/iST5ZOxvOmy9zih9ySbP1C2oEWQSOUS+2SNBTjzx5xLKO4xnod9eywdfq1Nb9A==", "dev": true, + "license": "MIT", "dependencies": { "jest-worker": "^27.0.2", "p-limit": "^3.1.0", @@ -8335,19 +8779,19 @@ "webpack": "^5.1.0" } }, - "node_modules/terser-webpack-plugin/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 10.13.0" } }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { @@ -8355,6 +8799,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -8368,10 +8813,37 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } }, "node_modules/test-exclude": { "version": "6.0.0", @@ -8399,6 +8871,7 @@ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", "dev": true, + "license": "MIT", "dependencies": { "setimmediate": "^1.0.4" }, @@ -8409,7 +8882,8 @@ "node_modules/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", - "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" }, "node_modules/tmpl": { "version": "1.0.5", @@ -8417,10 +8891,26 @@ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "license": "BSD-3-Clause" }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -8433,6 +8923,7 @@ "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.5.tgz", "integrity": "sha512-al/ATFEffybdRMUIr5zMEWQdVnCGMUA9d3fXJ8dBVvBlzytPvIszoG9kZoR+94k6/i293RnVOXwMaWbXhNy9pQ==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", @@ -8448,10 +8939,11 @@ } }, "node_modules/ts-loader/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -8486,7 +8978,8 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/type-check": { "version": "0.4.0", @@ -8511,9 +9004,10 @@ } }, "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -8522,11 +9016,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/typescript": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, + "license": "Apache-2.0", "peer": true, "bin": { "tsc": "bin/tsc", @@ -8540,6 +9050,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/typestyle/-/typestyle-2.0.1.tgz", "integrity": "sha512-3Mv5ZZbYJ3y3G6rX3iRLrgYibAlafK2nsc9VlTsYcEaK8w+9vtNDx0T2TJsznI5FIh+WoBnjJ5F0/26WaGRxXQ==", + "license": "MIT", "dependencies": { "csstype": "^2.4.0", "free-style": "2.5.1" @@ -8548,26 +9059,29 @@ "node_modules/typestyle/node_modules/csstype": { "version": "2.6.21", "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", - "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==", + "license": "MIT" }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "funding": [ { "type": "opencollective", @@ -8585,7 +9099,7 @@ "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -8598,18 +9112,23 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, "node_modules/url": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", - "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", "dev": true, + "license": "MIT", "dependencies": { "punycode": "^1.4.1", - "qs": "^6.11.2" + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/url-loader": { @@ -8617,6 +9136,7 @@ "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", "dev": true, + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "mime-types": "^2.1.27", @@ -8644,6 +9164,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -8661,14 +9182,16 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/use-sync-external-store": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", - "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/util": { @@ -8676,6 +9199,7 @@ "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", @@ -8688,12 +9212,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/v8-compile-cache": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", - "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==" + "dev": true, + "license": "MIT" }, "node_modules/v8-to-istanbul": { "version": "9.3.0", @@ -8712,13 +9232,15 @@ "node_modules/value-equal": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz", - "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==" + "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==", + "license": "MIT" }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/walker": { "version": "1.0.8", @@ -8733,14 +9255,16 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", "integrity": "sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==", + "license": "BSD-3-Clause", "dependencies": { "loose-envify": "^1.0.0" } }, "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -8750,35 +9274,37 @@ } }, "node_modules/webpack": { - "version": "5.96.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", - "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "version": "5.105.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", + "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", "license": "MIT", "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", + "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -8797,23 +9323,23 @@ } }, "node_modules/webpack-cli": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.2.tgz", - "integrity": "sha512-mEoLmnmOIZQNiRl0ebnjzQ74Hk0iKS5SiEEnpq3dRezoyR3yPaeQZCMCe+db4524pj1Pd5ghZXjT41KLzIhSLw==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "license": "MIT", "peer": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.0.4", - "@webpack-cli/info": "^1.3.0", - "@webpack-cli/serve": "^1.5.1", - "colorette": "^1.2.1", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", "commander": "^7.0.0", - "execa": "^5.0.0", + "cross-spawn": "^7.0.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^2.2.0", "rechoir": "^0.7.0", - "v8-compile-cache": "^2.2.0", "webpack-merge": "^5.7.3" }, "bin": { @@ -8822,6 +9348,10 @@ "engines": { "node": ">=10.13.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, "peerDependencies": { "webpack": "4.x.x || 5.x.x" }, @@ -8844,6 +9374,7 @@ "version": "5.10.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", @@ -8854,21 +9385,73 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "license": "MIT", "engines": { "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 10.13.0" @@ -8887,17 +9470,32 @@ "randombytes": "^2.1.0" } }, + "node_modules/webpack/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/webpack/node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.3.16", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -8925,6 +9523,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -8936,15 +9535,18 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, "engines": { @@ -8957,7 +9559,8 @@ "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "license": "MIT" }, "node_modules/word-wrap": { "version": "1.2.5", @@ -9010,6 +9613,7 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4" } @@ -9026,7 +9630,8 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", @@ -9073,6 +9678,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/src/OpenSEE/package.json b/src/OpenSEE/package.json index ccdc33fb..87b4dcb2 100644 --- a/src/OpenSEE/package.json +++ b/src/OpenSEE/package.json @@ -3,7 +3,10 @@ "name": "opensee", "private": true, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.60.0", + "@typescript-eslint/parser": "^5.60.0", "css-loader": "6.2.0", + "eslint": "^8.43.0", "fork-ts-checker-webpack-plugin": "^9.0.2", "node-polyfill-webpack-plugin": "1.1.3", "path": "0.12.7", @@ -14,15 +17,13 @@ "typescript": "5.5.3", "url-loader": "4.1.1", "webpack": "^5.47.0", - "webpack-cli": "^4.7.2", - "@typescript-eslint/eslint-plugin": "^5.60.0", - "@typescript-eslint/parser": "^5.60.0", - "eslint": "^8.43.0" + "webpack-cli": "^4.7.2" }, "dependencies": { + "@gpa-gemstone/gpa-symbols": "0.0.43", "@gpa-gemstone/react-forms": "1.1.75", "@gpa-gemstone/react-interactive": "1.0.135", - "@gpa-gemstone/gpa-symbols": "0.0.43", + "@popperjs/core": "^2.11.8", "@reduxjs/toolkit": "1.8.3", "@types/d3": "7.0.0", "@types/eonasdan-bootstrap-datetimepicker": "4.17.26", @@ -34,9 +35,9 @@ "@types/react": "^17.0.19", "@types/react-dom": "16.8.3", "@types/react-router-dom": "4.3.1", + "bootstrap": "4.6.2", "d3": "7.4.2", "history": "4.7.2", - "jquery": "3.7.1", "lodash": "^4.17.21", "moment": "2.30.1", "node": "^14.0.0", @@ -48,11 +49,11 @@ "react-redux": "8.0.2", "react-router-dom": "6.2.1", "reselect": "^4.0.0", - "styled-components": "^5.3.3", "typestyle": "2.0.1" }, "scripts": { "build": "npm prune && npm ci && webpack --mode=development", + "builddev": "webpack --mode=development", "buildrelease": "npm prune && npm ci && webpack --mode=production", "watch": "webpack --watch --color --mode=development", "update": "npx npm-check-updates", diff --git a/src/OpenSEE/packages.config b/src/OpenSEE/packages.config deleted file mode 100644 index b951020d..00000000 --- a/src/OpenSEE/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/OpenSEE/tsconfig.json b/src/OpenSEE/tsconfig.json index ce886a01..de72e82a 100644 --- a/src/OpenSEE/tsconfig.json +++ b/src/OpenSEE/tsconfig.json @@ -17,5 +17,5 @@ "exclude": [ "node_modules" ], - "include": [ "Scripts/TSX", "Scripts/TS/*" ] + "include": [ "wwwroot/Scripts/TSX", "wwwroot/Scripts/TS/*" ] } diff --git a/src/OpenSEE/webpack.config.js b/src/OpenSEE/webpack.config.js index 8bcba5c1..1e6cebd1 100644 --- a/src/OpenSEE/webpack.config.js +++ b/src/OpenSEE/webpack.config.js @@ -3,6 +3,7 @@ const path = require("path"); const NodePolyfillPlugin = require("node-polyfill-webpack-plugin"); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin'); +var webpack = require('webpack'); function buildConfig(env, argv) { if (env.NODE_ENV == undefined) env.NODE_ENV = 'development'; @@ -12,20 +13,10 @@ function buildConfig(env, argv) { context: path.resolve(__dirname), cache: true, entry: { - OpenSee: "./Scripts/TSX/OpenSee.tsx", - ToolTipDeltaWidget: "./Scripts/TSX/jQueryUI Widgets/TooltipWithDelta.tsx", - ToolTipWidget: "./Scripts/TSX/jQueryUI Widgets/Tooltip.tsx", - TimeCorrelatedSagsWidget: "./Scripts/TSX/jQueryUI Widgets/TimeCorrelatedSags.tsx", - PointWidget: "./Scripts/TSX/jQueryUI Widgets/AccumulatedPoints.tsx", - PhasorChartWidget: "./Scripts/TSX/jQueryUI Widgets/PhasorChart.tsx", - ScalarStatsWidget: "./Scripts/TSX/jQueryUI Widgets/ScalarStats.tsx", - LightningDataWidget: "./Scripts/TSX/jQueryUI Widgets/LightningData.tsx", - SettingsWidget: "./Scripts/TSX/jQueryUI Widgets/SettingWindow.tsx", - FFTTable: "./Scripts/TSX/jQueryUI Widgets/FFTTable.tsx", - HarmonicStatsWidget: "./Scripts/TSX/jQueryUI Widgets/HarmonicStats.tsx", + OpenSee: "./wwwroot/Scripts/TSX/OpenSee.tsx" }, output: { - path: path.resolve(__dirname, 'Scripts'), + path: path.resolve(__dirname, './wwwroot/Scripts'), filename: "[name].js", }, // Enable sourcemaps for debugging webpack's output. @@ -39,12 +30,11 @@ function buildConfig(env, argv) { // All files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'. { test: /\.tsx?$/, - include: path.resolve(__dirname, "Scripts"), + include: path.resolve(__dirname, 'wwwroot', "Scripts"), loader: "ts-loader", options: { transpileOnly: true } }, { test: /\.css$/, - include: path.resolve(__dirname, 'wwwroot', "Content"), use: [{ loader: 'style-loader' }, { loader: 'css-loader' }], }, //{ @@ -64,7 +54,11 @@ function buildConfig(env, argv) { }, plugins: [ new NodePolyfillPlugin(), - new ForkTsCheckerWebpackPlugin() + new ForkTsCheckerWebpackPlugin(), + new webpack.ProvidePlugin({ + $: "jquery", + "window.jQuery": "jquery", + }) ] }; diff --git a/src/OpenSEE/Content/bootstrap4-datetimepicker.css b/src/OpenSEE/wwwroot/Content/bootstrap4-datetimepicker.css similarity index 100% rename from src/OpenSEE/Content/bootstrap4-datetimepicker.css rename to src/OpenSEE/wwwroot/Content/bootstrap4-datetimepicker.css diff --git a/src/OpenSEE/Images/2-Line - 500.png b/src/OpenSEE/wwwroot/Images/2-Line - 500.png similarity index 100% rename from src/OpenSEE/Images/2-Line - 500.png rename to src/OpenSEE/wwwroot/Images/2-Line - 500.png diff --git a/src/OpenSEE/Images/openSEE - Waveform Viewer Header.png b/src/OpenSEE/wwwroot/Images/openSEE - Waveform Viewer Header.png similarity index 100% rename from src/OpenSEE/Images/openSEE - Waveform Viewer Header.png rename to src/OpenSEE/wwwroot/Images/openSEE - Waveform Viewer Header.png diff --git a/src/OpenSEE/Images/openSEE.jpg b/src/OpenSEE/wwwroot/Images/openSEE.jpg similarity index 100% rename from src/OpenSEE/Images/openSEE.jpg rename to src/OpenSEE/wwwroot/Images/openSEE.jpg diff --git a/src/OpenSEE/Images/openSEELogo.png b/src/OpenSEE/wwwroot/Images/openSEELogo.png similarity index 100% rename from src/OpenSEE/Images/openSEELogo.png rename to src/OpenSEE/wwwroot/Images/openSEELogo.png diff --git a/src/OpenSEE/Scripts/TSX/Components/About.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Components/About.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Components/About.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Components/About.tsx diff --git a/src/OpenSEE/Scripts/TSX/Components/AnalyticOptions.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Components/AnalyticOptions.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Components/AnalyticOptions.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Components/AnalyticOptions.tsx diff --git a/src/OpenSEE/Scripts/TSX/Components/Menu.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Components/Menu.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Components/Menu.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Components/Menu.tsx diff --git a/src/OpenSEE/Scripts/TSX/Components/OpenSEENavbar.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Components/OpenSEENavbar.tsx similarity index 99% rename from src/OpenSEE/Scripts/TSX/Components/OpenSEENavbar.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Components/OpenSEENavbar.tsx index 05464fcc..5eb985b2 100644 --- a/src/OpenSEE/Scripts/TSX/Components/OpenSEENavbar.tsx +++ b/src/OpenSEE/wwwroot/Scripts/TSX/Components/OpenSEENavbar.tsx @@ -82,10 +82,10 @@ const OpenSeeNavBar = (props: IProps) => { } return () => { } - }, [props.OpenDrawers.AccumulatedPoints]) + }, [props.OpenDrawers.AccumulatedPoints]); function exportData(type) { - window.open(homePath + `CSVDownload.ashx?type=${type}&eventID=${eventID}` + + const uri = homePath + `api/CSV/Download?type=${type}&eventID=${eventID}` + `${showPlots.Voltage != undefined ? `&displayVolt=${showPlots.Voltage}` : ``}` + `${showPlots.Current != undefined ? `&displayCur=${showPlots.Current}` : ``}` + `${showPlots.TripCoil != undefined ? `&displayTCE=${showPlots.TripCoil}` : ``}` + @@ -99,9 +99,9 @@ const OpenSeeNavBar = (props: IProps) => { `${type == 'fft' ? `&startDate=${fftTime[0]}` : ``}` + `${type == 'fft' ? `&cycles=${cycles}` : ``}` + `&Meter=${eventInfo.MeterName}` + - `&EventType=${eventInfo.EventName}` - ); - } + `&EventType=${eventInfo.EventName}`; + window.open(uri, '_blank'); + }; return ( <> diff --git a/src/OpenSEE/Scripts/TSX/Components/OverlappingEvents.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Components/OverlappingEvents.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Components/OverlappingEvents.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Components/OverlappingEvents.tsx diff --git a/src/OpenSEE/Scripts/TSX/Context/HoverContext.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Context/HoverContext.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Context/HoverContext.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Context/HoverContext.tsx diff --git a/src/OpenSEE/Scripts/TSX/Context/HoverProvider.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Context/HoverProvider.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Context/HoverProvider.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Context/HoverProvider.tsx diff --git a/src/OpenSEE/Scripts/TSX/Graphs/BarChartBase.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Graphs/BarChartBase.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Graphs/BarChartBase.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Graphs/BarChartBase.tsx diff --git a/src/OpenSEE/Scripts/TSX/Graphs/ChartIcons.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Graphs/ChartIcons.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Graphs/ChartIcons.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Graphs/ChartIcons.tsx diff --git a/src/OpenSEE/Scripts/TSX/Graphs/LegendBase.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Graphs/LegendBase.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Graphs/LegendBase.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Graphs/LegendBase.tsx diff --git a/src/OpenSEE/Scripts/TSX/Graphs/LineChartBase.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Graphs/LineChartBase.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Graphs/LineChartBase.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Graphs/LineChartBase.tsx diff --git a/src/OpenSEE/Scripts/TSX/Graphs/Utilities.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/Graphs/Utilities.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/Graphs/Utilities.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/Graphs/Utilities.tsx diff --git a/src/OpenSEE/Scripts/TSX/defaults.ts b/src/OpenSEE/wwwroot/Scripts/TSX/defaults.ts similarity index 100% rename from src/OpenSEE/Scripts/TSX/defaults.ts rename to src/OpenSEE/wwwroot/Scripts/TSX/defaults.ts diff --git a/src/OpenSEE/Scripts/TSX/global.d.ts b/src/OpenSEE/wwwroot/Scripts/TSX/global.d.ts similarity index 99% rename from src/OpenSEE/Scripts/TSX/global.d.ts rename to src/OpenSEE/wwwroot/Scripts/TSX/global.d.ts index 7c1697b3..3906e91b 100644 --- a/src/OpenSEE/Scripts/TSX/global.d.ts +++ b/src/OpenSEE/wwwroot/Scripts/TSX/global.d.ts @@ -25,7 +25,6 @@ // global variables declared in openSEE.cshtml scripts section declare global { var homePath: string; - var userIsAdmin: boolean; var eventID: number; var eventStartTime: string; var eventEndTime: string; diff --git a/src/OpenSEE/Scripts/TSX/hooks.ts b/src/OpenSEE/wwwroot/Scripts/TSX/hooks.ts similarity index 100% rename from src/OpenSEE/Scripts/TSX/hooks.ts rename to src/OpenSEE/wwwroot/Scripts/TSX/hooks.ts diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/AccumulatedPoints.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/AccumulatedPoints.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/AccumulatedPoints.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/AccumulatedPoints.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/EventInfo.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/EventInfo.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/EventInfo.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/EventInfo.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/FFTTable.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/FFTTable.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/FFTTable.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/FFTTable.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/HarmonicStats.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/HarmonicStats.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/HarmonicStats.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/HarmonicStats.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/LightningData.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/LightningData.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/LightningData.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/LightningData.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/PhasorChart.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/PhasorChart.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/PhasorChart.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/PhasorChart.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/ScalarStats.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/ScalarStats.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/ScalarStats.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/ScalarStats.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/SettingWindow.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/SettingWindow.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/SettingWindow.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/SettingWindow.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/TimeCorrelatedSags.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/TimeCorrelatedSags.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/TimeCorrelatedSags.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/TimeCorrelatedSags.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/Tooltip.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/Tooltip.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/Tooltip.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/Tooltip.tsx diff --git a/src/OpenSEE/Scripts/TSX/jQueryUI Widgets/TooltipWithDelta.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/TooltipWithDelta.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/jQueryUI Widgets/TooltipWithDelta.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/jQueryUI Widgets/TooltipWithDelta.tsx diff --git a/src/OpenSEE/Scripts/TSX/openSEE.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/openSEE.tsx similarity index 99% rename from src/OpenSEE/Scripts/TSX/openSEE.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/openSEE.tsx index 939fb990..bac2da8c 100644 --- a/src/OpenSEE/Scripts/TSX/openSEE.tsx +++ b/src/OpenSEE/wwwroot/Scripts/TSX/openSEE.tsx @@ -27,6 +27,7 @@ // # Fix Dowload.ash to include Analytics // +import 'bootstrap/dist/css/bootstrap.min.css'; import { Application, SplitDrawer, SplitSection, VerticalSplit } from '@gpa-gemstone/react-interactive'; import moment from 'moment' import * as React from 'react'; @@ -217,7 +218,7 @@ const OpenSeeHome = () => { }; function exportData(type) { - window.open(homePath + `CSVDownload.ashx?type=${type}&eventID=${eventID}` + + const uri = homePath + `api/CSV/Download?type=${type}&eventID=${eventID}` + `${showPlots.Voltage != undefined ? `&displayVolt=${showPlots.Voltage}` : ``}` + `${showPlots.Current != undefined ? `&displayCur=${showPlots.Current}` : ``}` + `${showPlots.TripCoil != undefined ? `&displayTCE=${showPlots.TripCoil}` : ``}` + @@ -226,8 +227,8 @@ const OpenSeeHome = () => { `${type == 'fft' ? `&startDate=${fftTime[0]}` : ``}` + `${type == 'fft' ? `&cycles=${cycles}` : ``}` + `&Meter=${eventInfo.MeterName}` + - `&EventType=${eventInfo.MeterName}` - ); + `&EventType=${eventInfo.MeterName}`; + window.open(uri, "_blank"); } return ( diff --git a/src/OpenSEE/Scripts/TSX/store/GraphLogic.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/store/GraphLogic.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/store/GraphLogic.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/store/GraphLogic.tsx diff --git a/src/OpenSEE/Scripts/TSX/store/RequestHandler.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/store/RequestHandler.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/store/RequestHandler.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/store/RequestHandler.tsx diff --git a/src/OpenSEE/Scripts/TSX/store/analyticSlice.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/store/analyticSlice.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/store/analyticSlice.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/store/analyticSlice.tsx diff --git a/src/OpenSEE/Scripts/TSX/store/dataSlice.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/store/dataSlice.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/store/dataSlice.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/store/dataSlice.tsx diff --git a/src/OpenSEE/Scripts/TSX/store/eventInfoSlice.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/store/eventInfoSlice.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/store/eventInfoSlice.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/store/eventInfoSlice.tsx diff --git a/src/OpenSEE/Scripts/TSX/store/overlappingEventsSlice.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/store/overlappingEventsSlice.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/store/overlappingEventsSlice.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/store/overlappingEventsSlice.tsx diff --git a/src/OpenSEE/Scripts/TSX/store/queryThunk.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/store/queryThunk.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/store/queryThunk.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/store/queryThunk.tsx diff --git a/src/OpenSEE/Scripts/TSX/store/settingSlice.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/store/settingSlice.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/store/settingSlice.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/store/settingSlice.tsx diff --git a/src/OpenSEE/Scripts/TSX/store/store.tsx b/src/OpenSEE/wwwroot/Scripts/TSX/store/store.tsx similarity index 100% rename from src/OpenSEE/Scripts/TSX/store/store.tsx rename to src/OpenSEE/wwwroot/Scripts/TSX/store/store.tsx