diff --git a/src/Microsoft.ML.TimeSeries/Deseasonality.cs b/src/Microsoft.ML.TimeSeries/Deseasonality.cs new file mode 100644 index 0000000000..b56613141c --- /dev/null +++ b/src/Microsoft.ML.TimeSeries/Deseasonality.cs @@ -0,0 +1,132 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.ML.TimeSeries +{ + internal interface IDeseasonality + { + /// + /// Remove the seasonality component from the given time-series. + /// + /// An array representing the input time-series. + /// The period value of the time-series. + /// The de-seasonalized time-series. + public abstract void Deseasonality(ref double[] values, int period, ref double[] results); + } + + internal sealed class MeanDeseasonality : IDeseasonality + { + private double[] _circularComponent; + + public void Deseasonality(ref double[] values, int period, ref double[] results) + { + Array.Resize(ref _circularComponent, period); + + var length = values.Length; + + // Initialize the circular component to 0. + for (int i = 0; i < period; ++i) + { + _circularComponent[i] = 0; + } + + // Sum up values that locate at the same position in one period. + for (int i = 0; i < length; ++i) + { + var indexInPeriod = i % period; + _circularComponent[indexInPeriod] += values[i]; + } + + // Calculate the mean value as circular component. + var cnt = (length - 1) / period; + var rest = (length - 1) % period; + for (int i = 0; i < period; ++i) + { + var lastCircle = i <= rest ? 1 : 0; + _circularComponent[i] = _circularComponent[i] / (cnt + lastCircle); + } + + // Substract the circular component from the original series. + for (int i = 0; i < length; ++i) + { + var indexInPeriod = i % period; + results[i] -= _circularComponent[indexInPeriod]; + } + } + } + + internal sealed class MedianDeseasonality : IDeseasonality + { + private List[] _subSeries; + private double[] _circularComponent; + + public void Deseasonality(ref double[] values, int period, ref double[] results) + { + Array.Resize(ref _circularComponent, period); + Array.Resize(ref _subSeries, period); + + var length = values.Length; + + for (int i = 0; i < period; ++i) + { + _subSeries[i] = new List(); + } + + // Split the original series into #period subseries. + for (int i = 0; i < length; ++i) + { + var indexInPeriod = i % period; + _subSeries[indexInPeriod].Add(values[i]); + } + + // Calculate the median value as circular component. + for (int i = 0; i < period; ++i) + { + _circularComponent[i] = MathUtility.QuickMedian(_subSeries[i]); + } + + // Substract the circular component from the original series. + for (int i = 0; i < length; ++i) + { + var indexInPeriod = i % period; + results[i] -= _circularComponent[indexInPeriod]; + } + } + } + + /// + /// This class takes the residual component of stl decompose as the deseasonality result. + /// + internal sealed class StlDeseasonality : IDeseasonality + { + private readonly InnerStl _stl; + + public StlDeseasonality() + { + _stl = new InnerStl(true); + } + + public void Deseasonality(ref double[] values, int period, ref double[] results) + { + bool success = _stl.Decomposition(values, period); + if (success) + { + for (int i = 0; i < _stl.Residual.Count; ++i) + { + results[i] = _stl.Residual[i]; + } + } + else + { + for (int i = 0; i < values.Length; ++i) + { + results[i] = values[i]; + } + } + } + } +} diff --git a/src/Microsoft.ML.TimeSeries/ExtensionsCatalog.cs b/src/Microsoft.ML.TimeSeries/ExtensionsCatalog.cs index 161f8bc27b..151e51bea6 100644 --- a/src/Microsoft.ML.TimeSeries/ExtensionsCatalog.cs +++ b/src/Microsoft.ML.TimeSeries/ExtensionsCatalog.cs @@ -176,7 +176,36 @@ public static SrCnnAnomalyEstimator DetectAnomalyBySrCnn(this TransformsCatalog /// public static IDataView DetectEntireAnomalyBySrCnn(this AnomalyDetectionCatalog catalog, IDataView input, string outputColumnName, string inputColumnName, double threshold = 0.3, int batchSize = 1024, double sensitivity = 99, SrCnnDetectMode detectMode = SrCnnDetectMode.AnomalyOnly) - => new SrCnnEntireAnomalyDetector(CatalogUtils.GetEnvironment(catalog), input, inputColumnName, outputColumnName, threshold, batchSize, sensitivity, detectMode); + { + var options = new SrCnnEntireAnomalyDetectorOptions() + { + Threshold = threshold, + BatchSize = batchSize, + Sensitivity = sensitivity, + DetectMode = detectMode, + }; + + return DetectEntireAnomalyBySrCnn(catalog, input, outputColumnName, inputColumnName, options); + } + + /// + /// Create , which detects timeseries anomalies for entire input using SRCNN algorithm. + /// + /// The AnomalyDetectionCatalog. + /// Input DataView. + /// Name of the column resulting from data processing of . + /// The column data is a vector of . The length of this vector varies depending on . + /// Name of column to process. The column data must be . + /// Defines the settings of the load operation. + /// + /// + /// + /// + /// + public static IDataView DetectEntireAnomalyBySrCnn(this AnomalyDetectionCatalog catalog, IDataView input, string outputColumnName, string inputColumnName, SrCnnEntireAnomalyDetectorOptions options) + => new SrCnnEntireAnomalyDetector(CatalogUtils.GetEnvironment(catalog), input, outputColumnName, inputColumnName, options); /// /// Create , which localizes root causes using decision tree algorithm. diff --git a/src/Microsoft.ML.TimeSeries/STL/FastLoess.cs b/src/Microsoft.ML.TimeSeries/STL/FastLoess.cs new file mode 100644 index 0000000000..6ed4dde87f --- /dev/null +++ b/src/Microsoft.ML.TimeSeries/STL/FastLoess.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.TimeSeries +{ + /// + /// This is the fast version of Loess. There are several alternatives to improve the performance. This one is an approximation approach. + /// The smoothing is conducted on a sample set, and then the values on the left points are assigned directly. + /// + internal class FastLoess + { + /// + /// This class is a sampling based method, so here specifies the sample size. + /// + private const int _sampleSize = 100; + + /// + /// The minimum length of a valid time series. A time series with length equals 2 is so trivial and meaningless less than 2. + /// + public const int MinTimeSeriesLength = 3; + + private readonly IReadOnlyList _x; + private readonly IReadOnlyList _y; + private readonly int _length; + + private readonly Loess _smoother; + + /// + /// Initializes a new instance of the class. + /// The fast version of the Loess method. when the time series is too long, the sampling will be conducted first to improve the performance. + /// + /// The input x-axis values + /// The input y-axis values + /// If the regression is considered to take temporal information into account. In general, this is true if we are regressing a time series, and false if we are regressing scatter plot data + /// This method will provide default smoothing ratio if user did not specify + public FastLoess(IReadOnlyList xValues, IReadOnlyList yValues, bool isTemporal = true, int r = -1) + { + Contracts.CheckValue(xValues, nameof(xValues)); + Contracts.CheckValue(yValues, nameof(yValues)); + Y = new List(); + + if (yValues.Count < MinTimeSeriesLength) + throw Contracts.Except("input data structure cannot be 0-length: lowess"); + + _x = xValues; + _y = yValues; + _length = _y.Count; + + if (_length <= FastLoess._sampleSize) + { + if (r == -1) + _smoother = new Loess(_x, _y, isTemporal); + else + _smoother = new Loess(_x, _y, isTemporal, r); + } + else + { + // Conduct sampling based strategy, to boost the performance. + double step = _length * 1.0 / FastLoess._sampleSize; + var sampleX = new double[FastLoess._sampleSize]; + var sampleY = new double[FastLoess._sampleSize]; + for (int i = 0; i < FastLoess._sampleSize; i++) + { + int index = (int)(i * step); + sampleX[i] = _x[index]; + sampleY[i] = _y[index]; + } + if (r == -1) + _smoother = new Loess(sampleX, sampleY, isTemporal); + else + _smoother = new Loess(sampleX, sampleY, isTemporal, r); + } + } + + /// + /// The estimated y values. + /// + public List Y { get; } + + /// + /// Assign the smoothing values to all the data points, not only on the sample size. + /// + public void Estimate() + { + for (int i = 0; i < _length; i++) + { + double yValue = _smoother.EstimateY(_x[i]); + Y.Add(yValue); + } + } + + /// + /// Estimate a y value by giving an x value, even if the x value is not one of the input points. + /// + public double EstimateY(double xValue) + { + return _smoother.EstimateY(xValue); + } + } +} diff --git a/src/Microsoft.ML.TimeSeries/STL/InnerStl.cs b/src/Microsoft.ML.TimeSeries/STL/InnerStl.cs new file mode 100644 index 0000000000..0093f0ff41 --- /dev/null +++ b/src/Microsoft.ML.TimeSeries/STL/InnerStl.cs @@ -0,0 +1,325 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.TimeSeries +{ + internal class InnerStl + { + private readonly bool _isTemporal; + private double[] _seasonalComponent; + private double[] _trendComponent; + private double[] _residual; + + // Arrays for intermediate results + private List[] _cycleSubSeries; + private List[] _smoothedSubseries; + + private double[] _s; + private double[] _t; + private double[] _detrendedY; + private double[] _c; + private double[] _deseasonSeries; + + /// + /// The smoothing parameter for the seasonal component. + /// This parameter should be odd, and at least 7. + /// + private const int Ns = 9; + + /// + /// The number of passes through the inner loop. This parameter is set to 2, which works for many cases. + /// + private const int Ni = 2; + + /// + /// The number of robustness iterations of the outer loop. This parameter is not used in this implementation as we simplify the implementation. + /// Keep this parameter here as it is listed as one of the six parameters described in the original paper. + /// + private const int No = 10; + + /// + /// The smoothing parameter for the low-pass filter. + /// This parameter should be the least odd integer greater than or equal to np. + /// It will preventing the trend and seasonal components from competing for the same variation in the data. + /// + private int Nl(int np) + { + if (np % 2 == 0) + return np + 1; + return np; + } + + /// + /// The smoothing parameter for the trend component. + /// In order to avoid the trend ans seasonal components compete for variation in the data, the nt should be chosen + /// S.t., satisty the following inequality. + /// + private int Nt(int np) + { + double value = 1.5 * np / (1.0 - 1.5 / Ns); + int result = (int)value + 1; + if (result % 2 == 0) + result++; + return result; + } + + /// + /// Initializes a new instance of the class. + /// For a time series, only with y values. assume the x-values are 0, 1, 2, ... + /// Since this method supports decompose seasonal signal, which requires the equal-space of the input x-axis values. + /// Otherwise, the smoothing on seasonal component will be very complicated. + /// + /// If the regression is considered to take temporal information into account. In general, this is true if we are regressing a time series, and false if we are regressing scatter plot data + public InnerStl(bool isTemporal) + { + _isTemporal = isTemporal; + } + + /// + /// The seasonal component + /// + public IReadOnlyList SeasonalComponent + { + get { return _seasonalComponent; } + } + + /// + /// The trend component + /// + public IReadOnlyList TrendComponent + { + get { return _trendComponent; } + } + + /// + /// The left component after seasonal and trend are eliminated. + /// + public IReadOnlyList Residual + { + get { return _residual; } + } + + /// + /// The core for the robust trend-seasonal decomposition. See the ref: http://www.wessa.net/download/stl.pdf, + /// See section 2 and 3. especially section 2. + /// + /// Return true if the process goes successfully. Otherwise, return false. + public bool Decomposition(IReadOnlyList yValues, int np) + { + Contracts.CheckValue(yValues, nameof(yValues)); + Contracts.CheckParam(np > 0, nameof(np)); + + if (yValues.Count == 0) + throw Contracts.Except("input data structure cannot be 0-length: innerSTL"); + + int length = yValues.Count; + Array.Resize(ref _seasonalComponent, length); + Array.Resize(ref _trendComponent, length); + Array.Resize(ref _residual, length); + + Array.Resize(ref _s, length); + Array.Resize(ref _t, length); + Array.Resize(ref _detrendedY, length); + Array.Resize(ref _c, length + np * 2); + Array.Resize(ref _deseasonSeries, length); + + Array.Resize(ref _cycleSubSeries, np); + Array.Resize(ref _smoothedSubseries, np); + + for (int i = 0; i < length; ++i) + { + _t[i] = 0; + } + + for (int iter = 0; iter < Ni; iter++) + { + // step1: detrending + Detrending(yValues, _t, _detrendedY); + + // step2: cycle-subseries smoothing + bool success = CycleSubseriesSmooth(_detrendedY, np, _c); + if (!success) + { + return false; + } + + // step3: low-pass filtering of smoothed cycle-subseries + var lowPass = LowPassFiltering(_c, np); + + // step4: detrending of smoothed cycle-subseries + SmoothedCycleSubseriesDetrending(_c, lowPass, _s); + + // step5: deseasonalizing + Deseasonalizing(yValues, _s, _deseasonSeries); + + // step6: trend smoothing + TrendSmooth(_deseasonSeries, np, _t); + } + + for (int i = 0; i < _s.Length; i++) + { + _seasonalComponent[i] = _s[i]; + _trendComponent[i] = _t[i]; + _residual[i] = yValues[i] - _s[i] - _t[i]; + } + + return true; + } + + private void Detrending(IReadOnlyList y, IReadOnlyList t, double[] detrendedY) + { + for (int i = 0; i < y.Count; i++) + detrendedY[i] = y[i] - t[i]; + } + + private bool CycleSubseriesSmooth(double[] detrendedY, int np, double[] c) + { + for (int i = 0; i < np; i++) + { + _cycleSubSeries[i] = new List(); + _smoothedSubseries[i] = new List(); + } + + // obtain all the subseries + for (int i = 0; i < detrendedY.Length; i++) + { + int cycleIndex = i % np; + _cycleSubSeries[cycleIndex].Add(detrendedY[i]); + } + + // smoothing on each subseries + for (int i = 0; i < _cycleSubSeries.Length; i++) + { + List virtualXValues = VirtualXValuesProvider.GetXValues(_cycleSubSeries[i].Count); + + FastLoess model = new FastLoess(virtualXValues, _cycleSubSeries[i], _isTemporal, Ns); + model.Estimate(); + + // add a prior point + _smoothedSubseries[i].Add(model.EstimateY(-1.0)); + _smoothedSubseries[i].AddRange(model.Y); + + // add a after point + _smoothedSubseries[i].Add(model.EstimateY(_cycleSubSeries[i].Count * 1.0)); + } + + // c is the smoothed series, with _length + 2Np points. + int index = 0; + for (int i = 0; i < _smoothedSubseries[0].Count; i++) + { + for (int j = 0; j < _smoothedSubseries.Length; j++) + { + if (_smoothedSubseries[j].Count <= i) + break; + if (_smoothedSubseries[j][i].Equals(double.NaN)) + { + return false; + } + c[index] = (_smoothedSubseries[j][i]); + ++index; + } + } + + return true; + } + + private FastLoess LowPassFiltering(double[] c, int np) + { + List c1 = MovingAverage(c, np); + List c2 = MovingAverage(c1, np); + List c3 = MovingAverage(c2, 3); + List virtualC3XValues = VirtualXValuesProvider.GetXValues(c3.Count); + FastLoess lowPass = new FastLoess(virtualC3XValues, c3, _isTemporal, Nl(np)); + lowPass.Estimate(); + + return lowPass; + } + + private void SmoothedCycleSubseriesDetrending(double[] c, FastLoess lowPass, double[] s) + { + for (int i = 0; i < s.Length; i++) + { + s[i] = c[i] - lowPass.Y[i]; + } + } + + private void Deseasonalizing(IReadOnlyList y, double[] s, double[] deseasonSeries) + { + for (int i = 0; i < y.Count; i++) + { + deseasonSeries[i] = y[i] - s[i]; + } + } + + private void TrendSmooth(double[] deseasonSeries, int np, double[] t) + { + List virtualDeseasonSeries = VirtualXValuesProvider.GetXValues(deseasonSeries.Length); + FastLoess trender = new FastLoess(virtualDeseasonSeries, deseasonSeries, _isTemporal, Nt(np)); + trender.Estimate(); + for (int i = 0; i < deseasonSeries.Length; i++) + { + t[i] = trender.Y[i]; + } + } + + /// + /// This class provides the virtual x values for multi object usage. + /// The cache mechanism is used for performance consideration. + /// + internal class VirtualXValuesProvider + { + private static Dictionary> _xValuesPool; + + static VirtualXValuesProvider() + { + _xValuesPool = new Dictionary>(); + } + + /// + /// Get a list of virtual x-axis values. the values are from 0 to length - 1. + /// + /// Specify the length you want to create the x values. + /// If the input is cached, return the cached output directly. Otherwise, create a new list and return + internal static List GetXValues(int length) + { + lock (_xValuesPool) + { + List xValues; + if (_xValuesPool.TryGetValue(length, out xValues)) + return xValues; + + var newXValues = new List(length); + for (int i = 0; i < length; i++) + newXValues.Add(i); + + _xValuesPool.Add(length, newXValues); + return newXValues; + } + } + } + + private static List MovingAverage(IReadOnlyList s, int length) + { + List results = new List(s.Count); + double partialSum = 0; + for (int i = 0; i < length; ++i) + { + partialSum += s[i]; + } + + for (int i = length; i < s.Count; ++i) + { + results.Add(partialSum / length); + partialSum = partialSum - s[i - length] + s[i]; + } + results.Add(partialSum / length); + + return results; + } + } +} diff --git a/src/Microsoft.ML.TimeSeries/STL/LeastSquares.cs b/src/Microsoft.ML.TimeSeries/STL/LeastSquares.cs new file mode 100644 index 0000000000..a2895ec509 --- /dev/null +++ b/src/Microsoft.ML.TimeSeries/STL/LeastSquares.cs @@ -0,0 +1,99 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.TimeSeries +{ + /// + /// This class is used to calculate the least squares of the scatterplots. + /// Please check http://en.wikipedia.org/wiki/Least_squares for more details. + /// + internal class LeastSquares + { + private readonly IReadOnlyList _x; + private readonly IReadOnlyList _y; + private readonly int _length; + + /// + /// Initializes a new instance of the class. + /// Constructing the least square algorithm. the input will be consumed directly without any copy, due to memory usage concern. + /// + /// The corresponding x-axis value + /// The corresponding y-axis value + public LeastSquares(IReadOnlyList x, IReadOnlyList y) + { + Contracts.CheckValue(x, nameof(x)); + Contracts.CheckValue(y, nameof(y)); + + if (x.Count == 0 || y.Count == 0) + throw Contracts.Except("input data structure cannot be 0-length"); + if (x.Count != y.Count) + throw Contracts.Except("the x-axis length should be equal to y-axis length!"); + _x = x; + _y = y; + _length = _x.Count; + } + + /// + /// y=b0+b1x, while the penalty is weighted + /// + /// The weighted least squares. Note that the weight should be non-negative, and equal length to data + public AbstractPolynomialModel RegressionDegreeOneWeighted(IReadOnlyList weights) + { + Contracts.CheckValue(weights, nameof(weights)); + + Contracts.CheckParam(weights.Count == _length, nameof(weights)); + if (weights.Count != _length) + throw Contracts.Except("The length of the weight vector is not equal to the length of the data points."); + + // This part unfolds the matrix calculation of [sqrt(W), sqrt(W) .* X]^T * [sqrt(W), sqrt(W) .* X] + double sum00 = 0; + double sum01 = 0; + double sum10 = 0; + double sum11 = 0; + double temp; + for (int k = 0; k < _length; k++) + { + temp = weights[k]; + sum00 += temp; + temp *= _x[k]; + sum01 += temp; + sum10 += temp; + temp *= _x[k]; + sum11 += temp; + } + + // calculate the reverse of a 2X2 matrix is simple, because suppose the matrix is [a,b;c,d], then its reverse is + // [x1,x2;x3,x4] where x1 = d/K, x2 = -c/K, x3 = -b/K, x4 = a/K, where K = ad-bc. + double a = sum00; + double b = sum01; + double c = sum10; + double d = sum11; + double divider = a * d - b * c; + double reverseS00 = d / divider; + double reverseS01 = -c / divider; + double reverseS10 = -b / divider; + double reverseS11 = a / divider; + + // This part unfolds the matrix calculation of [sqrt(W), sqrt(W) .* X]^T * [sqrt(W) .* Y] + double fy0 = 0; + double fy1 = 0; + for (int i = 0; i < _length; i++) + { + temp = weights[i] * _y[i]; + fy0 += temp; + fy1 += temp * _x[i]; + } + + double b0 = reverseS00 * fy0 + reverseS01 * fy1; + double b1 = reverseS10 * fy0 + reverseS11 * fy1; + + double[] results = new double[2] { b0, b1 }; + + return new LinearModel(results); + } + } +} diff --git a/src/Microsoft.ML.TimeSeries/STL/LocalRegression.cs b/src/Microsoft.ML.TimeSeries/STL/LocalRegression.cs new file mode 100644 index 0000000000..e10819257a --- /dev/null +++ b/src/Microsoft.ML.TimeSeries/STL/LocalRegression.cs @@ -0,0 +1,260 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Microsoft.ML.Internal.CpuMath.Core; + +namespace Microsoft.ML.TimeSeries +{ + /// + /// This class is used to maintain the neighbors of a given particular point. + /// + internal class LocalRegression + { + private const double NumericalThreshold = 1.0e-10; + private readonly IReadOnlyList _x; + private readonly IReadOnlyList _y; + private readonly int _length; + + /// + /// The model is learned by several iterations of local weighted regression. + /// + private AbstractPolynomialModel _model; + + /// + /// Initializes a new instance of the class. + /// Construct the neighborhood information of a given point. note that the input series will not be copies again, due to + /// memory usage concern. + /// + /// The complete values of x-axis + /// The complete values of y-axis + /// The index of the current point + /// Number of neighbors, usually should be less then n. if it is equal/larger than n, the weight has slight change. + /// If the regression is considered to take temporal information into account. In general, this is true if we are regressing a time series, and false if we are regressing scatter plot data + public LocalRegression(IReadOnlyList x, IReadOnlyList y, int selfIndex, int r, bool isTemporal = true) + { + Contracts.CheckValue(x, nameof(x)); + Contracts.CheckValue(y, nameof(y)); + + if (x.Count <= 1 || x.Count != y.Count) + throw Contracts.Except("cannot accomplish neighbors obtaining"); + + _model = null; + + _x = x; + _y = y; + _length = _x.Count; + SelfIndex = selfIndex; + + int startIndex = selfIndex; + int endIndex = selfIndex; + double selfValue = _x[SelfIndex]; + + // The farthest neighbor is contained in the list. This is the normal case. + if (r < _length) + { + int left = r; + while (left > 0) + { + if (startIndex == 0) + { + endIndex += left; + break; + } + if (endIndex == _length - 1) + { + startIndex -= left; + break; + } + double startV = _x[startIndex]; + double endV = _x[endIndex]; + + // the left point is closer to the current + // bug fix: avoid potential inconsistent index assignment due to numerical precision. + double distanceDiff = (selfValue - startV) - (endV - selfValue); + + if (distanceDiff < NumericalThreshold) + { + startIndex--; + } + else + { + endIndex++; + } + left--; + } + StartIndex = startIndex; + EndIndex = endIndex; + + var neighborsCount = EndIndex - StartIndex + 1; + NeighborsX = new double[neighborsCount]; + NeighborsY = new double[neighborsCount]; + Weights = new double[neighborsCount]; + + double leftRange = selfValue - _x[startIndex]; + double rightRange = _x[endIndex] - selfValue; + double range = Math.Max(leftRange, rightRange); + + if (isTemporal) + { + for (int i = StartIndex; i <= EndIndex; i++) + { + NeighborsX[i - StartIndex] = _x[i]; + NeighborsY[i - StartIndex] = _y[i]; + Weights[i - StartIndex] = WeightMethod.Tricube((_x[i] - selfValue) / range); + } + } + else + { + for (int i = StartIndex; i <= EndIndex; i++) + { + NeighborsX[i - StartIndex] = _x[i]; + NeighborsY[i - StartIndex] = _y[i]; + + // since we do not consider the local/temporal information, all the neighbors share same weight for further weighted regression + Weights[i - StartIndex] = 1.0; + } + } + } + else + { + // when the r is equal/larger than n + StartIndex = 0; + EndIndex = _length - 1; + + double leftRange = selfValue - _x[StartIndex]; + double rightRange = _x[EndIndex] - selfValue; + double range = Math.Max(leftRange, rightRange); + + var neighborsCount = EndIndex - StartIndex + 1; + NeighborsX = new double[neighborsCount]; + NeighborsY = new double[neighborsCount]; + Weights = new double[neighborsCount]; + + // this is the slight modification of the weighting calculation + range = range * r / (_length - 1); + + if (isTemporal) + { + for (int i = StartIndex; i <= EndIndex; i++) + { + NeighborsX[i - StartIndex] = _x[i]; + NeighborsY[i - StartIndex] = _y[i]; + Weights[i - StartIndex] = WeightMethod.Tricube((_x[i] - selfValue) / range); + } + } + else + { + for (int i = StartIndex; i <= EndIndex; i++) + { + NeighborsX[i - StartIndex] = _x[i]; + NeighborsY[i - StartIndex] = _y[i]; + + // since we do not consider the local/temporal information, all the neighbors share same weight for further weighted regression + Weights[i - StartIndex] = 1.0; + } + } + } + } + + /// + /// The values of the y-axis of the neighbors (include the self point) + /// + public double[] NeighborsY { get; private set; } + + /// + /// The values of the x-axis of the neighbors (include the self point) + /// + public double[] NeighborsX { get; private set; } + + /// + /// The weights for each neighbor. This is used for weighted least squares. + /// + public double[] Weights { get; private set; } + + /// + /// The start index of the neighbors (inclusive) + /// + public int StartIndex { get; private set; } + + /// + /// The end index of the neighbors (inclusive) + /// + public int EndIndex { get; private set; } + + /// + /// The index of the self point. The index is on the complete series, not only on the neighbor series. + /// + public int SelfIndex { get; private set; } + + private void Estimate() + { + for (int iter = 0; iter < LoessConfiguration.T; iter++) + { + _model = Regression(); + + // calculate the errors + var errors = new double[NeighborsX.Length]; + var absErrors = new double[NeighborsX.Length]; + for (int i = 0; i < NeighborsX.Length; i++) + { + double error = NeighborsY[i] - _model.Y(NeighborsX[i]); + errors[i] = error; + absErrors[i] = Math.Abs(error); + } + + Array.Sort(absErrors); + + double median = absErrors[absErrors.Length / 2]; + if (median == 0) // a very subtle bug! sometimes, when the input data is very clean, so that the median could be 0! + median = double.Epsilon; + + // calculate the gain for new weights. the outliers will get much less weight + var deltas = new double[errors.Length]; + for (int i = 0; i < errors.Length; i++) + { + deltas[i] = WeightMethod.BisquareWeight(errors[i] / 6.0 / median); + } + + // update new weights. + for (int i = 0; i < Weights.Length; i++) + { + Weights[i] *= deltas[i]; + } + } + } + + /// + /// Get the best estimated y for the current value. + /// + public double Y() + { + if (_model == null) + { + Estimate(); + } + return _model.Y(_x[SelfIndex]); + } + + /// + /// Get the best estimated y for any given x-value, event not one of the observed point + /// + /// Any given x value + public double Y(double xValue) + { + if (_model == null) + { + Estimate(); + } + return _model.Y(xValue); + } + + private AbstractPolynomialModel Regression() + { + LeastSquares ls = new LeastSquares(NeighborsX, NeighborsY); + return ls.RegressionDegreeOneWeighted(Weights); + } + } +} diff --git a/src/Microsoft.ML.TimeSeries/STL/Loess.cs b/src/Microsoft.ML.TimeSeries/STL/Loess.cs new file mode 100644 index 0000000000..798a5f0cdb --- /dev/null +++ b/src/Microsoft.ML.TimeSeries/STL/Loess.cs @@ -0,0 +1,179 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.TimeSeries +{ + /// + /// Loess is short for Robust Locally Weighted Regression and Smoothing Scatterplots. + /// + internal class Loess + { + /// + /// The minimum length of a valid time series. A time series with length equals 2 is so trivial and meaningless less than 2. + /// + public const int MinTimeSeriesLength = 3; + + private const double NumericalThreshold = 1.0e-10; + + /// + /// The ratio to determine the local region + /// + private readonly int _r; + + private readonly bool _isTemporal; + + /// + /// Key is the index of the given point, value is the corresponding neighbors of the given point. + /// + private readonly Dictionary _neighbors; + + private IReadOnlyList _x; + private IReadOnlyList _y; + private readonly int _length; + + /// + /// Initializes a new instance of the class. + /// Construct the least square algorithm specified with the number of neighbors + /// + /// The corresponding x-axis value + /// The corresponding y-axis value + /// If the regression is considered to take temporal information into account. In general, this is true if we are regressing a time series, and false if we are regressing scatter plot data + /// The smoothing range, if it is not specified, the algorithm will estimate the value of r by ratio. + public Loess(IReadOnlyList xValues, IReadOnlyList yValues, bool isTemporal, int? r = null) + { + Contracts.CheckValue(xValues, nameof(xValues)); + Contracts.CheckValue(yValues, nameof(yValues)); + + if (xValues.Count < MinTimeSeriesLength || yValues.Count < MinTimeSeriesLength) + throw Contracts.Except("input data structure cannot be 0-length: lowess"); + + if (xValues.Count != yValues.Count) + throw Contracts.Except("the x-axis length should be equal to y-axis length!: lowess"); + + _neighbors = new Dictionary(); + + _length = xValues.Count; + _isTemporal = isTemporal; + + if (r == null) + { + _r = (int)(_length * LoessConfiguration.F); + } + else + { + _r = (int)r; + } + + if (_r >= _length) + _r = _length - 1; + else if (_r < LoessConfiguration.MinimumNeighborCount) // the neighbors should be at least 2, or the matrix operations would encounter issues. + _r = LoessConfiguration.MinimumNeighborCount; + + Init(xValues, yValues); + } + + /// + /// Initialize the signal with basic checking + /// + /// The input x-axis values + /// The input y-axis values + private void Init(IReadOnlyList xValues, IReadOnlyList yValues) + { + _x = xValues; + _y = yValues; + for (int i = 0; i < _length; i++) + { + LocalRegression neighbor = new LocalRegression(_x, _y, i, _r, _isTemporal); + _neighbors.Add(i, neighbor); + } + } + + /// + /// Estimate a y value by giving an x value, even if the x value is not one of the input points. + /// When the x value is not one of the input points, find the closed one from input points, and use its model. + /// + /// find the index with value closest to the input x value. + public double EstimateY(double xValue) + { + // find the closest point in x to the xValue + int start = 0; + int end = _length - 1; + while (end - start > 1) + { + int mid = (start + end) / 2; + if (_x[mid] > xValue) + { + end = mid; + } + else + { + start = mid; + } + } + double distanceDiff = (_x[end] - xValue) - (xValue - _x[start]); + + int index = distanceDiff > -NumericalThreshold ? start : end; + return _neighbors[index].Y(xValue); + } + } + + /// + /// This class is used to define a set of weight functions. These functions are useful for various purposes for smoothing, + /// i.e., the weighted least squares. + /// + internal class WeightMethod + { + /// + /// This is used for robust weight, It is one iteration step of loess. + /// + public static double BisquareWeight(double value) + { + double abs = Math.Abs(value); + if (abs >= 1) + return 0; + double temp = 1 - abs * abs; + return temp * temp; + } + + /// + /// A famous weight function, since it enhances a chi-squared distributional approximation f an estimated of the error variance. + /// Tricube should provide an adequate smooth in almost all situations. + /// + public static double Tricube(double value) + { + double abs = Math.Abs(value); + if (abs >= 1) + return 0; + double temp = 1 - abs * abs * abs; + return temp * temp * temp; + } + } + + /// + /// This class is used to store the parameters which are needed for lowess algorithm. + /// The name of these constansts are compliant with the original terms in paper. + /// + internal class LoessConfiguration + { + /// + /// Minumum number of neighbor counts, to apply underlying regression analysis. + /// This number should be even, so that neighbors on left/right side of a given data point is balanced. Unbalanced neighbors would make the local-weighted regression biased noticeably at corner cases. + /// + public const int MinimumNeighborCount = 4; + + /// + /// (0, 1], a smooth range ratio. Let fn be the number of neighbors of a specific point. + /// + public const double F = 0.3; + + /// + /// The number of iterations for robust regression. + /// + public const int T = 2; + } +} diff --git a/src/Microsoft.ML.TimeSeries/STL/MathsTools.cs b/src/Microsoft.ML.TimeSeries/STL/MathsTools.cs new file mode 100644 index 0000000000..17f5547284 --- /dev/null +++ b/src/Microsoft.ML.TimeSeries/STL/MathsTools.cs @@ -0,0 +1,125 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace Microsoft.ML.TimeSeries +{ + internal class MathUtility + { + /// + /// Use quick-sort like method to obtain the median value. + /// The complexity in expectation is O(n), which is faster than using quickSort. + /// + /// The input list of values. Note that this list will be modified after calling this method + /// Returns the median value + public static double QuickMedian(List values) + { + if (values == null || values.Count == 0) + return double.NaN; + + // here the third parameter is start from 1. so we need to plus 1 to compliant. + return QuickSelect(values, values.Count / 2 + 1); + } + + /// + /// Use quick-sort like method to obtain the median value. + /// The complexity in expectation is O(n), which is faster than using quickSort. + /// + /// The list of values + /// The k smallest value in the list + public static double QuickSelect(IReadOnlyList values, int k) + { + var nums = values; + double[] left = new double[values.Count]; + double[] right = new double[values.Count]; + int numsCount = nums.Count; + + while (true) + { + if (numsCount == 1) + return nums[0]; + + int idx = FindMedianIndex(nums, 0, numsCount - 1); + double key = nums[idx]; + + int leftIdx = 0; + int rightIdx = 0; + for (int i = 0; i < numsCount; i++) + { + if (i == idx) + continue; + + if (nums[i] < key) + left[leftIdx++] = nums[i]; + else + right[rightIdx++] = nums[i]; + } + + if (leftIdx == k - 1) + return key; + + if (leftIdx >= k) + { + nums = left; + numsCount = leftIdx; + } + else + { + nums = right; + k = k - leftIdx - 1; + numsCount = rightIdx; + } + } + } + + public static int FindMedianIndex(IReadOnlyList values, int start, int end) + { + // Use the middle value among first/middle/end as the guard value, to make sure the average performance good. + // According to unit test, this fix will improve the average performance 10%. and works normally when input list is ordered. + double first = values[start]; + double last = values[end]; + int midIndex = (start + end) / 2; + int medianIndex = -1; + double middleValue = values[midIndex]; + if (first < last) + { + if (middleValue > last) + { + // last is the middle value + medianIndex = end; + } + else if (middleValue > first) + { + // middleValue is the middle value + medianIndex = midIndex; + } + else + { + // first is the middle value + medianIndex = start; + } + } + else + { + if (middleValue > first) + { + // first is the middle value + medianIndex = start; + } + else if (middleValue < last) + { + // last is the middle value + medianIndex = end; + } + else + { + // middleValue is the middle value + medianIndex = midIndex; + } + } + return medianIndex; + } + } +} diff --git a/src/Microsoft.ML.TimeSeries/STL/PolynomialModel.cs b/src/Microsoft.ML.TimeSeries/STL/PolynomialModel.cs new file mode 100644 index 0000000000..437916205f --- /dev/null +++ b/src/Microsoft.ML.TimeSeries/STL/PolynomialModel.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Microsoft.ML.Runtime; + +namespace Microsoft.ML.TimeSeries +{ + internal abstract class AbstractPolynomialModel + { + protected IReadOnlyList Coeffs; + + public AbstractPolynomialModel(IReadOnlyList coeffs) + { + Contracts.CheckValue(coeffs, nameof(coeffs)); + Coeffs = coeffs; + } + + public abstract double Y(double x); + } + + /// + /// A general polynomial model + /// + internal sealed class PolynomialModel : AbstractPolynomialModel + { + public PolynomialModel(IReadOnlyList coeffs) + : base(coeffs) + { + } + + /// + /// This function calculates the y value by given the x value, under this model + /// + /// The specific x value + public override double Y(double x) + { + double result = Coeffs[0]; + double p = 1.0; + for (int i = 1; i < Coeffs.Count; i++) + { + p *= x; + result += Coeffs[i] * p; + } + return result; + } + } + + /// + /// This class calculates f(x) = b0 + b1 * x + /// + internal sealed class LinearModel : AbstractPolynomialModel + { + /// + /// Store the coefficients in member variables for better performance. + /// + private readonly double _b0; + private readonly double _b1; + + public LinearModel(IReadOnlyList coeffs) + : base(coeffs) + { + Contracts.CheckParam(coeffs.Count == 2, nameof(coeffs), "must contain exact 2 elements."); + + _b0 = coeffs[0]; + _b1 = coeffs[1]; + } + + public override double Y(double x) + { + return _b0 + (_b1 * x); + } + } +} diff --git a/src/Microsoft.ML.TimeSeries/SrCnnAnomalyDetectionBase.cs b/src/Microsoft.ML.TimeSeries/SrCnnAnomalyDetectionBase.cs index 566b5b6cd2..c18a309539 100644 --- a/src/Microsoft.ML.TimeSeries/SrCnnAnomalyDetectionBase.cs +++ b/src/Microsoft.ML.TimeSeries/SrCnnAnomalyDetectionBase.cs @@ -174,13 +174,13 @@ private protected override sealed void SpectralResidual(Single input, FixedSizeQ // Step 1: Get backadd wave List backAddList = BackAdd(data); - // Step 2: FFT transformation + // Step 2: FftTransform transformation int length = backAddList.Count; float[] fftRe = new float[length]; float[] fftIm = new float[length]; FftUtils.ComputeForwardFft(backAddList.ToArray(), Enumerable.Repeat(0.0f, length).ToArray(), fftRe, fftIm, length); - // Step 3: Calculate mags of FFT + // Step 3: Calculate mags of FftTransform List magList = new List(); for (int i = 0; i < length; ++i) { diff --git a/src/Microsoft.ML.TimeSeries/SrCnnEntireAnomalyDetector.cs b/src/Microsoft.ML.TimeSeries/SrCnnEntireAnomalyDetector.cs index 1636179a19..5f296d806c 100644 --- a/src/Microsoft.ML.TimeSeries/SrCnnEntireAnomalyDetector.cs +++ b/src/Microsoft.ML.TimeSeries/SrCnnEntireAnomalyDetector.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.ML.CommandLine; using Microsoft.ML.Data; using Microsoft.ML.Data.DataView; using Microsoft.ML.Runtime; @@ -33,6 +34,63 @@ public enum SrCnnDetectMode AnomalyAndExpectedValue = 2 } + /// + /// The Deseasonality modes of SrCnn models. The de-seasonality mode is envoked when the period of the series is greater than 0. + /// + public enum SrCnnDeseasonalityMode + { + /// + /// In this mode, the stl decompose algorithm is used to de-seasonality. + /// + Stl = 0, + + /// + /// In this mode, the mean value of points in the same position in a period is substracted to de-seasonality. + /// + Mean = 1, + + /// + /// In this mode, the median value of points in the same position in a period is substracted to de-seasonality. + /// + Median = 2 + } + public sealed class SrCnnEntireAnomalyDetectorOptions + { + [Argument(ArgumentType.AtMostOnce, HelpText = "The threshold to determine anomaly, score larger than the threshold is considered as anomaly.", + SortOrder = 3, ShortName = "thr")] + public double Threshold = Defaults.Threshold; + + [Argument(ArgumentType.AtMostOnce, HelpText = "The number of data points to be detected in each batch. It should be at least 12. Set this parameter to -1 to detect anomaly on the entire series.", + SortOrder = 4, ShortName = "bsz")] + public int BatchSize = Defaults.BatchSize; + + [Argument(ArgumentType.AtMostOnce, HelpText = "This parameter is used in AnomalyAndMargin mode the determine the range of the boundaries.", + SortOrder = 4, ShortName = "sen")] + public double Sensitivity = Defaults.Sensitivity; + + [Argument(ArgumentType.AtMostOnce, HelpText = "Specify the detect mode as one of AnomalyOnly, AnomalyAndExpectedValue and AnomalyAndMargin.", + SortOrder = 5, ShortName = "dtmd")] + public SrCnnDetectMode DetectMode = Defaults.DetectMode; + + [Argument(ArgumentType.AtMostOnce, HelpText = "If there is circular pattern in the series, set this value to the number of points in one cycle.", + SortOrder = 5, ShortName = "prd")] + public int Period = Defaults.Period; + + [Argument(ArgumentType.AtMostOnce, HelpText = "Specify the deseasonality mode as one of stl, mean and median.", + SortOrder = 6, ShortName = "dsmd")] + public SrCnnDeseasonalityMode DeseasonalityMode = Defaults.DeseasonalityMode; + + internal static class Defaults + { + public const double Threshold = 0.3; + public const int BatchSize = 2000; + public const double Sensitivity = 55; + public const SrCnnDetectMode DetectMode = SrCnnDetectMode.AnomalyOnly; + public const int Period = 0; + public const SrCnnDeseasonalityMode DeseasonalityMode = SrCnnDeseasonalityMode.Stl; + } + } + /// /// Detect timeseries anomalies for entire input using Spectral Residual(SR) algorithm. /// @@ -72,19 +130,17 @@ public enum SrCnnDetectMode /// ]]> /// /// - /// + /// + /// internal sealed class SrCnnEntireAnomalyDetector : BatchDataViewMapperBase { private const int MinBatchSize = 12; private static readonly int[] _outputLengthArray = {3, 7, 4}; - private readonly int _batchSize; + private readonly SrCnnEntireAnomalyDetectorOptions _options; private readonly string _inputColumnName; private readonly int _outputLength; private readonly Bindings _bindings; - private readonly double _threshold; - private readonly double _sensitivity; - private readonly SrCnnDetectMode _detectMode; private class Bindings : ColumnBindingsBase { @@ -127,29 +183,42 @@ public Func GetDependencies(Func predicate) } } - public SrCnnEntireAnomalyDetector(IHostEnvironment env, IDataView input, string inputColumnName, string outputColumnName, double threshold, int batchSize, double sensitivity, SrCnnDetectMode detectMode) + public SrCnnEntireAnomalyDetector(IHostEnvironment env, IDataView input, string outputColumnName, string inputColumnName, SrCnnEntireAnomalyDetectorOptions options) : base(env, nameof(SrCnnEntireAnomalyDetector), input) { + Host.CheckValue(outputColumnName, nameof(outputColumnName)); + Host.CheckValue(inputColumnName, nameof(inputColumnName)); _inputColumnName = inputColumnName; - Host.CheckUserArg(batchSize == -1 || batchSize >= MinBatchSize, nameof(batchSize), "BatchSize must be -1 or no less than 12."); - _batchSize = batchSize; + Host.CheckValue(options, nameof(options)); + CheckOptionArguments(options); - Host.CheckUserArg(threshold >= 0 && threshold <= 1, nameof(threshold), "Must be in [0,1]."); - Host.CheckUserArg(detectMode == SrCnnDetectMode.AnomalyOnly - || detectMode == SrCnnDetectMode.AnomalyAndExpectedValue - || detectMode == SrCnnDetectMode.AnomalyAndMargin, nameof(detectMode), "Invalid detectMode"); - - Host.CheckUserArg(sensitivity >= 0 && sensitivity <= 100, nameof(sensitivity), "Must be in [0,100]."); - _outputLength = _outputLengthArray[(int)detectMode]; - _threshold = threshold; - _sensitivity = sensitivity; - _detectMode = detectMode; + _options = options; + _outputLength = _outputLengthArray[(int)options.DetectMode]; _bindings = new Bindings(input.Schema, inputColumnName, outputColumnName, new VectorDataViewType(NumberDataViewType.Double, _outputLength)); } + private void CheckOptionArguments(SrCnnEntireAnomalyDetectorOptions options) + { + Host.CheckUserArg(options.Period >= 0, nameof(options.Period), "Must be an integer equal to or greater than 0."); + + Host.CheckUserArg(options.BatchSize == -1 || options.BatchSize >= MinBatchSize, nameof(options.BatchSize), "Must be -1 or no less than 12."); + Host.CheckUserArg(options.BatchSize >= 4 * options.Period || options.BatchSize == -1 || options.Period == 0, nameof(options.BatchSize), "Must be at least four times the length of one period."); + + Host.CheckUserArg(options.Threshold >= 0 && options.Threshold <= 1, nameof(options.Threshold), "Must be in [0,1]."); + Host.CheckUserArg(options.DetectMode == SrCnnDetectMode.AnomalyOnly + || options.DetectMode == SrCnnDetectMode.AnomalyAndExpectedValue + || options.DetectMode == SrCnnDetectMode.AnomalyAndMargin, nameof(options.DetectMode), "Invalid detectMode"); + + Host.CheckUserArg(options.DeseasonalityMode == SrCnnDeseasonalityMode.Stl + || options.DeseasonalityMode == SrCnnDeseasonalityMode.Mean + || options.DeseasonalityMode == SrCnnDeseasonalityMode.Median, nameof(options.DeseasonalityMode), "Invalid detectMode"); + + Host.CheckUserArg(options.Sensitivity >= 0 && options.Sensitivity <= 100, nameof(options.Sensitivity), "Must be in [0,100]."); + } + protected override ColumnBindingsBase SchemaBindings => _bindings; protected override Delegate[] CreateGetters(DataViewRowCursor input, Batch currentBatch, bool[] active) @@ -159,16 +228,17 @@ protected override Delegate[] CreateGetters(DataViewRowCursor input, Batch curre return new[] { currentBatch.CreateGetter(input, _inputColumnName) }; } - protected override Batch CreateBatch(DataViewRowCursor input) => new Batch(_batchSize, _outputLength, _threshold, _sensitivity, _detectMode); + protected override Batch CreateBatch(DataViewRowCursor input) + => new Batch(_options.BatchSize, _outputLength, _options.Threshold, _options.Sensitivity, _options.DetectMode, _options.Period, _options.DeseasonalityMode); protected override Func GetIsNewBatchDelegate(DataViewRowCursor input) { - return () => _batchSize == -1 ? input.Position == 0 : input.Position % _batchSize == 0; + return () => _options.BatchSize == -1 ? input.Position == 0 : input.Position % _options.BatchSize == 0; } protected override Func GetLastInBatchDelegate(DataViewRowCursor input) { - return () => _batchSize == -1 ? input.Position == -1 : (input.Position + 1) % _batchSize == 0; + return () => _options.BatchSize == -1 ? input.Position == -1 : (input.Position + 1) % _options.BatchSize == 0; } protected override ValueGetter GetLookAheadGetter(DataViewRowCursor input) @@ -202,7 +272,7 @@ internal sealed class Batch private double[][] _results; private int _bLen; - public Batch(int batchSize, int outputLength, double threshold, double sensitivity, SrCnnDetectMode detectMode) + public Batch(int batchSize, int outputLength, double threshold, double sensitivity, SrCnnDetectMode detectMode, int period, SrCnnDeseasonalityMode deseasonalityMode) { _batchSize = batchSize; _outputLength = outputLength; @@ -216,7 +286,7 @@ public Batch(int batchSize, int outputLength, double threshold, double sensitivi _previousBatch = new List(batchSize); _batch = new List(batchSize); } - _modeler = new SrCnnEntireModeler(threshold, sensitivity, detectMode); + _modeler = new SrCnnEntireModeler(threshold, sensitivity, detectMode, period, deseasonalityMode); } public void AddValue(double value) @@ -312,6 +382,8 @@ internal sealed class SrCnnEntireModeler private readonly double _threshold; private readonly double _sensitivity; private readonly SrCnnDetectMode _detectMode; + private readonly int _period; + private readonly IDeseasonality _deseasonalityFunction; //used in all modes private readonly double[] _predictArray; @@ -329,6 +401,7 @@ internal sealed class SrCnnEntireModeler private double[] _cumSumList; private double[] _cumSumShift; private double[] _zeroArray; + private double[] _seriesToDetect; //used in AnomalyAndExpectedValue and AnomalyAndMargin private double[] _deAnomalyData; //used in AnomalyAndMargin mode @@ -337,12 +410,27 @@ internal sealed class SrCnnEntireModeler private double[] _trends; private double[] _curWindow; - public SrCnnEntireModeler(double threshold, double sensitivity, SrCnnDetectMode detectMode) + public SrCnnEntireModeler(double threshold, double sensitivity, SrCnnDetectMode detectMode, int period, SrCnnDeseasonalityMode deseasonalityMode) { _threshold = threshold; _sensitivity = sensitivity; _detectMode = detectMode; + _period = period; _predictArray = new double[_lookaheadWindowSize + 1]; + + switch (deseasonalityMode) + { + case SrCnnDeseasonalityMode.Stl: + _deseasonalityFunction = new StlDeseasonality(); + break; + case SrCnnDeseasonalityMode.Mean: + _deseasonalityFunction = new MeanDeseasonality(); + break; + default: + Contracts.Assert(deseasonalityMode == SrCnnDeseasonalityMode.Median); + _deseasonalityFunction = new MedianDeseasonality(); + break; + } } public void Train(double[] values, ref double[][] results) @@ -359,27 +447,42 @@ public void Train(double[] values, ref double[][] results) { Array.Resize(ref results, values.Length); } - SpectralResidual(values, results, _threshold); - //Optional Steps - if (_detectMode == SrCnnDetectMode.AnomalyAndMargin) + + Array.Resize(ref _seriesToDetect, values.Length); + for (int i = 0; i < values.Length; ++i) { - GetMargin(values, results, _sensitivity); + _seriesToDetect[i] = values[i]; } - else if (_detectMode == SrCnnDetectMode.AnomalyAndExpectedValue) + + if (_period > 0) { - GetExpectedValue(values, results); + _deseasonalityFunction.Deseasonality(ref values, _period, ref _seriesToDetect); } - } - private void AllocateDoubleArray(ref double[] arr, int length) - { - if (arr == null) + SpectralResidual(_seriesToDetect, results, _threshold); + + //Optional Steps + if (_detectMode == SrCnnDetectMode.AnomalyAndMargin) { - arr = new double[length]; + if (_period > 0) + { + GetMarginPeriod(values, results, _seriesToDetect, _sensitivity); + } + else + { + GetMargin(values, results, _sensitivity); + } } - else if (arr.Length != length) + else if (_detectMode == SrCnnDetectMode.AnomalyAndExpectedValue) { - Array.Resize(ref arr, length); + if (_period > 0) + { + GetExpectedValuePeriod(values, results, _seriesToDetect); + } + else + { + GetExpectedValue(values, results); + } } } @@ -390,18 +493,18 @@ private void SpectralResidual(double[] values, double[][] results, double thresh // Step 2: FFT transformation int length = _backAddArray.Length; - AllocateDoubleArray(ref _fftRe, length); - AllocateDoubleArray(ref _fftIm, length); + Array.Resize(ref _fftRe, length); + Array.Resize(ref _fftIm, length); - AllocateDoubleArray(ref _zeroArray, length); + Array.Resize(ref _zeroArray, length); FftUtils.ComputeForwardFft(_backAddArray, _zeroArray, _fftRe, _fftIm, length); // Step 3: Calculate mags of FFT - AllocateDoubleArray(ref _magList, length); - AllocateDoubleArray(ref _magLogList, length); + Array.Resize(ref _magList, length); + Array.Resize(ref _magLogList, length); for (int i = 0; i < length; ++i) { - _magList[i] = Math.Sqrt((Math.Pow(_fftRe[i], 2) + Math.Pow(_fftIm[i], 2))); + _magList[i] = Math.Sqrt(_fftRe[i] * _fftRe[i] + _fftIm[i] * _fftIm[i]); if (_magList[i] > _eps) { _magLogList[i] = Math.Log(_magList[i]); @@ -414,15 +517,15 @@ private void SpectralResidual(double[] values, double[][] results, double thresh // Step 4: Calculate spectral AverageFilter(_magLogList, _averagingWindowSize); - AllocateDoubleArray(ref _spectralList, length); + Array.Resize(ref _spectralList, length); for (int i = 0; i < length; ++i) { _spectralList[i] = Math.Exp(_magLogList[i] - _cumSumList[i]); } // Step 5: IFFT transformation - AllocateDoubleArray(ref _transRe, length); - AllocateDoubleArray(ref _transIm, length); + Array.Resize(ref _transRe, length); + Array.Resize(ref _transIm, length); for (int i = 0; i < length; ++i) { if (_magLogList[i] != 0) @@ -437,15 +540,15 @@ private void SpectralResidual(double[] values, double[][] results, double thresh } } - AllocateDoubleArray(ref _ifftRe, length); - AllocateDoubleArray(ref _ifftIm, length); + Array.Resize(ref _ifftRe, length); + Array.Resize(ref _ifftIm, length); FftUtils.ComputeBackwardFft(_transRe, _transIm, _ifftRe, _ifftIm, length); // Step 6: Calculate mag and ave_mag of IFFT - AllocateDoubleArray(ref _ifftMagList, length); + Array.Resize(ref _ifftMagList, length); for (int i = 0; i < length; ++i) { - _ifftMagList[i] = Math.Sqrt((Math.Pow(_ifftRe[i], 2) + Math.Pow(_ifftIm[i], 2))); + _ifftMagList[i] = Math.Sqrt(_ifftRe[i] * _ifftRe[i] + _ifftIm[i] * _ifftIm[i]); } AverageFilter(_ifftMagList, Math.Min(_ifftMagList.Length, _judgementWindowSize)); @@ -473,7 +576,7 @@ private void BackAdd(double[] data) _predictArray[j++] = data[i]; } var predictedValue = PredictNext(_predictArray); - AllocateDoubleArray(ref _backAddArray, data.Length + _backAddWindowSize); + Array.Resize(ref _backAddArray, data.Length + _backAddWindowSize); for (int i = 0; i < data.Length; ++i) { _backAddArray[i] = data[i]; @@ -500,8 +603,8 @@ private void AverageFilter(double[] data, int n) double cumsum = 0.0f; int length = data.Length; - AllocateDoubleArray(ref _cumSumList, length); - AllocateDoubleArray(ref _cumSumShift, length); + Array.Resize(ref _cumSumList, length); + Array.Resize(ref _cumSumShift, length); for (int i = 0; i < length; ++i) { @@ -541,6 +644,102 @@ private void GetExpectedValue(double[] values, double[][] results) } } + private void GetExpectedValuePeriod(double[] values, double[][] results, IReadOnlyList residual) + { + //Step 8: Calculate Expected Value + for (int i = 0; i < values.Length; ++i) + { + results[i][3] = values[i] - residual[i]; + } + } + + private void GetMarginPeriod(double[] values, double[][] results, IReadOnlyList residual, double sensitivity) + { + //Step 8: Calculated Expected Value + GetExpectedValuePeriod(values, results, residual); + + //Step 9: Calculate Boundary Unit + CalculateBoundaryUnit(values, results.Select(x => x[0] > 0).ToArray()); + + for (int i = 0; i < results.Length; ++i) + { + //Step 10: Calculate UpperBound and LowerBound + var margin = CalculateMargin(_units[i], sensitivity); + results[i][4] = _units[i]; + results[i][5] = results[i][3] + margin; + results[i][6] = results[i][3] - margin; + + // update anomaly result according to the boundary + results[i][0] = results[i][0] > 0 && (values[i] < results[i][6] || results[i][5] < values[i]) ? 1 : 0; + } + + List> segments = new List>(); + int start = -1; + int cursor = -1; + for(int i = 0; i < values.Length; ++i) + { + // this is a outlier + if (results[i][6] > values[i] || values[i] > results[i][5]) + { + if (cursor + 1 == i) + { + cursor = i; + } + else + { + if (start > -1) + { + segments.Add(new Tuple(start, cursor)); + } + start = i; + cursor = i; + } + } + } + + if (start > -1) + { + segments.Add(new Tuple(start, Math.Max(start, cursor))); + } + + List anomalyIndex = new List(); + for (int i = 0; i < values.Length; ++i) + { + if(results[i][0] > 0) + { + anomalyIndex.Add(i); + } + } + + // more than one anomaly, update anomaly results + if (anomalyIndex.Count > 1) + { + cursor = 0; + for(int i = 0; i < anomalyIndex.Count - 1; ++i) + { + while (cursor < segments.Count && anomalyIndex[i] >= segments[cursor].Item2) + { + ++cursor; + } + + if (cursor < segments.Count && segments[cursor].Item1 <= anomalyIndex[i] && anomalyIndex[i+1] <= segments[cursor].Item2) + { + for (int j = anomalyIndex[i]; j < anomalyIndex[i+1]; ++j) + { + results[j][0] = 1; + } + } + } + } + + //Step 11: Update Anomaly Score + for (int i = 0; i < results.Length; ++i) + { + results[i][1] = CalculateAnomalyScore(values[i], _ifftRe[i], _units[i], results[i][0] > 0); + } + + } + private void GetMargin(double[] values, double[][] results, double sensitivity) { //Step 8: Calculate Expected Value @@ -558,8 +757,10 @@ private void GetMargin(double[] values, double[][] results, double sensitivity) results[i][4] = _units[i]; results[i][5] = _ifftRe[i] + margin; results[i][6] = _ifftRe[i] - margin; + //Step 11: Update Anomaly Score results[i][1] = CalculateAnomalyScore(values[i], _ifftRe[i], _units[i], results[i][0] > 0); + //Step 12: Update IsAnomaly results[i][0] = results[i][0] > 0 && (values[i] < results[i][6] || values[i] > results[i][5]) ? 1 : 0; } @@ -579,7 +780,7 @@ private int[] GetAnomalyIndex(double[] scores) private void GetDeanomalyData(double[] data, int[] anomalyIdxList) { - AllocateDoubleArray(ref _deAnomalyData, data.Length); + Array.Resize(ref _deAnomalyData, data.Length); Array.Copy(data, _deAnomalyData, data.Length); int minPointsToFit = 4; foreach (var idx in anomalyIdxList) @@ -624,11 +825,11 @@ private double CalculateInterpolate(List> values, int idx) var n = values.Count; double sumX = values.Sum(item => item.Item1); double sumY = values.Sum(item => item.Item2); - double sumXX = values.Sum(item => Math.Pow(item.Item1, 2)); + double sumXX = values.Sum(item => item.Item1 * item.Item1); double sumXY = values.Sum(item => item.Item1 * item.Item2); - var a = ((double)n * sumXY - sumX * sumY) / ((double)n * sumXX - sumX * sumX); - var b = (sumXX * sumY - sumX * sumXY) / ((double)n * sumXX - sumX * sumX); + var a = ((n * sumXY) - (sumX * sumY)) / ((n * sumXX) - (sumX * sumX)); + var b = ((sumXX * sumY) - (sumX * sumXY)) / ((n * sumXX) - (sumX * sumX)); return a * (double)idx + b; } @@ -636,9 +837,9 @@ private double CalculateInterpolate(List> values, int idx) private void CalculateExpectedValueByFft(double[] data) { int length = data.Length; - AllocateDoubleArray(ref _fftRe, length); - AllocateDoubleArray(ref _fftIm, length); - AllocateDoubleArray(ref _zeroArray, length); + Array.Resize(ref _fftRe, length); + Array.Resize(ref _fftIm, length); + Array.Resize(ref _zeroArray, length); FftUtils.ComputeForwardFft(data, _zeroArray, _fftRe, _fftIm, length); for (int i = 0; i < length; ++i) @@ -650,8 +851,8 @@ private void CalculateExpectedValueByFft(double[] data) } } - AllocateDoubleArray(ref _ifftRe, length); - AllocateDoubleArray(ref _ifftIm, length); + Array.Resize(ref _ifftRe, length); + Array.Resize(ref _ifftIm, length); FftUtils.ComputeBackwardFft(_fftRe, _fftIm, _ifftRe, _ifftIm, length); } @@ -682,7 +883,7 @@ private void CalculateBoundaryUnit(double[] data, bool[] isAnomalys) trendFraction = 1.0; } - AllocateDoubleArray(ref _units, _trends.Length); + Array.Resize(ref _units, _trends.Length); for (int i = 0; i < _units.Length; ++i) { _units[i] = Math.Max(1, averageTrendPart + Math.Abs(_trends[i]) * trendFraction); @@ -697,11 +898,11 @@ private void MedianFilter(double[] data, int window, bool needTwoEnd = false) { int wLen = window / 2 * 2 + 1; int tLen = data.Length; - AllocateDoubleArray(ref _val, tLen); + Array.Resize(ref _val, tLen); Array.Copy(data, _val, tLen); - AllocateDoubleArray(ref _trends, tLen); + Array.Resize(ref _trends, tLen); Array.Copy(data, _trends, tLen); - AllocateDoubleArray(ref _curWindow, wLen); + Array.Resize(ref _curWindow, wLen); if (tLen < wLen) return; diff --git a/src/Microsoft.ML.TimeSeries/SrCnnTransformBase.cs b/src/Microsoft.ML.TimeSeries/SrCnnTransformBase.cs index c76973bef2..fda4001b69 100644 --- a/src/Microsoft.ML.TimeSeries/SrCnnTransformBase.cs +++ b/src/Microsoft.ML.TimeSeries/SrCnnTransformBase.cs @@ -26,7 +26,7 @@ internal abstract class SrCnnArgumentBase SortOrder = 3)] public int WindowSize = 24; - [Argument(ArgumentType.AtMostOnce, HelpText = "The size of the initial window for computingd. The default value is set to 0, which means there is no initial window considered.", ShortName = "iwnd", + [Argument(ArgumentType.AtMostOnce, HelpText = "The size of the initial window for computing. The default value is set to 0, which means there is no initial window considered.", ShortName = "iwnd", SortOrder = 4)] public int InitialWindowSize = 0; diff --git a/test/Microsoft.ML.TimeSeries.Tests/TimeSeriesDirectApi.cs b/test/Microsoft.ML.TimeSeries.Tests/TimeSeriesDirectApi.cs index d25b614d37..1cd4278934 100644 --- a/test/Microsoft.ML.TimeSeries.Tests/TimeSeriesDirectApi.cs +++ b/test/Microsoft.ML.TimeSeries.Tests/TimeSeriesDirectApi.cs @@ -616,8 +616,7 @@ public void TestSrCnnBatchAnomalyDetector( var outputDataView = ml.AnomalyDetection.DetectEntireAnomalyBySrCnn(dataView, outputColumnName, inputColumnName, threshold: 0.35, batchSize: batchSize, sensitivity: 90.0, mode); - // Getting the data of the newly created column as an IEnumerable of - // SrCnnAnomalyDetection. + // Getting the data of the newly created column as an IEnumerable of SrCnnAnomalyDetection. var predictionColumn = ml.Data.CreateEnumerable( outputDataView, reuseRowObject: false); @@ -661,6 +660,98 @@ public void TestSrCnnBatchAnomalyDetector( } } + [Theory, CombinatorialData] + public void TestSrCnnAnomalyDetectorWithSeasonalData( + [CombinatorialValues(SrCnnDeseasonalityMode.Stl, SrCnnDeseasonalityMode.Mean, SrCnnDeseasonalityMode.Median)] SrCnnDeseasonalityMode mode) + { + var ml = new MLContext(1); + IDataView dataView; + var dataPath = GetDataPath("Timeseries", "period_no_anomaly.csv"); + + // Load data from file into the dataView + dataView = ml.Data.LoadFromTextFile(dataPath, hasHeader: true); + + // Setup the detection arguments + string outputColumnName = nameof(SrCnnAnomalyDetection.Prediction); + string inputColumnName = nameof(TimeSeriesDataDouble.Value); + + // Do batch anomaly detection + var options = new SrCnnEntireAnomalyDetectorOptions() + { + Threshold = 0.3, + BatchSize = -1, + Sensitivity = 53.0, + DetectMode = SrCnnDetectMode.AnomalyAndMargin, + Period = 288, + DeseasonalityMode = mode + }; + + var outputDataView = ml.AnomalyDetection.DetectEntireAnomalyBySrCnn(dataView, outputColumnName, inputColumnName, options); + + // Getting the data of the newly created column as an IEnumerable of SrCnnAnomalyDetection. + var predictionColumn = ml.Data.CreateEnumerable( + outputDataView, reuseRowObject: false); + + foreach (var prediction in predictionColumn) + { + Assert.Equal(7, prediction.Prediction.Length); + Assert.Equal(0, prediction.Prediction[0]); + } + } + + [Theory, CombinatorialData] + public void TestSrCnnAnomalyDetectorWithSeasonalAnomalyData( + [CombinatorialValues(SrCnnDeseasonalityMode.Stl, SrCnnDeseasonalityMode.Mean, SrCnnDeseasonalityMode.Median)] SrCnnDeseasonalityMode mode + ) + { + var ml = new MLContext(1); + IDataView dataView; + var dataPath = GetDataPath("Timeseries", "period_anomaly.csv"); + + // Load data from file into the dataView + dataView = ml.Data.LoadFromTextFile(dataPath, hasHeader: true); + + // Setup the detection arguments + string outputColumnName = nameof(SrCnnAnomalyDetection.Prediction); + string inputColumnName = nameof(TimeSeriesDataDouble.Value); + + // Do batch anomaly detection + var options = new SrCnnEntireAnomalyDetectorOptions() + { + Threshold = 0.23, + BatchSize = -1, + Sensitivity = 53.0, + DetectMode = SrCnnDetectMode.AnomalyAndMargin, + Period = 288, + DeseasonalityMode = mode + }; + + var outputDataView = ml.AnomalyDetection.DetectEntireAnomalyBySrCnn(dataView, outputColumnName, inputColumnName, options); + + // Getting the data of the newly created column as an IEnumerable of SrCnnAnomalyDetection. + var predictionColumn = ml.Data.CreateEnumerable( + outputDataView, reuseRowObject: false); + + var anomalyStartIndex = 2988; + var anomalyEndIndex = 3095; + + int k = 0; + foreach (var prediction in predictionColumn) + { + Assert.Equal(7, prediction.Prediction.Length); + if (anomalyStartIndex <= k && k <= anomalyEndIndex) + { + Assert.Equal(1, prediction.Prediction[0]); + } + else + { + Assert.Equal(0, prediction.Prediction[0]); + } + + ++k; + } + } + [Fact] public void RootCauseLocalization() { diff --git a/test/data/Timeseries/period_anomaly.csv b/test/data/Timeseries/period_anomaly.csv new file mode 100644 index 0000000000..52183ce307 --- /dev/null +++ b/test/data/Timeseries/period_anomaly.csv @@ -0,0 +1,4033 @@ +Value +18.09048623 +20.35984259 +21.10546985 +21.15158525 +18.13714054 +21.62566053 +21.67380669 +20.24556149 +19.9283328 +18.17946985 +20.24781657 +19.63751633 +21.09122563 +19.61553427 +20.73432333 +18.40563259 +18.53180908 +18.55884076 +18.182102 +20.16531544 +21.1758709 +20.44164481 +20.29981954 +20.72249571 +19.35858129 +19.44781629 +19.25708039 +20.84843573 +18.64656134 +18.05210112 +20.38478579 +21.76952546 +20.43763167 +21.13168661 +20.69116284 +19.98974661 +20.87356961 +21.2964165 +18.89892658 +19.34452192 +18.89490293 +19.80869182 +21.5402582 +19.3808284 +19.49786756 +21.44146894 +20.06149732 +20.141796 +21.44320481 +19.96210695 +20.72623014 +18.34257866 +18.71452685 +19.6175048 +19.97935627 +21.8629348 +21.88260653 +21.40478835 +19.26239534 +21.85611316 +20.75736346 +19.57176051 +20.80669967 +18.06609092 +18.58461873 +21.31874285 +20.58229455 +19.45677881 +20.00266656 +21.6205686 +20.52631244 +19.59259714 +18.48130663 +19.17498721 +21.91336093 +19.74945225 +19.88735786 +19.99439213 +21.53641609 +20.41571314 +20.77470815 +19.55765417 +18.11635047 +21.72389166 +21.79651072 +21.79661221 +21.77474835 +21.26096776 +20.7383842 +21.37803967 +20.40218496 +18.53747846 +19.56487266 +21.88517965 +19.40455125 +21.47131165 +18.37284588 +19.33673537 +19.4038133 +18.20641017 +18.47637732 +18.77266084 +21.35126236 +18.25360796 +19.19480361 +18.04070001 +20.78251098 +20.48121236 +69.97175876 +66.29160587 +64.03244237 +70.9963549 +72.23120307 +63.08498037 +67.82088022 +64.58253327 +63.48625331 +71.18682426 +68.51811832 +64.14012052 +74.65120017 +84.84246498 +83.01150684 +83.49677345 +76.97938775 +79.52148874 +75.68743533 +71.04608986 +76.0645957 +79.05858129 +74.29647908 +83.00019292 +73.97109693 +77.40682104 +73.55447171 +78.00645026 +72.19877339 +75.90262558 +77.9412935 +79.17274194 +80.21494689 +75.94145893 +79.88644939 +79.6632095 +76.9663782 +85.18086544 +80.63338172 +77.22353592 +87.05282729 +85.41917245 +87.6161393 +82.9760511 +77.95790461 +76.40197814 +82.5139498 +87.58783364 +82.0077547 +86.08517365 +77.24711114 +78.49241782 +86.47964374 +84.08968086 +87.68151651 +84.37597226 +79.15724902 +80.47776902 +86.3875099 +80.80694945 +76.08270584 +78.96612645 +80.25720329 +73.54398706 +83.89617558 +73.74612295 +78.47491644 +84.86988511 +79.47731069 +85.46814565 +77.46638259 +87.31798924 +75.35077153 +72.61152924 +85.95799948 +84.03443672 +75.71101456 +87.75502326 +80.03571372 +87.21620976 +80.07969157 +79.54922971 +79.18545641 +77.35726178 +80.53906932 +79.24072245 +72.58781066 +76.16681749 +75.40982001 +85.87880475 +81.581763 +84.21876791 +87.30904897 +82.30447034 +87.72159144 +76.98807701 +74.98024612 +78.45292808 +79.5327601 +86.32575154 +80.95901594 +76.67486655 +83.88211632 +80.09328024 +74.59408248 +81.22908541 +86.58227934 +85.48192905 +32.55557757 +31.21332632 +29.35665837 +31.805747 +33.61330195 +31.10574583 +30.30685386 +34.76082353 +34.05794994 +32.88495765 +29.6754077 +29.72741087 +20.62242264 +22.92100781 +20.67772019 +23.93496854 +24.60848186 +21.80123867 +22.1924397 +23.34826767 +24.35844413 +24.16553878 +20.41801027 +20.91744053 +21.52282987 +21.25370592 +18.97766313 +20.48845628 +21.63021647 +19.32812544 +22.00079389 +18.64897217 +21.63587081 +20.95439396 +19.72305629 +21.38493946 +21.23088455 +21.83992669 +19.56455991 +20.84363841 +20.50843529 +20.19730819 +21.66516184 +18.09913002 +19.22026292 +20.24984383 +18.80299623 +21.73529712 +20.61014723 +19.93064704 +21.27921548 +19.82255616 +20.25403727 +18.02829454 +19.4814864 +18.57297484 +20.77868312 +19.93522729 +19.22546897 +19.89040582 +18.84213655 +21.70451299 +18.21938798 +21.46578878 +20.04928388 +20.47971733 +19.21411088 +21.87098889 +19.13107629 +20.35942024 +21.97788576 +21.52851026 +20.1453193 +21.96149809 +20.80547945 +18.83480166 +19.62238484 +19.33797334 +19.37605483 +21.04182576 +20.33705171 +18.15237085 +21.50979393 +19.18718456 +21.98829951 +21.81676292 +21.76212287 +21.24451042 +18.88245333 +20.13053098 +18.89721051 +19.03870182 +20.44380708 +18.16333418 +21.87783427 +21.67469269 +19.52307029 +20.06168979 +19.86447768 +21.52879911 +20.75440751 +19.11244499 +19.78736502 +19.7158639 +21.83734067 +18.70124364 +18.35830535 +21.52247533 +21.58674396 +21.48695635 +20.04390766 +20.63897771 +20.25345219 +18.2777913 +20.38333959 +18.05445659 +19.29994964 +21.7291703 +19.21618108 +21.75930657 +19.00053583 +19.25824896 +20.51362999 +21.04650789 +20.00555107 +21.52846275 +18.16096169 +21.68877935 +18.7852312 +21.53695498 +19.60345272 +21.33102822 +20.6866622 +18.70376653 +21.67219028 +18.98206956 +18.97656047 +21.25671559 +18.42349302 +18.88814363 +20.01471029 +21.32190811 +18.5899359 +20.19067294 +20.84496237 +21.4423809 +21.74226224 +21.13855966 +20.61131359 +19.73448034 +18.44844062 +20.83894877 +21.97094922 +20.94704238 +18.06684438 +19.98503991 +20.45858653 +20.7586968 +20.87890334 +20.23243376 +18.89344133 +21.76880265 +20.78666587 +18.94736015 +19.28928733 +21.68771068 +21.54994075 +19.62058575 +18.15322889 +18.19398948 +19.13567316 +20.51648888 +20.33677854 +20.53531115 +20.86913189 +18.07612901 +18.42034238 +19.43793381 +18.61943999 +18.30128017 +69.91711579 +72.28857609 +71.43572254 +72.31174099 +70.255649 +71.20069638 +64.89619133 +74.70490929 +63.6910529 +64.11711669 +65.12933691 +74.46452105 +85.17823891 +82.176751 +79.60297393 +77.91137117 +84.90403553 +80.6360659 +84.50221159 +74.75286841 +75.02018478 +83.1053257 +72.16574837 +84.52080041 +79.63887214 +86.30168633 +76.92435251 +82.95461041 +79.24764594 +81.53668494 +79.58954013 +86.94900678 +82.57524425 +75.56497688 +86.03550177 +76.24424896 +77.85214677 +73.54561839 +86.29578496 +76.48589902 +76.05131067 +86.62013253 +84.78656368 +74.16815403 +84.20802103 +86.50459933 +73.16827208 +85.10119579 +80.73933874 +82.68730947 +79.86649686 +83.14488979 +72.52815485 +84.18309878 +72.51609113 +79.26576921 +74.39758018 +85.15674591 +77.00009009 +79.24647299 +78.85622658 +84.35598217 +79.69448424 +84.61927144 +73.17261997 +75.06190034 +80.82066842 +87.14922983 +73.19261213 +72.68585837 +74.50123457 +82.25450166 +78.38313418 +85.20802007 +73.15022817 +75.14190402 +76.7996852 +82.02689392 +82.9619666 +73.98654243 +87.10003918 +77.45596258 +83.40989947 +80.38655178 +75.56398473 +85.53948893 +85.09164507 +78.33699926 +81.41756505 +76.12506497 +83.03746663 +76.94428127 +85.50509558 +75.47801675 +72.23671607 +76.29598218 +75.05681096 +80.13255226 +75.25922377 +84.21100559 +75.86190108 +83.31145889 +81.25550357 +87.779964 +87.99838184 +85.91238434 +84.15970159 +78.1832726 +33.6209646 +34.92271673 +28.94961092 +32.24264789 +30.19518335 +32.37040221 +31.78525527 +32.48491268 +32.32615201 +34.94467834 +32.33398489 +34.21587879 +21.5927937 +22.12268987 +22.26745115 +21.40870046 +21.86145917 +22.84133734 +22.75923993 +23.01122908 +21.73614307 +21.57492391 +22.90004686 +20.75521949 +19.46841697 +18.60455499 +18.72941383 +19.42889768 +18.51199171 +19.43720155 +21.11478277 +18.68229437 +20.22087319 +22.17209333 +21.6731024 +19.68307177 +21.80337813 +19.41131515 +18.37785424 +22.08170965 +21.58319449 +19.95907699 +20.76470048 +20.78419984 +18.86806294 +18.89043542 +19.97373871 +21.75019471 +18.05729347 +21.15030736 +18.24760803 +19.93200482 +20.57122075 +20.76695421 +18.25142161 +19.6933019 +20.35487097 +18.28171576 +18.55817698 +20.67442436 +20.0904094 +18.65089493 +20.14482441 +21.65492644 +18.06581831 +20.57448463 +18.2981143 +18.02925872 +18.60618966 +19.69540732 +21.21344819 +19.1308144 +20.50269285 +19.64462655 +18.93732717 +20.05698846 +21.18985796 +21.32996948 +21.38607813 +19.35423125 +21.17382426 +18.84871382 +20.95370041 +21.79353771 +18.05497534 +19.76145572 +20.59108395 +20.80710308 +18.70435103 +21.8887331 +20.46106147 +18.6573624 +18.08209005 +21.1330568 +18.31881896 +18.56420368 +20.29932011 +20.41402201 +20.74754847 +19.57405605 +21.09559468 +21.8974344 +19.08437977 +20.81211447 +21.71387461 +20.74514705 +20.72443799 +18.89509028 +20.1405208 +20.25009137 +20.80051825 +21.9872858 +18.13457529 +18.26093065 +18.31180028 +20.97191654 +18.54541518 +20.4898075 +19.29867551 +19.82927982 +18.86265264 +21.46442625 +20.3446013 +21.77825305 +20.298385 +18.49563212 +18.68348174 +21.95629591 +20.90226079 +18.197115 +20.81512402 +19.64869219 +19.22883355 +18.61624317 +21.35961582 +18.25536552 +19.15934185 +19.22553158 +18.64362114 +20.03273953 +18.04681051 +19.20390206 +21.73451778 +19.24211828 +19.44183755 +19.89266019 +20.2467735 +21.23483458 +18.76128489 +21.48698551 +21.03019743 +20.89060134 +18.34721829 +18.08656276 +20.3760508 +21.45253585 +20.33776586 +18.85293946 +18.36207959 +20.79838581 +20.88708111 +18.6901268 +18.11276126 +19.63313405 +20.33087481 +20.82400964 +21.23978004 +20.44214971 +18.44352243 +20.73032669 +21.93670657 +21.62233834 +21.48667564 +19.20868061 +21.00315271 +21.40441378 +20.71330482 +19.00224703 +21.81533589 +19.80327765 +62.9653556 +62.69297937 +70.00625823 +67.15285119 +62.4849807 +71.26895818 +72.07082227 +71.06565258 +63.95074794 +70.5809462 +61.34583012 +65.3495251 +76.02971017 +82.80303265 +75.89892067 +70.0149018 +75.30841631 +77.58330201 +84.56855429 +84.44485239 +72.64716507 +72.71347433 +72.3756802 +82.08406839 +71.66377453 +73.59062616 +80.12370998 +75.50522711 +73.03683711 +77.29149991 +75.92899775 +79.69660289 +87.14173108 +73.54494094 +77.49584551 +86.39028972 +85.92673273 +78.21436655 +83.08343233 +73.31762536 +83.3005761 +87.4606448 +80.50309067 +79.87987262 +74.9071014 +82.04204245 +81.3492601 +82.33201184 +72.39995243 +80.76018872 +81.49939295 +75.30240525 +75.31524572 +76.40115002 +83.36753246 +81.68064895 +85.51167461 +76.71212182 +86.57230662 +83.87916276 +78.31642735 +73.52066389 +76.10808524 +87.30410068 +76.96211966 +77.274706 +75.02982129 +84.90553396 +76.40663999 +77.28042234 +78.62579552 +78.93586337 +78.58069826 +80.05913055 +85.03138976 +85.10774361 +84.77219632 +73.61729069 +84.79404682 +73.92331871 +73.99486996 +87.16496755 +85.10954846 +80.83779142 +85.99935815 +87.82966565 +81.77011607 +81.80621792 +84.07067105 +75.71407787 +74.67385441 +84.15313043 +77.51832788 +74.16098331 +77.0378957 +77.73804063 +87.44360897 +83.16732344 +80.49367017 +87.50193662 +86.45020265 +80.19198291 +86.49084095 +78.4688444 +75.68670158 +75.72282175 +82.59701667 +80.0170944 +33.01727908 +33.1908798 +28.94286083 +29.1458478 +32.20913127 +30.02262129 +32.84820981 +32.33398252 +32.54886004 +30.73570853 +32.89499212 +34.10874632 +24.63135786 +23.91622954 +22.6575932 +21.02656342 +23.21287625 +24.36068762 +21.10916094 +21.30685921 +20.82755713 +23.46051168 +21.98139433 +20.44087534 +22.0157949 +20.71622387 +19.78816198 +19.84095403 +19.62086876 +20.29764654 +19.81252252 +20.67638781 +21.60032641 +21.19459316 +19.6380952 +20.59772294 +21.46303501 +18.36053445 +18.40109233 +20.32175869 +20.65513147 +18.93611115 +21.08158868 +20.68386171 +21.79728417 +18.76546068 +21.1063234 +18.42257826 +20.28062035 +20.22697983 +19.57231157 +21.39880773 +18.03477935 +20.09999509 +18.88672806 +20.9941295 +18.18971508 +21.34669191 +21.37286717 +21.35194224 +18.61384728 +20.52556622 +18.06093647 +21.3959576 +20.89591202 +20.12847885 +20.92638282 +18.38082483 +20.11848533 +19.16878567 +21.89468082 +21.43258607 +20.93310278 +21.73499054 +19.38737322 +21.6035196 +19.30095293 +20.93118688 +20.94566765 +18.07339951 +19.44423879 +18.07773069 +21.98836807 +18.48878705 +20.17124358 +21.16222496 +18.80505441 +19.94021067 +20.42971504 +18.64081902 +21.11422184 +19.19734583 +18.84409231 +20.23315499 +19.64125451 +21.68114378 +21.52025079 +19.93340265 +19.4370551 +19.30207193 +19.07025449 +20.17819141 +21.21991442 +19.24302643 +18.76037636 +19.90193522 +18.27613767 +20.80511602 +20.07343307 +19.98549923 +19.20178152 +21.61869375 +18.36194517 +21.47929604 +19.50682081 +21.52249406 +20.91504583 +18.41668291 +21.32614515 +20.72870733 +18.12920765 +18.53481073 +20.54251222 +20.65040201 +20.98660573 +20.8809816 +20.63807982 +21.06495561 +20.30034282 +19.04316554 +21.64950645 +18.07285612 +19.46624688 +20.91548117 +19.70862416 +18.09933763 +18.26392361 +20.59454948 +21.8594584 +20.20745454 +20.02703127 +19.27330085 +19.0267627 +18.08393993 +19.09181947 +19.79644176 +18.79179913 +18.34939195 +20.87091147 +21.57848108 +21.74708828 +20.47199491 +18.21109833 +20.96345052 +18.44038122 +20.67899247 +21.11746334 +20.90345884 +21.80753522 +20.95258514 +20.77283911 +19.04697269 +21.69907475 +18.71817548 +21.61958645 +19.25065017 +18.52065438 +21.30673211 +18.00998181 +21.32835327 +19.04924737 +21.53888509 +20.76591673 +20.66473333 +19.46127825 +18.2376119 +21.32029239 +18.68361518 +19.48903457 +20.40141874 +67.75865084 +63.90178464 +63.11238245 +62.8761493 +72.93690719 +61.62920987 +74.48739393 +63.89999019 +62.70038324 +69.04681451 +62.28780903 +69.39336438 +83.04172553 +70.58337729 +82.25396074 +75.96228988 +72.31529464 +72.57301737 +84.09922572 +71.55660127 +83.29246886 +78.28667652 +70.4461519 +77.04866978 +84.56871708 +83.11752913 +79.34159557 +85.24623329 +73.48228117 +86.03970251 +85.02980098 +82.83243464 +84.57568665 +80.21684182 +82.30578327 +80.48375172 +77.59363226 +81.00445063 +76.02810199 +78.94961337 +76.40061563 +73.87744519 +77.05720995 +85.52903734 +78.00357558 +83.86729671 +74.71340187 +78.6961577 +73.81997606 +74.20012471 +81.85933112 +81.70009635 +75.39585117 +79.57166932 +85.79230358 +74.76927521 +72.29001476 +82.41213859 +72.8384859 +87.65800085 +81.75000035 +79.52252438 +78.87609441 +81.16523442 +73.44646539 +86.87613469 +82.0063366 +74.94005867 +80.9974088 +74.12854575 +72.277374 +82.08433153 +82.37494266 +81.33836447 +74.93501189 +81.65409385 +72.90347517 +81.74702891 +80.86349601 +82.48328545 +86.32678095 +85.60490787 +87.68962524 +87.61901538 +84.35695313 +87.30254633 +85.87637729 +83.64115861 +73.20600752 +72.78465847 +85.40142911 +79.83434044 +85.03354369 +77.00654448 +78.36224728 +83.20282779 +86.64519452 +73.4041554 +85.78361737 +84.68817108 +77.04859875 +77.683436 +72.7433557 +72.25182203 +79.63206744 +73.52860609 +75.10400019 +85.54824234 +32.45457547 +32.85524129 +29.99986196 +34.103429 +34.35506395 +32.14929043 +34.64036309 +34.20689663 +33.4804683 +33.49807943 +29.47451257 +30.53334478 +20.45947442 +20.19889071 +20.86922556 +24.10458126 +21.23463462 +24.50628841 +22.83586243 +21.22291686 +22.38714477 +21.14154365 +24.56820019 +23.95574581 +18.53947386 +22.31409036 +21.38548242 +18.76943338 +21.17893195 +21.0818115 +19.32815847 +21.53859742 +18.7886168 +20.43676722 +18.47264523 +22.39994849 +21.1070845 +18.72485822 +19.45965625 +18.73173226 +21.16758886 +18.32311607 +21.46416238 +21.87327547 +20.80590298 +18.94235069 +19.53367407 +20.00452246 +20.43810084 +20.69450002 +20.23626704 +19.42388472 +21.58437023 +18.34316077 +19.88409463 +21.12251751 +18.2610044 +20.84132934 +21.29927417 +20.66314278 +18.0552135 +18.72414245 +19.37217106 +18.93839561 +21.85480388 +20.61033208 +19.1915679 +21.72296 +20.96640157 +19.14210342 +19.51927326 +18.80132459 +21.88429599 +20.06918598 +21.58422675 +19.38599908 +21.44336641 +18.21554739 +21.92836127 +21.64813747 +19.45281178 +21.09888866 +21.00903171 +21.60501919 +19.22901992 +19.86208002 +21.45999845 +21.11431782 +19.57386688 +21.38290093 +18.18781616 +21.12818521 +18.82706344 +19.14448363 +19.97285937 +19.798938 +20.08228043 +20.17910238 +19.32611076 +18.70091005 +21.07392492 +19.5999046 +20.02336345 +20.57878687 +21.63855169 +20.83021132 +18.1818369 +21.35424145 +21.95742006 +19.8899401 +21.87836135 +20.18931497 +19.83846398 +19.32561906 +20.6302195 +18.91928168 +18.41973687 +18.10894841 +19.16952045 +19.58308333 +20.20830679 +19.1709993 +21.93623829 +19.16698067 +19.76390155 +18.41310466 +19.04250605 +18.19332856 +20.23803453 +21.00425873 +18.78283926 +19.47164375 +18.06646491 +21.35808822 +21.1198541 +18.25301612 +19.45947044 +21.82114646 +19.56810822 +20.10483471 +19.42097144 +20.38452555 +21.9126275 +21.99001001 +21.09885991 +19.61724439 +19.9777288 +19.42692531 +21.94229852 +20.83104122 +19.79572578 +18.04846108 +20.08193366 +21.93571281 +20.09224364 +18.72970674 +18.08837499 +19.41881503 +21.67291222 +21.98621643 +21.7814719 +20.91767997 +20.23257091 +20.36274459 +20.15596804 +20.82819722 +19.67549291 +20.67681602 +18.48644846 +19.06278123 +21.34401216 +21.61499572 +20.15603295 +18.12654247 +21.70789428 +20.80825703 +19.6561117 +20.39351577 +19.71909934 +19.86135691 +73.26061417 +63.39074576 +62.60990024 +61.23711093 +65.47040511 +63.20482722 +64.19180273 +61.35285016 +64.28985764 +65.72487751 +61.62931795 +69.46749609 +78.66778141 +71.34599528 +79.07455175 +85.33910882 +84.49815815 +69.88145382 +82.18427139 +75.32795389 +70.82786927 +74.43365948 +74.83335073 +77.96075059 +82.08187623 +83.48098046 +75.47884199 +76.68543915 +76.47250267 +77.33696715 +87.46653394 +83.94041029 +87.07424836 +82.59123829 +78.02932924 +77.7664915 +79.72151756 +78.57551263 +85.15091607 +79.34470417 +76.63775397 +84.29648698 +85.56792168 +78.63239106 +82.58571523 +72.8533435 +80.37487191 +72.63243457 +72.44966136 +81.78716398 +76.83492131 +83.86046326 +86.31660001 +74.21244352 +83.57230325 +80.21306422 +73.77619746 +82.40569959 +81.7318485 +80.23100981 +86.81937174 +80.33341895 +87.84402513 +80.14381393 +73.85008764 +79.5237227 +74.91366417 +81.55022117 +83.08612648 +79.4911487 +73.55971645 +79.49444646 +73.30256372 +82.91321931 +84.645079 +87.39724621 +74.38011966 +80.51795239 +81.07981951 +86.75879165 +82.0356387 +74.32744078 +78.98086296 +82.47540868 +83.20439116 +85.80901922 +74.88797013 +87.22450688 +72.94609054 +87.74002569 +85.7241089 +82.564206 +83.75976719 +73.16293162 +72.66353829 +73.62811138 +73.39772885 +80.75806872 +75.44707482 +85.76325726 +79.13194758 +83.1281357 +82.44593783 +77.11761901 +75.89065203 +77.47927081 +84.74650144 +81.38039832 +30.4226416 +34.0342107 +29.15045447 +33.27476721 +31.61023909 +33.48025204 +34.73574552 +33.60021178 +31.6285722 +29.76623865 +33.96063972 +31.74850928 +20.49739808 +23.3813669 +21.46749563 +20.37901815 +24.20432322 +22.32429167 +21.41870434 +23.3694105 +24.12884133 +20.16137459 +23.24157651 +23.59621109 +19.29186251 +20.43749897 +18.79771482 +21.49068726 +21.90317959 +18.87513232 +21.77622094 +21.59235116 +19.85295672 +21.25942566 +18.43219689 +22.24864293 +20.29850025 +20.57966591 +20.75779906 +20.3426543 +21.52990536 +20.53691355 +21.7348689 +20.42690721 +18.77417519 +21.75819057 +20.82599719 +20.89678132 +21.96299124 +18.31835496 +19.73329621 +18.97457969 +20.54140669 +21.24762488 +21.88623346 +19.83741007 +21.16517199 +21.68900784 +20.75320569 +18.98914229 +20.43533943 +21.88400911 +21.95442975 +20.57338863 +21.55208824 +18.80500732 +18.98795941 +21.81573827 +18.54450136 +18.76802852 +19.68597338 +20.36224595 +20.41526888 +19.16790403 +21.68245559 +21.66039963 +19.56827221 +19.73716708 +20.80998847 +20.65198359 +19.52918806 +19.65697701 +19.39215577 +18.94154003 +19.83255345 +20.74573653 +20.96786682 +21.11549459 +19.49892805 +21.05854398 +18.02606526 +19.90819975 +21.1756176 +20.52017888 +19.8962525 +20.57856803 +21.62778401 +20.2655272 +21.19914477 +21.9229709 +20.82227281 +20.29330306 +18.14994379 +19.49791159 +20.26177093 +21.18882629 +19.75241916 +21.8402331 +19.08717501 +20.97826878 +19.67612567 +19.94395398 +21.21000814 +19.18486105 +18.38724823 +20.08102234 +20.11517845 +21.18867109 +21.87327682 +18.22120275 +20.3667579 +20.72511412 +21.9432054 +21.77036086 +20.84980306 +20.08715765 +18.64609569 +19.53670622 +20.3404893 +20.90080159 +20.54159823 +20.85649121 +19.71661002 +20.91050916 +18.57496502 +18.65034525 +18.65132858 +21.56345983 +18.30413625 +21.20603349 +18.93428359 +19.87371976 +21.66382638 +20.34374892 +18.84047074 +19.13636024 +21.6817865 +19.7085757 +20.34794193 +19.83972879 +19.51375235 +18.89311651 +20.744766 +20.87296811 +19.09954037 +21.15604337 +21.4181408 +21.68270039 +18.64484966 +19.21569473 +21.44141339 +18.79416081 +18.01387384 +21.48330924 +19.30579777 +19.6579901 +19.7853361 +21.3930984 +19.35156858 +21.56911954 +20.46775655 +20.1091469 +19.30245803 +18.97484679 +20.49623377 +19.78757664 +21.64206404 +19.96655486 +20.04717967 +19.66689312 +71.93397676 +66.97781309 +64.8630512 +72.92361989 +69.31686381 +69.24453899 +69.50718202 +70.97622058 +65.45772465 +61.66028344 +72.22406699 +62.95310873 +81.04264232 +71.11753343 +75.66477771 +70.8181646 +77.94475631 +79.97666719 +72.50064235 +75.60766064 +84.2773169 +76.7058791 +82.29547619 +84.22990724 +87.063996 +85.8549134 +76.61601435 +86.87675918 +84.48833392 +84.88244048 +71.80931114 +86.74421488 +83.94274692 +83.78175506 +72.86456932 +75.26677008 +87.29131122 +79.9148202 +78.27168942 +85.33652621 +73.30936969 +78.57666697 +77.91759894 +77.50450505 +76.83076821 +75.27076587 +74.67685296 +82.14780207 +86.68950698 +80.12239233 +76.74916862 +74.52867199 +85.26182609 +87.52286237 +77.56786567 +76.63680956 +81.60429751 +84.38500643 +79.26741611 +82.06147092 +83.46077878 +87.36528287 +74.63701454 +87.95389791 +78.27074931 +83.56719087 +81.15473443 +79.78286811 +83.16521378 +78.32830166 +74.01420685 +79.81846266 +80.34988256 +75.22971224 +86.96907479 +75.63888421 +78.54688745 +74.47815999 +80.57197284 +76.92146328 +79.82759397 +75.59314496 +72.85970259 +84.46681553 +82.25722261 +77.45168098 +72.7597679 +85.84903617 +74.71657662 +86.89170866 +79.65737312 +77.44603866 +83.8679906 +86.02926532 +77.93126739 +78.51734928 +78.9305012 +86.75713567 +83.08099196 +75.9623087 +74.95996638 +75.68585355 +76.21699296 +75.6829068 +82.53607146 +73.85490781 +78.19770581 +82.00082568 +30.66149795 +29.21775045 +29.32366748 +29.60618168 +34.1493888 +33.0103201 +29.21293782 +31.30283482 +30.58293923 +32.49945047 +32.14595191 +31.87918763 +21.56901424 +20.77734184 +23.48584491 +24.101757 +24.38979474 +20.42261187 +23.47478974 +23.41473421 +24.40304973 +21.29305622 +23.4849608 +20.40472465 +21.01758222 +19.86907245 +21.58145281 +21.96809409 +19.92630675 +20.58480039 +18.91288681 +20.13965069 +19.90983817 +19.18207346 +22.09578418 +19.03856756 +20.64156358 +21.66406126 +21.75178406 +21.27458895 +18.7943464 +21.37182027 +19.19796925 +21.7937021 +20.93636114 +21.24254733 +18.42816239 +20.42864949 +21.30500168 +21.46694991 +18.13191676 +21.77752329 +18.19080135 +20.47771446 +20.79349271 +18.44707336 +18.20951182 +21.15994267 +19.55743962 +18.44614136 +21.05471299 +21.40076044 +20.35345187 +18.64852706 +18.06435758 +20.80720414 +20.2044372 +20.60714438 +21.2568192 +19.74070059 +18.5016135 +21.76411105 +20.18104851 +20.46117648 +21.73364572 +21.72633463 +20.28837843 +19.1904457 +21.98845454 +20.72326836 +19.63374671 +20.23934721 +19.6633362 +21.55322061 +19.9299975 +21.2941135 +21.36070519 +21.29732935 +20.88875445 +21.41951087 +19.54891832 +18.45865282 +21.36981682 +19.99267366 +18.50950413 +18.46125009 +18.63696958 +21.00389304 +20.84342669 +18.81527472 +21.38769367 +19.12517918 +21.17194233 +19.95522363 +20.92619473 +19.52555065 +19.38856239 +21.3654384 +18.14120902 +21.89894779 +20.59271823 +19.72993355 +20.51221812 +18.49096379 +20.05620982 +21.94038209 +18.94107775 +20.8891124 +19.7398855 +20.60983259 +18.81954891 +19.88185993 +21.92037086 +18.7811486 +20.54578011 +20.302391 +20.26020635 +20.46049316 +20.00895189 +18.067723 +21.60038725 +21.30791531 +18.69667072 +19.65309271 +21.08219592 +21.92024926 +21.80454819 +21.5974368 +18.63349559 +21.65790042 +21.51377965 +19.50779964 +19.57809038 +19.83963569 +20.62470252 +19.04334246 +18.09179372 +18.5649181 +19.76046363 +19.12801028 +21.05806624 +18.42676028 +21.6698609 +21.58130872 +21.63502727 +20.95843999 +18.42799989 +19.75255029 +18.52562149 +21.95079677 +19.33215369 +20.34132217 +21.11757222 +21.68246434 +21.0221909 +20.69801512 +19.86392713 +20.42160054 +18.37665524 +21.53569017 +20.17510924 +18.1605402 +21.6796085 +19.9572079 +21.47435657 +21.42755182 +21.26300635 +18.24561208 +18.98826658 +21.50219149 +73.42627836 +67.42973653 +67.18456396 +63.58191262 +74.37038673 +64.09868326 +63.79674027 +70.18591399 +64.50268252 +73.96729391 +61.34833514 +61.27824437 +77.67568796 +77.41472938 +72.37540962 +77.51494362 +76.22898035 +83.65791423 +69.98362084 +84.99170737 +79.5305757 +72.19661028 +70.56571541 +78.19139982 +75.3036932 +76.3577367 +75.46658195 +81.90834048 +80.37132461 +72.80810523 +79.94187798 +84.15108203 +72.85931877 +85.71840868 +80.76538895 +86.68673156 +74.28101517 +87.79156354 +82.20959582 +80.9826113 +80.14818062 +72.29161581 +86.92978599 +82.20514687 +73.37786452 +72.24843244 +72.72516318 +81.65223182 +81.80460882 +79.97547795 +76.88979515 +80.48856181 +80.24156654 +72.2932944 +76.501143 +72.83348123 +86.38173943 +83.58350575 +87.91673764 +76.81629988 +86.05164289 +81.64494914 +79.24620251 +75.55754284 +83.81025156 +86.4621016 +75.76129765 +74.80265466 +83.13555994 +87.62736429 +83.99524965 +76.54961727 +78.71853108 +78.14833194 +85.63269821 +84.34112278 +81.42282529 +76.39861233 +87.00698117 +82.45225205 +87.52678608 +81.28109222 +85.1382668 +85.00886998 +77.39711183 +87.42416371 +72.35092457 +84.29921269 +87.44874547 +77.4223826 +82.36961125 +80.99541649 +84.18395532 +85.8586819 +81.64855634 +85.05431008 +76.99653965 +75.65736389 +78.89065274 +82.84375378 +74.99592238 +82.88560325 +78.30546831 +84.72917185 +72.5893452 +82.68769045 +82.39712575 +87.05493419 +33.36554594 +33.89632563 +34.58937586 +33.12032592 +30.65697738 +34.36654572 +33.58449352 +31.51639461 +33.3473803 +34.35320222 +35.04416691 +34.89504293 +21.61746748 +22.04918663 +20.65072286 +21.26899724 +24.11324569 +21.77660648 +22.94007465 +23.1435247 +23.66259385 +20.97894298 +21.52556166 +22.16854559 +19.92638875 +22.45797956 +21.85191727 +20.3967967 +22.03348403 +19.85598624 +21.65075255 +19.34817502 +21.59543084 +20.3016329 +18.87231699 +19.55128278 +19.70322212 +21.09795802 +18.37973208 +20.73725123 +20.96420197 +20.71464072 +21.14368336 +18.80249526 +20.44608575 +21.86904972 +20.54126409 +20.543483 +20.96586649 +19.35137642 +20.82187342 +21.68573366 +18.06090372 +21.50107339 +18.89259281 +19.84272383 +21.42994421 +21.31609232 +21.5884149 +21.78255836 +19.79242724 +20.62941533 +19.56566965 +19.40659222 +19.73016911 +20.97633122 +20.00960409 +21.26031989 +20.98490223 +18.08538557 +20.52489265 +19.75007578 +19.82651596 +21.27349222 +20.19043194 +21.54248729 +20.85122237 +20.21136004 +21.0181519 +18.1533962 +18.10833462 +18.33339731 +19.7502613 +18.94180058 +21.93704518 +20.16916056 +20.64966298 +19.11528055 +19.28718763 +19.34184766 +20.79494282 +19.89482483 +20.07073461 +20.36801193 +21.07524663 +18.36147899 +21.10749565 +20.25294028 +20.67638178 +19.31020706 +19.63754735 +18.92466328 +21.91719999 +19.98801189 +21.98430766 +19.95914391 +18.87900506 +20.02980959 +18.15838229 +21.61907921 +21.274201 +20.90328208 +20.43930686 +20.31933693 +21.98691286 +19.11198974 +21.11873746 +20.32561908 +21.90352218 +21.31121273 +21.99410045 +20.35329998 +18.81817583 +20.01474814 +20.84444454 +21.09744154 +18.00203996 +20.02010835 +18.94093832 +21.49964733 +18.61162178 +20.665825 +19.06424876 +19.42616857 +21.76223704 +18.9617925 +18.38001105 +18.27713961 +20.01846044 +20.56684593 +19.30917457 +20.76103897 +18.24413487 +21.42933858 +21.26626884 +21.94198509 +21.74601992 +19.42478866 +19.59710154 +20.98385939 +18.53633109 +19.25605884 +18.47416375 +19.8195458 +20.20801712 +18.84464188 +18.10652675 +20.87742333 +18.08002066 +21.89361044 +18.88642903 +20.65560037 +19.73900691 +18.23869544 +19.88873443 +20.06704254 +21.41873283 +20.92939628 +18.3172099 +18.83665073 +19.24755074 +18.46563075 +19.82759628 +21.93723676 +20.05845117 +20.96752867 +20.73175119 +21.39964574 +18.86289396 +21.01530505 +73.18643127 +63.53253359 +65.91651019 +74.39338399 +71.81871471 +65.04323532 +68.86960807 +66.69883527 +67.8635264 +66.0302602 +64.99890185 +70.37677736 +81.92296897 +83.40381455 +72.25072109 +82.61071773 +73.7945088 +76.47226077 +83.830406 +76.89389589 +72.89842605 +72.32116153 +77.18070806 +81.67667602 +87.42755061 +84.09094683 +85.5159982 +83.46152587 +85.80899984 +72.78137251 +86.35763215 +77.87244347 +86.22535261 +72.77245505 +82.94322399 +83.26839386 +87.84503354 +84.20052231 +78.02743388 +80.81887765 +77.77137723 +75.04613477 +75.884866 +75.46150595 +80.68410803 +86.39477187 +86.49970167 +72.78876898 +73.2608036 +75.90368366 +76.06269181 +73.50058243 +78.19664176 +81.38406942 +81.23109507 +80.67550813 +77.4001703 +83.28329818 +85.20328936 +77.52177857 +73.36504406 +76.73760044 +74.19433697 +79.4739247 +74.49138666 +79.40170466 +75.53242055 +83.81567434 +72.43761468 +80.87205882 +74.70822623 +72.01241307 +85.9063767 +82.74365026 +73.58237876 +82.62436468 +81.78557217 +79.57294309 +78.70737398 +86.19228875 +75.92163946 +78.37220853 +77.26510485 +84.33840681 +86.66327851 +85.59634283 +84.76310014 +87.78847057 +83.15415315 +84.01669935 +87.7246722 +72.11171411 +82.14461631 +83.82338357 +86.68506642 +86.14134348 +85.47133808 +87.13262689 +80.59803606 +72.11069384 +72.17684266 +80.7141939 +78.9643255 +79.21989043 +78.40644569 +86.68357966 +77.74669576 +85.69959816 +34.57832804 +31.99680518 +31.66039736 +33.6705254 +33.33101125 +30.90261881 +29.45630235 +30.49504951 +29.63857675 +30.68628067 +30.47565217 +32.8813468 +24.43614087 +23.23213065 +24.31138801 +23.67291122 +23.42089046 +22.01499628 +21.61507819 +23.95132131 +24.21616036 +22.18443235 +20.20060157 +23.71053784 +19.59964174 +18.47250047 +21.72923288 +20.55132827 +21.23862296 +22.17856924 +20.64864776 +20.49308268 +19.62255181 +19.68207371 +21.69463604 +20.27122355 +18.74364449 +18.46632996 +19.98716048 +19.95514718 +20.71277946 +19.97971436 +18.6630575 +20.12736131 +21.73096792 +18.72722688 +20.8586618 +20.47323911 +21.01449747 +18.62025939 +21.7873171 +20.50353021 +21.40881729 +19.00465402 +20.97777089 +21.14440196 +19.60854723 +19.55456818 +20.65099099 +18.3912694 +20.94651756 +18.17503597 +18.76596358 +20.66054109 +18.39682618 +21.89157074 +21.47770776 +20.50914633 +21.28031486 +21.55445785 +19.04155787 +21.4017547 +18.77917513 +19.65336906 +20.23303853 +20.85556385 +18.12056527 +19.16203765 +20.43407639 +19.42947472 +21.10010022 +20.60660864 +18.93760581 +18.58371592 +20.51618797 +19.80186931 +18.67582816 +19.30549682 +19.21218699 +18.43252789 +20.18763608 +21.05459454 +20.30186756 +21.30516546 +18.51027419 +19.74244743 +20.43766041 +20.70400624 +20.78314523 +20.91586171 +20.60571925 +18.37691236 +20.78122271 +20.89913063 +21.97391974 +20.77344975 +20.74732158 +20.05925316 +21.47169163 +21.98733905 +21.11617948 +20.45000151 +18.31581931 +20.90695653 +20.83424627 +21.10227259 +18.49822155 +20.61493 +19.18289562 +21.04108497 +18.96149582 +20.73591471 +19.17997179 +18.03597717 +20.53343165 +18.45307633 +20.63716589 +21.70243779 +21.87698374 +18.94369235 +21.23701291 +19.41421311 +21.60182829 +21.14995827 +18.29568687 +19.62854798 +19.3492713 +21.14072408 +19.64114284 +20.73835359 +20.40974102 +21.90255488 +21.75113983 +19.71079806 +20.89431285 +21.31784038 +21.59554302 +18.27253706 +19.2083152 +19.28092016 +19.7377838 +18.677059 +19.98482352 +20.65285731 +19.98945568 +20.66317238 +18.26576653 +21.50394933 +21.75627677 +20.4716297 +21.52556399 +18.52578407 +21.18979568 +18.47659277 +19.63204093 +19.29527414 +20.3423673 +19.20605814 +20.54925452 +19.46954916 +21.44316152 +20.53553536 +18.86119319 +19.34451769 +21.38968355 +19.545919 +20.14319626 +20.59576774 +19.3912386 +19.17591452 +67.66346668 +64.12238122 +65.06526398 +62.04426738 +65.33399575 +65.56157567 +74.28093106 +69.22031203 +71.90840099 +61.81713064 +62.64889903 +72.27770267 +79.51748901 +72.80404111 +76.1224247 +78.2001972 +82.93282455 +70.77759411 +79.10112993 +80.9683975 +85.01688163 +82.36712442 +74.12704791 +80.85266909 +83.70717148 +83.17371339 +84.61157126 +85.94092154 +73.13342864 +73.23416439 +84.23394542 +75.58173187 +72.49904277 +77.94914889 +84.60732241 +73.58089014 +82.65017218 +71.97138436 +73.6672922 +77.52046921 +73.24963133 +85.43178537 +85.7221379 +83.98822429 +75.78861849 +80.27550686 +74.85707999 +76.40865465 +80.23682321 +83.74011848 +73.49682661 +76.72872785 +86.80510335 +78.84704525 +87.00102952 +87.84132169 +80.40725484 +76.59031807 +84.63211235 +74.53108002 +76.02910018 +84.55401976 +78.93454576 +75.22099621 +82.41405585 +83.72017102 +73.99758778 +76.42801544 +75.53680215 +78.07392633 +84.211076 +83.41532551 +82.5995896 +72.09987657 +74.27357998 +75.57203529 +76.35056056 +74.34211098 +78.5642946 +73.20218661 +83.99954864 +84.6027204 +81.18748763 +73.43457305 +86.24116513 +87.45000536 +75.23767251 +83.27407722 +85.47085399 +80.63734154 +77.17302142 +79.6567865 +80.19614604 +78.41004216 +86.87731309 +83.90196868 +75.86079715 +81.36888375 +83.01899454 +74.24247424 +77.73478203 +86.48873929 +81.07473847 +75.47193496 +73.96452837 +80.29159946 +80.76294056 +77.35060152 +32.83465628 +29.23957638 +29.72888833 +32.29614625 +29.19561484 +34.43780948 +29.70973107 +33.11308084 +31.30369602 +31.35863556 +33.69528651 +31.99655152 +23.41093519 +22.42325547 +22.81621468 +23.56800024 +22.88074191 +22.91795443 +23.69570247 +24.4119076 +21.84768717 +22.74548362 +20.54650262 +21.76744019 +20.11975339 +21.85313179 +20.53485503 +21.42644761 +18.50985409 +20.33456173 +22.12379689 +19.35078954 +18.56111465 +20.20724193 +21.31735248 +20.29348228 +19.93514479 +20.77848037 +19.10883945 +21.1083954 +18.70179386 +19.67700078 +20.72302774 +21.41578066 +21.26772163 +20.98699871 +19.52968014 +18.57796546 +18.8854495 +21.47993621 +21.44989762 +21.82717739 +18.3215264 +20.16657768 +20.61450311 +20.86263842 +20.59520536 +21.10028239 +19.45654667 +18.7357001 +18.82194661 +18.05137996 +19.40501253 +18.37050266 +19.28965767 +20.51677877 +21.58205518 +21.36252262 +19.0143469 +18.53989154 +18.77589337 +21.88814832 +20.19789792 +18.73000889 +21.36298462 +19.58076498 +21.59688861 +19.04270851 +19.57288704 +20.01979105 +21.57046134 +21.47502973 +20.29742028 +18.88710204 +19.61342789 +21.90253226 +20.4310929 +21.12439102 +19.79945878 +20.1280291 +19.71581645 +20.81168399 +21.40588406 +20.02945417 +19.92346983 +19.36114587 +18.70838678 +21.75699089 +19.26431887 +21.20276585 +20.86138809 +21.1636704 +21.74707253 +20.49348304 +21.59180137 +18.67078929 +20.5068503 +21.08910245 +19.08656452 +20.96301521 +21.11390732 +21.32475182 +19.25153165 +20.72642636 +19.21701313 +20.95616155 +19.85189466 +20.3901775 +19.66335993 +18.64793171 +18.71211812 +18.31027563 +20.47229072 +21.39455359 +18.08334731 +18.26495801 +19.82986797 +20.95088294 +18.63083058 +19.08660528 +18.92802481 +19.59620487 +18.89999471 +19.41039471 +20.91417039 +20.44403699 +18.32472682 +20.55098267 +19.90830869 +21.7382623 +19.15721727 +20.90466568 +20.92344329 +18.88600312 +21.6128945 +19.9647328 +20.71553347 +18.58342224 +19.03121567 +20.34442847 +19.27610907 +19.99877167 +19.4960208 +20.56221519 +19.94858145 +18.01843974 +20.59872335 +19.68848623 +19.36679336 +18.37658701 +18.88147876 +18.89508917 +21.741478 +19.7300519 +18.16826339 +18.55526673 +18.3161307 +20.35547756 +18.74648597 +19.99423056 +19.48024825 +21.21550551 +19.28195855 +19.83306193 +20.88514219 +19.73340483 +21.17286214 +20.64673742 +19.64211646 +20.0159277 +74.353967 +70.19791635 +73.50793507 +63.63111565 +67.77201172 +73.55779871 +65.58752404 +74.36023309 +62.52025387 +73.47632792 +67.25488486 +62.20292065 +83.49017512 +73.7501121 +70.18532195 +71.94772628 +80.06946079 +85.01563431 +71.56989241 +77.00943371 +72.64347927 +81.40296701 +71.67227412 +73.56234394 +74.69164051 +80.35527459 +85.4551198 +79.69637856 +72.49430387 +80.52813755 +84.25177397 +73.66981216 +72.72439915 +74.55489489 +83.43375688 +80.97808539 +80.55273505 +75.9004883 +77.22300658 +87.34921521 +75.75898362 +86.32261518 +81.19095787 +73.88397617 +79.38162565 +87.07216734 +78.60261311 +85.71120801 +76.08459443 +81.11528209 +85.48111254 +86.71019962 +79.75402831 +82.21527323 +72.03039065 +76.03332054 +76.44104341 +73.47824917 +76.45676618 +77.11943942 +87.49605662 +82.6936686 +78.8122981 +87.80465655 +74.44814344 +79.6129975 +82.34904237 +72.88579147 +83.46797507 +73.59434495 +74.2409532 +74.55145356 +86.86140335 +82.93097258 +82.48604814 +80.88711942 +76.6841598 +81.9334487 +78.56164132 +74.32594487 +83.03275952 +74.07260358 +75.04997681 +85.08237219 +82.56171502 +82.09570084 +78.69109346 +78.34033788 +83.0440423 +83.83992764 +80.16325732 +87.50813989 +87.29102534 +78.59872093 +85.12979262 +80.69213054 +80.18806341 +72.879397 +81.18356419 +86.40921371 +84.48210915 +84.58104184 +74.55883599 +77.7351613 +75.73124959 +77.05461493 +81.27259829 +77.83651112 +32.38845981 +31.60640192 +30.63433369 +29.41057633 +34.5077595 +28.872784 +28.81057039 +34.09149899 +35.17958326 +33.45345167 +28.89774702 +30.25081164 +24.51376435 +23.78254575 +22.69926206 +21.22113481 +20.22437741 +20.25345829 +22.90167301 +20.25780569 +24.61146169 +20.98155842 +23.3439677 +20.85466641 +20.64422241 +18.76218361 +21.57272417 +20.82783655 +18.78493855 +21.90780877 +20.672588 +22.20684184 +22.18648907 +22.20239964 +18.75060796 +18.92744277 +22.05618714 +20.04616517 +19.04382987 +21.17983546 +19.14861511 +21.00922524 +21.45161895 +21.23851131 +19.1878529 +19.70058532 +19.74733838 +20.06092406 +18.68741411 +19.82889768 +20.06237336 +20.14615774 +21.30003013 +20.08860455 +18.94130189 +20.67234136 +21.20959825 +19.29599304 +20.60098168 +18.60559622 +19.37142382 +21.64105 +21.64938854 +20.30519616 +20.81340125 +21.42017354 +21.83840491 +19.96337799 +20.25019023 +19.66634148 +18.29143903 +19.6949946 +21.16250936 +21.21954199 +21.56950846 +18.20586682 +20.10861836 +18.42969795 +18.80296873 +21.60086601 +19.98716503 +21.03417968 +18.25753642 +19.66730602 +20.69696112 +18.53362593 +19.30327152 +18.25819122 +20.60535976 +21.88356504 +21.30818196 +21.89849247 +21.38241918 +21.42078322 +20.30870878 +20.07300925 +19.62501707 +21.27237958 +18.72827045 +18.22489966 +21.79157529 +18.01511274 +21.90731729 +20.91541348 +19.31399568 +20.79127937 +21.27150063 +18.98144822 +21.08358273 +21.2174785 +18.99741852 +18.16770542 +18.81648914 +18.80258564 +18.26096182 +20.90402954 +19.5198997 +21.53754467 +19.00868442 +19.81292866 +20.55606972 +21.5098598 +20.09848441 +19.49409851 +21.46806031 +19.2409857 +18.3176948 +19.78016843 +21.14037323 +18.12312333 +20.34352898 +20.37785619 +21.71416705 +19.14585927 +19.11534645 +19.76193461 +19.42765961 +20.94538345 +20.56700831 +21.03568415 +21.28016716 +21.69192453 +19.72374693 +21.93878956 +18.86264325 +20.85746065 +20.13603727 +21.26760238 +19.90708208 +21.13575454 +21.72067486 +20.92917706 +21.10437714 +18.26870173 +18.81983065 +21.89721496 +20.77274802 +20.24579607 +19.46790549 +18.177556 +19.47654363 +19.99565149 +18.84583804 +18.69254717 +20.03366621 +20.34361694 +18.95967168 +20.3495579 +21.60135986 +19.89269303 +21.42956068 +21.70908578 +18.36957612 +18.38324632 +19.90417673 +20.35240978 +19.70353386 +19.30580308 +20.56397646 +18.00832605 +39.37012762 +34.07096944 +39.00311113 +33.18490616 +34.11422771 +34.09109065 +39.57230091 +32.43312393 +37.00539511 +38.66174338 +37.24037031 +35.01168349 +42.7931454 +42.28520272 +38.68220657 +39.77489538 +42.86535043 +42.98327324 +38.80661448 +41.92322422 +37.64752498 +38.19501292 +36.57220356 +36.92000721 +41.08996647 +39.92590793 +37.69765867 +39.06638382 +38.82952581 +43.72328611 +42.65721259 +38.94731574 +43.1380873 +38.5861188 +41.17783925 +43.55826717 +39.09093313 +41.40592846 +38.33669658 +38.09999413 +40.56077873 +43.79904949 +39.59337073 +43.46629489 +43.28025624 +37.99967682 +39.18318361 +41.11350269 +40.13794398 +36.76178541 +43.94255231 +42.01450861 +39.49523206 +40.93879714 +36.69471044 +39.95601924 +43.43970786 +43.16590002 +38.69285492 +40.24450276 +41.57773766 +38.71883509 +36.51786514 +40.04225186 +40.81177987 +36.04557931 +36.76342652 +37.65712008 +38.78317719 +40.32711927 +38.34951613 +38.20824781 +42.95451984 +37.1601673 +39.9634253 +43.62231855 +40.99984359 +41.73737672 +39.44964345 +36.15922592 +41.16877947 +41.0551315 +36.88318504 +39.69702365 +43.3225761 +37.64063048 +39.68873924 +39.68877468 +42.48603736 +42.59655244 +42.0741015 +38.92358345 +36.57624858 +38.79581416 +41.43827657 +41.62191932 +43.71999048 +39.62911971 +41.05947415 +40.31351665 +37.20493896 +39.68960962 +40.35867091 +43.60598569 +38.93230247 +43.8407816 +40.33839027 +37.93974423 +22.51998714 +22.2801337 +23.77407575 +21.70524501 +23.73621533 +26.34434027 +24.8165105 +25.24697123 +22.17122398 +23.8708821 +22.97386892 +25.89166592 +19.4741763 +20.62833023 +21.16627809 +20.85841053 +22.17381264 +19.68284481 +20.28994662 +22.01507024 +20.91677666 +20.39280792 +18.84248049 +21.85408293 +22.06383805 +20.64499714 +21.59757411 +20.22804291 +19.07813758 +18.20223049 +20.77850173 +20.13221479 +21.29741964 +20.94495942 +22.12742386 +20.20158025 +19.74023306 +19.17759388 +19.93929706 +21.52587227 +18.1988305 +21.94665873 +22.00838593 +20.42391155 +19.35709868 +18.92242337 +19.13653111 +18.22954237 +19.90681197 +18.23513046 +20.8805765 +19.49395389 +18.80347411 +20.18587164 +21.90204364 +20.78717396 +19.97337683 +21.11441164 +20.95660985 +21.57384326 +18.81988019 +21.43688218 +19.20533341 +21.76538861 +19.12548455 +21.70878345 +21.85656159 +18.58315468 +21.899401 +18.34406582 +18.8754791 +19.77794083 +21.97438946 +19.9542522 +20.20163777 +20.7776998 +21.87317423 +21.1334056 +18.89661602 +19.21196372 +18.39051296 +20.57780946 +18.72296123 +19.02961955 +21.55245462 +19.3070227 +20.26658687 +19.59026404 +18.29612515 +19.45145532 +19.63227281 +21.58280441 +19.29780261 +19.51696448 +21.13158707 +21.0358266 +21.19314111 +21.81508296 +21.18222999 +19.63043281 +21.28603407 +20.03469853 +19.11085613 +19.21166827 +18.89536955 +18.57997183 +18.73796165 +18.2527122 +21.55380346 +21.72403124 +20.34708157 +21.36195823 +18.73428441 +21.6066953 +20.02544624 +18.26865997 +18.56525098 +19.23590584 +18.17423032 +19.23717351 +18.23972173 +18.94411042 +19.06267902 +21.97747591 +18.9421867 +18.9567458 +20.74715587 +21.43742991 +19.54822165 +21.50247208 +19.36056808 +18.78806352 +19.3185553 +20.4374255 +19.46857264 +20.69157522 +18.94774352 +20.80397158 +19.38975345 +19.82347349 +20.23098056 +20.74490001 +18.95485477 +21.34378215 +20.887371 +18.93639168 +21.89989825 +20.65918796 +19.80970755 +18.6301093 +20.13288401 +18.65910355 +19.71796671 +19.63485009 +20.87975858 +18.76953272 +21.28748542 +19.30452931 +19.77595451 +21.0893639 +20.5015696 +19.23210141 +19.5448117 +19.22314726 +20.37908067 +19.33049813 +20.90279078 +20.31914863 +18.58282645 +19.24107447 +18.88578977 +19.56125285 +20.06393634 +20.02705143 +21.01809471 +18.75668745 +21.78589132 +19.37138043 +19.20099539 +20.74071431 +72.15502615 +66.347216 +71.35711886 +73.218809 +71.62852985 +61.6650722 +72.45221719 +71.73294104 +70.30234724 +71.5363049 +74.52018538 +67.06313527 +70.88330461 +76.99301233 +70.56065033 +74.40676633 +78.94837437 +74.6453473 +80.47733422 +82.59722781 +76.36521606 +83.810141 +71.07910021 +82.87855631 +84.74562731 +76.68899093 +76.31876634 +76.42023058 +84.4724056 +84.79461707 +76.81190599 +80.99255689 +73.77759408 +79.02345705 +87.4528015 +74.09417781 +87.05640904 +85.08584986 +87.45036789 +74.78341226 +75.32579629 +72.18315106 +83.49491473 +82.20674848 +74.75922816 +84.55672947 +76.69498354 +74.07093719 +78.7421 +73.43788825 +76.19360764 +77.92262781 +85.60927563 +84.66045647 +79.0650884 +83.57313856 +81.07893056 +77.43488085 +83.59392214 +82.91608183 +81.90157961 +81.88335775 +82.92373135 +78.14897687 +85.90108959 +74.59334488 +86.13803259 +77.47279062 +73.99695383 +81.59652162 +78.01204195 +85.04391333 +78.89181013 +82.69620652 +76.93138928 +75.35051463 +78.20803369 +81.70814095 +82.51035572 +81.25052663 +87.80804853 +83.05664563 +86.90347976 +73.8862218 +72.98182675 +76.97576744 +74.18528058 +80.41374206 +80.30354587 +81.20059876 +83.92348496 +87.54110712 +86.05197384 +73.89373396 +77.41607038 +76.0930223 +74.82904899 +80.71556703 +80.85219939 +75.6358882 +83.39032398 +83.72659664 +72.33565214 +78.33209318 +86.24221714 +80.32506689 +77.56201504 +76.05878922 +30.3574631 +29.43850976 +34.03024255 +29.35460176 +30.67068061 +29.09231914 +33.80086756 +29.05140999 +30.77312116 +32.46909693 +31.42118667 +30.60652895 +21.39284587 +23.73409927 +24.52342052 +21.7192228 +20.33537079 +20.32381357 +23.56127481 +22.63461556 +23.67049381 +23.28478533 +24.22562712 +24.1284915 +21.66098875 +20.37837456 +19.69408553 +20.50878148 +20.48848506 +20.9316884 +19.19425541 +21.11741878 +20.30223714 +20.97235874 +19.41342112 +20.21128124 +18.93124067 +21.60442643 +20.04761298 +18.99064526 +18.25202595 +20.80232879 +18.94909999 +22.06372869 +20.23144849 +19.2478563 +20.72973709 +19.19256387 +21.30152702 +19.25140782 +21.97406579 +20.44018289 +21.39816712 +18.30882148 +19.41181513 +20.97006028 +20.64003149 +18.79499837 +19.44345953 +19.07206524 +20.45740775 +19.38199354 +19.23991032 +18.83312719 +19.63987861 +18.7856165 +21.8544736 +18.6215819 +21.65737628 +19.71767746 +19.51521017 +18.92891286 +20.54302534 +20.74211206 +19.87028385 +18.22282758 +21.6740406 +21.92131653 +19.72417366 +20.45464323 +19.80119451 +19.2875186 +18.30927517 +19.82427092 +21.27353823 +18.06812584 +20.32843073 +21.52308843 +18.87019772 +18.73302346 +21.0891065 +19.02034572 +18.76793707 +19.511957 +19.57000805 +21.49640425 +20.47377389 +19.62384583 +20.13755186 +21.81586093 +18.45285871 +18.83086209 +21.85011483 +21.82929939 +18.70866169 +18.58043527 +19.68434054 +18.19887317 +20.61961413 +18.30998409 +18.23211851 +19.94074774 +21.83114654 +19.70718374 +19.42592463 +21.99182686 +20.12787584 +19.50096563 +19.54344325 +18.77983798 +20.04889223 +19.75542011 +19.08318119 +18.64216035 +19.24495547 +20.03473331 +18.23333309 +18.61497611 +21.79062907 +20.1714214 +18.25379721 +20.77235104 +18.24721148 +20.95549691 +20.99985089 +20.6043159 +20.92881818 +18.35186312 +20.90712221 +18.54675328 +19.35802363 +21.77098101 +20.01150191 +21.86970573 +18.35568984 +19.9102264 +18.24960928 +20.52084105 +18.31482801 +18.70147121 +19.03532124 +20.99497541 +18.65584848 +21.38652821 +18.52761576 +18.1409778 +19.58018168 +21.91776657 +18.44136891 +18.40687378 +21.00466604 +19.24864678 +20.86912647 +18.80004236 +19.84028798 +19.06115951 +19.80611286 +21.07638837 +21.04803976 +20.06308915 +21.71348737 +19.05513641 +18.9612454 +20.4552256 +20.48518814 +18.18616016 +20.43111085 +19.49774463 +20.9897701 +21.23242266 +68.70929195 +61.22318843 +69.85457502 +71.3847854 +64.58617242 +67.51918562 +74.33388208 +65.25437153 +64.23488421 +64.06762515 +68.79969135 +74.11710458 +79.28687081 +74.54757483 +79.75060296 +79.53755246 +79.10427811 +72.31429473 +79.68847673 +76.5161523 +70.12854875 +78.21714484 +85.19341989 +75.26795845 +86.92425381 +73.09805612 +83.21688664 +73.38630424 +75.91888231 +80.64665265 +80.99556825 +83.89696079 +81.35391262 +81.00884826 +86.0780635 +78.7591646 +75.51352736 +74.49911102 +78.30583365 +83.30395923 +72.59347892 +73.97597636 +73.60937798 +81.26636565 +75.79477141 +74.57055867 +81.38655032 +84.0799415 +77.29592319 +81.23177339 +73.55233381 +86.94218535 +77.37176528 +87.93898067 +87.63636632 +84.44090451 +72.30371647 +80.67623178 +73.37176928 +86.30149109 +84.6301176 +87.55324327 +81.73020401 +80.35090784 +80.29972712 +78.1794212 +79.49522512 +82.16265733 +86.92298922 +81.53023577 +85.70974081 +85.80035997 +80.30055192 +77.55876969 +82.23239253 +79.13327778 +73.30235017 +78.04419638 +87.90431032 +72.77549127 +83.14587238 +85.45819887 +82.37882361 +81.11519299 +83.3207107 +78.86933237 +73.46164675 +87.39778026 +78.9166608 +82.64606911 +80.50081243 +72.87462923 +87.24377811 +84.68043303 +74.38542349 +87.70621362 +83.79038978 +79.55711586 +81.7818895 +73.70775861 +80.96655307 +73.17854905 +80.71765312 +80.84309998 +85.99098754 +83.6008879 +75.99280909 +86.21478517 +32.46874682 +32.68082239 +29.88147503 +34.28974443 +34.75817006 +33.75993367 +34.82080901 +30.73471349 +34.31115609 +31.92890998 +29.84906437 +33.08031748 +23.22485754 +21.44542065 +20.28316901 +21.05531457 +21.95100221 +20.91068069 +21.02925301 +21.91342897 +24.46880269 +23.58380966 +21.59247165 +24.42318489 +21.07656901 +20.2975215 +20.35015737 +20.1144091 +19.38633521 +20.01564522 +20.59426334 +20.59479978 +21.55207409 +19.90163578 +21.36800447 +20.79986392 +21.952249 +19.63493713 +21.70856916 +21.38472647 +20.64930024 +20.71702449 +18.42662497 +21.90554268 +18.51619738 +20.35014726 +19.41302051 +19.81406102 +20.46035514 +21.65617549 +19.84930554 +21.97199109 +20.39080465 +18.66011229 +18.77804681 +20.884474 +18.2190647 +19.94049081 +18.61072559 +19.75181809 +21.00370162 +19.83906008 +18.65738596 +19.01135096 +19.47389662 +18.28175416 +20.34125531 +20.43405775 +18.25211144 +19.61301026 +19.65977668 +19.33899065 +20.23095896 +19.38382996 +19.66563712 +21.19009419 +18.64843742 +20.47645878 +20.02237761 +19.22028655 +20.91013863 +20.20475344 +19.90944611 +20.67067726 +21.20916123 +21.89067516 +20.51740147 +21.49775994 +18.00436616 +20.12094277 +18.8585902 +18.37676983 +20.12788407 +20.98730602 +19.64909009 +20.6804298 +19.95887702 +19.74834346 +19.16102656 +19.53037406 +19.39918252 +20.58474874 +18.46407405 +18.37054547 +20.64005198 +20.18519228 +19.72080039 +18.60977154 +19.64410845 +21.15892705 +21.55848494 +20.81030628 +18.2396487 +20.68163911 +18.96394236 +19.26100497 +18.78349283 +21.10302316 +20.59440849 +20.44734022 +20.67189044 +18.94708905 +19.77857766 +20.53301489 +20.54637611 +21.16740745 +19.14841587 +21.08134449 +19.76073792 +20.68069077 +19.82287752 +21.79444068 +18.71720906 +20.70002035 +20.30614 +18.69092416 +18.26402534 +21.19657756 +18.62980533 +18.74602673 +21.9137369 +20.86904341 +19.00194737 +20.36379584 +20.13644735 +21.37789307 +20.91728299 +21.3268845 +18.84602635 +20.56087682 +18.16096343 +18.27576245 +20.85410813 +18.09768041 +20.31906004 +21.36162039 +19.51976723 +18.17936175 +20.8553898 +21.71874581 +20.86868557 +20.31378897 +18.92011532 +18.0615025 +20.77868843 +18.9241047 +21.43265071 +19.86545648 +20.12254233 +21.01574618 +21.11772243 +20.57060333 +21.75372726 +21.92919375 +21.78754178 +21.29671674 +20.82250088 +20.65330343 +18.41500071 +19.08593739 +61.27735984 +63.06877424 +67.17352089 +63.19289709 +73.46262244 +72.15750892 +62.173922 +64.58522653 +72.33937763 +72.12142732 +74.05812748 +74.76664956 +84.99171138 +76.20534154 +73.72509745 +81.61052616 +74.4847153 +82.35533359 +78.12697742 +82.16175131 +74.12165573 +77.72458394 +78.59364928 +84.47703721 +75.80796786 +86.46508976 +84.36847619 +83.19213904 +84.08238476 +81.19667993 +75.44984849 +74.58172798 +85.3462942 +83.10061706 +74.95880091 +81.35044489 +79.06575081 +74.44903654 +80.41310209 +76.41250031 +73.4516581 +79.37596718 +81.34400675 +72.66320196 +78.33936381 +76.03124361 +72.40342096 +73.92178807 +74.20673265 +74.90800573 +84.83367617 +79.01290221 +74.33553107 +73.58708633 +76.74862325 +84.74790392 +77.81267804 +74.54046376 +78.4470271 +80.86557252 +72.46986822 +82.03833079 +78.31785261 +72.15215053 +82.77825684 +83.39419906 +82.05749767 +77.46716488 +80.46981493 +78.19076996 +83.20595361 +81.33337879 +73.30808206 +82.28870695 +82.99501787 +77.93048675 +86.01174677 +85.48740899 +74.80194628 +86.46743084 +79.05319903 +83.57919207 +85.02473587 +80.08102995 +78.38548053 +86.64705554 +75.69351152 +76.11137511 +77.78577568 +85.7512878 +87.02044515 +75.52093844 +85.82175758 +76.13110118 +87.53009189 +81.55836968 +72.11335579 +72.54605061 +74.35972394 +75.00114172 +84.2818736 +75.56422501 +87.50623232 +82.17776136 +83.08024825 +75.48503532 +86.28326789 +82.68500141 +34.3321894 +34.92147232 +29.60409657 +29.41815263 +33.94180357 +34.34320018 +32.53606685 +31.14239753 +32.97682334 +30.75624416 +30.32566261 +31.92412321 +21.12836799 +22.32699094 +24.4455958 +23.92223117 +24.37850518 +23.7723525 +21.749283 +23.79796136 +24.2946612 +24.40271899 +23.2207251 +21.10692141 +18.59473039 +19.03493191 +22.38687991 +20.32474835 +21.93402245 +20.33682061 +21.13870857 +18.5308804 +19.45544657 +20.21895873 +21.01506452 +19.13455056 +21.15928519 +19.55101535 +21.37183578 +18.48015732 +20.81847763 +19.26534519 +21.283204 +19.70280333 +20.76057319 +21.84155968 +18.16930252 +18.13108053 +21.10135487 +20.60533435 +19.19032391 +19.99676528 +18.18518369 +18.7878014 +19.71689555 +21.35666039 +19.93779064 +20.36498164 +21.51565037 +19.25374151 +20.80679142 +21.45078679 +18.81407441 +19.42964243 +21.92344919 +21.93708537 +18.89654716 +18.26929038 +19.08735051 +19.59468929 +19.76781709 +20.47915647 diff --git a/test/data/Timeseries/period_no_anomaly.csv b/test/data/Timeseries/period_no_anomaly.csv new file mode 100644 index 0000000000..ef5a04acdd --- /dev/null +++ b/test/data/Timeseries/period_no_anomaly.csv @@ -0,0 +1,4033 @@ +Value +18.32491854 +21.97032718 +18.62480603 +21.95368398 +21.90911973 +21.17527242 +20.63769185 +20.3112282 +21.46440618 +19.15775809 +19.87072485 +20.47755988 +19.6447619 +19.70994582 +19.32113867 +20.25692727 +21.40229811 +18.80611351 +21.73773216 +20.75635062 +21.29309285 +20.22476277 +21.11806681 +18.06480159 +21.2735217 +18.16055544 +21.55965351 +21.96785099 +19.17626985 +18.84127423 +21.06145346 +19.01210536 +21.46224953 +18.41137037 +18.50382079 +21.91660622 +20.69535559 +21.3875489 +19.29731751 +20.705935 +20.37696731 +20.41260048 +20.73012984 +20.30143669 +19.71624948 +19.10369078 +21.07432532 +18.90508972 +20.76941722 +18.93333129 +20.50132068 +20.98831307 +18.87485556 +18.2397732 +18.52389497 +20.42398787 +21.39778562 +18.17998728 +20.93660504 +19.36527458 +19.91411348 +21.7154382 +19.32788602 +19.86134774 +18.05472966 +18.32639488 +19.03436636 +18.11140896 +20.5255013 +19.70559343 +20.19258081 +18.69858874 +19.18372812 +20.6552979 +21.86121089 +18.20166709 +21.56153728 +20.30752481 +20.25567827 +20.00111414 +18.27757634 +18.35950741 +20.40364802 +19.36383429 +21.66907227 +19.62636215 +18.57312583 +20.85887533 +19.17341369 +20.10188123 +20.79133114 +21.60105644 +21.16876478 +20.70544427 +20.71853273 +21.78369858 +19.18329639 +18.00444838 +19.08781824 +18.87156552 +20.64733834 +20.5348464 +20.37384553 +18.06497377 +20.91511222 +19.29412165 +20.66022396 +20.22631371 +65.86114059 +63.03023723 +62.48409701 +72.50864933 +73.69020657 +70.03711744 +62.60670396 +66.66757015 +71.11357312 +71.80556402 +62.80777326 +61.20041778 +80.89236695 +75.37437265 +73.78955027 +70.04016873 +78.22544679 +83.04985941 +84.70244315 +78.62036163 +77.82443981 +71.1600751 +78.35850588 +75.73727531 +81.22387951 +77.75030384 +75.38971726 +73.07832774 +76.57646294 +73.10503944 +74.38136911 +87.27059427 +78.63102297 +80.02688857 +85.46202908 +87.40152779 +81.22584307 +84.89758164 +77.13837912 +76.79963304 +78.34912762 +82.66080406 +82.81556895 +76.95137836 +74.04240116 +82.0197981 +73.96434994 +81.15837308 +83.07481131 +83.18981359 +84.03538044 +85.94511896 +79.98014403 +83.66390288 +81.88710614 +74.96824234 +72.39365567 +76.53428953 +79.06955805 +81.85404542 +85.59524052 +75.13632475 +74.00524422 +87.41148321 +73.72517397 +79.65203364 +81.36511395 +80.65811896 +73.37299244 +72.90893083 +73.68419783 +81.36549721 +80.70874339 +75.73912557 +82.20359711 +85.12026287 +72.66456577 +79.96931138 +83.02816952 +76.03626088 +76.92359601 +81.81742099 +86.36613557 +84.95797512 +81.32992735 +83.68338681 +77.83701008 +82.25529052 +79.4587529 +75.03883411 +83.22765258 +80.90327886 +77.73779605 +86.5812608 +72.334807 +77.05222248 +72.91007437 +84.2644047 +83.2336873 +77.30160582 +82.81057464 +78.33496554 +84.10002837 +79.26690817 +78.59644546 +86.95564526 +76.01403641 +73.92712905 +32.54106968 +35.00365288 +31.21816497 +29.19702968 +30.97154776 +32.03795644 +29.83630151 +33.01184786 +35.18558933 +31.69112656 +31.0702568 +31.36450065 +20.67585375 +24.11706441 +22.01841773 +21.89498816 +23.11541115 +22.14030851 +23.06408468 +20.43527826 +23.80547927 +24.37345637 +23.06646766 +24.43645402 +19.05226653 +20.38749647 +20.89700013 +20.81479306 +20.07638721 +19.8167935 +18.95147097 +20.03657684 +19.09825847 +21.43996155 +19.28737128 +18.67188327 +20.30646993 +20.47874729 +21.59079292 +20.40540445 +19.4749566 +21.3138653 +20.25788888 +18.40504328 +20.36066652 +21.73590808 +19.67925966 +19.27739262 +18.59170874 +18.62364363 +19.75002777 +20.4022867 +18.34005117 +21.77916229 +21.04071417 +20.3660283 +21.33421588 +18.33833494 +19.92646656 +20.54007206 +21.31870403 +21.13793594 +19.11194579 +21.76769927 +18.50093486 +21.50466258 +21.88796268 +18.71220615 +20.8922748 +18.16462901 +19.62545866 +20.0689857 +20.3225809 +21.74374899 +20.68900275 +19.9251118 +21.23870015 +21.80213128 +18.08826459 +21.93008509 +18.34452856 +21.25754712 +19.12133901 +18.52871863 +19.75942256 +20.57582632 +19.52380738 +18.21826163 +20.39784456 +21.6096131 +19.53286146 +18.86533111 +19.77030938 +18.19345084 +21.28195034 +21.30536324 +20.35200185 +19.41241156 +21.19913346 +20.2187481 +21.30372923 +20.52583517 +21.13762189 +20.39425197 +19.65656427 +21.83178344 +20.1644553 +20.42035807 +18.88195056 +20.50260316 +20.2864306 +18.73935359 +18.23834839 +20.41743728 +21.05476908 +20.09360548 +18.9070905 +20.66608791 +18.32042291 +19.76733482 +18.65346703 +18.7378362 +18.8091758 +19.54682823 +18.20460082 +19.59117376 +20.04682979 +19.93317714 +19.5311364 +21.35658643 +18.58130677 +20.02278698 +18.24816567 +18.28462272 +20.2954634 +20.2640737 +21.51213405 +20.2314947 +21.83916408 +18.19477939 +18.39203074 +18.17626345 +18.7411074 +20.16508044 +20.58228873 +18.18234063 +21.78388356 +21.36866151 +19.18644993 +18.30875012 +18.67954829 +18.50777766 +18.49313512 +20.07424675 +18.98338977 +19.43255887 +21.95802133 +20.737257 +21.79592267 +18.57022622 +19.5285579 +20.21892721 +18.30703225 +18.01674977 +20.68173734 +20.56727807 +19.64315524 +19.9585763 +19.661772 +18.09602018 +19.34148642 +18.70832902 +18.39369676 +21.82688174 +20.3974389 +20.91462514 +19.26145497 +19.57258852 +18.94769598 +18.38786268 +63.63483027 +72.04619102 +70.41462295 +68.63823271 +67.66122227 +73.74510626 +62.18919529 +65.01617106 +65.95915481 +71.84099105 +74.69819883 +64.473119 +83.40924983 +82.73126524 +73.32668281 +76.03764164 +76.19812293 +85.02198478 +72.64744231 +82.24293171 +75.02667092 +81.18310777 +76.35857079 +78.81614352 +84.80985764 +84.35744915 +85.34759431 +72.51615394 +82.574372 +73.79435924 +78.18117851 +80.29275015 +77.97316877 +79.83190409 +87.41675442 +73.71849616 +82.70792797 +78.24201224 +74.03920299 +74.45034047 +87.08374366 +85.9703356 +86.40885616 +87.75908698 +75.24264658 +77.59380496 +82.60825547 +79.64515163 +78.67534592 +77.70632599 +81.48092999 +81.19000458 +74.56542535 +79.52874592 +80.83614309 +81.10512112 +75.34362828 +83.85621195 +72.38580875 +77.65866713 +84.47934717 +81.01839767 +76.17494235 +83.11526019 +81.07436335 +84.73583024 +83.75638248 +81.75780219 +79.80701188 +74.12735573 +76.17767158 +78.7018137 +81.58800534 +80.21855558 +76.61021695 +72.10273753 +79.93906013 +76.56928074 +83.75292878 +72.38244537 +81.35646395 +87.06275199 +74.78983028 +79.54562821 +73.46261082 +82.01075314 +80.80835174 +78.51769763 +80.34187809 +86.34502875 +75.14056457 +72.36089325 +85.78647344 +81.23371735 +86.25036969 +81.550967 +84.96254481 +78.87474353 +83.99772665 +86.60863021 +81.15393626 +74.89253365 +76.30073254 +75.17828436 +75.94968328 +76.90261766 +80.88210953 +81.40783481 +31.52959233 +32.73868671 +29.32207389 +29.36183908 +29.89970281 +32.11568982 +30.16956015 +30.6130143 +31.36199613 +33.99593667 +28.88871212 +32.95601812 +23.15656559 +23.73797659 +24.33873183 +20.25021645 +20.84894986 +24.13004607 +22.21416194 +22.68936482 +23.1303606 +23.20221712 +24.33419567 +24.62633204 +21.3817647 +19.60845784 +22.03546558 +18.63360864 +19.37850694 +22.10769163 +19.48136021 +19.33578651 +18.99776097 +21.9509215 +20.48023838 +21.19636231 +19.04725556 +21.13311601 +21.14101423 +19.34279393 +19.73701559 +18.92918712 +22.01139401 +20.68120583 +21.84251871 +19.30576713 +21.22897591 +21.16453901 +20.78655856 +21.88354394 +19.59301259 +18.54065124 +20.70669479 +20.93731974 +20.31973052 +18.84534574 +20.03704087 +19.26723775 +19.72878757 +20.60063193 +20.98488729 +18.93253311 +19.62506873 +19.080309 +18.798135 +21.13760652 +21.64116508 +19.48466908 +21.00914868 +21.59212605 +21.38860266 +18.73484995 +21.82516753 +19.50670576 +19.35696264 +18.24972531 +19.94469462 +18.43605446 +18.99415928 +19.26777049 +21.23530529 +21.5019546 +19.20986527 +21.43479249 +21.42892375 +21.0586038 +18.58678046 +20.76129139 +21.78009626 +20.73016192 +19.3264674 +20.00231727 +20.58290017 +20.04228163 +18.47981177 +19.24825618 +21.20958412 +21.44567218 +18.54920013 +21.80954701 +19.31529047 +20.64925495 +21.00730058 +21.24778494 +21.78299881 +19.25167819 +21.43402582 +18.52674761 +20.82016363 +20.96791092 +20.71089296 +19.00925894 +21.49217259 +18.67543385 +18.21453917 +20.86985996 +19.90190286 +21.39639208 +19.53358856 +18.67311435 +21.34576877 +20.19563853 +18.75678317 +20.88153599 +20.04445455 +20.41725193 +19.84359335 +21.31483594 +21.31825086 +20.83755529 +18.42160551 +21.35541545 +20.68405192 +20.78809666 +19.45193136 +21.51711822 +20.9014864 +18.45036187 +19.63111214 +21.54552145 +18.18878681 +21.84566648 +20.71665027 +20.52550391 +19.08223703 +18.99516716 +21.76823288 +19.19308982 +21.10202119 +19.57248719 +18.55701628 +18.04286119 +20.17702935 +21.90311527 +19.47654478 +19.42876934 +19.37636647 +20.08217535 +19.76265953 +21.51965851 +20.02208317 +20.03103135 +18.55348638 +21.93095816 +18.99989156 +18.29345627 +20.652585 +20.38146548 +19.66058262 +19.68876894 +21.14025568 +18.78285056 +21.28101328 +20.59498846 +19.6758791 +19.83211447 +19.02658883 +21.00845733 +20.05149897 +19.28341817 +69.30628157 +74.74198855 +67.119567 +73.72140305 +65.89222902 +61.94436481 +63.97769265 +66.89425395 +64.18703503 +61.20308772 +73.64402091 +72.67675999 +81.36037543 +72.44448252 +71.7080427 +70.88922571 +81.07693301 +84.25509955 +76.52191594 +71.68906323 +77.79233658 +75.2538712 +75.65728283 +79.48305129 +82.99849287 +73.32703964 +72.13402703 +87.38182913 +75.26931166 +72.42412067 +74.58777723 +72.18758559 +77.79936047 +84.32939798 +76.99515173 +78.6322929 +82.71001711 +80.04613436 +85.68019122 +85.75354292 +72.07198084 +84.34740241 +79.27649152 +87.71606292 +79.63603516 +87.68498672 +83.97222205 +75.88650494 +80.59497223 +87.85308043 +85.69991681 +73.54021641 +83.28195948 +77.51066635 +72.09440938 +78.43686614 +75.73788929 +85.08148387 +77.37871439 +85.21992141 +72.00611056 +76.921414 +75.85500221 +75.7334424 +73.08747755 +74.99038862 +80.88491046 +76.6580974 +78.67453996 +78.02612465 +86.01035011 +86.48063271 +79.88654463 +77.28175329 +73.70810366 +87.25360843 +72.96293067 +76.76166752 +76.76832224 +77.12568016 +74.62787306 +84.5297714 +73.95925578 +82.15771782 +73.98139438 +73.12842979 +86.55070588 +75.04191618 +85.139839 +80.71393897 +73.24556368 +87.28700347 +75.95123285 +85.75416088 +74.70081667 +85.66292164 +72.21163328 +80.18845651 +84.3110489 +86.95669489 +86.54720095 +85.11396523 +86.21102849 +75.1874861 +76.54691934 +76.62346698 +78.03283293 +78.29310066 +32.28514788 +29.82322476 +33.22397227 +29.87242012 +30.78596837 +32.02140269 +33.89721309 +33.53259665 +32.93141356 +29.79694315 +32.30108401 +29.35965197 +21.85058583 +22.01255285 +20.33835413 +21.38746551 +24.44130827 +24.43227274 +21.73842401 +20.35308737 +20.96234418 +21.91713451 +24.40605171 +20.79257066 +21.55936064 +18.87716345 +22.45123077 +19.99510094 +21.60736041 +19.83525284 +21.00293147 +19.21849765 +19.03010187 +22.27431045 +22.19068298 +22.06707251 +20.60014207 +21.33499154 +18.36387321 +19.43198407 +19.34723555 +20.64118563 +19.51706544 +18.68327841 +20.48372042 +21.3595718 +19.6222307 +18.61801437 +18.80478806 +18.96812515 +19.21802197 +20.59092861 +20.42336956 +20.80427238 +19.46867994 +21.31643475 +18.83441433 +19.8952441 +21.22411048 +18.73860639 +18.44299283 +21.53887054 +19.37543802 +20.73946171 +18.10486988 +20.76417351 +19.26810401 +18.22646222 +20.44317538 +18.9668562 +19.55098203 +18.32584113 +18.588653 +19.19190894 +18.359038 +21.64330506 +18.02418817 +19.93544088 +18.49298983 +19.23071636 +21.70423824 +18.64677821 +21.86332928 +18.82317751 +20.96626443 +20.18670906 +21.53791491 +20.21597302 +20.13823688 +18.781832 +18.66491745 +21.6659566 +19.3113528 +19.48832902 +21.03929463 +19.35529393 +21.80824979 +20.95171108 +20.38971697 +21.52358064 +18.19842363 +19.02825077 +19.86014534 +18.90791416 +20.97562075 +21.67683212 +19.69508048 +19.3685304 +21.84620293 +19.77940973 +19.9561936 +19.40659949 +21.63819389 +20.27582193 +21.04869835 +21.24722687 +19.36739617 +19.73477733 +21.3938871 +19.45302141 +21.17574053 +21.76396929 +20.49284149 +20.96650915 +21.22038925 +21.3801586 +19.58021335 +18.20505384 +19.60750508 +20.69502492 +19.80140154 +20.9958526 +19.42792972 +20.53897656 +18.74567922 +20.99747775 +20.18278388 +18.81625755 +19.16764469 +20.99443483 +19.93040494 +18.86412576 +21.86908476 +20.86050008 +21.82853933 +19.70842018 +19.90040136 +21.59182086 +20.10019736 +20.82911565 +19.00869151 +19.78690587 +18.49379946 +18.82392014 +18.00377366 +18.15706021 +21.90913529 +18.96941478 +20.65324284 +21.3563988 +20.20264184 +18.612578 +20.91246575 +20.40100564 +20.92500236 +21.07898649 +21.90164147 +20.29425312 +19.36656445 +20.59385823 +18.27376284 +21.58958927 +18.47752405 +19.31137135 +21.26298152 +20.38924951 +19.57454208 +19.89374264 +21.41818957 +19.36001754 +73.02723571 +62.39862826 +71.76445875 +72.72664781 +63.67272008 +67.05271284 +63.45079694 +70.80981615 +68.48072965 +69.84039752 +63.87222275 +64.07974372 +70.48403849 +74.83848815 +78.52723714 +83.15514987 +80.19071398 +76.59735094 +84.63242418 +81.00268551 +84.27616395 +78.02816535 +73.85819434 +70.65987017 +83.11565348 +73.49720288 +76.38333564 +80.03641732 +80.54448141 +81.11967516 +74.21212477 +77.60734369 +81.38385699 +86.99199922 +83.14024561 +86.24109015 +84.09435846 +81.36971054 +74.98228706 +82.56777007 +81.87570417 +81.54153932 +79.74077 +80.36195546 +77.25825914 +80.21263228 +75.07070142 +84.78093101 +74.95443789 +73.34185437 +78.96098124 +82.51311113 +78.98450837 +76.40972338 +80.91131556 +77.53342488 +86.90502083 +86.74149928 +80.01874001 +77.22760483 +83.79009651 +72.5839229 +79.59248347 +77.37746001 +86.72441119 +72.18858322 +80.84115745 +83.84659247 +79.75645931 +73.36292689 +87.55517939 +80.28431307 +81.82619437 +75.78502898 +79.7352039 +78.86563475 +73.19763077 +73.69785815 +85.39874048 +75.8363912 +75.1186112 +80.07781447 +84.29914482 +72.99044358 +81.22877075 +73.90722518 +72.58323745 +72.84376337 +85.34646187 +73.88741787 +72.7222822 +79.0062465 +85.50373138 +76.19838772 +78.74725069 +72.63862105 +79.18522582 +81.24177809 +81.1344817 +77.31879738 +77.0485013 +73.7059496 +77.86874323 +73.59188644 +84.26550276 +87.46035518 +87.5211577 +85.84110463 +32.64506349 +33.28553407 +30.62531126 +32.83692438 +31.71615103 +31.88490485 +33.64976353 +30.6042716 +30.83544759 +34.7177008 +29.15982989 +31.90805338 +24.24934626 +22.89442502 +22.60790245 +21.27885276 +21.697873 +23.97717559 +22.66529599 +22.4660438 +20.60611599 +20.23180503 +24.4773083 +21.84889683 +20.90276045 +18.75851271 +21.23003586 +22.25179297 +20.78992463 +18.94856813 +20.81473113 +21.57095793 +20.09668189 +22.03581515 +21.08900512 +22.1153233 +20.5923925 +18.61407257 +19.33111288 +18.89745421 +21.73915541 +21.1425999 +20.80498027 +19.29604378 +18.8261127 +21.12672816 +19.99213557 +18.99389332 +20.48613573 +18.17877028 +19.3232135 +19.89330723 +18.60968149 +21.95967897 +18.85447238 +18.53919307 +18.83220106 +21.09647772 +19.72093657 +20.28111495 +18.08750876 +18.14120768 +19.78710059 +21.27070416 +21.54509138 +18.35034886 +20.15732187 +21.6570761 +19.55564498 +21.32235643 +18.53834129 +21.74575234 +21.00569327 +21.76533757 +20.70646893 +19.45361573 +21.75272469 +19.10226711 +19.32869009 +20.80323367 +21.0612652 +21.71761394 +18.81920964 +21.19199214 +20.95418421 +18.25517823 +19.54889256 +19.13106183 +19.2179617 +21.93178752 +20.57110965 +20.87070463 +21.90647055 +19.50880713 +21.20736067 +19.73812385 +21.47813469 +18.72263017 +21.79074471 +18.87508683 +19.30488203 +21.02476894 +19.57502057 +20.43284551 +19.778294 +20.96947975 +18.91332501 +18.23383195 +19.19971759 +19.89723466 +18.67208021 +19.41918916 +19.59993207 +18.22956737 +20.33322899 +21.53737371 +18.60697165 +20.39123205 +20.65895682 +19.67733872 +20.80439035 +19.64292617 +20.01854915 +18.02941218 +20.76688046 +20.64537072 +18.15360351 +19.47300043 +21.91612736 +19.68294625 +20.00778162 +21.63972063 +20.8690475 +20.32828052 +21.19121873 +21.45746507 +19.82755229 +19.90043346 +19.54420374 +21.86682456 +20.78866502 +18.33289226 +21.45183849 +19.92223976 +18.27501563 +20.19886902 +19.66865712 +21.51099762 +18.81597841 +21.30585844 +20.23075476 +18.21844121 +21.88738121 +20.05046098 +19.16350742 +19.87762737 +21.43143113 +19.2196125 +18.77070559 +18.51628499 +19.19143759 +21.12019235 +19.88650546 +18.90992641 +18.66474 +19.33091791 +21.75969749 +19.37210685 +21.9524963 +19.94092182 +18.71665567 +21.56456037 +19.84142149 +20.83868537 +21.93484633 +18.2007014 +18.38677824 +20.88182697 +19.12730001 +18.73720559 +61.73532157 +61.49711528 +71.7330042 +63.02829461 +67.56100038 +69.44019669 +67.02558449 +61.56865047 +71.85562044 +61.34297985 +71.56170256 +73.34894112 +76.55767557 +78.15161918 +77.24278225 +75.88051776 +83.61282879 +83.71384809 +75.05186998 +79.38588258 +84.22560536 +84.7711479 +77.73904431 +76.86784098 +76.0003544 +86.81789827 +73.8393187 +80.78960958 +76.06167945 +76.00534785 +78.00862041 +87.45280285 +72.44218414 +80.76912908 +72.8812276 +74.02549928 +78.93816746 +80.07116127 +76.04930972 +76.97083812 +73.30340256 +76.75929472 +87.35997711 +87.01077973 +77.26522298 +81.03630258 +86.44966203 +72.01242243 +84.9505441 +87.15299111 +73.44358106 +74.56526302 +87.35097158 +80.58129814 +72.20981164 +76.10384267 +79.180091 +83.06660181 +83.71047071 +87.90564179 +76.59650238 +80.60765228 +80.52931117 +78.48655662 +74.70300439 +87.63509832 +85.64896364 +79.96948973 +81.64800747 +75.63254632 +80.6967195 +83.11553239 +80.24190212 +87.84371942 +81.7806814 +77.93483122 +84.35362264 +74.7266828 +78.15150276 +77.55059871 +78.908156 +84.50766593 +79.74600295 +84.70341804 +81.2236665 +77.47296221 +84.95949678 +75.81248917 +75.58998254 +80.07189305 +76.17344168 +72.14525404 +82.37260228 +80.1773472 +79.12813311 +87.47132829 +81.13915579 +85.81487229 +74.23117527 +81.10727226 +85.88764105 +81.32966089 +83.48819479 +77.95266715 +73.47916406 +79.32637426 +78.31164018 +85.87292994 +30.36156411 +34.98709234 +34.93207726 +30.38483668 +31.02752656 +34.53155011 +34.9863755 +31.63800418 +30.85437517 +32.16699551 +33.20171655 +30.55023103 +23.45939854 +20.39142384 +20.38083821 +21.89056772 +21.74355871 +21.57403562 +22.35976731 +21.59688526 +21.02131432 +21.5464224 +24.5275698 +22.0017869 +20.25354329 +20.79352803 +22.45976352 +19.4215986 +21.22253127 +21.36467305 +20.91960056 +18.79481665 +21.20446859 +18.69453171 +20.87380004 +21.46132424 +18.93433014 +21.46904712 +18.20839797 +21.47785261 +19.93655447 +18.9609294 +18.62408107 +21.91793211 +18.37845748 +18.88659623 +19.48436753 +20.57924785 +20.19857637 +18.52033643 +19.17730448 +18.97320388 +18.87227141 +19.66343613 +20.83610928 +18.88792674 +19.48540356 +19.58245082 +21.9268557 +21.83961134 +21.20462083 +18.97027728 +18.27565751 +19.27131593 +19.07083909 +20.02754775 +21.11496493 +21.43740695 +21.3835612 +19.44243447 +20.75292117 +19.25503304 +18.24362217 +20.80626106 +18.03931021 +19.63673035 +19.31751708 +20.77351015 +21.06498189 +19.21637854 +21.24650806 +19.17566704 +19.78530544 +20.90807411 +20.77168092 +21.94947389 +18.9006441 +20.64927165 +20.43872763 +21.66039382 +18.62544857 +21.00719265 +20.27307447 +19.09866348 +19.89773966 +19.33510639 +20.31725361 +21.55600244 +20.27721994 +20.52688967 +20.07499139 +18.20466203 +18.93143423 +19.96800692 +19.24094114 +18.72705439 +20.01653137 +19.29123917 +19.03243057 +19.85594167 +18.53313703 +21.71098293 +21.47080839 +20.83048234 +18.42485531 +21.10350902 +21.23182931 +21.07105847 +18.45586355 +20.57563183 +21.33729918 +20.3094136 +20.5856295 +19.83345392 +20.11482928 +18.13750743 +20.55585209 +18.32578885 +19.74005838 +19.17062039 +20.1817118 +18.53366534 +20.76657361 +21.18004615 +18.6534178 +18.41725235 +18.58206193 +21.50851025 +20.11275705 +19.86904398 +18.42684728 +20.59822403 +21.47199837 +21.31274348 +20.50421884 +18.30111487 +18.44958811 +18.19723595 +19.02991687 +18.54264587 +19.04019216 +19.54023222 +21.77193114 +20.44150424 +21.33989514 +20.841406 +18.45001252 +20.94368163 +19.10039553 +20.55643139 +19.36384789 +21.99068905 +19.05420592 +19.11652188 +21.72268902 +18.09857762 +20.78675595 +20.90130556 +21.34551431 +21.89775724 +21.90240768 +18.26110703 +21.28735729 +20.58523973 +20.58936854 +18.51339971 +20.60074867 +21.92993032 +21.64727428 +19.75652264 +61.74329244 +66.12719146 +72.43890824 +70.74038778 +67.44707372 +61.94938088 +67.0057683 +67.57873918 +73.82835525 +69.91877101 +65.43847967 +68.3443284 +70.86517838 +84.93425902 +75.42812968 +77.25650135 +75.35400728 +80.43258205 +80.1178431 +80.94180226 +74.00158292 +74.73917483 +71.78389911 +80.01351476 +72.20093351 +81.07353986 +85.39964335 +85.73579449 +78.70949654 +78.87276586 +72.79211789 +82.23584696 +84.62930982 +75.45899399 +78.26836922 +84.90890081 +85.93068677 +75.79981063 +80.7121592 +74.98979454 +73.54170415 +86.47403451 +85.02596632 +84.05956576 +72.69292479 +85.39706109 +78.91389477 +77.38534799 +80.72424331 +73.44402109 +84.08615927 +81.29944468 +74.96744504 +74.99371238 +74.92999091 +72.89453931 +81.38523804 +85.4250639 +72.26262423 +72.76660614 +81.16042854 +85.10784559 +77.22411531 +77.59010588 +81.53762997 +76.38373963 +72.42225742 +83.75963563 +82.00646211 +81.28819396 +83.86292045 +82.79971882 +75.29338899 +77.63895141 +74.0170517 +74.07700107 +82.81833688 +85.73677863 +87.40288227 +82.05276617 +74.9449017 +73.6896981 +85.00479949 +81.25932352 +81.8924031 +84.50323117 +83.2522758 +85.35116817 +72.89928252 +83.96016898 +85.61347974 +76.57801365 +82.24699847 +77.02644513 +87.32736939 +72.53463789 +81.27665429 +74.66402808 +83.39549126 +74.81421581 +75.7661031 +79.90990229 +86.63732593 +75.38740101 +74.3078118 +84.143597 +80.00988179 +86.58852855 +29.73832746 +32.93393219 +30.29042072 +29.80326102 +33.17394189 +32.59957531 +33.63088928 +30.78055458 +31.66701252 +31.3950127 +35.09816583 +30.67038743 +21.48078005 +21.74837478 +22.68938024 +21.29040473 +24.2604976 +21.35027016 +24.17325315 +20.62356715 +23.10139964 +24.22329379 +20.91599634 +24.49810344 +20.28701 +22.30564882 +21.20425464 +19.66729958 +19.20328691 +19.67609851 +18.81299908 +19.02128296 +18.86068894 +20.16437651 +21.69068877 +19.01110681 +18.61018384 +20.67246958 +18.8789178 +18.47871422 +18.75699776 +21.79906117 +21.38805721 +19.50945624 +20.72227478 +20.24581834 +20.80789779 +20.83019185 +20.53463039 +19.08270729 +18.17345546 +19.84129649 +21.58459687 +20.29745589 +21.35004054 +21.9875852 +18.67237309 +20.78704697 +20.71704357 +21.94086481 +21.94661588 +20.75069781 +18.97810226 +21.19829264 +18.43165473 +21.12685279 +21.64493953 +19.53508359 +20.52648151 +19.72435728 +19.75485242 +19.24517792 +21.04851848 +21.74470626 +21.76300344 +18.69912514 +21.4989746 +20.94972577 +19.0113496 +18.26913845 +19.07198907 +21.64883295 +20.5327147 +20.88421864 +19.0286094 +20.87755262 +18.11248603 +19.50128538 +20.50701339 +18.58438626 +21.2920143 +18.9401252 +20.60912445 +19.62078857 +20.38417438 +18.42980221 +18.0676512 +21.63825771 +19.07852004 +21.27870801 +21.9974012 +18.84572503 +19.06068296 +20.65143915 +21.86179454 +21.66325739 +20.01150208 +21.18044113 +18.54298341 +21.90975274 +21.85741294 +18.65491583 +19.1976925 +18.40061999 +19.0868704 +21.26382316 +19.51326243 +18.35358787 +19.3689021 +21.92553334 +20.51873438 +19.66464379 +18.66615405 +21.94470719 +21.28339604 +19.12590921 +18.28027478 +18.22650223 +18.4815126 +20.32307433 +21.71505368 +19.98697371 +21.37178193 +19.78354648 +20.83433418 +20.92749095 +18.69585482 +19.44486424 +20.54920863 +18.28278643 +19.44616075 +20.13919787 +21.98489797 +19.89813425 +21.26422703 +19.72826914 +21.18556289 +20.38165921 +21.54638177 +19.64377021 +20.41721768 +20.52007472 +19.66953177 +18.57724817 +18.37423763 +18.0666862 +21.49413706 +18.94589965 +18.846027 +20.9441416 +19.28006445 +20.02417877 +18.65004426 +21.83898289 +21.4063256 +21.45515849 +19.62709499 +21.04944485 +18.57550462 +18.03447601 +18.07989173 +20.34640695 +19.82157962 +20.0720614 +18.02985256 +19.69074648 +20.87227264 +19.77077481 +20.92887683 +18.93207586 +72.25873126 +69.20266487 +64.06637815 +64.41939847 +69.74121432 +72.48717847 +66.85253784 +64.71288584 +72.99135785 +70.30204877 +67.29396263 +67.83544266 +73.01006038 +79.56797682 +75.40768376 +85.29241314 +77.29244816 +77.38094461 +78.62201974 +84.06805317 +82.26869691 +76.84153868 +80.99421261 +78.93837494 +79.39860554 +74.62659005 +78.94644233 +75.47749881 +86.11764955 +76.90230996 +86.71280689 +80.04571133 +81.6120818 +80.20292483 +73.62566933 +77.54506067 +73.49803419 +81.86890399 +79.05500714 +84.34642223 +75.43689466 +74.54349727 +78.40711412 +86.72117569 +83.26670894 +78.60833466 +80.18002309 +73.25939129 +87.73215357 +82.64267787 +76.54808914 +81.3534048 +73.73401744 +87.43239789 +74.77860863 +82.34871665 +75.90904886 +83.46094669 +84.40887888 +82.75484973 +81.82806343 +86.27536409 +73.25451099 +77.29092611 +75.96895299 +87.8040086 +78.22648142 +83.71778454 +82.95162075 +75.38968092 +75.82032333 +76.49688099 +78.5772821 +75.74847386 +72.31372951 +86.06946263 +87.44891778 +77.46438253 +77.41536688 +72.11277672 +82.88321533 +85.20622034 +74.34501909 +74.55394587 +84.64116949 +81.8604948 +72.7176293 +81.96059448 +76.94253584 +77.89945292 +84.31554081 +84.97479993 +78.40555549 +87.15427964 +78.50325276 +84.34921461 +79.74200561 +86.36048406 +86.52414667 +73.39864074 +86.9838599 +85.20852474 +84.66093892 +75.21455255 +84.88187475 +85.60209088 +76.62637593 +87.23612776 +29.11909935 +29.75941351 +32.24051309 +32.48506558 +32.92895421 +28.90859688 +34.94634065 +29.08535821 +29.71559079 +28.88968737 +32.42788775 +34.76650138 +23.14344203 +23.84550415 +20.21949868 +22.5882273 +22.21884092 +22.39537516 +20.48351395 +23.22626914 +22.41442623 +23.58786555 +22.33410082 +20.82922859 +21.08726023 +19.13809431 +22.00532787 +20.94332386 +19.07590688 +22.37373642 +20.55522469 +18.73059183 +20.99950732 +19.46910249 +21.72392812 +21.78179895 +22.02098516 +20.10351397 +19.91496264 +21.1147691 +18.61882602 +20.28456278 +20.2818783 +18.44601033 +19.76636159 +21.51592221 +21.52745258 +18.48525598 +18.38051189 +19.06907065 +21.51970334 +18.53338532 +20.90003199 +18.42233095 +20.51222425 +19.44291649 +21.17596527 +18.95293916 +20.57654184 +18.96091515 +20.85864522 +21.49883912 +18.51076058 +21.4705043 +20.37821288 +18.51199558 +19.71395177 +18.64702071 +20.80538542 +21.03951135 +18.42672333 +20.02840412 +21.25850022 +21.74465217 +20.05407147 +21.80111689 +20.14275588 +19.57676198 +21.39281251 +19.97193084 +19.88761004 +19.96124996 +21.38714001 +21.32776617 +19.61407997 +19.33319944 +19.9677121 +20.29109004 +18.95334884 +21.17582034 +19.94593106 +19.33618219 +18.42728397 +18.95538064 +21.79712469 +19.22039875 +18.67543716 +19.84269117 +19.22835097 +18.140637 +19.29258087 +20.1764345 +20.20684949 +19.42623568 +19.78921103 +21.86207167 +19.50939391 +19.03290725 +18.97386818 +19.83105845 +21.03808059 +18.82395274 +20.83718451 +18.08459929 +19.67573191 +21.10346026 +19.35493182 +20.25494841 +18.81991693 +20.96798156 +18.20911641 +21.41017058 +18.79278555 +21.49759213 +19.41011697 +20.8907343 +19.27690119 +21.62364668 +18.5065485 +18.71407916 +19.9721205 +18.32775376 +18.78392074 +21.77506553 +21.90595864 +19.50503732 +21.69314408 +20.1792987 +19.07896986 +20.80959488 +20.63560723 +21.95650128 +19.06018915 +20.68823801 +18.20809502 +18.45458415 +18.0156735 +21.99784272 +21.20909479 +21.14689206 +20.0389043 +19.20026833 +18.60505714 +19.13869896 +19.50388489 +21.02524039 +20.15864716 +18.30993451 +18.07211604 +18.40932872 +19.64199485 +21.73277167 +20.54960992 +21.2073036 +19.86549838 +19.44666433 +18.43360149 +21.50373209 +21.13264012 +18.67247239 +20.04904226 +19.94949923 +20.50036621 +21.78474758 +20.31908577 +20.16086907 +18.20129173 +18.2516299 +18.74938717 +18.12988309 +71.30959938 +71.03729213 +63.05036479 +72.57067305 +63.30509007 +65.29598798 +64.58608583 +66.26337654 +64.66342722 +67.8497326 +66.74074719 +74.61734507 +70.70797695 +72.04665496 +70.65985787 +79.55305535 +70.68598399 +82.82154472 +77.78528755 +78.01915833 +78.55594676 +72.49102872 +72.9081535 +74.78804485 +81.006967 +74.90971311 +73.41813979 +86.99673896 +71.91759878 +84.33409953 +84.10091102 +76.29489327 +73.7250057 +73.884078 +82.65995244 +81.79119602 +84.42250207 +86.89529912 +82.97115281 +74.40423224 +75.80400777 +85.37252957 +75.25847854 +73.07256464 +83.15257789 +78.34629318 +86.61657607 +82.30519624 +73.42907644 +87.14478531 +76.11864336 +77.37682495 +78.41734194 +72.80211204 +79.92506014 +73.95534231 +78.3967055 +77.59272988 +84.34519363 +84.83036401 +74.4510323 +77.86108149 +77.96990784 +74.41899482 +84.77118687 +83.3116541 +75.04250637 +77.8638129 +73.68934314 +82.04736709 +73.93840158 +87.7707335 +84.49010208 +78.24306565 +81.25624285 +86.58063788 +80.86481218 +74.79125778 +78.05850432 +85.48949713 +82.3066181 +82.410799 +85.86831943 +86.30274041 +86.71651465 +73.51744594 +80.70586108 +83.84799135 +84.11066803 +81.70730235 +74.668454 +84.75856613 +83.52162097 +73.37803146 +79.42080471 +74.78349481 +77.39960301 +72.28926972 +78.40524779 +80.79799971 +81.91329003 +82.6158138 +85.38062822 +75.44737754 +73.92768077 +85.62456187 +74.50577643 +87.59612766 +34.1922381 +32.00560413 +35.08109038 +29.42320542 +30.73961497 +32.88462994 +31.040038 +34.74157766 +29.22000135 +32.31622952 +32.58153786 +32.97745366 +21.30538351 +21.7932564 +23.93968746 +21.03334245 +23.86436665 +22.68069505 +23.57459876 +23.35695972 +21.08965034 +22.70827981 +24.04739841 +22.09587953 +22.39115553 +20.28427281 +19.01684974 +20.02712421 +22.33017279 +19.74157636 +21.9877298 +22.04160253 +19.86636377 +18.77302314 +21.39978894 +19.70795414 +21.23312654 +19.86551832 +20.03678404 +21.21297344 +19.62319465 +19.86741738 +19.59838468 +19.56281495 +20.20028443 +21.33712668 +19.54041915 +20.19348452 +20.70276488 +19.09607242 +19.1284369 +21.7545168 +20.91419666 +20.32824309 +20.61064745 +18.13459027 +20.49206537 +20.057272 +20.20237439 +19.45635549 +18.32941416 +18.77696142 +21.80716502 +19.63856813 +19.87054703 +18.21433564 +18.15374977 +20.87273258 +20.15624791 +20.03867062 +18.97614084 +20.98303089 +18.67294632 +18.75973897 +19.84284869 +19.14511945 +18.98985192 +20.58095058 +20.60388698 +21.29806828 +19.67083427 +18.29234036 +19.09466554 +21.92002185 +20.3850343 +20.83894834 +18.02943132 +20.07282293 +18.15011463 +20.27692085 +21.6830834 +21.87367652 +20.1622107 +19.83281922 +21.78006838 +20.69443933 +18.25959712 +19.86290231 +18.96098007 +19.87921729 +19.82186229 +20.32857921 +19.42708196 +18.6570818 +20.01487774 +21.32081154 +20.65604891 +19.35347146 +21.74209209 +21.64883029 +18.8373936 +18.15767034 +20.96523483 +21.31044105 +21.87145826 +21.55934558 +20.40213907 +20.12020936 +18.11136421 +18.98662579 +19.83845901 +20.5140156 +20.22900733 +20.97054396 +19.11906772 +20.25981043 +18.35256897 +19.65466209 +21.00064333 +20.77360341 +21.96257095 +19.1115645 +19.9927572 +19.31812166 +19.76241246 +21.42780052 +20.7368363 +21.52976477 +18.81404443 +21.49344447 +18.2390491 +21.55439712 +19.31629512 +19.25835053 +20.04835431 +21.76276075 +18.19112546 +19.4089239 +21.42628795 +19.58421791 +18.79662759 +19.69917673 +19.54221001 +21.66166481 +21.0477375 +20.02046222 +21.95348227 +19.86111013 +18.23295132 +19.04909729 +19.74428192 +18.6276105 +21.79026051 +21.06739559 +19.0731488 +20.36321813 +20.88579663 +21.76511572 +21.5265414 +20.0607689 +21.09861048 +20.24857902 +20.21081556 +18.45896783 +18.50455063 +20.11813446 +19.07544618 +18.08414761 +20.89135682 +18.12994639 +69.29576504 +68.5330356 +74.37587979 +67.7852987 +62.06497953 +68.70295636 +72.63890792 +74.75715027 +67.05266716 +65.5560629 +73.53048484 +63.80089296 +79.39145676 +76.13668786 +70.4775983 +75.22991712 +73.95634667 +80.48813471 +84.56522852 +74.00009235 +82.43395138 +70.69918436 +78.19163808 +70.93493699 +86.42286069 +83.75605077 +82.03203539 +84.67124805 +81.86615483 +86.97809169 +82.9227872 +86.27377053 +79.79246561 +73.42979242 +79.96813848 +73.58578546 +81.38211979 +79.6242251 +81.86285292 +72.07415879 +75.02730693 +79.76545337 +87.10340732 +78.04397935 +78.69540447 +83.33501526 +81.5626913 +76.69067902 +78.55420479 +75.46508081 +87.43535382 +74.07236847 +77.9306807 +72.39604433 +75.53034024 +84.4672612 +75.2007512 +73.263427 +79.57214898 +72.14218947 +73.35273737 +84.91793766 +84.33952503 +86.6380623 +85.66813471 +82.92682833 +72.83382953 +84.52152066 +85.52406762 +84.78124464 +80.13181805 +75.72279455 +85.52445857 +83.63380206 +87.69133695 +74.49036645 +75.60990747 +75.38804667 +84.67982335 +74.98979683 +73.06585584 +87.97612833 +72.39638037 +85.36308547 +77.84572 +85.46568326 +80.87377258 +86.42593373 +86.81892109 +72.14543238 +73.20645426 +76.00559374 +82.70888786 +86.21218962 +79.35891885 +81.71141297 +75.01596884 +84.87943675 +87.47721619 +76.29755363 +79.91718454 +73.37782959 +80.94615542 +80.04450433 +74.31095521 +79.07302905 +77.34564473 +80.34926315 +32.5481815 +28.85436616 +33.67043183 +33.36328506 +31.14422689 +29.13878439 +33.6315618 +34.91311432 +30.33696439 +30.8705516 +29.97639674 +32.49238495 +20.8536883 +21.75574767 +23.28261703 +22.66931836 +21.89135109 +22.04271701 +22.67825551 +20.18627287 +20.51172309 +24.10803482 +20.50889675 +23.32647883 +22.20047605 +19.54071981 +19.94953269 +20.76230183 +22.04347968 +22.29004502 +21.46125081 +18.78679432 +21.17285517 +20.1126038 +20.35999105 +18.63331158 +18.8543169 +21.26363224 +19.91095129 +19.29884083 +19.62984941 +21.52040247 +21.0967768 +19.18089 +18.55866335 +19.09923121 +21.78710427 +20.42392181 +20.15324939 +20.40514454 +19.4827986 +21.24880736 +20.11243441 +18.48471991 +18.5340361 +20.16677812 +21.76715729 +19.25187255 +21.4987837 +21.07659646 +18.99489609 +18.1488469 +18.41092328 +20.91799122 +18.8022883 +19.48882482 +20.01063797 +20.90588583 +18.45646785 +19.62923371 +19.94412017 +20.16717961 +21.27344257 +18.68671278 +21.23132581 +20.77151371 +20.22348326 +20.79811148 +19.64807096 +18.55359034 +20.66306096 +20.09868923 +20.5574992 +19.35199512 +21.62746631 +20.34947947 +18.34160994 +19.79921596 +21.02542422 +21.17653825 +19.97838821 +21.57899028 +19.07067375 +19.64239479 +21.59438764 +21.58502687 +20.74285108 +21.43592219 +18.35509307 +21.4599799 +19.28247963 +18.71332605 +18.95747935 +19.67187403 +19.00476802 +19.28227034 +18.53991394 +19.18470706 +20.28913526 +19.76741483 +19.38687504 +20.98580852 +21.57403989 +21.02715689 +19.32800281 +20.97776867 +18.60792073 +18.52127195 +19.38250815 +21.23080948 +18.98539299 +18.25301364 +18.52683814 +21.43497987 +20.53513314 +19.01280465 +20.2211833 +20.11031849 +20.62174391 +18.93275022 +21.45761195 +19.23747425 +20.77652662 +18.06449859 +19.49062852 +19.40683927 +20.17393771 +18.29094505 +21.16052549 +18.87112321 +20.70815126 +21.21284849 +20.24750783 +20.96353283 +20.64744125 +19.42211919 +21.23543416 +19.17880548 +20.28485167 +20.98159096 +19.51582364 +19.21107043 +19.83738404 +21.27185398 +21.71968705 +20.18033365 +20.64586482 +21.61309449 +18.39418741 +18.92831431 +20.83560003 +21.29497785 +21.42811611 +19.66042871 +18.35735961 +19.75112591 +18.92293836 +19.16478582 +21.08907023 +18.30210834 +21.31032487 +19.71067634 +20.38425572 +18.35860892 +19.34943631 +18.35880368 +21.84617489 +21.2290466 +19.83853102 +18.89441019 +73.89498943 +65.8865137 +63.38938827 +68.85903568 +74.03532804 +61.25209195 +64.43849787 +73.96288791 +63.52676915 +62.74011094 +68.95454613 +72.921076 +77.24474437 +85.27563726 +80.38074478 +70.98964256 +85.24875468 +76.17051855 +74.30048733 +78.49828493 +74.56285383 +71.18182051 +69.86216788 +76.81753364 +84.87747587 +80.67010071 +87.45939288 +76.13000905 +76.02835735 +74.10865542 +74.17726731 +76.10360762 +84.17732808 +85.973156 +87.07578635 +75.26233466 +85.99743982 +77.15937893 +73.71688217 +85.81729433 +82.07907693 +74.5461315 +78.78264736 +76.50420777 +83.68816664 +79.1595541 +87.72308495 +72.78846861 +77.661601 +79.69127218 +80.03092484 +77.03647996 +83.6477637 +85.97531415 +86.99862415 +84.86112247 +85.58873693 +80.78933072 +85.19376021 +76.83761709 +78.37189816 +77.06690883 +79.47438241 +76.56559853 +87.38158856 +77.00181778 +73.56518131 +80.42521406 +72.9100854 +73.76514976 +75.50660574 +79.42579138 +78.93125717 +84.79425576 +83.83078968 +78.82033602 +77.33852486 +77.06276074 +84.38311131 +72.8324593 +72.20445322 +84.72789688 +79.63357753 +74.09338691 +75.76890948 +86.91989636 +85.75188297 +83.35640076 +79.71545063 +80.32502379 +87.60374437 +87.45215919 +75.44415988 +84.9775099 +75.15573836 +75.41645485 +82.81745674 +78.47998744 +86.90467714 +73.42412756 +80.18437946 +86.6963112 +86.46578536 +74.5044388 +77.8661733 +81.90591095 +74.55028953 +87.48832116 +34.65438905 +29.86847541 +29.57538927 +29.34660866 +34.6204328 +30.03918662 +31.4642175 +31.67264266 +32.63366442 +29.25910058 +30.25124934 +34.7615318 +24.22967595 +23.6601808 +20.24691647 +21.62498914 +22.97325387 +21.39285098 +24.23494706 +22.99982353 +20.48214097 +24.23234371 +24.45079329 +20.50815051 +20.61254727 +19.67457986 +20.04106862 +19.16785116 +20.79978308 +22.35588316 +20.49258512 +18.7716179 +20.97152521 +19.82555315 +21.93786931 +20.21244145 +18.86146091 +18.85449167 +21.17621694 +19.15384963 +21.17006441 +18.91390223 +19.37932181 +19.95728519 +21.87729271 +21.83121489 +18.9178594 +19.52615392 +18.61545124 +20.05917865 +19.86137883 +21.62377956 +21.74087272 +19.55302245 +19.98612004 +21.60566653 +21.24720898 +18.03191928 +19.29874728 +19.70599657 +18.92249756 +18.80189573 +18.15462304 +20.57742901 +19.05369877 +18.21288491 +18.92755063 +21.21172768 +21.41006667 +19.93609197 +19.66805822 +21.91562176 +18.80225864 +18.86143713 +19.16746871 +18.69102927 +19.51746239 +21.64333691 +20.46139136 +19.64778619 +21.73764318 +18.19385693 +18.84110471 +20.26355442 +20.46221049 +18.15823003 +19.61215503 +20.59661586 +20.79228219 +20.55255961 +19.2822529 +18.37408049 +19.70844979 +18.51501775 +21.79049463 +19.90068346 +19.2690367 +21.06521628 +19.99179437 +19.2401361 +21.24787097 +21.4686086 +20.69203267 +18.18785769 +20.26529152 +21.05317965 +18.54601205 +18.91468301 +21.52998042 +18.08048689 +21.01090855 +19.89509317 +19.78708864 +18.02838613 +21.27759292 +19.4392996 +20.16306253 +20.70920275 +20.81051831 +21.82392024 +20.12535981 +19.5988782 +21.81481451 +20.56844094 +19.19260143 +18.50585698 +21.37021801 +19.44872641 +20.64187889 +19.88326568 +18.79571912 +20.40674643 +18.24273228 +19.65336984 +20.18645976 +19.7441879 +20.9946887 +21.31169982 +21.0849723 +18.15525179 +18.77651508 +20.14643004 +21.73928816 +21.3398271 +21.37013803 +19.21283278 +19.71779159 +19.88282379 +18.62948633 +18.12427252 +21.7876116 +18.96285034 +18.95979561 +18.33351622 +21.71403101 +20.31894846 +20.66814743 +21.64630755 +19.38248068 +20.48602924 +18.15519782 +18.74709011 +21.32498322 +21.06707343 +19.40257077 +19.50724251 +20.13421773 +18.00096402 +18.96497734 +18.83292723 +19.00193179 +21.22362337 +19.11869543 +18.76608529 +20.01705384 +21.46258015 +18.96539882 +18.31414497 +19.42561894 +20.9906073 +68.68939141 +72.30838983 +74.25045321 +71.98020968 +69.41172187 +67.9094456 +61.74493957 +74.58677891 +66.41534327 +63.27030371 +70.26724043 +65.06632073 +78.93127876 +78.94663793 +76.75772682 +82.81656091 +73.9522888 +76.80277782 +78.18498184 +80.13945567 +82.00724312 +75.96740903 +79.86664857 +72.17748199 +86.40083539 +77.66016726 +83.1703087 +71.89150457 +74.83129632 +79.31456078 +85.53572725 +79.9534659 +86.35666015 +79.26230584 +79.36810243 +73.47245292 +84.74068891 +75.86030486 +86.29012727 +86.4692997 +86.98845024 +80.2272994 +82.73410036 +84.35490658 +74.00731842 +81.51737674 +72.4617079 +79.86510407 +74.45960831 +74.90878439 +77.82207928 +78.90005411 +81.95108581 +73.17328889 +80.039854 +74.9040208 +81.16411874 +82.17874616 +80.88793034 +83.79261311 +77.36603416 +84.23766186 +78.92048494 +79.74312412 +82.36568029 +72.29026404 +82.45994928 +81.89343131 +76.95385991 +73.36918667 +73.45144136 +86.76741492 +83.02767207 +74.0329311 +77.70682472 +81.4789457 +85.36832774 +72.69787695 +75.78540256 +86.23515598 +72.1459562 +75.22166351 +87.34354831 +81.81364413 +76.18659559 +73.07171721 +72.45092234 +75.91577552 +86.10360779 +78.65446745 +83.52517354 +86.69239412 +78.52849661 +75.06029382 +80.27373277 +86.52917286 +84.86995804 +73.05324944 +83.0811329 +81.1503292 +86.5193776 +73.95967427 +80.54454688 +86.07137004 +78.56035042 +79.71188807 +73.12734276 +76.45026889 +30.87683663 +34.84877698 +30.60906523 +31.74955381 +33.09634196 +29.83796785 +31.91322515 +33.52664342 +34.34786677 +32.80805306 +33.08193615 +29.60820854 +24.39707737 +20.75393073 +23.63053346 +21.34637595 +24.34249595 +23.38541745 +23.53708414 +21.14138394 +22.14481788 +22.92780185 +23.60948051 +20.62573687 +22.37384807 +22.0783436 +19.53934759 +21.80202569 +20.55505454 +20.3235591 +19.71992186 +20.81164708 +21.42162557 +20.11518094 +21.00928156 +21.29638547 +20.94454076 +18.2952621 +21.54189833 +19.92821167 +19.14110267 +19.05809986 +20.02773027 +21.65075327 +19.60705455 +21.09969767 +18.4755338 +19.99976705 +21.98783263 +21.10198968 +18.86020237 +20.02497142 +18.95267616 +19.65709641 +21.14061161 +21.10514075 +18.93055741 +21.7097146 +20.38982818 +19.53843606 +20.01158381 +20.42420571 +20.24344812 +19.9494497 +20.023575 +18.70923912 +21.25501179 +20.17091335 +18.52787611 +21.06867281 +21.73394803 +21.79341113 +19.47607093 +18.54206749 +20.07359851 +18.45043692 +21.73594967 +18.73431851 +19.01106344 +19.62654611 +19.53265787 +21.17865157 +19.82526728 +18.68307304 +19.06883958 +20.03645354 +18.58981567 +20.4466227 +20.26298923 +20.85880927 +21.75081846 +21.64901824 +21.78430247 +18.97886239 +18.52626123 +19.2091068 +21.58034069 +21.8882139 +21.4372998 +18.44007088 +21.78971199 +19.69343211 +18.03724116 +19.76957496 +18.18427668 +20.17551168 +19.35421611 +19.89373973 +20.45268144 +21.47520438 +20.64760631 +19.73619547 +21.27771141 +21.62232855 +18.47903987 +20.12773191 +19.13804784 +18.18824479 +20.67418678 +21.45108311 +18.65161062 +21.24965463 +21.41358293 +21.65736177 +19.06114036 +21.61581226 +19.28265102 +20.20935205 +18.20202988 +18.17552435 +20.88149285 +19.77791991 +19.0251695 +18.76165398 +20.67981396 +18.00160618 +21.22356468 +18.31699842 +18.76595846 +19.54494558 +19.93943496 +19.41998046 +19.28284866 +21.85566405 +20.56631873 +18.09373182 +19.72070363 +21.5000348 +19.20582475 +18.37822538 +21.03353909 +20.42405533 +20.28125003 +18.21430624 +18.56199604 +20.49019758 +18.83129537 +20.01628032 +20.17952674 +19.13402876 +21.79370062 +21.36985643 +20.88949403 +18.31197547 +18.42452008 +19.97112538 +18.6428534 +21.91306185 +18.63408094 +19.94987134 +19.45648423 +20.55754569 +18.51614564 +19.72126571 +19.09882013 +21.5510061 +18.16234285 +21.65490998 +21.33197655 +19.19028287 +71.9343529 +61.62450442 +74.34937148 +68.36169122 +65.32462195 +66.13113169 +62.10311281 +74.65515339 +61.73437045 +70.10673687 +67.22120862 +74.10526057 +73.65791597 +78.09798751 +77.32616836 +80.74848721 +70.8955188 +72.8476073 +73.17004601 +81.29609972 +72.77543257 +78.74059218 +73.18058409 +83.21241923 +86.55251747 +79.81411227 +77.17112049 +75.29045485 +72.35971705 +75.83822521 +81.97296584 +80.05464368 +86.58203249 +77.87039358 +82.6032026 +79.35018898 +80.10497799 +76.19284777 +79.18407737 +79.43712088 +83.20631281 +86.9457797 +77.17641747 +72.58799725 +79.84479314 +80.61452766 +74.60541476 +84.06643278 +87.73780361 +87.1114837 +75.13565973 +85.98517044 +83.25191293 +79.24252225 +80.63041996 +85.57306034 +79.66303532 +77.95260479 +79.87278582 +81.24657301 +75.02164125 +86.41037579 +82.78301741 +82.12836033 +73.58840721 +81.66286301 +73.9318217 +73.25564636 +80.43311336 +78.44080321 +81.41705612 +73.42403017 +78.89497161 +74.79586939 +87.79275856 +80.97762601 +82.99819298 +77.20595131 +73.51511688 +87.61309271 +76.5794094 +78.78017467 +82.39703173 +72.39446177 +84.96398296 +80.58509632 +76.45132821 +72.98558763 +74.59983142 +86.32037601 +82.97622827 +75.99828163 +73.04947198 +83.04968554 +81.15836779 +78.47216172 +77.81775331 +75.46899943 +82.71374834 +87.53065483 +74.81141521 +81.5538346 +78.78693064 +79.14698916 +76.06632727 +85.20212529 +79.76405904 +80.69446265 +30.75046394 +29.96356843 +29.34982085 +33.37035609 +30.05589363 +33.21647589 +31.29840325 +31.46095269 +31.80272987 +31.15332847 +29.4439622 +30.78163767 +23.13352867 +23.14271285 +21.44228372 +22.22125855 +21.02664243 +21.10246577 +20.26324984 +24.17742322 +21.1039647 +21.17935061 +21.41261324 +20.73078702 +21.05042052 +18.73978531 +18.98169291 +21.0729233 +19.82324966 +21.33175404 +20.71521151 +19.48066249 +21.09779103 +18.90825677 +20.62913668 +20.2225584 +19.16303746 +20.51401684 +21.58846392 +22.10119772 +20.52912007 +19.7129938 +18.99155233 +19.11972056 +20.0134254 +19.56256249 +21.75920328 +19.5666531 +19.51249238 +19.55289081 +21.36697345 +20.6229323 +20.4763138 +19.35513519 +21.29203745 +18.17088275 +21.50381254 +20.07024855 +19.61181021 +20.00785824 +20.6736307 +18.05452751 +21.49033278 +19.7907572 +19.37558548 +18.55654443 +19.761655 +19.98912826 +19.61835278 +20.71861758 +19.68736536 +21.84986468 +20.39711007 +21.22991174 +18.43742361 +19.58916517 +19.34739081 +20.27792955 +21.44445408 +18.31335287 +18.29029919 +21.40127083 +18.85140034 +20.67501302 +20.17151253 +21.33157438 +18.50035564 +18.51913186 +20.22727344 +21.78551461 +19.65999103 +19.3077684 +20.42675729 +21.7217944 +21.34771133 +21.98193444 +18.09027433 +18.45143258 +20.43787105 +21.28230576 +19.14097737 +18.95684435 +21.1479032 +18.22552742 +19.47753059 +20.02323689 +20.2413947 +20.91446063 +19.41938289 +20.45073738 +20.34150169 +20.1904644 +20.56193317 +19.03779668 +18.33859501 +18.47708669 +18.89832953 +20.00079174 +21.361771 +20.80517337 +21.15616242 +19.4039025 +19.61861497 +19.57472754 +18.76749274 +18.24486663 +20.36366437 +21.95686673 +18.66731882 +18.18673928 +21.11812673 +19.01034403 +21.31857522 +20.81574667 +21.78269415 +19.63570894 +20.64787936 +19.85941912 +20.52235479 +19.79839562 +18.75452899 +20.03158966 +20.11433681 +21.24241539 +20.94208282 +20.6551665 +18.45354838 +20.88246516 +20.00122063 +21.57639814 +21.67948374 +18.22062636 +21.28256624 +18.15078956 +19.4686785 +20.1691999 +18.59240319 +20.98525525 +18.03341882 +18.67439619 +20.32318732 +20.85755025 +21.66657241 +20.82198661 +20.68711708 +19.57736459 +18.0051377 +18.48063703 +20.13821818 +20.70051954 +19.66979314 +20.92271605 +20.08744918 +18.29670478 +18.768065 +21.35999289 +20.89965099 +21.57904795 +18.470229 +21.96089014 +64.04793131 +61.36020632 +74.76495197 +65.02260484 +70.28506455 +63.60287947 +69.09110804 +73.49487582 +65.55446388 +70.31545407 +63.75548881 +69.69721742 +75.06170946 +73.11795217 +74.70058543 +72.61561338 +83.83773799 +76.00434048 +73.64673481 +76.79928969 +74.81472131 +81.39338682 +84.91333303 +76.63828235 +85.26187519 +80.56748632 +74.06867602 +82.55166409 +79.73366224 +81.91524615 +85.71758861 +78.57267141 +85.90032892 +83.50664 +79.33877274 +81.16164485 +77.11664696 +87.63227173 +82.57840547 +72.61430778 +77.13327935 +81.8746633 +72.81385085 +72.29528848 +79.10534737 +77.23025522 +78.9179624 +76.11164925 +74.61757143 +83.0063674 +80.21388191 +75.18441879 +77.0949236 +81.44937398 +73.13811221 +74.34140193 +73.1543684 +84.97667802 +84.01837848 +84.03283419 +83.45719936 +82.70619669 +79.62804832 +82.27250135 +72.61029941 +81.93949748 +84.44198988 +80.00189349 +77.71648268 +76.43515869 +82.28088313 +83.08083111 +85.93465662 +77.47660154 +84.31554748 +80.98091576 +86.12455705 +80.44422146 +80.28130655 +81.24525334 +83.98823939 +87.43420828 +73.17631117 +72.85425423 +87.00063836 +80.47785549 +81.8382911 +79.71862457 +73.49837812 +84.28926822 +83.95543313 +76.98710533 +76.89968028 +85.40529812 +73.15757566 +86.09751707 +76.10655781 +81.48772467 +86.97587347 +82.84992821 +78.63084681 +83.03251546 +77.50364442 +76.43610531 +87.94689868 +84.01261144 +82.31548803 +77.68460446 +29.11462372 +28.99875844 +32.34675382 +33.67700295 +32.23922063 +34.1810179 +29.01392424 +31.14720731 +30.31724468 +31.66254092 +29.2632033 +34.9064358 +21.16018304 +24.2919375 +22.06800012 +24.57514677 +22.64218032 +24.3301299 +20.18396236 +23.51210856 +24.2056656 +20.785947 +20.59064269 +22.06208407 +22.25634853 +20.6536151 +20.59246143 +19.01005235 +18.43523362 +21.75033355 +18.79070518 +21.02824861 +22.17826873 +19.286638 +21.15695728 +18.75434915 +20.51301262 +18.74527433 +21.0443445 +19.29710877 +19.94886109 +20.49563118 +18.77478205 +21.06719067 +19.30277201 +20.74860493 +18.72257119 +20.85208244 +18.53052452 +19.72033934 +19.00705356 +21.01365475 +19.06642622 +21.54753501 +21.58798542 +18.80379959 +20.47502094 +18.36848739 +19.58493189 +20.87330606 +20.64165542 +20.50273845 +19.13383644 +19.51584612 +18.41531964 +20.88009949 +20.01939817 +20.83906286 +18.99942129 +19.30145808 +19.34057402 +18.10644541 +19.36419149 +21.21321829 +21.58919398 +20.07287326 +19.82200678 +18.12329847 +21.51681735 +18.05204085 +21.77900032 +19.95686499 +19.36773797 +21.69687374 +18.09756397 +20.32569958 +20.1957301 +18.8772816 +19.71554973 +20.60905602 +20.90852479 +18.00286743 +21.74741372 +18.65810149 +18.93432174 +19.05389378 +18.15128055 +18.49220849 +21.94539969 +19.26086695 +18.46120436 +18.42796504 +20.87783987 +21.41827466 +19.0278092 +18.08363805 +18.89236007 +18.22606276 +18.41357975 +19.72603248 +18.91967348 +20.06378351 +19.01397501 +21.7621492 +21.62377587 +20.26722442 +19.41769597 +19.52458753 +19.64740913 +20.91031729 +19.80655598 +21.42691979 +21.77637914 +19.34378461 +20.24277793 +18.38022615 +18.80187619 +19.65386307 +18.82481086 +21.50624196 +18.63314502 +19.82264329 +20.42279696 +20.76745563 +19.53227748 +21.47639627 +20.2732766 +19.75803112 +18.26896254 +19.85875787 +21.28294336 +20.45816407 +21.32864981 +19.97604668 +18.47384682 +18.05455938 +19.21287819 +20.79196189 +21.16103962 +19.18301134 +19.98261568 +19.68447562 +19.64209114 +18.92539485 +18.54548442 +18.78675423 +18.22132955 +18.79252297 +18.03680359 +20.5090336 +19.26550163 +21.89257885 +18.7748682 +19.38331428 +19.43136463 +18.03380598 +21.35683181 +18.12797784 +21.76071934 +21.5682974 +20.14208766 +20.1743823 +20.61511169 +19.54820005 +20.58888913 +18.17907355 +18.21619051 +19.82892168 +20.1984892 +21.55127056 +62.62338462 +72.38801181 +64.05664379 +66.55953762 +65.50579311 +66.64211171 +63.24673877 +68.04855301 +72.10233922 +67.20486254 +67.87234463 +72.74323916 +80.79802194 +77.45185242 +73.83943646 +83.57406311 +78.79535663 +73.27221091 +74.01673856 +82.30462554 +70.52513912 +85.23727074 +71.86305807 +82.19498351 +77.84650664 +79.39620618 +85.57386678 +78.13493956 +80.11630066 +72.35206183 +71.60533422 +75.46129718 +82.39199351 +73.49659686 +73.37727019 +78.10391751 +82.26655415 +83.29308009 +74.76538453 +73.18548227 +86.94189692 +76.07925733 +85.55075971 +85.71288417 +84.25912903 +74.6116961 +85.04664476 +84.20683934 +81.52799643 +77.37665771 +76.18184964 +73.93247934 +80.1368756 +81.34464661 +77.73076399 +79.5866397 +77.79755542 +82.23635545 +86.39940649 +74.60481474 +78.09879204 +74.25033348 +81.99516437 +83.65791238 +86.90643201 +76.45828065 +87.19919353 +73.00869816 +81.6443027 +72.91062363 +86.29624459 +80.47308202 +82.7087796 +85.30436388 +74.40425567 +72.61676786 +86.06127214 +77.03819207 +74.06295152 +79.49461664 +81.57211411 +72.4948337 +76.39759711 +72.52410175 +78.72521507 +86.32143473 +87.72227016 +82.19260305 +74.5860599 +86.49342417 +80.25981107 +74.45984603 +86.74746016 +84.1193433 +83.70712365 +83.34673123 +75.20540826 +75.37607812 +83.0126561 +75.515535 +79.01871681 +84.51199676 +84.54320783 +79.25215793 +84.6750065 +85.41791594 +82.47638035 +75.65478459 +30.55366953 +30.81497748 +29.54754062 +30.54821571 +30.14091725 +31.71409791 +34.61399366 +29.46866837 +33.4097083 +33.19860485 +29.41282122 +34.70445673 +22.70675422 +21.78948914 +23.54929156 +21.31299608 +23.26692279 +20.33790509 +23.9205467 +22.16780418 +23.01238299 +21.15114427 +23.19328896 +23.61963514 +20.37028097 +20.96220923 +20.30111074 +22.09419798 +20.47127192 +21.88004821 +21.71433777 +20.11342751 +19.37442585 +20.09531217 +21.81618611 +19.36438263 +20.19421451 +21.326264 +19.50709662 +20.66756892 +19.07364238 +18.5256159 +21.27918903 +18.48417465 +19.17713606 +21.52325574 +19.47892931 +21.99726382 +21.93997951 +19.09141425 +18.18135024 +20.84024057 +19.82295779 +18.42067826 +20.85008815 +18.14209934 +21.50140831 +18.57242253 +18.52701638 +18.72064376 +21.84525892 +20.77666579 +21.20955759 +19.59430132 +19.3489652 +18.94157211 +19.92641725 +20.21119474 +20.53104058 +19.03212748 +21.79880089 +18.68262037