예제 #1
0
        public void ConstructionWithOnlyEditTimestampCreatesNewList()
        {
            var testState = new SensorState(_testSensor, DateTime.Now.AddDays(20));

            Assert.NotNull(testState.Values);
            Assert.IsTrue(testState.Values.Count == 0);
        }
예제 #2
0
 public void AddStateTest()
 {
     _testUndoStates.Clear();
     var state = new SensorState(_sensor1, DateTime.Now);
     _sensor1.AddState(state);
     Assert.AreEqual(state, _sensor1.CurrentState);
     Assert.IsEmpty(_sensor1.RedoStates);
 }
예제 #3
0
        public SensorState Clone()
        {
            var d = _valueList.ToDictionary(v => v.Key, v => v.Value);
            var c = _changes.ToDictionary(v => v.Key, v => v.Value);
            var s = new SensorState(_owner, d, c);

            return(s);
        }
예제 #4
0
파일: Sensor.cs 프로젝트: zhangzheng1205/B3
        /// <summary>
        /// Advance data values for this sensor to the next state stored.
        /// </summary>
        public void Redo()
        {
            if (RedoStack.Count == 0)
            {
                throw new InvalidOperationException("Redo is not possible at this stage. There are no more possible states to redo to.");
            }

            UndoStack.Push(CurrentState);
            _currentState = RedoStack.Pop();
        }
예제 #5
0
파일: Sensor.cs 프로젝트: zhangzheng1205/B3
        /// <summary>
        /// Revert data values for this sensor to the previous state held.
        /// </summary>
        public void Undo()
        {
            // This is because the undo stack has to have at least one item on it - the current state
            if (UndoStack.Count == 0)
            {
                throw new InvalidOperationException("Undo is not possible at this stage. There are no more possible states to undo to.");
            }

            RedoStack.Push(CurrentState);
            _currentState = UndoStack.Pop();
        }
        public void DetectNonFailingSensorBoundary()
        {
            var sensorState = new SensorState(_temperatureSensor, DateTime.Now, new Dictionary<DateTime, float>(), null);

            sensorState.Values.Add(DateTime.Now, 22.3f);
            sensorState.Values.Add(DateTime.Now.AddDays(3), 5);

            _temperatureSensor.AddState(sensorState);

            var ds = new Dataset(_site, new List<Sensor> { _temperatureSensor });

            Assert.IsFalse(_temperatureSensor.IsFailing(ds));
        }
예제 #7
0
파일: Sensor.cs 프로젝트: zhangzheng1205/B3
        /// <summary>
        /// Update the active state for data values, clearing the redo stack in the process.
        /// </summary>
        /// <param name="newState"></param>
        public void AddState(SensorState newState)
        {
            if (_rawData == null)
            {
                RawData = newState;
            }
            else
            {
                UndoStack.Push(CurrentState);
                RedoStack.Clear();

                _currentState = newState;
            }
        }
        public void DetectFailingSensorNonConsecutiveValues()
        {
            var sensorState = new SensorState(_temperatureSensor, DateTime.Now, new Dictionary<DateTime, float>(), null);
            sensorState.Values.Add(DateTime.Now.AddDays(2), 22.5f);
            sensorState.Values.Add(DateTime.Now.AddDays(7), 23.3f);
            sensorState.Values.Add(DateTime.Now.AddDays(8), 4);
            sensorState.Values.Add(DateTime.Now.AddDays(9), 4);

            _temperatureSensor.AddState(sensorState);

            var ds = new Dataset(_site, new List<Sensor> { _temperatureSensor });

            Assert.IsTrue(_temperatureSensor.IsFailing(ds));
        }
        public void DetectFailingSensorConsecutiveValuesBoundary()
        {
            var sensorState = new SensorState(_temperatureSensor, DateTime.Now, new Dictionary<DateTime, float>(), null);

            sensorState.Values.Add(DateTime.Now, 22.3f);
            sensorState.Values.Add(DateTime.Now.AddDays(5), 4);
            sensorState.Values.Add(DateTime.Now.AddDays(6), 4);
            sensorState.Values.Add(DateTime.Now.AddDays(7), 4);

            _temperatureSensor.AddState(sensorState);

            var ds = new Dataset(_site, new List<Sensor> { _temperatureSensor });
            ds.DataInterval = 60 * 24;

            Assert.IsTrue(_temperatureSensor.IsFailing(ds));
        }
