A lot
This commit is contained in:
@@ -6,6 +6,7 @@ import java.io.InputStreamReader;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
import com.flaremicro.util.Util;
|
import com.flaremicro.util.Util;
|
||||||
@@ -35,8 +36,11 @@ public class CanadaDatamartProvider extends ForecastProvider {
|
|||||||
BufferedReader bufferedReader = null;
|
BufferedReader bufferedReader = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HashSet<String> byCodes = new HashSet<String>(Arrays.asList(byCode.split(",")));
|
ArrayList<String> byCodesArray = new ArrayList<String>(Arrays.asList(byCode.split(",")));
|
||||||
HashSet<String> byNameAndProvinces = new HashSet<String>(Arrays.asList(byNameAndProvince.split(";")));
|
ArrayList<String> byNameAndProvincesArray = new ArrayList<String>(Arrays.asList(byNameAndProvince.split(";")));
|
||||||
|
|
||||||
|
HashSet<String> byCodes = new HashSet<String>(byCodesArray);
|
||||||
|
HashSet<String> byNameAndProvinces = new HashSet<String>(byNameAndProvincesArray);
|
||||||
URL url = new URL("https://dd.weather.gc.ca/citypage_weather/docs/site_list_towns_en.csv");
|
URL url = new URL("https://dd.weather.gc.ca/citypage_weather/docs/site_list_towns_en.csv");
|
||||||
bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
|
bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
|
||||||
String line;
|
String line;
|
||||||
@@ -51,12 +55,21 @@ public class CanadaDatamartProvider extends ForecastProvider {
|
|||||||
String[] data = line.trim().split(",");
|
String[] data = line.trim().split(",");
|
||||||
if (byCodes.contains(data[0].toLowerCase()) || byNameAndProvinces.contains(data[1].toLowerCase() + "," + data[2].toLowerCase()))
|
if (byCodes.contains(data[0].toLowerCase()) || byNameAndProvinces.contains(data[1].toLowerCase() + "," + data[2].toLowerCase()))
|
||||||
{
|
{
|
||||||
|
int priority = Integer.MAX_VALUE;
|
||||||
|
if(byCodes.contains(data[0].toLowerCase()))
|
||||||
|
{
|
||||||
|
priority = byCodesArray.indexOf(data[0]);
|
||||||
|
}
|
||||||
|
else if(byNameAndProvinces.contains(data[1].toLowerCase() + "," + data[2].toLowerCase()))
|
||||||
|
{
|
||||||
|
priority = byNameAndProvincesArray.indexOf(data[1].toLowerCase() + "," + data[2].toLowerCase());
|
||||||
|
}
|
||||||
String code = data[0].trim();
|
String code = data[0].trim();
|
||||||
String town = data[1].trim();
|
String town = data[1].trim();
|
||||||
String province = data[2].trim();
|
String province = data[2].trim();
|
||||||
float latitude = Float.parseFloat(data[3].trim().substring(0, data[3].length()-1));
|
float latitude = Float.parseFloat(data[3].trim().substring(0, data[3].length()-1));
|
||||||
float longitude = Float.parseFloat(data[4].trim().substring(0, data[4].length()-1));
|
float longitude = Float.parseFloat(data[4].trim().substring(0, data[4].length()-1));
|
||||||
towns.add(new TownInfo(code, town, province, latitude, longitude));
|
towns.add(new TownInfo(code, town, province, latitude, longitude, priority));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,8 +82,12 @@ public class CanadaDatamartProvider extends ForecastProvider {
|
|||||||
{
|
{
|
||||||
Util.cleanClose(bufferedReader);
|
Util.cleanClose(bufferedReader);
|
||||||
}
|
}
|
||||||
forecastProcessor = new ForecastProcessor(towns.toArray(new TownInfo[0]));
|
Collections.sort(towns);
|
||||||
|
forecastProcessor = new ForecastProcessor(towns.toArray(new TownInfo[0]), this);
|
||||||
forecastProcessor.processForecasts();
|
forecastProcessor.processForecasts();
|
||||||
|
this.getRenderPanel().notifyForecastProviderUpdate();
|
||||||
|
forecastProcessor.begin();
|
||||||
|
this.notifyForecastProviderUpdate();
|
||||||
ready = true;
|
ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +103,7 @@ public class CanadaDatamartProvider extends ForecastProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deinit() {
|
public void deinit() {
|
||||||
|
forecastProcessor.end();
|
||||||
propertyManager.store();
|
propertyManager.store();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,14 @@ package com.flaremicro.visualforecast.datamart;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.xml.XMLConstants;
|
import javax.xml.XMLConstants;
|
||||||
@@ -22,11 +27,13 @@ import org.xml.sax.SAXException;
|
|||||||
import com.flaremicro.util.Util;
|
import com.flaremicro.util.Util;
|
||||||
import com.flaremicro.visualforecast.forecast.DayForecast;
|
import com.flaremicro.visualforecast.forecast.DayForecast;
|
||||||
import com.flaremicro.visualforecast.forecast.ForecastDetails;
|
import com.flaremicro.visualforecast.forecast.ForecastDetails;
|
||||||
|
import com.flaremicro.visualforecast.forecast.HourlyForecast;
|
||||||
import com.flaremicro.visualforecast.forecast.TownForecast;
|
import com.flaremicro.visualforecast.forecast.TownForecast;
|
||||||
import com.flaremicro.visualforecast.forecast.ValueCheck;
|
import com.flaremicro.visualforecast.forecast.ValueCheck;
|
||||||
|
|
||||||
public class ForecastProcessor implements Runnable {
|
public class ForecastProcessor implements Runnable {
|
||||||
private final TownInfo[] towns;
|
private final TownInfo[] towns;
|
||||||
|
private final CanadaDatamartProvider cdp;
|
||||||
private ForecastDetails mostRecentForecast = null;
|
private ForecastDetails mostRecentForecast = null;
|
||||||
private boolean running = false;
|
private boolean running = false;
|
||||||
private Thread self;
|
private Thread self;
|
||||||
@@ -34,9 +41,9 @@ public class ForecastProcessor implements Runnable {
|
|||||||
|
|
||||||
private DatamartTranslation dmt = new DatamartTranslation();
|
private DatamartTranslation dmt = new DatamartTranslation();
|
||||||
|
|
||||||
public ForecastProcessor(TownInfo[] towns) {
|
public ForecastProcessor(TownInfo[] towns, CanadaDatamartProvider cdp) {
|
||||||
this.towns = towns;
|
this.towns = towns;
|
||||||
|
this.cdp = cdp;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||||
@@ -70,20 +77,74 @@ public class ForecastProcessor implements Runnable {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void processHourlyForecast(TownForecast forecast, Document doc) {
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmm");
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
|
NodeList hourlyForecast = doc.getElementsByTagName("hourlyForecast");
|
||||||
|
ArrayList<HourlyForecast> hourlyForecastArray = new ArrayList<HourlyForecast>(12);
|
||||||
|
for (int i = 0; i < hourlyForecast.getLength(); i++)
|
||||||
|
{
|
||||||
|
if (hourlyForecast.item(i).getNodeType() == Node.ELEMENT_NODE)
|
||||||
|
{
|
||||||
|
Element element = (Element) hourlyForecast.item(i);
|
||||||
|
byte iconCode = dmt.icon(XMLUtils.getIntFromTag(element, "iconCode", ValueCheck.NO_DATA_INT));
|
||||||
|
byte temp = XMLUtils.getByteFromTag(element, "temperature", ValueCheck.NO_DATA_BYTE);
|
||||||
|
byte windChill = XMLUtils.getByteFromTag(element, "windChill", ValueCheck.NO_DATA_BYTE);
|
||||||
|
float percip = XMLUtils.getFloatFromTag(element, "lop", ValueCheck.NO_DATA_FLOAT);
|
||||||
|
String dateTimeUTC = XMLUtils.getStringFromAttribute(element, "dateTimeUTC");
|
||||||
|
if (dateTimeUTC != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Date date = dateFormat.parse(dateTimeUTC);
|
||||||
|
hourlyForecastArray.add(new HourlyForecast(date, iconCode, temp, (short) 0, percip, windChill));
|
||||||
|
}
|
||||||
|
catch (ParseException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
forecast.setHourlyForecast(hourlyForecastArray.toArray(new HourlyForecast[0]));
|
||||||
|
}
|
||||||
|
|
||||||
public void processForecasts() {
|
public void processForecasts() {
|
||||||
|
System.out.println("Time to update");
|
||||||
ForecastDetails forecastDetails = new ForecastDetails();
|
ForecastDetails forecastDetails = new ForecastDetails();
|
||||||
ArrayList<TownForecast> townForecasts = new ArrayList<TownForecast>();
|
ArrayList<TownForecast> townForecasts = new ArrayList<TownForecast>();
|
||||||
for (TownInfo townInfo : towns)
|
for (TownInfo townInfo : towns)
|
||||||
{
|
{
|
||||||
DayForecast[] dayForecasts = new DayForecast[8];
|
DayForecast[] dayForecasts = new DayForecast[8];
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
|
Document doc = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
URL url = new URL("https://dd.weather.gc.ca/citypage_weather/xml/BC/" + townInfo.code + "_e.xml");
|
URL url = new URL("https://dd.weather.gc.ca/citypage_weather/xml/" + townInfo.province + "/" + townInfo.code + "_e.xml");
|
||||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||||
is = url.openStream();
|
is = url.openStream();
|
||||||
Document doc = db.parse(is);
|
doc = db.parse(is);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
catch (ParserConfigurationException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
catch (SAXException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Util.cleanClose(is);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc != null)
|
||||||
|
{
|
||||||
NodeList nodeList = doc.getElementsByTagName("forecast");
|
NodeList nodeList = doc.getElementsByTagName("forecast");
|
||||||
for (int i = 0; i < nodeList.getLength(); i++)
|
for (int i = 0; i < nodeList.getLength(); i++)
|
||||||
{
|
{
|
||||||
@@ -92,7 +153,8 @@ public class ForecastProcessor implements Runnable {
|
|||||||
Element node = (Element) nodeList.item(i);
|
Element node = (Element) nodeList.item(i);
|
||||||
int dayIndex = getDayIndex(XMLUtils.getStringFromTagAttribute(node, "period", "textForecastName"));
|
int dayIndex = getDayIndex(XMLUtils.getStringFromTagAttribute(node, "period", "textForecastName"));
|
||||||
Element abbForecast = XMLUtils.getFistElement(node, "abbreviatedForecast");
|
Element abbForecast = XMLUtils.getFistElement(node, "abbreviatedForecast");
|
||||||
int iconIndex = XMLUtils.getIntFromTag(abbForecast, "iconCode", 0);
|
int iconIndex = XMLUtils.getIntFromTag(abbForecast, "iconCode", ValueCheck.NO_DATA_INT);
|
||||||
|
float percip = XMLUtils.getFloatFromTag(abbForecast, "pop", ValueCheck.NO_DATA_FLOAT);
|
||||||
String textForecast = XMLUtils.getStringFromTag(abbForecast, "textSummary");
|
String textForecast = XMLUtils.getStringFromTag(abbForecast, "textSummary");
|
||||||
|
|
||||||
WeatherLines lines = dmt.weatherName(textForecast);
|
WeatherLines lines = dmt.weatherName(textForecast);
|
||||||
@@ -109,11 +171,11 @@ public class ForecastProcessor implements Runnable {
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte val = Byte.parseByte(n.getTextContent().trim());
|
byte val = Byte.parseByte(n.getTextContent().trim());
|
||||||
if(XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("high"))
|
if (XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("high"))
|
||||||
{
|
{
|
||||||
hi = val;
|
hi = val;
|
||||||
}
|
}
|
||||||
else if(XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("low"))
|
else if (XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("low"))
|
||||||
{
|
{
|
||||||
lo = val;
|
lo = val;
|
||||||
}
|
}
|
||||||
@@ -136,45 +198,49 @@ public class ForecastProcessor implements Runnable {
|
|||||||
{
|
{
|
||||||
dayForecasts[dayIndex].hiTemp = hi;
|
dayForecasts[dayIndex].hiTemp = hi;
|
||||||
}
|
}
|
||||||
|
if (!ValueCheck.valueNoData(percip))
|
||||||
|
{
|
||||||
|
if (ValueCheck.valueNoData(dayForecasts[dayIndex].percipPercent))
|
||||||
|
{
|
||||||
|
dayForecasts[dayIndex].percipPercent = percip;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dayForecasts[dayIndex].percipPercent = (dayForecasts[dayIndex].percipPercent + percip) - (percip * dayForecasts[dayIndex].percipPercent) / 100F;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dayForecasts[dayIndex] = new DayForecast(hi, lo, icon, lines.line1, lines.line2, ValueCheck.NO_DATA_FLOAT);
|
dayForecasts[dayIndex] = new DayForecast(hi, lo, icon, lines.line1, lines.line2, percip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (int i = 0; i < dayForecasts.length; i++)
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (ParserConfigurationException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
catch (SAXException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Util.cleanClose(is);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < dayForecasts.length; i++)
|
|
||||||
{
|
|
||||||
if (dayForecasts[i] == null)
|
|
||||||
{
|
{
|
||||||
dayForecasts[i] = new DayForecast();
|
if (dayForecasts[i] == null)
|
||||||
|
{
|
||||||
|
dayForecasts[i] = new DayForecast();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
TownForecast tf = new TownForecast(townInfo.townName + ", " + townInfo.province, dayForecasts);
|
||||||
|
townForecasts.add(tf);
|
||||||
|
this.processHourlyForecast(tf, doc);
|
||||||
}
|
}
|
||||||
townForecasts.add(new TownForecast(townInfo.townName + ", " + townInfo.province, dayForecasts));
|
|
||||||
}
|
}
|
||||||
forecastDetails.setTownForecast(townForecasts.toArray(new TownForecast[0]));
|
forecastDetails.setTownForecast(townForecasts.toArray(new TownForecast[0]));
|
||||||
setMostRecentForecast(forecastDetails);
|
setMostRecentForecast(forecastDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void begin() {
|
||||||
|
if (!running)
|
||||||
|
{
|
||||||
|
running = true;
|
||||||
|
new Thread(this).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void end() {
|
public void end() {
|
||||||
running = false;
|
running = false;
|
||||||
self.interrupt();
|
self.interrupt();
|
||||||
@@ -201,8 +267,14 @@ public class ForecastProcessor implements Runnable {
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Thread.sleep(TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS));
|
long hourInMillis = 60 * 60 * 1000;
|
||||||
|
long startDateInMillis = System.currentTimeMillis();
|
||||||
|
long millisSinceLastHourChange = startDateInMillis % hourInMillis;
|
||||||
|
long millisToNextHourChange = hourInMillis - millisSinceLastHourChange;
|
||||||
|
Thread.sleep(millisToNextHourChange);
|
||||||
processForecasts();
|
processForecasts();
|
||||||
|
this.cdp.notifyForecastProviderUpdate();
|
||||||
|
//Thread.sleep(TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS));
|
||||||
}
|
}
|
||||||
catch (InterruptedException e)
|
catch (InterruptedException e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
package com.flaremicro.visualforecast.datamart;
|
package com.flaremicro.visualforecast.datamart;
|
||||||
|
|
||||||
public class TownInfo {
|
public class TownInfo implements Comparable<TownInfo> {
|
||||||
public final String code;
|
public final String code;
|
||||||
public final String townName;
|
public final String townName;
|
||||||
public final String province;
|
public final String province;
|
||||||
public final float northLat;
|
public final float northLat;
|
||||||
public final float westLong;
|
public final float westLong;
|
||||||
|
public final int priority;
|
||||||
|
|
||||||
public TownInfo(String code, String townName, String province, float northLat, float westLong) {
|
public TownInfo(String code, String townName, String province, float northLat, float westLong, int priority) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.townName = townName;
|
this.townName = townName;
|
||||||
this.province = province;
|
this.province = province;
|
||||||
this.northLat = northLat;
|
this.northLat = northLat;
|
||||||
this.westLong = westLong;
|
this.westLong = westLong;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(TownInfo o) {
|
||||||
|
return priority - o.priority;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,15 @@ public class XMLUtils {
|
|||||||
if (l.getLength() > 0)
|
if (l.getLength() > 0)
|
||||||
{
|
{
|
||||||
Node attrib = l.item(0).getAttributes().getNamedItem(attribute);
|
Node attrib = l.item(0).getAttributes().getNamedItem(attribute);
|
||||||
if(attrib != null)
|
if (attrib != null)
|
||||||
return attrib.getTextContent();
|
return attrib.getTextContent();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static String getStringFromAttribute(Node n, String attribute) {
|
public static String getStringFromAttribute(Node n, String attribute) {
|
||||||
Node attrib = n.getAttributes().getNamedItem(attribute);
|
Node attrib = n.getAttributes().getNamedItem(attribute);
|
||||||
if(attrib != null)
|
if (attrib != null)
|
||||||
return attrib.getTextContent();
|
return attrib.getTextContent();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -41,8 +40,10 @@ public class XMLUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer getIntFromTag(Element abbForecast, String tag, Integer fallback) {
|
public static Integer getIntFromTag(Element parent, String tag, Integer fallback) {
|
||||||
String content = getStringFromTag(abbForecast, tag);
|
String content = getStringFromTag(parent, tag);
|
||||||
|
if(content == null || content.length() == 0)
|
||||||
|
return fallback;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Integer.parseInt(content);
|
return Integer.parseInt(content);
|
||||||
@@ -53,4 +54,34 @@ public class XMLUtils {
|
|||||||
}
|
}
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float getFloatFromTag(Element parent, String tag, float fallback) {
|
||||||
|
String content = getStringFromTag(parent, tag);
|
||||||
|
if(content == null || content.length() == 0)
|
||||||
|
return fallback;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Float.parseFloat(content);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte getByteFromTag(Element parent, String tag, Byte fallback) {
|
||||||
|
String content = getStringFromTag(parent, tag);
|
||||||
|
if(content == null || content.length() == 0)
|
||||||
|
return fallback;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Byte.parseByte(content);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
Flurries or rain showers,Flurries/,Showers
|
||||||
Mainly sunny,Mainly,Sunny
|
Mainly sunny,Mainly,Sunny
|
||||||
Mainly cloudy,Mainly, Cloudy
|
Mainly cloudy,Mainly,Cloudy
|
||||||
Sunny,Sunny,
|
Sunny,Sunny,
|
||||||
A few clouds,Few,Clouds
|
A few clouds,Few,Clouds
|
||||||
A mix of sun and cloud,Partly,Cloudy
|
A mix of sun and cloud,Partly,Cloudy
|
||||||
@@ -9,12 +10,15 @@ Cloudy with sunny periods,Sunny,Periods
|
|||||||
Increasing cloudiness,Increasing,Clouds
|
Increasing cloudiness,Increasing,Clouds
|
||||||
Clearing,Clearing,
|
Clearing,Clearing,
|
||||||
Clear,Sun,
|
Clear,Sun,
|
||||||
|
partly cloudy,Partly,Cloudy,
|
||||||
|
showers or drizzle,Showers/,Drizzle
|
||||||
Chance of showers,Chance,Showers
|
Chance of showers,Chance,Showers
|
||||||
A few showers,Few,Showers
|
A few showers,Few,Showers
|
||||||
Chance of drizzle or rain,Chance,Drizzle
|
Chance of drizzle or rain,Chance,Drizzle
|
||||||
A few flurries or rain showers,Flurries/,Showers
|
A few flurries or rain showers,Flurries/,Showers
|
||||||
Chance of flurries or rain showers,Flurries/,Showers
|
Chance of flurries or rain showers,Flurries/,Showers
|
||||||
Chance of rain showers or flurries,Flurries/,Showers
|
Chance of rain showers or flurries,Showers/Flurries
|
||||||
|
chance of rain showers or wet flurries,Showers/,Flurries
|
||||||
A few flurries,Flurries,
|
A few flurries,Flurries,
|
||||||
Chance of flurries,Chance,Flurries
|
Chance of flurries,Chance,Flurries
|
||||||
A few wet flurries,Wet,Flurries
|
A few wet flurries,Wet,Flurries
|
||||||
@@ -97,3 +101,4 @@ Chance of thunderstorms,Thunder,Storms
|
|||||||
Snow and blowing snow,Blowing,Snow
|
Snow and blowing snow,Blowing,Snow
|
||||||
Windy,Windy
|
Windy,Windy
|
||||||
Smoke,Smoke
|
Smoke,Smoke
|
||||||
|
rain showers or flurries,Showers/,Flurries
|
||||||
|
|||||||
|
Can't render this file because it has a wrong number of fields in line 13.
|
Reference in New Issue
Block a user