From 830eafd2cedb61f14a6bccc47471a0d7210c5337 Mon Sep 17 00:00:00 2001
From: Christopher Bohn <bohn@unl.edu>
Date: Fri, 12 Nov 2021 15:44:41 -0600
Subject: [PATCH] Reformatted to SOFT160 formatting specification

---
 pom.xml                                       |   93 +-
 .../json_connections/Demonstration.java       |  549 +-
 .../connection/Connection.java                |   20 +-
 .../connection/FileConnection.java            |   93 +-
 .../connection/RestConnection.java            |  142 +-
 .../connector/OpenWeatherConnector.java       | 3420 +++++++-----
 .../AirPollution_UnlNov24ToNov27Test.java     |  147 +-
 .../AirPollution_WebsiteExampleTest.java      |  174 +-
 .../json_connections/ExceptionsTest.java      | 4790 ++++++++---------
 .../Forecast_UnlNov7ToNov12Test.java          |  205 +-
 .../OneCall_WebsiteExampleTest.java           |  495 +-
 .../Weather_UnlOct24At0917Test.java           |  180 +-
 .../Weather_WebsiteExampleTest.java           |  167 +-
 13 files changed, 5459 insertions(+), 5016 deletions(-)

diff --git a/pom.xml b/pom.xml
index e9f0333..7cf766f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,50 +1,51 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>edu.unl.cse.soft160.rest_connector</groupId>
-    <artifactId>rest_and_file_connector</artifactId>
-    <packaging>jar</packaging>
-    <version>1.0-SNAPSHOT</version>
-    <name>rest_connector</name>
-    <url>http://maven.apache.org</url>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>edu.unl.cse.soft160.rest_connector</groupId>
+	<artifactId>rest_and_file_connector</artifactId>
+	<packaging>jar</packaging>
+	<version>1.0-SNAPSHOT</version>
+	<name>rest_connector</name>
+	<url>http://maven.apache.org</url>
 
-    <properties>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    </properties>
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
 
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.8.1</version>
-                <configuration>
-                    <source>11</source>
-                    <target>11</target>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-javadoc-plugin</artifactId>
-                <version>3.3.1</version>
-                <configuration>
-                    <show>public</show>
-                    <source>11</source>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.8.1</version>
+				<configuration>
+					<source>11</source>
+					<target>11</target>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-javadoc-plugin</artifactId>
+				<version>3.3.1</version>
+				<configuration>
+					<show>public</show>
+					<source>11</source>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
 
-    <dependencies>
-        <dependency>
-            <groupId>com.googlecode.json-simple</groupId>
-            <artifactId>json-simple</artifactId>
-            <version>1.1.1</version>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>4.13</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
+	<dependencies>
+		<dependency>
+			<groupId>com.googlecode.json-simple</groupId>
+			<artifactId>json-simple</artifactId>
+			<version>1.1.1</version>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.13</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
 </project>
diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/Demonstration.java b/src/main/java/edu/unl/cse/soft160/json_connections/Demonstration.java
index e2a7bae..4148324 100644
--- a/src/main/java/edu/unl/cse/soft160/json_connections/Demonstration.java
+++ b/src/main/java/edu/unl/cse/soft160/json_connections/Demonstration.java
@@ -16,291 +16,290 @@ import java.util.List;
 import java.util.Scanner;
 
 public class Demonstration {
-    private static String getDataSet(Scanner scanner) {
-        List<String> dataSets = new ArrayList<>(OpenWeatherConnector.allowableDataSets);
-        for (int i = 0; i < dataSets.size(); ++i) {
-            System.out.println((i + 1) + ". " + dataSets.get(i));
-        }
-        System.out.print(System.lineSeparator() + "Please enter the desired data set: ");
-        int choice = scanner.nextInt();
-        scanner.nextLine();
+	private static String getDataSet(Scanner scanner) {
+		List<String> dataSets = new ArrayList<>(OpenWeatherConnector.allowableDataSets);
+		for (int i = 0; i < dataSets.size(); ++i) {
+			System.out.println((i + 1) + ". " + dataSets.get(i));
+		}
+		System.out.print(System.lineSeparator() + "Please enter the desired data set: ");
+		int choice = scanner.nextInt();
+		scanner.nextLine();
 
-        return dataSets.get(choice - 1);
-    }
+		return dataSets.get(choice - 1);
+	}
 
-    private static String getData(OpenWeatherConnector weather, String dataSet, Instant now, Scanner scanner) {
-        String query;
-        switch (dataSet) {
-            case "weather":
-            case "forecast":
-                query = "zip=68588";
-                break;
-            case "onecall":
-            case "air_pollution":
-            case "air_pollution/forecast":
-                query = "lat=40.81506358&lon=-96.7048613";
-                break;
-            case "air_pollution/history":
-                Instant yesterday = now.minus(1, ChronoUnit.DAYS);
-                Instant twoDaysAgo = now.minus(2, ChronoUnit.DAYS);
-                query = "lat=40.81506358&lon=-96.7048613&start=" +
-                        twoDaysAgo.getEpochSecond() + "&end=" + yesterday.getEpochSecond();
-                break;
-            default:
-                System.err.println("The " + dataSet + " dataset is not currently supported.");
-                query = "";
-        }
+	private static String getData(OpenWeatherConnector weather, String dataSet, Instant now, Scanner scanner) {
+		String query;
+		switch (dataSet) {
+		case "weather":
+		case "forecast":
+			query = "zip=68588";
+			break;
+		case "onecall":
+		case "air_pollution":
+		case "air_pollution/forecast":
+			query = "lat=40.81506358&lon=-96.7048613";
+			break;
+		case "air_pollution/history":
+			Instant yesterday = now.minus(1, ChronoUnit.DAYS);
+			Instant twoDaysAgo = now.minus(2, ChronoUnit.DAYS);
+			query = "lat=40.81506358&lon=-96.7048613&start=" + twoDaysAgo.getEpochSecond() + "&end="
+					+ yesterday.getEpochSecond();
+			break;
+		default:
+			System.err.println("The " + dataSet + " dataset is not currently supported.");
+			query = "";
+		}
 
-        if (!query.equals("")) {
-            System.out.print("Enter query, or press the ENTER key to accept the example query (" + query + "): ");
-            String userQuery = scanner.nextLine();
-            if(!userQuery.equals("")) {
-                System.out.println("   " + "*".repeat(76));
-                System.out.println("   ***   The following example output strings assume default units.         ***");
-                System.out.println("   ***   If you specified other units, the values will be correct, but      ***");
-                System.out.println("   ***   the stated units will be the defaults, not your specified units.   ***");
-                System.out.println("   " + "*".repeat(76));
-                query = userQuery;
-            }
-        }
+		if (!query.equals("")) {
+			System.out.print("Enter query, or press the ENTER key to accept the example query (" + query + "): ");
+			String userQuery = scanner.nextLine();
+			if (!userQuery.equals("")) {
+				System.out.println("   " + "*".repeat(76));
+				System.out.println("   ***   The following example output strings assume default units.         ***");
+				System.out.println("   ***   If you specified other units, the values will be correct, but      ***");
+				System.out.println("   ***   the stated units will be the defaults, not your specified units.   ***");
+				System.out.println("   " + "*".repeat(76));
+				query = userQuery;
+			}
+		}
 
-        String data = null;
-        if (!query.equals("")) {
-            System.out.println("Requesting data at " + now);
-            try {
-                data = weather.retrieveData(query);
-            } catch (IOException ioException) {
-                System.err.println("IO Exception: " + ioException.getClass());
-                System.err.println("\t" + ioException.getMessage());
-                System.err.println("Caused by: " + ioException.getCause());
-                if (ioException.getCause() != null) {
-                    System.err.println("\t" + ioException.getCause().getMessage());
-                }
-            }
-        } else {
-            System.err.println("Not requesting data at " + now + " due to empty query.");
-        }
-        return data;
-    }
+		String data = null;
+		if (!query.equals("")) {
+			System.out.println("Requesting data at " + now);
+			try {
+				data = weather.retrieveData(query);
+			} catch (IOException ioException) {
+				System.err.println("IO Exception: " + ioException.getClass());
+				System.err.println("\t" + ioException.getMessage());
+				System.err.println("Caused by: " + ioException.getCause());
+				if (ioException.getCause() != null) {
+					System.err.println("\t" + ioException.getCause().getMessage());
+				}
+			}
+		} else {
+			System.err.println("Not requesting data at " + now + " due to empty query.");
+		}
+		return data;
+	}
 
-    private static void optionallySaveDataToFile(String data, String dataSet, Scanner scanner) {
-        System.out.print(System.lineSeparator() + "Do you wish to save this data to a file Y/(N)? ");
-        String answer = scanner.nextLine();
-        if (answer.length() > 0 && answer.toUpperCase().charAt(0) == 'Y') {
-            System.out.print("What shall the file's name be? ");
-            String filename = scanner.nextLine();
-            if (!filename.endsWith(".json")) {
-                filename += ".json";
-            }
-            FileConnection fileConnection = new FileConnection(dataSet);
-            try {
-                System.out.println("Saving...");
-                fileConnection.save(filename, (JSONObject)new JSONParser().parse(data));
-                System.out.println("\t" + filename + " saved");
-            } catch (ParseException | IOException exception) {
-                exception.printStackTrace();
-            }
-        } else {
-            System.out.println("Not saving data.");
-        }
-    }
-    
-    private static void reportAirPollutionHistoryOrForecastData(OpenWeatherConnector weather, Instant now) {
-        Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2);
-        System.out.println("The air quality at " + timestamp +
-                (timestamp.toInstant().isBefore(now) ? " was " : " will be ") +
-                weather.getAirQualityIndex(timestamp) + " pollutant concentration");
-        System.out.println("CO:  " + weather.getCarbonMonoxide(timestamp) + " μg/m3");
-        System.out.println("NO:  " + weather.getNitrogenMonoxide(timestamp) + " μg/m3");
-        System.out.println("NO2: " + weather.getNitrogenDioxide(timestamp) + " μg/m3");
-        System.out.println("O3:  " + weather.getOzone(timestamp) + " μg/m3");
-        System.out.println("SO2: " + weather.getSulfurDioxide(timestamp) + " μg/m3");
-        System.out.println("NH3: " + weather.getAmmonia(timestamp) + " μg/m3");
-        System.out.println("Fine particulate matter:   " + weather.getFineParticulateMatter(timestamp) + " " +
-                "μg/m3");
-        System.out.println("Coarse particulate matter: " + weather.getCoarseParticulateMatter(timestamp) + " " +
-                "μg/m3");
-    }
+	private static void optionallySaveDataToFile(String data, String dataSet, Scanner scanner) {
+		System.out.print(System.lineSeparator() + "Do you wish to save this data to a file Y/(N)? ");
+		String answer = scanner.nextLine();
+		if (answer.length() > 0 && answer.toUpperCase().charAt(0) == 'Y') {
+			System.out.print("What shall the file's name be? ");
+			String filename = scanner.nextLine();
+			if (!filename.endsWith(".json")) {
+				filename += ".json";
+			}
+			FileConnection fileConnection = new FileConnection(dataSet);
+			try {
+				System.out.println("Saving...");
+				fileConnection.save(filename, (JSONObject) new JSONParser().parse(data));
+				System.out.println("\t" + filename + " saved");
+			} catch (ParseException | IOException exception) {
+				exception.printStackTrace();
+			}
+		} else {
+			System.out.println("Not saving data.");
+		}
+	}
 
-    private static void reportAirPollutionData(OpenWeatherConnector weather) {
-        System.out.println("The current air quality is " + weather.getAirQualityIndex() +
-                " pollutant concentration");
-        System.out.println("CO:  " + weather.getCarbonMonoxide() + " μg/m3");
-        System.out.println("NO:  " + weather.getNitrogenMonoxide() + " μg/m3");
-        System.out.println("NO2: " + weather.getNitrogenDioxide() + " μg/m3");
-        System.out.println("O3:  " + weather.getOzone() + " μg/m3");
-        System.out.println("SO2: " + weather.getSulfurDioxide() + " μg/m3");
-        System.out.println("NH3: " + weather.getAmmonia() + " μg/m3");
-        System.out.println("Fine particulate matter:   " + weather.getFineParticulateMatter() + " μg/m3");
-        System.out.println("Coarse particulate matter: " + weather.getCoarseParticulateMatter() + " μg/m3");
-    }
+	private static void reportAirPollutionHistoryOrForecastData(OpenWeatherConnector weather, Instant now) {
+		Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2);
+		System.out.println(
+				"The air quality at " + timestamp + (timestamp.toInstant().isBefore(now) ? " was " : " will be ")
+						+ weather.getAirQualityIndex(timestamp) + " pollutant concentration");
+		System.out.println("CO:  " + weather.getCarbonMonoxide(timestamp) + " μg/m3");
+		System.out.println("NO:  " + weather.getNitrogenMonoxide(timestamp) + " μg/m3");
+		System.out.println("NO2: " + weather.getNitrogenDioxide(timestamp) + " μg/m3");
+		System.out.println("O3:  " + weather.getOzone(timestamp) + " μg/m3");
+		System.out.println("SO2: " + weather.getSulfurDioxide(timestamp) + " μg/m3");
+		System.out.println("NH3: " + weather.getAmmonia(timestamp) + " μg/m3");
+		System.out.println("Fine particulate matter:   " + weather.getFineParticulateMatter(timestamp) + " " + "μg/m3");
+		System.out
+				.println("Coarse particulate matter: " + weather.getCoarseParticulateMatter(timestamp) + " " + "μg/m3");
+	}
 
-    private static void reportOneCallData(OpenWeatherConnector weather) {
-        Date timestamp;
-        System.out.println("It is currently " + weather.getWeatherCategories());
-        System.out.println("Specifically, it is " + weather.getWeatherDescriptions());
-        System.out.println("The temperature is " + weather.getTemperature() + "K");
-        System.out.println("Factoring in the relative humidity of " + weather.getHumidity() + "%, the dew " +
-                "point is " + weather.getDewPoint() + "K, and it feels like " + weather.getFeelsLike() + "K");
-        System.out.println("That probably also factored in winds, which are " + weather.getWindSpeed() + "m/s" +
-                " from " + weather.getWindDirection() + "˚, gusting to " + weather.getWindGust() + "m/s");
-        System.out.println("Visibility is " + weather.getVisibility() + "m");
-        System.out.println("The pressure is " + weather.getPressure() + "hPa");
-        System.out.println("Cloud cover is " + weather.getCloudCover() + "%");
-        System.out.println("The UV Index is " + weather.getUltravioletIndex());
-        System.out.println("Precipitation in the last hour has been " + weather.getOneHourRainfall() + "mm of" +
-                " rain and " + weather.getOneHourSnowfall() + "mm of snow.");
-        if (weather.getTimestamps("minutely").size() > 0) {
-            System.out.println("There is minutely data from " + weather.getTimestamps("minutely").get(0) + " to " +
-                    weather.getTimestamps("minutely").get(weather.getTimestamps("minutely").size() - 1));
-            timestamp = weather.getTimestamps("minutely").get(weather.getTimestamps("minutely").size() / 2);
-            System.out.println("\tAt " + timestamp + " the 1-hour (?) precipitation total will be " +
-                    weather.getMinutelyPrecipitation(timestamp));
-        } else {
-            System.out.println("There is no minutely data.");
-        }
-        if (weather.getTimestamps("hourly").size() > 0) {
-            System.out.println("There is hourly data from " + weather.getTimestamps("hourly").get(0) + " to " +
-                    weather.getTimestamps("hourly").get(weather.getTimestamps("hourly").size() - 1));
-            timestamp = weather.getTimestamps("hourly").get(weather.getTimestamps("hourly").size() / 2);
-            System.out.println("\tAt " + timestamp + " it will be " + weather.getWeatherCategories(timestamp));
-            System.out.println("\tSpecifically, it will be " + weather.getWeatherDescriptions(timestamp));
-            System.out.println("\tThe temperature will be " + weather.getTemperature(timestamp) + "K");
-            System.out.println("\tFactoring in the relative humidity of " + weather.getHumidity(timestamp) + "%, the dew " +
-                    "point will be " + weather.getDewPoint(timestamp) + "K, and it will feel like " +
-                    weather.getFeelsLike(timestamp) + "K");
-            System.out.println("\tThat probably also factored in winds, which will be " +
-                    weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp) +
-                    "˚, gusting to " + weather.getWindGust(timestamp) + "m/s");
-            System.out.println("\tVisibility will be " + weather.getVisibility(timestamp) + "m");
-            System.out.println("\tThe pressure will be " + weather.getPressure(timestamp) + "hPa");
-            System.out.println("\tCloud cover will be " + weather.getCloudCover(timestamp) + "%");
-            System.out.println("\tThe UV Index will be " + weather.getUltravioletIndex(timestamp));
-            System.out.println("\tThere will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% " +
-                    "chance of precipitation, resulting in " + weather.getOneHourRainfall(timestamp) + "mm of " +
-                    "rain and " + weather.getOneHourSnowfall(timestamp) + "mm of snow in the hour before " +
-                    timestamp);
-        } else {
-            System.out.println("There is no hourly data.");
-        }
-        if (weather.getTimestamps("daily").size() > 0) {
-            System.out.println("There is daily data from " + weather.getTimestamps("daily").get(0) + " to " +
-                    weather.getTimestamps("daily").get(weather.getTimestamps("daily").size() - 1));
-            timestamp = weather.getTimestamps("daily").get(weather.getTimestamps("daily").size() / 2);
-            System.out.println("\tAt " + timestamp + " it will be " + weather.getWeatherCategories(timestamp));
-            System.out.println("\tSpecifically, it will be " + weather.getWeatherDescriptions(timestamp));
-            System.out.println("\tThe temperatures will range from " + weather.getLowTemperature(timestamp) + "K to " +
-                    weather.getHighTemperature(timestamp) + "K");
-            System.out.println("\t\tMorning:" + weather.getMorningTemperature(timestamp) + "K");
-            System.out.println("\t\tDaytime:" + weather.getDaytimeTemperature(timestamp) + "K");
-            System.out.println("\t\tEvening:" + weather.getEveningTemperature(timestamp) + "K");
-            System.out.println("\t\tNighttime:" + weather.getNighttimeTemperature(timestamp) + "K");
-            System.out.println("\tFactoring in the relative humidity of " + weather.getHumidity(timestamp) + "%, the dew " +
-                    "point will be " + weather.getDewPoint(timestamp) + "K, and it will feel like:");
-            System.out.println("\t\tMorning:" + weather.getMorningFeelsLike(timestamp) + "K");
-            System.out.println("\t\tDaytime:" + weather.getDaytimeFeelsLike(timestamp) + "K");
-            System.out.println("\t\tEvening:" + weather.getEveningFeelsLike(timestamp) + "K");
-            System.out.println("\t\tNighttime:" + weather.getNighttimeFeelsLike(timestamp) + "K");
-            System.out.println("\tThat probably also factored in winds, which will be " +
-                    weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp) +
-                    "˚, gusting to " + weather.getWindGust(timestamp) + "m/s");
-            System.out.println("\tThe pressure will be " + weather.getPressure(timestamp) + "hPa");
-            System.out.println("\tCloud cover will be " + weather.getCloudCover(timestamp) + "%");
-            System.out.println("\tThe UV Index will be " + weather.getUltravioletIndex(timestamp));
-            System.out.println("\tThere will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% " +
-                    "chance of precipitation, resulting in " + weather.getDailyRainfall(timestamp) + "mm of " +
-                    "rain and " + weather.getDailySnowfall(timestamp) + "mm of snow");
-        } else {
-            System.out.println("There is no daily data.");
-        }
-    }
+	private static void reportAirPollutionData(OpenWeatherConnector weather) {
+		System.out.println("The current air quality is " + weather.getAirQualityIndex() + " pollutant concentration");
+		System.out.println("CO:  " + weather.getCarbonMonoxide() + " μg/m3");
+		System.out.println("NO:  " + weather.getNitrogenMonoxide() + " μg/m3");
+		System.out.println("NO2: " + weather.getNitrogenDioxide() + " μg/m3");
+		System.out.println("O3:  " + weather.getOzone() + " μg/m3");
+		System.out.println("SO2: " + weather.getSulfurDioxide() + " μg/m3");
+		System.out.println("NH3: " + weather.getAmmonia() + " μg/m3");
+		System.out.println("Fine particulate matter:   " + weather.getFineParticulateMatter() + " μg/m3");
+		System.out.println("Coarse particulate matter: " + weather.getCoarseParticulateMatter() + " μg/m3");
+	}
 
-    private static void reportForecastData(OpenWeatherConnector weather) {
-        Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2);
-        System.out.println("At " + timestamp + " it will be " + weather.getWeatherCategories(timestamp));
-        System.out.println("Specifically, it will be " + weather.getWeatherDescriptions(timestamp));
-        System.out.println("The temperature will be " + weather.getTemperature(timestamp) + "K");
-        System.out.println("Factoring in the relative humidity of " + weather.getHumidity(timestamp) + "%, " +
-                "it will feel like " + weather.getFeelsLike(timestamp) + "K");
-        System.out.println("That probably also factored in winds, which will be " +
-                weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp) +
-                "˚, gusting to " + weather.getWindGust(timestamp) + "m/s");
-        System.out.println("Visibility will be " + weather.getVisibility(timestamp) + "m");
-        System.out.println("The pressure will be " + weather.getPressure(timestamp) + "hPa");
-        System.out.println("Cloud cover will be " + weather.getCloudCover(timestamp) + "%");
-        System.out.println("There will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% " +
-                "chance of precipitation, resulting in " + weather.getThreeHourRainfall(timestamp) + "mm of " +
-                "rain and " + weather.getThreeHourSnowfall(timestamp) + "mm of snow in the three hours before" +
-                " " + timestamp);
-    }
+	private static void reportOneCallData(OpenWeatherConnector weather) {
+		Date timestamp;
+		System.out.println("It is currently " + weather.getWeatherCategories());
+		System.out.println("Specifically, it is " + weather.getWeatherDescriptions());
+		System.out.println("The temperature is " + weather.getTemperature() + "K");
+		System.out.println("Factoring in the relative humidity of " + weather.getHumidity() + "%, the dew "
+				+ "point is " + weather.getDewPoint() + "K, and it feels like " + weather.getFeelsLike() + "K");
+		System.out.println("That probably also factored in winds, which are " + weather.getWindSpeed() + "m/s"
+				+ " from " + weather.getWindDirection() + "˚, gusting to " + weather.getWindGust() + "m/s");
+		System.out.println("Visibility is " + weather.getVisibility() + "m");
+		System.out.println("The pressure is " + weather.getPressure() + "hPa");
+		System.out.println("Cloud cover is " + weather.getCloudCover() + "%");
+		System.out.println("The UV Index is " + weather.getUltravioletIndex());
+		System.out.println("Precipitation in the last hour has been " + weather.getOneHourRainfall() + "mm of"
+				+ " rain and " + weather.getOneHourSnowfall() + "mm of snow.");
+		if (weather.getTimestamps("minutely").size() > 0) {
+			System.out.println("There is minutely data from " + weather.getTimestamps("minutely").get(0) + " to "
+					+ weather.getTimestamps("minutely").get(weather.getTimestamps("minutely").size() - 1));
+			timestamp = weather.getTimestamps("minutely").get(weather.getTimestamps("minutely").size() / 2);
+			System.out.println("\tAt " + timestamp + " the 1-hour (?) precipitation total will be "
+					+ weather.getMinutelyPrecipitation(timestamp));
+		} else {
+			System.out.println("There is no minutely data.");
+		}
+		if (weather.getTimestamps("hourly").size() > 0) {
+			System.out.println("There is hourly data from " + weather.getTimestamps("hourly").get(0) + " to "
+					+ weather.getTimestamps("hourly").get(weather.getTimestamps("hourly").size() - 1));
+			timestamp = weather.getTimestamps("hourly").get(weather.getTimestamps("hourly").size() / 2);
+			System.out.println("\tAt " + timestamp + " it will be " + weather.getWeatherCategories(timestamp));
+			System.out.println("\tSpecifically, it will be " + weather.getWeatherDescriptions(timestamp));
+			System.out.println("\tThe temperature will be " + weather.getTemperature(timestamp) + "K");
+			System.out.println("\tFactoring in the relative humidity of " + weather.getHumidity(timestamp)
+					+ "%, the dew " + "point will be " + weather.getDewPoint(timestamp) + "K, and it will feel like "
+					+ weather.getFeelsLike(timestamp) + "K");
+			System.out.println("\tThat probably also factored in winds, which will be "
+					+ weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp)
+					+ "˚, gusting to " + weather.getWindGust(timestamp) + "m/s");
+			System.out.println("\tVisibility will be " + weather.getVisibility(timestamp) + "m");
+			System.out.println("\tThe pressure will be " + weather.getPressure(timestamp) + "hPa");
+			System.out.println("\tCloud cover will be " + weather.getCloudCover(timestamp) + "%");
+			System.out.println("\tThe UV Index will be " + weather.getUltravioletIndex(timestamp));
+			System.out.println("\tThere will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% "
+					+ "chance of precipitation, resulting in " + weather.getOneHourRainfall(timestamp) + "mm of "
+					+ "rain and " + weather.getOneHourSnowfall(timestamp) + "mm of snow in the hour before "
+					+ timestamp);
+		} else {
+			System.out.println("There is no hourly data.");
+		}
+		if (weather.getTimestamps("daily").size() > 0) {
+			System.out.println("There is daily data from " + weather.getTimestamps("daily").get(0) + " to "
+					+ weather.getTimestamps("daily").get(weather.getTimestamps("daily").size() - 1));
+			timestamp = weather.getTimestamps("daily").get(weather.getTimestamps("daily").size() / 2);
+			System.out.println("\tAt " + timestamp + " it will be " + weather.getWeatherCategories(timestamp));
+			System.out.println("\tSpecifically, it will be " + weather.getWeatherDescriptions(timestamp));
+			System.out.println("\tThe temperatures will range from " + weather.getLowTemperature(timestamp) + "K to "
+					+ weather.getHighTemperature(timestamp) + "K");
+			System.out.println("\t\tMorning:" + weather.getMorningTemperature(timestamp) + "K");
+			System.out.println("\t\tDaytime:" + weather.getDaytimeTemperature(timestamp) + "K");
+			System.out.println("\t\tEvening:" + weather.getEveningTemperature(timestamp) + "K");
+			System.out.println("\t\tNighttime:" + weather.getNighttimeTemperature(timestamp) + "K");
+			System.out.println("\tFactoring in the relative humidity of " + weather.getHumidity(timestamp)
+					+ "%, the dew " + "point will be " + weather.getDewPoint(timestamp) + "K, and it will feel like:");
+			System.out.println("\t\tMorning:" + weather.getMorningFeelsLike(timestamp) + "K");
+			System.out.println("\t\tDaytime:" + weather.getDaytimeFeelsLike(timestamp) + "K");
+			System.out.println("\t\tEvening:" + weather.getEveningFeelsLike(timestamp) + "K");
+			System.out.println("\t\tNighttime:" + weather.getNighttimeFeelsLike(timestamp) + "K");
+			System.out.println("\tThat probably also factored in winds, which will be "
+					+ weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp)
+					+ "˚, gusting to " + weather.getWindGust(timestamp) + "m/s");
+			System.out.println("\tThe pressure will be " + weather.getPressure(timestamp) + "hPa");
+			System.out.println("\tCloud cover will be " + weather.getCloudCover(timestamp) + "%");
+			System.out.println("\tThe UV Index will be " + weather.getUltravioletIndex(timestamp));
+			System.out.println("\tThere will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% "
+					+ "chance of precipitation, resulting in " + weather.getDailyRainfall(timestamp) + "mm of "
+					+ "rain and " + weather.getDailySnowfall(timestamp) + "mm of snow");
+		} else {
+			System.out.println("There is no daily data.");
+		}
+	}
 
-    private static void reportWeatherData(OpenWeatherConnector weather) {
-        System.out.println("It is currently " + weather.getWeatherCategories());
-        System.out.println("Specifically, it is " + weather.getWeatherDescriptions());
-        System.out.println("The temperature is " + weather.getTemperature() + "K");
-        System.out.println("Factoring in the relative humidity of " + weather.getHumidity() + "%, it feels " +
-                "like " + weather.getFeelsLike() + "K");
-        System.out.println("That probably also factored in winds, which are " + weather.getWindSpeed() + "m/s" +
-                " from " + weather.getWindDirection() + "˚, gusting to " + weather.getWindGust() + "m/s");
-        System.out.println("Visibility is " + weather.getVisibility() + "m");
-        System.out.println("The pressure is " + weather.getPressure() + "hPa");
-        System.out.println("Cloud cover is " + weather.getCloudCover() + "%");
-        System.out.println("Precipitation in the last hour has been " + weather.getOneHourRainfall() + "mm of" +
-                " rain and " + weather.getOneHourSnowfall() + "mm of snow.");
-        System.out.println("If three-hour precipitation data is reported, it's " +
-                weather.getThreeHourRainfall() + "mm of rain and " + weather.getThreeHourSnowfall() + "mm of " +
-                "snow. (You might not want to trust those values if they match the 1-hour precipitation.)");
-    }
-    
-    public static void main(String... args) {
-        Scanner scanner = new Scanner(System.in);
-        Instant now = Instant.now();
-        String apiKey = null;
-        try {
-            apiKey = RestConnection.getApiKey("openweathermap");
-        } catch (IOException ioException) {
-            System.err.println("IO Exception: " + ioException.getClass());
-            System.err.println("\t" + ioException.getMessage());
-            System.err.println("Caused by: " + ioException.getCause());
-            System.err.println("\t" + ioException.getCause().getMessage());
-        }
+	private static void reportForecastData(OpenWeatherConnector weather) {
+		Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2);
+		System.out.println("At " + timestamp + " it will be " + weather.getWeatherCategories(timestamp));
+		System.out.println("Specifically, it will be " + weather.getWeatherDescriptions(timestamp));
+		System.out.println("The temperature will be " + weather.getTemperature(timestamp) + "K");
+		System.out.println("Factoring in the relative humidity of " + weather.getHumidity(timestamp) + "%, "
+				+ "it will feel like " + weather.getFeelsLike(timestamp) + "K");
+		System.out.println("That probably also factored in winds, which will be " + weather.getWindSpeed(timestamp)
+				+ "m/s from " + weather.getWindDirection(timestamp) + "˚, gusting to " + weather.getWindGust(timestamp)
+				+ "m/s");
+		System.out.println("Visibility will be " + weather.getVisibility(timestamp) + "m");
+		System.out.println("The pressure will be " + weather.getPressure(timestamp) + "hPa");
+		System.out.println("Cloud cover will be " + weather.getCloudCover(timestamp) + "%");
+		System.out.println("There will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% "
+				+ "chance of precipitation, resulting in " + weather.getThreeHourRainfall(timestamp) + "mm of "
+				+ "rain and " + weather.getThreeHourSnowfall(timestamp) + "mm of snow in the three hours before" + " "
+				+ timestamp);
+	}
 