예제 #10
0
 public void FindMissingValuesTest()
 {
     var missingDates = new List<DateTime>
                            {
                                new DateTime(2011, 8, 20, 0, 15, 0),
                                new DateTime(2011, 8, 20, 0, 30, 0),
                                new DateTime(2011, 8, 20, 0, 45, 0),
                                new DateTime(2011, 8, 20, 1, 0, 0),
                                new DateTime(2011, 8, 20, 1, 15, 0),
                                new DateTime(2011, 8, 20, 1, 30, 0),
                                new DateTime(2011, 8, 20, 1, 45, 0)
                            };
     var sensorState = new SensorState(_testSensor, new DateTime(2011, 8, 23, 0, 0, 0));
     sensorState.Values = new Dictionary<DateTime, float>
                              {
                                  {new DateTime(2011, 8, 20, 0, 0, 0), 100},
                                  {new DateTime(2011, 8, 20, 2, 0, 0), 50}
                              };
     Assert.AreEqual(missingDates, sensorState.GetMissingTimes(15, new DateTime(2011, 8, 20, 0, 0, 0), new DateTime(2011, 8, 20, 2, 0, 0)));
 }
예제 #11
0
        public void EqualityTest()
        {
            var a = new SensorState(_testSensor, baseDate,
                                    new Dictionary<DateTime, float> { { baseDate.AddMinutes(15), 200 }, { baseDate.AddMinutes(30), 200 }, { baseDate.AddMinutes(45), 200 }, { baseDate.AddMinutes(60), 200 } }, null);
            var b = new SensorState(_testSensor, baseDate,
                                    new Dictionary<DateTime, float> { { baseDate.AddMinutes(15), 200 }, { baseDate.AddMinutes(30), 200 }, { baseDate.AddMinutes(45), 200 }, { baseDate.AddMinutes(60), 200 } }, null);
            var c = new SensorState(_testSensor, baseDate,
                                    new Dictionary<DateTime, float> { { baseDate.AddMinutes(15), 200 }, { baseDate.AddMinutes(30), 10 }, { baseDate.AddMinutes(45), 200 }, { baseDate.AddMinutes(60), 50 } }, null);
            var d = new SensorState(_testSensor, baseDate,
                                    new Dictionary<DateTime, float> { { baseDate.AddMinutes(15), 200 }, { baseDate.AddMinutes(30), 200 }, { baseDate.AddMinutes(45), 200 }, { baseDate.AddMinutes(60), 200 } }, null);
            var e = new SensorState(_testSensor, baseDate.AddHours(50),
                                    new Dictionary<DateTime, float> { { baseDate.AddMinutes(15), 200 }, { baseDate.AddMinutes(30), 200 }, { baseDate.AddMinutes(45), 200 }, { baseDate.AddMinutes(60), 200 } }, null);
            var f = new SensorState(_testSensor, baseDate,
                                    new Dictionary<DateTime, float> { { baseDate.AddMinutes(45), 200 }, { baseDate.AddMinutes(60), 200 }, { baseDate.AddMinutes(75), 200 }, { baseDate.AddMinutes(90), 200 } }, null);

            Assert.AreEqual(a, b);
            Assert.AreNotEqual(b, c);
            Assert.AreNotEqual(c, d);
            Assert.AreNotEqual(d, e);
            Assert.AreNotEqual(e, f);
        }
예제 #12
0
        public void ExportAsCSVCorrectValueCount()
        {
            var dateTime = new DateTime(2011, 8, 4, 0, 0, 0);
            var givenDataSet = new Dataset(new Site(1, "Steven", "Kerry", Contact, Contact, new GPSCoords(0, 0, "arcGis")));
            var sampleData = new Dictionary<DateTime, float> { { dateTime.AddMinutes(15), 100 }, { dateTime.AddMinutes(30), 100 }, { dateTime.AddMinutes(45), 100 }, { dateTime.AddMinutes(60), 100 } };
            var s = new Sensor("Awesome Sensor", "Awesome");
            var ss = new SensorState(s, DateTime.Now, sampleData, null);
            s.AddState(ss);
            givenDataSet.AddSensor(s);

            Assert.AreEqual(4, givenDataSet.ExpectedDataPointCount);

            dateTime = new DateTime(2011, 8, 4, 0, 0, 0);
            givenDataSet = new Dataset(new Site(1, "Steven", "Kerry", Contact, Contact, new GPSCoords(0, 0, "arcGis")));

            sampleData = new Dictionary<DateTime, float> { { dateTime.AddMinutes(60), 100 }, { dateTime.AddMinutes(75), 100 }, { dateTime.AddMinutes(90), 100 }, { dateTime.AddMinutes(105), 100 } };
            s = new Sensor("Awesome Sensor", "Awesome");
            ss = new SensorState(s, DateTime.Now, sampleData, null);
            s.AddState(ss);
            givenDataSet.AddSensor(s);

            Assert.AreEqual(4, givenDataSet.ExpectedDataPointCount);
        }
