From 1ecacb734c6f261f40aa70cee39d5b931f6f9cd9 Mon Sep 17 00:00:00 2001 From: "Appleton, Joseph Dr (Comp Sci & Elec Eng)" <j.appleton@surrey.ac.uk> Date: Thu, 27 Feb 2025 07:42:34 +0000 Subject: [PATCH] initial commit --- .classpath | 57 ++++++++++++ .project | 34 +++++++ .settings/org.eclipse.jdt.apt.core.prefs | 2 + .settings/org.eclipse.jdt.core.prefs | 9 ++ .settings/org.eclipse.m2e.core.prefs | 4 + pom.xml | 24 +++++ .../travelagency/CurrencyConverter.java | 36 +++++++ .../com1028/travelagency/CurrencyService.java | 13 +++ .../travelagency/ExcursionService.java | 15 +++ .../com/com1028/travelagency/TripAdvisor.java | 78 ++++++++++++++++ .../com1028/travelagency/TripDatabase.java | 16 ++++ .../com/com1028/travelagency/TripManager.java | 48 ++++++++++ .../com1028/travelagency/WeatherService.java | 18 ++++ .../travelagency/CurrencyConverterTest.java | 46 +++++++++ .../com1028/travelagency/TripAdvisorTest.java | 74 +++++++++++++++ .../com1028/travelagency/TripManagerTest.java | 88 ++++++++++++++++++ .../travelagency/CurrencyConverter.class | Bin 0 -> 964 bytes .../travelagency/CurrencyService.class | Bin 0 -> 204 bytes .../travelagency/ExcursionService.class | Bin 0 -> 280 bytes .../com1028/travelagency/TripAdvisor.class | Bin 0 -> 2755 bytes .../com1028/travelagency/TripDatabase.class | Bin 0 -> 320 bytes .../com1028/travelagency/TripManager.class | Bin 0 -> 1006 bytes .../com1028/travelagency/WeatherService.class | Bin 0 -> 328 bytes .../travelagency/CurrencyConverterTest.class | Bin 0 -> 2022 bytes .../travelagency/TripAdvisorTest.class | Bin 0 -> 2984 bytes .../travelagency/TripManagerTest.class | Bin 0 -> 3163 bytes 26 files changed, 562 insertions(+) create mode 100644 .classpath create mode 100644 .project create mode 100644 .settings/org.eclipse.jdt.apt.core.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 pom.xml create mode 100644 src/main/java/com/com1028/travelagency/CurrencyConverter.java create mode 100644 src/main/java/com/com1028/travelagency/CurrencyService.java create mode 100644 src/main/java/com/com1028/travelagency/ExcursionService.java create mode 100644 src/main/java/com/com1028/travelagency/TripAdvisor.java create mode 100644 src/main/java/com/com1028/travelagency/TripDatabase.java create mode 100644 src/main/java/com/com1028/travelagency/TripManager.java create mode 100644 src/main/java/com/com1028/travelagency/WeatherService.java create mode 100644 src/test/java/com/com1028/travelagency/CurrencyConverterTest.java create mode 100644 src/test/java/com/com1028/travelagency/TripAdvisorTest.java create mode 100644 src/test/java/com/com1028/travelagency/TripManagerTest.java create mode 100644 target/classes/com/com1028/travelagency/CurrencyConverter.class create mode 100644 target/classes/com/com1028/travelagency/CurrencyService.class create mode 100644 target/classes/com/com1028/travelagency/ExcursionService.class create mode 100644 target/classes/com/com1028/travelagency/TripAdvisor.class create mode 100644 target/classes/com/com1028/travelagency/TripDatabase.class create mode 100644 target/classes/com/com1028/travelagency/TripManager.class create mode 100644 target/classes/com/com1028/travelagency/WeatherService.class create mode 100644 target/test-classes/com/com1028/travelagency/CurrencyConverterTest.class create mode 100644 target/test-classes/com/com1028/travelagency/TripAdvisorTest.class create mode 100644 target/test-classes/com/com1028/travelagency/TripManagerTest.class diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..653dfd7 --- /dev/null +++ b/.classpath @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" output="target/classes" path="src/main/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + <attribute name="optional" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" output="target/test-classes" path="src/test/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + <attribute name="test" value="true"/> + </attributes> + </classpathentry> + <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + <attribute name="test" value="true"/> + <attribute name="optional" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" path="target/generated-sources/annotations"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + <attribute name="ignore_optional_problems" value="true"/> + <attribute name="m2e-apt" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + <attribute name="ignore_optional_problems" value="true"/> + <attribute name="m2e-apt" value="true"/> + <attribute name="test" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="target/classes"/> +</classpath> diff --git a/.project b/.project new file mode 100644 index 0000000..7feca82 --- /dev/null +++ b/.project @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>TravelAgency</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + </natures> + <filteredResources> + <filter> + <id>1740642098171</id> + <name></name> + <type>30</type> + <matcher> + <id>org.eclipse.core.resources.regexFilterMatcher</id> + <arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments> + </matcher> + </filter> + </filteredResources> +</projectDescription> diff --git a/.settings/org.eclipse.jdt.apt.core.prefs b/.settings/org.eclipse.jdt.apt.core.prefs new file mode 100644 index 0000000..d4313d4 --- /dev/null +++ b/.settings/org.eclipse.jdt.apt.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.apt.aptEnabled=false diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..3a7f4f9 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.processAnnotations=disabled +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..14b697b --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f747836 --- /dev/null +++ b/pom.xml @@ -0,0 +1,24 @@ +<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>com.com1028.lab7</groupId> + <artifactId>TravelAgency</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>MyAgency</name> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.13.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>4.8.0</version> + </dependency> + </dependencies> + +</project> \ No newline at end of file diff --git a/src/main/java/com/com1028/travelagency/CurrencyConverter.java b/src/main/java/com/com1028/travelagency/CurrencyConverter.java new file mode 100644 index 0000000..9e72bf4 --- /dev/null +++ b/src/main/java/com/com1028/travelagency/CurrencyConverter.java @@ -0,0 +1,36 @@ +package com.com1028.travelagency; + +/** + * + * Defines the properties and behaviour for a Currency Converter class + * + * @author Mariam Cirovic + * + */ +public class CurrencyConverter { + CurrencyService service; + + public CurrencyConverter() { + this.service = null; + } + + // The CurrencyService is a dependency passed via a setter method + public void setCurrencyService(CurrencyService service) { + this.service = service; + } + + /** + * Retrieve the new currency amount given a amount in currency 1 to be converted to currency 2 + * + * @return currency amount + */ + public double convertCurrency(double amount, String currency1, String currency2) { + double newCurrencyAmount; + + // Call the currency service to get the exchange rate between currencies 1 & 2 + double exchangeRate = service.getExchangeRate(currency1, currency2); + newCurrencyAmount = amount * exchangeRate; + return newCurrencyAmount; + + } +} diff --git a/src/main/java/com/com1028/travelagency/CurrencyService.java b/src/main/java/com/com1028/travelagency/CurrencyService.java new file mode 100644 index 0000000..5908a21 --- /dev/null +++ b/src/main/java/com/com1028/travelagency/CurrencyService.java @@ -0,0 +1,13 @@ +package com.com1028.travelagency; + +/** + * + * Interface that defines the behaviour of a Currency Service + * + * @author Mariam Cirovic + * + */ +public interface CurrencyService { + // This method returns the exchange rate given the names of two currencies + public double getExchangeRate(String currency1, String currency2); +} diff --git a/src/main/java/com/com1028/travelagency/ExcursionService.java b/src/main/java/com/com1028/travelagency/ExcursionService.java new file mode 100644 index 0000000..a3c20bd --- /dev/null +++ b/src/main/java/com/com1028/travelagency/ExcursionService.java @@ -0,0 +1,15 @@ +package com.com1028.travelagency; + +import java.util.List; + +/** + * + * Interface that defines the behaviour of an Excursion Service + * + * @author Mariam Cirovic + * + */ +public interface ExcursionService { + // This method returns the list of excursions that are provided for a given city + public List<String> excursionList(String city); +} diff --git a/src/main/java/com/com1028/travelagency/TripAdvisor.java b/src/main/java/com/com1028/travelagency/TripAdvisor.java new file mode 100644 index 0000000..8652b37 --- /dev/null +++ b/src/main/java/com/com1028/travelagency/TripAdvisor.java @@ -0,0 +1,78 @@ +package com.com1028.travelagency; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * Defines the properties and behaviour for a Trip Advisor class + * It provides weather info and available excursions for a given city + * + * @author Mariam Cirovic + * + */ +public class TripAdvisor { + ExcursionService excursionService; + WeatherService weatherService; + + public TripAdvisor() { + excursionService = null; + weatherService = null; + } + + // The excursionService is a dependency passed via a setter method + public void setExcursionService(ExcursionService excursionService) { + this.excursionService = excursionService; + } + + public void setWeatherService(WeatherService weatherService) { + this.weatherService = weatherService; + } + + /** + * Retrieve the excursions of a given type offered in a specified city + * e.g. beach, island, historic + * + * @return list of excursions + */ + public List<String> getExcursionList(String city, String type){ + List<String> allExcursions = new ArrayList<String>(); + + // Call the excursion service to get all the excursions listed for a particular city + allExcursions = excursionService.excursionList(city); + + List<String> chosenExcursions = new ArrayList<String>(); + for(String excursion: allExcursions) { + //Checking to see if the excursion is of the type specifies e.g. beach + if (excursion.toLowerCase().contains(type.toLowerCase())){ + chosenExcursions.add(excursion); + } + } + return chosenExcursions; + } + + /** + * Retrieve the weather information for specified city in a specific month + * + * @return the weather info as a string + */ + public String weatherInfo(String city, Integer month) { + Integer temp = weatherService.predictedAverageTemperature(city, month); + Double rainprob = weatherService.predictedRainProbability(city, month); + + String weather = null; + + if (temp >= 21 && rainprob >= 0.5) { + weather = "Warm and Rainy"; + } else if (temp >= 21 && rainprob < 0.5) { + weather = "Warm and Dry"; + } else if (temp < 21 && rainprob < 0.5){ + weather = "Cold and Dry"; + } else { + weather = "Cold and Rainy"; + } + + return weather; + } +} + diff --git a/src/main/java/com/com1028/travelagency/TripDatabase.java b/src/main/java/com/com1028/travelagency/TripDatabase.java new file mode 100644 index 0000000..083a27e --- /dev/null +++ b/src/main/java/com/com1028/travelagency/TripDatabase.java @@ -0,0 +1,16 @@ +package com.com1028.travelagency; + +import java.util.List; +/** + * + * Interface that defines the behaviour of a Trip Database Service + * + * @author Mariam Cirovic + * + */ +public interface TripDatabase { + // This method returns the total cost of a trip for a given customer ID + public double totalTripCost(String CustomerID); + // This method returns the list of cities to be visited in order by the customer given the ID + public List<String> cityItinerary(String CustomerID); +} diff --git a/src/main/java/com/com1028/travelagency/TripManager.java b/src/main/java/com/com1028/travelagency/TripManager.java new file mode 100644 index 0000000..219e72b --- /dev/null +++ b/src/main/java/com/com1028/travelagency/TripManager.java @@ -0,0 +1,48 @@ +package com.com1028.travelagency; + +import java.util.List; +/** + * + * Defines the properties and behaviour for TripManager + * to apply a discount to the total trip cost and get the itinerary + * + * @author Mariam Cirovic + * + */ + +public class TripManager { + + private TripDatabase tripDB; + + /** + * Constructor sets the trip database + * TripDatabase dependency is passed via the constructor + * @param tripDB + * The database with details on Customers' Trips + */ + + public TripManager(TripDatabase tripDB) { + this.tripDB = tripDB; + } + + /** + * Retrieve the cost of a customers trip after applying a discount + * + * @return discounted cost + */ + public double applyDiscount(int percentageDiscount, String CustomerID) { + double cost = tripDB.totalTripCost(CustomerID); + return cost - (cost *percentageDiscount/100); + //return 1600.00; + } + + /** + * Retrieve the itinerary of a customer's trip given the customer id + * + * @return a list of places a traveller will visit in order + */ + public List<String> getItinerary(String CustomerID){ + return tripDB.cityItinerary(CustomerID); + } + +} diff --git a/src/main/java/com/com1028/travelagency/WeatherService.java b/src/main/java/com/com1028/travelagency/WeatherService.java new file mode 100644 index 0000000..2615cf6 --- /dev/null +++ b/src/main/java/com/com1028/travelagency/WeatherService.java @@ -0,0 +1,18 @@ +package com.com1028.travelagency; + +/** + * + * Interface that defines the behaviour of a Weather Service + * + * @author Mariam Cirovic + * + */ +public interface WeatherService { + // This method returns the predicted average temperature for a given city in a given month + // The month is expressed as a digit e.g. September = 9 + public Integer predictedAverageTemperature(String city, Integer month); + + // This method returns the predicted rain probability for a given city in a given month + // The month is expressed as a digit e.g. September = 9 + public Double predictedRainProbability(String city, Integer month); +} diff --git a/src/test/java/com/com1028/travelagency/CurrencyConverterTest.java b/src/test/java/com/com1028/travelagency/CurrencyConverterTest.java new file mode 100644 index 0000000..9bd69eb --- /dev/null +++ b/src/test/java/com/com1028/travelagency/CurrencyConverterTest.java @@ -0,0 +1,46 @@ +package com.com1028.travelagency; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * + * Tests that the CurencyConverter class is returning the correct exchange amount + * Annotations are used in these tests + * + * @author Mariam Cirovic + * + */ +@RunWith(MockitoJUnitRunner.class) +public class CurrencyConverterTest { + + // @InjectMocks annotation is used to create and inject the mock object + @InjectMocks + CurrencyConverter converter = new CurrencyConverter(); + + // @Mock annotation is used to create the mock object to be injected + @Mock + CurrencyService service; + + @Test + public void testConvertCurrency() { + // Method chain to return 1.12 as the exchange rate between pound and euro + when(service.getExchangeRate("pound", "euro")).thenReturn(1.12); + assertEquals(1120.0, converter.convertCurrency(1000.0, "pound", "euro"), 0); + verify(service).getExchangeRate("pound", "euro"); + } + + @Test(expected = RuntimeException.class) + public void testConvertCurrencyException() { + + doThrow(new RuntimeException("ExchangeRate not implemented")).when(service.getExchangeRate("pound", "euro")); + assertEquals(1120.0, converter.convertCurrency(1000.0, "pound", "euro"), 0); + verify(service).getExchangeRate("pound", "euro"); + } +} \ No newline at end of file diff --git a/src/test/java/com/com1028/travelagency/TripAdvisorTest.java b/src/test/java/com/com1028/travelagency/TripAdvisorTest.java new file mode 100644 index 0000000..155b32f --- /dev/null +++ b/src/test/java/com/com1028/travelagency/TripAdvisorTest.java @@ -0,0 +1,74 @@ +package com.com1028.travelagency; + +import static org.junit.Assert.*; + +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * + * Tests that the TripAdvisor class is retrieving an excursion list of the required type + * as well as retrieving the correct weather information + * Annotations are used in these tests + * + * @author Mariam Cirovic + * + */ +@RunWith(MockitoJUnitRunner.class) +public class TripAdvisorTest { + + @InjectMocks + TripAdvisor tripAdvisor = new TripAdvisor(); + + // @Mock annotation is used to create the mock object to be injected + @Mock + ExcursionService excursionService; + + @Mock + WeatherService weatherService; + + @Test + public void testExcursionList() { + String city = "Chania"; + List<String> excursions = new ArrayList<String>(); + excursions.add("Samaria Gorge"); + excursions.add("Santorini Island"); + excursions.add("Elafonisi Beach"); + excursions.add("Gavdos Island"); + excursions.add("Preveli Beach"); + + String type = "beach"; + List<String> beachExcursions = new ArrayList<String>(); + beachExcursions.add("Elafonisi Beach"); + beachExcursions.add("Preveli Beach"); + + // Method chain to return the above lsit of excursions when a city "Chania" is specified + when(excursionService.excursionList(city)).thenReturn(excursions); + assertEquals(beachExcursions, tripAdvisor.getExcursionList(city, type)); + verify(excursionService).excursionList(city); + } + + + @Test + public void testWeatherInfo() { + String city = "Chania"; + Integer month = 9; + InOrder inOrder = inOrder(weatherService); + + when(weatherService.predictedAverageTemperature(city, month)).thenReturn(27); + when(weatherService.predictedRainProbability(city, month)).thenReturn(0.15); + assertEquals("Warm and Dry", tripAdvisor.weatherInfo(city, month)); + + inOrder.verify(weatherService).predictedAverageTemperature(city, month); + inOrder.verify(weatherService).predictedRainProbability(city, month); + } +} diff --git a/src/test/java/com/com1028/travelagency/TripManagerTest.java b/src/test/java/com/com1028/travelagency/TripManagerTest.java new file mode 100644 index 0000000..b499a39 --- /dev/null +++ b/src/test/java/com/com1028/travelagency/TripManagerTest.java @@ -0,0 +1,88 @@ +package com.com1028.travelagency; + +import static org.junit.Assert.*; + + + +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +/** + * + * Tests that the TripManager class is calculating the discount correctly + * Also a Spy on an itinerary object is created and tested + * Static methods of Mockito are used + * + * @author Mariam Cirovic + * + */ +public class TripManagerTest { + + TripManager manager; + + // Mock the Trip Database class + TripDatabase db = mock(TripDatabase.class); + + @Before + public void setUp() { + manager = new TripManager(db); + } + + @Test + public void testApplyDiscount() { + + // Method chain (stub) to state that the customerID c11 should return the value 2000.00 + when(db.totalTripCost("c11")).thenReturn(2000.0); + assertEquals(1600.0, manager.applyDiscount(20, "c11"), 0); + verify(db).totalTripCost("c11"); + + when(db.totalTripCost("c20")).thenReturn(5000.0); + assertEquals(4000.0, manager.applyDiscount(20, "c20"), 0); + //assertEquals(4000.0, manager.applyDiscount(20, "c20"), 0); + verify(db).totalTripCost("c20"); + + //check if method is called once + verify(db, times(1)).totalTripCost("c20"); + + //verify that method was never called on a mock + verify(db, never()).cityItinerary("c11"); + } + + @Test + public void testItinerarySpy() { + List<String> itinerary = new ArrayList<String>(); + + itinerary.add("London"); + itinerary.add("Paris"); + itinerary.add("Rome"); + + // Create a spy to spy on the real instance itinerary + List<String> itinerarySpy = spy(itinerary); + + assertEquals("London", itinerarySpy.get(0)); + + // This is a stub - it states that return "Madrid" in position 1 instead of "Paris" + // You can use a spy to do a partial mock + doReturn("Madrid").when(itinerarySpy).get(1); + assertEquals("Madrid", itinerarySpy.get(1)); + + assertEquals("Rome", itinerarySpy.get(2)); + + System.out.println("Number of cities: " + itinerarySpy.size()); + + // Add another city to the spy object + itinerarySpy.add("Athens"); + + System.out.println("Number of cities (spy): " + itinerarySpy.size()); + // The size of itinerary is unchanged - the object was only added to the spy + // The spy has all the behaviour of the real object so it is mostly used to + // to explore legacy code that does not come with a clearly defined interface + System.out.println("Number of cities (original): " + itinerary.size()); + + } +} diff --git a/target/classes/com/com1028/travelagency/CurrencyConverter.class b/target/classes/com/com1028/travelagency/CurrencyConverter.class new file mode 100644 index 0000000000000000000000000000000000000000..7cea9855d473619b5f958ed96ff4e8cd87a7cebb GIT binary patch literal 964 zcma)4+iuf95Iq|^F>&3dH{z6A2ra5(D5ez;RIMVR1fC+02<p3IR;f#3OO6vjd=x?g zA$Z^e_$b7&V~19G2(orHGdpw6nHm57^Ya&gC%CVnAYgmp$l*DBeDu_bBX=r??m!0K zN2fiBqQq#2!Bj@Ej5MeM>lg0Sb%t&*a9;H<q!$ZlV;N0-PZF%V6s<SQJrO9K`hg#} z1Qe@zCZM*%w^E0K6$2Wsl_9Wdpoo${rRxXs<z&>C(HplvB++I!^xWZ@8~KT!1=aZ6 z9}7HOE@IviWo(XRoVS{Z6F9JzgXEng;w#>4NI8&zWp%p$M%9ZWKNy@WMw*=!nAp)! zW6A#x&%h1bB<VoL&p&wQ+=YDY#vIGOwaBm-X?8e#cN9(nE>F-Yd)cZFlgTcqzLanz zuo1}jd7IBN5JO&(q4&Z`<jEI)vZ`vHJRka_gaHjMSmBQ-c(`TW3T<wlcbVQP3hA3} ze}`_1Z!o?vTEH6bwX|{-Dy=dq`~YK?jdg6$V<XtgkXo!NFjlf3TtU&(=oZ<xQ-ta) zD??y@s*5Ay`}GX#6FC!gru`Mh!H)U^RRzb|eocFKT&xv8^Xan0ItAWkc_SrgrEQvX k0u#4zo4|y_9n{mNOy<`~vQ4kS*J9e@Jz5$wcT@bmzf(ro^8f$< literal 0 HcmV?d00001 diff --git a/target/classes/com/com1028/travelagency/CurrencyService.class b/target/classes/com/com1028/travelagency/CurrencyService.class new file mode 100644 index 0000000000000000000000000000000000000000..42d43a4580095e287502b35a11637edb808b2216 GIT binary patch literal 204 zcmX^0Z`VEs1_l!bPId++Mh1=K{9Jt?HZ(A@&@U-UEKAKvOi#^AuGDufEh+*rf>Vpi zGLuu;8CVz@1hNv#67_Qu^V0SGld@8iOBfmW(^E@aE0QySVyQuiC8>-I>KZ->Wx*vy znR)5fm?D}kj0{}C`K3k4scxA$Ky4yu7V3cvVPj-qWMBrmmw|y1Xg@0h8;Hfg4kVcv FH~@)jIO6~S literal 0 HcmV?d00001 diff --git a/target/classes/com/com1028/travelagency/ExcursionService.class b/target/classes/com/com1028/travelagency/ExcursionService.class new file mode 100644 index 0000000000000000000000000000000000000000..d741173f5f4d551a101883a70138ba7b50956110 GIT binary patch literal 280 zcmX^0Z`VEs1_l!bZgvJHMh4B~{9Jt?HZ(A@&@U-UEKAKvOi#^AuGDv}NG>fZ&dkpX zPAw|SOipEIU}0ns$Vx0r)Xz!GOV{^L%1TWxVPxP<g(>vOEC%vbG<*<>f=h}r^U|#~ zAws1knK}9(Ro09QoWYstd5I;ZMX8Jo7DQ;V!8FwlXbe|yerZv1s#|6b&>T^8H|v31 i!p6wJ$iNKrGXn!7&<m^#Y(PFckjKQp0c3H4SzG`H8&FLE literal 0 HcmV?d00001 diff --git a/target/classes/com/com1028/travelagency/TripAdvisor.class b/target/classes/com/com1028/travelagency/TripAdvisor.class new file mode 100644 index 0000000000000000000000000000000000000000..0490fec3db6176cdb408c861ffa0a4a4495a1f67 GIT binary patch literal 2755 zcmbVNTUQfT6#h;w3?u_a6lz4R7b@Wz@6`mMT(rdoyg;F-wVh1HFq+K7$%M!+>Gh?3 z@wHv6#YMYTSD*XbAJAW-{mx{_g-BN`i#a)GpS{1c_qX>x=g(Ka{tn<0wiE;e26elb z<ahqug{w)|(Kd~OmNzVYE4kvBrJ3BOS+*SoA%WNvZBt7YG%KIHoqb~HE=9(3z2cNj z+gdi9O;a}nMl<^Y-q@p@7U-!On!8~*b@So<&DUB~Y1}bsTBbWC5KIiO3WVnDoDo3~ z-72~e>4Lxk6=8J9*+CTwIw{GRma$YRW({XW%NFQxZ^qWO!m8$&a_tL4?uJ<wIJ>_$ zP3+K>LuJF=8=k;KVt@O++G!cWLBh0#DKPdgAg#I{L@eLrNyaQQOIH$^M(UPb$F%b4 zcFAx}RB_EhQra=9u4OZCX>P?KO}E|(WU~F7skDN3$(ZMociN2OXj}5g2u`3oiqjZW za7JMGKUb29_i$FAyIzj9zz5&pb6c2EBru|2n8ny|N!qIz#h5^+=^Bpa+KxbfqS<=E zm#3qcz&Qm;)=~pucUQ%ETwrlp#&f3P@Ge4A8<CGoE!|a1Q3MxpMaBELDiC$;j9oRH zIjzi8w1W5vmFg)KX-v{(-L_oKv{=Cd%@oXSXza9S6}GpL9=<OlpHeZ657<IlE+^2} ztX*qzPj3RVD&{aRploR6B`*{<-F?QTo9>ouqP7a-p1W0|yWLu$P_K5n6l*WEn7(0` z4XatJtDZ~p-rAx>_1koC57ZmWjUFt!n*MZAEBR(o|JGTs9@_%fnuBg{j|Iy$@`jW4 zQ|~3t*NWmERun7?4DDO0tu3nJ6R^(*N{*2;b=SzvY_hoW#)?ra$tv?&E%pB$+I3QT z^r?z<Ff~W&humW=+;QxzmNg4ry51t>dAq{vF&)7}JW}u(@2W<|{nJ%^jxS`xSnjG; zs4(@ck%b7d$SKfUO1y@q!oXuzch19Z*vxlK|IH_gf1P;3zFgCs;z`ZQos@xWb)q1k z)@Ab!B^D)fb|L3!d6E+C>JraRAY5c$Z1C=Bs@7fRWVtd4bl>42C9>68)qec!0Ka$y zBFlEg(T$s?d`4nT55k0`2B-M!1Q|nsA73FEj(mf>74KF=xF6-}1~mkK4~)EoIwF2S zj~rq@Q4~Ng$6kc|@es`pqX&IBM2T86qoj{3wh7+xA*X05kL?&4C0qk3;z{Fl=ctF! zU(@mtsP8!{h;jt+H(@n-Rl_<?ixc}`$zUbcQ4H{$WArD0<1%Cs<4oat{WqLge~FVz zBR`{ObO)ybSn@@w(D)991X3L@kcfBeU|ir2Tug=I;cZ+V<F}1#U!yx7iidY_J%BZ- zG$ZiM>%Zcm9|<1v$UE&ZKE!c^ZjRB7ao&_k%;Fp}oUd{v$(-^sv|guToq4%Q=jkLq z<SamhyZ8tT%;_;)$1To6w2k9q?uLm4CSX@<v97g9ttIXqN8mMvpePUuE_(k7g%_~G z#{+{r=r-<fl<f4=M3zgHti(pgc5pWc$&fc+3nCQ~sqpwV9>n^-M}IuD4ec=UUw(^7 zubB$Jz;xT*SKo2(soXnL+xwwm=j|2cp3-YedL?&3kGl&jF<_G8b;dc(xM%p9&EhiO zf<?@ej~g%<eUS{6$c;-b8eCTETvqE`R`CoDSyJ&7WzK@ceMGwoLq3KF*z~xRd>usS W6|O3Hs31$W1_pv;r^<~0p8o@aj+{XN literal 0 HcmV?d00001 diff --git a/target/classes/com/com1028/travelagency/TripDatabase.class b/target/classes/com/com1028/travelagency/TripDatabase.class new file mode 100644 index 0000000000000000000000000000000000000000..06d87d429c7166e3654941568988e69a5d0ea3ab GIT binary patch literal 320 zcma)2L23d)5UerLjV3~J@CORXB@;sqf*}`05CjkF2ijp+Mkcc|+bitXJoo?~71FDR z1d@Y?hU%iKyQ`01`vZVCbQ3fb1}6X1Qp1<mk>*G{>nXFrRC*QNc1lcZDr|ylh5HTd zNP7yIUamLRutJw}CSNNjc_Dr8aq%NcIl7RIpQfTSj;lGlU?as!q5q%mY%SS&y>JDO z722uG0&y9w!sr6a``_&!GNzN}Wi)o?yv%v{o$I;2wxytOB|iZg60?aG>bMDRgm2d@ KI)ZLb=<XZ9a9L9T literal 0 HcmV?d00001 diff --git a/target/classes/com/com1028/travelagency/TripManager.class b/target/classes/com/com1028/travelagency/TripManager.class new file mode 100644 index 0000000000000000000000000000000000000000..dfabac1693ba88abd46a3429cba7da2500864648 GIT binary patch literal 1006 zcma)4+iuf95IyUp35lIHls1%BT-v5>oD>X*hf1jmB2lHF01v4m@whRT+2Yudy{?om z;Bx>8gvtXSz(*lwH-ScKRmH1ad1hzM%sI2a|NQ&~;2HMwFc_+CG<0Y`dHnRikug8> z0`7aEJ9bWDF?!8Ivf@0l4CPaP#+`tNzVmi)>ba63Cn=`=l3}lVElitBKH!Phq?AJu z3VFm(ug#fb_ZhOS=)G4&2Bw8PEQU<Y?iawYXkh_4hNZ3uy*KG_;Ke6=5O@sB-N@xZ zpT|PkQ)gCw5DCNX^`)n*soN4Cje>DoByN<3M7UDxbT4G+5&h6_+HDgRtmSc=VP`HK zEZo65q030}K<V6y5<*|CT?L+d@s8$2A8{IavFnABW^&OJ>o62sX(FSc7kAo<`K1;~ zL06YxbZ_~d>`2lp=JA+bz*SWz5UCV_(-ny%DGEK|hg_yHX?rk7%HicMj+#oSngttG zV($t$p6R35i&A2DEY$SMGq3NFqJvH1pV2B9YUK2nAx|DR=q!+R41*R>tpA|h_>R(7 zvJ5QIxu`SOkR{y<SVx(Bl}R*iVwo(;)2NKlZeeALIiNZVDz^R&rTufP8hB;f8=pR| zU?cKB)6E3GsIj(SVq0U^sgkPj54(c9xJQ`EcOMTZ+N8CKEzMyYRr2g;v|Y{RIoXPf gsp>Y)v1j0mzE)&%8tCB+3G;s;Q^P9~bsgXM3x^5dA^-pY literal 0 HcmV?d00001 diff --git a/target/classes/com/com1028/travelagency/WeatherService.class b/target/classes/com/com1028/travelagency/WeatherService.class new file mode 100644 index 0000000000000000000000000000000000000000..16bb022f9642f5bb74396dc6bf02cd53ffb1fa13 GIT binary patch literal 328 zcmb7=&1wQc5QM8ubQ5zCauIxhB$td44>5ZR1VIoYZXoB`u~|pPS!re$e6<|%0C}k3 z>?J?o#Y02$K^0Z?_5JY)V2rB-Ey9f{w<_MlaP+8x=$f4_*qgn2XC2lo8B1*qCpahc zHoDfzX<w+<e8VOX20P)EHGx;pHA|Gf@pc!VPze*BZs)&}EQs|*`iIPX;DRN+JHiP4 zAM2&Iej#P9bL(u_6DFtozLZt&I3;wmvJ%5n>tev`|1IyEv>gKBEN%p}V(B(IXv!zJ Kh=g$2aC8rc8)CZv literal 0 HcmV?d00001 diff --git a/target/test-classes/com/com1028/travelagency/CurrencyConverterTest.class b/target/test-classes/com/com1028/travelagency/CurrencyConverterTest.class new file mode 100644 index 0000000000000000000000000000000000000000..fa53b37104fdaeec0dd829caa20241d6ee196a53 GIT binary patch literal 2022 zcmbtU-*XdH6#h18vu(PzC8R0^p+JEoLbqTCktnn@MT&t+Qc^1Z+H7yrt;ufP>=t;^ z7ax3b{8N}wo66|;?7yNf{sWHR-E5N$7R!teclX|N&pG!y=X~e<{`b$n0+_+NikN~a z(`o2j7pE^>(LLAL7ImX0Z1age@4K$t%sckBa6REJi>9ZdPr>M>v2Eye!>;K|)lFe~ z3I@$REd}R`FYhz2;7G~0J*y!qR@181#hh(Bp5a-J-Q-=-acg?RF~6`pM_;t%V|RFJ z(oSs(ciS?Bg51FmmfN~COZB*v&L~X0YuT1}O+h@9ttjZ5ch*D_ag1uv@QR8QA9?wp zk~oCXK`0p0(2s<Ik)mabyMCj}BpQq{Kw%p7is4%F918oq4U0if9~@3kO^E-n$J&I# zy}GeZL8zNPL(^sP@)FY<8U~RZzzGHYTaIt94d5gr7QX8Y;WW;um{gECFxW7m8qVSz z1FQ*e;jy_vN{Eu-F~D<~VwWXl&$aAY{@;>pA&D&BRFUgpRl)I@6%FTcfpy+C>b_W7 zXF4;5Y{W-fE1!gpiz=p>g(z8MWl0(hm+%(jd$b{J1y`e}+T6`&dkE3={A!h8^(DLJ z@Lvwk`NZ|V{`ls2>)xM3cpLAixT0V(`reBSHC&Ydk{$t+gy*|<V)py5*?~Y}_Pg0& zBMCFBVGcK#%CM8VWz1v>k*NPOmj&EZvA|qPWbMMwHQ6VghWBwxfo24!g)e=hPNpR? zg+d`)kr}+L;R6&YVy|24PZXTpH&xx5hS^haY#;8C3t~(5uz~^cc#B;t)~Fc?BW(JP zVqV2PR<P@TdBb%c$>vZ|RxsYZc;0dV_vt#yz6nl{39GSH7Y$+a<s?d2k)8ZNawq~K z%w;<RA8B}qkIA<+CwN=I<;=r~atF|h7!y!MxcMP`iqBPiMpXL}B-E44WWtkW$9GL} z(~@Ihe6Q*~4L&7<=VhdwUEj8at1}lXmbbwP&>wUO%hto@HU+{~xP704fEF~&<0MBx zoaBpfaYpf^awq=-0VO#jBC;XM;yiO0@;l7ajo=K7=5{cWdxk@+J2?C!(ocC8!>jxb z2mZ&<ha(ul7+#}Hqcv^tI%VK~oc>~+myZTkz*m$=y~W%QIF>q|n%KpuI9kZGFqOs( zH@mnT!%7-?YNXS6Pb&R{>%%R~OPdxJf5YjH<%2G$6yX4;aDt<529vmjGZA2m9bk7l zz=jCrDA!#ROF`t{hUm(Dzu?2w_%oDNQ_DN3lv`MR9`G(c`9C;waya4|=U@pJA~?$- U&KL|v6GJsfp+stOt(g%200Suv!T<mO literal 0 HcmV?d00001 diff --git a/target/test-classes/com/com1028/travelagency/TripAdvisorTest.class b/target/test-classes/com/com1028/travelagency/TripAdvisorTest.class new file mode 100644 index 0000000000000000000000000000000000000000..ab96c7e9aa16c4145e937bbb506026a8b47c3ed0 GIT binary patch literal 2984 zcmbVOZBr9h6n-`d29i}`L@H7(wp4jFidK<W6#+3CKnX(C+IEv%lEq{fHyae~o7KK* ze@tgu#X9Xc({KGP{SBQycXtz)2s2D!lD&KHIp?19oadaAzyJOHPXNd9a~J^yJvp<S z;OFR(q2YvWX)B_n6@-ynP0U&P@@RfVub9@HsMukI6vURa6)jQHj6z~2yCib9f~fsk zPQk(SR_rAebj(%_TQ7@wy`pDJV$?89TeEf3sPHUpT7^W}%-z;)Gm$dnMN@pMP%kF# z<*HVNf*E10=sBUFfAc#h8iZ*ezRtKb%gr5kg=QCpRkzu@xy^-jqEy~?S~qn2jDlcK z@4SN0n3)$51QA!U1Fd1SDd^q`DiQ2Lyafv0QqhEM3R=^;A*QS4tgz-Zg5)@#(@OK2 zrOS73Gh`QaqSm*$%MGcd&pU0Vw2n?%uP~D_2brZRgGtDYC!6sOqZ=z~hOUKiK*262 z{Z(5pB}OevTa|hdbRpi1ZUx&jT3LG5HOcgeC=Q}0j6($XwU$&+(ThHUrRDPqcK4(k zDV6NK(ToAQlhF*@w1{n2szS=;n{k+!Oq8@m(;#cQ&I>J9Y{n7ZJgKeZ%}QNvh+9`I zK`z&&jw@)&N(Bk<2^B4fL@|t!Fit7x-84OQh&*PfNa8fD*IDR7*X<7@!-_Bp$zC@y z2Q4X;jNlB;g>jZR`uQy>NS>=0#d)&lZc!KtM*IfdQlmk?TE(trv%DuUV-!q2Gv0eL zig8>BV}h*PioA+Rd2fXDH)e%hwG7F_l!{BZ%p?><BTY{DUGrk~C2{lUr!W)7G;K<^ zT$+tmD#9WouHdQyRde1Z?o_oB`FzNKj|YM8o*F3g64s20Ib0)ISA?Z6uCfnppzI~Y z*S%N>p`310KJK&ZML<mIS*AO&#&lBGUR`EUwmQ73GljD4Y13b(l=4coyTQomH?KWI zr&?uodVMBkESeE~hHMxb>-KfEqzqdWgry<}7E*XcD^<nJA}{Yr`6Knjl9Km}DpYKj zfE88fSfZM4%vgD0v3>O1^f^;QcOB(Yt}Gc=f)PfUIoh;v)^|x2CYBX+E?Xk6=WLN5 zWuiD|=0tg!3$l(luH*ch#Ht0dQE<{DB2fX`*q-_&vzl&PvCOQN)k{v6Px)D~wHwCG zDm!g*+u6U4Ie!t{!~HNw8Q&~)g=8ik$d)$lchNJ@j4#OW1<fjVv6Xd=TdT6nzEbfu z9&(6!^G7CI!T)g63nq$3$b|8@p~ZNKV+$;shF#>TFV!_%>G_7)W*ubAs+AKLbUA|B z8ivVX$w&ozeZ#}58iueEobU^}T_m5I9CFHE2mX%awg9jFUAo4xLk%h>ae!P6@<)pN za1!z@%$0mL^9k9!eS1-7kHl`+3-X-<nBOr<oToK~&sg7c?Cg7qUDuyu_it$bg?j<) z;r9;bzD|U&pIV*h;GXL0U@zan_1ioN)V<lqJ=#`=sMEyt)A;`MOLWolyHf-4_g>)r z02T(~{k6qlZIP%gj=GEZv1w0lB-9a#dvaWP=Y7B816ny5z#2Xrc!4q6?FezVy?^i- zF0LUhCDt(e3d644f{ZKZ#C3)~gF`onK19)vHVj}N205P(Bf<Y+9OYCS;@CKbY5p+$ z2q#%i!?=%Ac!CiJhvRO19u7hLh<Pj!k0>5e{yH&9;wo-%FGxEVag%!?e9U{>dFD#p z;>ta{#WMw;Y=kBL;aP}!kBMchWeuNBh5kVBdXNE%%o+;Qa?wu=ZU-e8u}+G(fYc7| zI0tR0uHmkG691fM?fnDK@Fk%dl!7ntO#rV@@+>X9u}LcqhAuY_l5@aWMt6>@QQ|sA z)W&fc6O42c24jANl!H~D>wg`qhaOffcz|#59Z}dre06+JYXST~y8+@U86G7nKk@S< Hho}Dm^1KnJ literal 0 HcmV?d00001 diff --git a/target/test-classes/com/com1028/travelagency/TripManagerTest.class b/target/test-classes/com/com1028/travelagency/TripManagerTest.class new file mode 100644 index 0000000000000000000000000000000000000000..5f4f8f0c86e398198ef902f387bb66cda482f9f5 GIT binary patch literal 3163 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 literal 0 HcmV?d00001 -- GitLab