Revize ce0940b5
Přidáno uživatelem Roman Kalivoda před více než 3 roky(ů)
Server/ServerApp/Connection/XMLProtocolHandler/Request.cs | ||
---|---|---|
1 | 1 |
using System; |
2 |
using System.Collections.Generic; |
|
3 |
using System.Linq; |
|
4 |
using System.Text; |
|
5 |
using System.Threading.Tasks; |
|
6 | 2 |
using System.Xml.Serialization; |
7 | 3 |
|
8 | 4 |
namespace ServerApp.Connection.XMLProtocolHandler |
Server/ServerApp/Parser/Parsers/DataParser.cs | ||
---|---|---|
81 | 81 |
var jisFiles = downloader.GetData(pathJis, start, end); |
82 | 82 |
var loginFiles = downloader.GetData(pathLogIn, start, end); |
83 | 83 |
|
84 |
WeatherDataUsed = new List<string>(); |
|
85 |
ActivityDataUsed = new List<string>(); |
|
86 |
|
|
87 |
WeatherDataUsed.AddRange(weatherFiles); |
|
88 |
ActivityDataUsed.AddRange(jisFiles); |
|
89 |
ActivityDataUsed.AddRange(loginFiles); |
|
90 |
|
|
84 | 91 |
WeatherList = weatherParser.ParseWeatherData(weatherFiles, startTime, endTime, wholeDay, interval); |
85 | 92 |
jisList = jisParser.ParseJisData(jisFiles, startTime, endTime, wholeDay, interval); |
86 | 93 |
loginList = loginParser.ParseLogInData(loginFiles, startTime, endTime, wholeDay, interval); |
Server/ServerApp/Parser/Parsers/IDataParser.cs | ||
---|---|---|
21 | 21 |
List<ActivityInfo> attendanceList; |
22 | 22 |
public List<ActivityInfo> AttendanceList { get => attendanceList; internal set => attendanceList = value; } |
23 | 23 |
|
24 |
/// <summary> List of weather file names the parser was last used on </summary> |
|
25 |
List<String> weatherdataUsed; |
|
26 |
public List<string> WeatherDataUsed { get => weatherdataUsed; set => weatherdataUsed = value; } |
|
27 |
|
|
28 |
/// <summary> List of activity file names the parser was last used on </summary> |
|
29 |
List<String> activitydataUsed; |
|
30 |
public List<string> ActivityDataUsed { get => activitydataUsed; set => activitydataUsed = value; } |
|
31 |
|
|
32 |
|
|
24 | 33 |
/// <summary> |
25 | 34 |
/// Parse data |
26 | 35 |
/// </summary> |
Server/ServerApp/Predictor/FeatureExtractor.cs | ||
---|---|---|
13 | 13 |
/// <summary> |
14 | 14 |
/// A class responsible for preparation of features for classifiers. |
15 | 15 |
/// </summary> |
16 |
public class FeatureExtractor
|
|
16 |
class FeatureExtractor |
|
17 | 17 |
{ |
18 | 18 |
/// <summary> |
19 | 19 |
/// A DataParser instance used to access info objects. |
20 | 20 |
/// </summary> |
21 |
private readonly IDataParser dataParser;
|
|
21 |
private readonly IDataParser DataParser;
|
|
22 | 22 |
|
23 |
private Dictionary<string, int> buildingsToAreas; |
|
23 |
/// <summary> |
|
24 |
/// A configuration object of the <c>Predictor</c> package |
|
25 |
/// </summary> |
|
26 |
private PredictorConfiguration Configuration; |
|
24 | 27 |
|
25 | 28 |
/// <summary> |
26 | 29 |
/// Instantiates new FeatureExtractor class. |
27 | 30 |
/// </summary> |
28 | 31 |
/// <param name="dataParser">Data parser used to access training data.</param> |
29 |
public FeatureExtractor(IDataParser dataParser, Dictionary<string, int> buildingsToAreas)
|
|
32 |
public FeatureExtractor(IDataParser dataParser, PredictorConfiguration configuration)
|
|
30 | 33 |
{ |
31 |
this.dataParser = dataParser;
|
|
32 |
this.buildingsToAreas = buildingsToAreas;
|
|
34 |
this.DataParser = dataParser;
|
|
35 |
this.Configuration = configuration;
|
|
33 | 36 |
} |
34 | 37 |
|
35 | 38 |
/// <summary> |
... | ... | |
41 | 44 |
/// <param name="interval"></param> |
42 | 45 |
/// <param name="wholeDay"></param> |
43 | 46 |
/// <returns></returns> |
44 |
public List<ModelInput> PrepareTrainingInput(int area, DateTime startDate, DateTime endDate, int interval = 1, bool wholeDay = true)
|
|
47 |
public List<ModelInput> PrepareTrainingInput(int area) |
|
45 | 48 |
{ |
46 |
dataParser.Parse(startDate, endDate, interval, wholeDay); |
|
47 | 49 |
List<string> buildings = new List<string>(); |
48 | 50 |
|
49 | 51 |
// find all buildings in area |
50 |
foreach (KeyValuePair<string, int> kvp in buildingsToAreas)
|
|
52 |
foreach (KeyValuePair<string, int> kvp in Configuration.BuildingsToAreas)
|
|
51 | 53 |
{ |
52 | 54 |
if (kvp.Value == area) |
53 | 55 |
{ |
... | ... | |
56 | 58 |
} |
57 | 59 |
|
58 | 60 |
var res = new List<ModelInput>(); |
59 |
foreach (WeatherInfo val in dataParser.WeatherList)
|
|
61 |
foreach (WeatherInfo val in DataParser.WeatherList)
|
|
60 | 62 |
{ |
61 | 63 |
res.Add(new ModelInput |
62 | 64 |
{ |
63 |
Temp = (float)val.temp, |
|
64 | 65 |
Time = val.startTime, |
66 |
Temp = (float)val.temp, |
|
67 |
Hour = val.startTime.Hour, |
|
65 | 68 |
Wind = (float)val.wind, |
66 | 69 |
Rain = (float)val.rain, |
67 | 70 |
}); |
68 | 71 |
} |
69 | 72 |
|
70 |
List<ActivityInfo> attendance = dataParser.AttendanceList;
|
|
73 |
List<ActivityInfo> attendance = DataParser.AttendanceList;
|
|
71 | 74 |
foreach (ModelInput input in res) |
72 | 75 |
{ |
73 | 76 |
List<int> amounts = new List<int>(); |
... | ... | |
90 | 93 |
if (ratio < 0.1f) |
91 | 94 |
{ |
92 | 95 |
return "10%"; |
93 |
} else if (ratio < 0.2f) |
|
96 |
} |
|
97 |
else if (ratio < 0.2f) |
|
94 | 98 |
{ |
95 | 99 |
return "20%"; |
96 |
} else if (ratio < 0.3f) |
|
100 |
} |
|
101 |
else if (ratio < 0.3f) |
|
97 | 102 |
{ |
98 | 103 |
return "30%"; |
99 |
} else if (ratio < 0.4f) |
|
104 |
} |
|
105 |
else if (ratio < 0.4f) |
|
100 | 106 |
{ |
101 | 107 |
return "40%"; |
102 |
} else if (ratio < 0.5f) |
|
108 |
} |
|
109 |
else if (ratio < 0.5f) |
|
103 | 110 |
{ |
104 | 111 |
return "50%"; |
105 |
} else if (ratio < 0.6f) |
|
112 |
} |
|
113 |
else if (ratio < 0.6f) |
|
106 | 114 |
{ |
107 | 115 |
return "60%"; |
108 |
} else if(ratio < 0.7f) { |
|
116 |
} |
|
117 |
else if (ratio < 0.7f) |
|
118 |
{ |
|
109 | 119 |
return "70%"; |
110 |
} else if (ratio < 0.8f) |
|
120 |
} |
|
121 |
else if (ratio < 0.8f) |
|
111 | 122 |
{ |
112 | 123 |
return "80%"; |
113 |
} else if (ratio < 0.9f) |
|
124 |
} |
|
125 |
else if (ratio < 0.9f) |
|
114 | 126 |
{ |
115 | 127 |
return "90%"; |
116 |
} else |
|
128 |
} |
|
129 |
else |
|
117 | 130 |
{ |
118 | 131 |
return "100%"; |
119 | 132 |
} |
120 | 133 |
} |
121 | 134 |
|
122 |
private double LabelToRatio(string label)
|
|
135 |
internal double LabelToRatio(string label)
|
|
123 | 136 |
{ |
124 |
if (label.Equals("10%")) { |
|
137 |
if (label.Equals("10%")) |
|
138 |
{ |
|
125 | 139 |
return 0.1f; |
126 | 140 |
} |
127 |
else if (label.Equals("20%")) { |
|
141 |
else if (label.Equals("20%")) |
|
142 |
{ |
|
128 | 143 |
return 0.2f; |
129 | 144 |
} |
130 |
else if (label.Equals("30%")) { |
|
145 |
else if (label.Equals("30%")) |
|
146 |
{ |
|
131 | 147 |
return 0.3f; |
132 | 148 |
} |
133 |
else if (label.Equals("40%")) { |
|
149 |
else if (label.Equals("40%")) |
|
150 |
{ |
|
134 | 151 |
return 0.4f; |
135 | 152 |
} |
136 |
else if (label.Equals("50%")) { |
|
153 |
else if (label.Equals("50%")) |
|
154 |
{ |
|
137 | 155 |
return 0.5f; |
138 | 156 |
} |
139 |
else if (label.Equals("60%")) { |
|
157 |
else if (label.Equals("60%")) |
|
158 |
{ |
|
140 | 159 |
return 0.6f; |
141 | 160 |
} |
142 |
else if (label.Equals("70%")) { |
|
161 |
else if (label.Equals("70%")) |
|
162 |
{ |
|
143 | 163 |
return 0.7f; |
144 | 164 |
} |
145 |
else if (label.Equals("80%")) { |
|
165 |
else if (label.Equals("80%")) |
|
166 |
{ |
|
146 | 167 |
return 0.8f; |
147 | 168 |
} |
148 |
else if (label.Equals("90%")) { |
|
169 |
else if (label.Equals("90%")) |
|
170 |
{ |
|
149 | 171 |
return 0.9f; |
150 | 172 |
} |
151 | 173 |
else |
Server/ServerApp/Predictor/IPredictionController.cs | ||
---|---|---|
2 | 2 |
// Author: Roman Kalivoda |
3 | 3 |
// |
4 | 4 |
|
5 |
using System; |
|
6 | 5 |
using System.Collections.Generic; |
7 |
using System.IO; |
|
8 |
using Microsoft.ML; |
|
9 | 6 |
using ServerApp.Connection.XMLProtocolHandler; |
10 |
using ServerApp.Parser.OutputInfo; |
|
11 | 7 |
|
12 | 8 |
namespace ServerApp.Predictor |
13 | 9 |
{ |
... | ... | |
32 | 28 |
/// </summary> |
33 | 29 |
/// <param name="locationKey">A string identifier of the location for which to load a predictor.</param> |
34 | 30 |
/// <param name="path">A path to folder with trained prediction model.</param> |
35 |
void Load(string locationKey = null,string path = null); |
|
31 |
void Load(string locationKey = null, string path = null);
|
|
36 | 32 |
|
37 | 33 |
/// <summary> |
38 | 34 |
/// Predicts turnout level at given time supposing given weather conditions. |
Server/ServerApp/Predictor/ModelInput.cs | ||
---|---|---|
13 | 13 |
/// </summary> |
14 | 14 |
public class ModelInput |
15 | 15 |
{ |
16 |
/// <summary> |
|
17 |
/// Start time of the information. |
|
18 |
/// </summary> |
|
19 |
public DateTime Time { get; set; } |
|
20 |
|
|
16 | 21 |
/// <summary> |
17 | 22 |
/// A label of this training input. |
18 | 23 |
/// </summary> |
... | ... | |
26 | 31 |
public float Temp { get; set; } |
27 | 32 |
|
28 | 33 |
/// <summary> |
29 |
/// Time of the predicted turnout.
|
|
34 |
/// Hour of the predicted turnout.
|
|
30 | 35 |
/// </summary> |
31 |
[ColumnName("Time"), LoadColumn(2)]
|
|
32 |
public DateTime Time { get; set; }
|
|
36 |
[ColumnName("Hour"), LoadColumn(2)]
|
|
37 |
public int Hour { get; set; }
|
|
33 | 38 |
|
34 | 39 |
/// <summary> |
35 |
/// Wind velocity in ? units
|
|
40 |
/// Wind velocity in m/s
|
|
36 | 41 |
/// </summary> |
37 | 42 |
[ColumnName("Wind"), LoadColumn(3)] |
38 | 43 |
public float Wind { get; set; } |
39 | 44 |
|
40 | 45 |
/// <summary> |
41 |
/// Precipitation |
|
46 |
/// Precipitation in %
|
|
42 | 47 |
/// </summary> |
43 | 48 |
[ColumnName("Rain"), LoadColumn(4)] |
44 | 49 |
public float Rain { get; set; } |
Server/ServerApp/Predictor/ModelOutput.cs | ||
---|---|---|
2 | 2 |
// Author: Roman Kalivoda |
3 | 3 |
// |
4 | 4 |
|
5 |
using System; |
|
6 | 5 |
using Microsoft.ML.Data; |
7 | 6 |
|
8 | 7 |
namespace ServerApp.Predictor |
... | ... | |
16 | 15 |
/// A predicted class. |
17 | 16 |
/// </summary> |
18 | 17 |
[ColumnName("PredictedLabel")] |
19 |
public String Prediction { get; set; }
|
|
18 |
public string PredictedLabel { get; set; }
|
|
20 | 19 |
|
21 | 20 |
} |
22 | 21 |
} |
Server/ServerApp/Predictor/NaiveBayesClassifier.cs | ||
---|---|---|
44 | 44 |
{ |
45 | 45 |
this._trainingDataView = _mlContext.Data.LoadFromEnumerable(trainInput); |
46 | 46 |
var pipeline = _mlContext.Transforms.Conversion.MapValueToKey(nameof(ModelInput.Label)) |
47 |
.Append(_mlContext.Transforms.Concatenate("Features", new[] { "Temp" })) |
|
48 |
.Append(_mlContext.Transforms.NormalizeMinMax("Features", "Features")) |
|
47 |
.Append(_mlContext.Transforms.Conversion.ConvertType(nameof(ModelInput.Hour))) |
|
48 |
.Append(_mlContext.Transforms.Concatenate("Features", |
|
49 |
new[] { nameof(ModelInput.Temp), nameof(ModelInput.Rain), nameof(ModelInput.Wind), nameof(ModelInput.Hour) })) |
|
50 |
.Append(_mlContext.Transforms.NormalizeMeanVariance("Features", useCdf:false)) |
|
49 | 51 |
.AppendCacheCheckpoint(_mlContext) |
50 | 52 |
.Append(_mlContext.MulticlassClassification.Trainers.NaiveBayes()) |
51 |
.Append(_mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel")); ;
|
|
53 |
.Append(_mlContext.Transforms.Conversion.MapKeyToValue(nameof(ModelOutput.PredictedLabel)));
|
|
52 | 54 |
|
53 | 55 |
var cvResults = _mlContext.MulticlassClassification.CrossValidate(this._trainingDataView, pipeline); |
54 | 56 |
_log.Debug("Cross-validated the trained model"); |
... | ... | |
67 | 69 |
public void Evaluate(IEnumerable<ModelInput> modelInputs) |
68 | 70 |
{ |
69 | 71 |
var testDataView = this._mlContext.Data.LoadFromEnumerable(modelInputs); |
70 |
var testMetrics = _mlContext.MulticlassClassification.Evaluate(_trainedModel.Transform(testDataView)); |
|
72 |
var data = _trainedModel.Transform(testDataView); |
|
73 |
var testMetrics = _mlContext.MulticlassClassification.Evaluate(data); |
|
71 | 74 |
|
72 | 75 |
Console.WriteLine($"*************************************************************************************************************"); |
73 | 76 |
Console.WriteLine($"* Metrics for Multi-class Classification model - Test Data "); |
... | ... | |
76 | 79 |
Console.WriteLine($"* MacroAccuracy: {testMetrics.MacroAccuracy:0.###}"); |
77 | 80 |
Console.WriteLine($"* LogLoss: {testMetrics.LogLoss:#.###}"); |
78 | 81 |
Console.WriteLine($"* LogLossReduction: {testMetrics.LogLossReduction:#.###}"); |
82 |
Console.WriteLine($"* Confusion Matrix: {testMetrics.ConfusionMatrix.GetFormattedConfusionTable()}"); |
|
79 | 83 |
Console.WriteLine($"*************************************************************************************************************"); |
80 | 84 |
} |
81 | 85 |
} |
Server/ServerApp/Predictor/PredictionController.cs | ||
---|---|---|
4 | 4 |
|
5 | 5 |
using System; |
6 | 6 |
using System.Collections.Generic; |
7 |
using System.IO; |
|
8 |
using Microsoft.ML; |
|
9 | 7 |
using ServerApp.Connection.XMLProtocolHandler; |
8 |
using ServerApp.Parser.Parsers; |
|
9 |
using Newtonsoft.Json; |
|
10 |
using ServerApp.WeatherPredictionParser; |
|
10 | 11 |
using ServerApp.Parser.OutputInfo; |
11 | 12 |
using System.Reflection; |
12 | 13 |
using log4net; |
... | ... | |
16 | 17 |
/// <summary> |
17 | 18 |
/// Implentation of the <c>IPredicitionController</c> interface. |
18 | 19 |
/// </summary> |
19 |
class PredictionController : IPredictionController |
|
20 |
public class PredictionController : IPredictionController
|
|
20 | 21 |
{ |
21 | 22 |
private static readonly ILog _log = LogManager.GetLogger(typeof(PredictionController)); |
22 | 23 |
|
23 | 24 |
/// <summary> |
24 |
/// A dictionary for storing trained predictors.
|
|
25 |
/// Configuration of the <c>Predictor</c>
|
|
25 | 26 |
/// </summary> |
26 |
private Dictionary<string, int> buildingsToAreas;
|
|
27 |
private PredictorConfiguration Configuration;
|
|
27 | 28 |
|
28 |
private List<IPredictor> predictors;
|
|
29 |
private List<IPredictor> Predictors;
|
|
29 | 30 |
|
30 | 31 |
/// <summary> |
31 | 32 |
/// A reference to a data parser. |
32 | 33 |
/// </summary> |
33 |
private IDataParser dataParser;
|
|
34 |
private IDataParser DataParser;
|
|
34 | 35 |
|
35 | 36 |
/// <summary> |
36 | 37 |
/// A feature extractor instance. |
37 | 38 |
/// </summary> |
38 |
private FeatureExtractor featureExtractor; |
|
39 |
private FeatureExtractor FeatureExtractor; |
|
40 |
|
|
41 |
/// <summary> |
|
42 |
/// A weather prediction parser service |
|
43 |
/// </summary> |
|
44 |
private IJsonParser weatherService; |
|
39 | 45 |
|
40 | 46 |
/// <summary> |
41 | 47 |
/// Instantiates new prediction controller. |
42 | 48 |
/// </summary> |
43 | 49 |
/// <param name="dataParser">A data parser used to get training data.</param> |
44 |
public PredictionController(IDataParser dataParser)
|
|
50 |
public PredictionController(IJsonParser weatherService, IDataParser dataParser, string pathToConfig = null)
|
|
45 | 51 |
{ |
46 | 52 |
_log.Info("Constructing a new PredictionController instance."); |
47 | 53 |
this.weatherService = weatherService; |
... | ... | |
68 | 74 |
|
69 | 75 |
for (int i = 0; i < this.Configuration.PredictorCount; i++) |
70 | 76 |
{ |
71 |
buildingsToAreas.Add(key, 0);
|
|
77 |
Predictors.Add(new NaiveBayesClassifier());
|
|
72 | 78 |
} |
73 |
IPredictor predictor = new NaiveBayesClassifier(); |
|
74 |
predictors.Add(predictor); |
|
79 |
PredictorConfiguration.SaveConfig(PredictorConfiguration.DEFAULT_CONFIG_PATH, Configuration); |
|
75 | 80 |
} |
76 | 81 |
public List<string> GetPredictors() |
77 | 82 |
{ |
78 |
return new List<string>(buildingsToAreas.Keys);
|
|
83 |
return new List<string>(this.Configuration.BuildingsToAreas.Keys);
|
|
79 | 84 |
} |
80 | 85 |
|
81 | 86 |
public void Load(string locationKey = null, string path = null) |
... | ... | |
180 | 185 |
if (locationKey is null) |
181 | 186 |
// train all predictors |
182 | 187 |
{ |
183 |
// TODO A single predictor is used for all areas, so training is done only once now.
|
|
184 |
for (int i = 0; i < this.predictors.Count; i++)
|
|
188 |
DataParser.Parse(DateTime.MinValue, DateTime.MaxValue, this.Configuration.TimeResolution, wholeDay: false);
|
|
189 |
for (int i = 0; i < this.Predictors.Count; i++)
|
|
185 | 190 |
{ |
186 | 191 |
// train on all available data |
187 |
// TODO the train/test split is used just temporarily for demonstration. |
|
188 |
List<ModelInput> data = featureExtractor.PrepareTrainingInput(i, DateTime.MinValue, DateTime.MaxValue); |
|
189 |
List<ModelInput> trainingData = data.GetRange(index: 0, count: 500); |
|
190 |
List<ModelInput> testData = data.GetRange(index: 500, count: 94); |
|
191 |
Console.WriteLine("Training predictor with {0} samples.", trainingData.Count); |
|
192 |
this.predictors[i].Fit(trainingData); |
|
193 |
|
|
194 |
Console.WriteLine("Evaluating predictor with {0} samples.", testData.Count); |
|
195 |
this.predictors[i].Evaluate(testData); |
|
192 |
List<ModelInput> data = FeatureExtractor.PrepareTrainingInput(i); |
|
193 |
Console.WriteLine("Training predictor with {0} samples.", data.Count); |
|
194 |
this.Predictors[i].Fit(data); |
|
196 | 195 |
} |
197 |
} else |
|
196 |
} |
|
197 |
else |
|
198 | 198 |
// train specified predictor only |
199 | 199 |
{ |
200 | 200 |
throw new NotImplementedException(); |
Server/ServerApp/WeatherPredictionParser/IJsonParser.cs | ||
---|---|---|
3 | 3 |
// |
4 | 4 |
|
5 | 5 |
using ServerApp.Parser.OutputInfo; |
6 |
using System; |
|
6 | 7 |
using System.Collections.Generic; |
7 | 8 |
|
8 | 9 |
namespace ServerApp.WeatherPredictionParser |
... | ... | |
10 | 11 |
/// <summary> |
11 | 12 |
/// Abstract class that every Json parser should inherit from |
12 | 13 |
/// </summary> |
13 |
abstract class IJsonParser |
|
14 |
public abstract class IJsonParser
|
|
14 | 15 |
{ |
15 | 16 |
|
16 | 17 |
/// <summary> Current weather </summary> |
17 | 18 |
WeatherInfo current; |
18 |
public WeatherInfo Current { get => current; } |
|
19 |
public WeatherInfo Current { get => current; set => current = value; }
|
|
19 | 20 |
|
20 | 21 |
/// <summary> Prediction for today, tommorrow and day after tommorrow </summary> |
21 | 22 |
List<WeatherInfo> predictions; |
... | ... | |
27 | 28 |
/// </summary> |
28 | 29 |
abstract public void ParsePrediction(); |
29 | 30 |
|
31 |
/// <summary> |
|
32 |
/// Get predictions from Predictions that are within specified time span |
|
33 |
/// </summary> |
|
34 |
/// <param name="from">DateTime from</param> |
|
35 |
/// <param name="to">DateTime to</param> |
|
36 |
/// <returns>List of predictions that fit specified criteria</returns> |
|
37 |
abstract public List<WeatherInfo> GetPredictionForTime(DateTime from, DateTime to); |
|
38 |
|
|
30 | 39 |
} |
31 | 40 |
|
32 | 41 |
} |
Server/ServerApp/WeatherPredictionParser/JsonParser.cs | ||
---|---|---|
119 | 119 |
|
120 | 120 |
DateTime now = DateTime.Now; |
121 | 121 |
|
122 |
current = new WeatherInfo();
|
|
123 |
predictions = new List<WeatherInfo>();
|
|
122 |
Current = new WeatherInfo();
|
|
123 |
Predictions = new List<WeatherInfo>();
|
|
124 | 124 |
|
125 | 125 |
// parse |
126 | 126 |
JsonDocument doc = JsonDocument.Parse(data); |
... | ... | |
138 | 138 |
case "current_condition": |
139 | 139 |
{ |
140 | 140 |
ArrayEnumerator currentWeather = weatherP.Current.Value.EnumerateArray(); |
141 |
current = ParseCurrentWeather(currentWeather);
|
|
141 |
Current = ParseCurrentWeather(currentWeather);
|
|
142 | 142 |
|
143 | 143 |
break; |
144 | 144 |
} |
... | ... | |
164 | 164 |
/// </summary> |
165 | 165 |
private void TestConsoleOutput() |
166 | 166 |
{ |
167 |
Console.WriteLine(current);
|
|
168 |
foreach (WeatherInfo w in predictions)
|
|
167 |
Console.WriteLine(Current);
|
|
168 |
foreach (WeatherInfo w in Predictions)
|
|
169 | 169 |
Console.WriteLine(w); |
170 | 170 |
} |
171 | 171 |
|
... | ... | |
477 | 477 |
return res; |
478 | 478 |
} |
479 | 479 |
|
480 |
|
|
480 | 481 |
} |
481 | 482 |
} |
Také k dispozici: Unified diff
Re #9034 fixing files corrupted by merge