예제 #13
0
파일: Sensor.cs 프로젝트: rwlamont/AllItUp
        /// <summary>
        /// Revert data values for this sensor to the previous state held.
        /// </summary>
        public void Undo()
        {
            // This is because the undo stack has to have at least one item on it - the current state
            if (UndoStack.Count == 0)
                throw new InvalidOperationException("Undo is not possible at this stage. There are no more possible states to undo to.");

            RedoStack.Push(CurrentState);
            _currentState = UndoStack.Pop();
        }
예제 #14
0
파일: Sensor.cs 프로젝트: rwlamont/AllItUp
 public void RevertToRaw()
 {
     EventLogger.LogSensorInfo(Owner, Name, "Reverted to raw");
     _currentState = null;
 }
예제 #15
0
 public void AllowConstructionWithOnlyEditTimestamp()
 {
     var testState = new SensorState(_testSensor, DateTime.Now);
     Assert.Pass();
 }
예제 #16
0
        /// <summary>
        /// Returns a calibrated state
        /// </summary>
        /// <param name="start">The start timestamp for the calibration</param>
        /// <param name="end">The end timestamp for the calibration</param>
        /// <param name="origA">The original high</param>
        /// <param name="origB">The original low</param>
        /// <param name="newA">The calibrated high</param>
        /// <param name="newB">The calibrated low</param>
        /// <param name="reason">The reason for the calibration</param>
        /// <returns>The calibrated sensor state</returns>
        public SensorState Calibrate(DateTime start, DateTime end, double origA, double origB, double newA, double newB, ChangeReason reason)
        {
            if (start >= end)
            {
                throw new ArgumentException("End time must be greater than start time");
            }

            if (origB > origA)
            {
                throw new ArgumentException("Calibrated B value must be less than the calibrated A value");
            }

            if (newB > newA)
            {
                throw new ArgumentException("Current B value must be less than the current A value");
            }

            //The total minutes in the time span
            double totalMinutes = end.Subtract(start).TotalMinutes;

            //The distance from the median line to the A and B points
            double origMedianDistance = (origA - origB) / 2;
            double newMedianDistance  = (newA - newB) / 2;

            //The largest distance the points must move to normalise them with the median line
            double normalisationDistance = newMedianDistance - origMedianDistance;

            //The largest distance the points must move from the normalised position, to the calibrated (correct) position
            double calibrationDistance = (newB + newMedianDistance) - (origB + origMedianDistance);

            //The increment that must be made per minute to normalise the points above and below the median line
            double normalisationIncrement = normalisationDistance / totalMinutes;
            double calibrationIncrement   = calibrationDistance / totalMinutes;

            //The gradients of the lines
            double slopeA      = (newA - origA) / totalMinutes;
            double slopeMedian = ((newB + newMedianDistance) - (origB + origMedianDistance)) / totalMinutes;

            //The y-intercepts of the lines
            double interceptA      = origA;
            double interceptMedian = origB + origMedianDistance;

            //Copy!
            SensorState newState = Clone();

            foreach (var value in Values)
            {
                if (value.Key < start || value.Key > end)
                {
                    continue;
                }

                double timeDiff           = value.Key.Subtract(start).TotalMinutes;
                double normalisationScale = GetRelativePositionBetweenLines(interceptA, interceptMedian, slopeA, slopeMedian, timeDiff, value.Value);

                newState.Values[value.Key] = (float)(value.Value - (normalisationScale * normalisationIncrement + calibrationIncrement) * timeDiff);
                newState.AddToChanges(value.Key, reason.ID);
            }

            return(newState);
        }