-        String dataSet = getDataSet(scanner);
-        OpenWeatherConnector weather = new OpenWeatherConnector(dataSet, apiKey);
-        String data = getData(weather, dataSet, now, scanner);
-        
-        System.out.println("Raw JSON: " + data);
-        if (data != null) {
-            System.out.println("Location: " + weather.getLatitude() + " latitude, " + weather.getLongitude() + " " +
-                    "longitude");
-            Date currentTimeStamp = weather.getTimestamp();
-            System.out.println("Current timestamp: " +
-                    (currentTimeStamp == OpenWeatherConnector.IMPOSSIBLE_DATE ? "not present" : currentTimeStamp));
-            System.out.println("Available timestamps: " + weather.getTimestamps());
+	private static void reportWeatherData(OpenWeatherConnector weather) {
+		System.out.println("It is currently " + weather.getWeatherCategories());
+		System.out.println("Specifically, it is " + weather.getWeatherDescriptions());
+		System.out.println("The temperature is " + weather.getTemperature() + "K");
+		System.out.println("Factoring in the relative humidity of " + weather.getHumidity() + "%, it feels " + "like "
+				+ weather.getFeelsLike() + "K");
+		System.out.println("That probably also factored in winds, which are " + weather.getWindSpeed() + "m/s"
+				+ " from " + weather.getWindDirection() + "˚, gusting to " + weather.getWindGust() + "m/s");
+		System.out.println("Visibility is " + weather.getVisibility() + "m");
+		System.out.println("The pressure is " + weather.getPressure() + "hPa");
+		System.out.println("Cloud cover is " + weather.getCloudCover() + "%");
+		System.out.println("Precipitation in the last hour has been " + weather.getOneHourRainfall() + "mm of"
+				+ " rain and " + weather.getOneHourSnowfall() + "mm of snow.");
+		System.out.println("If three-hour precipitation data is reported, it's " + weather.getThreeHourRainfall()
+				+ "mm of rain and " + weather.getThreeHourSnowfall() + "mm of "
+				+ "snow. (You might not want to trust those values if they match the 1-hour precipitation.)");
+	}
 
-            switch (dataSet) {
-                case "weather":
-                    reportWeatherData(weather);
-                    break;
-                case "forecast":
-                    reportForecastData(weather);
-                    break;
-                case "onecall":
-                    reportOneCallData(weather);
-                    break;
-                case "air_pollution":
-                    reportAirPollutionData(weather);
-                    break;
-                case "air_pollution/history":
-                case "air_pollution/forecast":
-                    reportAirPollutionHistoryOrForecastData(weather, now);
-                    break;
-                default:
-                    System.out.println("No examples yet for this dataset.");
-            }
+	public static void main(String... args) {
+		Scanner scanner = new Scanner(System.in);
+		Instant now = Instant.now();
+		String apiKey = null;
+		try {
+			apiKey = RestConnection.getApiKey("openweathermap");
+		} catch (IOException ioException) {
+			System.err.println("IO Exception: " + ioException.getClass());
+			System.err.println("\t" + ioException.getMessage());
+			System.err.println("Caused by: " + ioException.getCause());
+			System.err.println("\t" + ioException.getCause().getMessage());
+			System.exit(1);
+		}
 
-            optionallySaveDataToFile(data, dataSet, scanner);
-        }
-        scanner.close();
-    }
+		String dataSet = getDataSet(scanner);
+		OpenWeatherConnector weather = new OpenWeatherConnector(dataSet, apiKey);
+		String data = getData(weather, dataSet, now, scanner);
+
+		System.out.println("Raw JSON: " + data);
+		if (data != null) {
+			System.out.println(
+					"Location: " + weather.getLatitude() + " latitude, " + weather.getLongitude() + " " + "longitude");
+			Date currentTimeStamp = weather.getTimestamp();
+			System.out.println("Current timestamp: "
+					+ (currentTimeStamp == OpenWeatherConnector.IMPOSSIBLE_DATE ? "not present" : currentTimeStamp));
+			System.out.println("Available timestamps: " + weather.getTimestamps());
+
+			switch (dataSet) {
+			case "weather":
+				reportWeatherData(weather);
+				break;
+			case "forecast":
+				reportForecastData(weather);
+				break;
+			case "onecall":
+				reportOneCallData(weather);
+				break;
+			case "air_pollution":
+				reportAirPollutionData(weather);
+				break;
+			case "air_pollution/history":
+			case "air_pollution/forecast":
+				reportAirPollutionHistoryOrForecastData(weather, now);
+				break;
+			default:
+				System.out.println("No examples yet for this dataset.");
+			}
+
+			optionallySaveDataToFile(data, dataSet, scanner);
+		}
+		scanner.close();
+	}
 }
diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/connection/Connection.java b/src/main/java/edu/unl/cse/soft160/json_connections/connection/Connection.java
index c1d8ce6..99ef769 100644
--- a/src/main/java/edu/unl/cse/soft160/json_connections/connection/Connection.java
+++ b/src/main/java/edu/unl/cse/soft160/json_connections/connection/Connection.java
@@ -9,14 +9,14 @@ import java.io.IOException;
  * Interface for connections to JSON data sources.
  */
 public interface Connection {
-    /**
-     * Retrieves data in JSON format.
-     *
-     * @param dataSpecification identifies the data to be retrieved; the nature of this String depends on the
-     *                          implementing class
-     * @return requested data
-     * @throws IOException    if the data cannot be requested or delivered
-     * @throws ParseException if the data is not a properly-formatted JSON string
-     */
-    JSONObject get(String dataSpecification) throws IOException, ParseException;
+	/**
+	 * Retrieves data in JSON format.
+	 *
+	 * @param dataSpecification identifies the data to be retrieved; the nature of
+	 *                          this String depends on the implementing class
+	 * @return requested data
+	 * @throws IOException    if the data cannot be requested or delivered
+	 * @throws ParseException if the data is not a properly-formatted JSON string
+	 */
+	JSONObject get(String dataSpecification) throws IOException, ParseException;
 }
diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/connection/FileConnection.java b/src/main/java/edu/unl/cse/soft160/json_connections/connection/FileConnection.java
index 82c1cfd..5b83477 100644
--- a/src/main/java/edu/unl/cse/soft160/json_connections/connection/FileConnection.java
+++ b/src/main/java/edu/unl/cse/soft160/json_connections/connection/FileConnection.java
@@ -13,54 +13,55 @@ import java.util.Objects;
  * Connection to JSON files stored locally.
  */
 public class FileConnection implements Connection {
-    protected String directory;
+	protected String directory;
 
-    /**
-     * Initiates connection to files at the top-level directory.
-     */
-    public FileConnection() {
-        directory = "";
-    }
+	/**
+	 * Initiates connection to files at the top-level directory.
+	 */
+	public FileConnection() {
+		directory = "";
+	}
 
-    /**
-     * Initiates connection to files in a particular directory.
-     *
-     * @param directory location of files that will be accessed
-     */
-    public FileConnection(String directory) {
-        this.directory = directory + "/";
-    }
+	/**
+	 * Initiates connection to files in a particular directory.
+	 *
+	 * @param directory location of files that will be accessed
+	 */
+	public FileConnection(String directory) {
+		this.directory = directory + "/";
+	}
 
-    /**
-     * Retrieves data from a JSON file.
-     *
-     * @param filename name of the file containing data
-     * @return requested data
-     * @throws IOException    if the data cannot be requested or delivered; probably the most-common reason is that
-     *                        the requested file is not in the directory
-     * @throws ParseException if the data is not a properly-formatted JSON string
-     */
-    public JSONObject get(String filename) throws IOException, ParseException {
-        JSONObject data;
-        try (InputStreamReader inputStreamReader = new InputStreamReader(Objects.requireNonNull(
-                FileConnection.class.getClassLoader().getResourceAsStream(directory + filename)))) {
-            data = (JSONObject)new JSONParser().parse(inputStreamReader);
-        } catch (NullPointerException originalException) {
-            throw new IOException("Could not find " + directory + filename + ".", originalException);
-        }
-        return data;
-    }
+	/**
+	 * Retrieves data from a JSON file.
+	 *
+	 * @param filename name of the file containing data
+	 * @return requested data
+	 * @throws IOException    if the data cannot be requested or delivered; probably
+	 *                        the most-common reason is that the requested file is
+	 *                        not in the directory
+	 * @throws ParseException if the data is not a properly-formatted JSON string
+	 */
+	public JSONObject get(String filename) throws IOException, ParseException {
+		JSONObject data;
+		try (InputStreamReader inputStreamReader = new InputStreamReader(Objects
+				.requireNonNull(FileConnection.class.getClassLoader().getResourceAsStream(directory + filename)))) {
+			data = (JSONObject) new JSONParser().parse(inputStreamReader);
+		} catch (NullPointerException originalException) {
+			throw new IOException("Could not find " + directory + filename + ".", originalException);
+		}
+		return data;
+	}
 
-    /**
-     * Saves data to a JSON file.
-     *
-     * @param filename name of the file that will hold the data
-     * @param data     data to be saved
-     * @throws IOException if the data cannot be written to the file
-     */
-    public void save(String filename, JSONObject data) throws IOException {
-        FileWriter fileWriter = new FileWriter(filename);
-        data.writeJSONString(fileWriter);
-        fileWriter.close();
-    }
+	/**
+	 * Saves data to a JSON file.
+	 *
+	 * @param filename name of the file that will hold the data
+	 * @param data     data to be saved
+	 * @throws IOException if the data cannot be written to the file
+	 */
+	public void save(String filename, JSONObject data) throws IOException {
+		FileWriter fileWriter = new FileWriter(filename);
+		data.writeJSONString(fileWriter);
+		fileWriter.close();
+	}
 }
diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/connection/RestConnection.java b/src/main/java/edu/unl/cse/soft160/json_connections/connection/RestConnection.java
index a7ada3f..293f3ea 100644
--- a/src/main/java/edu/unl/cse/soft160/json_connections/connection/RestConnection.java
+++ b/src/main/java/edu/unl/cse/soft160/json_connections/connection/RestConnection.java
@@ -19,79 +19,79 @@ import java.util.Objects;
  */
 public class RestConnection implements Connection {
 
-    private static final String FILENAME = "apikeys.json";
+	private static final String FILENAME = "apikeys.json";
 
-    /**
-     * Retrieves the specified API key from the {@code apikeys.json} file.
-     * @param apiKeyName name of the key to be retrieved
-     * @return the API key
-     * @throws IOException if no data stored in {@code apikeys.json} could be retrieved
-     */
-    public static String getApiKey(String apiKeyName) throws IOException {
-        JSONObject apiKeyJson;
-        try (InputStreamReader inputStreamReader = new InputStreamReader(Objects.requireNonNull(
-                Demonstration.class.getClassLoader().getResourceAsStream(FILENAME)))) {
-            apiKeyJson = (JSONObject)new JSONParser().parse(inputStreamReader);
-        } catch (NullPointerException nullPointerException) {
-            FileNotFoundException newException = new FileNotFoundException("File " + FILENAME + " not found.");
-            newException.initCause(nullPointerException);
-            throw newException;
-        } catch (ParseException parseException) {
-            throw new IOException("Error while parsing file " + FILENAME + ".", parseException);
-        }
-        if (!apiKeyJson.containsKey(apiKeyName)) {
-            System.err.println("WARNING! Could not locate API key named " + apiKeyName + " in file " + FILENAME + ".");
-        }
-        String apiKey = apiKeyJson.get(apiKeyName).toString();
-        if (apiKey.equals("")) {
-            System.err.println("WARNING! API key named " + apiKeyName + " in file " + FILENAME + " is blank.");
-        }
-        return apiKey;
-    }
+	/**
+	 * Retrieves the specified API key from the {@code apikeys.json} file.
+	 * 
+	 * @param apiKeyName name of the key to be retrieved
+	 * @return the API key
+	 * @throws IOException if no data stored in {@code apikeys.json} could be
+	 *                     retrieved
+	 */
+	public static String getApiKey(String apiKeyName) throws IOException {
+		JSONObject apiKeyJson;
+		try (InputStreamReader inputStreamReader = new InputStreamReader(
+				Objects.requireNonNull(Demonstration.class.getClassLoader().getResourceAsStream(FILENAME)))) {
+			apiKeyJson = (JSONObject) new JSONParser().parse(inputStreamReader);
+		} catch (NullPointerException nullPointerException) {
+			FileNotFoundException newException = new FileNotFoundException("File " + FILENAME + " not found.");
+			newException.initCause(nullPointerException);
+			throw newException;
+		} catch (ParseException parseException) {
+			throw new IOException("Error while parsing file " + FILENAME + ".", parseException);
+		}
+		if (!apiKeyJson.containsKey(apiKeyName)) {
+			System.err.println("WARNING! Could not locate API key named " + apiKeyName + " in file " + FILENAME + ".");
+		}
+		String apiKey = apiKeyJson.get(apiKeyName).toString();
+		if (apiKey.equals("")) {
+			System.err.println("WARNING! API key named " + apiKeyName + " in file " + FILENAME + " is blank.");
+		}
+		return apiKey;
+	}
 
-    protected final String protocol;
-    protected final String authority;
-    protected final String path;
-    protected final String apiKey;
+	protected final String protocol;
+	protected final String authority;
+	protected final String path;
+	protected final String apiKey;
 
-    /**
-     * Initializes connection to REST API service.
-     *
-     * @param protocol  transfer protocol to be used, typically as "http"
-     * @param authority service provider, typically the server's fully-resolved name
-     * @param path      filepath on the authority to the REST service
-     * @param apiKey    token provided by service owner to authenticate requester and grant appropriate privileges
-     */
-    public RestConnection(String protocol, String authority, String path, String apiKey) {
-        this.protocol = protocol;
-        this.authority = authority;
-        this.path = path;
-        this.apiKey = apiKey;
-    }
+	/**
+	 * Initializes connection to REST API service.
+	 *
+	 * @param protocol  transfer protocol to be used, typically as "http"
+	 * @param authority service provider, typically the server's fully-resolved name
+	 * @param path      filepath on the authority to the REST service
+	 * @param apiKey    token provided by service owner to authenticate requester
+	 *                  and grant appropriate privileges
+	 */
+	public RestConnection(String protocol, String authority, String path, String apiKey) {
+		this.protocol = protocol;
+		this.authority = authority;
+		this.path = path;
+		this.apiKey = apiKey;
+	}
 
-    /**
-     * Retrieves data from REST service.
-     *
-     * @param query the REST query specifying the requested data
-     * @return requested data
-     * @throws IOException    if the data cannot be requested or delivered, such as an incorrect URL or network problems
-     * @throws ParseException if the data is not a properly-formatted JSON string
-     */
-    public JSONObject get(String query) throws IOException, ParseException {
-        JSONObject data;
-        try {
-            URLConnection connection =
-                    new URI(protocol,
-                            authority,
-                            path,
-                            query + "&appid=" + apiKey,
-                            null).toURL().openConnection();
-            connection.setRequestProperty("Accept", "application/json");
-            InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream());
-            data = (JSONObject)new JSONParser().parse(inputStreamReader);
-        } catch (URISyntaxException | MalformedURLException originalException) {
-            throw new IOException("Could not retrieve usable data from " + authority + ".", originalException);
-        }
-        return data;
-    }
+	/**
+	 * Retrieves data from REST service.
+	 *
+	 * @param query the REST query specifying the requested data
+	 * @return requested data
+	 * @throws IOException    if the data cannot be requested or delivered, such as
+	 *                        an incorrect URL or network problems
+	 * @throws ParseException if the data is not a properly-formatted JSON string
+	 */
+	public JSONObject get(String query) throws IOException, ParseException {
+		JSONObject data;
+		try {
+			URLConnection connection = new URI(protocol, authority, path, query + "&appid=" + apiKey, null).toURL()
+					.openConnection();
+			connection.setRequestProperty("Accept", "application/json");
+			InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream());
+			data = (JSONObject) new JSONParser().parse(inputStreamReader);
+		} catch (URISyntaxException | MalformedURLException originalException) {
+			throw new IOException("Could not retrieve usable data from " + authority + ".", originalException);
+		}
+		return data;
+	}
 }
diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/connector/OpenWeatherConnector.java b/src/main/java/edu/unl/cse/soft160/json_connections/connector/OpenWeatherConnector.java
index 3d64643..f0b3d47 100644
--- a/src/main/java/edu/unl/cse/soft160/json_connections/connector/OpenWeatherConnector.java
+++ b/src/main/java/edu/unl/cse/soft160/json_connections/connector/OpenWeatherConnector.java
@@ -15,1498 +15,1938 @@ import java.util.List;
 import java.util.Set;
 
 /**
- * <p>Wrapper for {@link Connection}s to OpenWeather data sources. Provides methods to extract values from OpenWeather
- * data.</p>
+ * <p>
+ * Wrapper for {@link Connection}s to OpenWeather data sources. Provides methods
+ * to extract values from OpenWeather data.
+ * </p>
  *
- * <p>All "get" methods will throw {@link IllegalStateException} if {@link #retrieveData(String)} had not been called.
- * Most "get" methods will throw {@link UnsupportedOperationException} if called when the dataset is not relevant to the
- * method (this distinguishes between a default value being returned because the requested datum isn't part of the data
- * and an exceptional condition when the requested datum cannot be part of the data; see each method's JavaDoc for the
- * relevant datasets).</p>
+ * <p>
+ * All "get" methods will throw {@link IllegalStateException} if
+ * {@link #retrieveData(String)} had not been called. Most "get" methods will
+ * throw {@link UnsupportedOperationException} if called when the dataset is not
+ * relevant to the method (this distinguishes between a default value being
+ * returned because the requested datum isn't part of the data and an
+ * exceptional condition when the requested datum cannot be part of the data;
+ * see each method's JavaDoc for the relevant datasets).
+ * </p>
  *
- * @see <a href="https://openweathermap.org/api">OpenWeathermap.org API documentation</a>
+ * @see <a href="https://openweathermap.org/api">OpenWeathermap.org API
+ *      documentation</a>
  */
 public class OpenWeatherConnector {
-    /**
-     * <p>Top-level weather categories that may be reported in OpenWeather data.</p>
-     *
-     * <p>(n.b., {@link WeatherCategory#UNKNOWN_CATEGORY} is a catch-all for any reported categories that are not a
-     * documented weather condition.)</p>
-     *
-     * @see <a href="https://openweathermap.org/weather-conditions">OpenWeathermap Weather Conditions</a>
-     */
-    public enum WeatherCategory {
-        UNKNOWN_CATEGORY,
-        THUNDERSTORM,   // Group 2xx
-        DRIZZLE,        // Group 3xx
-        RAIN,           // Group 5xx
-        SNOW,           // Group 6xx
-                        // Group 7xx (Atmosphere)
-        MIST,               // 701
-        SMOKE,              // 711
-        HAZE,               // 721
-        DUST,               // 731, 761
-        FOG,                // 741
-        SAND,               // 751
-        ASH,                // 762
-        SQUALL,             // 771
-        TORNADO,            // 781
-        CLEAR,          // Group 800
-        CLOUDS,         // Group 80x
-    }
-
-    /**
-     * <p>Air Quality Indices reported in OpenWeather air pollution reports. Note that while openweathermap.org refers
-     * to the Air Quality Indices on a scale of Good (1) to Very Poor (5), the CAQI Air Quality Index report refers to
-     * the Air Quality Indices as a level of pollutants on a scale of Very Low (1) to Very High (5). Numerically they
-     * are equivalent but the English-language meaning is different. This enumerated type uses the CAQI
-     * nomenclature.</p>
-     *
-     * <p>(n.b., {@link AirQuality#UNKNOWN_AIR_QUALITY} is a catch-all when no air quality data is present.)</p>
-     *
-     * @see <a href="https://openweathermap.org/api/air-pollution">OpenWeathermap Air Pollution API</a>
-     * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality Index entry on Wikipedia</a>
-     * @see
-     * <a href="https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI Air Quality Index</a>
-     */
-    public enum AirQuality {
-        UNKNOWN_AIR_QUALITY,
-        VERY_LOW,       // aqi==1 "Good" in openweathermap.org/api/air-pollution
-        LOW,            // aqi==2 "Fair" in openweathermap.org/api/air-pollution
-        MEDIUM,         // aqi==3 "Moderate" in openweathermap.org/api/air-pollution
-        HIGH,           // aqi==4 "Poor" in openweathermap.org/api/air-pollution
-        VERY_HIGH,      // aqi==5 "Very Poor" in openweathermap.org/api/air-pollution
-    }
-
-    /**
-     * Supported data sets, a subset of the documented OpenWeathermap APIs.
-     */
-    public static final Set<String> allowableDataSets = Set.of(
-            "weather",
-            "onecall", "onecall/timemachine",
-            "forecast",
-            "air_pollution", "air_pollution/forecast", "air_pollution/history",
-            "direct", "reverse"         // geocoding
-            // "stations", "triggers"   excluded because PUT/POST calls are not supported here
-            // "map"                    excluded because it isn't JSON and also appears not to be a REST call
-    );
-
-    public static final Date IMPOSSIBLE_DATE = new Date(Long.MIN_VALUE);
-    public static final String PROTOCOL = "http";
-    public static final String REST_AUTHORITY = "api.openweathermap.org";
-
-    protected final Connection dataSource;
-    protected String dataSet;
-    protected String REST_PATH;     // Should be able to declare this as final, but static analysis doesn't see that
-
-    protected JSONObject data;
-    protected Date currentTimestamp;
-
-    /**
-     * <p>Constructor to be used when connecting to OpenWeather data stored in a local file.</p>
-     *
-     * <p><i>Note</i>: in the case of Air Pollution Forecast and Air Pollution History, the data set is of the form
-     * "air_pollution/forecast" and "air_pollution/history".</p>
-     *
-     * @param fileDataSet directory containing the specified file; must correspond to one of the
-     *                    <a href="https://openweathermap.org/api">OpenWeathermap.org APIs</a>
-     * @throws IllegalArgumentException if {@code fileDataSet} does not correspond to an OpenWeathermap.org API
-     */
-    public OpenWeatherConnector(String fileDataSet) throws IllegalArgumentException {
-        initializeFields(fileDataSet);
-        dataSource = new FileConnection(fileDataSet);
-    }
-
-    /**
-     * <p>Constructor to be used when connecting to <a href="https://openweathermap.org">OpenWeathermap.org</a>s's
-     * REST API.</p>
-     *
-     * <p><i>Note</i>: in the case of Air Pollution Forecast and Air Pollution History, the data set is of the form
-     * "air_pollution/forecast" and "air_pollution/history".</p>
-     *
-     * @param restDataSet specific <a href="https://openweathermap.org/api">OpenWeathermap.org API</a> to be used
-     * @param apiKey      token provided by <a href="https://openweathermap.org">OpenWeathermap.org</a>
-     *                    to authenticate requester and grant appropriate privileges
-     * @throws IllegalArgumentException if {@code fileDataSet} does not correspond to an OpenWeathermap.org API
-     */
-    public OpenWeatherConnector(String restDataSet, String apiKey) throws IllegalArgumentException {
-        initializeFields(restDataSet);
-        dataSource = new RestConnection(PROTOCOL, REST_AUTHORITY, REST_PATH + restDataSet, apiKey);
-    }
-
-    private void initializeFields(String intendedDataSet) throws IllegalArgumentException {
-        if (!allowableDataSets.contains(intendedDataSet)) {
-            throw new IllegalArgumentException(intendedDataSet + " is not a valid data set.");
-        }
-        dataSet = intendedDataSet;
-        switch (dataSet) {
-            case "weather":
-            case "onecall":
-            case "onecall/timemachine":
-            case "forecast":
-            case "air_pollution":
-            case "air_pollution/forecast":
-            case "air_pollution/history":
-                REST_PATH = "/data/2.5/";
-                break;
-            case "direct":
-            case "reverse":
-                REST_PATH = "/geo/1.0/";
-                break;
-            default:
-                REST_PATH = "unknown";
-        }
-        data = null;
-        currentTimestamp = null;
-    }
-
-    /**
-     * Retrieves requested data from the data set. Must be called at least once (without data, the other methods have
-     * no data to work with). The data will be stored as part of the {@link OpenWeatherConnector} instance; however,
-     * the JSON string will also be returned.
-     *
-     * @param requestedData the data to be retrieved. If connected to the local file system, this is the name of the
-     *                      file with the data. If connected to
-     *                      <a href="https://openweathermap.org">OpenWeathermap.org/api</a>
-     *                      's REST API, this is the query string.
-     * @return JSON string for the requested data
-     * @throws IOException if the data cannot be retrieved
-     */
-    public String retrieveData(String requestedData) throws IOException {
-        try {
-            data = dataSource.get(requestedData);
-        } catch (FileNotFoundException fileNotFoundException) {
-            if (dataSource instanceof RestConnection) {
-                throw new IOException("Could not access \"" + dataSet + "\" dataset at " + REST_AUTHORITY + ".",
-                        fileNotFoundException);
-            } else {
-                throw fileNotFoundException;    // For FileConnection, this exception is exactly what's on the label,
-            }                                   // except that we'd more likely see a NullPointerException...
-        } catch (NullPointerException nullPointerException) {
-            if (dataSource instanceof FileConnection) {
-                FileNotFoundException newException = new FileNotFoundException("File " + requestedData + " not found.");
-                newException.initCause(nullPointerException);
-                throw newException;
-            } else {
-                throw nullPointerException;     // Not going to try to predict why RestConnection generates NPE
-            }
-        } catch (ParseException parseException) {
-            String message;
-            if (dataSource instanceof FileConnection) {
-                message = "Error while parsing file " + requestedData + ".";
-            } else if (dataSource instanceof RestConnection) {
-                message = "Error while parsing the " + dataSet + " response from " + REST_AUTHORITY + ".";
-            } else {
-                message = "Error while parsing requested data.";
-            }
-            throw new IOException(message, parseException);
-        }
-        checkForDataReadiness(null);
-        long unixTime = extractLongFromJSON(data, "dt", extractLongFromJSON(data, "current", "dt",
-                Long.MIN_VALUE));
-        if (unixTime == Long.MIN_VALUE && data.containsKey("list") && ((JSONArray)data.get("list")).size() == 1) {
-            // this is how current air quality data is reported
-            unixTime = (Long)((JSONObject)((JSONArray)data.get("list")).get(0)).get("dt");
-        }
-        currentTimestamp = unixTime == Long.MIN_VALUE ? IMPOSSIBLE_DATE : new Date(unixTime * 1000);
-        return data.toJSONString();
-    }
-
-    /*
-     * Helper Methods
-     */
-
-    /**
-     * Checks whether {@link #data} was populated by calling {@link #retrieveData(String)} and whether the calling
-     * method can use the dataset specified in the constructor call.
-     *
-     * @param supportedDataSets the datasets that are relevant to the calling method or {@code null} if all datasets are
-     *                         relevant
-     * @throws IllegalStateException if no data has been retrieved using {@link #retrieveData(String)}
-     * @throws UnsupportedOperationException if the dataset specified in the constructor call does not apply to the
-     * method that called {@code checkForDataPresence(Set)}
-     */
-    private void checkForDataReadiness(Set<String> supportedDataSets)
-            throws IllegalStateException, UnsupportedOperationException {
-        if (data == null) {
-            throw new IllegalStateException("No data has been retrieved from the " + dataSet + " dataset.");
-        }
-        if (supportedDataSets != null && !supportedDataSets.contains(dataSet)) {
-            throw new UnsupportedOperationException("Attempted to call method on an inapplicable dataset (" + dataSet +
-                    "). Applicable dataset(s): " + supportedDataSets + ".");
-        }
-    }
-
-    /**
-     * Returns value associated with the key in the JSON object. The caller is responsible for making sure that the
-     * JSON object is not null; however, the caller does <i>not</i> need to establish that the key is present.
-     * Returns the default value if the key is not present.
-     *
-     * @param jsonObject   JSON object that may contain the key and value of interest
-     * @param key          the key of interest
-     * @param defaultValue the value to be returned if the key is not present
-     * @return the value of interest, or the default value if the key is not present
-     */
-    private double extractDoubleFromJSON(JSONObject jsonObject, String key, double defaultValue) {
-        double returnValue = defaultValue;
-        if (jsonObject.containsKey(key)) {
-            Number value = (Number)jsonObject.get(key);
-            returnValue = value == null ? defaultValue : value.doubleValue();
-        }
-        return returnValue;
-    }
-
-    /**
-     * Returns value associated with the key in a second-level JSON object in the specified JSON object. The caller
-     * is responsible for making sure that the JSON object is not null; however, the caller does <i>not</i> need to
-     * establish that the key is present. Returns the default value if the key is not present.
-     *
-     * @param jsonObject    JSON object that may contain the key and value of interest
-     * @param topLevelField the key to access the second-level JSON object
-     * @param subField      the key of interest in the second-level JSON object
-     * @param defaultValue  the value to be returned if the key is not present
-     * @return the value of interest, or the default value if the key is not present
-     */
-    private double extractDoubleFromJSON(JSONObject jsonObject, String topLevelField, String subField,
-                                         double defaultValue) {
-        double returnValue = defaultValue;
-        if (jsonObject.containsKey(topLevelField)) {
-            JSONObject secondLevelJsonObject = (JSONObject)jsonObject.get(topLevelField);
-            returnValue = extractDoubleFromJSON(secondLevelJsonObject, subField, defaultValue);
-        }
-        return returnValue;
-    }
-
-    /**
-     * Returns value associated with the key in the JSON object. The caller is responsible for making sure that the
-     * JSON object is not null; however, the caller does <i>not</i> need to establish that the key is present.
-     * Returns the default value if the key is not present.
-     *
-     * @param jsonObject   JSON object that may contain the key and value of interest
-     * @param key          the key of interest
-     * @param defaultValue the value to be returned if the key is not present
-     * @return the value of interest, or the default value if the key is not present
-     */
-    private long extractLongFromJSON(JSONObject jsonObject, String key, long defaultValue) {
-        long returnValue = defaultValue;
-        if (jsonObject.containsKey(key)) {
-            Long value = (Long)jsonObject.get(key);
-            returnValue = value == null ? defaultValue : value;
-        }
-        return returnValue;
-    }
-
-    /**
-     * Returns value associated with the key in a second-level JSON object in the specified JSON object. The caller
-     * is responsible for making sure that the JSON object is not null; however, the caller does <i>not</i> need to
-     * establish that the key is present. Returns the default value if the key is not present.
-     *
-     * @param jsonObject    JSON object that may contain the key and value of interest
-     * @param topLevelField the key to access the second-level JSON object
-     * @param subField      the key of interest in the second-level JSON object
-     * @param defaultValue  the value to be returned if the key is not present
-     * @return the value of interest, or the default value if the key is not present
-     */
-    private long extractLongFromJSON(JSONObject jsonObject, String topLevelField, String subField, long defaultValue) {
-        long returnValue = defaultValue;
-        if (jsonObject.containsKey(topLevelField)) {
-            JSONObject secondLevelJsonObject = (JSONObject)jsonObject.get(topLevelField);
-            returnValue = extractLongFromJSON(secondLevelJsonObject, subField, defaultValue);
-        }
-        return returnValue;
-    }
-
-    /**
-     * Returns object in the list associated with the key, at the specified timestamp. Returns null if the list is not
-     * present, or if there is no list entry at the timestamp.
-     *
-     * @param listName  the key to access the list
-     * @param timestamp the timestamp of the list entry
-     * @return the object of interest, or null if the list or the timestamp are not present
-     */
-    private JSONObject getListEntry(String listName, Date timestamp) {
-        JSONObject listEntry = null;
-        if (data.containsKey(listName)) {
-            JSONArray list = (JSONArray)data.get(listName);
-            for (Object entry : list) {
-                if ((Long)((JSONObject)entry).get("dt") == timestamp.getTime() / 1000) {
-                    listEntry = (JSONObject)entry;
-                }
-            }
-        }
-        return listEntry;
-    }
-
-    /*
-     * Wrapper methods for all reports
-     */
-
-    /**
-     * <p>Provides the latitude for the weather's location.</p>
-     * <p>Available for all datasets.</p>
-     *
-     * @return location's latitude
-     */
-    public double getLatitude() {
-        checkForDataReadiness(null);
-        JSONObject locationContainer = data;
-        if (data.containsKey("city")) {
-            locationContainer = (JSONObject)data.get("city");
-        }
-        if (dataSet.startsWith("onecall")) {
-            return extractDoubleFromJSON(locationContainer, "lat", Double.NaN);
-        } else {
-            return extractDoubleFromJSON(locationContainer, "coord", "lat", Double.NaN);
-        }
-    }
-
-    /**
-     * <p>Provides the longitude for the weather's location.</p>
-     * <p>Available for all datasets.</p>
-     *
-     * @return location's longitude
-     */
-    public double getLongitude() {
-        checkForDataReadiness(null);
-        JSONObject locationContainer = data;
-        if (data.containsKey("city")) {
-            locationContainer = (JSONObject)data.get("city");
-        }
-        if (dataSet.startsWith("onecall")) {
-            return extractDoubleFromJSON(locationContainer, "lon", Double.NaN);
-        } else {
-            return extractDoubleFromJSON(locationContainer, "coord", "lon", Double.NaN);
-        }
-    }
-
-    /**
-     * <p>Provides the date and time for the current weather, or {@link #IMPOSSIBLE_DATE} if no valid timestamp
-     * exists.</p>
-     * <p>Available for all datasets with data for the present.</p>
-     *
-     * @return timestamp for the weather observations
-     */
-    public Date getTimestamp() {
-        checkForDataReadiness(null);
-        return currentTimestamp;
-    }
-
-    /**
-     * Extracts epoch-based timestamps from the specified JSON list and places {@link Date} timestamps into the provided
-     * {@link List}.
-     * @param jsonListName the name of the JSON list containing data with timestamps
-     * @param timestamps the possibly-nonempty {@link List} to place the {@link Date} timestamps in
-     */
-    private void moveTimestampsFromJsonArrayToJavaList(String jsonListName, List<Date> timestamps) {
-        if (data.containsKey(jsonListName)) {
-            JSONArray entries = (JSONArray)data.get(jsonListName);
-            if (entries != null) {
-                for (Object entry : entries) {
-                    long unixTime = (Long)((JSONObject)entry).get("dt");
-                    timestamps.add(new Date(unixTime * 1000));
-                }
-            }
-        }
-    }
-
-    /**
-     * <p>Provides all dates and times for reports with multiple timestamps.</p>
-     * <p>Available for all datasets with data in the past or the future.</p>
-     *
-     * @return list of timestamps for the weather observations
-     */
-    public List<Date> getTimestamps() {
-        checkForDataReadiness(null);
-        Set<String> possibleListNames = Set.of("list", "minutely", "hourly", "daily");
-        List<Date> timestamps = new ArrayList<>();
-        for (String listName : possibleListNames) {
-            moveTimestampsFromJsonArrayToJavaList(listName, timestamps);
-        }
-        timestamps.sort(null);
-        return List.copyOf(timestamps);
-    }
-
-    /**
-     * <p>Provides the dates and times for a specific list, for reports with multiple timestamps.</p>
-     * <p>Available for all datasets with data in the past or the future.</p>
-     *
-     * @param listName the name of the list whose timestamps are of interest
-     * @return list of timestamps for the weather observations
-     */
-    public List<Date> getTimestamps(String listName) {
-        checkForDataReadiness(null);
-        List<Date> timestamps = new ArrayList<>();
-        moveTimestampsFromJsonArrayToJavaList(listName, timestamps);
-        timestamps.sort(null);
-        return List.copyOf(timestamps);
-    }
-
-    /*
-     * Wrapper methods for current and forecasted weather
-     */
-
-    /**
-     * <p>Provides the broad categories for the weather reported in the provided JSON object. If there are more than
-     * one category provided, the "primary" category will at the head of the list. The weather categories are guaranteed
-     * to be in the same order as the corresponding descriptions provided by {@link #getWeatherDescriptions()}.</p>
-     * <p>The caller is responsible for ensuring that data is present.</p>
-     *
-     * @param jsonObject the object containing the weather data
-     * @return list of weather categories
-     * @see #getWeatherDescriptions()
-     */
-    private List<WeatherCategory> getWeatherCategories(JSONObject jsonObject) {
-        JSONArray weather = (JSONArray)jsonObject.get("weather");
-        List<WeatherCategory> categories;
-        if (weather != null) {
-            categories = new ArrayList<>(weather.size());
-            for (Object condition : weather) {
-                String category = ((JSONObject)condition).get("main").toString();
-                try {
-                    categories.add(WeatherCategory.valueOf(category.toUpperCase()));
-                } catch (IllegalArgumentException ignored) {
-                    categories.add(WeatherCategory.UNKNOWN_CATEGORY);
-                }
-            }
-        } else {
-            categories = new ArrayList<>(0);
-        }
-        return List.copyOf(categories);
-    }
-
-    /**
-     * <p>Provides the broad categories for the current weather. If there are more than one category provided, the
-     * "primary" category will at the head of the list. The weather categories are guaranteed to be in
-     * the same order as the corresponding descriptions provided by {@link #getWeatherDescriptions()}.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return list of weather categories
-     * @see #getWeatherDescriptions()
-     */
-    public List<WeatherCategory> getWeatherCategories() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        return getWeatherCategories(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data);
-    }
-
-    /**
-     * <p>Provides the broad categories for the forecasted weather. If there are more than one category provided, the
-     * "primary" category will at the head of the list. The weather categories are guaranteed to be in the same order
-     * as the corresponding descriptions provided by {@link #getWeatherDescriptions()}.</p>
-     * <p>Available for the "forecast" and "onecall" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return list of forecasted weather categories
-     * @see #getWeatherDescriptions()
-     */
-    public List<WeatherCategory> getWeatherCategories(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        String listName = "list";
-        if (dataSet.equals("onecall")) {
-            List<Date> hours = getTimestamps("hourly");
-            listName = hours.contains(timestamp) ? "hourly" : "daily";
-        }
-        return getWeatherCategories(getListEntry(listName, timestamp));
-    }
-
-    /**
-     * <p>Provides descriptions of the weather reported in the provided JSON object. If there are more than one weather
-     * description provided, the "primary" description will be at the head of the list. The weather descriptions are
-     * guaranteed to be in the same order as the corresponding categories provided by
-     * {@link #getWeatherCategories()}.</p>
-     * <p>The caller is responsible for ensuring that data is present.</p>
-     *
-     * @param jsonObject the object containing the weather data
-     * @return list of weather descriptions
-     * @see #getWeatherCategories()
-     */
-    private List<String> getWeatherDescriptions(JSONObject jsonObject) {
-        JSONArray weather = (JSONArray)jsonObject.get("weather");
-        List<String> descriptions;
-        if (weather != null) {
-            descriptions = new ArrayList<>(weather.size());
-            for (Object condition : weather) {
-                descriptions.add(((JSONObject)condition).get("description").toString());
-            }
-        } else {
-            descriptions = new ArrayList<>(0);
-        }
-        return List.copyOf(descriptions);
-    }
-
-    /**
-     * <p>Provides descriptions of the current weather. If there are more than one weather description provided, the
-     * "primary" description will be at the head of the list. The weather descriptions are guaranteed to be in the
-     * same order as the corresponding categories provided by {@link #getWeatherCategories()}.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return list of weather descriptions
-     * @see #getWeatherCategories()
-     */
-    public List<String> getWeatherDescriptions() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        return getWeatherDescriptions(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data);
-    }
-
-    /**
-     * <p>Provides descriptions of the forecasted weather. If there are more than one weather description provided,
-     * the "primary" description will be at the head of the list. The weather descriptions are guaranteed to be in
-     * the same order as the corresponding categories provided by {@link #getWeatherCategories()}.</p>
-     * <p>Available for the "forecast" and "onecall" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return list of forecasted weather descriptions
-     * @see #getWeatherCategories()
-     */
-    public List<String> getWeatherDescriptions(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        String listName = "list";
-        if (dataSet.equals("onecall")) {
-            List<Date> hours = getTimestamps("hourly");
-            listName = hours.contains(timestamp) ? "hourly" : "daily";
-        }
-        return getWeatherDescriptions(getListEntry(listName, timestamp));
-    }
-
-    /**
-     * <p>Provides the current visibility in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current visibility, or {@link Long#MIN_VALUE} if visibility is not in current observation
-     */
-    public long getVisibility() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        return extractLongFromJSON(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data,
-                "visibility", Long.MIN_VALUE);
-    }
-
-    /**
-     * <p>Provides the forecasted visibility in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "forecast" and "onecall" (hourly only) datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted visibility, or {@link Long#MIN_VALUE} if visibility is not in the forecast
-     */
-    public long getVisibility(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        if (dataSet.equals("onecall") && !getTimestamps("hourly").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
-        }
-        String listName = dataSet.equals("onecall") ? "hourly" : "list";
-        return extractLongFromJSON(getListEntry(listName, timestamp), "visibility", Long.MIN_VALUE);
-    }
-
-    /**
-     * <p>Provides the current temperature in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current temperature, or {@link Double#NaN} if temperature is not in current observation
-     */
-    public double getTemperature() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        return extractDoubleFromJSON(data,
-                dataSet.startsWith("onecall") ? "current" : "main", "temp", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted temperature in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "forecast" and "onecall" (hourly only) datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted temperature, or {@link Double#NaN} if temperature is not in the forecast
-     */
-    public double getTemperature(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        if (dataSet.equals("forecast")) {
-            return extractDoubleFromJSON(getListEntry("list", timestamp), "main", "temp", Double.NaN);
-        } else if (dataSet.equals("onecall") && getTimestamps("hourly").contains(timestamp)) {
-            return extractDoubleFromJSON(getListEntry("hourly", timestamp), "temp", Double.NaN);
-        } else {
-            throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
-        }
-    }
-
-    /**
-     * <p>Provides the forecasted morning temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted morning temperature, or {@link Double#NaN} if morning temperature is not in the forecast
-     */
-    public double getMorningTemperature(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "morn", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted daytime temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted daytime temperature, or {@link Double#NaN} if daytime temperature is not in the forecast
-     */
-    public double getDaytimeTemperature(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "day", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted evening temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted evening temperature, or {@link Double#NaN} if evening temperature is not in the forecast
-     */
-    public double getEveningTemperature(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "eve", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted nighttime temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted nighttime temperature, or {@link Double#NaN} if nighttime temperature is not in the
-     * forecast
-     */
-    public double getNighttimeTemperature(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "night", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted daily low temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted daily low temperature, or {@link Double#NaN} if daily low temperature is not in the
-     * forecast
-     */
-    public double getLowTemperature(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "min", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted daily high temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted daily high temperature, or {@link Double#NaN} if daily high temperature is not in the
-     * forecast
-     */
-    public double getHighTemperature(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "max", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the current relative humidity (percent of saturation).</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current humidity, or {@link Long#MIN_VALUE} if visibility is not in current observation
-     */
-    public long getHumidity() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        return extractLongFromJSON(data,
-                dataSet.startsWith("onecall") ? "current" : "main", "humidity", Long.MIN_VALUE);
-    }
-
-    /**
-     * <p>Provides the forecasted relative humidity (percent of saturation).</p>
-     * <p>Available for the "forecast" and "onecall" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted humidity, or {@link Long#MIN_VALUE} if visibility is not in the forecast
-     */
-    public long getHumidity(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        if (dataSet.equals("forecast")) {
-            return extractLongFromJSON(getListEntry("list", timestamp), "main", "humidity", Long.MIN_VALUE);
-        } else if (dataSet.equals("onecall")) {
-            return extractLongFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily",
-                    timestamp), "humidity", Long.MIN_VALUE);
-        } else {
-            return Long.MIN_VALUE;
-        }
-    }
-
-    /**
-     * <p>Provides the current dew point in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" dataset.</p>
-     *
-     * @return the current dew point, or {@link Double#NaN} if dew point is not in current observation
-     */
-    public double getDewPoint() {
-        checkForDataReadiness(Set.of("onecall"));
-        return extractDoubleFromJSON(data, "current", "dew_point", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted dew point in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted dew point, or {@link Double#NaN} if dew point is not in the forecast
-     */
-    public double getDewPoint(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        return extractDoubleFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily",
-                timestamp), "dew_point", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the current "feels like" temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current "feels like" temperature, or {@link Double#NaN} if "feels like" temperature is not in
-     * current observation
-     */
-    public double getFeelsLike() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        return extractDoubleFromJSON(data,
-                dataSet.startsWith("onecall") ? "current" : "main", "feels_like", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted "feels like" temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "forecast" and "onecall" (hourly only) datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted "feels like" temperature, or {@link Double#NaN} if "feels like" temperature is not in
-     * the forecast
-     */
-    public double getFeelsLike(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        if (dataSet.equals("forecast")) {
-            return extractDoubleFromJSON(getListEntry("list", timestamp), "main", "feels_like", Double.NaN);
-        } else if (dataSet.equals("onecall") && getTimestamps("hourly").contains(timestamp)) {
-            return extractDoubleFromJSON(getListEntry("hourly", timestamp), "feels_like", Double.NaN);
-        } else {
-            throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
-        }
-    }
-
-    /**
-     * <p>Provides the forecasted morning "feels like" temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted morning "feels like" temperature, or {@link Double#NaN} if morning "feels like"
-     * temperature is not in the forecast
-     */
-    public double getMorningFeelsLike(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "morn", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted "feels like" daytime temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted daytime "feels like" temperature, or {@link Double#NaN} if daytime "feels like"
-     * temperature is not in the forecast
-     */
-    public double getDaytimeFeelsLike(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "day", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted evening "feels like" temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted evening "feels like" temperature, or {@link Double#NaN} if evening "feels like"
-     * temperature is not in the forecast
-     */
-    public double getEveningFeelsLike(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "eve", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted nighttime "feels like" temperature in the default
-     * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to
-     * {@link #retrieveData(String)}.</p>
-     * <p>Available for the "onecall" (daily only) dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted nighttime "feels like" temperature, or {@link Double#NaN} if nighttime "feels like"
-     * temperature is not in the
-     * forecast
-     */
-    public double getNighttimeFeelsLike(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("daily").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "night", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the current pressure in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current pressure, or {@link Long#MIN_VALUE} if pressure is not in current observation
-     */
-    public long getPressure() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        return extractLongFromJSON(data,
-                dataSet.startsWith("onecall") ? "current" : "main", "pressure", Long.MIN_VALUE);
-    }
-
-    /**
-     * <p>Provides the forecasted pressure in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "forecast" and "onecall" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted pressure, or {@link Long#MIN_VALUE} if pressure is not in the forecast
-     */
-    public long getPressure(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        if (dataSet.equals("forecast")) {
-            return extractLongFromJSON(getListEntry("list", timestamp), "main", "pressure", Long.MIN_VALUE);
-        } else if (dataSet.equals("onecall")) {
-            return extractLongFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily",
-                    timestamp), "pressure", Long.MIN_VALUE);
-        } else {
-            return Long.MIN_VALUE;
-        }
-    }
-
-    /**
-     * <p>Provides the current wind direction, in degrees.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current wind direction, or {@link Long#MIN_VALUE} if winds are not in current observation
-     */
-    public long getWindDirection() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        if (dataSet.startsWith("onecall")) {
-            return extractLongFromJSON(data, "current", "wind_deg", Long.MIN_VALUE);
-        } else {
-            return extractLongFromJSON(data, "wind", "deg", Long.MIN_VALUE);
-        }
-    }
-
-    /**
-     * <p>Provides the forecasted wind direction, in degrees.</p>
-     * <p>Available for the "forecast" and "onecall" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted wind direction, or {@link Long#MIN_VALUE} if winds are not in the forecast
-     */
-    public long getWindDirection(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        if (dataSet.equals("forecast")) {
-            return extractLongFromJSON(getListEntry("list", timestamp), "wind", "deg", Long.MIN_VALUE);
-        } else if (dataSet.equals("onecall")) {
-            return extractLongFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily",
-                    timestamp), "wind_deg", Long.MIN_VALUE);
-        } else {
-            return Long.MIN_VALUE;
-        }
-    }
-
-    /**
-     * <p>Provides the current wind speed in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current wind speed, or 0.0 if winds are not in current observation
-     */
-    public double getWindSpeed() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        if (dataSet.startsWith("onecall")) {
-            return extractDoubleFromJSON(data, "current", "wind_speed", 0.0);
-        } else {
-            return extractDoubleFromJSON(data, "wind", "speed", 0.0);
-        }
-    }
-
-    /**
-     * <p>Provides the forecasted wind speed in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "forecast" and "onecall" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted wind speed, or 0.0 if winds are not in the forecast
-     */
-    public double getWindSpeed(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        if (dataSet.equals("forecast")) {
-            return extractDoubleFromJSON(getListEntry("list", timestamp), "wind", "speed", 0.0);
-        } else if (dataSet.equals("onecall")) {
-            return extractDoubleFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily",
-                    timestamp), "wind_speed", 0.0);
-        } else {
-            return 0.0;
-        }
-    }
-
-    /**
-     * <p>Provides the current wind gust in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current wind gust, or current wind speed if wind gust is not in current observation
-     */
-    public double getWindGust() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        if (dataSet.startsWith("onecall")) {
-            return extractDoubleFromJSON(data, "current", "wind_gust", getWindSpeed());
-        } else {
-            return extractDoubleFromJSON(data, "wind", "gust", getWindSpeed());
-        }
-    }
-
-    /**
-     * <p>Provides the forecasted wind gust in the default <a href="https://openweathermap.org/current#data">units</a>
-     * or those specified in the call to {@link #retrieveData(String)}.</p>
-     * <p>Available for the "forecast" and "onecall" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted wind gust, or current wind speed if wind gust is not in the forecast
-     */
-    public double getWindGust(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        if (dataSet.equals("forecast")) {
-            return extractDoubleFromJSON(getListEntry("list", timestamp), "wind", "gust", getWindSpeed(timestamp));
-        } else if (dataSet.equals("onecall")) {
-            return extractDoubleFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily",
-                    timestamp), "wind_gust", getWindSpeed(timestamp));
-        } else {
-            return getWindSpeed(timestamp);
-        }
-    }
-
-    /**
-     * <p>Provides the current UV Index.</p>
-     * <p>Available for the "onecall" dataset.</p>
-     *
-     * @return the current UV Index, or {@link Double#NaN} if the UV Index is not in current observation
-     */
-    public double getUltravioletIndex() {
-        checkForDataReadiness(Set.of("onecall"));
-        return extractDoubleFromJSON(data, "current", "uvi", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the forecasted UV Index.</p>
-     * <p>Available for the "onecall" dataset.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted UV Index, or {@link Double#NaN} if the UV Index is not in the forecast
-     */
-    public double getUltravioletIndex(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        return extractDoubleFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily",
-                timestamp), "uvi", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the current cloud cover percentage (cloudiness).</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current cloudiness, or 0 if cloudiness is not in current observation
-     */
-    public long getCloudCover() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        if (dataSet.startsWith("onecall")) {
-            return extractLongFromJSON(data, "clouds", 0);
-        } else {
-            return extractLongFromJSON(data, "clouds", "all", 0);
-        }
-    }
-
-    /**
-     * <p>Provides the forecasted cloud cover percentage (cloudiness).</p>
-     * <p>Available for the "forecast" and "onecall" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted cloudiness, or 0 if cloudiness is not in current observation
-     */
-    public long getCloudCover(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        if (dataSet.startsWith("onecall")) {
-            return extractLongFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily",
-                    timestamp), "clouds", 0);
-        } else {
-            return extractLongFromJSON(getListEntry("list", timestamp), "clouds", "all", 0);
-        }
-    }
-
-    /**
-     * <p>Provides the forecasted probability of rain, on a 0.0-1.0 scale.</p>
-     * <p>Available for the "forecast" and "onecall" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return the forecasted probability of precipitation, or NaN if cloudiness is not in current observation
-     */
-    public double getProbabilityOfPrecipitation(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast", "onecall"));
-        String listName = "list";
-        if (dataSet.equals("onecall")) {
-            List<Date> hours = getTimestamps("hourly");
-            listName = hours.contains(timestamp) ? "hourly" : "daily";
-        }
-        return extractDoubleFromJSON(getListEntry(listName, timestamp), "pop", Double.NaN);
-    }
-
-    /**
-     * <p>Provides the one-hour rainfall total column, in millimeters.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current one-hour rainfall total, or 0.0 if rain volume is not in current observation
-     */
-    public double getOneHourRainfall() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        return extractDoubleFromJSON(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data,
-                "rain", "1h", 0.0);
-    }
-
-    /**
-     * <p>Provides the total rain column, in millimeters, forecasted for the one hour before the specified
-     * timestamp.</p>
-     * <p>Available for the "onecall" (hourly only) dataset.</p>
-     *
-     * @param timestamp the timestamp for the forecasted rainfall
-     * @return the forecasted one-hour rainfall total, or 0.0 if rain volume is not in the forecast
-     */
-    public double getOneHourRainfall(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("hourly").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("hourly", timestamp), "rain", "1h", 0.0);
-    }
-
-    /**
-     * <p>Provides the three-hour rainfall total column, in millimeters.</p>
-     * <p>Available for the "weather" dataset.</p>
-     *
-     * @return the current three-hour rainfall total, or 0.0 if rain volume is not in current observation
-     */
-    public double getThreeHourRainfall() {
-        checkForDataReadiness(Set.of("weather"));
-        return extractDoubleFromJSON(data, "rain", "3h", getOneHourRainfall());
-    }
-
-    /**
-     * <p>Provides the total rain column, in millimeters, forecasted for the three hours before the specified
-     * timestamp.</p>
-     * <p>Available for the "forecast" dataset.</p>
-     *
-     * @param timestamp the timestamp for the forecasted rainfall
-     * @return the forecasted three-hour rainfall total, or 0.0 if rain volume is not in the forecast
-     */
-    public double getThreeHourRainfall(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast"));
-        return extractDoubleFromJSON(getListEntry("list", timestamp), "rain", "3h", 0.0);
-    }
-
-    /**
-     * <p>Provides the one-hour snowfall total column, in millimeters.</p>
-     * <p>Available for the "weather" and "onecall" datasets.</p>
-     *
-     * @return the current one-hour snowfall total, or 0.0 if snow volume is not in current observation
-     */
-    public double getOneHourSnowfall() {
-        checkForDataReadiness(Set.of("weather", "onecall"));
-        return extractDoubleFromJSON(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data,
-                "snow", "1h", 0.0);
-    }
-
-    /**
-     * <p>Provides the total snow column, in millimeters, forecasted for the one hour before the specified
-     * timestamp.</p>
-     * <p>Available for the "onecall" (hourly only) dataset.</p>
-     *
-     * @param timestamp the timestamp for the forecasted snowfall
-     * @return the forecasted one-hour rainfall total, or 0.0 if rain volume is not in the forecast
-     */
-    public double getOneHourSnowfall(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("hourly").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("hourly", timestamp), "snow", "1h", 0.0);
-    }
-
-    /**
-     * <p>Provides the three-hour snowfall total column, in millimeters.</p>
-     * <p>Available for the "weather" dataset.</p>
-     *
-     * @return the current three-hour snowfall total, or 0.0 if snow volume is not in current observation
-     */
-    public double getThreeHourSnowfall() {
-        checkForDataReadiness(Set.of("weather"));
-        return extractDoubleFromJSON(data, "snow", "3h", getOneHourSnowfall());
-    }
-
-    /**
-     * <p>Provides the total snow column, in millimeters, forecasted for the three hours before the specified
-     * timestamp.</p>
-     * <p>Available for the "forecast" dataset.</p>
-     *
-     * @param timestamp the timestamp for the forecasted snowfall
-     * @return the forecasted three-hour snowfall total, or 0.0 if snow volume is not in the forecast
-     */
-    public double getThreeHourSnowfall(Date timestamp) {
-        checkForDataReadiness(Set.of("forecast"));
-        return extractDoubleFromJSON(getListEntry("list", timestamp), "snow", "3h", 0.0);
-    }
-
-    /**
-     * <p>Provides the precipitation column, in millimeters, forecasted for the the specified minute. Not explicitly
-     * stated in the API specification, this appears to be a 1-hour total that does not distinguish between rain and
-     * snow.</p>
-     * <p>Available for the "onecall" dataset.</p>
-     *
-     * @param timestamp the timestamp for the forecasted precipitation
-     * @return the forecasted precipitation total, or 0.0 if precipitation volume is not in the forecast
-     */
-    public double getMinutelyPrecipitation(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        if (!getTimestamps("minutely").contains(timestamp)) {
-            throw new UnsupportedOperationException("This onecall datum is only available for minutely timestamps.");
-        }
-        return extractDoubleFromJSON(getListEntry("minutely", timestamp), "precipitation", 0.0);
-    }
-
-    /**
-     * <p>Provides the rain column, in millimeters, forecasted for the the specified day. Not explicitly stated in the
-     * API specification, this appears to be a daily total.</p>
-     * <p>Available for the "onecall" dataset.</p>
-     *
-     * @param timestamp the timestamp for the forecasted rainfall
-     * @return the forecasted rain total, or 0.0 if precipitation volume is not in the forecast
-     */
-    public double getDailyRainfall(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "rain", 0.0);
-    }
-
-    /**
-     * <p>Provides the snow column, in millimeters, forecasted for the the specified day. Not explicitly stated in the
-     * API specification, this appears to be a daily total.</p>
-     * <p>Available for the "onecall" dataset.</p>
-     *
-     * @param timestamp the timestamp for the forecasted snowfall
-     * @return the forecasted snow total, or 0.0 if precipitation volume is not in the forecast
-     */
-    public double getDailySnowfall(Date timestamp) {
-        checkForDataReadiness(Set.of("onecall"));
-        return extractDoubleFromJSON(getListEntry("daily", timestamp), "snow", 0.0);
-    }
-
-    /*
-     * Wrapper methods for Air Quality
-     */
-
-    /**
-     * Returns the concentration for the specified pollutant at the specified timestamp from the list of air quality
-     * entries.
-     *
-     * @param timestamp the timestamp for the air quality entry
-     * @param pollutant the pollutant whose concentration is to be obtained
-     * @return the value associated with the specified pollutant at the specified timestamp
-     */
-    private double getPollutionData(Date timestamp, String pollutant) {
-        JSONObject currentEntry = getListEntry("list", timestamp);
-        if (currentEntry == null) {
-            return Double.NaN;
-        } else {
-            return extractDoubleFromJSON(currentEntry, "components", pollutant, Double.NaN);
-        }
-    }
-
-    /**
-     * <p>Provides the current basic Air Quality Index, using the European CAQI tables. This is a composite metric
-     * based on concentrations of nitrogen monoxide, ozone, coarse particulates, and optionally fine particulates.</p>
-     *
-     * <p>The air quality is reported on a range from {@link AirQuality#VERY_LOW} (good) to
-     * {@link AirQuality#VERY_HIGH} (very poor)</p>
-     *
-     * <p>Available for the "air_pollution" dataset.</p>
-     *
-     * @return air quality index at the requested timestamp
-     * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality Index entry on Wikipedia</a>
-     * @see
-     * <a href="https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI Air Quality Index</a>
-     */
-    public AirQuality getAirQualityIndex() {
-        checkForDataReadiness(Set.of("air_pollution"));
-        return getAirQualityIndex(currentTimestamp);
-    }
-
-    /**
-     * <p>Provides the current, historical, or forecasted basic Air Quality Index, using the European CAQI tables. This
-     * is a composite metric based on concentrations of nitrogen monoxide, ozone, coarse particulates, and optionally
-     * fine particulates.</p>
-     *
-     * <p>The air quality is reported on a range from {@link AirQuality#VERY_LOW} (good) to
-     * {@link AirQuality#VERY_HIGH} (very poor)</p>
-     *
-     * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return air quality index at the requested timestamp
-     * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality Index entry on Wikipedia</a>
-     * @see
-     * <a href="https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI Air Quality Index</a>
-     */
-    public AirQuality getAirQualityIndex(Date timestamp) {
-        checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
-        JSONObject currentEntry = getListEntry("list", timestamp);
-        int airQualityIndex = 0;
-        if (currentEntry != null) {
-            airQualityIndex = (int)extractLongFromJSON(currentEntry, "main", "aqi", 0);
-        }
-        return AirQuality.values()[airQualityIndex];
-    }
-
-    /**
-     * <p>Provides the current concentration of Carbon Monoxide (CO), in μg/m3</p>
-     * <p>Available for the "air_pollution" dataset.</p>
-     *
-     * @return current concentration of CO
-     */
-    public double getCarbonMonoxide() {
-        checkForDataReadiness(Set.of("air_pollution"));
-        return getCarbonMonoxide(currentTimestamp);
-    }
-
-    /**
-     * <p>Provides the current, historical, or forecasted concentration of Carbon Monoxide (CO), in μg/m3</p>
-     * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return concentration of CO at the requested timestamp
-     */
-    public double getCarbonMonoxide(Date timestamp) {
-        checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
-        return getPollutionData(timestamp, "co");
-    }
-
-    /**
-     * <p>Provides the current concentration of Nitrogen Monoxide (NO), in μg/m3</p>
-     * <p>Available for the "air_pollution" dataset.</p>
-     *
-     * @return current concentration of NO
-     */
-    public double getNitrogenMonoxide() {
-        checkForDataReadiness(Set.of("air_pollution"));
-        return getNitrogenMonoxide(currentTimestamp);
-    }
-
-    /**
-     * <p>Provides the current, historical, or forecasted concentration of Nitrogen Monoxide (NO), in μg/m3</p>
-     * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return concentration of NO at the requested timestamp
-     */
-    public double getNitrogenMonoxide(Date timestamp) {
-        checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
-        return getPollutionData(timestamp, "no");
-    }
-
-    /**
-     * <p>Provides the current concentration of Nitrogen Dioxide (NO2), in μg/m3</p>
-     * <p>Available for the "air_pollution" dataset.</p>
-     *
-     * @return current concentration of NO2
-     */
-    public double getNitrogenDioxide() {
-        checkForDataReadiness(Set.of("air_pollution"));
-        return getNitrogenDioxide(currentTimestamp);
-    }
-
-    /**
-     * <p>Provides the current, historical, or forecasted concentration of Nitrogen Dioxide (NO2), in μg/m3</p>
-     * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return concentration of NO2 at the requested timestamp
-     */
-    public double getNitrogenDioxide(Date timestamp) {
-        checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
-        return getPollutionData(timestamp, "no2");
-    }
-
-    /**
-     * <p>Provides the current concentration of Ozone (O3), in μg/m3</p>
-     * <p>Available for the "air_pollution" dataset.</p>
-     *
-     * @return current concentration of O3
-     */
-    public double getOzone() {
-        checkForDataReadiness(Set.of("air_pollution"));
-        return getOzone(currentTimestamp);
-    }
-
-    /**
-     * <p>Provides the current, historical, or forecasted concentration of Ozone (O3), in μg/m3</p>
-     * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return concentration of O3 at the requested timestamp
-     */
-    public double getOzone(Date timestamp) {
-        checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
-        return getPollutionData(timestamp, "o3");
-    }
-
-    /**
-     * <p>Provides the current concentration of Sulfur Dioxide (SO2), in μg/m3</p>
-     * <p>Available for the "air_pollution" dataset.</p>
-     *
-     * @return current concentration of SO2
-     */
-    public double getSulfurDioxide() {
-        checkForDataReadiness(Set.of("air_pollution"));
-        return getSulfurDioxide(currentTimestamp);
-    }
-
-    /**
-     * <p>Provides the current, historical, or forecasted concentration of Sulfur Dioxide (SO2), in μg/m3</p>
-     * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return concentration of SO2 at the requested timestamp
-     */
-    public double getSulfurDioxide(Date timestamp) {
-        checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
-        return getPollutionData(timestamp, "so2");
-    }
-
-    /**
-     * <p>Provides the current concentration of Fine Particulate Matter (PM2.5), in μg/m3</p>
-     * <p>Available for the "air_pollution" dataset.</p>
-     *
-     * @return current concentration of PM2.5
-     */
-    public double getFineParticulateMatter() {
-        checkForDataReadiness(Set.of("air_pollution"));
-        return getFineParticulateMatter(currentTimestamp);
-    }
-
-    /**
-     * <p>Provides the current, historical, or forecasted concentration of Fine Particulate Matter (PM2.5), in μg/m3</p>
-     * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return concentration of PM2.5 at the requested timestamp
-     */
-    public double getFineParticulateMatter(Date timestamp) {
-        checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
-        return getPollutionData(timestamp, "pm2_5");
-    }
-
-    /**
-     * <p>Provides the current concentration of Coarse Particulate Matter (PM10), in μg/m3</p>
-     * <p>Available for the "air_pollution" dataset.</p>
-     *
-     * @return current concentration of PM10
-     */
-    public double getCoarseParticulateMatter() {
-        checkForDataReadiness(Set.of("air_pollution"));
-        return getCoarseParticulateMatter(currentTimestamp);
-    }
-
-    /**
-     * <p>Provides the current, historical, or forecasted concentration of Coarse Particulate Matter (PM10), in
-     * μg/m3</p>
-     * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return concentration of PM10 at the requested timestamp
-     */
-    public double getCoarseParticulateMatter(Date timestamp) {
-        checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
-        return getPollutionData(timestamp, "pm10");
-    }
-
-    /**
-     * <p>Provides the current concentration of Ammonia (NH3), in μg/m3</p>
-     * <p>Available for the "air_pollution" dataset.</p>
-     *
-     * @return current concentration of NH3
-     */
-    public double getAmmonia() {
-        checkForDataReadiness(Set.of("air_pollution"));
-        return getAmmonia(currentTimestamp);
-    }
-
-    /**
-     * <p>Provides the current, historical, or forecasted concentration of Ammonia (NH3), in μg/m3</p>
-     * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p>
-     *
-     * @param timestamp the date/time corresponding to the desired data
-     * @return concentration of NH3 at the requested timestamp
-     */
-    public double getAmmonia(Date timestamp) {
-        checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
-        return getPollutionData(timestamp, "nh3");
-    }
+	/**
+	 * <p>
+	 * Top-level weather categories that may be reported in OpenWeather data.
+	 * </p>
+	 *
+	 * <p>
+	 * (n.b., {@link WeatherCategory#UNKNOWN_CATEGORY} is a catch-all for any
+	 * reported categories that are not a documented weather condition.)
+	 * </p>
+	 *
+	 * @see <a href="https://openweathermap.org/weather-conditions">OpenWeathermap
+	 *      Weather Conditions</a>
+	 */
+	public enum WeatherCategory {
+		UNKNOWN_CATEGORY,
+		THUNDERSTORM,	// Group 2xx
+		DRIZZLE, 		// Group 3xx
+		RAIN, 			// Group 5xx
+		SNOW, 			// Group 6xx
+						// Group 7xx (Atmosphere)
+		MIST, 				// 701
+		SMOKE, 				// 711
+		HAZE, 				// 721
+		DUST, 				// 731, 761
+		FOG, 				// 741
+		SAND, 				// 751
+		ASH, 				// 762
+		SQUALL, 			// 771
+		TORNADO, 			// 781
+		CLEAR, 			// Group 800
+		CLOUDS, 		// Group 80x
+	}
+
+	/**
+	 * <p>
+	 * Air Quality Indices reported in OpenWeather air pollution reports. Note that
+	 * while openweathermap.org refers to the Air Quality Indices on a scale of Good
+	 * (1) to Very Poor (5), the CAQI Air Quality Index report refers to the Air
+	 * Quality Indices as a level of pollutants on a scale of Very Low (1) to Very
+	 * High (5). Numerically they are equivalent but the English-language meaning is
+	 * different. This enumerated type uses the CAQI nomenclature.
+	 * </p>
+	 *
+	 * <p>
+	 * (n.b., {@link AirQuality#UNKNOWN_AIR_QUALITY} is a catch-all when no air
+	 * quality data is present.)
+	 * </p>
+	 *
+	 * @see <a href="https://openweathermap.org/api/air-pollution">OpenWeathermap
+	 *      Air Pollution API</a>
+	 * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality
+	 *      Index entry on Wikipedia</a>
+	 * @see <a href=
+	 *      "https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI
+	 *      Air Quality Index</a>
+	 */
+	public enum AirQuality {
+		UNKNOWN_AIR_QUALITY, VERY_LOW, // aqi==1 "Good" in openweathermap.org/api/air-pollution
+		LOW, // aqi==2 "Fair" in openweathermap.org/api/air-pollution
+		MEDIUM, // aqi==3 "Moderate" in openweathermap.org/api/air-pollution
+		HIGH, // aqi==4 "Poor" in openweathermap.org/api/air-pollution
+		VERY_HIGH, // aqi==5 "Very Poor" in openweathermap.org/api/air-pollution
+	}
+
+	/**
+	 * Supported data sets, a subset of the documented OpenWeathermap APIs.
+	 */
+	public static final Set<String> allowableDataSets = Set.of("weather", "onecall", "onecall/timemachine", "forecast",
+			"air_pollution", "air_pollution/forecast", "air_pollution/history", "direct", "reverse" // geocoding
+	// "stations", "triggers" excluded because PUT/POST calls are not supported here
+	// "map" excluded because it isn't JSON and also appears not to be a REST call
+	);
+
+	public static final Date IMPOSSIBLE_DATE = new Date(Long.MIN_VALUE);
+	public static final String PROTOCOL = "http";
+	public static final String REST_AUTHORITY = "api.openweathermap.org";
+
+	protected final Connection dataSource;
+	protected String dataSet;
+	protected String REST_PATH; // Should be able to declare this as final, but static analysis doesn't see that
+
+	protected JSONObject data;
+	protected Date currentTimestamp;
+
+	/**
+	 * <p>
+	 * Constructor to be used when connecting to OpenWeather data stored in a local
+	 * file.
+	 * </p>
+	 *
+	 * <p>
+	 * <i>Note</i>: in the case of Air Pollution Forecast and Air Pollution History,
+	 * the data set is of the form "air_pollution/forecast" and
+	 * "air_pollution/history".
+	 * </p>
+	 *
+	 * @param fileDataSet directory containing the specified file; must correspond
+	 *                    to one of the <a href=
+	 *                    "https://openweathermap.org/api">OpenWeathermap.org
+	 *                    APIs</a>
+	 * @throws IllegalArgumentException if {@code fileDataSet} does not correspond
+	 *                                  to an OpenWeathermap.org API
+	 */
+	public OpenWeatherConnector(String fileDataSet) throws IllegalArgumentException {
+		initializeFields(fileDataSet);
+		dataSource = new FileConnection(fileDataSet);
+	}
+
+	/**
+	 * <p>
+	 * Constructor to be used when connecting to
+	 * <a href="https://openweathermap.org">OpenWeathermap.org</a>s's REST API.
+	 * </p>
+	 *
+	 * <p>
+	 * <i>Note</i>: in the case of Air Pollution Forecast and Air Pollution History,
+	 * the data set is of the form "air_pollution/forecast" and
+	 * "air_pollution/history".
+	 * </p>
+	 *
+	 * @param restDataSet specific <a href=
+	 *                    "https://openweathermap.org/api">OpenWeathermap.org
+	 *                    API</a> to be used
+	 * @param apiKey      token provided by <a href=
+	 *                    "https://openweathermap.org">OpenWeathermap.org</a> to
+	 *                    authenticate requester and grant appropriate privileges
+	 * @throws IllegalArgumentException if {@code fileDataSet} does not correspond
+	 *                                  to an OpenWeathermap.org API
+	 */
+	public OpenWeatherConnector(String restDataSet, String apiKey) throws IllegalArgumentException {
+		initializeFields(restDataSet);
+		dataSource = new RestConnection(PROTOCOL, REST_AUTHORITY, REST_PATH + restDataSet, apiKey);
+	}
+
+	private void initializeFields(String intendedDataSet) throws IllegalArgumentException {
+		if (!allowableDataSets.contains(intendedDataSet)) {
+			throw new IllegalArgumentException(intendedDataSet + " is not a valid data set.");
+		}
+		dataSet = intendedDataSet;
+		switch (dataSet) {
+		case "weather":
+		case "onecall":
+		case "onecall/timemachine":
+		case "forecast":
+		case "air_pollution":
+		case "air_pollution/forecast":
+		case "air_pollution/history":
+			REST_PATH = "/data/2.5/";
+			break;
+		case "direct":
+		case "reverse":
+			REST_PATH = "/geo/1.0/";
+			break;
+		default:
+			REST_PATH = "unknown";
+		}
+		data = null;
+		currentTimestamp = null;
+	}
+
+	/**
+	 * Retrieves requested data from the data set. Must be called at least once
+	 * (without data, the other methods have no data to work with). The data will be
+	 * stored as part of the {@link OpenWeatherConnector} instance; however, the
+	 * JSON string will also be returned.
+	 *
+	 * @param requestedData the data to be retrieved. If connected to the local file
+	 *                      system, this is the name of the file with the data. If
+	 *                      connected to <a href=
+	 *                      "https://openweathermap.org">OpenWeathermap.org/api</a>
+	 *                      's REST API, this is the query string.
+	 * @return JSON string for the requested data
+	 * @throws IOException if the data cannot be retrieved
+	 */
+	public String retrieveData(String requestedData) throws IOException {
+		try {
+			data = dataSource.get(requestedData);
+		} catch (FileNotFoundException fileNotFoundException) {
+			if (dataSource instanceof RestConnection) {
+				throw new IOException("Could not access \"" + dataSet + "\" dataset at " + REST_AUTHORITY + ".",
+						fileNotFoundException);
+			} else {
+				throw fileNotFoundException; // For FileConnection, this exception is exactly what's on the label,
+			} // except that we'd more likely see a NullPointerException...
+		} catch (NullPointerException nullPointerException) {
+			if (dataSource instanceof FileConnection) {
+				FileNotFoundException newException = new FileNotFoundException("File " + requestedData + " not found.");
+				newException.initCause(nullPointerException);
+				throw newException;
+			} else {
+				throw nullPointerException; // Not going to try to predict why RestConnection generates NPE
+			}
+		} catch (ParseException parseException) {
+			String message;
+			if (dataSource instanceof FileConnection) {
+				message = "Error while parsing file " + requestedData + ".";
+			} else if (dataSource instanceof RestConnection) {
+				message = "Error while parsing the " + dataSet + " response from " + REST_AUTHORITY + ".";
+			} else {
+				message = "Error while parsing requested data.";
+			}
+			throw new IOException(message, parseException);
+		}
+		checkForDataReadiness(null);
+		long unixTime = extractLongFromJSON(data, "dt", extractLongFromJSON(data, "current", "dt", Long.MIN_VALUE));
+		if (unixTime == Long.MIN_VALUE && data.containsKey("list") && ((JSONArray) data.get("list")).size() == 1) {
+			// this is how current air quality data is reported
+			unixTime = (Long) ((JSONObject) ((JSONArray) data.get("list")).get(0)).get("dt");
+		}
+		currentTimestamp = unixTime == Long.MIN_VALUE ? IMPOSSIBLE_DATE : new Date(unixTime * 1000);
+		return data.toJSONString();
+	}
+
+	/*
+	 * Helper Methods
+	 */
+
+	/**
+	 * Checks whether {@link #data} was populated by calling
+	 * {@link #retrieveData(String)} and whether the calling method can use the
+	 * dataset specified in the constructor call.
+	 *
+	 * @param supportedDataSets the datasets that are relevant to the calling method
+	 *                          or {@code null} if all datasets are relevant
+	 * @throws IllegalStateException         if no data has been retrieved using
+	 *                                       {@link #retrieveData(String)}
+	 * @throws UnsupportedOperationException if the dataset specified in the
+	 *                                       constructor call does not apply to the
+	 *                                       method that called
+	 *                                       {@code checkForDataPresence(Set)}
+	 */
+	private void checkForDataReadiness(Set<String> supportedDataSets)
+			throws IllegalStateException, UnsupportedOperationException {
+		if (data == null) {
+			throw new IllegalStateException("No data has been retrieved from the " + dataSet + " dataset.");
+		}
+		if (supportedDataSets != null && !supportedDataSets.contains(dataSet)) {
+			throw new UnsupportedOperationException("Attempted to call method on an inapplicable dataset (" + dataSet
+					+ "). Applicable dataset(s): " + supportedDataSets + ".");
+		}
+	}
+
+	/**
+	 * Returns value associated with the key in the JSON object. The caller is
+	 * responsible for making sure that the JSON object is not null; however, the
+	 * caller does <i>not</i> need to establish that the key is present. Returns the
+	 * default value if the key is not present.
+	 *
+	 * @param jsonObject   JSON object that may contain the key and value of
+	 *                     interest
+	 * @param key          the key of interest
+	 * @param defaultValue the value to be returned if the key is not present
+	 * @return the value of interest, or the default value if the key is not present
+	 */
+	private double extractDoubleFromJSON(JSONObject jsonObject, String key, double defaultValue) {
+		double returnValue = defaultValue;
+		if (jsonObject.containsKey(key)) {
+			Number value = (Number) jsonObject.get(key);
+			returnValue = value == null ? defaultValue : value.doubleValue();
+		}
+		return returnValue;
+	}
+
+	/**
+	 * Returns value associated with the key in a second-level JSON object in the
+	 * specified JSON object. The caller is responsible for making sure that the
+	 * JSON object is not null; however, the caller does <i>not</i> need to
+	 * establish that the key is present. Returns the default value if the key is
+	 * not present.
+	 *
+	 * @param jsonObject    JSON object that may contain the key and value of
+	 *                      interest
+	 * @param topLevelField the key to access the second-level JSON object
+	 * @param subField      the key of interest in the second-level JSON object
+	 * @param defaultValue  the value to be returned if the key is not present
+	 * @return the value of interest, or the default value if the key is not present
+	 */
+	private double extractDoubleFromJSON(JSONObject jsonObject, String topLevelField, String subField,
+			double defaultValue) {
+		double returnValue = defaultValue;
+		if (jsonObject.containsKey(topLevelField)) {
+			JSONObject secondLevelJsonObject = (JSONObject) jsonObject.get(topLevelField);
+			returnValue = extractDoubleFromJSON(secondLevelJsonObject, subField, defaultValue);
+		}
+		return returnValue;
+	}
+
+	/**
+	 * Returns value associated with the key in the JSON object. The caller is
+	 * responsible for making sure that the JSON object is not null; however, the
+	 * caller does <i>not</i> need to establish that the key is present. Returns the
+	 * default value if the key is not present.
+	 *
+	 * @param jsonObject   JSON object that may contain the key and value of
+	 *                     interest
+	 * @param key          the key of interest
+	 * @param defaultValue the value to be returned if the key is not present
+	 * @return the value of interest, or the default value if the key is not present
+	 */
+	private long extractLongFromJSON(JSONObject jsonObject, String key, long defaultValue) {
+		long returnValue = defaultValue;
+		if (jsonObject.containsKey(key)) {
+			Long value = (Long) jsonObject.get(key);
+			returnValue = value == null ? defaultValue : value;
+		}
+		return returnValue;
+	}
+
+	/**
+	 * Returns value associated with the key in a second-level JSON object in the
+	 * specified JSON object. The caller is responsible for making sure that the
+	 * JSON object is not null; however, the caller does <i>not</i> need to
+	 * establish that the key is present. Returns the default value if the key is
+	 * not present.
+	 *
+	 * @param jsonObject    JSON object that may contain the key and value of
+	 *                      interest
+	 * @param topLevelField the key to access the second-level JSON object
+	 * @param subField      the key of interest in the second-level JSON object
+	 * @param defaultValue  the value to be returned if the key is not present
+	 * @return the value of interest, or the default value if the key is not present
+	 */
+	private long extractLongFromJSON(JSONObject jsonObject, String topLevelField, String subField, long defaultValue) {
+		long returnValue = defaultValue;
+		if (jsonObject.containsKey(topLevelField)) {
+			JSONObject secondLevelJsonObject = (JSONObject) jsonObject.get(topLevelField);
+			returnValue = extractLongFromJSON(secondLevelJsonObject, subField, defaultValue);
+		}
+		return returnValue;
+	}
+
+	/**
+	 * Returns object in the list associated with the key, at the specified
+	 * timestamp. Returns null if the list is not present, or if there is no list
+	 * entry at the timestamp.
+	 *
+	 * @param listName  the key to access the list
+	 * @param timestamp the timestamp of the list entry
+	 * @return the object of interest, or null if the list or the timestamp are not
+	 *         present
+	 */
+	private JSONObject getListEntry(String listName, Date timestamp) {
+		JSONObject listEntry = null;
+		if (data.containsKey(listName)) {
+			JSONArray list = (JSONArray) data.get(listName);
+			for (Object entry : list) {
+				if ((Long) ((JSONObject) entry).get("dt") == timestamp.getTime() / 1000) {
+					listEntry = (JSONObject) entry;
+				}
+			}
+		}
+		return listEntry;
+	}
+
+	/*
+	 * Wrapper methods for all reports
+	 */
+
+	/**
+	 * <p>
+	 * Provides the latitude for the weather's location.
+	 * </p>
+	 * <p>
+	 * Available for all datasets.
+	 * </p>
+	 *
+	 * @return location's latitude
+	 */
+	public double getLatitude() {
+		checkForDataReadiness(null);
+		JSONObject locationContainer = data;
+		if (data.containsKey("city")) {
+			locationContainer = (JSONObject) data.get("city");
+		}
+		if (dataSet.startsWith("onecall")) {
+			return extractDoubleFromJSON(locationContainer, "lat", Double.NaN);
+		} else {
+			return extractDoubleFromJSON(locationContainer, "coord", "lat", Double.NaN);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the longitude for the weather's location.
+	 * </p>
+	 * <p>
+	 * Available for all datasets.
+	 * </p>
+	 *
+	 * @return location's longitude
+	 */
+	public double getLongitude() {
+		checkForDataReadiness(null);
+		JSONObject locationContainer = data;
+		if (data.containsKey("city")) {
+			locationContainer = (JSONObject) data.get("city");
+		}
+		if (dataSet.startsWith("onecall")) {
+			return extractDoubleFromJSON(locationContainer, "lon", Double.NaN);
+		} else {
+			return extractDoubleFromJSON(locationContainer, "coord", "lon", Double.NaN);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the date and time for the current weather, or
+	 * {@link #IMPOSSIBLE_DATE} if no valid timestamp exists.
+	 * </p>
+	 * <p>
+	 * Available for all datasets with data for the present.
+	 * </p>
+	 *
+	 * @return timestamp for the weather observations
+	 */
+	public Date getTimestamp() {
+		checkForDataReadiness(null);
+		return currentTimestamp;
+	}
+
+	/**
+	 * Extracts epoch-based timestamps from the specified JSON list and places
+	 * {@link Date} timestamps into the provided {@link List}.
+	 * 
+	 * @param jsonListName the name of the JSON list containing data with timestamps
+	 * @param timestamps   the possibly-nonempty {@link List} to place the
+	 *                     {@link Date} timestamps in
+	 */
+	private void moveTimestampsFromJsonArrayToJavaList(String jsonListName, List<Date> timestamps) {
+		if (data.containsKey(jsonListName)) {
+			JSONArray entries = (JSONArray) data.get(jsonListName);
+			if (entries != null) {
+				for (Object entry : entries) {
+					long unixTime = (Long) ((JSONObject) entry).get("dt");
+					timestamps.add(new Date(unixTime * 1000));
+				}
+			}
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides all dates and times for reports with multiple timestamps.
+	 * </p>
+	 * <p>
+	 * Available for all datasets with data in the past or the future.
+	 * </p>
+	 *
+	 * @return list of timestamps for the weather observations
+	 */
+	public List<Date> getTimestamps() {
+		checkForDataReadiness(null);
+		Set<String> possibleListNames = Set.of("list", "minutely", "hourly", "daily");
+		List<Date> timestamps = new ArrayList<>();
+		for (String listName : possibleListNames) {
+			moveTimestampsFromJsonArrayToJavaList(listName, timestamps);
+		}
+		timestamps.sort(null);
+		return List.copyOf(timestamps);
+	}
+
+	/**
+	 * <p>
+	 * Provides the dates and times for a specific list, for reports with multiple
+	 * timestamps.
+	 * </p>
+	 * <p>
+	 * Available for all datasets with data in the past or the future.
+	 * </p>
+	 *
+	 * @param listName the name of the list whose timestamps are of interest
+	 * @return list of timestamps for the weather observations
+	 */
+	public List<Date> getTimestamps(String listName) {
+		checkForDataReadiness(null);
+		List<Date> timestamps = new ArrayList<>();
+		moveTimestampsFromJsonArrayToJavaList(listName, timestamps);
+		timestamps.sort(null);
+		return List.copyOf(timestamps);
+	}
+
+	/*
+	 * Wrapper methods for current and forecasted weather
+	 */
+
+	/**
+	 * <p>
+	 * Provides the broad categories for the weather reported in the provided JSON
+	 * object. If there are more than one category provided, the "primary" category
+	 * will at the head of the list. The weather categories are guaranteed to be in
+	 * the same order as the corresponding descriptions provided by
+	 * {@link #getWeatherDescriptions()}.
+	 * </p>
+	 * <p>
+	 * The caller is responsible for ensuring that data is present.
+	 * </p>
+	 *
+	 * @param jsonObject the object containing the weather data
+	 * @return list of weather categories
+	 * @see #getWeatherDescriptions()
+	 */
+	private List<WeatherCategory> getWeatherCategories(JSONObject jsonObject) {
+		JSONArray weather = (JSONArray) jsonObject.get("weather");
+		List<WeatherCategory> categories;
+		if (weather != null) {
+			categories = new ArrayList<>(weather.size());
+			for (Object condition : weather) {
+				String category = ((JSONObject) condition).get("main").toString();
+				try {
+					categories.add(WeatherCategory.valueOf(category.toUpperCase()));
+				} catch (IllegalArgumentException ignored) {
+					categories.add(WeatherCategory.UNKNOWN_CATEGORY);
+				}
+			}
+		} else {
+			categories = new ArrayList<>(0);
+		}
+		return List.copyOf(categories);
+	}
+
+	/**
+	 * <p>
+	 * Provides the broad categories for the current weather. If there are more than
+	 * one category provided, the "primary" category will at the head of the list.
+	 * The weather categories are guaranteed to be in the same order as the
+	 * corresponding descriptions provided by {@link #getWeatherDescriptions()}.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return list of weather categories
+	 * @see #getWeatherDescriptions()
+	 */
+	public List<WeatherCategory> getWeatherCategories() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		return getWeatherCategories(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data);
+	}
+
+	/**
+	 * <p>
+	 * Provides the broad categories for the forecasted weather. If there are more
+	 * than one category provided, the "primary" category will at the head of the
+	 * list. The weather categories are guaranteed to be in the same order as the
+	 * corresponding descriptions provided by {@link #getWeatherDescriptions()}.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return list of forecasted weather categories
+	 * @see #getWeatherDescriptions()
+	 */
+	public List<WeatherCategory> getWeatherCategories(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		String listName = "list";
+		if (dataSet.equals("onecall")) {
+			List<Date> hours = getTimestamps("hourly");
+			listName = hours.contains(timestamp) ? "hourly" : "daily";
+		}
+		return getWeatherCategories(getListEntry(listName, timestamp));
+	}
+
+	/**
+	 * <p>
+	 * Provides descriptions of the weather reported in the provided JSON object. If
+	 * there are more than one weather description provided, the "primary"
+	 * description will be at the head of the list. The weather descriptions are
+	 * guaranteed to be in the same order as the corresponding categories provided
+	 * by {@link #getWeatherCategories()}.
+	 * </p>
+	 * <p>
+	 * The caller is responsible for ensuring that data is present.
+	 * </p>
+	 *
+	 * @param jsonObject the object containing the weather data
+	 * @return list of weather descriptions
+	 * @see #getWeatherCategories()
+	 */
+	private List<String> getWeatherDescriptions(JSONObject jsonObject) {
+		JSONArray weather = (JSONArray) jsonObject.get("weather");
+		List<String> descriptions;
+		if (weather != null) {
+			descriptions = new ArrayList<>(weather.size());
+			for (Object condition : weather) {
+				descriptions.add(((JSONObject) condition).get("description").toString());
+			}
+		} else {
+			descriptions = new ArrayList<>(0);
+		}
+		return List.copyOf(descriptions);
+	}
+
+	/**
+	 * <p>
+	 * Provides descriptions of the current weather. If there are more than one
+	 * weather description provided, the "primary" description will be at the head
+	 * of the list. The weather descriptions are guaranteed to be in the same order
+	 * as the corresponding categories provided by {@link #getWeatherCategories()}.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return list of weather descriptions
+	 * @see #getWeatherCategories()
+	 */
+	public List<String> getWeatherDescriptions() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		return getWeatherDescriptions(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data);
+	}
+
+	/**
+	 * <p>
+	 * Provides descriptions of the forecasted weather. If there are more than one
+	 * weather description provided, the "primary" description will be at the head
+	 * of the list. The weather descriptions are guaranteed to be in the same order
+	 * as the corresponding categories provided by {@link #getWeatherCategories()}.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return list of forecasted weather descriptions
+	 * @see #getWeatherCategories()
+	 */
+	public List<String> getWeatherDescriptions(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		String listName = "list";
+		if (dataSet.equals("onecall")) {
+			List<Date> hours = getTimestamps("hourly");
+			listName = hours.contains(timestamp) ? "hourly" : "daily";
+		}
+		return getWeatherDescriptions(getListEntry(listName, timestamp));
+	}
+
+	/**
+	 * <p>
+	 * Provides the current visibility in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current visibility, or {@link Long#MIN_VALUE} if visibility is
+	 *         not in current observation
+	 */
+	public long getVisibility() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		return extractLongFromJSON(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data,
+				"visibility", Long.MIN_VALUE);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted visibility in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" (hourly only) datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted visibility, or {@link Long#MIN_VALUE} if visibility is
+	 *         not in the forecast
+	 */
+	public long getVisibility(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		if (dataSet.equals("onecall") && !getTimestamps("hourly").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
+		}
+		String listName = dataSet.equals("onecall") ? "hourly" : "list";
+		return extractLongFromJSON(getListEntry(listName, timestamp), "visibility", Long.MIN_VALUE);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current temperature, or {@link Double#NaN} if temperature is not
+	 *         in current observation
+	 */
+	public double getTemperature() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		return extractDoubleFromJSON(data, dataSet.startsWith("onecall") ? "current" : "main", "temp", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" (hourly only) datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted temperature, or {@link Double#NaN} if temperature is
+	 *         not in the forecast
+	 */
+	public double getTemperature(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		if (dataSet.equals("forecast")) {
+			return extractDoubleFromJSON(getListEntry("list", timestamp), "main", "temp", Double.NaN);
+		} else if (dataSet.equals("onecall") && getTimestamps("hourly").contains(timestamp)) {
+			return extractDoubleFromJSON(getListEntry("hourly", timestamp), "temp", Double.NaN);
+		} else {
+			throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted morning temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted morning temperature, or {@link Double#NaN} if morning
+	 *         temperature is not in the forecast
+	 */
+	public double getMorningTemperature(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "morn", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted daytime temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted daytime temperature, or {@link Double#NaN} if daytime
+	 *         temperature is not in the forecast
+	 */
+	public double getDaytimeTemperature(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "day", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted evening temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted evening temperature, or {@link Double#NaN} if evening
+	 *         temperature is not in the forecast
+	 */
+	public double getEveningTemperature(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "eve", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted nighttime temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted nighttime temperature, or {@link Double#NaN} if
+	 *         nighttime temperature is not in the forecast
+	 */
+	public double getNighttimeTemperature(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "night", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted daily low temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted daily low temperature, or {@link Double#NaN} if daily
+	 *         low temperature is not in the forecast
+	 */
+	public double getLowTemperature(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "min", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted daily high temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted daily high temperature, or {@link Double#NaN} if daily
+	 *         high temperature is not in the forecast
+	 */
+	public double getHighTemperature(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "max", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current relative humidity (percent of saturation).
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current humidity, or {@link Long#MIN_VALUE} if visibility is not
+	 *         in current observation
+	 */
+	public long getHumidity() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		return extractLongFromJSON(data, dataSet.startsWith("onecall") ? "current" : "main", "humidity",
+				Long.MIN_VALUE);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted relative humidity (percent of saturation).
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted humidity, or {@link Long#MIN_VALUE} if visibility is
+	 *         not in the forecast
+	 */
+	public long getHumidity(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		if (dataSet.equals("forecast")) {
+			return extractLongFromJSON(getListEntry("list", timestamp), "main", "humidity", Long.MIN_VALUE);
+		} else if (dataSet.equals("onecall")) {
+			return extractLongFromJSON(
+					getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp),
+					"humidity", Long.MIN_VALUE);
+		} else {
+			return Long.MIN_VALUE;
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the current dew point in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" dataset.
+	 * </p>
+	 *
+	 * @return the current dew point, or {@link Double#NaN} if dew point is not in
+	 *         current observation
+	 */
+	public double getDewPoint() {
+		checkForDataReadiness(Set.of("onecall"));
+		return extractDoubleFromJSON(data, "current", "dew_point", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted dew point in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted dew point, or {@link Double#NaN} if dew point is not
+	 *         in the forecast
+	 */
+	public double getDewPoint(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		return extractDoubleFromJSON(
+				getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), "dew_point",
+				Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current "feels like" temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current "feels like" temperature, or {@link Double#NaN} if "feels
+	 *         like" temperature is not in current observation
+	 */
+	public double getFeelsLike() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		return extractDoubleFromJSON(data, dataSet.startsWith("onecall") ? "current" : "main", "feels_like",
+				Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted "feels like" temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" (hourly only) datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted "feels like" temperature, or {@link Double#NaN} if
+	 *         "feels like" temperature is not in the forecast
+	 */
+	public double getFeelsLike(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		if (dataSet.equals("forecast")) {
+			return extractDoubleFromJSON(getListEntry("list", timestamp), "main", "feels_like", Double.NaN);
+		} else if (dataSet.equals("onecall") && getTimestamps("hourly").contains(timestamp)) {
+			return extractDoubleFromJSON(getListEntry("hourly", timestamp), "feels_like", Double.NaN);
+		} else {
+			throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted morning "feels like" temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted morning "feels like" temperature, or
+	 *         {@link Double#NaN} if morning "feels like" temperature is not in the
+	 *         forecast
+	 */
+	public double getMorningFeelsLike(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "morn", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted "feels like" daytime temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted daytime "feels like" temperature, or
+	 *         {@link Double#NaN} if daytime "feels like" temperature is not in the
+	 *         forecast
+	 */
+	public double getDaytimeFeelsLike(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "day", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted evening "feels like" temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted evening "feels like" temperature, or
+	 *         {@link Double#NaN} if evening "feels like" temperature is not in the
+	 *         forecast
+	 */
+	public double getEveningFeelsLike(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "eve", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted nighttime "feels like" temperature in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (daily only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted nighttime "feels like" temperature, or
+	 *         {@link Double#NaN} if nighttime "feels like" temperature is not in
+	 *         the forecast
+	 */
+	public double getNighttimeFeelsLike(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("daily").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "night", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current pressure in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current pressure, or {@link Long#MIN_VALUE} if pressure is not in
+	 *         current observation
+	 */
+	public long getPressure() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		return extractLongFromJSON(data, dataSet.startsWith("onecall") ? "current" : "main", "pressure",
+				Long.MIN_VALUE);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted pressure in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted pressure, or {@link Long#MIN_VALUE} if pressure is not
+	 *         in the forecast
+	 */
+	public long getPressure(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		if (dataSet.equals("forecast")) {
+			return extractLongFromJSON(getListEntry("list", timestamp), "main", "pressure", Long.MIN_VALUE);
+		} else if (dataSet.equals("onecall")) {
+			return extractLongFromJSON(
+					getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp),
+					"pressure", Long.MIN_VALUE);
+		} else {
+			return Long.MIN_VALUE;
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the current wind direction, in degrees.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current wind direction, or {@link Long#MIN_VALUE} if winds are
+	 *         not in current observation
+	 */
+	public long getWindDirection() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		if (dataSet.startsWith("onecall")) {
+			return extractLongFromJSON(data, "current", "wind_deg", Long.MIN_VALUE);
+		} else {
+			return extractLongFromJSON(data, "wind", "deg", Long.MIN_VALUE);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted wind direction, in degrees.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted wind direction, or {@link Long#MIN_VALUE} if winds are
+	 *         not in the forecast
+	 */
+	public long getWindDirection(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		if (dataSet.equals("forecast")) {
+			return extractLongFromJSON(getListEntry("list", timestamp), "wind", "deg", Long.MIN_VALUE);
+		} else if (dataSet.equals("onecall")) {
+			return extractLongFromJSON(
+					getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp),
+					"wind_deg", Long.MIN_VALUE);
+		} else {
+			return Long.MIN_VALUE;
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the current wind speed in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current wind speed, or 0.0 if winds are not in current
+	 *         observation
+	 */
+	public double getWindSpeed() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		if (dataSet.startsWith("onecall")) {
+			return extractDoubleFromJSON(data, "current", "wind_speed", 0.0);
+		} else {
+			return extractDoubleFromJSON(data, "wind", "speed", 0.0);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted wind speed in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted wind speed, or 0.0 if winds are not in the forecast
+	 */
+	public double getWindSpeed(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		if (dataSet.equals("forecast")) {
+			return extractDoubleFromJSON(getListEntry("list", timestamp), "wind", "speed", 0.0);
+		} else if (dataSet.equals("onecall")) {
+			return extractDoubleFromJSON(
+					getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp),
+					"wind_speed", 0.0);
+		} else {
+			return 0.0;
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the current wind gust in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current wind gust, or current wind speed if wind gust is not in
+	 *         current observation
+	 */
+	public double getWindGust() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		if (dataSet.startsWith("onecall")) {
+			return extractDoubleFromJSON(data, "current", "wind_gust", getWindSpeed());
+		} else {
+			return extractDoubleFromJSON(data, "wind", "gust", getWindSpeed());
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted wind gust in the default
+	 * <a href="https://openweathermap.org/current#data">units</a> or those
+	 * specified in the call to {@link #retrieveData(String)}.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted wind gust, or current wind speed if wind gust is not
+	 *         in the forecast
+	 */
+	public double getWindGust(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		if (dataSet.equals("forecast")) {
+			return extractDoubleFromJSON(getListEntry("list", timestamp), "wind", "gust", getWindSpeed(timestamp));
+		} else if (dataSet.equals("onecall")) {
+			return extractDoubleFromJSON(
+					getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp),
+					"wind_gust", getWindSpeed(timestamp));
+		} else {
+			return getWindSpeed(timestamp);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the current UV Index.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" dataset.
+	 * </p>
+	 *
+	 * @return the current UV Index, or {@link Double#NaN} if the UV Index is not in
+	 *         current observation
+	 */
+	public double getUltravioletIndex() {
+		checkForDataReadiness(Set.of("onecall"));
+		return extractDoubleFromJSON(data, "current", "uvi", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted UV Index.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" dataset.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted UV Index, or {@link Double#NaN} if the UV Index is not
+	 *         in the forecast
+	 */
+	public double getUltravioletIndex(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		return extractDoubleFromJSON(
+				getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), "uvi",
+				Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current cloud cover percentage (cloudiness).
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current cloudiness, or 0 if cloudiness is not in current
+	 *         observation
+	 */
+	public long getCloudCover() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		if (dataSet.startsWith("onecall")) {
+			return extractLongFromJSON(data, "clouds", 0);
+		} else {
+			return extractLongFromJSON(data, "clouds", "all", 0);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted cloud cover percentage (cloudiness).
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted cloudiness, or 0 if cloudiness is not in current
+	 *         observation
+	 */
+	public long getCloudCover(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		if (dataSet.startsWith("onecall")) {
+			return extractLongFromJSON(
+					getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), "clouds",
+					0);
+		} else {
+			return extractLongFromJSON(getListEntry("list", timestamp), "clouds", "all", 0);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the forecasted probability of rain, on a 0.0-1.0 scale.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return the forecasted probability of precipitation, or NaN if cloudiness is
+	 *         not in current observation
+	 */
+	public double getProbabilityOfPrecipitation(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast", "onecall"));
+		String listName = "list";
+		if (dataSet.equals("onecall")) {
+			List<Date> hours = getTimestamps("hourly");
+			listName = hours.contains(timestamp) ? "hourly" : "daily";
+		}
+		return extractDoubleFromJSON(getListEntry(listName, timestamp), "pop", Double.NaN);
+	}
+
+	/**
+	 * <p>
+	 * Provides the one-hour rainfall total column, in millimeters.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current one-hour rainfall total, or 0.0 if rain volume is not in
+	 *         current observation
+	 */
+	public double getOneHourRainfall() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		return extractDoubleFromJSON(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data, "rain",
+				"1h", 0.0);
+	}
+
+	/**
+	 * <p>
+	 * Provides the total rain column, in millimeters, forecasted for the one hour
+	 * before the specified timestamp.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (hourly only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the timestamp for the forecasted rainfall
+	 * @return the forecasted one-hour rainfall total, or 0.0 if rain volume is not
+	 *         in the forecast
+	 */
+	public double getOneHourRainfall(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("hourly").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("hourly", timestamp), "rain", "1h", 0.0);
+	}
+
+	/**
+	 * <p>
+	 * Provides the three-hour rainfall total column, in millimeters.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" dataset.
+	 * </p>
+	 *
+	 * @return the current three-hour rainfall total, or 0.0 if rain volume is not
+	 *         in current observation
+	 */
+	public double getThreeHourRainfall() {
+		checkForDataReadiness(Set.of("weather"));
+		return extractDoubleFromJSON(data, "rain", "3h", getOneHourRainfall());
+	}
+
+	/**
+	 * <p>
+	 * Provides the total rain column, in millimeters, forecasted for the three
+	 * hours before the specified timestamp.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" dataset.
+	 * </p>
+	 *
+	 * @param timestamp the timestamp for the forecasted rainfall
+	 * @return the forecasted three-hour rainfall total, or 0.0 if rain volume is
+	 *         not in the forecast
+	 */
+	public double getThreeHourRainfall(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast"));
+		return extractDoubleFromJSON(getListEntry("list", timestamp), "rain", "3h", 0.0);
+	}
+
+	/**
+	 * <p>
+	 * Provides the one-hour snowfall total column, in millimeters.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" and "onecall" datasets.
+	 * </p>
+	 *
+	 * @return the current one-hour snowfall total, or 0.0 if snow volume is not in
+	 *         current observation
+	 */
+	public double getOneHourSnowfall() {
+		checkForDataReadiness(Set.of("weather", "onecall"));
+		return extractDoubleFromJSON(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data, "snow",
+				"1h", 0.0);
+	}
+
+	/**
+	 * <p>
+	 * Provides the total snow column, in millimeters, forecasted for the one hour
+	 * before the specified timestamp.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" (hourly only) dataset.
+	 * </p>
+	 *
+	 * @param timestamp the timestamp for the forecasted snowfall
+	 * @return the forecasted one-hour rainfall total, or 0.0 if rain volume is not
+	 *         in the forecast
+	 */
+	public double getOneHourSnowfall(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("hourly").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("hourly", timestamp), "snow", "1h", 0.0);
+	}
+
+	/**
+	 * <p>
+	 * Provides the three-hour snowfall total column, in millimeters.
+	 * </p>
+	 * <p>
+	 * Available for the "weather" dataset.
+	 * </p>
+	 *
+	 * @return the current three-hour snowfall total, or 0.0 if snow volume is not
+	 *         in current observation
+	 */
+	public double getThreeHourSnowfall() {
+		checkForDataReadiness(Set.of("weather"));
+		return extractDoubleFromJSON(data, "snow", "3h", getOneHourSnowfall());
+	}
+
+	/**
+	 * <p>
+	 * Provides the total snow column, in millimeters, forecasted for the three
+	 * hours before the specified timestamp.
+	 * </p>
+	 * <p>
+	 * Available for the "forecast" dataset.
+	 * </p>
+	 *
+	 * @param timestamp the timestamp for the forecasted snowfall
+	 * @return the forecasted three-hour snowfall total, or 0.0 if snow volume is
+	 *         not in the forecast
+	 */
+	public double getThreeHourSnowfall(Date timestamp) {
+		checkForDataReadiness(Set.of("forecast"));
+		return extractDoubleFromJSON(getListEntry("list", timestamp), "snow", "3h", 0.0);
+	}
+
+	/**
+	 * <p>
+	 * Provides the precipitation column, in millimeters, forecasted for the the
+	 * specified minute. Not explicitly stated in the API specification, this
+	 * appears to be a 1-hour total that does not distinguish between rain and snow.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" dataset.
+	 * </p>
+	 *
+	 * @param timestamp the timestamp for the forecasted precipitation
+	 * @return the forecasted precipitation total, or 0.0 if precipitation volume is
+	 *         not in the forecast
+	 */
+	public double getMinutelyPrecipitation(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		if (!getTimestamps("minutely").contains(timestamp)) {
+			throw new UnsupportedOperationException("This onecall datum is only available for minutely timestamps.");
+		}
+		return extractDoubleFromJSON(getListEntry("minutely", timestamp), "precipitation", 0.0);
+	}
+
+	/**
+	 * <p>
+	 * Provides the rain column, in millimeters, forecasted for the the specified
+	 * day. Not explicitly stated in the API specification, this appears to be a
+	 * daily total.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" dataset.
+	 * </p>
+	 *
+	 * @param timestamp the timestamp for the forecasted rainfall
+	 * @return the forecasted rain total, or 0.0 if precipitation volume is not in
+	 *         the forecast
+	 */
+	public double getDailyRainfall(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "rain", 0.0);
+	}
+
+	/**
+	 * <p>
+	 * Provides the snow column, in millimeters, forecasted for the the specified
+	 * day. Not explicitly stated in the API specification, this appears to be a
+	 * daily total.
+	 * </p>
+	 * <p>
+	 * Available for the "onecall" dataset.
+	 * </p>
+	 *
+	 * @param timestamp the timestamp for the forecasted snowfall
+	 * @return the forecasted snow total, or 0.0 if precipitation volume is not in
+	 *         the forecast
+	 */
+	public double getDailySnowfall(Date timestamp) {
+		checkForDataReadiness(Set.of("onecall"));
+		return extractDoubleFromJSON(getListEntry("daily", timestamp), "snow", 0.0);
+	}
+
+	/*
+	 * Wrapper methods for Air Quality
+	 */
+
+	/**
+	 * Returns the concentration for the specified pollutant at the specified
+	 * timestamp from the list of air quality entries.
+	 *
+	 * @param timestamp the timestamp for the air quality entry
+	 * @param pollutant the pollutant whose concentration is to be obtained
+	 * @return the value associated with the specified pollutant at the specified
+	 *         timestamp
+	 */
+	private double getPollutionData(Date timestamp, String pollutant) {
+		JSONObject currentEntry = getListEntry("list", timestamp);
+		if (currentEntry == null) {
+			return Double.NaN;
+		} else {
+			return extractDoubleFromJSON(currentEntry, "components", pollutant, Double.NaN);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Provides the current basic Air Quality Index, using the European CAQI tables.
+	 * This is a composite metric based on concentrations of nitrogen monoxide,
+	 * ozone, coarse particulates, and optionally fine particulates.
+	 * </p>
+	 *
+	 * <p>
+	 * The air quality is reported on a range from {@link AirQuality#VERY_LOW}
+	 * (good) to {@link AirQuality#VERY_HIGH} (very poor)
+	 * </p>
+	 *
+	 * <p>
+	 * Available for the "air_pollution" dataset.
+	 * </p>
+	 *
+	 * @return air quality index at the requested timestamp
+	 * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality
+	 *      Index entry on Wikipedia</a>
+	 * @see <a href=
+	 *      "https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI
+	 *      Air Quality Index</a>
+	 */
+	public AirQuality getAirQualityIndex() {
+		checkForDataReadiness(Set.of("air_pollution"));
+		return getAirQualityIndex(currentTimestamp);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current, historical, or forecasted basic Air Quality Index,
+	 * using the European CAQI tables. This is a composite metric based on
+	 * concentrations of nitrogen monoxide, ozone, coarse particulates, and
+	 * optionally fine particulates.
+	 * </p>
+	 *
+	 * <p>
+	 * The air quality is reported on a range from {@link AirQuality#VERY_LOW}
+	 * (good) to {@link AirQuality#VERY_HIGH} (very poor)
+	 * </p>
+	 *
+	 * <p>
+	 * Available for the "air_pollution", "air_pollution/history" and
+	 * "air_pollution/forecast" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return air quality index at the requested timestamp
+	 * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality
+	 *      Index entry on Wikipedia</a>
+	 * @see <a href=
+	 *      "https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI
+	 *      Air Quality Index</a>
+	 */
+	public AirQuality getAirQualityIndex(Date timestamp) {
+		checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
+		JSONObject currentEntry = getListEntry("list", timestamp);
+		int airQualityIndex = 0;
+		if (currentEntry != null) {
+			airQualityIndex = (int) extractLongFromJSON(currentEntry, "main", "aqi", 0);
+		}
+		return AirQuality.values()[airQualityIndex];
+	}
+
+	/**
+	 * <p>
+	 * Provides the current concentration of Carbon Monoxide (CO), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution" dataset.
+	 * </p>
+	 *
+	 * @return current concentration of CO
+	 */
+	public double getCarbonMonoxide() {
+		checkForDataReadiness(Set.of("air_pollution"));
+		return getCarbonMonoxide(currentTimestamp);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current, historical, or forecasted concentration of Carbon
+	 * Monoxide (CO), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution", "air_pollution/history" and
+	 * "air_pollution/forecast" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return concentration of CO at the requested timestamp
+	 */
+	public double getCarbonMonoxide(Date timestamp) {
+		checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
+		return getPollutionData(timestamp, "co");
+	}
+
+	/**
+	 * <p>
+	 * Provides the current concentration of Nitrogen Monoxide (NO), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution" dataset.
+	 * </p>
+	 *
+	 * @return current concentration of NO
+	 */
+	public double getNitrogenMonoxide() {
+		checkForDataReadiness(Set.of("air_pollution"));
+		return getNitrogenMonoxide(currentTimestamp);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current, historical, or forecasted concentration of Nitrogen
+	 * Monoxide (NO), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution", "air_pollution/history" and
+	 * "air_pollution/forecast" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return concentration of NO at the requested timestamp
+	 */
+	public double getNitrogenMonoxide(Date timestamp) {
+		checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
+		return getPollutionData(timestamp, "no");
+	}
+
+	/**
+	 * <p>
+	 * Provides the current concentration of Nitrogen Dioxide (NO2), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution" dataset.
+	 * </p>
+	 *
+	 * @return current concentration of NO2
+	 */
+	public double getNitrogenDioxide() {
+		checkForDataReadiness(Set.of("air_pollution"));
+		return getNitrogenDioxide(currentTimestamp);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current, historical, or forecasted concentration of Nitrogen
+	 * Dioxide (NO2), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution", "air_pollution/history" and
+	 * "air_pollution/forecast" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return concentration of NO2 at the requested timestamp
+	 */
+	public double getNitrogenDioxide(Date timestamp) {
+		checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
+		return getPollutionData(timestamp, "no2");
+	}
+
+	/**
+	 * <p>
+	 * Provides the current concentration of Ozone (O3), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution" dataset.
+	 * </p>
+	 *
+	 * @return current concentration of O3
+	 */
+	public double getOzone() {
+		checkForDataReadiness(Set.of("air_pollution"));
+		return getOzone(currentTimestamp);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current, historical, or forecasted concentration of Ozone (O3),
+	 * in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution", "air_pollution/history" and
+	 * "air_pollution/forecast" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return concentration of O3 at the requested timestamp
+	 */
+	public double getOzone(Date timestamp) {
+		checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
+		return getPollutionData(timestamp, "o3");
+	}
+
+	/**
+	 * <p>
+	 * Provides the current concentration of Sulfur Dioxide (SO2), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution" dataset.
+	 * </p>
+	 *
+	 * @return current concentration of SO2
+	 */
+	public double getSulfurDioxide() {
+		checkForDataReadiness(Set.of("air_pollution"));
+		return getSulfurDioxide(currentTimestamp);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current, historical, or forecasted concentration of Sulfur
+	 * Dioxide (SO2), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution", "air_pollution/history" and
+	 * "air_pollution/forecast" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return concentration of SO2 at the requested timestamp
+	 */
+	public double getSulfurDioxide(Date timestamp) {
+		checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
+		return getPollutionData(timestamp, "so2");
+	}
+
+	/**
+	 * <p>
+	 * Provides the current concentration of Fine Particulate Matter (PM2.5), in
+	 * μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution" dataset.
+	 * </p>
+	 *
+	 * @return current concentration of PM2.5
+	 */
+	public double getFineParticulateMatter() {
+		checkForDataReadiness(Set.of("air_pollution"));
+		return getFineParticulateMatter(currentTimestamp);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current, historical, or forecasted concentration of Fine
+	 * Particulate Matter (PM2.5), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution", "air_pollution/history" and
+	 * "air_pollution/forecast" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return concentration of PM2.5 at the requested timestamp
+	 */
+	public double getFineParticulateMatter(Date timestamp) {
+		checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
+		return getPollutionData(timestamp, "pm2_5");
+	}
+
+	/**
+	 * <p>
+	 * Provides the current concentration of Coarse Particulate Matter (PM10), in
+	 * μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution" dataset.
+	 * </p>
+	 *
+	 * @return current concentration of PM10
+	 */
+	public double getCoarseParticulateMatter() {
+		checkForDataReadiness(Set.of("air_pollution"));
+		return getCoarseParticulateMatter(currentTimestamp);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current, historical, or forecasted concentration of Coarse
+	 * Particulate Matter (PM10), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution", "air_pollution/history" and
+	 * "air_pollution/forecast" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return concentration of PM10 at the requested timestamp
+	 */
+	public double getCoarseParticulateMatter(Date timestamp) {
+		checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
+		return getPollutionData(timestamp, "pm10");
+	}
+
+	/**
+	 * <p>
+	 * Provides the current concentration of Ammonia (NH3), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution" dataset.
+	 * </p>
+	 *
+	 * @return current concentration of NH3
+	 */
+	public double getAmmonia() {
+		checkForDataReadiness(Set.of("air_pollution"));
+		return getAmmonia(currentTimestamp);
+	}
+
+	/**
+	 * <p>
+	 * Provides the current, historical, or forecasted concentration of Ammonia
+	 * (NH3), in μg/m3
+	 * </p>
+	 * <p>
+	 * Available for the "air_pollution", "air_pollution/history" and
+	 * "air_pollution/forecast" datasets.
+	 * </p>
+	 *
+	 * @param timestamp the date/time corresponding to the desired data
+	 * @return concentration of NH3 at the requested timestamp
+	 */
+	public double getAmmonia(Date timestamp) {
+		checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast"));
+		return getPollutionData(timestamp, "nh3");
+	}
 }
diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_UnlNov24ToNov27Test.java b/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_UnlNov24ToNov27Test.java
index 8ec2328..7c99d0a 100644
--- a/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_UnlNov24ToNov27Test.java
+++ b/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_UnlNov24ToNov27Test.java
@@ -11,88 +11,89 @@ import java.util.List;
 import static org.junit.Assert.assertEquals;
 
 public class AirPollution_UnlNov24ToNov27Test {
-    private OpenWeatherConnector connector;
-    private List<Date> timestamps;
+	private OpenWeatherConnector connector;
+	private List<Date> timestamps;
 
-    @Before
-    public void setup() throws IOException {
-        connector = new OpenWeatherConnector("air_pollution/history");
-        connector.retrieveData("air_pollution-unl-historical.json");
-        timestamps = connector.getTimestamps();
-    }
+	@Before
+	public void setup() throws IOException {
+		connector = new OpenWeatherConnector("air_pollution/history");
+		connector.retrieveData("air_pollution-unl-historical.json");
+		timestamps = connector.getTimestamps();
+	}
 
-    @Test
-    public void testLocation() {
-        double expectedLatitude = 40.8151;
-        double expectedLongitude = -96.7049;
-        double actualLatitude = connector.getLatitude();
-        double actualLongitude = connector.getLongitude();
-        assertEquals(expectedLatitude, actualLatitude, 0.0001);
-        assertEquals(expectedLongitude, actualLongitude, 0.0001);
-    }
+	@Test
+	public void testLocation() {
+		double expectedLatitude = 40.8151;
+		double expectedLongitude = -96.7049;
+		double actualLatitude = connector.getLatitude();
+		double actualLongitude = connector.getLongitude();
+		assertEquals(expectedLatitude, actualLatitude, 0.0001);
+		assertEquals(expectedLongitude, actualLongitude, 0.0001);
+	}
 
-    @Test
-    public void testAirQualityIndex() {
-        // We'll pick one of the hours that has AQI==2
-        OpenWeatherConnector.AirQuality expectedValue = OpenWeatherConnector.AirQuality.LOW;
-        OpenWeatherConnector.AirQuality actualValue = connector.getAirQualityIndex(timestamps.get(25));
-        assertEquals(expectedValue, actualValue);
-    }
+	@Test
+	public void testAirQualityIndex() {
+		// We'll pick one of the hours that has AQI==2
+		OpenWeatherConnector.AirQuality expectedValue = OpenWeatherConnector.AirQuality.LOW;
+		OpenWeatherConnector.AirQuality actualValue = connector.getAirQualityIndex(timestamps.get(25));
+		assertEquals(expectedValue, actualValue);
+	}
 
-    @Test
-    public void testCO() {
-        double expectedValue = 240.33;
-        double actualValue = connector.getCarbonMonoxide(timestamps.get(0));
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
+	@Test
+	public void testCO() {
+		double expectedValue = 240.33;
+		double actualValue = connector.getCarbonMonoxide(timestamps.get(0));
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
 
-    @Test
-    public void testNO() {
-        // This is interesting. Normally a double, this report has NO as 0 instead of 0.0.
-        double expectedValue = 0.0;
-        double actualValue = connector.getNitrogenMonoxide(timestamps.get(1));
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
+	@Test
+	public void testNO() {
+		// This is interesting. Normally a double, this report has NO as 0 instead of
+		// 0.0.
+		double expectedValue = 0.0;
+		double actualValue = connector.getNitrogenMonoxide(timestamps.get(1));
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
 
-    @Test
-    public void testNO2() {
-        double expectedValue = 3.64;
-        double actualValue = connector.getNitrogenDioxide(timestamps.get(2));
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
+	@Test
+	public void testNO2() {
+		double expectedValue = 3.64;
+		double actualValue = connector.getNitrogenDioxide(timestamps.get(2));
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
 
-    @Test
-    public void testO3() {
-        double expectedValue = 55.08;
-        double actualValue = connector.getOzone(timestamps.get(3));
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
+	@Test
+	public void testO3() {
+		double expectedValue = 55.08;
+		double actualValue = connector.getOzone(timestamps.get(3));
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
 
-    @Test
-    public void testSO2() {
-        double expectedValue = 0.08;
-        double actualValue = connector.getSulfurDioxide(timestamps.get(60));
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
+	@Test
+	public void testSO2() {
+		double expectedValue = 0.08;
+		double actualValue = connector.getSulfurDioxide(timestamps.get(60));
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
 
-    @Test
-    public void testPM2_5() {
-        double expectedValue = 1.32;
-        double actualValue = connector.getFineParticulateMatter(timestamps.get(59));
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
+	@Test
+	public void testPM2_5() {
+		double expectedValue = 1.32;
+		double actualValue = connector.getFineParticulateMatter(timestamps.get(59));
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
 
-    @Test
-    public void testPM10() {
-        double expectedValue = 1.78;
-        double actualValue = connector.getCoarseParticulateMatter(timestamps.get(58));
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
+	@Test
+	public void testPM10() {
+		double expectedValue = 1.78;
+		double actualValue = connector.getCoarseParticulateMatter(timestamps.get(58));
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
 
-    @Test
-    public void testNH3() {
-        double expectedValue = 1.85;
-        double actualValue = connector.getAmmonia(timestamps.get(57));
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
+	@Test
+	public void testNH3() {
+		double expectedValue = 1.85;
+		double actualValue = connector.getAmmonia(timestamps.get(57));
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
 }
diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_WebsiteExampleTest.java b/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_WebsiteExampleTest.java
index 63b1c5f..4dde1d9 100644
--- a/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_WebsiteExampleTest.java
+++ b/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_WebsiteExampleTest.java
@@ -10,92 +10,92 @@ import java.util.Date;
 import static org.junit.Assert.assertEquals;
 
 public class AirPollution_WebsiteExampleTest {
-    private OpenWeatherConnector connector;
-
-    @Before
-    public void setup() throws IOException {
-        connector = new OpenWeatherConnector("air_pollution");
-        connector.retrieveData("website-example.json");
-    }
-
-    @Test
-    public void testLocation() {
-        double expectedLatitude = 50.0;
-        double expectedLongitude = 50.0;
-        double actualLatitude = connector.getLatitude();
-        double actualLongitude = connector.getLongitude();
-        assertEquals(expectedLatitude, actualLatitude, 0.0001);
-        assertEquals(expectedLongitude, actualLongitude, 0.0001);
-    }
-
-    @Test
-    public void testDateTime() {
+	private OpenWeatherConnector connector;
+
+	@Before
+	public void setup() throws IOException {
+		connector = new OpenWeatherConnector("air_pollution");
+		connector.retrieveData("website-example.json");
+	}
+
+	@Test
+	public void testLocation() {
+		double expectedLatitude = 50.0;
+		double expectedLongitude = 50.0;
+		double actualLatitude = connector.getLatitude();
+		double actualLongitude = connector.getLongitude();
+		assertEquals(expectedLatitude, actualLatitude, 0.0001);
+		assertEquals(expectedLongitude, actualLongitude, 0.0001);
+	}
+
+	@Test
+	public void testDateTime() {
 //        Date expectedValue = new Date(1605182400000L);
-        String expectedValue = "Thu Nov 12 06:00:00 CST 2020";
-        Date actualValue = connector.getTimestamp();
-        assertEquals(expectedValue, actualValue.toString());
-    }
-
-    @Test
-    public void testAirQualityIndex() {
-        OpenWeatherConnector.AirQuality expectedValue = OpenWeatherConnector.AirQuality.VERY_LOW;
-        OpenWeatherConnector.AirQuality actualValue = connector.getAirQualityIndex();
-        assertEquals(expectedValue, actualValue);
-    }
-
-    @Test
-    public void testCO() {
-        double expectedValue = 201.94053649902344;
-        double actualValue = connector.getCarbonMonoxide();
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
-
-    @Test
-    public void testNO() {
-        double expectedValue = 0.01877197064459324;
-        double actualValue = connector.getNitrogenMonoxide();
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
-
-    @Test
-    public void testNO2() {
-        double expectedValue = 0.7711350917816162;
-        double actualValue = connector.getNitrogenDioxide();
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
-
-    @Test
-    public void testO3() {
-        double expectedValue = 68.66455078125;
-        double actualValue = connector.getOzone();
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
-
-    @Test
-    public void testSO2() {
-        double expectedValue = 0.6407499313354492;
-        double actualValue = connector.getSulfurDioxide();
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
-
-    @Test
-    public void testPM2_5() {
-        double expectedValue = 0.5;
-        double actualValue = connector.getFineParticulateMatter();
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
-
-    @Test
-    public void testPM10() {
-        double expectedValue = 0.540438711643219;
-        double actualValue = connector.getCoarseParticulateMatter();
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
-
-    @Test
-    public void testNH3() {
-        double expectedValue = 0.12369127571582794;
-        double actualValue = connector.getAmmonia();
-        assertEquals(expectedValue, actualValue, 0.0001);
-    }
+		String expectedValue = "Thu Nov 12 06:00:00 CST 2020";
+		Date actualValue = connector.getTimestamp();
+		assertEquals(expectedValue, actualValue.toString());
+	}
+
+	@Test
+	public void testAirQualityIndex() {
+		OpenWeatherConnector.AirQuality expectedValue = OpenWeatherConnector.AirQuality.VERY_LOW;
+		OpenWeatherConnector.AirQuality actualValue = connector.getAirQualityIndex();
+		assertEquals(expectedValue, actualValue);
+	}
+
+	@Test
+	public void testCO() {
+		double expectedValue = 201.94053649902344;
+		double actualValue = connector.getCarbonMonoxide();
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
+
+	@Test
+	public void testNO() {
+		double expectedValue = 0.01877197064459324;
+		double actualValue = connector.getNitrogenMonoxide();
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
+
+	@Test
+	public void testNO2() {
+		double expectedValue = 0.7711350917816162;
+		double actualValue = connector.getNitrogenDioxide();
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
+
+	@Test
+	public void testO3() {
+		double expectedValue = 68.66455078125;
+		double actualValue = connector.getOzone();
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
+
+	@Test
+	public void testSO2() {
+		double expectedValue = 0.6407499313354492;
+		double actualValue = connector.getSulfurDioxide();
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
+
+	@Test
+	public void testPM2_5() {
+		double expectedValue = 0.5;
+		double actualValue = connector.getFineParticulateMatter();
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
+
+	@Test
+	public void testPM10() {
+		double expectedValue = 0.540438711643219;
+		double actualValue = connector.getCoarseParticulateMatter();
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
+
+	@Test
+	public void testNH3() {
+		double expectedValue = 0.12369127571582794;
+		double actualValue = connector.getAmmonia();
+		assertEquals(expectedValue, actualValue, 0.0001);
+	}
 }
diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/ExceptionsTest.java b/src/test/java/edu/unl/cse/soft160/json_connections/ExceptionsTest.java
index 47195af..56dec5a 100644
--- a/src/test/java/edu/unl/cse/soft160/json_connections/ExceptionsTest.java
+++ b/src/test/java/edu/unl/cse/soft160/json_connections/ExceptionsTest.java
@@ -10,2416 +10,2416 @@ import java.util.Date;
 import static org.junit.Assert.*;
 
 public class ExceptionsTest {
-    OpenWeatherConnector weather, forecast, airPollution, airPollutionHistory, airPollutionForecast, oneCall, dataLess;
+	OpenWeatherConnector weather, forecast, airPollution, airPollutionHistory, airPollutionForecast, oneCall, dataLess;
 
-    @Before
-    public void setup() throws IOException {
-        weather = new OpenWeatherConnector("weather");
-        weather.retrieveData("website-example.json");
-        forecast = new OpenWeatherConnector("forecast");
-        forecast.retrieveData("forecasted_weather-unl-nov7-nov12.json");
-        airPollution = new OpenWeatherConnector("air_pollution");
-        airPollution.retrieveData("website-example.json");
-        airPollutionHistory = new OpenWeatherConnector("air_pollution/history");
-        airPollutionHistory.retrieveData("air_pollution-unl-historical.json");
-        airPollutionForecast = new OpenWeatherConnector("air_pollution/forecast");
-        airPollutionForecast.retrieveData("stub.json");
-        oneCall = new OpenWeatherConnector("onecall");
-        oneCall.retrieveData("website-example.json");
-        dataLess = new OpenWeatherConnector("weather");
-    }
+	@Before
+	public void setup() throws IOException {
+		weather = new OpenWeatherConnector("weather");
+		weather.retrieveData("website-example.json");
+		forecast = new OpenWeatherConnector("forecast");
+		forecast.retrieveData("forecasted_weather-unl-nov7-nov12.json");
+		airPollution = new OpenWeatherConnector("air_pollution");
+		airPollution.retrieveData("website-example.json");
+		airPollutionHistory = new OpenWeatherConnector("air_pollution/history");
+		airPollutionHistory.retrieveData("air_pollution-unl-historical.json");
+		airPollutionForecast = new OpenWeatherConnector("air_pollution/forecast");
+		airPollutionForecast.retrieveData("stub.json");
+		oneCall = new OpenWeatherConnector("onecall");
+		oneCall.retrieveData("website-example.json");
+		dataLess = new OpenWeatherConnector("weather");
+	}
 
-    @Test
-    public void testAllowedWeatherMethods() {
-        OpenWeatherConnector connector = weather;
-        connector.getLatitude();
-        connector.getLongitude();
-        connector.getTimestamp();
-        connector.getTimestamps();
-        connector.getTimestamps("Anything");
-        connector.getWeatherCategories();
-        connector.getWeatherDescriptions();
-        connector.getVisibility();
-        connector.getTemperature();
-        connector.getHumidity();
-        connector.getFeelsLike();
-        connector.getPressure();
-        connector.getWindDirection();
-        connector.getWindGust();
-        connector.getCloudCover();
-        connector.getOneHourRainfall();
-        connector.getThreeHourRainfall();
-        connector.getOneHourSnowfall();
-        connector.getThreeHourSnowfall();
-        // pass
-    }
+	@Test
+	public void testAllowedWeatherMethods() {
+		OpenWeatherConnector connector = weather;
+		connector.getLatitude();
+		connector.getLongitude();
+		connector.getTimestamp();
+		connector.getTimestamps();
+		connector.getTimestamps("Anything");
+		connector.getWeatherCategories();
+		connector.getWeatherDescriptions();
+		connector.getVisibility();
+		connector.getTemperature();
+		connector.getHumidity();
+		connector.getFeelsLike();
+		connector.getPressure();
+		connector.getWindDirection();
+		connector.getWindGust();
+		connector.getCloudCover();
+		connector.getOneHourRainfall();
+		connector.getThreeHourRainfall();
+		connector.getOneHourSnowfall();
+		connector.getThreeHourSnowfall();
+		// pass
+	}
 
-    @Test
-    public void testAllowedForecastMethods() {
-        OpenWeatherConnector connector = forecast;
-        Date timestamp = connector.getTimestamps().get(0);
-        connector.getLatitude();
-        connector.getLongitude();
-        connector.getTimestamp();
-        connector.getTimestamps();
-        connector.getTimestamps("Anything");
-        connector.getWeatherCategories(timestamp);
-        connector.getWeatherDescriptions(timestamp);
-        connector.getVisibility(timestamp);
-        connector.getTemperature(timestamp);
-        connector.getHumidity(timestamp);
-        connector.getFeelsLike(timestamp);
-        connector.getPressure(timestamp);
-        connector.getWindDirection(timestamp);
-        connector.getWindGust(timestamp);
-        connector.getCloudCover(timestamp);
-        connector.getProbabilityOfPrecipitation(timestamp);
-        connector.getThreeHourRainfall(timestamp);
-        connector.getThreeHourSnowfall(timestamp);
-        // pass
-    }
+	@Test
+	public void testAllowedForecastMethods() {
+		OpenWeatherConnector connector = forecast;
+		Date timestamp = connector.getTimestamps().get(0);
+		connector.getLatitude();
+		connector.getLongitude();
+		connector.getTimestamp();
+		connector.getTimestamps();
+		connector.getTimestamps("Anything");
+		connector.getWeatherCategories(timestamp);
+		connector.getWeatherDescriptions(timestamp);
+		connector.getVisibility(timestamp);
+		connector.getTemperature(timestamp);
+		connector.getHumidity(timestamp);
+		connector.getFeelsLike(timestamp);
+		connector.getPressure(timestamp);
+		connector.getWindDirection(timestamp);
+		connector.getWindGust(timestamp);
+		connector.getCloudCover(timestamp);
+		connector.getProbabilityOfPrecipitation(timestamp);
+		connector.getThreeHourRainfall(timestamp);
+		connector.getThreeHourSnowfall(timestamp);
+		// pass
+	}
 
-    @Test
-    public void testAllowedOneCallMethods() {
-        OpenWeatherConnector connector = oneCall;
-        Date minutely = connector.getTimestamps("minutely").get(0);
-        Date hourly = connector.getTimestamps("hourly").get(0);
-        Date daily = connector.getTimestamps("daily").get(0);
-        connector.getLatitude();
-        connector.getLongitude();
-        connector.getTimestamp();
-        connector.getTimestamps();
-        connector.getTimestamps("Anything");
-        connector.getWeatherCategories();
-        connector.getWeatherDescriptions();
-        connector.getVisibility();
-        connector.getTemperature();
-        connector.getHumidity();
-        connector.getFeelsLike();
-        connector.getPressure();
-        connector.getWindDirection();
-        connector.getWindGust();
-        connector.getCloudCover();
-        connector.getOneHourRainfall();
-        connector.getOneHourSnowfall();
-        connector.getDewPoint();
-        connector.getUltravioletIndex();
-        connector.getMinutelyPrecipitation(minutely); // only
-        connector.getWeatherCategories(hourly);
-        connector.getWeatherDescriptions(daily);
-        connector.getVisibility(hourly); // only
-        connector.getTemperature(hourly); // only
-        connector.getHumidity(hourly);
-        connector.getFeelsLike(hourly); // only
-        connector.getPressure(daily);
-        connector.getWindDirection(hourly);
-        connector.getWindSpeed(daily);
-        connector.getWindGust(daily);
-        connector.getProbabilityOfPrecipitation(hourly);
-        connector.getCloudCover(daily);
-        connector.getDailyRainfall(daily);
-        connector.getDailySnowfall(daily);
-        connector.getOneHourRainfall(hourly);
-        connector.getOneHourSnowfall(hourly);
-        connector.getUltravioletIndex(daily);
-        connector.getDewPoint(hourly);
-        connector.getMorningTemperature(daily);
-        connector.getDaytimeTemperature(daily);
-        connector.getEveningTemperature(daily);
-        connector.getNighttimeTemperature(daily);
-        connector.getLowTemperature(daily);
-        connector.getHighTemperature(daily);
-        connector.getMorningFeelsLike(daily);
-        connector.getDaytimeFeelsLike(daily);
-        connector.getEveningFeelsLike(daily);
-        connector.getNighttimeFeelsLike(daily);
-        // pass
-    }
+	@Test
+	public void testAllowedOneCallMethods() {
+		OpenWeatherConnector connector = oneCall;
+		Date minutely = connector.getTimestamps("minutely").get(0);
+		Date hourly = connector.getTimestamps("hourly").get(0);
+		Date daily = connector.getTimestamps("daily").get(0);
+		connector.getLatitude();
+		connector.getLongitude();
+		connector.getTimestamp();
+		connector.getTimestamps();
+		connector.getTimestamps("Anything");
+		connector.getWeatherCategories();
+		connector.getWeatherDescriptions();
+		connector.getVisibility();
+		connector.getTemperature();
+		connector.getHumidity();
+		connector.getFeelsLike();
+		connector.getPressure();
+		connector.getWindDirection();
+		connector.getWindGust();
+		connector.getCloudCover();
+		connector.getOneHourRainfall();
+		connector.getOneHourSnowfall();
+		connector.getDewPoint();
+		connector.getUltravioletIndex();
+		connector.getMinutelyPrecipitation(minutely); // only
+		connector.getWeatherCategories(hourly);
+		connector.getWeatherDescriptions(daily);
+		connector.getVisibility(hourly); // only
+		connector.getTemperature(hourly); // only
+		connector.getHumidity(hourly);
+		connector.getFeelsLike(hourly); // only
+		connector.getPressure(daily);
+		connector.getWindDirection(hourly);
+		connector.getWindSpeed(daily);
+		connector.getWindGust(daily);
+		connector.getProbabilityOfPrecipitation(hourly);
+		connector.getCloudCover(daily);
+		connector.getDailyRainfall(daily);
+		connector.getDailySnowfall(daily);
+		connector.getOneHourRainfall(hourly);
+		connector.getOneHourSnowfall(hourly);
+		connector.getUltravioletIndex(daily);
+		connector.getDewPoint(hourly);
+		connector.getMorningTemperature(daily);
+		connector.getDaytimeTemperature(daily);
+		connector.getEveningTemperature(daily);
+		connector.getNighttimeTemperature(daily);
+		connector.getLowTemperature(daily);
+		connector.getHighTemperature(daily);
+		connector.getMorningFeelsLike(daily);
+		connector.getDaytimeFeelsLike(daily);
+		connector.getEveningFeelsLike(daily);
+		connector.getNighttimeFeelsLike(daily);
+		// pass
+	}
 
-    @Test
-    public void testAllowedAirPollutionMethods() {
-        OpenWeatherConnector connector = airPollution;
-        Date timestamp = connector.getTimestamp();
-        connector.getAirQualityIndex();
-        connector.getCarbonMonoxide();
-        connector.getNitrogenDioxide();
-        connector.getOzone();
-        connector.getSulfurDioxide();
-        connector.getFineParticulateMatter();
-        connector.getCoarseParticulateMatter();
-        connector.getAmmonia();
-        connector.getAirQualityIndex(timestamp);
-        connector.getCarbonMonoxide(timestamp);
-        connector.getNitrogenDioxide(timestamp);
-        connector.getOzone(timestamp);
-        connector.getSulfurDioxide(timestamp);
-        connector.getFineParticulateMatter(timestamp);
-        connector.getCoarseParticulateMatter(timestamp);
-        connector.getAmmonia(timestamp);
-        // pass
-    }
+	@Test
+	public void testAllowedAirPollutionMethods() {
+		OpenWeatherConnector connector = airPollution;
+		Date timestamp = connector.getTimestamp();
+		connector.getAirQualityIndex();
+		connector.getCarbonMonoxide();
+		connector.getNitrogenDioxide();
+		connector.getOzone();
+		connector.getSulfurDioxide();
+		connector.getFineParticulateMatter();
+		connector.getCoarseParticulateMatter();
+		connector.getAmmonia();
+		connector.getAirQualityIndex(timestamp);
+		connector.getCarbonMonoxide(timestamp);
+		connector.getNitrogenDioxide(timestamp);
+		connector.getOzone(timestamp);
+		connector.getSulfurDioxide(timestamp);
+		connector.getFineParticulateMatter(timestamp);
+		connector.getCoarseParticulateMatter(timestamp);
+		connector.getAmmonia(timestamp);
+		// pass
+	}
 
-    @Test
-    public void testAllowedAirPollutionHistoryMethods() {
-        OpenWeatherConnector connector = airPollutionHistory;
-        Date timestamp = connector.getTimestamps().get(0);
-        connector.getAirQualityIndex(timestamp);
-        connector.getCarbonMonoxide(timestamp);
-        connector.getNitrogenDioxide(timestamp);
-        connector.getOzone(timestamp);
-        connector.getSulfurDioxide(timestamp);
-        connector.getFineParticulateMatter(timestamp);
-        connector.getCoarseParticulateMatter(timestamp);
-        connector.getAmmonia(timestamp);
-        // pass
-    }
+	@Test
+	public void testAllowedAirPollutionHistoryMethods() {
+		OpenWeatherConnector connector = airPollutionHistory;
+		Date timestamp = connector.getTimestamps().get(0);
+		connector.getAirQualityIndex(timestamp);
+		connector.getCarbonMonoxide(timestamp);
+		connector.getNitrogenDioxide(timestamp);
+		connector.getOzone(timestamp);
+		connector.getSulfurDioxide(timestamp);
+		connector.getFineParticulateMatter(timestamp);
+		connector.getCoarseParticulateMatter(timestamp);
+		connector.getAmmonia(timestamp);
+		// pass
+	}
 
-    @Test
-    public void testAllowedAirPollutionForecastMethods() {
-        OpenWeatherConnector connector = airPollutionForecast;
-        Date timestamp = connector.getTimestamps().get(0);
-        connector.getAirQualityIndex(timestamp);
-        connector.getCarbonMonoxide(timestamp);
-        connector.getNitrogenDioxide(timestamp);
-        connector.getOzone(timestamp);
-        connector.getSulfurDioxide(timestamp);
-        connector.getFineParticulateMatter(timestamp);
-        connector.getCoarseParticulateMatter(timestamp);
-        connector.getAmmonia(timestamp);
-        // pass
-    }
+	@Test
+	public void testAllowedAirPollutionForecastMethods() {
+		OpenWeatherConnector connector = airPollutionForecast;
+		Date timestamp = connector.getTimestamps().get(0);
+		connector.getAirQualityIndex(timestamp);
+		connector.getCarbonMonoxide(timestamp);
+		connector.getNitrogenDioxide(timestamp);
+		connector.getOzone(timestamp);
+		connector.getSulfurDioxide(timestamp);
+		connector.getFineParticulateMatter(timestamp);
+		connector.getCoarseParticulateMatter(timestamp);
+		connector.getAmmonia(timestamp);
+		// pass
+	}
 
-    @Test
-    public void testRetrieveDataNotCalled() {
-        OpenWeatherConnector connector = dataLess;
-        Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
-        String failMessage = "Expected IllegalStateException";
-        try {
-            connector.getLatitude();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getLongitude();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getTimestamp();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getTimestamps();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getTimestamps("Anything");
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getWeatherCategories();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getWeatherDescriptions();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getVisibility();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getTemperature();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getHumidity();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getFeelsLike();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getPressure();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getWindDirection();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getWindGust();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getCloudCover();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getOneHourRainfall();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getThreeHourRainfall();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getOneHourSnowfall();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getThreeHourSnowfall();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getWeatherCategories(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getWeatherDescriptions(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getVisibility(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getTemperature(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getHumidity(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getPressure(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getWindDirection(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getWindGust(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getCloudCover(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getProbabilityOfPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getThreeHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getThreeHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getAirQualityIndex();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getCarbonMonoxide();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getNitrogenDioxide();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getOzone();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getSulfurDioxide();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getFineParticulateMatter();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getCoarseParticulateMatter();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getAmmonia();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getAirQualityIndex(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getCarbonMonoxide(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getNitrogenDioxide(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getOzone(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getSulfurDioxide(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getFineParticulateMatter(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getCoarseParticulateMatter(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getAmmonia(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getDewPoint();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getUltravioletIndex();
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getMinutelyPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getDailyRainfall(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getDailySnowfall(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getOneHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getOneHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getDewPoint(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getUltravioletIndex(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getMorningTemperature(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getDaytimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getEveningTemperature(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getNighttimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getLowTemperature(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getHighTemperature(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getMorningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getDaytimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getEveningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        try {
-            connector.getNighttimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (IllegalStateException ignored) {
-        }
-        // pass
-    }
+	@Test
+	public void testRetrieveDataNotCalled() {
+		OpenWeatherConnector connector = dataLess;
+		Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
+		String failMessage = "Expected IllegalStateException";
+		try {
+			connector.getLatitude();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getLongitude();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getTimestamp();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getTimestamps();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getTimestamps("Anything");
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getWeatherCategories();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getWeatherDescriptions();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getVisibility();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getTemperature();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getHumidity();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getFeelsLike();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getPressure();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getWindDirection();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getWindGust();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getCloudCover();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getOneHourRainfall();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getThreeHourRainfall();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getOneHourSnowfall();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getThreeHourSnowfall();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getWeatherCategories(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getWeatherDescriptions(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getVisibility(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getTemperature(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getHumidity(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getPressure(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getWindDirection(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getWindGust(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getCloudCover(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getProbabilityOfPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getThreeHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getThreeHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getAirQualityIndex();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getCarbonMonoxide();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getNitrogenDioxide();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getOzone();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getSulfurDioxide();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getFineParticulateMatter();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getCoarseParticulateMatter();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getAmmonia();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getAirQualityIndex(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getCarbonMonoxide(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getNitrogenDioxide(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getOzone(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getSulfurDioxide(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getFineParticulateMatter(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getCoarseParticulateMatter(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getAmmonia(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getDewPoint();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getUltravioletIndex();
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getMinutelyPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getDailyRainfall(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getDailySnowfall(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getOneHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getOneHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getDewPoint(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getUltravioletIndex(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getMorningTemperature(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getDaytimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getEveningTemperature(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getNighttimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getLowTemperature(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getHighTemperature(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getMorningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getDaytimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getEveningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		try {
+			connector.getNighttimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (IllegalStateException ignored) {
+		}
+		// pass
+	}
 
-    @Test
-    public void testProhibitedWeatherMethods() {
-        OpenWeatherConnector connector = weather;
-        Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
-        String failMessage = "Expected UnsupportedOperationException";
-        try {
-            connector.getWeatherCategories(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherDescriptions(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getVisibility(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHumidity(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getPressure(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindDirection(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindGust(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCloudCover(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getProbabilityOfPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAirQualityIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCarbonMonoxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNitrogenDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOzone();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getSulfurDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFineParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCoarseParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAmmonia();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAirQualityIndex(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCarbonMonoxide(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNitrogenDioxide(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOzone(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getSulfurDioxide(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFineParticulateMatter(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCoarseParticulateMatter(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAmmonia(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMinutelyPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailyRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailySnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getLowTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHighTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        // pass
-    }
+	@Test
+	public void testProhibitedWeatherMethods() {
+		OpenWeatherConnector connector = weather;
+		Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
+		String failMessage = "Expected UnsupportedOperationException";
+		try {
+			connector.getWeatherCategories(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherDescriptions(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getVisibility(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHumidity(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getPressure(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindDirection(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindGust(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCloudCover(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getProbabilityOfPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAirQualityIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCarbonMonoxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNitrogenDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOzone();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getSulfurDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFineParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCoarseParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAmmonia();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAirQualityIndex(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCarbonMonoxide(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNitrogenDioxide(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOzone(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getSulfurDioxide(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFineParticulateMatter(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCoarseParticulateMatter(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAmmonia(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMinutelyPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailyRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailySnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getLowTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHighTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		// pass
+	}
 
-    @Test
-    public void testProhibitedForecastMethods() {
-        OpenWeatherConnector connector = forecast;
-        Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
-        String failMessage = "Expected UnsupportedOperationException";
-        try {
-            connector.getWeatherCategories();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherDescriptions();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getVisibility();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getTemperature();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHumidity();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFeelsLike();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getPressure();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindDirection();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindGust();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCloudCover();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourRainfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourRainfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourSnowfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourSnowfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAirQualityIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCarbonMonoxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNitrogenDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOzone();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getSulfurDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFineParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCoarseParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAmmonia();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAirQualityIndex(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCarbonMonoxide(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNitrogenDioxide(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOzone(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getSulfurDioxide(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFineParticulateMatter(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCoarseParticulateMatter(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAmmonia(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMinutelyPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailyRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailySnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getLowTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHighTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        // pass
-    }
+	@Test
+	public void testProhibitedForecastMethods() {
+		OpenWeatherConnector connector = forecast;
+		Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
+		String failMessage = "Expected UnsupportedOperationException";
+		try {
+			connector.getWeatherCategories();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherDescriptions();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getVisibility();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getTemperature();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHumidity();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFeelsLike();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getPressure();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindDirection();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindGust();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCloudCover();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourRainfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourRainfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourSnowfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourSnowfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAirQualityIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCarbonMonoxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNitrogenDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOzone();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getSulfurDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFineParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCoarseParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAmmonia();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAirQualityIndex(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCarbonMonoxide(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNitrogenDioxide(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOzone(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getSulfurDioxide(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFineParticulateMatter(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCoarseParticulateMatter(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAmmonia(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMinutelyPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailyRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailySnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getLowTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHighTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		// pass
+	}
 
-    @Test
-    public void testProhibitedOneCallMethods() {
-        OpenWeatherConnector connector = oneCall;
-        Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
-        String failMessage = "Expected UnsupportedOperationException";
-        try {
-            connector.getThreeHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAirQualityIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCarbonMonoxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNitrogenDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOzone();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getSulfurDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFineParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCoarseParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAmmonia();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAirQualityIndex(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCarbonMonoxide(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNitrogenDioxide(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOzone(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getSulfurDioxide(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFineParticulateMatter(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCoarseParticulateMatter(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAmmonia(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        // pass
-    }
+	@Test
+	public void testProhibitedOneCallMethods() {
+		OpenWeatherConnector connector = oneCall;
+		Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
+		String failMessage = "Expected UnsupportedOperationException";
+		try {
+			connector.getThreeHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAirQualityIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCarbonMonoxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNitrogenDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOzone();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getSulfurDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFineParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCoarseParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAmmonia();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAirQualityIndex(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCarbonMonoxide(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNitrogenDioxide(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOzone(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getSulfurDioxide(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFineParticulateMatter(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCoarseParticulateMatter(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAmmonia(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		// pass
+	}
 
-    @Test
-    public void testProhibitedAirPollutionMethods() {
-        OpenWeatherConnector connector = airPollution;
-        Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
-        String failMessage = "Expected UnsupportedOperationException";
-        try {
-            connector.getWeatherCategories();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherDescriptions();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getVisibility();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getTemperature();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHumidity();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFeelsLike();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getPressure();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindDirection();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindGust();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCloudCover();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourRainfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourRainfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourSnowfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourSnowfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherCategories(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherDescriptions(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getVisibility(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHumidity(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getPressure(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindDirection(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindGust(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCloudCover(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getProbabilityOfPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMinutelyPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailyRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailySnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getLowTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHighTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        // pass
-    }
+	@Test
+	public void testProhibitedAirPollutionMethods() {
+		OpenWeatherConnector connector = airPollution;
+		Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
+		String failMessage = "Expected UnsupportedOperationException";
+		try {
+			connector.getWeatherCategories();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherDescriptions();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getVisibility();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getTemperature();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHumidity();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFeelsLike();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getPressure();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindDirection();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindGust();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCloudCover();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourRainfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourRainfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourSnowfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourSnowfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherCategories(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherDescriptions(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getVisibility(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHumidity(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getPressure(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindDirection(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindGust(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCloudCover(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getProbabilityOfPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMinutelyPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailyRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailySnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getLowTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHighTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		// pass
+	}
 
-    @Test
-    public void testProhibitedAirPollutionHistoryMethods() {
-        OpenWeatherConnector connector = airPollutionHistory;
-        Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
-        String failMessage = "Expected UnsupportedOperationException";
-        try {
-            connector.getWeatherCategories();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherDescriptions();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getVisibility();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getTemperature();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHumidity();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFeelsLike();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getPressure();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindDirection();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindGust();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCloudCover();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourRainfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourRainfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourSnowfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourSnowfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherCategories(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherDescriptions(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getVisibility(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHumidity(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getPressure(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindDirection(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindGust(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCloudCover(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getProbabilityOfPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAirQualityIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCarbonMonoxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNitrogenDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOzone();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getSulfurDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFineParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCoarseParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAmmonia();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMinutelyPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailyRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailySnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getLowTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHighTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        // pass
-    }
+	@Test
+	public void testProhibitedAirPollutionHistoryMethods() {
+		OpenWeatherConnector connector = airPollutionHistory;
+		Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
+		String failMessage = "Expected UnsupportedOperationException";
+		try {
+			connector.getWeatherCategories();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherDescriptions();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getVisibility();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getTemperature();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHumidity();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFeelsLike();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getPressure();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindDirection();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindGust();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCloudCover();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourRainfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourRainfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourSnowfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourSnowfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherCategories(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherDescriptions(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getVisibility(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHumidity(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getPressure(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindDirection(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindGust(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCloudCover(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getProbabilityOfPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAirQualityIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCarbonMonoxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNitrogenDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOzone();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getSulfurDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFineParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCoarseParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAmmonia();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMinutelyPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailyRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailySnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getLowTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHighTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		// pass
+	}
 
-    @Test
-    public void testProhibitedAirPollutionForecastMethods() {
-        OpenWeatherConnector connector = airPollutionForecast;
-        Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
-        String failMessage = "Expected UnsupportedOperationException";
-        try {
-            connector.getWeatherCategories();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherDescriptions();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getVisibility();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getTemperature();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHumidity();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFeelsLike();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getPressure();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindDirection();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindGust();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCloudCover();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourRainfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourRainfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourSnowfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourSnowfall();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherCategories(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWeatherDescriptions(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getVisibility(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHumidity(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getPressure(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindDirection(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getWindGust(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCloudCover(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getProbabilityOfPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getThreeHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAirQualityIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCarbonMonoxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNitrogenDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOzone();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getSulfurDioxide();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getFineParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getCoarseParticulateMatter();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getAmmonia();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex();
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMinutelyPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailyRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDailySnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getOneHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDewPoint(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getUltravioletIndex(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getLowTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getHighTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getMorningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getDaytimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getEveningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        try {
-            connector.getNighttimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
-        }
-        // pass
-    }
+	@Test
+	public void testProhibitedAirPollutionForecastMethods() {
+		OpenWeatherConnector connector = airPollutionForecast;
+		Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE;
+		String failMessage = "Expected UnsupportedOperationException";
+		try {
+			connector.getWeatherCategories();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherDescriptions();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getVisibility();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getTemperature();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHumidity();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFeelsLike();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getPressure();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindDirection();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindGust();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCloudCover();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourRainfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourRainfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourSnowfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourSnowfall();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherCategories(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWeatherDescriptions(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getVisibility(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHumidity(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getPressure(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindDirection(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getWindGust(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCloudCover(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getProbabilityOfPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getThreeHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAirQualityIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCarbonMonoxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNitrogenDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOzone();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getSulfurDioxide();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getFineParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getCoarseParticulateMatter();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getAmmonia();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex();
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMinutelyPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailyRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDailySnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getOneHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDewPoint(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getUltravioletIndex(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getLowTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getHighTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getMorningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getDaytimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getEveningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		try {
+			connector.getNighttimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset"));
+		}
+		// pass
+	}
 
-    @Test
-    public void testOnlyMinutelyMethods() {
-        OpenWeatherConnector connector = oneCall;
-        Date timestamp = connector.getTimestamps("minutely").get(0);
-        String failMessage = "Expected UnsupportedOperationException";
-        connector.getMinutelyPrecipitation(timestamp);
-        try {
-            connector.getVisibility(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getOneHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getOneHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getMorningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getDaytimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getEveningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getNighttimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getLowTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getHighTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getMorningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getDaytimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getEveningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getNighttimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-    }
+	@Test
+	public void testOnlyMinutelyMethods() {
+		OpenWeatherConnector connector = oneCall;
+		Date timestamp = connector.getTimestamps("minutely").get(0);
+		String failMessage = "Expected UnsupportedOperationException";
+		connector.getMinutelyPrecipitation(timestamp);
+		try {
+			connector.getVisibility(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getOneHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getOneHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getMorningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getDaytimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getEveningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getNighttimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getLowTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getHighTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getMorningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getDaytimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getEveningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getNighttimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+	}
 
-    @Test
-    public void testOnlyHourlyMethods() {
-        OpenWeatherConnector connector = oneCall;
-        Date timestamp = connector.getTimestamps("hourly").get(0);
-        String failMessage = "Expected UnsupportedOperationException";
-        try {
-            connector.getMinutelyPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for minutely timestamps.", exception.getMessage());
-        }
-        connector.getVisibility(timestamp);
-        connector.getTemperature(timestamp);
-        connector.getFeelsLike(timestamp);
-        connector.getOneHourRainfall(timestamp);
-        connector.getOneHourSnowfall(timestamp);
-        try {
-            connector.getMorningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getDaytimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getEveningTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getNighttimeTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getLowTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getHighTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getMorningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getDaytimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getEveningFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getNighttimeFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
-        }
-    }
+	@Test
+	public void testOnlyHourlyMethods() {
+		OpenWeatherConnector connector = oneCall;
+		Date timestamp = connector.getTimestamps("hourly").get(0);
+		String failMessage = "Expected UnsupportedOperationException";
+		try {
+			connector.getMinutelyPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for minutely timestamps.", exception.getMessage());
+		}
+		connector.getVisibility(timestamp);
+		connector.getTemperature(timestamp);
+		connector.getFeelsLike(timestamp);
+		connector.getOneHourRainfall(timestamp);
+		connector.getOneHourSnowfall(timestamp);
+		try {
+			connector.getMorningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getDaytimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getEveningTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getNighttimeTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getLowTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getHighTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getMorningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getDaytimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getEveningFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getNighttimeFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage());
+		}
+	}
 
-    @Test
-    public void testOnlyDailyMethods() {
-        OpenWeatherConnector connector = oneCall;
-        Date timestamp = connector.getTimestamps("daily").get(0);
-        String failMessage = "Expected UnsupportedOperationException";
-        try {
-            connector.getMinutelyPrecipitation(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for minutely timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getVisibility(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getTemperature(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getFeelsLike(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getOneHourRainfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        try {
-            connector.getOneHourSnowfall(timestamp);
-            fail(failMessage);
-        } catch (UnsupportedOperationException exception) {
-            assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
-        }
-        connector.getMorningTemperature(timestamp);
-        connector.getDaytimeTemperature(timestamp);
-        connector.getEveningTemperature(timestamp);
-        connector.getNighttimeTemperature(timestamp);
-        connector.getLowTemperature(timestamp);
-        connector.getHighTemperature(timestamp);
-        connector.getMorningFeelsLike(timestamp);
-        connector.getDaytimeFeelsLike(timestamp);
-        connector.getEveningFeelsLike(timestamp);
-        connector.getNighttimeFeelsLike(timestamp);
-    }
+	@Test
+	public void testOnlyDailyMethods() {
+		OpenWeatherConnector connector = oneCall;
+		Date timestamp = connector.getTimestamps("daily").get(0);
+		String failMessage = "Expected UnsupportedOperationException";
+		try {
+			connector.getMinutelyPrecipitation(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for minutely timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getVisibility(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getTemperature(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getFeelsLike(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getOneHourRainfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		try {
+			connector.getOneHourSnowfall(timestamp);
+			fail(failMessage);
+		} catch (UnsupportedOperationException exception) {
+			assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage());
+		}
+		connector.getMorningTemperature(timestamp);
+		connector.getDaytimeTemperature(timestamp);
+		connector.getEveningTemperature(timestamp);
+		connector.getNighttimeTemperature(timestamp);
+		connector.getLowTemperature(timestamp);
+		connector.getHighTemperature(timestamp);
+		connector.getMorningFeelsLike(timestamp);
+		connector.getDaytimeFeelsLike(timestamp);
+		connector.getEveningFeelsLike(timestamp);
+		connector.getNighttimeFeelsLike(timestamp);
+	}
 }
diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/Forecast_UnlNov7ToNov12Test.java b/src/test/java/edu/unl/cse/soft160/json_connections/Forecast_UnlNov7ToNov12Test.java
index b62c3c2..7770b84 100644
--- a/src/test/java/edu/unl/cse/soft160/json_connections/Forecast_UnlNov7ToNov12Test.java
+++ b/src/test/java/edu/unl/cse/soft160/json_connections/Forecast_UnlNov7ToNov12Test.java
@@ -11,115 +11,114 @@ import java.util.List;
 import static org.junit.Assert.assertEquals;
 
 public class Forecast_UnlNov7ToNov12Test {
-    private OpenWeatherConnector connector;
-    private Date Sunday, Monday, Tuesday, Wednesday, Thursday, Friday;
+	private OpenWeatherConnector connector;
+	private Date Sunday, Monday, Tuesday, Wednesday, Thursday, Friday;
 
-    @Before
-    public void setup() throws IOException {
-        connector = new OpenWeatherConnector("forecast");
-        connector.retrieveData("forecasted_weather-unl-nov7-nov12.json");
-        List<Date> timestamps = connector.getTimestamps();
-        Sunday = timestamps.get(0);
-        Monday = timestamps.get(8);
-        Tuesday = timestamps.get(16);
-        Wednesday = timestamps.get(24);
-        Thursday = timestamps.get(32);
-        Friday = timestamps.get(39);
-    }
+	@Before
+	public void setup() throws IOException {
+		connector = new OpenWeatherConnector("forecast");
+		connector.retrieveData("forecasted_weather-unl-nov7-nov12.json");
+		List<Date> timestamps = connector.getTimestamps();
+		Sunday = timestamps.get(0);
+		Monday = timestamps.get(8);
+		Tuesday = timestamps.get(16);
+		Wednesday = timestamps.get(24);
+		Thursday = timestamps.get(32);
+		Friday = timestamps.get(39);
+	}
 
-    @Test
-    public void testLocation() {
-        double expectedLatitude = 40.8206;
-        double expectedLongitude = -96.6928;
-        double actualLatitude = connector.getLatitude();
-        double actualLongitude = connector.getLongitude();
-        assertEquals(expectedLatitude, actualLatitude, 0.0001);
-        assertEquals(expectedLongitude, actualLongitude, 0.0001);
-    }
+	@Test
+	public void testLocation() {
+		double expectedLatitude = 40.8206;
+		double expectedLongitude = -96.6928;
+		double actualLatitude = connector.getLatitude();
+		double actualLongitude = connector.getLongitude();
+		assertEquals(expectedLatitude, actualLatitude, 0.0001);
+		assertEquals(expectedLongitude, actualLongitude, 0.0001);
+	}
 
-    @Test
-    public void testWeather() {
-        Date timestamp = Sunday;
-        List<OpenWeatherConnector.WeatherCategory> expectedCategories = List.of(
-                OpenWeatherConnector.WeatherCategory.CLEAR
-        );
-        List<String> expectedDescriptions = List.of("clear sky");
-        int expectedListSize = 1;
-        List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(timestamp);
-        List<String> actualDescriptions = connector.getWeatherDescriptions(timestamp);
-        assertEquals(expectedListSize, actualCategories.size());
-        assertEquals(expectedListSize, actualDescriptions.size());
-        assertEquals(expectedCategories, actualCategories);
-        assertEquals(expectedDescriptions, actualDescriptions);
-    }
+	@Test
+	public void testWeather() {
+		Date timestamp = Sunday;
+		List<OpenWeatherConnector.WeatherCategory> expectedCategories = List
+				.of(OpenWeatherConnector.WeatherCategory.CLEAR);
+		List<String> expectedDescriptions = List.of("clear sky");
+		int expectedListSize = 1;
+		List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(timestamp);
+		List<String> actualDescriptions = connector.getWeatherDescriptions(timestamp);
+		assertEquals(expectedListSize, actualCategories.size());
+		assertEquals(expectedListSize, actualDescriptions.size());
+		assertEquals(expectedCategories, actualCategories);
+		assertEquals(expectedDescriptions, actualDescriptions);
+	}
 
-    @Test
-    public void testMainObservations() {
-        Date timestamp = Monday;
-        long expectedVisibility = 10000;
-        double expectedAmbientTemperature = 285.91;
-        long expectedHumidity = 70;
-        double expectedFeelsLikeTemperature = 285.07;
-        long expectedPressure = 1016;
-        long actualVisibility = connector.getVisibility(timestamp);
-        double actualAmbientTemperature = connector.getTemperature(timestamp);
-        long actualHumidity = connector.getHumidity(timestamp);
-        double actualFeelsLikeTemperature = connector.getFeelsLike(timestamp);
-        long actualPressure = connector.getPressure(timestamp);
-        assertEquals(expectedVisibility, actualVisibility);
-        assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
-        assertEquals(expectedHumidity, actualHumidity);
-        assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
-        assertEquals(expectedPressure, actualPressure);
-    }
+	@Test
+	public void testMainObservations() {
+		Date timestamp = Monday;
+		long expectedVisibility = 10000;
+		double expectedAmbientTemperature = 285.91;
+		long expectedHumidity = 70;
+		double expectedFeelsLikeTemperature = 285.07;
+		long expectedPressure = 1016;
+		long actualVisibility = connector.getVisibility(timestamp);
+		double actualAmbientTemperature = connector.getTemperature(timestamp);
+		long actualHumidity = connector.getHumidity(timestamp);
+		double actualFeelsLikeTemperature = connector.getFeelsLike(timestamp);
+		long actualPressure = connector.getPressure(timestamp);
+		assertEquals(expectedVisibility, actualVisibility);
+		assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
+		assertEquals(expectedHumidity, actualHumidity);
+		assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
+		assertEquals(expectedPressure, actualPressure);
+	}
 
-    @Test
-    public void testWinds() {
-        Date timestamp = Tuesday;
-        long expectedDirection = 357;
-        double expectedSpeed = 5.6;
-        double expectedGust = 9.73;
-        long actualDirection = connector.getWindDirection(timestamp);
-        double actualSpeed = connector.getWindSpeed(timestamp);
-        double actualGust = connector.getWindGust(timestamp);
-        assertEquals(expectedDirection, actualDirection);
-        assertEquals(expectedSpeed, actualSpeed, 0.0001);
-        assertEquals(expectedGust, actualGust, 0.0001);
-    }
+	@Test
+	public void testWinds() {
+		Date timestamp = Tuesday;
+		long expectedDirection = 357;
+		double expectedSpeed = 5.6;
+		double expectedGust = 9.73;
+		long actualDirection = connector.getWindDirection(timestamp);
+		double actualSpeed = connector.getWindSpeed(timestamp);
+		double actualGust = connector.getWindGust(timestamp);
+		assertEquals(expectedDirection, actualDirection);
+		assertEquals(expectedSpeed, actualSpeed, 0.0001);
+		assertEquals(expectedGust, actualGust, 0.0001);
+	}
 
-    @Test
-    public void testClouds() {
-        Date timestamp = Friday;
-        long expectedValue = 48;
-        long actualValue = connector.getCloudCover(timestamp);
-        assertEquals(expectedValue, actualValue);
-    }
+	@Test
+	public void testClouds() {
+		Date timestamp = Friday;
+		long expectedValue = 48;
+		long actualValue = connector.getCloudCover(timestamp);
+		assertEquals(expectedValue, actualValue);
+	}
 
-    @Test
-    public void testPrecipitationWhenNoRain() {
-        Date timestamp = Thursday;
-        double expectedProbability = 0.0;
-        double expected3HourRain = 0.0;
-        double expected3HourSnow = 0.0;
-        double actualProbability = connector.getProbabilityOfPrecipitation(timestamp);
-        double actual3HourRain = connector.getThreeHourRainfall(timestamp);
-        double actual3HourSnow = connector.getThreeHourSnowfall(timestamp);
-        assertEquals(expectedProbability, actualProbability, 0.0001);
-        assertEquals(expected3HourRain, actual3HourRain, 0.0001);
-        assertEquals(expected3HourSnow, actual3HourSnow, 0.0001);
-    }
+	@Test
+	public void testPrecipitationWhenNoRain() {
+		Date timestamp = Thursday;
+		double expectedProbability = 0.0;
+		double expected3HourRain = 0.0;
+		double expected3HourSnow = 0.0;
+		double actualProbability = connector.getProbabilityOfPrecipitation(timestamp);
+		double actual3HourRain = connector.getThreeHourRainfall(timestamp);
+		double actual3HourSnow = connector.getThreeHourSnowfall(timestamp);
+		assertEquals(expectedProbability, actualProbability, 0.0001);
+		assertEquals(expected3HourRain, actual3HourRain, 0.0001);
+		assertEquals(expected3HourSnow, actual3HourSnow, 0.0001);
+	}
 
-    @Test
-    public void testPrecipitationWhenRainForecasted() {
-        Date timestamp = Wednesday;
-        double expectedProbability = 0.27;
-        double expected3HourRain = 0.18;
-        double expected3HourSnow = 0.0;
-        double actualProbability = connector.getProbabilityOfPrecipitation(timestamp);
-        double actual3HourRain = connector.getThreeHourRainfall(timestamp);
-        double actual3HourSnow = connector.getThreeHourSnowfall(timestamp);
-        assertEquals(expectedProbability, actualProbability, 0.0001);
-        assertEquals(expected3HourRain, actual3HourRain, 0.0001);
-        assertEquals(expected3HourSnow, actual3HourSnow, 0.0001);
-    }
+	@Test
+	public void testPrecipitationWhenRainForecasted() {
+		Date timestamp = Wednesday;
+		double expectedProbability = 0.27;
+		double expected3HourRain = 0.18;
+		double expected3HourSnow = 0.0;
+		double actualProbability = connector.getProbabilityOfPrecipitation(timestamp);
+		double actual3HourRain = connector.getThreeHourRainfall(timestamp);
+		double actual3HourSnow = connector.getThreeHourSnowfall(timestamp);
+		assertEquals(expectedProbability, actualProbability, 0.0001);
+		assertEquals(expected3HourRain, actual3HourRain, 0.0001);
+		assertEquals(expected3HourSnow, actual3HourSnow, 0.0001);
+	}
 }
diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/OneCall_WebsiteExampleTest.java b/src/test/java/edu/unl/cse/soft160/json_connections/OneCall_WebsiteExampleTest.java
index 81883c2..039f857 100644
--- a/src/test/java/edu/unl/cse/soft160/json_connections/OneCall_WebsiteExampleTest.java
+++ b/src/test/java/edu/unl/cse/soft160/json_connections/OneCall_WebsiteExampleTest.java
@@ -12,278 +12,277 @@ import java.util.stream.Collectors;
 import static org.junit.Assert.assertEquals;
 
 public class OneCall_WebsiteExampleTest {
-    private OpenWeatherConnector connector;
-    private Date minutely, hourly, daily;
+	private OpenWeatherConnector connector;
+	private Date minutely, hourly, daily;
 
-    @Before
-    public void setup() throws IOException {
-        connector = new OpenWeatherConnector("onecall");
-        connector.retrieveData("website-example.json");
-        minutely = connector.getTimestamps("minutely").get(0);
-        hourly = connector.getTimestamps("hourly").get(0);
-        daily = connector.getTimestamps("daily").get(0);
-    }
+	@Before
+	public void setup() throws IOException {
+		connector = new OpenWeatherConnector("onecall");
+		connector.retrieveData("website-example.json");
+		minutely = connector.getTimestamps("minutely").get(0);
+		hourly = connector.getTimestamps("hourly").get(0);
+		daily = connector.getTimestamps("daily").get(0);
+	}
 
-    @Test
-    public void testLocation() {
-        double expectedLatitude = 33.44;
-        double expectedLongitude = -94.04;
-        double actualLatitude = connector.getLatitude();
-        double actualLongitude = connector.getLongitude();
-        assertEquals(expectedLatitude, actualLatitude, 0.0001);
-        assertEquals(expectedLongitude, actualLongitude, 0.0001);
-    }
+	@Test
+	public void testLocation() {
+		double expectedLatitude = 33.44;
+		double expectedLongitude = -94.04;
+		double actualLatitude = connector.getLatitude();
+		double actualLongitude = connector.getLongitude();
+		assertEquals(expectedLatitude, actualLatitude, 0.0001);
+		assertEquals(expectedLongitude, actualLongitude, 0.0001);
+	}
 
-    @Test
-    public void testCurrentDateTime() {
+	@Test
+	public void testCurrentDateTime() {
 //        Date expectedValue = new Date(16183170400000L);
-        String expectedValue = "Tue Apr 13 07:30:40 CDT 2021";
-        Date actualValue = connector.getTimestamp();
-        assertEquals(expectedValue, actualValue.toString());
-    }
+		String expectedValue = "Tue Apr 13 07:30:40 CDT 2021";
+		Date actualValue = connector.getTimestamp();
+		assertEquals(expectedValue, actualValue.toString());
+	}
 
-    @Test
-    public void testListDateTimes() {
+	@Test
+	public void testListDateTimes() {
 //        List<Date> expectedMinutes = List.of(new Date(1618317060000L));
 //        List<Date> expectedHours = List.of(new Date(1618315200000L));
 //        List<Date> expectedDays = List.of(new Date(1618308000000L));
-        List<String> expectedMinutes = List.of("Tue Apr 13 07:31:00 CDT 2021");
-        List<String> expectedHours = List.of("Tue Apr 13 07:00:00 CDT 2021");
-        List<String> expectedDays = List.of("Tue Apr 13 05:00:00 CDT 2021");
-        List<String> actualMinutes = connector.getTimestamps("minutely")
-                .stream().map(Date::toString).collect(Collectors.toList());
-        List<String> actualHours = connector.getTimestamps("hourly")
-                .stream().map(Date::toString).collect(Collectors.toList());
-        List<String> actualDays = connector.getTimestamps("daily")
-                .stream().map(Date::toString).collect(Collectors.toList());
-        assertEquals(expectedMinutes, actualMinutes);
-        assertEquals(expectedHours, actualHours);
-        assertEquals(expectedDays, actualDays);
-    }
+		List<String> expectedMinutes = List.of("Tue Apr 13 07:31:00 CDT 2021");
+		List<String> expectedHours = List.of("Tue Apr 13 07:00:00 CDT 2021");
+		List<String> expectedDays = List.of("Tue Apr 13 05:00:00 CDT 2021");
+		List<String> actualMinutes = connector.getTimestamps("minutely").stream().map(Date::toString)
+				.collect(Collectors.toList());
+		List<String> actualHours = connector.getTimestamps("hourly").stream().map(Date::toString)
+				.collect(Collectors.toList());
+		List<String> actualDays = connector.getTimestamps("daily").stream().map(Date::toString)
+				.collect(Collectors.toList());
+		assertEquals(expectedMinutes, actualMinutes);
+		assertEquals(expectedHours, actualHours);
+		assertEquals(expectedDays, actualDays);
+	}
 
-    @Test
-    public void testWeather() {
-        OpenWeatherConnector.WeatherCategory expectedCategory = OpenWeatherConnector.WeatherCategory.RAIN;
-        String expectedDescription = "light rain";
-        int expectedListSize = 1;
-        List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories();
-        List<String> actualDescriptions = connector.getWeatherDescriptions();
-        assertEquals(expectedListSize, actualCategories.size());
-        assertEquals(expectedListSize, actualDescriptions.size());
-        assertEquals(expectedCategory, actualCategories.get(0));
-        assertEquals(expectedDescription, actualDescriptions.get(0));
-    }
+	@Test
+	public void testWeather() {
+		OpenWeatherConnector.WeatherCategory expectedCategory = OpenWeatherConnector.WeatherCategory.RAIN;
+		String expectedDescription = "light rain";
+		int expectedListSize = 1;
+		List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories();
+		List<String> actualDescriptions = connector.getWeatherDescriptions();
+		assertEquals(expectedListSize, actualCategories.size());
+		assertEquals(expectedListSize, actualDescriptions.size());
+		assertEquals(expectedCategory, actualCategories.get(0));
+		assertEquals(expectedDescription, actualDescriptions.get(0));
+	}
 
-    @Test
-    public void testMainObservationsCommonWithWeatherDataset() {
-        long expectedVisibility = 10000;
-        double expectedAmbientTemperature = 284.07;
-        long expectedHumidity = 62;
-        double expectedFeelsLikeTemperature = 282.84;
-        long expectedPressure = 1019;
-        long actualVisibility = connector.getVisibility();
-        double actualAmbientTemperature = connector.getTemperature();
-        long actualHumidity = connector.getHumidity();
-        double actualFeelsLikeTemperature = connector.getFeelsLike();
-        long actualPressure = connector.getPressure();
-        assertEquals(expectedVisibility, actualVisibility);
-        assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
-        assertEquals(expectedHumidity, actualHumidity);
-        assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
-        assertEquals(expectedPressure, actualPressure);
-    }
+	@Test
+	public void testMainObservationsCommonWithWeatherDataset() {
+		long expectedVisibility = 10000;
+		double expectedAmbientTemperature = 284.07;
+		long expectedHumidity = 62;
+		double expectedFeelsLikeTemperature = 282.84;
+		long expectedPressure = 1019;
+		long actualVisibility = connector.getVisibility();
+		double actualAmbientTemperature = connector.getTemperature();
+		long actualHumidity = connector.getHumidity();
+		double actualFeelsLikeTemperature = connector.getFeelsLike();
+		long actualPressure = connector.getPressure();
+		assertEquals(expectedVisibility, actualVisibility);
+		assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
+		assertEquals(expectedHumidity, actualHumidity);
+		assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
+		assertEquals(expectedPressure, actualPressure);
+	}
 
-    @Test
-    public void testMainObservationsUniqueToOnecallDataset() {
-        double expectedDewPoint = 277.08;
-        double expectedUVI = 0.89;
-        double actualDewPoint = connector.getDewPoint();
-        double actualUVI = connector.getUltravioletIndex();
-        assertEquals(expectedDewPoint, actualDewPoint, 0.0001);
-        assertEquals(expectedUVI, actualUVI, 0.0001);
-    }
+	@Test
+	public void testMainObservationsUniqueToOnecallDataset() {
+		double expectedDewPoint = 277.08;
+		double expectedUVI = 0.89;
+		double actualDewPoint = connector.getDewPoint();
+		double actualUVI = connector.getUltravioletIndex();
+		assertEquals(expectedDewPoint, actualDewPoint, 0.0001);
+		assertEquals(expectedUVI, actualUVI, 0.0001);
+	}
 
-    @Test
-    public void testWinds() {
-        long expectedDirection = 300;
-        double expectedSpeed = 6.0;
-        double expectedGust = 6.0;
-        long actualDirection = connector.getWindDirection();
-        double actualSpeed = connector.getWindSpeed();
-        double actualGust = connector.getWindGust();
-        assertEquals(expectedDirection, actualDirection);
-        assertEquals(expectedSpeed, actualSpeed, 0.0001);
-        assertEquals(expectedGust, actualGust, 0.0001);
-    }
+	@Test
+	public void testWinds() {
+		long expectedDirection = 300;
+		double expectedSpeed = 6.0;
+		double expectedGust = 6.0;
+		long actualDirection = connector.getWindDirection();
+		double actualSpeed = connector.getWindSpeed();
+		double actualGust = connector.getWindGust();
+		assertEquals(expectedDirection, actualDirection);
+		assertEquals(expectedSpeed, actualSpeed, 0.0001);
+		assertEquals(expectedGust, actualGust, 0.0001);
+	}
 
-    @Test
-    public void testClouds() {
-        long expectedValue = 0;
-        long actualValue = connector.getCloudCover();
-        assertEquals(expectedValue, actualValue);
-    }
+	@Test
+	public void testClouds() {
+		long expectedValue = 0;
+		long actualValue = connector.getCloudCover();
+		assertEquals(expectedValue, actualValue);
+	}
 
-    @Test
-    public void testPrecipitation() {
-        double expected1HourRain = 0.21;
-        double expected1HourSnow = 0.0;
-        double actual1HourRain = connector.getOneHourRainfall();
-        double actual1HourSnow = connector.getOneHourSnowfall();
-        assertEquals(expected1HourRain, actual1HourRain, 0.0001);
-        assertEquals(expected1HourSnow, actual1HourSnow, 0.0001);
-    }
+	@Test
+	public void testPrecipitation() {
+		double expected1HourRain = 0.21;
+		double expected1HourSnow = 0.0;
+		double actual1HourRain = connector.getOneHourRainfall();
+		double actual1HourSnow = connector.getOneHourSnowfall();
+		assertEquals(expected1HourRain, actual1HourRain, 0.0001);
+		assertEquals(expected1HourSnow, actual1HourSnow, 0.0001);
+	}
 
-    @Test
-    public void testWeatherForecast() {
-        List<OpenWeatherConnector.WeatherCategory> expectedCategories = List.of(
-                OpenWeatherConnector.WeatherCategory.CLOUDS
-        );
-        List<String> expectedDescriptions = List.of("few clouds");
-        int expectedListSize = 1;
-        List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(hourly);
-        List<String> actualDescriptions = connector.getWeatherDescriptions(hourly);
-        assertEquals(expectedListSize, actualCategories.size());
-        assertEquals(expectedListSize, actualDescriptions.size());
-        assertEquals(expectedCategories, actualCategories);
-        assertEquals(expectedDescriptions, actualDescriptions);
+	@Test
+	public void testWeatherForecast() {
+		List<OpenWeatherConnector.WeatherCategory> expectedCategories = List
+				.of(OpenWeatherConnector.WeatherCategory.CLOUDS);
+		List<String> expectedDescriptions = List.of("few clouds");
+		int expectedListSize = 1;
+		List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(hourly);
+		List<String> actualDescriptions = connector.getWeatherDescriptions(hourly);
+		assertEquals(expectedListSize, actualCategories.size());
+		assertEquals(expectedListSize, actualDescriptions.size());
+		assertEquals(expectedCategories, actualCategories);
+		assertEquals(expectedDescriptions, actualDescriptions);
 
-        expectedCategories = List.of(OpenWeatherConnector.WeatherCategory.RAIN);
-        expectedDescriptions = List.of("light rain");
-        actualCategories = connector.getWeatherCategories(daily);
-        actualDescriptions = connector.getWeatherDescriptions(daily);
-        assertEquals(expectedListSize, actualCategories.size());
-        assertEquals(expectedListSize, actualDescriptions.size());
-        assertEquals(expectedCategories, actualCategories);
-        assertEquals(expectedDescriptions, actualDescriptions);
-    }
+		expectedCategories = List.of(OpenWeatherConnector.WeatherCategory.RAIN);
+		expectedDescriptions = List.of("light rain");
+		actualCategories = connector.getWeatherCategories(daily);
+		actualDescriptions = connector.getWeatherDescriptions(daily);
+		assertEquals(expectedListSize, actualCategories.size());
+		assertEquals(expectedListSize, actualDescriptions.size());
+		assertEquals(expectedCategories, actualCategories);
+		assertEquals(expectedDescriptions, actualDescriptions);
+	}
 
-    @Test
-    public void testMainObservationForecast() {
-        long expectedVisibility = 306;
-        double expectedAmbientTemperature = 282.58;
-        long expectedHumidity = 68;
-        double expectedFeelsLikeTemperature = 280.4;
-        long expectedPressure = 1019;
-        double expectedDewPoint = 276.98;
-        double expectedUVI = 1.4;
-        long actualVisibility = connector.getVisibility(hourly);
-        double actualAmbientTemperature = connector.getTemperature(hourly);
-        long actualHumidity = connector.getHumidity(hourly);
-        double actualFeelsLikeTemperature = connector.getFeelsLike(hourly);
-        long actualPressure = connector.getPressure(hourly);
-        double actualDewPoint = connector.getDewPoint(hourly);
-        double actualUVI = connector.getUltravioletIndex(hourly);
-        assertEquals(expectedVisibility, actualVisibility);
-        assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
-        assertEquals(expectedHumidity, actualHumidity);
-        assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
-        assertEquals(expectedPressure, actualPressure);
-        assertEquals(expectedDewPoint, actualDewPoint, 0.0001);
-        assertEquals(expectedUVI, actualUVI, 0.0001);
+	@Test
+	public void testMainObservationForecast() {
+		long expectedVisibility = 306;
+		double expectedAmbientTemperature = 282.58;
+		long expectedHumidity = 68;
+		double expectedFeelsLikeTemperature = 280.4;
+		long expectedPressure = 1019;
+		double expectedDewPoint = 276.98;
+		double expectedUVI = 1.4;
+		long actualVisibility = connector.getVisibility(hourly);
+		double actualAmbientTemperature = connector.getTemperature(hourly);
+		long actualHumidity = connector.getHumidity(hourly);
+		double actualFeelsLikeTemperature = connector.getFeelsLike(hourly);
+		long actualPressure = connector.getPressure(hourly);
+		double actualDewPoint = connector.getDewPoint(hourly);
+		double actualUVI = connector.getUltravioletIndex(hourly);
+		assertEquals(expectedVisibility, actualVisibility);
+		assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
+		assertEquals(expectedHumidity, actualHumidity);
+		assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
+		assertEquals(expectedPressure, actualPressure);
+		assertEquals(expectedDewPoint, actualDewPoint, 0.0001);
+		assertEquals(expectedUVI, actualUVI, 0.0001);
 
-        expectedHumidity = 81;
-        expectedPressure = 1020;
-        expectedDewPoint = 276.77;
-        expectedUVI = 1.93;
-        actualHumidity = connector.getHumidity(daily);
-        actualPressure = connector.getPressure(daily);
-        assertEquals(expectedHumidity, actualHumidity);
-        assertEquals(expectedPressure, actualPressure);
-        actualDewPoint = connector.getDewPoint(daily);
-        actualUVI = connector.getUltravioletIndex(daily);
-        assertEquals(expectedDewPoint, actualDewPoint, 0.0001);
-        assertEquals(expectedUVI, actualUVI, 0.0001);
+		expectedHumidity = 81;
+		expectedPressure = 1020;
+		expectedDewPoint = 276.77;
+		expectedUVI = 1.93;
+		actualHumidity = connector.getHumidity(daily);
+		actualPressure = connector.getPressure(daily);
+		assertEquals(expectedHumidity, actualHumidity);
+		assertEquals(expectedPressure, actualPressure);
+		actualDewPoint = connector.getDewPoint(daily);
+		actualUVI = connector.getUltravioletIndex(daily);
+		assertEquals(expectedDewPoint, actualDewPoint, 0.0001);
+		assertEquals(expectedUVI, actualUVI, 0.0001);
 
-        double expectedMorningTemperature = 278.49;
-        double expectedDaytimeTemperature = 279.79;
-        double expectedEveningTemperature = 279.21;
-        double expectedNighttimeTemperature = 275.09;
-        double expectedHighTemperature = 284.07;
-        double expectedLowTemperature = 275.09;
-        double expectedMorningFeelsLikeTemperature = 276.27;
-        double expectedDaytimeFeelsLikeTemperature = 277.59;
-        double expectedEveningFeelsLikeTemperature = 276.49;
-        double expectedNighttimeFeelsLikeTemperature = 276.27;
-        double actualMorningTemperature = connector.getMorningTemperature(daily);
-        double actualDaytimeTemperature = connector.getDaytimeTemperature(daily);
-        double actualEveningTemperature = connector.getEveningTemperature(daily);
-        double actualNighttimeTemperature = connector.getNighttimeTemperature(daily);
-        double actualHighTemperature = connector.getHighTemperature(daily);
-        double actualLowTemperature = connector.getLowTemperature(daily);
-        double actualMorningFeelsLikeTemperature = connector.getMorningFeelsLike(daily);
-        double actualDaytimeFeelsLikeTemperature = connector.getDaytimeFeelsLike(daily);
-        double actualEveningFeelsLikeTemperature = connector.getEveningFeelsLike(daily);
-        double actualNighttimeFeelsLikeTemperature = connector.getNighttimeFeelsLike(daily);
-        assertEquals(expectedMorningTemperature, actualMorningTemperature, 0.0001);
-        assertEquals(expectedDaytimeTemperature, actualDaytimeTemperature, 0.0001);
-        assertEquals(expectedEveningTemperature, actualEveningTemperature, 0.0001);
-        assertEquals(expectedNighttimeTemperature, actualNighttimeTemperature, 0.0001);
-        assertEquals(expectedLowTemperature, actualLowTemperature, 0.0001);
-        assertEquals(expectedHighTemperature, actualHighTemperature, 0.0001);
-        assertEquals(expectedMorningFeelsLikeTemperature, actualMorningFeelsLikeTemperature, 0.0001);
-        assertEquals(expectedDaytimeFeelsLikeTemperature, actualDaytimeFeelsLikeTemperature, 0.0001);
-        assertEquals(expectedEveningFeelsLikeTemperature, actualEveningFeelsLikeTemperature, 0.0001);
-        assertEquals(expectedNighttimeFeelsLikeTemperature, actualNighttimeFeelsLikeTemperature, 0.0001);
-    }
+		double expectedMorningTemperature = 278.49;
+		double expectedDaytimeTemperature = 279.79;
+		double expectedEveningTemperature = 279.21;
+		double expectedNighttimeTemperature = 275.09;
+		double expectedHighTemperature = 284.07;
+		double expectedLowTemperature = 275.09;
+		double expectedMorningFeelsLikeTemperature = 276.27;
+		double expectedDaytimeFeelsLikeTemperature = 277.59;
+		double expectedEveningFeelsLikeTemperature = 276.49;
+		double expectedNighttimeFeelsLikeTemperature = 276.27;
+		double actualMorningTemperature = connector.getMorningTemperature(daily);
+		double actualDaytimeTemperature = connector.getDaytimeTemperature(daily);
+		double actualEveningTemperature = connector.getEveningTemperature(daily);
+		double actualNighttimeTemperature = connector.getNighttimeTemperature(daily);
+		double actualHighTemperature = connector.getHighTemperature(daily);
+		double actualLowTemperature = connector.getLowTemperature(daily);
+		double actualMorningFeelsLikeTemperature = connector.getMorningFeelsLike(daily);
+		double actualDaytimeFeelsLikeTemperature = connector.getDaytimeFeelsLike(daily);
+		double actualEveningFeelsLikeTemperature = connector.getEveningFeelsLike(daily);
+		double actualNighttimeFeelsLikeTemperature = connector.getNighttimeFeelsLike(daily);
+		assertEquals(expectedMorningTemperature, actualMorningTemperature, 0.0001);
+		assertEquals(expectedDaytimeTemperature, actualDaytimeTemperature, 0.0001);
+		assertEquals(expectedEveningTemperature, actualEveningTemperature, 0.0001);
+		assertEquals(expectedNighttimeTemperature, actualNighttimeTemperature, 0.0001);
+		assertEquals(expectedLowTemperature, actualLowTemperature, 0.0001);
+		assertEquals(expectedHighTemperature, actualHighTemperature, 0.0001);
+		assertEquals(expectedMorningFeelsLikeTemperature, actualMorningFeelsLikeTemperature, 0.0001);
+		assertEquals(expectedDaytimeFeelsLikeTemperature, actualDaytimeFeelsLikeTemperature, 0.0001);
+		assertEquals(expectedEveningFeelsLikeTemperature, actualEveningFeelsLikeTemperature, 0.0001);
+		assertEquals(expectedNighttimeFeelsLikeTemperature, actualNighttimeFeelsLikeTemperature, 0.0001);
+	}
 
-    @Test
-    public void testWindForecast() {
-        long expectedDirection = 296;
-        double expectedSpeed = 4.12;
-        double expectedGust = 7.33;
-        long actualDirection = connector.getWindDirection(hourly);
-        double actualSpeed = connector.getWindSpeed(hourly);
-        double actualGust = connector.getWindGust(hourly);
-        assertEquals(expectedDirection, actualDirection);
-        assertEquals(expectedSpeed, actualSpeed, 0.0001);
-        assertEquals(expectedGust, actualGust, 0.0001);
+	@Test
+	public void testWindForecast() {
+		long expectedDirection = 296;
+		double expectedSpeed = 4.12;
+		double expectedGust = 7.33;
+		long actualDirection = connector.getWindDirection(hourly);
+		double actualSpeed = connector.getWindSpeed(hourly);
+		double actualGust = connector.getWindGust(hourly);
+		assertEquals(expectedDirection, actualDirection);
+		assertEquals(expectedSpeed, actualSpeed, 0.0001);
+		assertEquals(expectedGust, actualGust, 0.0001);
 
-        expectedDirection = 294;
-        expectedSpeed = 3.06;
-        expectedGust = 3.06;
-        actualDirection = connector.getWindDirection(daily);
-        actualSpeed = connector.getWindSpeed(daily);
-        actualGust = connector.getWindGust(daily);
-        assertEquals(expectedDirection, actualDirection);
-        assertEquals(expectedSpeed, actualSpeed, 0.0001);
-        assertEquals(expectedGust, actualGust, 0.0001);
-    }
+		expectedDirection = 294;
+		expectedSpeed = 3.06;
+		expectedGust = 3.06;
+		actualDirection = connector.getWindDirection(daily);
+		actualSpeed = connector.getWindSpeed(daily);
+		actualGust = connector.getWindGust(daily);
+		assertEquals(expectedDirection, actualDirection);
+		assertEquals(expectedSpeed, actualSpeed, 0.0001);
+		assertEquals(expectedGust, actualGust, 0.0001);
+	}
 
-    @Test
-    public void testCloudinessForecast() {
-        long expectedClouds = 19;
-        long actualClouds = connector.getCloudCover(hourly);
-        assertEquals(expectedClouds, actualClouds);
+	@Test
+	public void testCloudinessForecast() {
+		long expectedClouds = 19;
+		long actualClouds = connector.getCloudCover(hourly);
+		assertEquals(expectedClouds, actualClouds);
 
-        expectedClouds = 56;
-        actualClouds = connector.getCloudCover(daily);
-        assertEquals(expectedClouds, actualClouds);
-    }
+		expectedClouds = 56;
+		actualClouds = connector.getCloudCover(daily);
+		assertEquals(expectedClouds, actualClouds);
+	}
 
-    @Test
-    public void testPrecipitationForecast() {
-        double expectedPrecipitation = 0.205;
-        double actualPrecipitation = connector.getMinutelyPrecipitation(minutely);
-        assertEquals(expectedPrecipitation, actualPrecipitation, 0.0001);
+	@Test
+	public void testPrecipitationForecast() {
+		double expectedPrecipitation = 0.205;
+		double actualPrecipitation = connector.getMinutelyPrecipitation(minutely);
+		assertEquals(expectedPrecipitation, actualPrecipitation, 0.0001);
 
-        double expectedProbability = 0.0;
-        double expectedRain = 0.0;
-        double expectedSnow = 0.0;
-        double actualProbability = connector.getProbabilityOfPrecipitation(hourly);
-        double actualRain = connector.getOneHourRainfall(hourly);
-        double actualSnow = connector.getOneHourSnowfall(hourly);
-        assertEquals(expectedProbability, actualProbability, 0.0001);
-        assertEquals(expectedRain, actualRain, 0.0001);
-        assertEquals(expectedSnow, actualSnow, 0.0001);
+		double expectedProbability = 0.0;
+		double expectedRain = 0.0;
+		double expectedSnow = 0.0;
+		double actualProbability = connector.getProbabilityOfPrecipitation(hourly);
+		double actualRain = connector.getOneHourRainfall(hourly);
+		double actualSnow = connector.getOneHourSnowfall(hourly);
+		assertEquals(expectedProbability, actualProbability, 0.0001);
+		assertEquals(expectedRain, actualRain, 0.0001);
+		assertEquals(expectedSnow, actualSnow, 0.0001);
 
-        expectedProbability = 0.2;
-        expectedRain = 0.62;
-        expectedSnow = 0.0;
-        actualProbability = connector.getProbabilityOfPrecipitation(daily);
-        actualRain = connector.getDailyRainfall(daily);
-        actualSnow = connector.getDailySnowfall(daily);
-        assertEquals(expectedProbability, actualProbability, 0.0001);
-        assertEquals(expectedRain, actualRain, 0.0001);
-        assertEquals(expectedSnow, actualSnow, 0.0001);
-    }
+		expectedProbability = 0.2;
+		expectedRain = 0.62;
+		expectedSnow = 0.0;
+		actualProbability = connector.getProbabilityOfPrecipitation(daily);
+		actualRain = connector.getDailyRainfall(daily);
+		actualSnow = connector.getDailySnowfall(daily);
+		assertEquals(expectedProbability, actualProbability, 0.0001);
+		assertEquals(expectedRain, actualRain, 0.0001);
+		assertEquals(expectedSnow, actualSnow, 0.0001);
+	}
 }
diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/Weather_UnlOct24At0917Test.java b/src/test/java/edu/unl/cse/soft160/json_connections/Weather_UnlOct24At0917Test.java
index 6219252..39bcf4b 100644
--- a/src/test/java/edu/unl/cse/soft160/json_connections/Weather_UnlOct24At0917Test.java
+++ b/src/test/java/edu/unl/cse/soft160/json_connections/Weather_UnlOct24At0917Test.java
@@ -12,104 +12,104 @@ import java.util.List;
 import static org.junit.Assert.assertEquals;
 
 public class Weather_UnlOct24At0917Test {
-    private OpenWeatherConnector connector;
+	private OpenWeatherConnector connector;
 
-    /* Demonstrates most fields; gust is distinct from wind speed; 3hr rain defaults to 1hr rain; no snow; multiple
-    weather categories */
+	/*
+	 * Demonstrates most fields; gust is distinct from wind speed; 3hr rain defaults
+	 * to 1hr rain; no snow; multiple weather categories
+	 */
 
-    @Before
-    public void setup() throws IOException {
-        connector = new OpenWeatherConnector("weather");
-        connector.retrieveData("unl-oct24-0917.json");
-    }
+	@Before
+	public void setup() throws IOException {
+		connector = new OpenWeatherConnector("weather");
+		connector.retrieveData("unl-oct24-0917.json");
+	}
 
-    @Test
-    public void testLocation() {
-        double expectedLatitude = 40.8206;
-        double expectedLongitude = -96.6928;
-        double actualLatitude = connector.getLatitude();
-        double actualLongitude = connector.getLongitude();
-        assertEquals(expectedLatitude, actualLatitude, 0.0001);
-        assertEquals(expectedLongitude, actualLongitude, 0.0001);
-    }
+	@Test
+	public void testLocation() {
+		double expectedLatitude = 40.8206;
+		double expectedLongitude = -96.6928;
+		double actualLatitude = connector.getLatitude();
+		double actualLongitude = connector.getLongitude();
+		assertEquals(expectedLatitude, actualLatitude, 0.0001);
+		assertEquals(expectedLongitude, actualLongitude, 0.0001);
+	}
 
-    @Test
-    public void testDateTime() {
+	@Test
+	public void testDateTime() {
 //        Date expectedValue = new Date(1635085053000L);
-        String expectedValue = "Sun Oct 24 09:17:33 CDT 2021";
-        Date actualValue = connector.getTimestamp();
-        assertEquals(expectedValue, actualValue.toString());
-    }
+		String expectedValue = "Sun Oct 24 09:17:33 CDT 2021";
+		Date actualValue = connector.getTimestamp();
+		assertEquals(expectedValue, actualValue.toString());
+	}
 
-    @Test
-    public void testWeather() {
-        List<OpenWeatherConnector.WeatherCategory> expectedCategories = List.of(
-                OpenWeatherConnector.WeatherCategory.MIST,
-                OpenWeatherConnector.WeatherCategory.RAIN,
-                OpenWeatherConnector.WeatherCategory.THUNDERSTORM
-        );
-        List<String> expectedDescriptions = Arrays.asList("mist", "light rain", "thunderstorm with light rain");
-        int expectedListSize = 3;
-        List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories();
-        List<String> actualDescriptions = connector.getWeatherDescriptions();
-        assertEquals(expectedListSize, actualCategories.size());
-        assertEquals(expectedListSize, actualDescriptions.size());
-        assertEquals(expectedCategories, actualCategories);
-        assertEquals(expectedDescriptions, actualDescriptions);
-    }
+	@Test
+	public void testWeather() {
+		List<OpenWeatherConnector.WeatherCategory> expectedCategories = List.of(
+				OpenWeatherConnector.WeatherCategory.MIST, OpenWeatherConnector.WeatherCategory.RAIN,
+				OpenWeatherConnector.WeatherCategory.THUNDERSTORM);
+		List<String> expectedDescriptions = Arrays.asList("mist", "light rain", "thunderstorm with light rain");
+		int expectedListSize = 3;
+		List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories();
+		List<String> actualDescriptions = connector.getWeatherDescriptions();
+		assertEquals(expectedListSize, actualCategories.size());
+		assertEquals(expectedListSize, actualDescriptions.size());
+		assertEquals(expectedCategories, actualCategories);
+		assertEquals(expectedDescriptions, actualDescriptions);
+	}
 
-    @Test
-    public void testMainObservations() {
-        long expectedVisibility = 8047;
-        double expectedAmbientTemperature = 281.25;
-        long expectedHumidity = 96;
-        double expectedFeelsLikeTemperature = 279.92;
-        long expectedPressure = 1003;
-        long actualVisibility = connector.getVisibility();
-        double actualAmbientTemperature = connector.getTemperature();
-        long actualHumidity = connector.getHumidity();
-        double actualFeelsLikeTemperature = connector.getFeelsLike();
-        long actualPressure = connector.getPressure();
-        assertEquals(expectedVisibility, actualVisibility);
-        assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
-        assertEquals(expectedHumidity, actualHumidity);
-        assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
-        assertEquals(expectedPressure, actualPressure);
-    }
+	@Test
+	public void testMainObservations() {
+		long expectedVisibility = 8047;
+		double expectedAmbientTemperature = 281.25;
+		long expectedHumidity = 96;
+		double expectedFeelsLikeTemperature = 279.92;
+		long expectedPressure = 1003;
+		long actualVisibility = connector.getVisibility();
+		double actualAmbientTemperature = connector.getTemperature();
+		long actualHumidity = connector.getHumidity();
+		double actualFeelsLikeTemperature = connector.getFeelsLike();
+		long actualPressure = connector.getPressure();
+		assertEquals(expectedVisibility, actualVisibility);
+		assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
+		assertEquals(expectedHumidity, actualHumidity);
+		assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
+		assertEquals(expectedPressure, actualPressure);
+	}
 
-    @Test
-    public void testWinds() {
-        long expectedDirection = 43;
-        double expectedSpeed = 2.24;
-        double expectedGust = 4.92;
-        long actualDirection = connector.getWindDirection();
-        double actualSpeed = connector.getWindSpeed();
-        double actualGust = connector.getWindGust();
-        assertEquals(expectedDirection, actualDirection);
-        assertEquals(expectedSpeed, actualSpeed, 0.0001);
-        assertEquals(expectedGust, actualGust, 0.0001);
-    }
+	@Test
+	public void testWinds() {
+		long expectedDirection = 43;
+		double expectedSpeed = 2.24;
+		double expectedGust = 4.92;
+		long actualDirection = connector.getWindDirection();
+		double actualSpeed = connector.getWindSpeed();
+		double actualGust = connector.getWindGust();
+		assertEquals(expectedDirection, actualDirection);
+		assertEquals(expectedSpeed, actualSpeed, 0.0001);
+		assertEquals(expectedGust, actualGust, 0.0001);
+	}
 
-    @Test
-    public void testClouds() {
-        long expectedValue = 90;
-        long actualValue = connector.getCloudCover();
-        assertEquals(expectedValue, actualValue);
-    }
+	@Test
+	public void testClouds() {
+		long expectedValue = 90;
+		long actualValue = connector.getCloudCover();
+		assertEquals(expectedValue, actualValue);
+	}
 
-    @Test
-    public void testPrecipitation() {
-        double expected1HourRain = 0.11;
-        double expected3HourRain = 0.11;
-        double expected1HourSnow = 0.0;
-        double expected3HourSnow = 0.0;
-        double actual1HourRain = connector.getOneHourRainfall();
-        double actual3HourRain = connector.getThreeHourRainfall();
-        double actual1HourSnow = connector.getOneHourSnowfall();
-        double actual3HourSnow = connector.getThreeHourSnowfall();
-        assertEquals(expected1HourRain, actual1HourRain, 0.0001);
-        assertEquals(expected3HourRain, actual3HourRain, 0.0001);
-        assertEquals(expected1HourSnow, actual1HourSnow, 0.0001);
-        assertEquals(expected3HourSnow, actual3HourSnow, 0.0001);
-    }
+	@Test
+	public void testPrecipitation() {
+		double expected1HourRain = 0.11;
+		double expected3HourRain = 0.11;
+		double expected1HourSnow = 0.0;
+		double expected3HourSnow = 0.0;
+		double actual1HourRain = connector.getOneHourRainfall();
+		double actual3HourRain = connector.getThreeHourRainfall();
+		double actual1HourSnow = connector.getOneHourSnowfall();
+		double actual3HourSnow = connector.getThreeHourSnowfall();
+		assertEquals(expected1HourRain, actual1HourRain, 0.0001);
+		assertEquals(expected3HourRain, actual3HourRain, 0.0001);
+		assertEquals(expected1HourSnow, actual1HourSnow, 0.0001);
+		assertEquals(expected3HourSnow, actual3HourSnow, 0.0001);
+	}
 }
diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/Weather_WebsiteExampleTest.java b/src/test/java/edu/unl/cse/soft160/json_connections/Weather_WebsiteExampleTest.java
index 2a67669..9dcc044 100644
--- a/src/test/java/edu/unl/cse/soft160/json_connections/Weather_WebsiteExampleTest.java
+++ b/src/test/java/edu/unl/cse/soft160/json_connections/Weather_WebsiteExampleTest.java
@@ -12,96 +12,99 @@ import org.junit.Test;
 import static org.junit.Assert.*;
 
 public class Weather_WebsiteExampleTest {
-    private OpenWeatherConnector connector;
+	private OpenWeatherConnector connector;
 
-    /* Demonstrates most fields; gust defaults to wind speed; no rain or snow; one weather category */
+	/*
+	 * Demonstrates most fields; gust defaults to wind speed; no rain or snow; one
+	 * weather category
+	 */
 
-    @Before
-    public void setup() throws IOException {
-        connector = new OpenWeatherConnector("weather");
-        connector.retrieveData("website-example.json");
-    }
+	@Before
+	public void setup() throws IOException {
+		connector = new OpenWeatherConnector("weather");
+		connector.retrieveData("website-example.json");
+	}
 
-    @Test
-    public void testLocation() {
-        double expectedLatitude = 37.39;
-        double expectedLongitude = -122.08;
-        double actualLatitude = connector.getLatitude();
-        double actualLongitude = connector.getLongitude();
-        assertEquals(expectedLatitude, actualLatitude, 0.0001);
-        assertEquals(expectedLongitude, actualLongitude, 0.0001);
-    }
+	@Test
+	public void testLocation() {
+		double expectedLatitude = 37.39;
+		double expectedLongitude = -122.08;
+		double actualLatitude = connector.getLatitude();
+		double actualLongitude = connector.getLongitude();
+		assertEquals(expectedLatitude, actualLatitude, 0.0001);
+		assertEquals(expectedLongitude, actualLongitude, 0.0001);
+	}
 
-    @Test
-    public void testDateTime() {
+	@Test
+	public void testDateTime() {
 //        Date expectedValue = new Date(1560350645000L);
-        String expectedValue = "Wed Jun 12 09:44:05 CDT 2019";
-        Date actualValue = connector.getTimestamp();
-        assertEquals(expectedValue, actualValue.toString());
-    }
+		String expectedValue = "Wed Jun 12 09:44:05 CDT 2019";
+		Date actualValue = connector.getTimestamp();
+		assertEquals(expectedValue, actualValue.toString());
+	}
 
-    @Test
-    public void testWeather() {
-        OpenWeatherConnector.WeatherCategory expectedCategory = OpenWeatherConnector.WeatherCategory.CLEAR;
-        String expectedDescription = "clear sky";
-        int expectedListSize = 1;
-        List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories();
-        List<String> actualDescriptions = connector.getWeatherDescriptions();
-        assertEquals(expectedListSize, actualCategories.size());
-        assertEquals(expectedListSize, actualDescriptions.size());
-        assertEquals(expectedCategory, actualCategories.get(0));
-        assertEquals(expectedDescription, actualDescriptions.get(0));
-    }
+	@Test
+	public void testWeather() {
+		OpenWeatherConnector.WeatherCategory expectedCategory = OpenWeatherConnector.WeatherCategory.CLEAR;
+		String expectedDescription = "clear sky";
+		int expectedListSize = 1;
+		List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories();
+		List<String> actualDescriptions = connector.getWeatherDescriptions();
+		assertEquals(expectedListSize, actualCategories.size());
+		assertEquals(expectedListSize, actualDescriptions.size());
+		assertEquals(expectedCategory, actualCategories.get(0));
+		assertEquals(expectedDescription, actualDescriptions.get(0));
+	}
 
-    @Test
-    public void testMainObservations() {
-        long expectedVisibility = 16093;
-        double expectedAmbientTemperature = 282.55;
-        long expectedHumidity = 100;
-        double expectedFeelsLikeTemperature = 281.86;
-        long actualVisibility = connector.getVisibility();
-        double actualAmbientTemperature = connector.getTemperature();
-        long actualHumidity = connector.getHumidity();
-        double actualFeelsLikeTemperature = connector.getFeelsLike();
-        assertEquals(expectedVisibility, actualVisibility);
-        assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
-        assertEquals(expectedHumidity, actualHumidity);
-        assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
-    }
+	@Test
+	public void testMainObservations() {
+		long expectedVisibility = 16093;
+		double expectedAmbientTemperature = 282.55;
+		long expectedHumidity = 100;
+		double expectedFeelsLikeTemperature = 281.86;
+		long actualVisibility = connector.getVisibility();
+		double actualAmbientTemperature = connector.getTemperature();
+		long actualHumidity = connector.getHumidity();
+		double actualFeelsLikeTemperature = connector.getFeelsLike();
+		assertEquals(expectedVisibility, actualVisibility);
+		assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001);
+		assertEquals(expectedHumidity, actualHumidity);
+		assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001);
+	}
 
-    @Test
-    public void testWinds() {
-        long expectedDirection = 350;
-        double expectedSpeed = 1.5;
-        double expectedGust = 1.5;
-        long actualDirection = connector.getWindDirection();
-        double actualSpeed = connector.getWindSpeed();
-        double actualGust = connector.getWindGust();
-        assertEquals(expectedDirection, actualDirection);
-        assertEquals(expectedSpeed, actualSpeed, 0.0001);
-        assertEquals(expectedGust, actualGust, 0.0001);
-    }
+	@Test
+	public void testWinds() {
+		long expectedDirection = 350;
+		double expectedSpeed = 1.5;
+		double expectedGust = 1.5;
+		long actualDirection = connector.getWindDirection();
+		double actualSpeed = connector.getWindSpeed();
+		double actualGust = connector.getWindGust();
+		assertEquals(expectedDirection, actualDirection);
+		assertEquals(expectedSpeed, actualSpeed, 0.0001);
+		assertEquals(expectedGust, actualGust, 0.0001);
+	}
 
-    @Test
-    public void testClouds() {
-        long expectedValue = 1;
-        long actualValue = connector.getCloudCover();
-        assertEquals(expectedValue, actualValue);
-    }
+	@Test
+	public void testClouds() {
+		long expectedValue = 1;
+		long actualValue = connector.getCloudCover();
+		assertEquals(expectedValue, actualValue);
+	}
 
-    @Test
-    public void testPrecipitation() {
-        double expected1HourRain = 0.0;
-        double expected3HourRain = 0.0;
-        double expected1HourSnow = 0.0;
-        double expected3HourSnow = 0.0;
-        double actual1HourRain = connector.getOneHourRainfall();
-        double actual3HourRain = connector.getThreeHourRainfall();
-        double actual1HourSnow = connector.getOneHourSnowfall();
-        double actual3HourSnow = connector.getThreeHourSnowfall();
-        assertEquals(expected1HourRain, actual1HourRain, 0.0001);
-        assertEquals(expected3HourRain, actual3HourRain, 0.0001);
-        assertEquals(expected1HourSnow, actual1HourSnow, 0.0001);
-        assertEquals(expected3HourSnow, actual3HourSnow, 0.0001);
-    }
+	@Test
+	public void testPrecipitation() {
+		double expected1HourRain = 0.0;
+		double expected3HourRain = 0.0;
+		double expected1HourSnow = 0.0;
+		double expected3HourSnow = 0.0;
+		double actual1HourRain = connector.getOneHourRainfall();
+		double actual3HourRain = connector.getThreeHourRainfall();
+		double actual1HourSnow = connector.getOneHourSnowfall();
+		double actual3HourSnow = connector.getThreeHourSnowfall();
+		assertEquals(expected1HourRain, actual1HourRain, 0.0001);
+		assertEquals(expected3HourRain, actual3HourRain, 0.0001);
+		assertEquals(expected1HourSnow, actual1HourSnow, 0.0001);
+		assertEquals(expected3HourSnow, actual3HourSnow, 0.0001);
+	}
 }
-- 
GitLab