Initial Commit

This commit is contained in:
Flare Microsystems
2024-03-07 14:15:34 -08:00
commit 37c506249a
12 changed files with 669 additions and 0 deletions

7
.classpath Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="src" path="/VisualForecast 1000"/>
<classpathentry kind="output" path="bin"/>
</classpath>

26
.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
#Compiled binary directory
bin/
# Package Files #
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*.dat

13
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,13 @@
# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Container Scanning customization: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
stages:
- test
sast:
stage: test
include:
- template: Security/SAST.gitlab-ci.yml

17
.project Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>CanadaDatamartProvider</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

View File

@@ -0,0 +1,92 @@
package com.flaremicro.visualforecast.datamart;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import com.flaremicro.util.Util;
import com.flaremicro.visualforecast.PropertyManager;
import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.forecast.ForecastDetails;
public class CanadaDatamartProvider extends ForecastProvider {
boolean ready = false;
PropertyManager propertyManager;
ForecastProcessor forecastProcessor;
ArrayList<TownInfo> towns = new ArrayList<TownInfo>();
@Override
public void init() {
propertyManager = super.getOwnPropertyManager();
String byCode = propertyManager.getString("towns-by-code", "").toLowerCase();
String byNameAndProvince = propertyManager.getString("towns-by-name-and-province", "").toLowerCase();
if(byCode.isEmpty() && byNameAndProvince.isEmpty())
{
ready = true;
return;
}
BufferedReader bufferedReader = null;
try
{
HashSet<String> byCodes = new HashSet<String>(Arrays.asList(byCode.split(",")));
HashSet<String> byNameAndProvinces = new HashSet<String>(Arrays.asList(byNameAndProvince.split(";")));
URL url = new URL("https://dd.weather.gc.ca/citypage_weather/docs/site_list_towns_en.csv");
bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
String line;
int skip = 2;
while ((line = bufferedReader.readLine()) != null)
{
if (skip > 0)
{
skip--;
continue;
}
String[] data = line.trim().split(",");
if (byCodes.contains(data[0].toLowerCase()) || byNameAndProvinces.contains(data[1].toLowerCase() + "," + data[2].toLowerCase()))
{
String code = data[0].trim();
String town = data[1].trim();
String province = data[2].trim();
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));
towns.add(new TownInfo(code, town, province, latitude, longitude));
}
}
}
catch (IOException e)
{
e.printStackTrace();
ready = true;
}
finally
{
Util.cleanClose(bufferedReader);
}
forecastProcessor = new ForecastProcessor(towns.toArray(new TownInfo[0]));
forecastProcessor.processForecasts();
ready = true;
}
@Override
public ForecastDetails getForecast() {
return forecastProcessor.getMostRecentForecast();
}
@Override
public boolean isForecastReady() {
return ready;
}
@Override
public void deinit() {
propertyManager.store();
}
}

View File