예제 #17
0
        public void MultipleValuesMadeZero()
        {
            var date = new DateTime(2011, 7, 7, 12, 15, 0);

            var list = new List<DateTime>();
            list.Add(date.AddMinutes(15));
            list.Add(date.AddMinutes(30));
            list.Add(date.AddMinutes(45));

            var oldState = new SensorState(_testSensor, DateTime.Now, new Dictionary<DateTime, float>(), null);
            oldState.Values.Add(date, 5000);

            var newState = oldState.MakeZero(list, new ChangeReason(0, "Test"));

            Assert.AreNotEqual(0, newState.Values[date]);
            Assert.AreEqual(0, newState.Values[list[0]]);
            Assert.AreEqual(0, newState.Values[list[1]]);
            Assert.AreEqual(0, newState.Values[list[2]]);
        }
예제 #18
0
        public void SetRawData()
        {
            var s = new Sensor("Temperature", "C");
            var baseDate = new DateTime(2011, 5, 5, 12, 15, 0);
            var original = new SensorState(s, new Dictionary<DateTime, float>() { { baseDate.AddMinutes(15), 20 }, { baseDate.AddMinutes(30), 40 }, { baseDate.AddMinutes(45), 60 }, { baseDate.AddMinutes(60), 80 } }, null);

            foreach (KeyValuePair<DateTime, float> kv in original.Values)
                s.RawData.Values.Add(kv.Key, kv.Value);

            Assert.AreEqual(s.RawData, original);
        }
예제 #19
0
 public void NullZeroValueList()
 {
     var oldState = new SensorState(_testSensor, DateTime.Now, new Dictionary<DateTime, float>(), null);
     oldState.MakeZero(null, new ChangeReason(0, "Test"));
 }
예제 #20
0
        public void SetsChangeReasonCorrectly()
        {
            var s = new SensorState(_testSensor, DateTime.Now,
                                    new Dictionary<DateTime, float> { { new DateTime(2011, 5, 7, 12, 20, 0), 200 } }, null);
            Assert.AreEqual(null, s.Reason);

            s.Reason = _reason;
            Assert.AreEqual(_reason, s.Reason);
        }
예제 #21
0
        private bool AllDataValuesCorrect(SensorState sensorState, Dictionary<DateTime, float> listOfValues)
        {
            if (sensorState.Values.Count != listOfValues.Count)
                return false;

            //for (int i = 0; i < listOfValues.Count; i++)
            //    if (!sensorState.Values[i].Equals(listOfValues[i]))
            //        return false;
            foreach (var key in listOfValues.Keys)
            {
                if (!listOfValues.Keys.Contains(key))
                    return false;
                if (!sensorState.Values[key].Equals(listOfValues[key]))
                    return false;
            }

            return true;
        }
예제 #22
0
        public void SetsRawCorrectlyOnConstruction()
        {
            var testState = new SensorState(_testSensor, DateTime.Now, new Dictionary<DateTime, float>(), null, true, null);
            Assert.IsTrue(testState.IsRaw);

            testState = new SensorState(_testSensor, DateTime.Now, new Dictionary<DateTime, float>(), null, false, null);
            Assert.IsTrue(!testState.IsRaw);
        }
예제 #23
0
        public void SingleValueMadeZero()
        {
            var date = new DateTime(2011, 7, 7, 12, 15, 0);

            var list = new List<DateTime>();
            list.Add(date);

            var oldState = new SensorState(_testSensor, DateTime.Now, new Dictionary<DateTime, float>(), null);
            var newState = oldState.MakeZero(list, new ChangeReason(0, "Test"));

            Assert.AreEqual(0, newState.Values[date]);
        }
예제 #24
0
        public void SingleValueMadeDifferentValue()
        {
            // TODO: could move these to SetUp
            var date = new DateTime(2011, 7, 7, 12, 15, 0);

            var list = new List<DateTime>();
            list.Add(date);

            var oldState = new SensorState(_testSensor, DateTime.Now, new Dictionary<DateTime, float>(), null);
            var newState = oldState.MakeValue(list, 5, new ChangeReason(0, "Test"));

            Assert.AreEqual(5, newState.Values[date]);
        }
예제 #25
0
        public void SetValues()
        {
            SensorState valueSensorState = new SensorState(_testSensor, testDate, valueList, null);
            valueSensorState.Values = valueList;
            Assert.IsTrue(AllDataValuesCorrect(valueSensorState, valueList));

            SensorState secondValueSensorState = new SensorState(_testSensor, modifiedDate, secondValueList, null);
            secondValueSensorState.Values = secondValueList;
            Assert.IsTrue(AllDataValuesCorrect(secondValueSensorState, secondValueList));
        }
        public void SensorStateWithNoValues()
        {
            var sensorState = new SensorState(_temperatureSensor, DateTime.Now, new Dictionary<DateTime, float>(), null);

            _temperatureSensor.AddState(sensorState);

            var ds = new Dataset(_site, new List<Sensor> { _temperatureSensor });

            Assert.IsFalse(_temperatureSensor.IsFailing(ds));
        }
예제 #27
0
        public void SetEditTimestamp()
        {
            SensorState modifiedSensorState = new SensorState(_testSensor, testDate);
            modifiedSensorState.EditTimestamp = modifiedDate;

            Assert.IsTrue(DateTime.Compare(modifiedDate, modifiedSensorState.EditTimestamp) == 0);

            SensorState augustSensorState = new SensorState(_testSensor, modifiedDate);
            augustSensorState.EditTimestamp = testDate;
            Assert.IsTrue(DateTime.Compare(testDate, augustSensorState.EditTimestamp) == 0);
        }
예제 #28
0
 /// <summary>
 /// Creates a preview of the state given
 /// </summary>
 /// <param name="stateToPreview">The state to preview</param>
 public void GeneratePreview(SensorState stateToPreview)
 {
     PreviewDataPoints = !BoundsSet ? (from dataValue in stateToPreview.Values select new DataPoint <DateTime, float>(dataValue.Key, dataValue.Value)).OrderBy(dataPoint => dataPoint.X) : (from dataValue in stateToPreview.Values where dataValue.Key >= LowerBound && dataValue.Key <= UpperBound select new DataPoint <DateTime, float>(dataValue.Key, dataValue.Value)).OrderBy(dataPoint => dataPoint.X);
 }
예제 #29
0
 public void NullValueList()
 {
     var testState = new SensorState(_testSensor, DateTime.Now, null, null);
 }
예제 #30
0
        public SensorState Clone()
        {
            var d = _valueList.ToDictionary(v => v.Key, v => v.Value);
            var c = _changes.ToDictionary(v => v.Key, v => v.Value);
            var s = new SensorState(_owner, d, c);

            return s;
        }
예제 #31
0
        public void Setup()
        {
            _testUndoStates = new Stack<SensorState>();

            var testState = new SensorState(null, new DateTime(2010, 5, 7, 18, 42, 0));
            var secondaryTestState = new SensorState(null, new DateTime(2010, 12, 18, 5, 22, 0));

            _testUndoStates.Push(testState);
            _testUndoStates.Push(secondaryTestState);

            _secondUndoStates = new Stack<SensorState>();
            _secondUndoStates.Push(new SensorState(null, new DateTime(2005, 4, 3, 2, 1, 0)));
            _secondUndoStates.Push(new SensorState(null, new DateTime(2005, 4, 4, 2, 1, 0)));

            _tempSensor = new Sensor("Temperature", "C");

            // Initialise sensors for undo testing
            _undoSensor = new Sensor("Temperature", "C");
            _undoSensor.AddState(new SensorState(_undoSensor, new DateTime(2011, 8, 11),
                                                       new Dictionary<DateTime, float> { { new DateTime(2011, 8, 12), 66.77f } }, null));
            _undoSensor.AddState(new SensorState(_undoSensor, new DateTime(2011, 8, 12),
                                            new Dictionary<DateTime, float> { { new DateTime(2011, 8, 12), 66.77f } }, null));

            _secondUndoSensor = new Sensor("Temperature", "C");
            _secondUndoSensor.AddState(new SensorState(_secondUndoSensor, new DateTime(2011, 3, 11),
                                                       new Dictionary<DateTime, float> { { new DateTime(2011, 8, 12), 66.77f } }, null));
            _secondUndoSensor.AddState(new SensorState(_secondUndoSensor, new DateTime(2011, 3, 12),
                                            new Dictionary<DateTime, float> { { new DateTime(2011, 8, 12), 66.77f } }, null));

            _sensorEmpty = new Sensor("Temperature", "C");
            _ds = new Dataset(new Site(10, "Lake", "Bob Smith", contact, contact, new GPSCoords(50, 50, "argis")));
            _ds2 = new Dataset(new Site(10, "Lake Awesome", "Andy Smith", contact, contact, new GPSCoords(70, 30, "argis")));

            _sensor1 = new Sensor("Temperature", "Temperature at 10m", 100, 20, "°C", 0.003f, _ds);
            _sensor2 = new Sensor("DO", "Dissolved Oxygen in the water", 50, 0, "%", 5.6f, _ds2);
        }