@@ -0,0 +1,117 @@
package com.flaremicro.visualforecast.datamart;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import com.flaremicro.util.Util;
import com.flaremicro.visualforecast.icons.IconProvider;
public class DatamartTranslation {
private HashMap<Integer, Byte> iconTranslation = new HashMap<Integer, Byte>();
private HashMap<String, WeatherLines> stringTranslation = new HashMap<String, WeatherLines>();
public DatamartTranslation() {
iconTranslation.put(0, IconProvider.SUN.id);
iconTranslation.put(1, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(2, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(3, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(4, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(5, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(6, IconProvider.SCATTERD_SHOWERS.id);
iconTranslation.put(7, IconProvider.RAIN_SNOW.id);
iconTranslation.put(8, IconProvider.SNOW.id);
iconTranslation.put(9, IconProvider.RAIN_STORM.id);
iconTranslation.put(10, IconProvider.CLOUD.id);
iconTranslation.put(11, IconProvider.INVALID.id);
iconTranslation.put(12, IconProvider.RAIN_LIGHT.id);
iconTranslation.put(13, IconProvider.RAIN_HEAVY.id);
iconTranslation.put(14, IconProvider.FREEZING_RAIN.id);
iconTranslation.put(15, IconProvider.SCATTERD_SHOWERS.id);
iconTranslation.put(16, IconProvider.SNOW.id);
iconTranslation.put(17, IconProvider.SNOW.id);
iconTranslation.put(18, IconProvider.BLIZZARD.id);
iconTranslation.put(19, IconProvider.RAIN_STORM.id);
iconTranslation.put(20, IconProvider.INVALID.id);
iconTranslation.put(21, IconProvider.INVALID.id);
iconTranslation.put(22, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(23, IconProvider.FOG.id);
iconTranslation.put(24, IconProvider.FOG.id);
iconTranslation.put(25, IconProvider.INVALID.id);
iconTranslation.put(26, IconProvider.INVALID.id);
iconTranslation.put(27, IconProvider.HAIL.id);
iconTranslation.put(28, IconProvider.RAIN_LIGHTEST.id);
iconTranslation.put(29, IconProvider.INVALID.id);
iconTranslation.put(30, IconProvider.SUN.id); //MOON
iconTranslation.put(31, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(32, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(33, IconProvider.CLOUD.id);
iconTranslation.put(34, IconProvider.CLOUDY_CLOUDY.id);
iconTranslation.put(35, IconProvider.PARTLY_CLOUDY.id);
iconTranslation.put(36, IconProvider.SCATTERD_SHOWERS.id);
iconTranslation.put(37, IconProvider.RAIN_LIGHT.id);
iconTranslation.put(38, IconProvider.SNOW.id);
iconTranslation.put(39, IconProvider.LIGHTNING_STORM.id);
iconTranslation.put(40, IconProvider.SNOW.id);
iconTranslation.put(41, IconProvider.INVALID.id);
iconTranslation.put(42, IconProvider.INVALID.id);
iconTranslation.put(43, IconProvider.INVALID.id); //WIND
iconTranslation.put(44, IconProvider.INVALID.id); //SMOKE
BufferedReader reader = null;
try
{
reader = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream("/translation.csv")));
String line;
while((line = reader.readLine()) != null)
{
String[] info = line.split(",");
if(info.length == 2)
{
stringTranslation.put(info[0].toLowerCase(), new WeatherLines(info[1], ""));
}
else if(info.length == 3)
{
stringTranslation.put(info[0].toLowerCase(), new WeatherLines(info[1], info[2]));
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
Util.cleanClose(reader);
}
}
public byte icon(int icon) {
if(!iconTranslation.containsKey(icon))
return IconProvider.INVALID.id;
return iconTranslation.get(icon);
}
public WeatherLines weatherName(String desc) {
WeatherLines lines = stringTranslation.get(desc.toLowerCase());
if(lines == null)
{
System.out.println("FAILED:"+desc.toLowerCase());
return new WeatherLines("TRANSLAT.", "FAILURE");
}
else return lines;
}
}
class WeatherLines {
public final String line1;
public final String line2;
public WeatherLines(String line1, String line2) {
this.line1 = line1;
this.line2 = line2;
}
}

View File

@@ -0,0 +1,213 @@
package com.flaremicro.visualforecast.datamart;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.flaremicro.util.Util;
import com.flaremicro.visualforecast.forecast.DayForecast;
import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.forecast.TownForecast;
import com.flaremicro.visualforecast.forecast.ValueCheck;
public class ForecastProcessor implements Runnable {
private final TownInfo[] towns;
private ForecastDetails mostRecentForecast = null;
private boolean running = false;
private Thread self;
private DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
private DatamartTranslation dmt = new DatamartTranslation();
public ForecastProcessor(TownInfo[] towns) {
this.towns = towns;
try
{
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
}
}
public void stringToOffset(String dayString) {
}
public int getDayIndex(String dayString) {
dayString = dayString.trim();
if (dayString.equalsIgnoreCase("today") || dayString.equalsIgnoreCase("tonight"))
return 0;
dayString = dayString.toLowerCase().replace("night", "").trim();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
for (int i = 1; i < 8; i++)
{
calendar.add(Calendar.HOUR, 24);
if (calendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US).equalsIgnoreCase(dayString))
return i;
}
return -1;
}
public void processForecasts() {
ForecastDetails forecastDetails = new ForecastDetails();
ArrayList<TownForecast> townForecasts = new ArrayList<TownForecast>();
for (TownInfo townInfo : towns)
{
DayForecast[] dayForecasts = new DayForecast[8];
InputStream is = null;
try
{
URL url = new URL("https://dd.weather.gc.ca/citypage_weather/xml/BC/" + townInfo.code + "_e.xml");
DocumentBuilder db = dbf.newDocumentBuilder();
is = url.openStream();
Document doc = db.parse(is);
NodeList nodeList = doc.getElementsByTagName("forecast");
for (int i = 0; i < nodeList.getLength(); i++)
{
if (nodeList.item(1).getNodeType() == Node.ELEMENT_NODE)
{
Element node = (Element) nodeList.item(i);
int dayIndex = getDayIndex(XMLUtils.getStringFromTagAttribute(node, "period", "textForecastName"));
Element abbForecast = XMLUtils.getFistElement(node, "abbreviatedForecast");
int iconIndex = XMLUtils.getIntFromTag(abbForecast, "iconCode", 0);
String textForecast = XMLUtils.getStringFromTag(abbForecast, "textSummary");
WeatherLines lines = dmt.weatherName(textForecast);
byte icon = dmt.icon(iconIndex);
byte lo = ValueCheck.NO_DATA_BYTE;
byte hi = ValueCheck.NO_DATA_BYTE;
Element element = XMLUtils.getFistElement(node, "temperatures");
NodeList temps = element.getElementsByTagName("temperature");
for (int j = 0; j < temps.getLength(); j++)
{
Node n = temps.item(j);
try
{
byte val = Byte.parseByte(n.getTextContent().trim());
if(XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("high"))
{
hi = val;
}
else if(XMLUtils.getStringFromAttribute(n, "class").trim().equalsIgnoreCase("low"))
{
lo = val;
}
}
catch (NumberFormatException ex)
{
}
}
if (dayIndex >= 0 && dayIndex <= 7)
{
if (dayForecasts[dayIndex] != null)
{
if (lo != ValueCheck.NO_DATA_BYTE && dayForecasts[dayIndex].loTemp == ValueCheck.NO_DATA_BYTE)
{
dayForecasts[dayIndex].loTemp = lo;
}
if (hi != ValueCheck.NO_DATA_BYTE && dayForecasts[dayIndex].hiTemp == ValueCheck.NO_DATA_BYTE)
{
dayForecasts[dayIndex].hiTemp = hi;
}
}
else
{
dayForecasts[dayIndex] = new DayForecast(hi, lo, icon, lines.line1, lines.line2, ValueCheck.NO_DATA_FLOAT);
}
}
}
}
}
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();
}
}
townForecasts.add(new TownForecast(townInfo.townName + ", " + townInfo.province, dayForecasts));
}
forecastDetails.setTownForecast(townForecasts.toArray(new TownForecast[0]));
setMostRecentForecast(forecastDetails);
}
public void end() {
running = false;
self.interrupt();
}
public ForecastDetails getMostRecentForecast() {
synchronized (this)
{
return mostRecentForecast;
}
}
private void setMostRecentForecast(ForecastDetails forecast) {
synchronized (this)
{
mostRecentForecast = forecast;
}
}
@Override
public void run() {
self = Thread.currentThread();
while (running)
{
try
{
Thread.sleep(TimeUnit.MILLISECONDS.convert(1, TimeUnit.HOURS));
processForecasts();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,17 @@
package com.flaremicro.visualforecast.datamart;
public class TownInfo {
public final String code;
public final String townName;
public final String province;
public final float northLat;
public final float westLong;
public TownInfo(String code, String townName, String province, float northLat, float westLong) {
this.code = code;
this.townName = townName;
this.province = province;
this.northLat = northLat;
this.westLong = westLong;
}
}

View File

@@ -0,0 +1,56 @@
package com.flaremicro.visualforecast.datamart;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class XMLUtils {
public static String getStringFromTag(Element parent, String tag) {
NodeList l = parent.getElementsByTagName(tag);
if (l.getLength() > 0)
return l.item(0).getTextContent();
return null;
}
public static String getStringFromTagAttribute(Element parent, String tag, String attribute) {
NodeList l = parent.getElementsByTagName(tag);
if (l.getLength() > 0)
{
Node attrib = l.item(0).getAttributes().getNamedItem(attribute);
if(attrib != null)
return attrib.getTextContent();
}
return null;
}
public static String getStringFromAttribute(Node n, String attribute) {
Node attrib = n.getAttributes().getNamedItem(attribute);
if(attrib != null)
return attrib.getTextContent();
return null;
}
public static Element getFistElement(Element parent, String tag) {
NodeList l = parent.getElementsByTagName(tag);
for (int i = 0; i < l.getLength(); i++)
{
if (l.item(i).getNodeType() == Node.ELEMENT_NODE)
return (Element) l.item(i);
}
return null;
}
public static Integer getIntFromTag(Element abbForecast, String tag, Integer fallback) {
String content = getStringFromTag(abbForecast, tag);
try
{
return Integer.parseInt(content);
}
catch (NumberFormatException ex)
{
}
return fallback;
}
}

1
src/provider.properties Normal file
View File

@@ -0,0 +1 @@
main-class=com.flaremicro.visualforecast.datamart.CanadaDatamartProvider

99
src/translation.csv Normal file
View File

@@ -0,0 +1,99 @@
Mainly sunny,Mainly,Sunny
Mainly cloudy,Mainly, Cloudy
Sunny,Sunny,
A few clouds,Few,Clouds
A mix of sun and cloud,Partly,Cloudy
Cloudy periods,Cloudy,Periods
Sunny with cloudy periods,Cloudy,Periods
Cloudy with sunny periods,Sunny,Periods
Increasing cloudiness,Increasing,Clouds
Clearing,Clearing,
Clear,Sun,
Chance of showers,Chance,Showers
A few showers,Few,Showers
Chance of drizzle or rain,Chance,Drizzle
A few flurries or rain showers,Flurries/,Showers
Chance of flurries or rain showers,Flurries/,Showers
Chance of rain showers or flurries,Flurries/,Showers
A few flurries,Flurries,
Chance of flurries,Chance,Flurries
A few wet flurries,Wet,Flurries
Chance of showers at times heavy or thundershowers,Scattered,T'Storms
Chance of showers at times heavy or thunderstorms,Scattered,T'Storms
Chance of thundershowers,Thunder,Storms
Chance of thunderstorms,Thunder,Storms
Chance of showers or thundershowers,Thunder,Storms
Chance of showers or thunderstorms,Thunder,Storms
A few flurries or thundershowers,Thunder,Storms
Cloudy,Cloudy,
Overcast,Overcast,
Showers,Showers,
Chance of showers,Chance,Showers
Periods of rain,Scattered,Rain
Mostly Cloudy,Mostly,Cloudy
Rain at times heavy,Heavy,Rain
A few showers or drizzle,Drizzle
Rain,Rain
Chance of freezing rain,Chance,Ice Rain
Freezing rain,Freezing,Rain
Chance of freezing rain or rain,Chance,Ice Rain,
Chance of rain or freezing rain,Chance,Ice Rain,
A few rain showers or flurries,Scattered,Flurries
Periods of rain or snow,Rain or,Snow
A few rain showers or wet flurries,Rain or,Flurries
Snow mixed with rain,Rain,Snow
Chance of snow mixed with freezing rain,Rain,Snow
Wet snow or rain,Wet,Snow
Flurries,Flurries,
Light snow,Light,Snow
Wet flurries,Wet,Flurries
Wet snow,Wet,Snow
Snow at times heavy,Heavy,Snow
Periods of snow,Scattered,Snow
Snow,Snow,
Chance of snow,Chance,Snow
Snow squalls,Snow,Squalls
Local snow squalls,Snow,Squalls
Blizzard,Blizzard,
Near blizzard,Near,Blizzard
Snow and blizzard,Blizzard,
Snow at times heavy and blowing snow,Blowing,Snow
A few showers or thundershowers,Thunder,Showers
A few showers or thunderstorms,Thunder,Storms
Showers or thundershowers,Thunder,Showers
Showers or thunderstorms,Thunder,Storms
Rain or thunderstorms,Thunder,Storms
Rain or thundershowers,Thunder,Showers
Chance of thunderstorms and possible hail,Hail,T'Storms
Thunderstorms and possible hail,Hail,T'Storms
A mix of sun and cloud,Partly,Cloudy
Haze,Haze,
Fog,Fog,
Fog Patches,Patchy,Fog
Fog dissipating,Fog
Fog developing,Fog
Ice fog,Ice,Fog
Ice fog developing,Ice,Fog
Ice fog dissipating,Ice,Fog
A few flurries mixed with ice pellets,Sleet,Flurries
Ice pellet,Sleet
Ice pellet mixed with freezing rain,Sleet,Rain
Ice pellet mixed with snow,Sleet,Snow
Ice pellet or snow,Sleet,Snow
Possibility of drizzle mixed with freezing drizzle,Ice,Drizzle
Drizzle,Drizzle
Freezing drizzle,Freezing,Drizzle
Possibility of drizzle,Drizzle
Drizzle or freezing drizzle,Freezing,Drizzle
Not available,MISSING,DATA
Chance of drizzle or rain,Chance,Rain
A few flurries or showers,Flurries/,Showers
Chance of snow or rain,Chance,Snow
A few flurries,Scattered,Flurries
Chance of light snow,Light,Snow
A few wet flurries,Wet,Flurries
Chance of showers at times heavy or thunderstorms,Thunder,Storms
Chance of thunderstorms,Thunder,Storms
Snow and blowing snow,Blowing,Snow
Windy,Windy
Smoke,Smoke
1 Mainly sunny Mainly Sunny
2 Mainly cloudy Mainly Cloudy
3 Sunny Sunny
4 A few clouds Few Clouds
5 A mix of sun and cloud Partly Cloudy
6 Cloudy periods Cloudy Periods
7 Sunny with cloudy periods Cloudy Periods
8 Cloudy with sunny periods Sunny Periods
9 Increasing cloudiness Increasing Clouds
10 Clearing Clearing
11 Clear Sun
12 Chance of showers Chance Showers
13 A few showers Few Showers
14 Chance of drizzle or rain Chance Drizzle
15 A few flurries or rain showers Flurries/ Showers
16 Chance of flurries or rain showers Flurries/ Showers
17 Chance of rain showers or flurries Flurries/ Showers
18 A few flurries Flurries
19 Chance of flurries Chance Flurries
20 A few wet flurries Wet Flurries
21 Chance of showers at times heavy or thundershowers Scattered T'Storms
22 Chance of showers at times heavy or thunderstorms Scattered T'Storms
23 Chance of thundershowers Thunder Storms
24 Chance of thunderstorms Thunder Storms
25 Chance of showers or thundershowers Thunder Storms
26 Chance of showers or thunderstorms Thunder Storms
27 A few flurries or thundershowers Thunder Storms
28 Cloudy Cloudy
29 Overcast Overcast
30 Showers Showers
31 Chance of showers Chance Showers
32 Periods of rain Scattered Rain
33 Mostly Cloudy Mostly Cloudy
34 Rain at times heavy Heavy Rain
35 A few showers or drizzle Drizzle
36 Rain Rain
37 Chance of freezing rain Chance Ice Rain
38 Freezing rain Freezing Rain
39 Chance of freezing rain or rain Chance Ice Rain
40 Chance of rain or freezing rain Chance Ice Rain
41 A few rain showers or flurries Scattered Flurries
42 Periods of rain or snow Rain or Snow
43 A few rain showers or wet flurries Rain or Flurries
44 Snow mixed with rain Rain Snow
45 Chance of snow mixed with freezing rain Rain Snow
46 Wet snow or rain Wet Snow
47 Flurries Flurries
48 Light snow Light Snow
49 Wet flurries Wet Flurries
50 Wet snow Wet Snow
51 Snow at times heavy Heavy Snow
52 Periods of snow Scattered Snow
53 Snow Snow
54 Chance of snow Chance Snow
55 Snow squalls Snow Squalls
56 Local snow squalls Snow Squalls
57 Blizzard Blizzard
58 Near blizzard Near Blizzard
59 Snow and blizzard Blizzard
60 Snow at times heavy and blowing snow Blowing Snow
61 A few showers or thundershowers Thunder Showers
62 A few showers or thunderstorms Thunder Storms
63 Showers or thundershowers Thunder Showers
64 Showers or thunderstorms Thunder Storms
65 Rain or thunderstorms Thunder Storms
66 Rain or thundershowers Thunder Showers
67 Chance of thunderstorms and possible hail Hail T'Storms
68 Thunderstorms and possible hail Hail T'Storms
69 A mix of sun and cloud Partly Cloudy
70 Haze Haze
71 Fog Fog
72 Fog Patches Patchy Fog
73 Fog dissipating Fog
74 Fog developing Fog
75 Ice fog Ice Fog
76 Ice fog developing Ice Fog
77 Ice fog dissipating Ice Fog
78 A few flurries mixed with ice pellets Sleet Flurries
79 Ice pellet Sleet
80 Ice pellet mixed with freezing rain Sleet Rain
81 Ice pellet mixed with snow Sleet Snow
82 Ice pellet or snow Sleet Snow
83 Possibility of drizzle mixed with freezing drizzle Ice Drizzle
84 Drizzle Drizzle
85 Freezing drizzle Freezing Drizzle
86 Possibility of drizzle Drizzle
87 Drizzle or freezing drizzle Freezing Drizzle
88 Not available MISSING DATA
89 Chance of drizzle or rain Chance Rain
90 A few flurries or showers Flurries/ Showers
91 Chance of snow or rain Chance Snow
92 A few flurries Scattered Flurries
93 Chance of light snow Light Snow
94 A few wet flurries Wet Flurries
95 Chance of showers at times heavy or thunderstorms Thunder Storms
96 Chance of thunderstorms Thunder Storms
97 Snow and blowing snow Blowing Snow
98 Windy Windy
99 Smoke Smoke