예제 #32
0
 public SensorStateListObject(SensorState obj, bool raw)
 {
     _object = obj;
     _isRaw  = raw;
 }
예제 #33
0
        public void ValidUndoStatesAfterRedo()
        {
            var redoSensor = new Sensor("Temperature", "C");

            var correctStackItem = new SensorState(redoSensor, new DateTime(2011, 7, 5, 22, 47, 0), new Dictionary<DateTime, float> { { new DateTime(2010, 5, 5, 22, 00, 0), 22.5f }, { new DateTime(2010, 5, 5, 22, 15, 0), 21.4f }, { new DateTime(2010, 5, 5, 22, 30, 0), 22.0f } }, null);
            var correctStackItemTwo = new SensorState(redoSensor, new DateTime(2011, 7, 9, 22, 47, 0), new Dictionary<DateTime, float> { { new DateTime(2010, 5, 5, 22, 00, 0), 22.5f }, { new DateTime(2010, 5, 5, 22, 15, 0), 21.4f }, { new DateTime(2010, 5, 5, 22, 30, 0), 22.0f } }, null);

            redoSensor.AddState(correctStackItem);
            redoSensor.AddState(correctStackItemTwo);

            redoSensor.Undo();

            Assert.AreEqual(correctStackItem, redoSensor.CurrentState);

            redoSensor.Redo();

            Assert.AreEqual(1, redoSensor.UndoStates.Count);
        }
예제 #34
0
파일: Sensor.cs 프로젝트: rwlamont/AllItUp
        /// <summary>
        /// Update the active state for data values, clearing the redo stack in the process.
        /// </summary>
        /// <param name="newState"></param>
        public void AddState(SensorState newState)
        {
            if (_rawData == null)
            {
                RawData = newState;
            }
            else
            {
                UndoStack.Push(CurrentState);
                RedoStack.Clear();

                _currentState = newState;
            }
        }
예제 #35
0
파일: Sensor.cs 프로젝트: rwlamont/AllItUp
        /// <summary>
        /// Advance data values for this sensor to the next state stored.
        /// </summary>
        public void Redo()
        {
            if (RedoStack.Count == 0)
                throw new InvalidOperationException("Redo is not possible at this stage. There are no more possible states to redo to.");

            UndoStack.Push(CurrentState);
            _currentState = RedoStack.Pop();
        }
예제 #36
0
 public void Setup()
 {
     _testSensor = new Sensor("Temperature1", "Temp at 100m", 100, 0, "C", 2, null);
     testSensorState = new SensorState(_testSensor, testDate);
     valueList = new Dictionary<DateTime, float>();
     secondValueList = new Dictionary<DateTime, float>();
     valueList.Add(testDate, 55.2f);
     valueList.Add(modifiedDate, 63.77f);
     secondValueList.Add(new DateTime(2005, 11, 3, 14, 27, 12), 22.7f);
     secondValueList.Add(new DateTime(2005, 12, 4, 14, 27, 28), 22.3f);
 }
예제 #37
0
파일: Sensor.cs 프로젝트: zhangzheng1205/B3
 public void RevertToRaw()
 {
     EventLogger.LogSensorInfo(Owner, Name, "Reverted to raw");
     _currentState = null;
 }
예제 #38
0
        public void GetEditTimestamp()
        {
            Assert.IsTrue(DateTime.Compare(testSensorState.EditTimestamp, testDate) == 0);

            SensorState modifiedSensorState = new SensorState(_testSensor, modifiedDate);
            Assert.IsTrue(DateTime.Compare(modifiedDate, modifiedSensorState.EditTimestamp) == 0);
        }