diff --git a/completesolution/c++/CMakeLists.txt b/completesolution/c++/CMakeLists.txt deleted file mode 100644 index 958d99ad..00000000 --- a/completesolution/c++/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.14) - -project(OctoConverter - VERSION 1.0.0 - LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -enable_testing() - -add_subdirectory(src) -add_subdirectory(test) diff --git a/completesolution/c++/src/CMakeLists.txt b/completesolution/c++/src/CMakeLists.txt deleted file mode 100644 index f25cc575..00000000 --- a/completesolution/c++/src/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_subdirectory(converters) -add_executable(main main.cpp) -target_link_libraries(main PRIVATE converters) - -set_target_properties( - main - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY - "${CMAKE_BINARY_DIR}" -) diff --git a/completesolution/c++/src/converters/CMakeLists.txt b/completesolution/c++/src/converters/CMakeLists.txt deleted file mode 100644 index 187e9fc1..00000000 --- a/completesolution/c++/src/converters/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -## Build a library "converters" with all included files -add_library( - converters - distance.cpp - distance.h - temperature.cpp - temperature.h - weight.cpp - weight.h - types.h -) diff --git a/completesolution/c++/src/converters/distance.cpp b/completesolution/c++/src/converters/distance.cpp deleted file mode 100644 index 073878f0..00000000 --- a/completesolution/c++/src/converters/distance.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "distance.h" -#include -#include - -namespace /* private */ { - std::string getDistanceUnitSign(DistanceUnit unit) - { - std::unordered_map unitSigns = { - {DistanceUnit::Meters, "m"}, - {DistanceUnit::Feet, "ft"}, - {DistanceUnit::Yards, "yd"} - }; - - return unitSigns.at(unit); - } -} // namespace private - -namespace DistanceConversion -{ - void startFlow() - { - double sourceValue = getSourceValue(); - DistanceUnit from = getDistanceUnit("source"); - DistanceUnit to = getDistanceUnit("target"); - - double targetValue = convertDistance(sourceValue, from, to); - - std::cout << sourceValue << getDistanceUnitSign(from) << " is " << targetValue << getDistanceUnitSign(to) << std::endl; - } - - double getSourceValue() - { - double value; - std::cout << "Enter the value to be converted: "; - std::cin >> value; - return value; - } - - DistanceUnit getDistanceUnit(const std::string_view &sourceOrTarget) - { - int choice; - std::cout << "Select " << sourceOrTarget << " distance unit:\n"; - std::cout << "[1] Meters\n"; - std::cout << "[2] Feet\n"; - std::cout << "[3] Yards\n"; - std::cout << "Enter choice: "; - std::cin >> choice; - - switch (choice) - { - case 1: - return DistanceUnit::Meters; - case 2: - return DistanceUnit::Feet; - case 3: - return DistanceUnit::Yards; - default: - return DistanceUnit::Meters; // Default to Meters - } - } - - double convertDistance(double value, DistanceUnit from, DistanceUnit to) - { - if (from == to) - { - return value; - } - - if (from == DistanceUnit::Meters) - { - if (to == DistanceUnit::Feet) - { - return value * 3.28084; - } - else if (to == DistanceUnit::Yards) - { - return value * 1.09361; - } - } - else if (from == DistanceUnit::Feet) - { - if (to == DistanceUnit::Meters) - { - return value / 3.28084; - } - else if (to == DistanceUnit::Yards) - { - return value / 3.0; - } - } - else if (from == DistanceUnit::Yards) - { - if (to == DistanceUnit::Meters) - { - return value / 1.09361; - } - else if (to == DistanceUnit::Feet) - { - return value * 3.0; - } - } - - return 0; - } -} \ No newline at end of file diff --git a/completesolution/c++/src/converters/distance.h b/completesolution/c++/src/converters/distance.h deleted file mode 100644 index 90685182..00000000 --- a/completesolution/c++/src/converters/distance.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef DISTANCE_H -#define DISTANCE_H - -#include - -enum class DistanceUnit -{ - Meters, - Feet, - Yards -}; - -namespace DistanceConversion -{ - void startFlow(); - double getSourceValue(); - DistanceUnit getDistanceUnit(const std::string_view &sourceOrTarget); - double convertDistance(double value, DistanceUnit from, DistanceUnit to); -} - -#endif diff --git a/completesolution/c++/src/converters/temperature.cpp b/completesolution/c++/src/converters/temperature.cpp deleted file mode 100644 index 013163a2..00000000 --- a/completesolution/c++/src/converters/temperature.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "temperature.h" -#include -#include - -namespace /* private */ -{ - std::string getTemperatureUnitSign(TemperatureUnit unit) - { - std::unordered_map unitSigns = { - {TemperatureUnit::Celsius, "°C"}, - {TemperatureUnit::Fahrenheit, "°F"}, - {TemperatureUnit::Kelvin, "K"} - }; - - return unitSigns.at(unit); - } -} // namespace private - -namespace TemperatureConversion -{ - void startFlow() - { - double sourceValue = getSourceValue(); - TemperatureUnit from = getTemperatureUnit("source"); - TemperatureUnit to = getTemperatureUnit("target"); - - double targetValue = convertTemperature(sourceValue, from, to); - - std::cout << sourceValue << getTemperatureUnitSign(from) << " is " << targetValue << getTemperatureUnitSign(to) << std::endl; - } - - double getSourceValue() - { - double value; - std::cout << "Enter the value to be converted: "; - std::cin >> value; - return value; - } - - TemperatureUnit getTemperatureUnit(const std::string_view &sourceOrTarget) - { - int choice; - std::cout << "Select " << sourceOrTarget << " temperature unit:\n"; - std::cout << "[1] Celsius\n"; - std::cout << "[2] Fahrenheit\n"; - std::cout << "[3] Kelvin\n"; - std::cout << "Enter choice: "; - std::cin >> choice; - - switch (choice) - { - case 1: - return TemperatureUnit::Celsius; - case 2: - return TemperatureUnit::Fahrenheit; - case 3: - return TemperatureUnit::Kelvin; - default: - return TemperatureUnit::Celsius; // Default to Celsius - } - } - - double convertTemperature(double value, TemperatureUnit from, TemperatureUnit to) - { - if (from == to) - { - return value; - } - - // Convert everything to Celsius first - if (from == TemperatureUnit::Fahrenheit) - { - value = (value - 32) * 5 / 9; - } - else if (from == TemperatureUnit::Kelvin) - { - value -= 273.15; - } - - // Then convert to the target unit - if (to == TemperatureUnit::Fahrenheit) - { - value = value * 9 / 5 + 32; - } - else if (to == TemperatureUnit::Kelvin) - { - value += 273.15; - } - - return value; - } -} \ No newline at end of file diff --git a/completesolution/c++/src/converters/temperature.h b/completesolution/c++/src/converters/temperature.h deleted file mode 100644 index 94b8c126..00000000 --- a/completesolution/c++/src/converters/temperature.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef TEMPERATURE_H -#define TEMPERATURE_H - -#include "types.h" -#include - -enum class TemperatureUnit -{ - Celsius, - Fahrenheit, - Kelvin -}; - -namespace TemperatureConversion -{ - void startFlow(); - double getSourceValue(); - TemperatureUnit getTemperatureUnit(const std::string_view &sourceOrTarget); - double convertTemperature(double value, TemperatureUnit from, TemperatureUnit to); -} - -#endif diff --git a/completesolution/c++/src/converters/types.h b/completesolution/c++/src/converters/types.h deleted file mode 100644 index 6f4752f9..00000000 --- a/completesolution/c++/src/converters/types.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef TYPES -#define TYPES - -enum class ConversionType -{ - Temperature, - Distance, - Weight, -}; - -#endif diff --git a/completesolution/c++/src/converters/weight.cpp b/completesolution/c++/src/converters/weight.cpp deleted file mode 100644 index fb007b1f..00000000 --- a/completesolution/c++/src/converters/weight.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "weight.h" -#include -#include - -namespace /* private */ -{ - std::string getWeightUnitSign(WeightConversion::WeightUnit unit) - { - std::unordered_map unitSigns = { - {WeightConversion::WeightUnit::Kilograms, "kg"}, - {WeightConversion::WeightUnit::Pounds, "lb"}, - {WeightConversion::WeightUnit::Ounces, "oz"} - }; - - return unitSigns.at(unit); - } -} // namespace private - -namespace WeightConversion -{ - void startFlow() - { - double sourceValue = getSourceValue(); - WeightUnit from = getWeightUnit("source"); - WeightUnit to = getWeightUnit("target"); - - double targetValue = convertWeight(sourceValue, from, to); - - std::cout << sourceValue << getWeightUnitSign(from) << " is " << targetValue << getWeightUnitSign(to) << std::endl; - } - - double getSourceValue() - { - double value; - std::cout << "Enter the value to be converted: "; - std::cin >> value; - return value; - } - - WeightUnit getWeightUnit(const std::string_view &sourceOrTarget) - { - int choice; - std::cout << "Select " << sourceOrTarget << " weight unit:\n"; - std::cout << "[1] Kilograms\n"; - std::cout << "[2] Pounds\n"; - std::cout << "[3] Ounces\n"; - std::cout << "Enter choice: "; - std::cin >> choice; - - switch (choice) - { - case 1: - return WeightUnit::Kilograms; - case 2: - return WeightUnit::Pounds; - case 3: - return WeightUnit::Ounces; - default: - return WeightUnit::Kilograms; // Default to Kilograms - } - } - - double convertWeight(double value, WeightUnit from, WeightUnit to) - { - if (from == to) - { - return value; - } - - // Convert everything to Kilograms first - if (from == WeightUnit::Pounds) - { - value = value * 0.453592; - } - else if (from == WeightUnit::Ounces) - { - value = value * 0.0283495; - } - - // Then convert to the target unit - if (to == WeightUnit::Pounds) - { - value = value / 0.453592; - } - else if (to == WeightUnit::Ounces) - { - value = value / 0.0283495; - } - - return value; - } -} \ No newline at end of file diff --git a/completesolution/c++/src/converters/weight.h b/completesolution/c++/src/converters/weight.h deleted file mode 100644 index 7dadc588..00000000 --- a/completesolution/c++/src/converters/weight.h +++ /dev/null @@ -1,21 +0,0 @@ -#include - -#ifndef WEIGHT_H -#define WEIGHT_H - -namespace WeightConversion -{ - enum class WeightUnit - { - Kilograms, - Pounds, - Ounces - }; - - void startFlow(); - double getSourceValue(); - WeightUnit getWeightUnit(const std::string_view &sourceOrTarget); - double convertWeight(double value, WeightUnit from, WeightUnit to); -} - -#endif // WEIGHT_H \ No newline at end of file diff --git a/completesolution/c++/src/main.cpp b/completesolution/c++/src/main.cpp deleted file mode 100644 index 030a77b7..00000000 --- a/completesolution/c++/src/main.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "converters/types.h" -#include "converters/temperature.h" -#include "converters/distance.h" -#include "converters/weight.h" -#include -#include - -ConversionType getConversionType() -{ - int choice; - std::array conversionTypes = { - ConversionType::Temperature, - ConversionType::Distance, - ConversionType::Weight}; - - while (true) - { - std::cout << "Select type of conversion:\n"; - std::cout << "[1] Temperature\n"; - std::cout << "[2] Distance\n"; - std::cout << "[3] Weight\n"; - std::cout << "Enter choice: "; - std::cin >> choice; - - if (choice > 0 && choice <= conversionTypes.size()) - { - return conversionTypes[choice - 1]; - } - - std::cout << "Invalid choice. Please try again.\n"; - } -} - -int main() -{ - ConversionType type = getConversionType(); - switch (type) - { - case ConversionType::Temperature: - { - TemperatureConversion::startFlow(); - break; - } - case ConversionType::Distance: - { - DistanceConversion::startFlow(); - break; - } - case ConversionType::Weight: - { - WeightConversion::startFlow(); - break; - } - } -} \ No newline at end of file diff --git a/completesolution/c++/test/CMakeLists.txt b/completesolution/c++/test/CMakeLists.txt deleted file mode 100644 index 889ec270..00000000 --- a/completesolution/c++/test/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -set(target run-tests) - -add_executable( - ${target} - temperature_test.cpp - distance_test.cpp - weight_test.cpp -) - -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip -) -# For Windows: Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) - -target_link_libraries(${target} GTest::gtest_main) - -target_include_directories( - ${target} - PUBLIC "${CMAKE_SOURCE_DIR}/src/converters" -) - -target_link_libraries(${target} converters) - -add_test(NAME ${target} COMMAND ${target}) - -include(GoogleTest) -gtest_discover_tests(${target}) - -set_target_properties( - ${target} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY - "${CMAKE_BINARY_DIR}" -) diff --git a/completesolution/c++/test/distance_test.cpp b/completesolution/c++/test/distance_test.cpp deleted file mode 100644 index 44e0d092..00000000 --- a/completesolution/c++/test/distance_test.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "gtest/gtest.h" -#include "distance.h" - -TEST(DistanceConversionTest, MetersToFeet) { - double result = DistanceConversion::convertDistance(1.0, DistanceUnit::Meters, DistanceUnit::Feet); - ASSERT_NEAR(result, 3.28084, 0.00001); -} - -TEST(DistanceConversionTest, FeetToMeters) { - double result = DistanceConversion::convertDistance(3.28084, DistanceUnit::Feet, DistanceUnit::Meters); - ASSERT_NEAR(result, 1.0, 0.00001); -} - -TEST(DistanceConversionTest, MetersToYards) { - double result = DistanceConversion::convertDistance(1.0, DistanceUnit::Meters, DistanceUnit::Yards); - ASSERT_NEAR(result, 1.09361, 0.00001); -} - -TEST(DistanceConversionTest, YardsToMeters) { - double result = DistanceConversion::convertDistance(1.09361, DistanceUnit::Yards, DistanceUnit::Meters); - ASSERT_NEAR(result, 1.0, 0.00001); -} - -TEST(DistanceConversionTest, FeetToYards) { - double result = DistanceConversion::convertDistance(3.0, DistanceUnit::Feet, DistanceUnit::Yards); - ASSERT_NEAR(result, 1.0, 0.00001); -} - -TEST(DistanceConversionTest, YardsToFeet) { - double result = DistanceConversion::convertDistance(1.0, DistanceUnit::Yards, DistanceUnit::Feet); - ASSERT_NEAR(result, 3.0, 0.00001); -} \ No newline at end of file diff --git a/completesolution/c++/test/temperature_test.cpp b/completesolution/c++/test/temperature_test.cpp deleted file mode 100644 index 381b7c8b..00000000 --- a/completesolution/c++/test/temperature_test.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "temperature.h" -#include - -TEST(TemperatureConverterTest, FahrenheitToCelsius) { - double result = TemperatureConversion::convertTemperature(32, TemperatureUnit::Fahrenheit, TemperatureUnit::Celsius); - ASSERT_DOUBLE_EQ(result, 0); -} - -TEST(TemperatureConverterTest, KelvinToCelsius) { - double result = TemperatureConversion::convertTemperature(273.15, TemperatureUnit::Kelvin, TemperatureUnit::Celsius); - ASSERT_DOUBLE_EQ(result, 0); -} - -TEST(TemperatureConverterTest, CelsiusToFahrenheit) { - double result = TemperatureConversion::convertTemperature(0, TemperatureUnit::Celsius, TemperatureUnit::Fahrenheit); - ASSERT_DOUBLE_EQ(result, 32); -} - -TEST(TemperatureConverterTest, CelsiusToKelvin) { - double result = TemperatureConversion::convertTemperature(0, TemperatureUnit::Celsius, TemperatureUnit::Kelvin); - ASSERT_DOUBLE_EQ(result, 273.15); -} - -TEST(TemperatureConverterTest, FahrenheitToKelvin) { - double result = TemperatureConversion::convertTemperature(32, TemperatureUnit::Fahrenheit, TemperatureUnit::Kelvin); - ASSERT_DOUBLE_EQ(result, 273.15); -} - -TEST(TemperatureConverterTest, KelvinToFahrenheit) { - double result = TemperatureConversion::convertTemperature(273.15, TemperatureUnit::Kelvin, TemperatureUnit::Fahrenheit); - ASSERT_DOUBLE_EQ(result, 32); -} diff --git a/completesolution/c++/test/weight_test.cpp b/completesolution/c++/test/weight_test.cpp deleted file mode 100644 index a0b483a6..00000000 --- a/completesolution/c++/test/weight_test.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include "weight.h" - -TEST(WeightConversionTest, KilogramsToPounds) { - double result = WeightConversion::convertWeight(1.0, WeightConversion::WeightUnit::Kilograms, WeightConversion::WeightUnit::Pounds); - ASSERT_NEAR(result, 2.20462, 0.00001); -} - -TEST(WeightConversionTest, PoundsToKilograms) { - double result = WeightConversion::convertWeight(2.20462, WeightConversion::WeightUnit::Pounds, WeightConversion::WeightUnit::Kilograms); - ASSERT_NEAR(result, 1.0, 0.00001); -} - -TEST(WeightConversionTest, KilogramsToOunces) { - double result = WeightConversion::convertWeight(1.0, WeightConversion::WeightUnit::Kilograms, WeightConversion::WeightUnit::Ounces); - ASSERT_NEAR(result, 35.274, 0.001); -} - -TEST(WeightConversionTest, OuncesToKilograms) { - double result = WeightConversion::convertWeight(35.274, WeightConversion::WeightUnit::Ounces, WeightConversion::WeightUnit::Kilograms); - ASSERT_NEAR(result, 1.0, 0.001); -} - -TEST(WeightConversionTest, PoundsToOunces) { - double result = WeightConversion::convertWeight(1.0, WeightConversion::WeightUnit::Pounds, WeightConversion::WeightUnit::Ounces); - ASSERT_NEAR(result, 16.0, 0.00001); -} - -TEST(WeightConversionTest, OuncesToPounds) { - double result = WeightConversion::convertWeight(16.0, WeightConversion::WeightUnit::Ounces, WeightConversion::WeightUnit::Pounds); - ASSERT_NEAR(result, 1.0, 0.00001); -} \ No newline at end of file diff --git a/completesolution/dataengineer/COVID19WorldwideTestingData.ipynb b/completesolution/dataengineer/COVID19WorldwideTestingData.ipynb deleted file mode 100644 index 81b4d82c..00000000 --- a/completesolution/dataengineer/COVID19WorldwideTestingData.ipynb +++ /dev/null @@ -1,1450 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Import Required Libraries\n", - "Import the necessary libraries, including pandas." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Import Required Libraries\n", - "# Here we are importing the necessary libraries for our task\n", - "\n", - "import pandas as pd # pandas is a software library written for the Python programming language for data manipulation and analysis." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Load the Dataset\n", - "Use pandas to load the 'tested_worldwide.csv' file from the root level." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
DateCountry_RegionProvince_StatepositiveactivehospitalizedhospitalizedCurrrecovereddeathtotal_testeddaily_testeddaily_positive
02020-01-16IcelandAll States3.0NaNNaNNaNNaNNaNNaNNaNNaN
12020-01-17IcelandAll States4.0NaNNaNNaNNaNNaNNaNNaN1.0
22020-01-18IcelandAll States7.0NaNNaNNaNNaNNaNNaNNaN3.0
32020-01-20South KoreaAll States1.0NaNNaNNaNNaNNaN4.0NaNNaN
42020-01-22United StatesAll States0.0NaNNaNNaNNaN0.00.0NaNNaN
\n", - "
" - ], - "text/plain": [ - " Date Country_Region Province_State positive active hospitalized \\\n", - "0 2020-01-16 Iceland All States 3.0 NaN NaN \n", - "1 2020-01-17 Iceland All States 4.0 NaN NaN \n", - "2 2020-01-18 Iceland All States 7.0 NaN NaN \n", - "3 2020-01-20 South Korea All States 1.0 NaN NaN \n", - "4 2020-01-22 United States All States 0.0 NaN NaN \n", - "\n", - " hospitalizedCurr recovered death total_tested daily_tested \\\n", - "0 NaN NaN NaN NaN NaN \n", - "1 NaN NaN NaN NaN NaN \n", - "2 NaN NaN NaN NaN NaN \n", - "3 NaN NaN NaN 4.0 NaN \n", - "4 NaN NaN 0.0 0.0 NaN \n", - "\n", - " daily_positive \n", - "0 NaN \n", - "1 1.0 \n", - "2 3.0 \n", - "3 NaN \n", - "4 NaN " - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Load the Dataset\n", - "# Here we are using pandas to load the 'tested_worldwide.csv' file from the root level.\n", - "\n", - "# Load the dataset\n", - "data = pd.read_csv('tested_worldwide.csv')\n", - "\n", - "# Display the first 5 rows of the dataset\n", - "data.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Display the First 5 Rows\n", - "Use the head() function to display the first 5 rows of the dataset." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
DateCountry_RegionProvince_StatepositiveactivehospitalizedhospitalizedCurrrecovereddeathtotal_testeddaily_testeddaily_positive
02020-01-16IcelandAll States3.0NaNNaNNaNNaNNaNNaNNaNNaN
12020-01-17IcelandAll States4.0NaNNaNNaNNaNNaNNaNNaN1.0
22020-01-18IcelandAll States7.0NaNNaNNaNNaNNaNNaNNaN3.0
32020-01-20South KoreaAll States1.0NaNNaNNaNNaNNaN4.0NaNNaN
42020-01-22United StatesAll States0.0NaNNaNNaNNaN0.00.0NaNNaN
\n", - "
" - ], - "text/plain": [ - " Date Country_Region Province_State positive active hospitalized \\\n", - "0 2020-01-16 Iceland All States 3.0 NaN NaN \n", - "1 2020-01-17 Iceland All States 4.0 NaN NaN \n", - "2 2020-01-18 Iceland All States 7.0 NaN NaN \n", - "3 2020-01-20 South Korea All States 1.0 NaN NaN \n", - "4 2020-01-22 United States All States 0.0 NaN NaN \n", - "\n", - " hospitalizedCurr recovered death total_tested daily_tested \\\n", - "0 NaN NaN NaN NaN NaN \n", - "1 NaN NaN NaN NaN NaN \n", - "2 NaN NaN NaN NaN NaN \n", - "3 NaN NaN NaN 4.0 NaN \n", - "4 NaN NaN 0.0 0.0 NaN \n", - "\n", - " daily_positive \n", - "0 NaN \n", - "1 1.0 \n", - "2 3.0 \n", - "3 NaN \n", - "4 NaN " - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Display the First 5 Rows\n", - "# Here we are using the head() function to display the first 5 rows of the dataset\n", - "\n", - "# Display the first 5 rows of the dataset\n", - "data.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the number of rows and columns in the dataframe" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of rows: 27641\n", - "Number of columns: 12\n" - ] - } - ], - "source": [ - "num_rows, num_cols = data.shape\n", - "print(\"Number of rows:\", num_rows)\n", - "print(\"Number of columns:\", num_cols)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the data types of each column" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Date object\n", - "Country_Region object\n", - "Province_State object\n", - "positive float64\n", - "active float64\n", - "hospitalized float64\n", - "hospitalizedCurr float64\n", - "recovered float64\n", - "death float64\n", - "total_tested float64\n", - "daily_tested float64\n", - "daily_positive float64\n", - "dtype: object" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data.dtypes\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the number of missing values in each column" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Date 0\n", - "Country_Region 0\n", - "Province_State 0\n", - "positive 4242\n", - "active 9833\n", - "hospitalized 19231\n", - "hospitalizedCurr 13080\n", - "recovered 9626\n", - "death 4010\n", - "total_tested 912\n", - "daily_tested 1174\n", - "daily_positive 4557\n", - "dtype: int64\n" - ] - } - ], - "source": [ - "missing_values = data.isnull().sum()\n", - "print(missing_values)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the number of unique values in each column" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Date 297\n", - "Country_Region 147\n", - "Province_State 81\n", - "positive 14998\n", - "active 9554\n", - "hospitalized 4862\n", - "hospitalizedCurr 2904\n", - "recovered 9183\n", - "death 5641\n", - "total_tested 23610\n", - "daily_tested 13375\n", - "daily_positive 3440\n", - "dtype: int64\n" - ] - } - ], - "source": [ - "unique_values = data.nunique()\n", - "print(unique_values)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Drop the columns that are not needed for the analysis" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "data = data[['Country_Region', 'positive', 'total_tested']]\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Rename the columns to make them more readable" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "data.rename(columns={'Country_Region': 'Country', 'positive': 'Positive Cases', 'total_tested': 'Total Tested'}, inplace=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Drop the rows that have missing values" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "data.dropna(inplace=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Convert the data types of the columns to the appropriate types" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "data['Positive Cases'] = data['Positive Cases'].astype(int)\n", - "data['Total Tested'] = data['Total Tested'].astype(int)\n", - "data['Country'] = data['Country'].astype(str)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the number of missing values in each column" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Country 0\n", - "Positive Cases 0\n", - "Total Tested 0\n", - "dtype: int64\n" - ] - } - ], - "source": [ - "missing_values = data.isnull().sum()\n", - "print(missing_values)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create a new dataframe that contains the total number of positive cases for each country" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CountryTotal Positive Cases
0Albania12279
1Argentina28220
2Armenia7225809
3Australia20654
4Austria541013
.........
112United States1837768204
113Uruguay2160
114Veneto119910
115Venezuela461
116Vietnam6450
\n", - "

117 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " Country Total Positive Cases\n", - "0 Albania 12279\n", - "1 Argentina 28220\n", - "2 Armenia 7225809\n", - "3 Australia 20654\n", - "4 Austria 541013\n", - ".. ... ...\n", - "112 United States 1837768204\n", - "113 Uruguay 2160\n", - "114 Veneto 119910\n", - "115 Venezuela 461\n", - "116 Vietnam 6450\n", - "\n", - "[117 rows x 2 columns]" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Group the data by 'Country' and calculate the sum of 'Positive Cases'\n", - "total_positive_cases = data.groupby('Country')['Positive Cases'].sum()\n", - "\n", - "# Create a new dataframe with the total positive cases for each country\n", - "df_total_positive_cases = pd.DataFrame({'Country': total_positive_cases.index, 'Total Positive Cases': total_positive_cases.values})\n", - "\n", - "# Display the new dataframe\n", - "df_total_positive_cases\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Sort the dataframe in descending order of the total number of positive cases" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "df_total_positive_cases.sort_values(by='Total Positive Cases', ascending=False, inplace=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the top ten countries with the most positive cases" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CountryTotal Positive Cases
112United States1837768204
48Italy64199206
17Canada50960416
7Bangladesh43771939
106Turkey16556127
26Czechia10822251
88Russia10663267
2Armenia7225809
21Costa Rica6655702
111United Kingdom4924956
\n", - "
" - ], - "text/plain": [ - " Country Total Positive Cases\n", - "112 United States 1837768204\n", - "48 Italy 64199206\n", - "17 Canada 50960416\n", - "7 Bangladesh 43771939\n", - "106 Turkey 16556127\n", - "26 Czechia 10822251\n", - "88 Russia 10663267\n", - "2 Armenia 7225809\n", - "21 Costa Rica 6655702\n", - "111 United Kingdom 4924956" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_total_positive_cases.head(10)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create a new dataframe that contains the total number of tests conducted for each country" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CountryTotal Tests
0Albania114611
1Argentina323035
2Armenia35667650
3Australia323233309
4Austria7610548
.........
112United States23592177772
113Uruguay51789
114Veneto1650118
115Venezuela395904
116Vietnam3761926
\n", - "

117 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " Country Total Tests\n", - "0 Albania 114611\n", - "1 Argentina 323035\n", - "2 Armenia 35667650\n", - "3 Australia 323233309\n", - "4 Austria 7610548\n", - ".. ... ...\n", - "112 United States 23592177772\n", - "113 Uruguay 51789\n", - "114 Veneto 1650118\n", - "115 Venezuela 395904\n", - "116 Vietnam 3761926\n", - "\n", - "[117 rows x 2 columns]" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Group the data by 'Country' and calculate the sum of 'Total Tested'\n", - "total_tests = data.groupby('Country')['Total Tested'].sum()\n", - "\n", - "# Create a new dataframe with the total tests conducted for each country\n", - "df_total_tests = pd.DataFrame({'Country': total_tests.index, 'Total Tests': total_tests.values})\n", - "\n", - "# Display the new dataframe\n", - "df_total_tests\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Sort the dataframe in descending order of the total number of tests conducted" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "df_total_tests.sort_values(by='Total Tests', ascending=False, inplace=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the top ten countries with the most tests conducted" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CountryTotal Tests
112United States23592177772
17Canada1797986542
48Italy1547472209
47Israel388197039
3Australia323233309
88Russia300300499
7Bangladesh233149800
106Turkey228325949
26Czechia180065598
39Greece142101237
\n", - "
" - ], - "text/plain": [ - " Country Total Tests\n", - "112 United States 23592177772\n", - "17 Canada 1797986542\n", - "48 Italy 1547472209\n", - "47 Israel 388197039\n", - "3 Australia 323233309\n", - "88 Russia 300300499\n", - "7 Bangladesh 233149800\n", - "106 Turkey 228325949\n", - "26 Czechia 180065598\n", - "39 Greece 142101237" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_total_tests.head(10)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Merge the two dataframes created in the previous steps" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CountryTotal Positive CasesTotal Tests
0United States183776820423592177772
1Italy641992061547472209
2Canada509604161797986542
3Bangladesh43771939233149800
4Turkey16556127228325949
............
112Mozambique1605287
113Myanmar1518460
114Malawi781689
115Grenada42322
116North Korea01449
\n", - "

117 rows × 3 columns

\n", - "
" - ], - "text/plain": [ - " Country Total Positive Cases Total Tests\n", - "0 United States 1837768204 23592177772\n", - "1 Italy 64199206 1547472209\n", - "2 Canada 50960416 1797986542\n", - "3 Bangladesh 43771939 233149800\n", - "4 Turkey 16556127 228325949\n", - ".. ... ... ...\n", - "112 Mozambique 160 5287\n", - "113 Myanmar 151 8460\n", - "114 Malawi 78 1689\n", - "115 Grenada 42 322\n", - "116 North Korea 0 1449\n", - "\n", - "[117 rows x 3 columns]" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "merged_df = pd.merge(df_total_positive_cases, df_total_tests, on='Country')\n", - "merged_df\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create a new column that contains the ratio of positive cases to the number of tests conducted" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "merged_df['Positive Cases to Tests Ratio'] = merged_df['Total Positive Cases'] / merged_df['Total Tests']\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Sort the dataframe in descending order of the ratio of positive cases to the number of tests conducted" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "merged_df.sort_values(by='Positive Cases to Tests Ratio', ascending=False, inplace=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the top three countries with the highest ratio of positive cases to the number of tests conducted" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CountryPositive Cases to Tests Ratio
106Tanzania0.780675
103Burkina Faso0.480870
50Ecuador0.322330
\n", - "
" - ], - "text/plain": [ - " Country Positive Cases to Tests Ratio\n", - "106 Tanzania 0.780675\n", - "103 Burkina Faso 0.480870\n", - "50 Ecuador 0.322330" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "top_countries = merged_df.nlargest(3, 'Positive Cases to Tests Ratio')\n", - "top_countries[['Country', 'Positive Cases to Tests Ratio']]\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the results a chart that shows the top three countries with the highest ratio of positive cases to the number of tests conducted" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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/HMlJiaaLs/lcZjGxcyfP1+33nqrPD09NX/+/HP2HTVqVBVVBfzO399fW7ZsUevWrfX0009r1apVWrlypb766ivdeuutysjIMF0iaqGgoCC9++67GjBggEP7Z599pltuuUU5OTlmCqslOJvGxfwxYBA2UB3ZbDaVlpZKkj799FNdd911kqTQ0FBOOYcxhYWFCg4OPqu9cePGHKapAoyMuLjS0lLt27dP2dnZ9l8AZ/Tv399QVajN/v73vys0NFTR0dG68847tXPnTrVp00aff/65Ro0apYMHD5ouEbXQlVdeqYYNG2rBggXy8vKSJP32228aNWqUjh49qk8//dRwha6NMOLCvv76a40YMUKHDh06686oFotFJSUlhipDbfbNN99o5MiRSk9PV0JCgpKSkiRJ999/v44cOaK33nrLcIWojb799lvFxMSoqKhI3bp1kyRt375dXl5eWrlypf2Ckbg4CCMuLCIiQm3bttWUKVPUpEkTWSwWh+f9/f0NVQac7cSJE3J3d1fdunVNl4JaqrCwUAsXLtTu3bslnb7+zciRI1WvXj3Dlbk+wogL8/Hx0fbt29WmTRvTpQAAUC4msLqwqKgo7du3jzCCaqWkpET//ve/9c477yg9Pf2sa4scPXrUUGWobZYuXVrhvtdff/1FrASEERd2//33KzExUZmZmerSpctZw99du3Y1VBlqsylTpui1115TYmKinnjiCT3++OM6ePCgPvjgA02aNMl0eahFhgwZ4vDYYrGUOb9OEnPsLjIO07gwN7ezr2l35oeNCawwpXXr1po1a5YGDRokX19fbdu2zd729ddfM4EVRnz66acaN26cpk+frj59+kiS1q1bpyeeeELTp0/XVVddZbhC10YYcWGHDh065/PcKA8m+Pj4aNeuXWrevLmaNGmiZcuWqUePHjpw4IC6d++uvLw80yWiFurcubPS0tL0t7/9zaH9yy+/1D//+U/7TR1xcXCYxoURNlAdXXLJJTp8+LCaN2+u1q1b6+OPP1aPHj20ceNGeXp6mi4PtdT+/fsVEBBwVru/vz/XvqkCjIzUAjt37ixzoiATsmDCY489Jj8/P02YMEGLFy/W7bffrrCwMKWnp2vs2LGaMWOG6RJRC/Xv319eXl5644037FdizcrKUmxsrE6cOKHPP//ccIWujTDiwg4cOKChQ4dqx44dDhOzmJAFE0pLS8ucx/T1119r7dq1Cg8P1+DBgw1UBkj79u3T0KFD9f333ys0NFSSlJGRofDwcH3wwQeclXiREUZc2ODBg+Xu7q7XXntNLVu21IYNG3TkyBElJibq2WefVb9+/UyXiFrE3d1dhw8fVuPGjSVJjzzyiMaPH88dpFFt2Gw2ffLJJw4XPYuOjj7rgpGofIQRFxYUFKRVq1apa9eu8vf314YNG9SuXTutWrVKiYmJ2rp1q+kSUYu4ubkpMzPTHkb8/Py0bds2tWrVynBlAExjAqsLKykpka+vr6TTweTnn39Wu3bt1KJFC+3Zs8dwdajt+DsI1U1BQYE+//zzMufYPfDAA4aqqh0IIy6sc+fO2r59u1q2bKmoqCg988wz8vDw0CuvvMJfowDwB1u3btW1116rwsJCFRQUqEGDBsrNzZW3t7caN25MGLnICCMu7IknnlBBQYEkaerUqbruuuvUr18/NWzYUIsXLzZcHWqjSZMmydvbW5JUXFysadOmnXXDxpSUFBOloZYbO3asBg8erLS0NPn7++vrr79W3bp1dfvtt+vBBx80XZ7LY85ILXP06FEFBgYyIQtVbsCAAX/5vbNYLFq1alUVVQT8LiAgQOvXr1e7du0UEBCgdevWqUOHDlq/fr1GjRpln9SKi4ORERe2YMECRUZGqmPHjva2Bg0a6MSJE3rnnXcUGxtrsDrUNqtXrzZdAlCuunXr2k89b9y4sdLT09WhQwf5+/srIyPDcHWu7+yT/uEyRo8eraioKL333nsO7Xl5eYqLizNUFQBUP927d9fGjRslSZdffrkmTZqkhQsX6qGHHlLnzp0NV+f6CCMubsqUKbrjjjs0efJk06UAQLU1ffp0NWnSRJI0bdo0BQYG6t5771VOTo5eeeUVw9W5PuaMuLAz13U4cyXWyy67TG+88Yby8/PVtGlTrsAKAKgWGBlxYWcmC1566aVav3699u3bp759+3LTJwBAtcLIiAv78xUvCwsLNXLkSFmtVhUUFDAyAgD/p2XLluc82+vAgQNVWE3tw9k0LiwpKUn169e3P/b29tb777+vpKQkffHFFwYrA06H47KudNm1a1dDFaE2e+ihhxwenzx5Ulu3btWKFSv0yCOPmCmqFmFkBECVysnJUVxcnP73v/+V+TwjdqhOZs+erU2bNmnu3LmmS3FphBEXt3fvXn322WfKzs5WaWmpvd1isWjixIkGK0NtNXLkSB06dEipqakaMGCA3n//fWVlZempp57Sc889p0GDBpkuEbA7cOCAIiIilJ+fb7oUl8ZhGhf26quv6t5771VQUJBCQkIcjocSRmDKqlWr9OGHHyoyMlJubm5q0aKFrrrqKvn5+Sk5OZkwgmrl3XffVYMGDUyX4fIIIy7sqaee0rRp0zRu3DjTpQB2BQUF9knVgYGBysnJUdu2bdWlSxdt2bLFcHWorbp37+7wB5vNZlNmZqZycnL04osvGqysdiCMuLBjx45p2LBhpssAHLRr10579uxRWFiYunXrppdffllhYWFKS0uzX3QKqGpDhgxxeOzm5qZGjRppwIABat++vZmiahHmjLiwO++8U7169dI999xjuhTA7s0339SpU6c0evRobd68WQMHDtTRo0fl4eGhefPmafjw4aZLBFDFCCMuLDk5WSkpKRo0aJC6dOmiunXrOjz/wAMPGKoM+F1hYaF2796t5s2bKygoyHQ5qKWWL18ud3d3xcTEOLSvXLlSpaWluuaaawxVVjsQRlxYy5Yty33OYrFwER8A+D9du3bVjBkzdO211zq0r1ixQuPGjdP27dsNVVY7EEYAVKmSkhLNmzdPVqv1rFPOpdNn2wBVrV69etq1a5fCwsIc2g8ePKhOnTqpoKDATGG1BBNYAVSpBx98UPPmzdOgQYPUuXPnc16CG6gq/v7+OnDgwFlhZN++ffLx8TFTVC3CyIiL+/HHH7V06dIyL7udkpJiqCrUZkFBQVqwYMFZw+GASXfffbfWrVun999/X61bt5Z0OojcdNNN6tWrl1577TXDFbo2RkZcmNVq1fXXX69WrVpp9+7d6ty5sw4ePCibzaYePXqYLg+1lIeHh9q0aWO6DMDBM888o4EDB6p9+/a65JJLJJ3+Y65fv36aOXOm4epcHyMjLqx379665pprNGXKFPn6+mr79u1q3LixRo4cqYEDB+ree+81XSJqoeeee04HDhzQCy+8wCEaVCs2m02ffvqptm3bpnr16qlr167q37+/6bJqBcKIC/P19dW2bdvUunVrBQYGas2aNerUqZO2b9+uG264QQcPHjRdImqhoUOH6rPPPlODBg3UqVOns045X7JkiaHKUBtde+21evvtt+Xv7y9JmjFjhu655x4FBARIko4cOaJ+/fpp586d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gIAA7dq1y6n9de3a1eFxkyZNlJ2d/ZfrtWjRwiGISNKYMWP08ccf66effpIkzZs3T6NHj5bFYnGqJgBVg5ERAGUKDw+XxWK54Emqbm5uZwWbkydPntWvbt26Do8tFotKS0v/cvtlHULq3r27unXrpgULFujqq6/Wd999p2XLljlZOYCqwsgIgDI1aNBAMTExmj17tgoKCs56/pdfflGHDh2UkZGhjIwMe/vOnTv1yy+/qGPHjpKkRo0a6fDhww7rbtu2zel66tatq5KSkgr3v+uuuzRv3jzNnTtX0dHRDqM3AKoXwgiAcs2ePVslJSXq3bu33nvvPe3du1e7du3SrFmz1KdPH0VHR6tLly4aOXKktmzZog0bNig2NlaXX365IiMjJUl///vftWnTJi1YsEB79+5VUlKSvv32W6drCQsLk9VqVWZmpo4dO/aX/UeMGKEff/xRr776KhNXgWqOMAKgXK1atdKWLVt0xRVXKDExUZ07d9ZVV10lq9Wql156SRaLRR9++KECAwPVv39/RUdHq1WrVlq8eLF9GzExMZo4caIeffRR9erVS7/++qtiY2OdruW5557TJ598otDQUHXv3v0v+/v7++umm25S/fr1zzq1GED1YrFVZJYaANRAV155pTp16qRZs2aZLgXAORBGALicY8eOafXq1br55pu1c+dOtWvXznRJAM6Bs2kAuJzu3bvr2LFjevrppwkiQA3AyAgAADCKCawAAMAowggAADCKMAIAAIwijAAAAKMIIwAAwCjCCAAAMIowAgAAjCKMAAAAo/4/36kP45oL7z0AAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "top_countries.plot(x='Country', y='Positive Cases to Tests Ratio', kind='bar')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Display the results in a chart that shows the top ten countries with the most positive cases" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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/v4qr29paQlLS0vpfmhoKJ4+fYq+ffsqraenp/feK+oSERVX2b/7sosgouLGysoqX/7Ga/ShkdWrV8PX1xdOTk5K7Tdu3ICDgwOMjIxQr149zJw5E+XKlctzO+np6UhPT5fuJycnF1hmIqKCpFAoYG9vDxsbG7x69UruOET5Sl9f/5OP/GTT2ALov//+w59//onffvtNqb1OnTpYt24dKlasiPv372Py5Mlo1KgR/vnnH5ibm+e6rZkzZ0rTdRMRFQe6urr59oeCqDjS2FFg69evh5WVFTp06KDU7u/vjy5dusDDwwN+fn7Yt28fnj17hq1bt+a5rbFjxyIpKUm63b17t4DTExERkZw08giQEAJr1qxBr169YGBg8N51raysUKFCBcTGxua5jqGhIQwNDfM7JhERERVRGnkEKCIiArGxsfj6668/uG5KSgpu3rwJe3v7QkhGREREmkDWAiglJQUxMTGIiYkBAMTFxSEmJgbx8fEA3pyaCggIyPG41atXo06dOqhWrVqOZSNHjkRERARu376NU6dOoWPHjtDV1UWPHj0KdF+IiIhIc8h6CuzcuXPw8fGR7gcGBgIAevfujXXr1uH+/ftSMZQtKSkJO3bswMKFC3Pd5r///osePXrg8ePHKF26NBo2bIjTp0+jdOnSBbcjREREpFEUgnOm55CcnAxLS0skJSXBwsJCpcc4j9lbwKmA27NaF/hzEBERaSp1/n5rZB8gIiIiok/BAoiIiIi0DgsgIiIi0josgIiIiEjrsAAiIiIircMCiIiIiLQOCyAiIiLSOiyAiIiISOuwACIiIiKtwwKIiIiItA4LICIiItI6LICIiIhI67AAIiIiIq3DAoiIiIi0DgsgIiIi0josgIiIiEjrsAAiIiIircMCiIiIiLQOCyAiIiLSOiyAiIiISOuwACIiIiKtwwKIiIiItA4LICIiItI6LICIiIhI67AAIiIiIq3DAoiIiIi0DgsgIiIi0josgIiIiEjrsAAiIiIircMCiIiIiLQOCyAiIiLSOiyAiIiISOuwACIiIiKtwwKIiIiItA4LICIiItI6LICIiIhI67AAIiIiIq0jawF07NgxtG3bFg4ODlAoFAgNDX3v+kePHoVCochxS0hIUFpvyZIlcHZ2hpGREerUqYOzZ88W4F4QERGRppG1AEpNTYWnpyeWLFmi1uOuXbuG+/fvSzcbGxtpWUhICAIDAzFx4kRER0fD09MTfn5+ePDgQX7HJyIiIg2lJ+eT+/v7w9/fX+3H2djYwMrKKtdl8+fPx4ABA9C3b18AwLJly7B3716sWbMGY8aM+ZS4REREVExoZB8gLy8v2Nvbo3nz5jh58qTUnpGRgfPnz8PX11dq09HRga+vLyIjI/PcXnp6OpKTk5VuREREVHxpVAFkb2+PZcuWYceOHdixYwccHR3RtGlTREdHAwAePXqEzMxM2NraKj3O1tY2Rz+ht82cOROWlpbSzdHRsUD3g4iIiOQl6ykwdVWsWBEVK1aU7tevXx83b97EggULsHHjxo/e7tixYxEYGCjdT05OZhFERERUjGlUAZSb2rVr48SJEwCAUqVKQVdXF4mJiUrrJCYmws7OLs9tGBoawtDQsEBzEhERUdGhUafAchMTEwN7e3sAgIGBAby9vREeHi4tz8rKQnh4OOrVqydXRCIiIipiZD0ClJKSgtjYWOl+XFwcYmJiUKJECZQrVw5jx47FvXv3sGHDBgBAcHAwXFxcULVqVbx8+RKrVq3C4cOHceDAAWkbgYGB6N27N2rVqoXatWsjODgYqamp0qgwIiIiIlkLoHPnzsHHx0e6n90Pp3fv3li3bh3u37+P+Ph4aXlGRgZGjBiBe/fuwcTEBB4eHjh06JDSNrp164aHDx8iKCgICQkJ8PLyQlhYWI6O0URERKS9FEIIIXeIoiY5ORmWlpZISkqChYWFSo9xHrO3gFMBt2e1LvDnICIi0lTq/P3W+D5AREREROpiAURERERahwUQERERaR0WQERERKR1WAARERGR1mEBRERERFqHBRARERFpHRZAREREpHVYABEREZHWYQFEREREWocFEBEREWkdFkBERESkdVgAERERkdZhAURERERahwUQERERaR0WQERERKR1WAARERGR1mEBRERERFqHBRARERFpHRZAREREpHVYABEREZHWYQFEREREWocFEBEREWkdFkBERESkdVgAERERkdZhAURERERahwUQERERaR0WQERERKR1WAARERGR1vnkAig5ORmhoaG4cuVKfuQhIiIiKnBqF0Bdu3bF4sWLAQAvXrxArVq10LVrV3h4eGDHjh35HpCIiIgov6ldAB07dgyNGjUCAOzatQtCCDx79gyLFi3CtGnT8j0gERERUX5TuwBKSkpCiRIlAABhYWHo3LkzTExM0Lp1a9y4cSPfAxIRERHlN7ULIEdHR0RGRiI1NRVhYWFo0aIFAODp06cwMjLK94BERERE+U1P3QcMGzYMPXv2hJmZGcqVK4emTZsCeHNqrHr16vmdj4iIiCjfqV0Afffdd6hduzbu3r2L5s2bQ0fnzUEkV1dX9gEiIiIijaB2AQQAtWrVgoeHB+Li4uDm5gY9PT20bt06v7MRERERFQi1+wClpaXh66+/homJCapWrYr4+HgAwPfff49Zs2apta1jx46hbdu2cHBwgEKhQGho6HvX37lzJ5o3b47SpUvDwsIC9erVw/79+5XWmTRpEhQKhdKtUqVKauUiIiKi4k3tAmjs2LG4cOECjh49qtTp2dfXFyEhIWptKzU1FZ6enliyZIlK6x87dgzNmzfHvn37cP78efj4+KBt27b466+/lNarWrUq7t+/L91OnDihVi4iIiIq3tQ+BRYaGoqQkBDUrVsXCoVCaq9atSpu3ryp1rb8/f3h7++v8vrBwcFK92fMmIHdu3fj999/R40aNaR2PT092NnZqZWFiIiItIfaR4AePnwIGxubHO2pqalKBVFhyMrKwvPnz6V5ibLduHEDDg4OcHV1Rc+ePaXTdHlJT09HcnKy0o2IiIiKL7ULoFq1amHv3r3S/eyiZ9WqVahXr17+JVPBzz//jJSUFHTt2lVqq1OnDtatW4ewsDAsXboUcXFxaNSoEZ4/f57ndmbOnAlLS0vp5ujoWBjxiYiISCZqnwKbMWMG/P39cfnyZbx+/RoLFy7E5cuXcerUKURERBRExlz99ttvmDx5Mnbv3q10ROrtU2oeHh6oU6cOnJycsHXrVnz99de5bmvs2LEIDAyU7icnJ7MIIiIiKsbUPgLUsGFDxMTE4PXr16hevToOHDgAGxsbREZGwtvbuyAy5rBlyxb0798fW7duha+v73vXtbKyQoUKFRAbG5vnOoaGhrCwsFC6ERERUfH1UfMAubm5YeXKlfmdRSWbN29Gv379sGXLFpXmHkpJScHNmzfRq1evQkhHREREmkDtI0DR0dG4ePGidH/37t3o0KEDxo0bh4yMDLW2lZKSgpiYGMTExAAA4uLiEBMTI3VaHjt2LAICAqT1f/vtNwQEBGDevHmoU6cOEhISkJCQgKSkJGmdkSNHIiIiArdv38apU6fQsWNH6OrqokePHuruKhERERVTahdA33zzDa5fvw4AuHXrFrp16wYTExNs27YNo0ePVmtb586dQ40aNaQh7IGBgahRowaCgoIAAPfv31cawbVixQq8fv0agwcPhr29vXT74YcfpHX+/fdf9OjRAxUrVkTXrl1RsmRJnD59GqVLl1Z3V4mIiKiYUgghhDoPsLS0RHR0NNzc3DB79mwcPnwY+/fvx8mTJ9G9e3fcvXu3oLIWmuTkZFhaWiIpKUnl/kDOY/Z+eKVPdHsWLzdCRESUF3X+fqt9BEgIgaysLADAoUOH0KpVKwCAo6MjHj169BFxiYiIiArXR80DNG3aNGzcuBERERFSR+S4uDjY2trme0AiIiKi/KZ2ARQcHIzo6GgMGTIE48ePR/ny5QEA27dvR/369fM9IBEREVF+U3sYvIeHh9IosGxz586Frq5uvoQiIiIiKkgfNQ9Qbt6+MjwRERFRUaZ2AZSZmYkFCxZg69atiI+PzzH3z5MnT/ItHBEREVFBULsP0OTJkzF//nx069YNSUlJCAwMRKdOnaCjo4NJkyYVQEQiIiKi/KV2AbRp0yasXLkSI0aMgJ6eHnr06IFVq1YhKCgIp0+fLoiMRERERPlK7QIoISEB1atXBwCYmZlJl6Fo06YN9u4t+MkAiYiIiD6V2gVQ2bJlcf/+fQBvLop64MABAEBUVBQMDQ3zNx0RERFRAVC7AOrYsSPCw8MBAN9//z0mTJgAd3d3BAQEoF+/fvkekIiIiCi/qT0KbNasWdL/u3XrBicnJ5w6dQru7u5o27ZtvoYjIiIiKgifPA9Q3bp1Ubdu3fzIQkRERFQoVD4Fdv78efj4+CA5OTnHsqSkJPj4+ODChQv5Go6IiIioIKhcAM2bNw+ff/55rpeXt7S0hK+vL+bOnZuv4YiIiIgKgsoF0JkzZ9C+ffs8l7dr1w6nTp3Kl1BEREREBUnlAujevXswNzfPc7mZmZk0PJ6IiIioKFO5ACpdujSuXbuW5/KrV6+iVKlS+RKKiIiIqCCpXAD5+vpi+vTpuS4TQmD69Onw9fXNt2BEREREBUXlYfA//fQTvL29UadOHYwYMQIVK1YE8ObIz7x583D9+nWsW7euoHISERER5RuVCyA3NzccOnQIffr0Qffu3aFQKAC8OfpTpUoVHDx4EOXLly+woERERET5Ra2JEGvVqoV//vkHMTExuHHjBoQQqFChAry8vAooHhEREVH++6iZoL28vFj0EBERkcZS+2KoRERERJqOBRARERFpHRZAREREpHVYABEREZHW+agC6Pjx4/jqq69Qr1493Lt3DwCwceNGnDhxIl/DERERERUEtQugHTt2wM/PD8bGxvjrr7+Qnp4OAEhKSsKMGTPyPSARERFRflO7AJo2bRqWLVuGlStXQl9fX2pv0KABoqOj8zUcERERUUFQuwC6du0aGjdunKPd0tISz549y49MRERERAVK7QLIzs4OsbGxOdpPnDgBV1fXfAlFREREVJDULoAGDBiAH374AWfOnIFCocB///2HTZs2YeTIkfj2228LIiMRERFRvlL7UhhjxoxBVlYWmjVrhrS0NDRu3BiGhoYYOXIkvv/++4LISERERJSv1C6AFAoFxo8fj1GjRiE2NhYpKSmoUqUKzMzMCiIfERERUb5T+xTY//73P6SlpcHAwABVqlRB7dq1WfwQERGRRlG7ABo+fDhsbGzw5ZdfYt++fcjMzCyIXEREREQFRu0C6P79+9iyZQsUCgW6du0Ke3t7DB48GKdOnVL7yY8dO4a2bdvCwcEBCoUCoaGhH3zM0aNHUbNmTRgaGqJ8+fJYt25djnWWLFkCZ2dnGBkZoU6dOjh79qza2YiIiKj4UrsA0tPTQ5s2bbBp0yY8ePAACxYswO3bt+Hj4wM3Nze1tpWamgpPT08sWbJEpfXj4uLQunVr+Pj4ICYmBsOGDUP//v2xf/9+aZ2QkBAEBgZi4sSJiI6OhqenJ/z8/PDgwQO1shEREVHxpXYn6LeZmJjAz88PT58+xZ07d3DlyhW1Hu/v7w9/f3+V11+2bBlcXFwwb948AEDlypVx4sQJLFiwAH5+fgCA+fPnY8CAAejbt6/0mL1792LNmjUYM2aMWvmIiIioePqoi6GmpaVh06ZNaNWqFcqUKYPg4GB07NgRly5dyu98SiIjI+Hr66vU5ufnh8jISABARkYGzp8/r7SOjo4OfH19pXVyk56ejuTkZKUbERERFV9qHwHq3r07/vjjD5iYmKBr166YMGEC6tWrVxDZckhISICtra1Sm62tLZKTk/HixQs8ffoUmZmZua5z9erVPLc7c+ZMTJ48uUAyExERUdGjdgGkq6uLrVu3ws/PD7q6ugWRqdCNHTsWgYGB0v3k5GQ4OjrKmIiIiIgKktoF0KZNmwoih0rs7OyQmJio1JaYmAgLCwsYGxtDV1cXurq6ua5jZ2eX53YNDQ1haGhYIJmJiIio6FGpAFq0aBEGDhwIIyMjLFq06L3rDh06NF+C5aZevXrYt2+fUtvBgwelU3AGBgbw9vZGeHg4OnToAADIyspCeHg4hgwZUmC5iIiISLOoVAAtWLAAPXv2hJGRERYsWJDnegqFQq0CKCUlRenK8nFxcYiJiUGJEiVQrlw5jB07Fvfu3cOGDRsAAIMGDcLixYsxevRo9OvXD4cPH8bWrVuxd+9eaRuBgYHo3bs3atWqhdq1ayM4OBipqanSqDAiIiIilQqguLi4XP//qc6dOwcfHx/pfnY/nN69e2PdunW4f/8+4uPjpeUuLi7Yu3cvhg8fjoULF6Js2bJYtWqVNAQeALp164aHDx8iKCgICQkJ8PLyQlhYWI6O0URERKS9FEIIoc4DpkyZgpEjR8LExESp/cWLF5g7dy6CgoLyNaAckpOTYWlpiaSkJFhYWKj0GOcxez+80ie6Pat1gT8HERGRplLn77fa8wBNnjwZKSkpOdrT0tI4lJyIiIg0gtoFkBACCoUiR/uFCxdQokSJfAlFREREVJBUHgZvbW0NhUIBhUKBChUqKBVBmZmZSElJwaBBgwokJBEREVF+UrkACg4OhhAC/fr1w+TJk2FpaSktMzAwgLOzc6HNCE1ERET0KVQugHr37g3gzUis+vXrQ19fv8BCERERERUklQqg5ORkqTd1jRo18OLFC7x48SLXdVUdNUVEREQkF5UKIGtra9y/fx82NjawsrLKtRN0dufozMzMfA9JRERElJ9UKoAOHz4sjfA6cuRIgQYiIiIiKmgqFUBNmjTJ9f9EREREmkjteYDCwsJw4sQJ6f6SJUvg5eWFL7/8Ek+fPs3XcEREREQFQe0CaNSoUUhOTgYAXLx4EYGBgWjVqhXi4uKka3kRERERFWUqD4PPFhcXhypVqgAAduzYgbZt22LGjBmIjo5Gq1at8j0gERERUX5T+wiQgYEB0tLSAACHDh1CixYtAAAlSpSQjgwRERERFWVqHwFq2LAhAgMD0aBBA5w9exYhISEAgOvXr6Ns2bL5HpCIiIgov6l9BGjx4sXQ09PD9u3bsXTpUpQpUwYA8Oeff6Jly5b5HpCIiIgov6l9BKhcuXL4448/crQvWLAgXwIRERERFTS1CyDgzdXfQ0NDceXKFQBA1apV0a5dO+jq6uZrOCIiIqKCoHYBFBsbi1atWuHevXuoWLEiAGDmzJlwdHTE3r174ebmlu8hiYiIiPKT2n2Ahg4dCjc3N9y9exfR0dGIjo5GfHw8XFxcMHTo0ILISERERJSv1D4CFBERgdOnT0vXBgOAkiVLYtasWWjQoEG+hiMiIiIqCGofATI0NMTz589ztKekpMDAwCBfQhEREREVJLULoDZt2mDgwIE4c+YMhBAQQuD06dMYNGgQ2rVrVxAZiYiIiPKV2gXQokWL4Obmhnr16sHIyAhGRkZo0KABypcvj4ULFxZERiIiIqJ8pXYfICsrK+zevRuxsbHSMPjKlSujfPny+R6OiIiIqCCoXABlZWVh7ty52LNnDzIyMtCsWTNMnDgRxsbGBZmPiIiIKN+pfAps+vTpGDduHMzMzFCmTBksXLgQgwcPLshsRERERAVC5QJow4YN+PXXX7F//36Ehobi999/x6ZNm5CVlVWQ+YiIiIjyncoFUHx8PFq1aiXd9/X1hUKhwH///VcgwYiIiIgKisoF0OvXr2FkZKTUpq+vj1evXuV7KCIiIqKCpHInaCEE+vTpA0NDQ6nt5cuXGDRoEExNTaW2nTt35m9CIiIionymcgHUu3fvHG1fffVVvoYhIiIiKgwqF0Br164tyBxEREREhUbtmaCJiIiINB0LICIiItI6LICIiIhI67AAIiIiIq3DAoiIiIi0jkqjwPbs2aPyBtu1a6d2iCVLlmDu3LlISEiAp6cnfvnlF9SuXTvXdZs2bYqIiIgc7a1atcLevXsBAH369MH69euVlvv5+SEsLEztbERERFT8qFQAdejQQaWNKRQKZGZmqhUgJCQEgYGBWLZsGerUqYPg4GD4+fnh2rVrsLGxybH+zp07kZGRId1//PgxPD090aVLF6X1WrZsqTR0/+0JHImIiEi7qXQKLCsrS6WbusUPAMyfPx8DBgxA3759UaVKFSxbtgwmJiZYs2ZNruuXKFECdnZ20u3gwYMwMTHJUQAZGhoqrWdtba12NiIiIiqeZO0DlJGRgfPnz8PX11dq09HRga+vLyIjI1XaxurVq9G9e3ely3EAwNGjR2FjY4OKFSvi22+/xePHj/PcRnp6OpKTk5VuREREVHypPBP021JTUxEREYH4+Hil01EAMHToUJW38+jRI2RmZsLW1lap3dbWFlevXv3g48+ePYt//vkHq1evVmpv2bIlOnXqBBcXF9y8eRPjxo2Dv78/IiMjoaurm2M7M2fOxOTJk1XOTURERJpN7QLor7/+QqtWrZCWlobU1FSUKFECjx49gomJCWxsbNQqgD7V6tWrUb169Rwdprt37y79v3r16vDw8ICbmxuOHj2KZs2a5djO2LFjERgYKN1PTk6Go6NjwQUnIiIiWal9Cmz48OFo27Ytnj59CmNjY5w+fRp37tyBt7c3fv75Z7W2VapUKejq6iIxMVGpPTExEXZ2du99bGpqKrZs2YKvv/76g8/j6uqKUqVKITY2NtflhoaGsLCwULoRERFR8aV2ARQTE4MRI0ZAR0cHurq6SE9Ph6OjI+bMmYNx48aptS0DAwN4e3sjPDxcasvKykJ4eDjq1av33sdu27YN6enpKl2R/t9//8Xjx49hb2+vVj4iIiIqntQugPT19aGj8+ZhNjY2iI+PBwBYWlri7t27agcIDAzEypUrsX79ely5cgXffvstUlNT0bdvXwBAQEAAxo4dm+Nxq1evRocOHVCyZEml9pSUFIwaNQqnT5/G7du3ER4ejvbt26N8+fLw8/NTOx8REREVP2r3AapRowaioqLg7u6OJk2aICgoCI8ePcLGjRtRrVo1tQN069YNDx8+RFBQEBISEuDl5YWwsDCpY3R8fLxUcGW7du0aTpw4gQMHDuTYnq6uLv7++2+sX78ez549g4ODA1q0aIGpU6dyLiAiIiICACiEEEKdB5w7dw7Pnz+Hj48PHjx4gICAAJw6dQru7u5YvXo1vLy8Cihq4UlOToalpSWSkpJU7g/kPGZvAacCbs9qXeDPQUREpKnU+fut9hGgWrVqSf+3sbHh5SWIiIhI46jdB+jzzz/Hs2fPcrQnJyfj888/z49MRERERAVK7QLo6NGjOSY/BICXL1/i+PHj+RKKiIiIqCCpfArs77//lv5/+fJlJCQkSPczMzMRFhaGMmXK5G86IiIiogKgcgHk5eUFhUIBhUKR66kuY2Nj/PLLL/kajoiIiKggqFwAxcXFQQgBV1dXnD17FqVLl5aWGRgYwMbGJtfrbBEREREVNSoXQE5OTgDezNRMREREpMk+6mrwN2/eRHBwMK5cuQIAqFKlCn744Qe4ubnlazgiIiKigqD2KLD9+/ejSpUqOHv2LDw8PODh4YEzZ86gatWqOHjwYEFkJCIiIspXah8BGjNmDIYPH45Zs2blaP/xxx/RvHnzfAtHREREVBDUPgJ05coVfP311zna+/Xrh8uXL+dLKCIiIqKCpHYBVLp0acTExORoj4mJgY2NTX5kIiIiIipQKp8CmzJlCkaOHIkBAwZg4MCBuHXrFurXrw8AOHnyJGbPno3AwMACC0pERESUX1S+Gryuri7u37+P0qVLIzg4GPPmzcN///0HAHBwcMCoUaMwdOhQKBSKAg1cGHg1eCIiIs1TIFeDz66TFAoFhg8fjuHDh+P58+cAAHNz80+IS0RERFS41BoF9u7RHRY+REREpInUKoAqVKjwwVNcT548+aRARERERAVNrQJo8uTJsLS0LKgsRERERIVCrQKoe/fuHOpOREREGk/leYCKw+guIiIiIkCNAkjF0fJERERERZ7Kp8CysrIKMgcRERFRoVH7UhhEREREmo4FEBEREWkdFkBERESkdVgAERERkdZhAURERERahwUQERERaR0WQERERKR1WAARERGR1mEBRERERFqHBRARERFpHRZAREREpHVYABEREZHWYQFEREREWocFEBEREWkdFkBERESkdYpEAbRkyRI4OzvDyMgIderUwdmzZ/Ncd926dVAoFEo3IyMjpXWEEAgKCoK9vT2MjY3h6+uLGzduFPRuEBERkYaQvQAKCQlBYGAgJk6ciOjoaHh6esLPzw8PHjzI8zEWFha4f/++dLtz547S8jlz5mDRokVYtmwZzpw5A1NTU/j5+eHly5cFvTtERESkAWQvgObPn48BAwagb9++qFKlCpYtWwYTExOsWbMmz8coFArY2dlJN1tbW2mZEALBwcH46aef0L59e3h4eGDDhg3477//EBoaWgh7REREREWdrAVQRkYGzp8/D19fX6lNR0cHvr6+iIyMzPNxKSkpcHJygqOjI9q3b49Lly5Jy+Li4pCQkKC0TUtLS9SpUyfPbaanpyM5OVnpRkRERMWXrAXQo0ePkJmZqXQEBwBsbW2RkJCQ62MqVqyINWvWYPfu3fjf//6HrKws1K9fH//++y8ASI9TZ5szZ86EpaWldHN0dPzUXSMiIqIiTPZTYOqqV68eAgIC4OXlhSZNmmDnzp0oXbo0li9f/tHbHDt2LJKSkqTb3bt38zExERERFTWy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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "df_total_positive_cases.head(10).plot(x='Country', y='Total Positive Cases', kind='bar')\n", - "plt.xlabel('Country')\n", - "plt.ylabel('Total Positive Cases')\n", - "plt.title('Top Ten Countries with the Most Positive Cases')\n", - "plt.show()\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.10" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/completesolution/dataengineer/PROMPTS.md b/completesolution/dataengineer/PROMPTS.md deleted file mode 100644 index 5d0f25bf..00000000 --- a/completesolution/dataengineer/PROMPTS.md +++ /dev/null @@ -1,121 +0,0 @@ -# Exercises tips and tricks - -## 1. Understanding the Data - -### 1.1 Import data and show first 5 rows of the dataframe - -Chat prompt: @workspace /newNotebook create a notebook called "COVID19 Worldwide Testing Data" that imports the tested_worldwide.csv at root level and display the first 5 rows - -NOTE: In case you get an error related to "pandas library not found", use copilot to help you fixing it: - -![Pandas error fixed by copilot](images/pandaserror.png) - -### 1.2 Display the number of rows and columns in the dataframe. - -![Display the number of rows and columns in the dataframet](images/1_2.png) - -### 1.3 Display the data types of each column - -![Display the data types of each column](images/1_3.png) - -### 1.4 Display the number of missing values in each column - -![Display the number of missing values in each column](images/1_4.png) - -### 1.5 Display the number of unique values in each column - -![Display the number of unique values in each column](images/1_5.png) - -## 2. Data Cleaning - -### 2.1 Drop the columns that are not needed for the analysis - -![Drop the columns that are not needed for the analysis](images/2_1.png) - -### 2.2 Rename the columns to make them more readable - -![Rename the columns to make them more readable](images/2_2.png) - -### 2.3 Drop the rows that have missing values - -![Drop the rows that have missing values](images/2_3.png) - -### 2.4 Convert the data types of the columns to the appropriate types - -![Convert the data types of the columns to the appropriate types](images/2_4.png) - -Notice that I have first used the chat, then copilot inline to complete the coversion for the column "Country". - -### 2.5 Display the number of missing values in each column - -![Display the number of missing values in each column](images/2_5.png) - -## 3. Extracting the Top Ten Countries with Most Covid-19 Cases - -### 3.1 Create a new dataframe that contains the total number of positive cases for each country - -![Create a new dataframe that contains the total number of positive cases for each country](images/3_1.png) - -### 3.2 Sort the dataframe in descending order of the total number of positive cases - -![Sort the dataframe in descending order of the total number of positive cases](images/3_2.png) - -### 3.3 Display the top ten countries with the most positive cases - -![Display the top ten countries with the most positive cases](images/3_3.png) - -## 4. Identifying the Highest Positive Against Tested Cases - -### 4.1 Create a new dataframe that contains the total number of tests conducted for each country - -![Create a new dataframe that contains the total number of tests conducted for each country](images/4_1.png) - -### 4.2 Sort the dataframe in descending order of the total number of tests conducted - -![Sort the dataframe in descending order of the total number of tests conducted](images/4_2.png) - -### 4.3 Display the top ten countries with the most tests conducted - -![Display the top ten countries with the most tests conducted](images/4_3.png) - -## 5. Identifying top three countries that have had the highest number of positive cases against the number of tests carried out - -### 5.1 Merge the two dataframes created in the previous steps - -![Merge the two dataframes created in the previous steps](images/5_1.png) - -### 5.2 Create a new column that contains the ratio of positive cases to the number of tests conducted - -![Create a new column that contains the ratio of positive cases to the number of tests conducted](images/5_2.png) - -### 5.3 Sort the dataframe in descending order of the ratio of positive cases to the number of tests conducted - -![Sort the dataframe in descending order of the ratio of positive cases to the number of tests conducted](images/5_3.png) - -### 5.4 Display the top three countries with the highest ratio of positive cases to the number of tests conducted - -![Display the top three countries with the highest ratio of positive cases to the number of tests conducted](images/5_4.png) - -## 6. Displaying the Results - -### 6.1 Display the results a chart that shows the top three countries with the highest ratio of positive cases to the number of tests conducted - -![Display the results a chart that shows the top three countries with the highest ratio of positive cases to the number of tests conducted](images/6_1.png) - -NOTE: In case you get an error related to "ImportError with matplotlib", use copilot inline to help you fixing it: - -![Import matplotlib](images/importmatplot.png) - -And then, if the module is not found, use copilot chat to help you fixing it: -![Module not found matplotlib](images/notfoundmatplotlib.png) - - -### 6.2 Display the results in a chart that shows the top ten countries with the most positive cases - -![Display the results in a chart that shows the top ten countries with the most positive cases](images/6_2.png) - -### 6.3 Display the results in a chart that shows the top ten countries with the most tests conducted - -![Display the results in a chart that shows the top ten countries with the most tests conducted](images/6_3.png) - - diff --git a/completesolution/dataengineer/images/1_2.png b/completesolution/dataengineer/images/1_2.png deleted file mode 100644 index fac8c0c9..00000000 Binary files a/completesolution/dataengineer/images/1_2.png and /dev/null differ diff --git a/completesolution/dataengineer/images/1_3.png b/completesolution/dataengineer/images/1_3.png deleted file mode 100644 index f9e75ea6..00000000 Binary files a/completesolution/dataengineer/images/1_3.png and /dev/null differ diff --git a/completesolution/dataengineer/images/1_4.png b/completesolution/dataengineer/images/1_4.png deleted file mode 100644 index f29617b5..00000000 Binary files a/completesolution/dataengineer/images/1_4.png and /dev/null differ diff --git a/completesolution/dataengineer/images/1_5.png b/completesolution/dataengineer/images/1_5.png deleted file mode 100644 index 65c6b038..00000000 Binary files a/completesolution/dataengineer/images/1_5.png and /dev/null differ diff --git a/completesolution/dataengineer/images/2_1.png b/completesolution/dataengineer/images/2_1.png deleted file mode 100644 index f25c29fe..00000000 Binary files a/completesolution/dataengineer/images/2_1.png and /dev/null differ diff --git a/completesolution/dataengineer/images/2_2.png b/completesolution/dataengineer/images/2_2.png deleted file mode 100644 index 6e647225..00000000 Binary files a/completesolution/dataengineer/images/2_2.png and /dev/null differ diff --git a/completesolution/dataengineer/images/2_3.png b/completesolution/dataengineer/images/2_3.png deleted file mode 100644 index 85ececee..00000000 Binary files a/completesolution/dataengineer/images/2_3.png and /dev/null differ diff --git a/completesolution/dataengineer/images/2_4.png b/completesolution/dataengineer/images/2_4.png deleted file mode 100644 index 44db685e..00000000 Binary files a/completesolution/dataengineer/images/2_4.png and /dev/null differ diff --git a/completesolution/dataengineer/images/2_5.png b/completesolution/dataengineer/images/2_5.png deleted file mode 100644 index 15ca0a75..00000000 Binary files a/completesolution/dataengineer/images/2_5.png and /dev/null differ diff --git a/completesolution/dataengineer/images/3_1.png b/completesolution/dataengineer/images/3_1.png deleted file mode 100644 index 900c3a95..00000000 Binary files a/completesolution/dataengineer/images/3_1.png and /dev/null differ diff --git a/completesolution/dataengineer/images/3_2.png b/completesolution/dataengineer/images/3_2.png deleted file mode 100644 index 232b59f6..00000000 Binary files a/completesolution/dataengineer/images/3_2.png and /dev/null differ diff --git a/completesolution/dataengineer/images/3_3.png b/completesolution/dataengineer/images/3_3.png deleted file mode 100644 index affd86d1..00000000 Binary files a/completesolution/dataengineer/images/3_3.png and /dev/null differ diff --git a/completesolution/dataengineer/images/4_1.png b/completesolution/dataengineer/images/4_1.png deleted file mode 100644 index 236b6d53..00000000 Binary files a/completesolution/dataengineer/images/4_1.png and /dev/null differ diff --git a/completesolution/dataengineer/images/4_2.png b/completesolution/dataengineer/images/4_2.png deleted file mode 100644 index 1ba365df..00000000 Binary files a/completesolution/dataengineer/images/4_2.png and /dev/null differ diff --git a/completesolution/dataengineer/images/4_3.png b/completesolution/dataengineer/images/4_3.png deleted file mode 100644 index 402ef4a4..00000000 Binary files a/completesolution/dataengineer/images/4_3.png and /dev/null differ diff --git a/completesolution/dataengineer/images/5_1.png b/completesolution/dataengineer/images/5_1.png deleted file mode 100644 index c3dd18d8..00000000 Binary files a/completesolution/dataengineer/images/5_1.png and /dev/null differ diff --git a/completesolution/dataengineer/images/5_2.png b/completesolution/dataengineer/images/5_2.png deleted file mode 100644 index 41b4bbde..00000000 Binary files a/completesolution/dataengineer/images/5_2.png and /dev/null differ diff --git a/completesolution/dataengineer/images/5_3.png b/completesolution/dataengineer/images/5_3.png deleted file mode 100644 index 107913d2..00000000 Binary files a/completesolution/dataengineer/images/5_3.png and /dev/null differ diff --git a/completesolution/dataengineer/images/5_4.png b/completesolution/dataengineer/images/5_4.png deleted file mode 100644 index 9e949b21..00000000 Binary files a/completesolution/dataengineer/images/5_4.png and /dev/null differ diff --git a/completesolution/dataengineer/images/6_1.png b/completesolution/dataengineer/images/6_1.png deleted file mode 100644 index 6f247644..00000000 Binary files a/completesolution/dataengineer/images/6_1.png and /dev/null differ diff --git a/completesolution/dataengineer/images/6_2.png b/completesolution/dataengineer/images/6_2.png deleted file mode 100644 index b72ed758..00000000 Binary files a/completesolution/dataengineer/images/6_2.png and /dev/null differ diff --git a/completesolution/dataengineer/images/6_3.png b/completesolution/dataengineer/images/6_3.png deleted file mode 100644 index e501fedf..00000000 Binary files a/completesolution/dataengineer/images/6_3.png and /dev/null differ diff --git a/completesolution/dataengineer/images/importmatplot.png b/completesolution/dataengineer/images/importmatplot.png deleted file mode 100644 index 3002957e..00000000 Binary files a/completesolution/dataengineer/images/importmatplot.png and /dev/null differ diff --git a/completesolution/dataengineer/images/notfoundmatplotlib.png b/completesolution/dataengineer/images/notfoundmatplotlib.png deleted file mode 100644 index af26c95c..00000000 Binary files a/completesolution/dataengineer/images/notfoundmatplotlib.png and /dev/null differ diff --git a/completesolution/dataengineer/images/pandaserror.png b/completesolution/dataengineer/images/pandaserror.png deleted file mode 100644 index cd010c62..00000000 Binary files a/completesolution/dataengineer/images/pandaserror.png and /dev/null differ diff --git a/completesolution/datascientist/diabetes.csv b/completesolution/datascientist/diabetes.csv deleted file mode 100644 index dcaf5fe8..00000000 --- a/completesolution/datascientist/diabetes.csv +++ /dev/null @@ -1,769 +0,0 @@ -Pregnancies,Glucose,BloodPressure,SkinThickness,Insulin,BMI,DiabetesPedigreeFunction,Age,Outcome -6,148,72,35,0,33.6,0.627,50,1 -1,85,66,29,0,26.6,0.351,31,0 -8,183,64,0,0,23.3,0.672,32,1 -1,89,66,23,94,28.1,0.167,21,0 -0,137,40,35,168,43.1,2.288,33,1 -5,116,74,0,0,25.6,0.201,30,0 -3,78,50,32,88,31,0.248,26,1 -10,115,0,0,0,35.3,0.134,29,0 -2,197,70,45,543,30.5,0.158,53,1 -8,125,96,0,0,0,0.232,54,1 -4,110,92,0,0,37.6,0.191,30,0 -10,168,74,0,0,38,0.537,34,1 -10,139,80,0,0,27.1,1.441,57,0 -1,189,60,23,846,30.1,0.398,59,1 -5,166,72,19,175,25.8,0.587,51,1 -7,100,0,0,0,30,0.484,32,1 -0,118,84,47,230,45.8,0.551,31,1 -7,107,74,0,0,29.6,0.254,31,1 -1,103,30,38,83,43.3,0.183,33,0 -1,115,70,30,96,34.6,0.529,32,1 -3,126,88,41,235,39.3,0.704,27,0 -8,99,84,0,0,35.4,0.388,50,0 -7,196,90,0,0,39.8,0.451,41,1 -9,119,80,35,0,29,0.263,29,1 -11,143,94,33,146,36.6,0.254,51,1 -10,125,70,26,115,31.1,0.205,41,1 -7,147,76,0,0,39.4,0.257,43,1 -1,97,66,15,140,23.2,0.487,22,0 -13,145,82,19,110,22.2,0.245,57,0 -5,117,92,0,0,34.1,0.337,38,0 -5,109,75,26,0,36,0.546,60,0 -3,158,76,36,245,31.6,0.851,28,1 -3,88,58,11,54,24.8,0.267,22,0 -6,92,92,0,0,19.9,0.188,28,0 -10,122,78,31,0,27.6,0.512,45,0 -4,103,60,33,192,24,0.966,33,0 -11,138,76,0,0,33.2,0.42,35,0 -9,102,76,37,0,32.9,0.665,46,1 -2,90,68,42,0,38.2,0.503,27,1 -4,111,72,47,207,37.1,1.39,56,1 -3,180,64,25,70,34,0.271,26,0 -7,133,84,0,0,40.2,0.696,37,0 -7,106,92,18,0,22.7,0.235,48,0 -9,171,110,24,240,45.4,0.721,54,1 -7,159,64,0,0,27.4,0.294,40,0 -0,180,66,39,0,42,1.893,25,1 -1,146,56,0,0,29.7,0.564,29,0 -2,71,70,27,0,28,0.586,22,0 -7,103,66,32,0,39.1,0.344,31,1 -7,105,0,0,0,0,0.305,24,0 -1,103,80,11,82,19.4,0.491,22,0 -1,101,50,15,36,24.2,0.526,26,0 -5,88,66,21,23,24.4,0.342,30,0 -8,176,90,34,300,33.7,0.467,58,1 -7,150,66,42,342,34.7,0.718,42,0 -1,73,50,10,0,23,0.248,21,0 -7,187,68,39,304,37.7,0.254,41,1 -0,100,88,60,110,46.8,0.962,31,0 -0,146,82,0,0,40.5,1.781,44,0 -0,105,64,41,142,41.5,0.173,22,0 -2,84,0,0,0,0,0.304,21,0 -8,133,72,0,0,32.9,0.27,39,1 -5,44,62,0,0,25,0.587,36,0 -2,141,58,34,128,25.4,0.699,24,0 -7,114,66,0,0,32.8,0.258,42,1 -5,99,74,27,0,29,0.203,32,0 -0,109,88,30,0,32.5,0.855,38,1 -2,109,92,0,0,42.7,0.845,54,0 -1,95,66,13,38,19.6,0.334,25,0 -4,146,85,27,100,28.9,0.189,27,0 -2,100,66,20,90,32.9,0.867,28,1 -5,139,64,35,140,28.6,0.411,26,0 -13,126,90,0,0,43.4,0.583,42,1 -4,129,86,20,270,35.1,0.231,23,0 -1,79,75,30,0,32,0.396,22,0 -1,0,48,20,0,24.7,0.14,22,0 -7,62,78,0,0,32.6,0.391,41,0 -5,95,72,33,0,37.7,0.37,27,0 -0,131,0,0,0,43.2,0.27,26,1 -2,112,66,22,0,25,0.307,24,0 -3,113,44,13,0,22.4,0.14,22,0 -2,74,0,0,0,0,0.102,22,0 -7,83,78,26,71,29.3,0.767,36,0 -0,101,65,28,0,24.6,0.237,22,0 -5,137,108,0,0,48.8,0.227,37,1 -2,110,74,29,125,32.4,0.698,27,0 -13,106,72,54,0,36.6,0.178,45,0 -2,100,68,25,71,38.5,0.324,26,0 -15,136,70,32,110,37.1,0.153,43,1 -1,107,68,19,0,26.5,0.165,24,0 -1,80,55,0,0,19.1,0.258,21,0 -4,123,80,15,176,32,0.443,34,0 -7,81,78,40,48,46.7,0.261,42,0 -4,134,72,0,0,23.8,0.277,60,1 -2,142,82,18,64,24.7,0.761,21,0 -6,144,72,27,228,33.9,0.255,40,0 -2,92,62,28,0,31.6,0.13,24,0 -1,71,48,18,76,20.4,0.323,22,0 -6,93,50,30,64,28.7,0.356,23,0 -1,122,90,51,220,49.7,0.325,31,1 -1,163,72,0,0,39,1.222,33,1 -1,151,60,0,0,26.1,0.179,22,0 -0,125,96,0,0,22.5,0.262,21,0 -1,81,72,18,40,26.6,0.283,24,0 -2,85,65,0,0,39.6,0.93,27,0 -1,126,56,29,152,28.7,0.801,21,0 -1,96,122,0,0,22.4,0.207,27,0 -4,144,58,28,140,29.5,0.287,37,0 -3,83,58,31,18,34.3,0.336,25,0 -0,95,85,25,36,37.4,0.247,24,1 -3,171,72,33,135,33.3,0.199,24,1 -8,155,62,26,495,34,0.543,46,1 -1,89,76,34,37,31.2,0.192,23,0 -4,76,62,0,0,34,0.391,25,0 -7,160,54,32,175,30.5,0.588,39,1 -4,146,92,0,0,31.2,0.539,61,1 -5,124,74,0,0,34,0.22,38,1 -5,78,48,0,0,33.7,0.654,25,0 -4,97,60,23,0,28.2,0.443,22,0 -4,99,76,15,51,23.2,0.223,21,0 -0,162,76,56,100,53.2,0.759,25,1 -6,111,64,39,0,34.2,0.26,24,0 -2,107,74,30,100,33.6,0.404,23,0 -5,132,80,0,0,26.8,0.186,69,0 -0,113,76,0,0,33.3,0.278,23,1 -1,88,30,42,99,55,0.496,26,1 -3,120,70,30,135,42.9,0.452,30,0 -1,118,58,36,94,33.3,0.261,23,0 -1,117,88,24,145,34.5,0.403,40,1 -0,105,84,0,0,27.9,0.741,62,1 -4,173,70,14,168,29.7,0.361,33,1 -9,122,56,0,0,33.3,1.114,33,1 -3,170,64,37,225,34.5,0.356,30,1 -8,84,74,31,0,38.3,0.457,39,0 -2,96,68,13,49,21.1,0.647,26,0 -2,125,60,20,140,33.8,0.088,31,0 -0,100,70,26,50,30.8,0.597,21,0 -0,93,60,25,92,28.7,0.532,22,0 -0,129,80,0,0,31.2,0.703,29,0 -5,105,72,29,325,36.9,0.159,28,0 -3,128,78,0,0,21.1,0.268,55,0 -5,106,82,30,0,39.5,0.286,38,0 -2,108,52,26,63,32.5,0.318,22,0 -10,108,66,0,0,32.4,0.272,42,1 -4,154,62,31,284,32.8,0.237,23,0 -0,102,75,23,0,0,0.572,21,0 -9,57,80,37,0,32.8,0.096,41,0 -2,106,64,35,119,30.5,1.4,34,0 -5,147,78,0,0,33.7,0.218,65,0 -2,90,70,17,0,27.3,0.085,22,0 -1,136,74,50,204,37.4,0.399,24,0 -4,114,65,0,0,21.9,0.432,37,0 -9,156,86,28,155,34.3,1.189,42,1 -1,153,82,42,485,40.6,0.687,23,0 -8,188,78,0,0,47.9,0.137,43,1 -7,152,88,44,0,50,0.337,36,1 -2,99,52,15,94,24.6,0.637,21,0 -1,109,56,21,135,25.2,0.833,23,0 -2,88,74,19,53,29,0.229,22,0 -17,163,72,41,114,40.9,0.817,47,1 -4,151,90,38,0,29.7,0.294,36,0 -7,102,74,40,105,37.2,0.204,45,0 -0,114,80,34,285,44.2,0.167,27,0 -2,100,64,23,0,29.7,0.368,21,0 -0,131,88,0,0,31.6,0.743,32,1 -6,104,74,18,156,29.9,0.722,41,1 -3,148,66,25,0,32.5,0.256,22,0 -4,120,68,0,0,29.6,0.709,34,0 -4,110,66,0,0,31.9,0.471,29,0 -3,111,90,12,78,28.4,0.495,29,0 -6,102,82,0,0,30.8,0.18,36,1 -6,134,70,23,130,35.4,0.542,29,1 -2,87,0,23,0,28.9,0.773,25,0 -1,79,60,42,48,43.5,0.678,23,0 -2,75,64,24,55,29.7,0.37,33,0 -8,179,72,42,130,32.7,0.719,36,1 -6,85,78,0,0,31.2,0.382,42,0 -0,129,110,46,130,67.1,0.319,26,1 -5,143,78,0,0,45,0.19,47,0 -5,130,82,0,0,39.1,0.956,37,1 -6,87,80,0,0,23.2,0.084,32,0 -0,119,64,18,92,34.9,0.725,23,0 -1,0,74,20,23,27.7,0.299,21,0 -5,73,60,0,0,26.8,0.268,27,0 -4,141,74,0,0,27.6,0.244,40,0 -7,194,68,28,0,35.9,0.745,41,1 -8,181,68,36,495,30.1,0.615,60,1 -1,128,98,41,58,32,1.321,33,1 -8,109,76,39,114,27.9,0.64,31,1 -5,139,80,35,160,31.6,0.361,25,1 -3,111,62,0,0,22.6,0.142,21,0 -9,123,70,44,94,33.1,0.374,40,0 -7,159,66,0,0,30.4,0.383,36,1 -11,135,0,0,0,52.3,0.578,40,1 -8,85,55,20,0,24.4,0.136,42,0 -5,158,84,41,210,39.4,0.395,29,1 -1,105,58,0,0,24.3,0.187,21,0 -3,107,62,13,48,22.9,0.678,23,1 -4,109,64,44,99,34.8,0.905,26,1 -4,148,60,27,318,30.9,0.15,29,1 -0,113,80,16,0,31,0.874,21,0 -1,138,82,0,0,40.1,0.236,28,0 -0,108,68,20,0,27.3,0.787,32,0 -2,99,70,16,44,20.4,0.235,27,0 -6,103,72,32,190,37.7,0.324,55,0 -5,111,72,28,0,23.9,0.407,27,0 -8,196,76,29,280,37.5,0.605,57,1 -5,162,104,0,0,37.7,0.151,52,1 -1,96,64,27,87,33.2,0.289,21,0 -7,184,84,33,0,35.5,0.355,41,1 -2,81,60,22,0,27.7,0.29,25,0 -0,147,85,54,0,42.8,0.375,24,0 -7,179,95,31,0,34.2,0.164,60,0 -0,140,65,26,130,42.6,0.431,24,1 -9,112,82,32,175,34.2,0.26,36,1 -12,151,70,40,271,41.8,0.742,38,1 -5,109,62,41,129,35.8,0.514,25,1 -6,125,68,30,120,30,0.464,32,0 -5,85,74,22,0,29,1.224,32,1 -5,112,66,0,0,37.8,0.261,41,1 -0,177,60,29,478,34.6,1.072,21,1 -2,158,90,0,0,31.6,0.805,66,1 -7,119,0,0,0,25.2,0.209,37,0 -7,142,60,33,190,28.8,0.687,61,0 -1,100,66,15,56,23.6,0.666,26,0 -1,87,78,27,32,34.6,0.101,22,0 -0,101,76,0,0,35.7,0.198,26,0 -3,162,52,38,0,37.2,0.652,24,1 -4,197,70,39,744,36.7,2.329,31,0 -0,117,80,31,53,45.2,0.089,24,0 -4,142,86,0,0,44,0.645,22,1 -6,134,80,37,370,46.2,0.238,46,1 -1,79,80,25,37,25.4,0.583,22,0 -4,122,68,0,0,35,0.394,29,0 -3,74,68,28,45,29.7,0.293,23,0 -4,171,72,0,0,43.6,0.479,26,1 -7,181,84,21,192,35.9,0.586,51,1 -0,179,90,27,0,44.1,0.686,23,1 -9,164,84,21,0,30.8,0.831,32,1 -0,104,76,0,0,18.4,0.582,27,0 -1,91,64,24,0,29.2,0.192,21,0 -4,91,70,32,88,33.1,0.446,22,0 -3,139,54,0,0,25.6,0.402,22,1 -6,119,50,22,176,27.1,1.318,33,1 -2,146,76,35,194,38.2,0.329,29,0 -9,184,85,15,0,30,1.213,49,1 -10,122,68,0,0,31.2,0.258,41,0 -0,165,90,33,680,52.3,0.427,23,0 -9,124,70,33,402,35.4,0.282,34,0 -1,111,86,19,0,30.1,0.143,23,0 -9,106,52,0,0,31.2,0.38,42,0 -2,129,84,0,0,28,0.284,27,0 -2,90,80,14,55,24.4,0.249,24,0 -0,86,68,32,0,35.8,0.238,25,0 -12,92,62,7,258,27.6,0.926,44,1 -1,113,64,35,0,33.6,0.543,21,1 -3,111,56,39,0,30.1,0.557,30,0 -2,114,68,22,0,28.7,0.092,25,0 -1,193,50,16,375,25.9,0.655,24,0 -11,155,76,28,150,33.3,1.353,51,1 -3,191,68,15,130,30.9,0.299,34,0 -3,141,0,0,0,30,0.761,27,1 -4,95,70,32,0,32.1,0.612,24,0 -3,142,80,15,0,32.4,0.2,63,0 -4,123,62,0,0,32,0.226,35,1 -5,96,74,18,67,33.6,0.997,43,0 -0,138,0,0,0,36.3,0.933,25,1 -2,128,64,42,0,40,1.101,24,0 -0,102,52,0,0,25.1,0.078,21,0 -2,146,0,0,0,27.5,0.24,28,1 -10,101,86,37,0,45.6,1.136,38,1 -2,108,62,32,56,25.2,0.128,21,0 -3,122,78,0,0,23,0.254,40,0 -1,71,78,50,45,33.2,0.422,21,0 -13,106,70,0,0,34.2,0.251,52,0 -2,100,70,52,57,40.5,0.677,25,0 -7,106,60,24,0,26.5,0.296,29,1 -0,104,64,23,116,27.8,0.454,23,0 -5,114,74,0,0,24.9,0.744,57,0 -2,108,62,10,278,25.3,0.881,22,0 -0,146,70,0,0,37.9,0.334,28,1 -10,129,76,28,122,35.9,0.28,39,0 -7,133,88,15,155,32.4,0.262,37,0 -7,161,86,0,0,30.4,0.165,47,1 -2,108,80,0,0,27,0.259,52,1 -7,136,74,26,135,26,0.647,51,0 -5,155,84,44,545,38.7,0.619,34,0 -1,119,86,39,220,45.6,0.808,29,1 -4,96,56,17,49,20.8,0.34,26,0 -5,108,72,43,75,36.1,0.263,33,0 -0,78,88,29,40,36.9,0.434,21,0 -0,107,62,30,74,36.6,0.757,25,1 -2,128,78,37,182,43.3,1.224,31,1 -1,128,48,45,194,40.5,0.613,24,1 -0,161,50,0,0,21.9,0.254,65,0 -6,151,62,31,120,35.5,0.692,28,0 -2,146,70,38,360,28,0.337,29,1 -0,126,84,29,215,30.7,0.52,24,0 -14,100,78,25,184,36.6,0.412,46,1 -8,112,72,0,0,23.6,0.84,58,0 -0,167,0,0,0,32.3,0.839,30,1 -2,144,58,33,135,31.6,0.422,25,1 -5,77,82,41,42,35.8,0.156,35,0 -5,115,98,0,0,52.9,0.209,28,1 -3,150,76,0,0,21,0.207,37,0 -2,120,76,37,105,39.7,0.215,29,0 -10,161,68,23,132,25.5,0.326,47,1 -0,137,68,14,148,24.8,0.143,21,0 -0,128,68,19,180,30.5,1.391,25,1 -2,124,68,28,205,32.9,0.875,30,1 -6,80,66,30,0,26.2,0.313,41,0 -0,106,70,37,148,39.4,0.605,22,0 -2,155,74,17,96,26.6,0.433,27,1 -3,113,50,10,85,29.5,0.626,25,0 -7,109,80,31,0,35.9,1.127,43,1 -2,112,68,22,94,34.1,0.315,26,0 -3,99,80,11,64,19.3,0.284,30,0 -3,182,74,0,0,30.5,0.345,29,1 -3,115,66,39,140,38.1,0.15,28,0 -6,194,78,0,0,23.5,0.129,59,1 -4,129,60,12,231,27.5,0.527,31,0 -3,112,74,30,0,31.6,0.197,25,1 -0,124,70,20,0,27.4,0.254,36,1 -13,152,90,33,29,26.8,0.731,43,1 -2,112,75,32,0,35.7,0.148,21,0 -1,157,72,21,168,25.6,0.123,24,0 -1,122,64,32,156,35.1,0.692,30,1 -10,179,70,0,0,35.1,0.2,37,0 -2,102,86,36,120,45.5,0.127,23,1 -6,105,70,32,68,30.8,0.122,37,0 -8,118,72,19,0,23.1,1.476,46,0 -2,87,58,16,52,32.7,0.166,25,0 -1,180,0,0,0,43.3,0.282,41,1 -12,106,80,0,0,23.6,0.137,44,0 -1,95,60,18,58,23.9,0.26,22,0 -0,165,76,43,255,47.9,0.259,26,0 -0,117,0,0,0,33.8,0.932,44,0 -5,115,76,0,0,31.2,0.343,44,1 -9,152,78,34,171,34.2,0.893,33,1 -7,178,84,0,0,39.9,0.331,41,1 -1,130,70,13,105,25.9,0.472,22,0 -1,95,74,21,73,25.9,0.673,36,0 -1,0,68,35,0,32,0.389,22,0 -5,122,86,0,0,34.7,0.29,33,0 -8,95,72,0,0,36.8,0.485,57,0 -8,126,88,36,108,38.5,0.349,49,0 -1,139,46,19,83,28.7,0.654,22,0 -3,116,0,0,0,23.5,0.187,23,0 -3,99,62,19,74,21.8,0.279,26,0 -5,0,80,32,0,41,0.346,37,1 -4,92,80,0,0,42.2,0.237,29,0 -4,137,84,0,0,31.2,0.252,30,0 -3,61,82,28,0,34.4,0.243,46,0 -1,90,62,12,43,27.2,0.58,24,0 -3,90,78,0,0,42.7,0.559,21,0 -9,165,88,0,0,30.4,0.302,49,1 -1,125,50,40,167,33.3,0.962,28,1 -13,129,0,30,0,39.9,0.569,44,1 -12,88,74,40,54,35.3,0.378,48,0 -1,196,76,36,249,36.5,0.875,29,1 -5,189,64,33,325,31.2,0.583,29,1 -5,158,70,0,0,29.8,0.207,63,0 -5,103,108,37,0,39.2,0.305,65,0 -4,146,78,0,0,38.5,0.52,67,1 -4,147,74,25,293,34.9,0.385,30,0 -5,99,54,28,83,34,0.499,30,0 -6,124,72,0,0,27.6,0.368,29,1 -0,101,64,17,0,21,0.252,21,0 -3,81,86,16,66,27.5,0.306,22,0 -1,133,102,28,140,32.8,0.234,45,1 -3,173,82,48,465,38.4,2.137,25,1 -0,118,64,23,89,0,1.731,21,0 -0,84,64,22,66,35.8,0.545,21,0 -2,105,58,40,94,34.9,0.225,25,0 -2,122,52,43,158,36.2,0.816,28,0 -12,140,82,43,325,39.2,0.528,58,1 -0,98,82,15,84,25.2,0.299,22,0 -1,87,60,37,75,37.2,0.509,22,0 -4,156,75,0,0,48.3,0.238,32,1 -0,93,100,39,72,43.4,1.021,35,0 -1,107,72,30,82,30.8,0.821,24,0 -0,105,68,22,0,20,0.236,22,0 -1,109,60,8,182,25.4,0.947,21,0 -1,90,62,18,59,25.1,1.268,25,0 -1,125,70,24,110,24.3,0.221,25,0 -1,119,54,13,50,22.3,0.205,24,0 -5,116,74,29,0,32.3,0.66,35,1 -8,105,100,36,0,43.3,0.239,45,1 -5,144,82,26,285,32,0.452,58,1 -3,100,68,23,81,31.6,0.949,28,0 -1,100,66,29,196,32,0.444,42,0 -5,166,76,0,0,45.7,0.34,27,1 -1,131,64,14,415,23.7,0.389,21,0 -4,116,72,12,87,22.1,0.463,37,0 -4,158,78,0,0,32.9,0.803,31,1 -2,127,58,24,275,27.7,1.6,25,0 -3,96,56,34,115,24.7,0.944,39,0 -0,131,66,40,0,34.3,0.196,22,1 -3,82,70,0,0,21.1,0.389,25,0 -3,193,70,31,0,34.9,0.241,25,1 -4,95,64,0,0,32,0.161,31,1 -6,137,61,0,0,24.2,0.151,55,0 -5,136,84,41,88,35,0.286,35,1 -9,72,78,25,0,31.6,0.28,38,0 -5,168,64,0,0,32.9,0.135,41,1 -2,123,48,32,165,42.1,0.52,26,0 -4,115,72,0,0,28.9,0.376,46,1 -0,101,62,0,0,21.9,0.336,25,0 -8,197,74,0,0,25.9,1.191,39,1 -1,172,68,49,579,42.4,0.702,28,1 -6,102,90,39,0,35.7,0.674,28,0 -1,112,72,30,176,34.4,0.528,25,0 -1,143,84,23,310,42.4,1.076,22,0 -1,143,74,22,61,26.2,0.256,21,0 -0,138,60,35,167,34.6,0.534,21,1 -3,173,84,33,474,35.7,0.258,22,1 -1,97,68,21,0,27.2,1.095,22,0 -4,144,82,32,0,38.5,0.554,37,1 -1,83,68,0,0,18.2,0.624,27,0 -3,129,64,29,115,26.4,0.219,28,1 -1,119,88,41,170,45.3,0.507,26,0 -2,94,68,18,76,26,0.561,21,0 -0,102,64,46,78,40.6,0.496,21,0 -2,115,64,22,0,30.8,0.421,21,0 -8,151,78,32,210,42.9,0.516,36,1 -4,184,78,39,277,37,0.264,31,1 -0,94,0,0,0,0,0.256,25,0 -1,181,64,30,180,34.1,0.328,38,1 -0,135,94,46,145,40.6,0.284,26,0 -1,95,82,25,180,35,0.233,43,1 -2,99,0,0,0,22.2,0.108,23,0 -3,89,74,16,85,30.4,0.551,38,0 -1,80,74,11,60,30,0.527,22,0 -2,139,75,0,0,25.6,0.167,29,0 -1,90,68,8,0,24.5,1.138,36,0 -0,141,0,0,0,42.4,0.205,29,1 -12,140,85,33,0,37.4,0.244,41,0 -5,147,75,0,0,29.9,0.434,28,0 -1,97,70,15,0,18.2,0.147,21,0 -6,107,88,0,0,36.8,0.727,31,0 -0,189,104,25,0,34.3,0.435,41,1 -2,83,66,23,50,32.2,0.497,22,0 -4,117,64,27,120,33.2,0.23,24,0 -8,108,70,0,0,30.5,0.955,33,1 -4,117,62,12,0,29.7,0.38,30,1 -0,180,78,63,14,59.4,2.42,25,1 -1,100,72,12,70,25.3,0.658,28,0 -0,95,80,45,92,36.5,0.33,26,0 -0,104,64,37,64,33.6,0.51,22,1 -0,120,74,18,63,30.5,0.285,26,0 -1,82,64,13,95,21.2,0.415,23,0 -2,134,70,0,0,28.9,0.542,23,1 -0,91,68,32,210,39.9,0.381,25,0 -2,119,0,0,0,19.6,0.832,72,0 -2,100,54,28,105,37.8,0.498,24,0 -14,175,62,30,0,33.6,0.212,38,1 -1,135,54,0,0,26.7,0.687,62,0 -5,86,68,28,71,30.2,0.364,24,0 -10,148,84,48,237,37.6,1.001,51,1 -9,134,74,33,60,25.9,0.46,81,0 -9,120,72,22,56,20.8,0.733,48,0 -1,71,62,0,0,21.8,0.416,26,0 -8,74,70,40,49,35.3,0.705,39,0 -5,88,78,30,0,27.6,0.258,37,0 -10,115,98,0,0,24,1.022,34,0 -0,124,56,13,105,21.8,0.452,21,0 -0,74,52,10,36,27.8,0.269,22,0 -0,97,64,36,100,36.8,0.6,25,0 -8,120,0,0,0,30,0.183,38,1 -6,154,78,41,140,46.1,0.571,27,0 -1,144,82,40,0,41.3,0.607,28,0 -0,137,70,38,0,33.2,0.17,22,0 -0,119,66,27,0,38.8,0.259,22,0 -7,136,90,0,0,29.9,0.21,50,0 -4,114,64,0,0,28.9,0.126,24,0 -0,137,84,27,0,27.3,0.231,59,0 -2,105,80,45,191,33.7,0.711,29,1 -7,114,76,17,110,23.8,0.466,31,0 -8,126,74,38,75,25.9,0.162,39,0 -4,132,86,31,0,28,0.419,63,0 -3,158,70,30,328,35.5,0.344,35,1 -0,123,88,37,0,35.2,0.197,29,0 -4,85,58,22,49,27.8,0.306,28,0 -0,84,82,31,125,38.2,0.233,23,0 -0,145,0,0,0,44.2,0.63,31,1 -0,135,68,42,250,42.3,0.365,24,1 -1,139,62,41,480,40.7,0.536,21,0 -0,173,78,32,265,46.5,1.159,58,0 -4,99,72,17,0,25.6,0.294,28,0 -8,194,80,0,0,26.1,0.551,67,0 -2,83,65,28,66,36.8,0.629,24,0 -2,89,90,30,0,33.5,0.292,42,0 -4,99,68,38,0,32.8,0.145,33,0 -4,125,70,18,122,28.9,1.144,45,1 -3,80,0,0,0,0,0.174,22,0 -6,166,74,0,0,26.6,0.304,66,0 -5,110,68,0,0,26,0.292,30,0 -2,81,72,15,76,30.1,0.547,25,0 -7,195,70,33,145,25.1,0.163,55,1 -6,154,74,32,193,29.3,0.839,39,0 -2,117,90,19,71,25.2,0.313,21,0 -3,84,72,32,0,37.2,0.267,28,0 -6,0,68,41,0,39,0.727,41,1 -7,94,64,25,79,33.3,0.738,41,0 -3,96,78,39,0,37.3,0.238,40,0 -10,75,82,0,0,33.3,0.263,38,0 -0,180,90,26,90,36.5,0.314,35,1 -1,130,60,23,170,28.6,0.692,21,0 -2,84,50,23,76,30.4,0.968,21,0 -8,120,78,0,0,25,0.409,64,0 -12,84,72,31,0,29.7,0.297,46,1 -0,139,62,17,210,22.1,0.207,21,0 -9,91,68,0,0,24.2,0.2,58,0 -2,91,62,0,0,27.3,0.525,22,0 -3,99,54,19,86,25.6,0.154,24,0 -3,163,70,18,105,31.6,0.268,28,1 -9,145,88,34,165,30.3,0.771,53,1 -7,125,86,0,0,37.6,0.304,51,0 -13,76,60,0,0,32.8,0.18,41,0 -6,129,90,7,326,19.6,0.582,60,0 -2,68,70,32,66,25,0.187,25,0 -3,124,80,33,130,33.2,0.305,26,0 -6,114,0,0,0,0,0.189,26,0 -9,130,70,0,0,34.2,0.652,45,1 -3,125,58,0,0,31.6,0.151,24,0 -3,87,60,18,0,21.8,0.444,21,0 -1,97,64,19,82,18.2,0.299,21,0 -3,116,74,15,105,26.3,0.107,24,0 -0,117,66,31,188,30.8,0.493,22,0 -0,111,65,0,0,24.6,0.66,31,0 -2,122,60,18,106,29.8,0.717,22,0 -0,107,76,0,0,45.3,0.686,24,0 -1,86,66,52,65,41.3,0.917,29,0 -6,91,0,0,0,29.8,0.501,31,0 -1,77,56,30,56,33.3,1.251,24,0 -4,132,0,0,0,32.9,0.302,23,1 -0,105,90,0,0,29.6,0.197,46,0 -0,57,60,0,0,21.7,0.735,67,0 -0,127,80,37,210,36.3,0.804,23,0 -3,129,92,49,155,36.4,0.968,32,1 -8,100,74,40,215,39.4,0.661,43,1 -3,128,72,25,190,32.4,0.549,27,1 -10,90,85,32,0,34.9,0.825,56,1 -4,84,90,23,56,39.5,0.159,25,0 -1,88,78,29,76,32,0.365,29,0 -8,186,90,35,225,34.5,0.423,37,1 -5,187,76,27,207,43.6,1.034,53,1 -4,131,68,21,166,33.1,0.16,28,0 -1,164,82,43,67,32.8,0.341,50,0 -4,189,110,31,0,28.5,0.68,37,0 -1,116,70,28,0,27.4,0.204,21,0 -3,84,68,30,106,31.9,0.591,25,0 -6,114,88,0,0,27.8,0.247,66,0 -1,88,62,24,44,29.9,0.422,23,0 -1,84,64,23,115,36.9,0.471,28,0 -7,124,70,33,215,25.5,0.161,37,0 -1,97,70,40,0,38.1,0.218,30,0 -8,110,76,0,0,27.8,0.237,58,0 -11,103,68,40,0,46.2,0.126,42,0 -11,85,74,0,0,30.1,0.3,35,0 -6,125,76,0,0,33.8,0.121,54,1 -0,198,66,32,274,41.3,0.502,28,1 -1,87,68,34,77,37.6,0.401,24,0 -6,99,60,19,54,26.9,0.497,32,0 -0,91,80,0,0,32.4,0.601,27,0 -2,95,54,14,88,26.1,0.748,22,0 -1,99,72,30,18,38.6,0.412,21,0 -6,92,62,32,126,32,0.085,46,0 -4,154,72,29,126,31.3,0.338,37,0 -0,121,66,30,165,34.3,0.203,33,1 -3,78,70,0,0,32.5,0.27,39,0 -2,130,96,0,0,22.6,0.268,21,0 -3,111,58,31,44,29.5,0.43,22,0 -2,98,60,17,120,34.7,0.198,22,0 -1,143,86,30,330,30.1,0.892,23,0 -1,119,44,47,63,35.5,0.28,25,0 -6,108,44,20,130,24,0.813,35,0 -2,118,80,0,0,42.9,0.693,21,1 -10,133,68,0,0,27,0.245,36,0 -2,197,70,99,0,34.7,0.575,62,1 -0,151,90,46,0,42.1,0.371,21,1 -6,109,60,27,0,25,0.206,27,0 -12,121,78,17,0,26.5,0.259,62,0 -8,100,76,0,0,38.7,0.19,42,0 -8,124,76,24,600,28.7,0.687,52,1 -1,93,56,11,0,22.5,0.417,22,0 -8,143,66,0,0,34.9,0.129,41,1 -6,103,66,0,0,24.3,0.249,29,0 -3,176,86,27,156,33.3,1.154,52,1 -0,73,0,0,0,21.1,0.342,25,0 -11,111,84,40,0,46.8,0.925,45,1 -2,112,78,50,140,39.4,0.175,24,0 -3,132,80,0,0,34.4,0.402,44,1 -2,82,52,22,115,28.5,1.699,25,0 -6,123,72,45,230,33.6,0.733,34,0 -0,188,82,14,185,32,0.682,22,1 -0,67,76,0,0,45.3,0.194,46,0 -1,89,24,19,25,27.8,0.559,21,0 -1,173,74,0,0,36.8,0.088,38,1 -1,109,38,18,120,23.1,0.407,26,0 -1,108,88,19,0,27.1,0.4,24,0 -6,96,0,0,0,23.7,0.19,28,0 -1,124,74,36,0,27.8,0.1,30,0 -7,150,78,29,126,35.2,0.692,54,1 -4,183,0,0,0,28.4,0.212,36,1 -1,124,60,32,0,35.8,0.514,21,0 -1,181,78,42,293,40,1.258,22,1 -1,92,62,25,41,19.5,0.482,25,0 -0,152,82,39,272,41.5,0.27,27,0 -1,111,62,13,182,24,0.138,23,0 -3,106,54,21,158,30.9,0.292,24,0 -3,174,58,22,194,32.9,0.593,36,1 -7,168,88,42,321,38.2,0.787,40,1 -6,105,80,28,0,32.5,0.878,26,0 -11,138,74,26,144,36.1,0.557,50,1 -3,106,72,0,0,25.8,0.207,27,0 -6,117,96,0,0,28.7,0.157,30,0 -2,68,62,13,15,20.1,0.257,23,0 -9,112,82,24,0,28.2,1.282,50,1 -0,119,0,0,0,32.4,0.141,24,1 -2,112,86,42,160,38.4,0.246,28,0 -2,92,76,20,0,24.2,1.698,28,0 -6,183,94,0,0,40.8,1.461,45,0 -0,94,70,27,115,43.5,0.347,21,0 -2,108,64,0,0,30.8,0.158,21,0 -4,90,88,47,54,37.7,0.362,29,0 -0,125,68,0,0,24.7,0.206,21,0 -0,132,78,0,0,32.4,0.393,21,0 -5,128,80,0,0,34.6,0.144,45,0 -4,94,65,22,0,24.7,0.148,21,0 -7,114,64,0,0,27.4,0.732,34,1 -0,102,78,40,90,34.5,0.238,24,0 -2,111,60,0,0,26.2,0.343,23,0 -1,128,82,17,183,27.5,0.115,22,0 -10,92,62,0,0,25.9,0.167,31,0 -13,104,72,0,0,31.2,0.465,38,1 -5,104,74,0,0,28.8,0.153,48,0 -2,94,76,18,66,31.6,0.649,23,0 -7,97,76,32,91,40.9,0.871,32,1 -1,100,74,12,46,19.5,0.149,28,0 -0,102,86,17,105,29.3,0.695,27,0 -4,128,70,0,0,34.3,0.303,24,0 -6,147,80,0,0,29.5,0.178,50,1 -4,90,0,0,0,28,0.61,31,0 -3,103,72,30,152,27.6,0.73,27,0 -2,157,74,35,440,39.4,0.134,30,0 -1,167,74,17,144,23.4,0.447,33,1 -0,179,50,36,159,37.8,0.455,22,1 -11,136,84,35,130,28.3,0.26,42,1 -0,107,60,25,0,26.4,0.133,23,0 -1,91,54,25,100,25.2,0.234,23,0 -1,117,60,23,106,33.8,0.466,27,0 -5,123,74,40,77,34.1,0.269,28,0 -2,120,54,0,0,26.8,0.455,27,0 -1,106,70,28,135,34.2,0.142,22,0 -2,155,52,27,540,38.7,0.24,25,1 -2,101,58,35,90,21.8,0.155,22,0 -1,120,80,48,200,38.9,1.162,41,0 -11,127,106,0,0,39,0.19,51,0 -3,80,82,31,70,34.2,1.292,27,1 -10,162,84,0,0,27.7,0.182,54,0 -1,199,76,43,0,42.9,1.394,22,1 -8,167,106,46,231,37.6,0.165,43,1 -9,145,80,46,130,37.9,0.637,40,1 -6,115,60,39,0,33.7,0.245,40,1 -1,112,80,45,132,34.8,0.217,24,0 -4,145,82,18,0,32.5,0.235,70,1 -10,111,70,27,0,27.5,0.141,40,1 -6,98,58,33,190,34,0.43,43,0 -9,154,78,30,100,30.9,0.164,45,0 -6,165,68,26,168,33.6,0.631,49,0 -1,99,58,10,0,25.4,0.551,21,0 -10,68,106,23,49,35.5,0.285,47,0 -3,123,100,35,240,57.3,0.88,22,0 -8,91,82,0,0,35.6,0.587,68,0 -6,195,70,0,0,30.9,0.328,31,1 -9,156,86,0,0,24.8,0.23,53,1 -0,93,60,0,0,35.3,0.263,25,0 -3,121,52,0,0,36,0.127,25,1 -2,101,58,17,265,24.2,0.614,23,0 -2,56,56,28,45,24.2,0.332,22,0 -0,162,76,36,0,49.6,0.364,26,1 -0,95,64,39,105,44.6,0.366,22,0 -4,125,80,0,0,32.3,0.536,27,1 -5,136,82,0,0,0,0.64,69,0 -2,129,74,26,205,33.2,0.591,25,0 -3,130,64,0,0,23.1,0.314,22,0 -1,107,50,19,0,28.3,0.181,29,0 -1,140,74,26,180,24.1,0.828,23,0 -1,144,82,46,180,46.1,0.335,46,1 -8,107,80,0,0,24.6,0.856,34,0 -13,158,114,0,0,42.3,0.257,44,1 -2,121,70,32,95,39.1,0.886,23,0 -7,129,68,49,125,38.5,0.439,43,1 -2,90,60,0,0,23.5,0.191,25,0 -7,142,90,24,480,30.4,0.128,43,1 -3,169,74,19,125,29.9,0.268,31,1 -0,99,0,0,0,25,0.253,22,0 -4,127,88,11,155,34.5,0.598,28,0 -4,118,70,0,0,44.5,0.904,26,0 -2,122,76,27,200,35.9,0.483,26,0 -6,125,78,31,0,27.6,0.565,49,1 -1,168,88,29,0,35,0.905,52,1 -2,129,0,0,0,38.5,0.304,41,0 -4,110,76,20,100,28.4,0.118,27,0 -6,80,80,36,0,39.8,0.177,28,0 -10,115,0,0,0,0,0.261,30,1 -2,127,46,21,335,34.4,0.176,22,0 -9,164,78,0,0,32.8,0.148,45,1 -2,93,64,32,160,38,0.674,23,1 -3,158,64,13,387,31.2,0.295,24,0 -5,126,78,27,22,29.6,0.439,40,0 -10,129,62,36,0,41.2,0.441,38,1 -0,134,58,20,291,26.4,0.352,21,0 -3,102,74,0,0,29.5,0.121,32,0 -7,187,50,33,392,33.9,0.826,34,1 -3,173,78,39,185,33.8,0.97,31,1 -10,94,72,18,0,23.1,0.595,56,0 -1,108,60,46,178,35.5,0.415,24,0 -5,97,76,27,0,35.6,0.378,52,1 -4,83,86,19,0,29.3,0.317,34,0 -1,114,66,36,200,38.1,0.289,21,0 -1,149,68,29,127,29.3,0.349,42,1 -5,117,86,30,105,39.1,0.251,42,0 -1,111,94,0,0,32.8,0.265,45,0 -4,112,78,40,0,39.4,0.236,38,0 -1,116,78,29,180,36.1,0.496,25,0 -0,141,84,26,0,32.4,0.433,22,0 -2,175,88,0,0,22.9,0.326,22,0 -2,92,52,0,0,30.1,0.141,22,0 -3,130,78,23,79,28.4,0.323,34,1 -8,120,86,0,0,28.4,0.259,22,1 -2,174,88,37,120,44.5,0.646,24,1 -2,106,56,27,165,29,0.426,22,0 -2,105,75,0,0,23.3,0.56,53,0 -4,95,60,32,0,35.4,0.284,28,0 -0,126,86,27,120,27.4,0.515,21,0 -8,65,72,23,0,32,0.6,42,0 -2,99,60,17,160,36.6,0.453,21,0 -1,102,74,0,0,39.5,0.293,42,1 -11,120,80,37,150,42.3,0.785,48,1 -3,102,44,20,94,30.8,0.4,26,0 -1,109,58,18,116,28.5,0.219,22,0 -9,140,94,0,0,32.7,0.734,45,1 -13,153,88,37,140,40.6,1.174,39,0 -12,100,84,33,105,30,0.488,46,0 -1,147,94,41,0,49.3,0.358,27,1 -1,81,74,41,57,46.3,1.096,32,0 -3,187,70,22,200,36.4,0.408,36,1 -6,162,62,0,0,24.3,0.178,50,1 -4,136,70,0,0,31.2,1.182,22,1 -1,121,78,39,74,39,0.261,28,0 -3,108,62,24,0,26,0.223,25,0 -0,181,88,44,510,43.3,0.222,26,1 -8,154,78,32,0,32.4,0.443,45,1 -1,128,88,39,110,36.5,1.057,37,1 -7,137,90,41,0,32,0.391,39,0 -0,123,72,0,0,36.3,0.258,52,1 -1,106,76,0,0,37.5,0.197,26,0 -6,190,92,0,0,35.5,0.278,66,1 -2,88,58,26,16,28.4,0.766,22,0 -9,170,74,31,0,44,0.403,43,1 -9,89,62,0,0,22.5,0.142,33,0 -10,101,76,48,180,32.9,0.171,63,0 -2,122,70,27,0,36.8,0.34,27,0 -5,121,72,23,112,26.2,0.245,30,0 -1,126,60,0,0,30.1,0.349,47,1 -1,93,70,31,0,30.4,0.315,23,0 diff --git a/completesolution/datascientist/diabetestree.ipynb b/completesolution/datascientist/diabetestree.ipynb deleted file mode 100644 index af27c10e..00000000 --- a/completesolution/datascientist/diabetestree.ipynb +++ /dev/null @@ -1,232 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Import Required Libraries\n", - "Import the necessary libraries, including pandas, sklearn, etc." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Importing required libraries\n", - "\n", - "# pandas for data manipulation and analysis\n", - "import pandas as pd\n", - "\n", - "\n", - "# matplotlib for data visualization\n", - "import matplotlib.pyplot as plt\n", - "\n", - "\n", - "# train_test_split for splitting the data into training and testing sets\n", - "from sklearn.model_selection import train_test_split\n", - "\n", - "# DecisionTreeClassifier for decision tree classification\n", - "from sklearn.tree import DecisionTreeClassifier\n", - "\n", - "# accuracy_score for evaluating the model\n", - "from sklearn import metrics\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Load the Diabetes Dataset\n", - "Load the diabetes dataset using pandas or from sklearn datasets." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the Diabetes Dataset\n", - "\n", - "\n", - "col_names = ['pregnant', 'glucose', 'bp', 'skin', 'insulin', 'bmi', 'pedigree', 'age', 'label']\n", - "\n", - "# load dataset\n", - "diabetes_df = pd.read_csv(\"diabetes.csv\", header=None, names=col_names)\n", - "\n", - "\n", - "# Display the first 5 rows of the DataFrame\n", - "diabetes_df.head()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Exploratory Data Analysis\n", - "Display the number of rows and columns in the dataframe.\n", - "Display the data types of each column.\n", - "Display the number of missing values in each column.\n", - "Display the number of unique values in each column.\n", - "Display the basic statistics of each column." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Exploratory Data Analysis\n", - "\n", - "# Display the first 5 rows of the DataFrame\n", - "diabetes_df.head()\n", - "\n", - "# Display the data types of each column.\n", - "diabetes_df.dtypes\n", - "\n", - "# Display the number of missing values in each column.\n", - "diabetes_df.isnull().sum()\n", - "\n", - "# Display the number of unique values in each column.\n", - "diabetes_df.nunique()\n", - "\n", - "# Display the summary statistics of the dataframe.\n", - "diabetes_df.describe()\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Feature Selection\n", - "\n", - "Select the features that you want to use for the prediction. You can use all the features or a subset of features.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# feature Selection\n", - "\n", - "#split dataset in features and target variable\n", - "feature_cols = ['pregnant', 'insulin', 'bmi', 'age','glucose','bp','pedigree']\n", - "\n", - "X = diabetes_df[feature_cols] # Features\n", - "y = diabetes_df.label # Target variable\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Splitting Data\n", - "Divide the data into training and testing sets. The training set will be used to train the model and the testing set will be used to evaluate the model." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Split dataset into training set and test set\n", - "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) # 70% training and 30% test\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Building Decision Tree Model\n", - "Build a decision tree model using the training set." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Building Decision Tree Model\n", - "\n", - "# Create Decision Tree classifer object\n", - "clf = DecisionTreeClassifier()\n", - "\n", - "# Train Decision Tree Classifer\n", - "clf = clf.fit(X_train,y_train)\n", - "\n", - "#Predict the response for test dataset\n", - "y_pred = clf.predict(X_test)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Evaluating Model\n", - "Evaluate the model using the testing set." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Evaluating Model\n", - "\n", - "# Model Accuracy, how often is the classifier correct?\n", - "print(\"Accuracy:\",metrics.accuracy_score(y_test, y_pred))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Visualizing Decision Trees\n", - "\n", - "Visualize the decision tree using the graphviz library.\n", - "\n", - "pip install graphviz\n", - "\n", - "pip install pydotplus" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.tree import export_graphviz\n", - "from sklearn.externals.six import StringIO \n", - "from IPython.display import Image \n", - "import pydotplus\n", - "\n", - "dot_data = StringIO()\n", - "export_graphviz(clf, out_file=dot_data, \n", - " filled=True, rounded=True,\n", - " special_characters=True,feature_names = feature_cols,class_names=['0','1'])\n", - "graph = pydotplus.graph_from_dot_data(dot_data.getvalue()) \n", - "graph.write_png('diabetes.png')\n", - "Image(graph.create_png())" - ] - } - ], - "metadata": { - "language_info": { - "name": "python" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/completesolution/dotnet/.vscode/settings.json b/completesolution/dotnet/.vscode/settings.json deleted file mode 100644 index 18cd287f..00000000 --- a/completesolution/dotnet/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "dotnet.defaultSolution": "MinimalAPI.sln" -} \ No newline at end of file diff --git a/completesolution/dotnet/MinimalAPI.Tests/Helpers/TestWebApplicationFactory.cs b/completesolution/dotnet/MinimalAPI.Tests/Helpers/TestWebApplicationFactory.cs deleted file mode 100644 index 2ed7cb2f..00000000 --- a/completesolution/dotnet/MinimalAPI.Tests/Helpers/TestWebApplicationFactory.cs +++ /dev/null @@ -1,12 +0,0 @@ - - -namespace IntegrationTests; - -public class TestWebApplicationFactory - : WebApplicationFactory where TProgram : class -{ - protected override IHost CreateHost(IHostBuilder builder) - { - return base.CreateHost(builder); - } -} \ No newline at end of file diff --git a/completesolution/dotnet/MinimalAPI.Tests/IntegrationTests.cs b/completesolution/dotnet/MinimalAPI.Tests/IntegrationTests.cs deleted file mode 100644 index 6e575fb3..00000000 --- a/completesolution/dotnet/MinimalAPI.Tests/IntegrationTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace IntegrationTests; - -public class IntegrationTests : IClassFixture> -{ - private readonly HttpClient _client; - - public IntegrationTests(TestWebApplicationFactory factory) - { - _client = factory.CreateClient(); - } - - [Fact] - public async Task Get_ReturnsHelloWorld() - { - // Arrange - - // Act - var response = await _client.GetAsync("/"); - - // Assert - response.EnsureSuccessStatusCode(); - var content = await response.Content.ReadAsStringAsync(); - Assert.Equal("Hello World!", content); - } -} diff --git a/completesolution/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj b/completesolution/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj deleted file mode 100644 index 67976258..00000000 --- a/completesolution/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - net8.0 - enable - enable - - false - true - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/completesolution/dotnet/MinimalAPI.Tests/Usings.cs b/completesolution/dotnet/MinimalAPI.Tests/Usings.cs deleted file mode 100644 index 28389ef8..00000000 --- a/completesolution/dotnet/MinimalAPI.Tests/Usings.cs +++ /dev/null @@ -1,3 +0,0 @@ -global using Xunit; -global using Microsoft.AspNetCore.Mvc.Testing; -global using Microsoft.Extensions.Hosting; diff --git a/completesolution/dotnet/MinimalAPI.sln b/completesolution/dotnet/MinimalAPI.sln deleted file mode 100644 index 9c12c699..00000000 --- a/completesolution/dotnet/MinimalAPI.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.001.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MinimalAPI", "MinimalAPI\MinimalAPI.csproj", "{03FF4ABB-0BAB-42BA-9910-725B80C69895}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MinimalAPI.Tests", "MinimalAPI.Tests\MinimalAPI.Tests.csproj", "{0ED02B58-62C2-4474-BF04-40CF38069A84}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {03FF4ABB-0BAB-42BA-9910-725B80C69895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {03FF4ABB-0BAB-42BA-9910-725B80C69895}.Debug|Any CPU.Build.0 = Debug|Any CPU - {03FF4ABB-0BAB-42BA-9910-725B80C69895}.Release|Any CPU.ActiveCfg = Release|Any CPU - {03FF4ABB-0BAB-42BA-9910-725B80C69895}.Release|Any CPU.Build.0 = Release|Any CPU - {0ED02B58-62C2-4474-BF04-40CF38069A84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0ED02B58-62C2-4474-BF04-40CF38069A84}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0ED02B58-62C2-4474-BF04-40CF38069A84}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0ED02B58-62C2-4474-BF04-40CF38069A84}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9F921EE8-9C46-4602-A195-8C24938239EC} - EndGlobalSection -EndGlobal diff --git a/completesolution/dotnet/MinimalAPI/Color.cs b/completesolution/dotnet/MinimalAPI/Color.cs deleted file mode 100644 index 6a75b93e..00000000 --- a/completesolution/dotnet/MinimalAPI/Color.cs +++ /dev/null @@ -1,23 +0,0 @@ -public class Color -{ - [JsonPropertyName("name")] - public string Name { get; set; } - - [JsonPropertyName("category")] - public string Category { get; set; } - - [JsonPropertyName("type")] - public string Type { get; set; } - - [JsonPropertyName("code")] - public ColorCode Code { get; set; } -} - -public class ColorCode -{ - [JsonPropertyName("rgba")] - public int[] RGBA { get; set; } - - [JsonPropertyName("hex")] - public string HEX { get; set; } -} \ No newline at end of file diff --git a/completesolution/dotnet/MinimalAPI/Dockerfile b/completesolution/dotnet/MinimalAPI/Dockerfile deleted file mode 100644 index 53830eaf..00000000 --- a/completesolution/dotnet/MinimalAPI/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -# create dotnet 7 image for the current project - -# Use the official .NET 7 SDK image as the base image -FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS build - -# Set the working directory to /app -WORKDIR /app - -# Copy the current directory contents into the container at /app -COPY . . - -# Build the project and restore the packages -RUN dotnet restore - -# Publish the project to a folder called "out" -RUN dotnet publish -c Release -o out - -# Use the official .NET 7 runtime image as the base image -FROM mcr.microsoft.com/dotnet/runtime:7.0 AS runtime - -# Set the working directory to /app -WORKDIR /app - -# Copy the published output from the build image to the runtime image -COPY --from=build /app/out ./ - -# Set the entry point to the application -ENTRYPOINT ["dotnet", "/app/MinimalAPI.dll"] diff --git a/completesolution/dotnet/MinimalAPI/MinimalAPI.csproj b/completesolution/dotnet/MinimalAPI/MinimalAPI.csproj deleted file mode 100644 index 06c5c763..00000000 --- a/completesolution/dotnet/MinimalAPI/MinimalAPI.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - net8.0 - enable - enable - - - - - - - - - diff --git a/completesolution/dotnet/MinimalAPI/Program.cs b/completesolution/dotnet/MinimalAPI/Program.cs deleted file mode 100644 index 56855869..00000000 --- a/completesolution/dotnet/MinimalAPI/Program.cs +++ /dev/null @@ -1,107 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); - -// Add services to the container. -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); - -// Register a HttpClient so IHttpClientFactory can be used to create HttpClient instances. -builder.Services.AddHttpClient(); - -var app = builder.Build(); - -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - app.UseSwagger(); - app.UseSwaggerUI(); -} - -app.UseHttpsRedirection(); - -// Hello World Get endpoint -app.MapGet("/", () => "Hello World!"); - -// Endpoint daysdetweendates. Reads startdate and enddate from the query string and returns the number of days between the dates -app.MapGet("/daysbetweendates", (DateTime startdate, DateTime enddate) => (enddate - startdate).TotalDays.ToString()); - -// Endpoint validatephonenumber. Reads phonenumber from the query string and returns true if the number is valid using regex -app.MapGet("/validatephonenumber", (string phonenumber) => Regex.IsMatch(phonenumber, @"^(\+[0-9]{9})$").ToString()); - -// Endpopoint validatespanishdni. Reads dni from the query string and returns true if the dni is valid. Implement inline. -app.MapGet("/validatespanishdni", (string dni) => -{ - if (dni.Length != 9) return false; - var dniLetters = "TRWAGMYFPDXBNJZSQVHLCKE"; - var dniNumber = int.Parse(dni.Substring(0, 8)); - var dniLetter = dniLetters[dniNumber % 23]; - return dniLetter == dni[8]; -}); - -// Endpoint color. -// Reads color from the query string. -// Read colors.json into a Coloresarray and iterated to find the correct color -// Return the Hex code. -// Implement inline. -app.MapGet("/color", (string color) => -{ - var colors = JsonSerializer.Deserialize(File.ReadAllText("colors.json")); - return colors.First(c => c.Name == color).Code.HEX; -}); - -// tellmeajoke endpoint. Calls jokeapi and returns a sinlgle joke. -// Deserialize to dynamic. -// Make sure to use IHttpClientFactory to create the HttpClient instance. -app.MapGet("/tellmeajoke", async (IHttpClientFactory httpClientFactory) => -{ - var client = httpClientFactory.CreateClient(); - var response = await client.GetAsync("https://v2.jokeapi.dev/joke/Any"); - var content = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(content); -}); - -// moviesbydirector endpoint. -// Calls omdbapi with an apikey specified in code and returns a list of movies -// for the director specified in the query string. Deserialize to dynamic. -// Make sure to use IHttpClientFactory to create the HttpClient instance. -app.MapGet("/moviesbydirector", async (string director, IHttpClientFactory httpClientFactory) => -{ - var client = httpClientFactory.CreateClient(); - var response = await client.GetAsync($"http://www.omdbapi.com/?apikey=4e3b711b&r=json&s={director}"); - var content = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(content); -}); - -// parseurl endpoint. Reads url from the query string and returns the protocol, host and path in a json object. Implement inline. -app.MapGet("/parseurl", (string url) => -{ - var uri = new Uri(url); - return new { Protocol = uri.Scheme, Host = uri.Host, Path = uri.AbsolutePath }; -}); - -// listfiles endpoint. Read contents of the current directory and return a list of files. Implement inline. -app.MapGet("/listfiles", () => -{ - var files = Directory.GetFileSystemEntries(Directory.GetCurrentDirectory()); - return JsonSerializer.Serialize(files); -}); - -// calculate memory usage endpoint. Return the current memory usage of the process in GB. Implement inline. -app.MapGet("/calculatememoryusage", () => -{ - var process = Process.GetCurrentProcess(); - return $"{process.WorkingSet64 / 1024 / 1024 / 1024} GB"; -}); - -// random european country endpoint. Return a random european country from an array. Implement inline. -app.MapGet("/randomeuropeancountry", () => -{ - var countries = new[] { "Spain", "France", "Germany", "Italy", "Portugal", "Sweden", "Norway", "Denmark", "Finland", "Iceland", "Ireland", "United Kingdom", "Greece", "Austria", "Belgium", "Bulgaria", "Croatia", "Cyprus", "Czech Republic", "Estonia", "Hungary", "Latvia", "Lithuania", "Luxembourg", "Malta", "Netherlands", "Poland", "Romania", "Slovakia", "Slovenia" }; - return countries[new Random().Next(0, countries.Length)]; -}); - -app.Run(); - -// Needed to be able to access this type from the MinimalAPI.Tests project. -public partial class Program -{ } diff --git a/completesolution/dotnet/MinimalAPI/Properties/launchSettings.json b/completesolution/dotnet/MinimalAPI/Properties/launchSettings.json deleted file mode 100644 index 1632a63a..00000000 --- a/completesolution/dotnet/MinimalAPI/Properties/launchSettings.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:51750", - "sslPort": 44373 - } - }, - "profiles": { - "http": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "http://localhost:5163", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "https://localhost:7007;http://localhost:5163", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "swagger", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} diff --git a/completesolution/dotnet/MinimalAPI/Usings.cs b/completesolution/dotnet/MinimalAPI/Usings.cs deleted file mode 100644 index 09b16c96..00000000 --- a/completesolution/dotnet/MinimalAPI/Usings.cs +++ /dev/null @@ -1,4 +0,0 @@ -global using System.Diagnostics; -global using System.Text.RegularExpressions; -global using System.Text.Json; -global using System.Text.Json.Serialization; \ No newline at end of file diff --git a/completesolution/dotnet/MinimalAPI/appsettings.Development.json b/completesolution/dotnet/MinimalAPI/appsettings.Development.json deleted file mode 100644 index 0c208ae9..00000000 --- a/completesolution/dotnet/MinimalAPI/appsettings.Development.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} diff --git a/completesolution/dotnet/MinimalAPI/appsettings.json b/completesolution/dotnet/MinimalAPI/appsettings.json deleted file mode 100644 index 10f68b8c..00000000 --- a/completesolution/dotnet/MinimalAPI/appsettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*" -} diff --git a/completesolution/dotnet/MinimalAPI/colors.json b/completesolution/dotnet/MinimalAPI/colors.json deleted file mode 100644 index e7283ffa..00000000 --- a/completesolution/dotnet/MinimalAPI/colors.json +++ /dev/null @@ -1,56 +0,0 @@ -[ - { - "name": "black", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,255,255,1], - "hex": "#000000" - } - }, - { - "name": "white", - "category": "value", - "code": { - "rgba": [0,0,0,1], - "hex": "#FFFFFF" - } - }, - { - "name": "red", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,0,0,1], - "hex": "#FF0000" - } - }, - { - "name": "blue", - "category": "hue", - "type": "primary", - "code": { - "rgba": [0,0,255,1], - "hex": "#0000FF" - } - }, - { - "name": "yellow", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,255,0,1], - "hex": "#FFFF00" - } - }, - { - "name": "green", - "category": "hue", - "type": "secondary", - "code": { - "rgba": [0,255,0,1], - "hex": "#00FF00" - } - } - ] - \ No newline at end of file diff --git a/completesolution/node/.dockerignore b/completesolution/node/.dockerignore deleted file mode 100644 index 5309493a..00000000 --- a/completesolution/node/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -[D|d]ockerfile \ No newline at end of file diff --git a/completesolution/node/Dockerfile b/completesolution/node/Dockerfile deleted file mode 100644 index 0086afcd..00000000 --- a/completesolution/node/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -# Create a dockerfile with node image -FROM node:latest - -# Create a directory to hold the application code inside the image, this will be the working directory for your application -RUN mkdir -p /usr/src/app - -# Set the working directory to /usr/src/app -WORKDIR /usr/src/app - -# Copy package.json and package-lock.json to the working directory -COPY package*.json ./ - -# Install npm -RUN npm install - -# Copy the current directory contents into the container at /usr/src/app -COPY . . - -# Make port 3000 available to the world outside this container -EXPOSE 3000 - -# Run Nodeserver.js when the container launches -CMD ["node", "nodeserver.js"] - -# Write a docker comand to build the image and tag it as mynodeapp -#docker build -t mynodeapp . - -# Write command to run docker in port 4000 -#docker run -p 4000:3000 -d diff --git a/completesolution/node/colors.json b/completesolution/node/colors.json deleted file mode 100644 index 395bf81f..00000000 --- a/completesolution/node/colors.json +++ /dev/null @@ -1,55 +0,0 @@ -[ - { - "color": "black", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,255,255,1], - "hex": "#000000" - } - }, - { - "color": "white", - "category": "value", - "code": { - "rgba": [0,0,0,1], - "hex": "#FFFFFF" - } - }, - { - "color": "red", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,0,0,1], - "hex": "#FF0000" - } - }, - { - "color": "blue", - "category": "hue", - "type": "primary", - "code": { - "rgba": [0,0,255,1], - "hex": "#0000FF" - } - }, - { - "color": "yellow", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,255,0,1], - "hex": "#FFFF00" - } - }, - { - "color": "green", - "category": "hue", - "type": "secondary", - "code": { - "rgba": [0,255,0,1], - "hex": "#00FF00" - } - } -] diff --git a/completesolution/node/nodeserver.js b/completesolution/node/nodeserver.js deleted file mode 100644 index 7d5b8787..00000000 --- a/completesolution/node/nodeserver.js +++ /dev/null @@ -1,327 +0,0 @@ -// write a nodejs server that will expose a method call "get" that will return the value of the key passed in the query string -// example: http://localhost:3000/get?key=hello -// should return the value of foo -// if the key is not passed, return "key not passed" -// if the key is passed, return "hello" key - -const http = require('http'); -const url = require('url'); -const fs = require('fs'); -const escape = require('escape-html'); - -const server = http.createServer((req, res) => { - if (req.url.startsWith('/DaysBetweenDates')) { - //calculate days between two dates - - //get dates from querystring - var queryData = url.parse(req.url, true).query; - var date1 = queryData.date1; - var date2 = queryData.date2; - - //convert dates to milliseconds - var date1_ms = Date.parse(date1); - var date2_ms = Date.parse(date2); - - //calculate difference in milliseconds - var difference_ms = date2_ms - date1_ms; - - //convert to days and return - res.end(Math.round(difference_ms / 86400000) + " days"); - - } else if (req.url.startsWith('/Validatephonenumber')) { - - //get phoneNumber var from querystring - var queryData = url.parse(req.url, true).query; - var phoneNumber = queryData.phoneNumber; - - - //validate phoneNumber with Spanish format - var regex = /^(\+34|0034|34)?[ -]*(6|7)[ -]*([0-9][ -]*){8}$/; - - //if phoneNumber is valid return "valid" - if (regex.test(phoneNumber)) { - res.end("valid"); - } - //if phoneNumber is not valid return "invalid" - else { - res.end("invalid"); - } - } else if (req.url.startsWith('/ValidateSpanishDNI')) { - var queryData = url.parse(req.url, true).query; - var dni = queryData.dni; - - // calculate DNI letter - var dniLetter = dni.charAt(dni.length - 1); - var dniNumber = dni.substring(0, dni.length - 1); - var dniLetterCalc = "TRWAGMYFPDXBNJZSQVHLCKE".charAt(dniNumber % 23); - - //if DNI is valid return "valid" - if (dniLetter == dniLetterCalc) { - res.end("valid"); - } - //if DNI is not valid return "invalid" - else { - res.end("invalid"); - } - - } else if (req.url.startsWith('/ReturnColorCode')) { - - //read colors.json file and return the rgba field - var colors = fs.readFileSync('colors.json', 'utf-8'); - var colorsObj = JSON.parse(colors); - - //get color var from querystring - var queryData = url.parse(req.url, true).query; - var color = queryData.color; - var colorFound = "not found"; - - //for each color in colors.json - for (var i = 1; i < colorsObj.length; i++) { - //if color is found return the color code - if (colorsObj[i].color == color) { - colorFound = colorsObj[i].code.hex; - } - } - - res.end(colorFound); - - } - else if (req.url.startsWith('/SendEmail')) { - } - else if (req.url.startsWith('/TellMeAJoke')) { - - //make a call to the joke api and return a random joke using axios - const axios = require('axios'); - - axios.get('https://official-joke-api.appspot.com/random_joke') - .then(function (response) { - // handle success - res.end(response.data.setup + " " + response.data.punchline); - } - ) - .catch(function (error) { - // handle error - console.log(error); - }) - .then(function () { - // always executed - }); - } - - //method that gets the name of a director and retrieves from an api the list of movies of that director - else if (req.url.startsWith('/MoviesByDirector')) { - - //get a director name from querystring - var queryData = url.parse(req.url, true).query; - var director = queryData.director; - - //make a call to the movie api omdbapi.com and return a list of movies of that director using axios - const axios = require('axios'); - - axios.get('http://www.omdbapi.com/?apikey=XXXXXXX&s=' + director) - .then(function (response) { - - //return the full list of movies - var movies = ""; - for (var i = 0; i < response.data.Search.length; i++) { - movies = movies + response.data.Search[i].Title + ", "; - } - - res.end(movies); - - } - ) - .catch(function (error) { - // handle error - console.log(error); - } - ) - .then(function () { - // always executed - } - ); - } - //If url equals to ParseUrl - else if (req.url.startsWith('/ParseUrl')) { - - //retrieves a parameter from querystring called someurl - var queryData = url.parse(req.url, true).query; - var someUrl = queryData.someurl; - - //parse the url and return the protocol, host, port, path, querystring and hash - var urlObj = new URL(someUrl); - - var protocol = urlObj.protocol; - var host = urlObj.host; - var port = urlObj.port; - var path = urlObj.pathname; - var querystring = urlObj.search; - var hash = urlObj.hash; - - //return the parsed host - res.end("host: " + host); - - } - //if url contains listFiles in current directory - else if (req.url.startsWith('/ListFiles')) { - - //get the current directory - var currentDir = __dirname; - - //get the list of files in the current directory - var files = fs.readdirSync(currentDir); - - //return the list of files - res.end(escape(files.toString())); - - } - else if (req.url.startsWith('/GetFullTextFile')) { - - //read sample.txt and return lines that contains the word "Fusce" - var text = fs.readFileSync('sample.txt', 'utf-8'); - var lines = text.split("\r"); - - var linesFound = ""; - for (var i = 1; i < lines.length; i++) { - if (lines[i].includes("Fusce")) { - linesFound = linesFound + lines[i] + ", "; - } - } - - res.end(linesFound); - } - else if (req.url.startsWith('/GetLineByLinefromtTextFile')) { - - //read sample.txt line by line - var lineReader = require('readline').createInterface({ - input: require('fs').createReadStream('sample.txt') - }); - - //create a promise to read the file line by line, and return a list of lines that contains the word "Fusce" - var promise = new Promise(function (resolve, reject) { - var lines = []; - lineReader.on('line', function (line) { - if (line.includes("Fusce")) { - lines.push(line); - } - }); - lineReader.on('close', function () { - resolve(lines); - }); - }); - - //return the list of lines - promise.then(function (lines) { - res.end(lines.toString()); - }); - } - else if (req.url.startsWith('/CalculateMemoryConsumption')) { - - //return the memory consumption of the process in GB, rounded to 2 decimals - var memory = process.memoryUsage().heapUsed / 1024 / 1024; - - res.end(memory.toFixed(2) + " GB"); - - } - else if (req.url.startsWith('/MakeZipFile')) { - - //using zlib create a zip file called sample.gz that contains sample.txt - var zlib = require('zlib'); - - var gzip = zlib.createGzip(); - var input = fs.createReadStream('sample.txt'); - var output = fs.createWriteStream('sample.gz'); - - input.pipe(gzip).pipe(output); - - res.end("sample.gz created"); - - } - else if (req.url.startsWith('/RandomEuropeanCountry')) { - - //make an array of european countries and its iso codes - var countries = [ - { country: "Italy", iso: "IT" }, - { country: "France", iso: "FR" }, - { country: "Spain", iso: "ES" }, - { country: "Germany", iso: "DE" }, - { country: "United Kingdom", iso: "GB" }, - { country: "Greece", iso: "GR" }, - { country: "Portugal", iso: "PT" }, - { country: "Romania", iso: "RO" }, - { country: "Bulgaria", iso: "BG" }, - { country: "Croatia", iso: "HR" }, - { country: "Czech Republic", iso: "CZ" }, - { country: "Denmark", iso: "DK" }, - { country: "Estonia", iso: "EE" }, - { country: "Finland", iso: "FI" }, - { country: "Hungary", iso: "HU" }, - { country: "Ireland", iso: "IE" }, - { country: "Latvia", iso: "LV" }, - { country: "Lithuania", iso: "LT" }, - { country: "Luxembourg", iso: "LU" }, - { country: "Malta", iso: "MT" }, - { country: "Netherlands", iso: "NL" }, - { country: "Poland", iso: "PL" }, - { country: "Slovakia", iso: "SK" }, - { country: "Slovenia", iso: "SI" }, - { country: "Sweden", iso: "SE" }, - { country: "Belgium", iso: "BE" }, - { country: "Austria", iso: "AT" }, - { country: "Switzerland", iso: "CH" }, - { country: "Cyprus", iso: "CY" }, - { country: "Iceland", iso: "IS" }, - { country: "Norway", iso: "NO" }, - { country: "Albania", iso: "AL" }, - { country: "Andorra", iso: "AD" }, - { country: "Armenia", iso: "AM" }, - { country: "Azerbaijan", iso: "AZ" }, - { country: "Belarus", iso: "BY" }, - { country: "Bosnia and Herzegovina", iso: "BA" }, - { country: "Georgia", iso: "GE" }, - { country: "Kazakhstan", iso: "KZ" }, - { country: "Kosovo", iso: "XK" }, - { country: "Liechtenstein", iso: "LI" }, - { country: "Macedonia", iso: "MK" }, - { country: "Moldova", iso: "MD" }, - { country: "Monaco", iso: "MC" }, - { country: "Montenegro", iso: "ME" }, - { country: "Russia", iso: "RU" }, - { country: "San Marino", iso: "SM" }, - { country: "Serbia", iso: "RS" }, - { country: "Turkey", iso: "TR" }, - { country: "Ukraine", iso: "UA" }, - { country: "Vatican City", iso: "VA" } - ]; - - //return a random country from the array - var randomCountry = countries[Math.floor(Math.random() * countries.length)]; - - //return the country and its iso code - res.end(randomCountry.country + " " + randomCountry.iso); - - } - else if (req.url.startsWith('/Get')) { - const { query } = url.parse(req.url, true); - const { key } = query; - - if (!key) { - res.end('key not passed'); - } else { - res.end('hello ' + escape(key)); - } - } - else { - res.end('Called method not found'); - } -}); - -server.listen(3000, () => { - console.log('server is listening on port 3000'); -}); - -//write command line to generate package.json -//npm init -y - -//write curl command to getMoviesByDirector -//curl http://localhost:3000/getMoviesByDirector?director=Quentin%20Tarantino diff --git a/completesolution/node/package-lock.json b/completesolution/node/package-lock.json deleted file mode 100644 index 1f2a147c..00000000 --- a/completesolution/node/package-lock.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "nodeserver", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "nodeserver", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "escape-html": "^1.0.3" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - } - }, - "dependencies": { - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - } - } -} diff --git a/completesolution/node/package.json b/completesolution/node/package.json deleted file mode 100644 index 4cc7c3f8..00000000 --- a/completesolution/node/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "nodeserver", - "version": "1.0.0", - "main": "nodeserver.js", - "scripts": { - "start": "node nodeserver.js", - "test": "mocha test.js" - }, - "keywords": [], - "author": "", - "license": "ISC", - "description": "", - "dependencies": { - "escape-html": "^1.0.3" - } -} diff --git a/completesolution/node/test.js b/completesolution/node/test.js deleted file mode 100644 index 92a2543b..00000000 --- a/completesolution/node/test.js +++ /dev/null @@ -1,131 +0,0 @@ -//write npm command line to install mocha -//npm install --global mocha - -//command to run this test file -//mocha test.js - -const assert = require('assert'); -const http = require('http'); - -const server = require('./nodeserver'); - - - -describe('Node Server', () => { - it('should return "key not passed" if key is not passed', (done) => { - http - .get('http://localhost:3000/Get' , (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - assert.equal(data, 'key not passed'); - done(); - }); - }); - }); - - - it('should return the value of the key if key is found', (done) => { - http.get('http://localhost:3000/Get?key=world', (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - assert.equal(data, 'hello world'); - done(); - }); - }); - }); - - //add test to check validatephoneNumber - it('should return "valid" if phoneNumber is valid', (done) => { - http.get('http://localhost:3000/Validatephonenumber?phoneNumber=34666666666', (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - assert.equal(data, 'valid'); - done(); - }); - }); - }); - - //write test to validate spanish DNI - it('should return "valid" if spanish DNI 86471508H is valid', (done) => { - http.get('http://localhost:3000/ValidateSpanishDNI?dni=86471508H', (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - assert.equal(data, 'valid'); - done(); - }); - }); - }); - - - - //write test to validate spanish DNI - it('should return "valid" if spanish DNI 24153149K is valid', (done) => { - http.get('http://localhost:3000/ValidateSpanishDNI?dni=24153149K', (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - assert.equal(data, 'valid'); - done(); - }); - }); - }); - - - //write test to validate spanish DNI - it('should return "valid" if spanish DNI 12345678A is invalid', (done) => { - http.get('http://localhost:3000/ValidateSpanishDNI?dni=12345678A', (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - assert.equal(data, 'invalid'); - done(); - }); - }); - }); - - //write test for returnColorCode - it('should return "red" if color is red', (done) => { - http.get('http://localhost:3000/ReturnColorCode?color=red', (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - assert.equal(data, '#FF0000'); - done(); - }); - }); - }); - - //write test for daysBetweenDates - it('should return "1" if dates are 2020-01-01 and 2020-01-02', (done) => { - http.get('http://localhost:3000/DaysBetweenDates?date1=2020-01-01&date2=2020-01-02', (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - res.on('end', () => { - assert.equal(data, '1 days'); - done(); - }); - }); - }); - - -}); \ No newline at end of file diff --git a/completesolution/node_typescript/.dockerignore b/completesolution/node_typescript/.dockerignore deleted file mode 100644 index 5309493a..00000000 --- a/completesolution/node_typescript/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -[D|d]ockerfile \ No newline at end of file diff --git a/completesolution/node_typescript/Dockerfile b/completesolution/node_typescript/Dockerfile deleted file mode 100644 index 0086afcd..00000000 --- a/completesolution/node_typescript/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -# Create a dockerfile with node image -FROM node:latest - -# Create a directory to hold the application code inside the image, this will be the working directory for your application -RUN mkdir -p /usr/src/app - -# Set the working directory to /usr/src/app -WORKDIR /usr/src/app - -# Copy package.json and package-lock.json to the working directory -COPY package*.json ./ - -# Install npm -RUN npm install - -# Copy the current directory contents into the container at /usr/src/app -COPY . . - -# Make port 3000 available to the world outside this container -EXPOSE 3000 - -# Run Nodeserver.js when the container launches -CMD ["node", "nodeserver.js"] - -# Write a docker comand to build the image and tag it as mynodeapp -#docker build -t mynodeapp . - -# Write command to run docker in port 4000 -#docker run -p 4000:3000 -d diff --git a/completesolution/node_typescript/colors.json b/completesolution/node_typescript/colors.json deleted file mode 100644 index 395bf81f..00000000 --- a/completesolution/node_typescript/colors.json +++ /dev/null @@ -1,55 +0,0 @@ -[ - { - "color": "black", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,255,255,1], - "hex": "#000000" - } - }, - { - "color": "white", - "category": "value", - "code": { - "rgba": [0,0,0,1], - "hex": "#FFFFFF" - } - }, - { - "color": "red", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,0,0,1], - "hex": "#FF0000" - } - }, - { - "color": "blue", - "category": "hue", - "type": "primary", - "code": { - "rgba": [0,0,255,1], - "hex": "#0000FF" - } - }, - { - "color": "yellow", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,255,0,1], - "hex": "#FFFF00" - } - }, - { - "color": "green", - "category": "hue", - "type": "secondary", - "code": { - "rgba": [0,255,0,1], - "hex": "#00FF00" - } - } -] diff --git a/completesolution/node_typescript/nodeserver.ts b/completesolution/node_typescript/nodeserver.ts deleted file mode 100644 index 59b4e338..00000000 --- a/completesolution/node_typescript/nodeserver.ts +++ /dev/null @@ -1,220 +0,0 @@ -import http from "http" -import url from "url" -import fs from "fs" -import escape from "escape-html" -import axios from "axios" -import zlib from "zlib" -import readline from "readline" - -const server = http.createServer((req, res) => { - if (!req.url) { - res.end("Invalid request") - return - } - - const parsedUrl = url.parse(req.url, true) - const queryData = parsedUrl.query - - if (req.url.startsWith("/DaysBetweenDates")) { - const date1 = queryData.date1 as string - const date2 = queryData.date2 as string - - const date1_ms = Date.parse(date1) - const date2_ms = Date.parse(date2) - - const difference_ms = date2_ms - date1_ms - - res.end(Math.round(difference_ms / 86400000) + " days") - } else if (req.url.startsWith("/Validatephonenumber")) { - const phoneNumber = queryData.phoneNumber as string - - const regex = /^(\+34|0034|34)?[ -]*(6|7)[ -]*([0-9][ -]*){8}$/ - - if (regex.test(phoneNumber)) { - res.end("valid") - } else { - res.end("invalid") - } - } else if (req.url.startsWith("/ValidateSpanishDNI")) { - const dni = queryData.dni as string - - const dniLetter = dni.charAt(dni.length - 1) - const dniNumber = parseInt(dni.substring(0, dni.length - 1), 10) - const dniLetterCalc = "TRWAGMYFPDXBNJZSQVHLCKE".charAt(dniNumber % 23) - - if (dniLetter === dniLetterCalc) { - res.end("valid") - } else { - res.end("invalid") - } - } else if (req.url.startsWith("/ReturnColorCode")) { - const colors = fs.readFileSync("colors.json", "utf-8") - const colorsObj = JSON.parse(colors) - - const color = queryData.color as string - let colorFound = "not found" - - for (let i = 0; i < colorsObj.length; i++) { - if (colorsObj[i].color === color) { - colorFound = colorsObj[i].code.hex - break - } - } - - res.end(colorFound) - } else if (req.url.startsWith("/SendEmail")) { - // Implementation for SendEmail - } else if (req.url.startsWith("/TellMeAJoke")) { - axios - .get("https://official-joke-api.appspot.com/random_joke") - .then((response) => { - res.end(response.data.setup + " " + response.data.punchline) - }) - .catch((error) => { - console.log(error) - }) - } else if (req.url.startsWith("/MoviesByDirector")) { - const director = queryData.director as string - - axios - .get(`http://www.omdbapi.com/?apikey=XXXXXXX&s=${director}`) - .then((response) => { - let movies = "" - for (let i = 0; i < response.data.Search.length; i++) { - movies += response.data.Search[i].Title + ", " - } - res.end(movies) - }) - .catch((error) => { - console.log(error) - }) - } else if (req.url.startsWith("/ParseUrl")) { - const someUrl = queryData.someurl as string - const urlObj = new URL(someUrl) - - const host = urlObj.host - - res.end("host: " + host) - } else if (req.url.startsWith("/ListFiles")) { - const currentDir = __dirname - const files = fs.readdirSync(currentDir) - - res.end(escape(files.toString())) - } else if (req.url.startsWith("/GetFullTextFile")) { - const text = fs.readFileSync("sample.txt", "utf-8") - const lines = text.split("\r") - - let linesFound = "" - for (let i = 0; i < lines.length; i++) { - if (lines[i].includes("Fusce")) { - linesFound += lines[i] + ", " - } - } - - res.end(linesFound) - } else if (req.url.startsWith("/GetLineByLinefromtTextFile")) { - const lineReader = readline.createInterface({ - input: fs.createReadStream("sample.txt"), - }) - - const promise = new Promise((resolve, reject) => { - const lines: string[] = [] - lineReader.on("line", (line: string) => { - if (line.includes("Fusce")) { - lines.push(line) - } - }) - lineReader.on("close", () => { - resolve(lines) - }) - }) - - promise.then((lines) => { - res.end(lines.toString()) - }) - } else if (req.url.startsWith("/CalculateMemoryConsumption")) { - const memory = process.memoryUsage().heapUsed / 1024 / 1024 - - res.end(memory.toFixed(2) + " GB") - } else if (req.url.startsWith("/MakeZipFile")) { - const gzip = zlib.createGzip() - const input = fs.createReadStream("sample.txt") - const output = fs.createWriteStream("sample.gz") - - input.pipe(gzip).pipe(output) - - res.end("sample.gz created") - } else if (req.url.startsWith("/RandomEuropeanCountry")) { - const countries = [ - { country: "Italy", iso: "IT" }, - { country: "France", iso: "FR" }, - { country: "Spain", iso: "ES" }, - { country: "Germany", iso: "DE" }, - { country: "United Kingdom", iso: "GB" }, - { country: "Greece", iso: "GR" }, - { country: "Portugal", iso: "PT" }, - { country: "Romania", iso: "RO" }, - { country: "Bulgaria", iso: "BG" }, - { country: "Croatia", iso: "HR" }, - { country: "Czech Republic", iso: "CZ" }, - { country: "Denmark", iso: "DK" }, - { country: "Estonia", iso: "EE" }, - { country: "Finland", iso: "FI" }, - { country: "Hungary", iso: "HU" }, - { country: "Ireland", iso: "IE" }, - { country: "Latvia", iso: "LV" }, - { country: "Lithuania", iso: "LT" }, - { country: "Luxembourg", iso: "LU" }, - { country: "Malta", iso: "MT" }, - { country: "Netherlands", iso: "NL" }, - { country: "Poland", iso: "PL" }, - { country: "Slovakia", iso: "SK" }, - { country: "Slovenia", iso: "SI" }, - { country: "Sweden", iso: "SE" }, - { country: "Belgium", iso: "BE" }, - { country: "Austria", iso: "AT" }, - { country: "Switzerland", iso: "CH" }, - { country: "Cyprus", iso: "CY" }, - { country: "Iceland", iso: "IS" }, - { country: "Norway", iso: "NO" }, - { country: "Albania", iso: "AL" }, - { country: "Andorra", iso: "AD" }, - { country: "Armenia", iso: "AM" }, - { country: "Azerbaijan", iso: "AZ" }, - { country: "Belarus", iso: "BY" }, - { country: "Bosnia and Herzegovina", iso: "BA" }, - { country: "Georgia", iso: "GE" }, - { country: "Kazakhstan", iso: "KZ" }, - { country: "Kosovo", iso: "XK" }, - { country: "Liechtenstein", iso: "LI" }, - { country: "Macedonia", iso: "MK" }, - { country: "Moldova", iso: "MD" }, - { country: "Monaco", iso: "MC" }, - { country: "Montenegro", iso: "ME" }, - { country: "Russia", iso: "RU" }, - { country: "San Marino", iso: "SM" }, - { country: "Serbia", iso: "RS" }, - { country: "Turkey", iso: "TR" }, - { country: "Ukraine", iso: "UA" }, - { country: "Vatican City", iso: "VA" }, - ] - - const randomCountry = countries[Math.floor(Math.random() * countries.length)] - - res.end(randomCountry.country + " " + randomCountry.iso) - } else if (req.url.startsWith("/Get")) { - const key = queryData.key as string - - if (!key) { - res.end("key not passed") - } else { - res.end("hello " + escape(key)) - } - } else { - res.end("Called method not found") - } -}) - -server.listen(3000, () => { - console.log("server is listening on port 3000") -}) diff --git a/completesolution/node_typescript/package.json b/completesolution/node_typescript/package.json deleted file mode 100644 index 7da3e48b..00000000 --- a/completesolution/node_typescript/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "nodeserver", - "version": "1.0.0", - "main": "nodeserver.js", - "scripts": { - "build": "tsc", - "start": "node nodeserver.js", - "test": "mocha test.js" - }, - "keywords": [], - "author": "", - "license": "ISC", - "description": "", - "dependencies": { - "axios": "^1.7.7", - "escape-html": "^1.0.3", - "typescript": "^5.6.3" - }, - "devDependencies": { - "@types/escape-html": "^1.0.4", - "@types/mocha": "^10.0.9", - "@types/node": "^22.8.6", - "mocha": "^10.8.2" - } -} diff --git a/completesolution/node_typescript/test.ts b/completesolution/node_typescript/test.ts deleted file mode 100644 index d68e41ff..00000000 --- a/completesolution/node_typescript/test.ts +++ /dev/null @@ -1,215 +0,0 @@ -import * as assert from "assert" -import * as http from "http" -const server = require("./nodeserver") - -describe("Node Server", () => { - it('should return "key not passed" if key is not passed', (done) => { - http.get("http://localhost:3000/Get", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "key not passed") - done() - }) - }) - }) - - it("should return the value of the key if key is found", (done) => { - http.get("http://localhost:3000/Get?key=world", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "hello world") - done() - }) - }) - }) - - it('should return "valid" if phoneNumber is valid', (done) => { - http.get("http://localhost:3000/Validatephonenumber?phoneNumber=34666666666", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "valid") - done() - }) - }) - }) - - it('should return "valid" if spanish DNI 86471508H is valid', (done) => { - http.get("http://localhost:3000/ValidateSpanishDNI?dni=86471508H", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "valid") - done() - }) - }) - }) - - it('should return "valid" if spanish DNI 24153149K is valid', (done) => { - http.get("http://localhost:3000/ValidateSpanishDNI?dni=24153149K", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "valid") - done() - }) - }) - }) - - it('should return "invalid" if spanish DNI 12345678A is invalid', (done) => { - http.get("http://localhost:3000/ValidateSpanishDNI?dni=12345678A", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "invalid") - done() - }) - }) - }) - - it('should return "#FF0000" if color is red', (done) => { - http.get("http://localhost:3000/ReturnColorCode?color=red", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "#FF0000") - done() - }) - }) - }) - - it('should return "1 days" if dates are 2020-01-01 and 2020-01-02', (done) => { - http.get("http://localhost:3000/DaysBetweenDates?date1=2020-01-01&date2=2020-01-02", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "1 days") - done() - }) - }) - }) -}) - -describe("Node Server", () => { - it('should return "key not passed" if key is not passed', (done) => { - http.get("http://localhost:3000/Get", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "key not passed") - done() - }) - }) - }) - - it("should return the value of the key if key is found", (done) => { - http.get("http://localhost:3000/Get?key=world", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "hello world") - done() - }) - }) - }) - - it('should return "valid" if phoneNumber is valid', (done) => { - http.get("http://localhost:3000/Validatephonenumber?phoneNumber=34666666666", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "valid") - done() - }) - }) - }) - - it('should return "valid" if spanish DNI 86471508H is valid', (done) => { - http.get("http://localhost:3000/ValidateSpanishDNI?dni=86471508H", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "valid") - done() - }) - }) - }) - - it('should return "valid" if spanish DNI 24153149K is valid', (done) => { - http.get("http://localhost:3000/ValidateSpanishDNI?dni=24153149K", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "valid") - done() - }) - }) - }) - - it('should return "invalid" if spanish DNI 12345678A is invalid', (done) => { - http.get("http://localhost:3000/ValidateSpanishDNI?dni=12345678A", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "invalid") - done() - }) - }) - }) - - it('should return "#FF0000" if color is red', (done) => { - http.get("http://localhost:3000/ReturnColorCode?color=red", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "#FF0000") - done() - }) - }) - }) - - it('should return "1 days" if dates are 2020-01-01 and 2020-01-02', (done) => { - http.get("http://localhost:3000/DaysBetweenDates?date1=2020-01-01&date2=2020-01-02", (res: http.IncomingMessage) => { - let data = "" - res.on("data", (chunk: string) => { - data += chunk - }) - res.on("end", () => { - assert.strictEqual(data, "1 days") - done() - }) - }) - }) -}) diff --git a/completesolution/node_typescript/tsconfig.json b/completesolution/node_typescript/tsconfig.json deleted file mode 100644 index 56a8ab81..00000000 --- a/completesolution/node_typescript/tsconfig.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } -} diff --git a/completesolution/quarkus/README.md b/completesolution/quarkus/README.md deleted file mode 100644 index 2ae464d5..00000000 --- a/completesolution/quarkus/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# Quarkus REST API Exercise - -## Goal - -The goal of this exercise is to learn how to use GitHub Copilot, using an exercise that consist of building a REST API using [Quarkus](https://quarkus.io/). - -## Exercises - -We have created a Quarkus project with some files already created, you can find the project in the folder **exercisefiles/quarkus**. - -Let's start copiloting!!! - -### 1. Create the code to handle a simple GET request - -Move to the 'DemoResource.java' file and start writing the code to handle a simple GET request. In this first exercise, we have provided a comment that describes the code you need to generate. Just press enter and wait a couple of seconds, Copilot will generate the code for you. If you are not happy with the code generated, you can press enter again and Copilot will generate a new code - -There is already a unit test implemented for this exercise, you can run it using the command `mvn test` before and after to validate that the code generated by Copilot is correct. - -Then, create a new unit test for the case when no key is provided in the request. - -After every exercise, feel free to package and run your application to test it. - -Package: `mvn package` - -Run: `mvn quarkus:dev` - -Test: `curl -v http://localhost:8080/hello?key=world` - -### 2. Dates comparison - -New operation under /diffdates that calculates the difference between two dates. The operation should receive two dates as parameter in format dd-MM-yyyy and return the difference in days. - -Additionally, create a unit test that validates the operation. - -From now on, you will have to create the unit tests for every new operation. Wasn't it easy with Copilot? - -### 3. Validate the format of a spanish phone - -Validate the format of a spanish phone number (+34 prefix, then 9 digits, starting with 6, 7 or 9). The operation should receive a phone number as parameter and return true if the format is correct, false otherwise. - -### 4. Validate the format of a spanish DNI - -Validate the format of a spanish DNI (8 digits and 1 letter). The operation should receive a DNI as parameter and return true if the format is correct, false otherwise. - -### 5. From color name to hexadecimal code - -Based on existing colors.json file under resources, given the name of the color as path parameter, return the hexadecimal code. If the color is not found, return 404 - -Hint: Use TDD. Start by creating the unit test and then implement the code. - -### 6. Jokes creator - -Create a new operation that call the API https://api.chucknorris.io/jokes/random and return the joke. - -### 7. URL parsing - -Given a url as query parameter, parse it and return the protocol, host, port, path and query parameters. The response should be in Json format. - -### 8. List files and folders - -List files and folders under a given path. The path should be a query parameter. The response should be in Json format. - -### 9. Word counting - -Given the path of a file and count the number of occurrence of a provided word. The path and the word should be query parameters. The response should be in Json format. - -### 10. Zipping - -Create a zip file with the content of a given folder. The path of the folder should be a query parameter. - -### 11. Containerize the application - -Use the Dockerfile provided to create a docker image of the application. In this case, the full content is provided, but in order build, run and test the docker image, you will use Copilot as well to generate the commands. - -I have created a DOCKER.md file where we will document the steps to build the application (native), build the container image, yun the container and test the container. - - - - - - - - - - diff --git a/completesolution/quarkus/copilot-demo/.dockerignore b/completesolution/quarkus/copilot-demo/.dockerignore deleted file mode 100644 index 94810d00..00000000 --- a/completesolution/quarkus/copilot-demo/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -* -!target/*-runner -!target/*-runner.jar -!target/lib/* -!target/quarkus-app/* \ No newline at end of file diff --git a/completesolution/quarkus/copilot-demo/.gitignore b/completesolution/quarkus/copilot-demo/.gitignore deleted file mode 100644 index 8c7863e7..00000000 --- a/completesolution/quarkus/copilot-demo/.gitignore +++ /dev/null @@ -1,43 +0,0 @@ -#Maven -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -release.properties -.flattened-pom.xml - -# Eclipse -.project -.classpath -.settings/ -bin/ - -# IntelliJ -.idea -*.ipr -*.iml -*.iws - -# NetBeans -nb-configuration.xml - -# Visual Studio Code -.vscode -.factorypath - -# OSX -.DS_Store - -# Vim -*.swp -*.swo - -# patch -*.orig -*.rej - -# Local environment -.env - -# Plugin directory -/.quarkus/cli/plugins/ diff --git a/completesolution/quarkus/copilot-demo/.mvn/wrapper/.gitignore b/completesolution/quarkus/copilot-demo/.mvn/wrapper/.gitignore deleted file mode 100644 index e72f5e8b..00000000 --- a/completesolution/quarkus/copilot-demo/.mvn/wrapper/.gitignore +++ /dev/null @@ -1 +0,0 @@ -maven-wrapper.jar diff --git a/completesolution/quarkus/copilot-demo/.mvn/wrapper/MavenWrapperDownloader.java b/completesolution/quarkus/copilot-demo/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index 84d1e60d..00000000 --- a/completesolution/quarkus/copilot-demo/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import java.io.IOException; -import java.io.InputStream; -import java.net.Authenticator; -import java.net.PasswordAuthentication; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; - -public final class MavenWrapperDownloader -{ - private static final String WRAPPER_VERSION = "3.2.0"; - - private static final boolean VERBOSE = Boolean.parseBoolean( System.getenv( "MVNW_VERBOSE" ) ); - - public static void main( String[] args ) - { - log( "Apache Maven Wrapper Downloader " + WRAPPER_VERSION ); - - if ( args.length != 2 ) - { - System.err.println( " - ERROR wrapperUrl or wrapperJarPath parameter missing" ); - System.exit( 1 ); - } - - try - { - log( " - Downloader started" ); - final URL wrapperUrl = new URL( args[0] ); - final String jarPath = args[1].replace( "..", "" ); // Sanitize path - final Path wrapperJarPath = Paths.get( jarPath ).toAbsolutePath().normalize(); - downloadFileFromURL( wrapperUrl, wrapperJarPath ); - log( "Done" ); - } - catch ( IOException e ) - { - System.err.println( "- Error downloading: " + e.getMessage() ); - if ( VERBOSE ) - { - e.printStackTrace(); - } - System.exit( 1 ); - } - } - - private static void downloadFileFromURL( URL wrapperUrl, Path wrapperJarPath ) - throws IOException - { - log( " - Downloading to: " + wrapperJarPath ); - if ( System.getenv( "MVNW_USERNAME" ) != null && System.getenv( "MVNW_PASSWORD" ) != null ) - { - final String username = System.getenv( "MVNW_USERNAME" ); - final char[] password = System.getenv( "MVNW_PASSWORD" ).toCharArray(); - Authenticator.setDefault( new Authenticator() - { - @Override - protected PasswordAuthentication getPasswordAuthentication() - { - return new PasswordAuthentication( username, password ); - } - } ); - } - try ( InputStream inStream = wrapperUrl.openStream() ) - { - Files.copy( inStream, wrapperJarPath, StandardCopyOption.REPLACE_EXISTING ); - } - log( " - Downloader complete" ); - } - - private static void log( String msg ) - { - if ( VERBOSE ) - { - System.out.println( msg ); - } - } - -} diff --git a/completesolution/quarkus/copilot-demo/.mvn/wrapper/maven-wrapper.properties b/completesolution/quarkus/copilot-demo/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 70f4f50f..00000000 --- a/completesolution/quarkus/copilot-demo/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.8/apache-maven-3.8.8-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/completesolution/quarkus/copilot-demo/DOCKER.md b/completesolution/quarkus/copilot-demo/DOCKER.md deleted file mode 100644 index 67c8d517..00000000 --- a/completesolution/quarkus/copilot-demo/DOCKER.md +++ /dev/null @@ -1,26 +0,0 @@ -# Build a Quarkus native image - -## Build the native executable - -```bash -mvn clean package -Pnative -``` - -## Build the docker image using the Dockerfile.native-micro - -```bash -docker build -f Dockerfile.native-micro -t quarkus/quarkus-native-micro . -``` - -## Run the docker image - -```bash -docker run -i --rm -p 8080:8080 quarkus/quarkus-native-micro -``` - -## Test the application - -```bash -curl -v http://localhost:8080/hello -``` - diff --git a/completesolution/quarkus/copilot-demo/Dockerfile.native-micro b/completesolution/quarkus/copilot-demo/Dockerfile.native-micro deleted file mode 100644 index 1807ff8b..00000000 --- a/completesolution/quarkus/copilot-demo/Dockerfile.native-micro +++ /dev/null @@ -1,16 +0,0 @@ -#### -# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode. -# It uses a micro base image, tuned for Quarkus native executables. -# -### -FROM quay.io/quarkus/quarkus-micro-image:2.0 -WORKDIR /work/ -RUN chown 1001 /work \ - && chmod "g+rwX" /work \ - && chown 1001:root /work -COPY --chown=1001:root target/*-runner /work/application - -EXPOSE 8080 -USER 1001 - -CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] diff --git a/completesolution/quarkus/copilot-demo/mvnw b/completesolution/quarkus/copilot-demo/mvnw deleted file mode 100644 index 8d937f4c..00000000 --- a/completesolution/quarkus/copilot-demo/mvnw +++ /dev/null @@ -1,308 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.2.0 -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "$(uname)" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME - else - JAVA_HOME="/Library/Java/Home"; export JAVA_HOME - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --unix "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --unix "$CLASSPATH") -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && - JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="$(which javac)" - if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=$(which readlink) - if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then - if $darwin ; then - javaHome="$(dirname "\"$javaExecutable\"")" - javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" - else - javaExecutable="$(readlink -f "\"$javaExecutable\"")" - fi - javaHome="$(dirname "\"$javaExecutable\"")" - javaHome=$(expr "$javaHome" : '\(.*\)/bin') - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=$(cd "$wdir/.." || exit 1; pwd) - fi - # end of workaround - done - printf '%s' "$(cd "$basedir" || exit 1; pwd)" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - # Remove \r in case we run on Windows within Git Bash - # and check out the repository with auto CRLF management - # enabled. Otherwise, we may read lines that are delimited with - # \r\n and produce $'-Xarg\r' rather than -Xarg due to word - # splitting rules. - tr -s '\r\n' ' ' < "$1" - fi -} - -log() { - if [ "$MVNW_VERBOSE" = true ]; then - printf '%s\n' "$1" - fi -} - -BASE_DIR=$(find_maven_basedir "$(dirname "$0")") -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR -log "$MAVEN_PROJECTBASEDIR" - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" -if [ -r "$wrapperJarPath" ]; then - log "Found $wrapperJarPath" -else - log "Couldn't find $wrapperJarPath, downloading it ..." - - if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - fi - while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') - case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; - esac - done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" - log "Downloading from: $wrapperUrl" - - if $cygwin; then - wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") - fi - - if command -v wget > /dev/null; then - log "Found wget ... using wget" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - log "Found curl ... using curl" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - fi - else - log "Falling back to using Java to download" - javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" - javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaSource=$(cygpath --path --windows "$javaSource") - javaClass=$(cygpath --path --windows "$javaClass") - fi - if [ -e "$javaSource" ]; then - if [ ! -e "$javaClass" ]; then - log " - Compiling MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/javac" "$javaSource") - fi - if [ -e "$javaClass" ]; then - log " - Running MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -# If specified, validate the SHA-256 sum of the Maven wrapper jar file -wrapperSha256Sum="" -while IFS="=" read -r key value; do - case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; - esac -done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" -if [ -n "$wrapperSha256Sum" ]; then - wrapperSha256Result=false - if command -v sha256sum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - elif command -v shasum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." - echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." - exit 1 - fi - if [ $wrapperSha256Result = false ]; then - echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 - echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 - echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 - exit 1 - fi -fi - -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --windows "$CLASSPATH") - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -# shellcheck disable=SC2086 # safe args -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/completesolution/quarkus/copilot-demo/mvnw.cmd b/completesolution/quarkus/copilot-demo/mvnw.cmd deleted file mode 100644 index c4586b56..00000000 --- a/completesolution/quarkus/copilot-demo/mvnw.cmd +++ /dev/null @@ -1,205 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/completesolution/quarkus/copilot-demo/pom.xml b/completesolution/quarkus/copilot-demo/pom.xml deleted file mode 100644 index 690d6632..00000000 --- a/completesolution/quarkus/copilot-demo/pom.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - 4.0.0 - com.microsoft.hackathon.quarkus - copilot-demo - 1.0.0-SNAPSHOT - - 3.11.0 - 17 - UTF-8 - UTF-8 - quarkus-bom - io.quarkus.platform - 3.2.0.Final - true - 3.0.0 - - - - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - - - - - - io.quarkus - quarkus-resteasy - - - io.quarkus - quarkus-arc - - - io.quarkus - quarkus-rest-client - - - io.quarkus - quarkus-rest-client-jackson - - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - - - - - - ${quarkus.platform.group-id} - quarkus-maven-plugin - ${quarkus.platform.version} - true - - - - build - generate-code - generate-code-tests - - - - - - maven-compiler-plugin - ${compiler-plugin.version} - - - -parameters - - - - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - ${maven.home} - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - ${project.build.directory}/${project.build.finalName}-runner - org.jboss.logmanager.LogManager - ${maven.home} - - - - - - - - - - native - - - native - - - - false - native - - - - diff --git a/completesolution/quarkus/copilot-demo/src/main/java/com/microsoft/hackathon/quarkus/DemoResource.java b/completesolution/quarkus/copilot-demo/src/main/java/com/microsoft/hackathon/quarkus/DemoResource.java deleted file mode 100644 index e1600162..00000000 --- a/completesolution/quarkus/copilot-demo/src/main/java/com/microsoft/hackathon/quarkus/DemoResource.java +++ /dev/null @@ -1,282 +0,0 @@ -package com.microsoft.hackathon.quarkus; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Objects; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import io.quarkus.fs.util.ZipUtils; - - - - - -/* -* The Demo resource should be mapped to the root path. -* -* Create a GET operation to return the value of a key passed as query parameter in the request. -* -* If the key is not passed, return "key not passed". -* If the key is passed, return "hello ". -* -*/ - -@Path("/") -public class DemoResource { - - @GET - @Path("/hello") - @Produces(MediaType.TEXT_PLAIN) - public String hello(@QueryParam("key") String key) { - if (key == null) { - return "key not passed"; - } else { - return "hello " + key; - } - } - - // New operation under /diffdates that calculates the difference between two dates. The operation should receive two dates as parameter in format dd-MM-yyyy and return the difference in days. - - @GET - @Path("/diffdates") - @Produces(MediaType.TEXT_PLAIN) - public String diffdates(@QueryParam("date1") String date1, @QueryParam("date2") String date2) { - Objects.requireNonNull(date1, "date1 must not be null"); - Objects.requireNonNull(date2, "date2 must not be null"); - - try { - SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); - Date date1Obj = dateFormat.parse(date1); - Date date2Obj = dateFormat.parse(date2); - long diffMillis = Math.abs(date1Obj.getTime() - date2Obj.getTime()); - long diffDays = diffMillis / (24 * 60 * 60 * 1000); - return String.valueOf(diffDays); - } catch (Exception e) { - return "invalid date format"; - } - } - - // Validate the format of a spanish phone number (+34 prefix, then 9 digits, starting with 6, 7 or 9). The operation should receive a phone number as parameter and return true if the format is correct, false otherwise. - - @GET - @Path("/validatephone") - @Produces(MediaType.TEXT_PLAIN) - public boolean validatephone(@QueryParam("phone") String phone) { - Objects.requireNonNull(phone, "phone must not be null"); - if (!phone.matches("\\+34[679]\\d{8}")) { - return false; - } - - return true; - } - - // Validate the format of a spanish DNI (8 digits and 1 letter). The operation should receive a DNI as parameter and return true if the format is correct, false otherwise. - - @GET - @Path("/validatedni") - @Produces(MediaType.TEXT_PLAIN) - public boolean validatedni(@QueryParam("dni") String dni) { - Objects.requireNonNull(dni, "dni must not be null"); - - if (!dni.matches("\\d{8}[A-Z]")) { - return false; - } - - return true; - } - - // Based on existing colors.json file under resources, given the name of the color as path parameter, return the hexadecimal code. If the color is not found, return 404 - - @GET - @Path("/hexcolor") - @Produces(MediaType.TEXT_PLAIN) - public Response color(@QueryParam("name") String name) { - Objects.requireNonNull(name, "name must not be null"); - ObjectMapper mapper = new ObjectMapper(); - try { - InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("colors.json"); - JsonNode root = mapper.readTree(inputStream); - for (JsonNode color : root) { - if (color.get("color").asText().equals(name)) { - ObjectNode code = (ObjectNode) color.get("code"); - return Response.ok(code.get("hex").asText()).build(); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - // return http 404 - return Response.status(Response.Status.NOT_FOUND).build(); - } - - - // Create a new operation that call the API https://api.chucknorris.io/jokes/random and return the joke. - - @GET - @Path("/chucknorris") - @Produces(MediaType.TEXT_PLAIN) - public String chucknorris() { - // create a new instance of the Resteasy client - Client client = ClientBuilder.newClient(); - // create a new target - WebTarget target = client.target("https://api.chucknorris.io/jokes/random"); - // send the request and get the response - Response response = target.request(MediaType.APPLICATION_JSON).get(); - // parse the response - ObjectMapper mapper = new ObjectMapper(); - try { - JsonNode root = mapper.readTree(response.readEntity(String.class)); - return root.get("value").asText(); - } catch (IOException e) { - e.printStackTrace(); - } - return "error"; - } - - // Given a url as query parameter, parse it and return the protocol, host, port, path and query parameters. The response should be in Json format. - - @GET - @Path("/parseurl") - @Produces(MediaType.APPLICATION_JSON) - public Response parseurl(@QueryParam("url") String url) { - Objects.requireNonNull(url, "url must not be null"); - ObjectMapper mapper = new ObjectMapper(); - try { - URL urlNode = new URL(url); - JsonNode root = mapper.createObjectNode(); - ((ObjectNode) root).put("protocol", urlNode.getProtocol()); - ((ObjectNode) root).put("host", urlNode.getHost()); - ((ObjectNode) root).put("port", urlNode.getPort()); - ((ObjectNode) root).put("path", urlNode.getPath()); - ((ObjectNode) root).put("query", urlNode.getQuery()); - return Response.ok(root).build(); - } catch (IOException e) { - e.printStackTrace(); - } - // return http 500 - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - - // List files and folders under a given path. The path should be a query parameter. The response should be in Json format. - - @GET - @Path("/listfiles") - @Produces(MediaType.APPLICATION_JSON) - public Response listfiles(@QueryParam("path") String path) { - Objects.requireNonNull(path, "path must not be null"); - if (path.contains("..") || path.contains("/") || path.contains("\\")) { - throw new IllegalArgumentException("Invalid path"); - } - ObjectMapper mapper = new ObjectMapper(); - try { - List fileList = new ArrayList<>(); - Files.walk(Paths.get(path)) - .forEach(file -> { - ObjectNode fileNode = mapper.createObjectNode(); - fileNode.put("path", file.toString()); - fileNode.put("isDirectory", file.toFile().isDirectory()); - fileList.add(fileNode); - }); - - return Response.ok(fileList).build(); - } catch (Exception e) { - e.printStackTrace(); - } - // return http 500 - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - - // Given the path of a file and count the number of occurrence of a provided word. The path and the word should be query parameters. The response should be in Json format. - - @GET - @Path("/countword") - @Produces(MediaType.APPLICATION_JSON) - public Response countWord(@QueryParam("path") String path, @QueryParam("word") String word) { - Objects.requireNonNull(path, "path must not be null"); - Objects.requireNonNull(word, "word must not be null"); - if (path.contains("..") || path.contains("/") || path.contains("\\")) { - throw new IllegalArgumentException("Invalid path"); - } - java.nio.file.Path filePath = Paths.get(path); - String content; - int count = 0; - try { - content = Files.readString(filePath); - String[] words = content.split("\\s+"); - for (String w : words) { - if (w.equals(word)) { - count++; - } - } - } catch (IOException e) { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - - ObjectMapper mapper = new ObjectMapper(); - ObjectNode responseNode = mapper.createObjectNode(); - responseNode.put("count", count); - return Response.ok(responseNode).build(); - } - - // Create a zip file with the content of a given folder. The path of the folder should be a query parameter. - - @GET - @Path("/zipfolder") - @Produces(MediaType.APPLICATION_OCTET_STREAM) - public Response zipFolder(@QueryParam("path") String path) { - Objects.requireNonNull(path, "path must not be null"); - if (path.contains("..") || path.contains("/") || path.contains("\\")) { - throw new IllegalArgumentException("Invalid path"); - } - java.nio.file.Path folderPath = Paths.get(path); - File folder = folderPath.toFile(); - if (!folder.exists()) { - return Response.status(Response.Status.NOT_FOUND).build(); - } - if (!folder.isDirectory()) { - return Response.status(Response.Status.BAD_REQUEST).build(); - } - try { - // create a zip file from the folder - java.nio.file.Path zipPath = folderPath.getParent().resolve(folderPath.getFileName() + ".zip"); - ZipUtils.zip(folderPath, zipPath); - // return the zip file - InputStream inputStream = new FileInputStream(zipPath.toFile()); - Response.ResponseBuilder response = Response.ok(inputStream); - response.type("application/zip"); - response.header("Content-Disposition", "attachment; filename=\"" + folderPath.getFileName() + ".zip\""); - // remove the zip file - Files.delete(zipPath); - return response.build(); - } catch (IOException e) { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); - } - } - -} - - - - diff --git a/completesolution/quarkus/copilot-demo/src/main/resources/META-INF/resources/colors.json b/completesolution/quarkus/copilot-demo/src/main/resources/META-INF/resources/colors.json deleted file mode 100644 index 9d8e8adb..00000000 --- a/completesolution/quarkus/copilot-demo/src/main/resources/META-INF/resources/colors.json +++ /dev/null @@ -1,56 +0,0 @@ - [ - { - "color": "black", - "category": "hue", - "type": "primary", - "code": { - "rgba": [0,0,0,1], - "hex": "#000000" - } - }, - { - "color": "white", - "category": "value", - "code": { - "rgba": [255,255,255,1], - "hex": "#FFFFFF" - } - }, - { - "color": "red", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,0,0,1], - "hex": "#FF0000" - } - }, - { - "color": "blue", - "category": "hue", - "type": "primary", - "code": { - "rgba": [0,0,255,1], - "hex": "#0000FF" - } - }, - { - "color": "yellow", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,255,0,1], - "hex": "#FFFF00" - } - }, - { - "color": "green", - "category": "hue", - "type": "secondary", - "code": { - "rgba": [0,255,0,1], - "hex": "#00FF00" - } - } - ] - \ No newline at end of file diff --git a/completesolution/quarkus/copilot-demo/src/main/resources/META-INF/resources/index.html b/completesolution/quarkus/copilot-demo/src/main/resources/META-INF/resources/index.html deleted file mode 100644 index 98c539e7..00000000 --- a/completesolution/quarkus/copilot-demo/src/main/resources/META-INF/resources/index.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - copilot-demo - 1.0.0-SNAPSHOT - - - -
-
-
- - - - - quarkus_logo_horizontal_rgb_1280px_reverse - - - - - - - - - - - - - - - - - - -
-
-
- -
-
-
-

You just made a Quarkus application.

-

This page is served by Quarkus.

- Visit the Dev UI -

This page: src/main/resources/META-INF/resources/index.html

-

App configuration: src/main/resources/application.properties

-

Static assets: src/main/resources/META-INF/resources/

-

Code: src/main/java

-

Dev UI V1: /q/dev-v1

-

Generated starter code:

-
    -
  • - RESTEasy JAX-RS Easily start your RESTful Web Services -
    @Path: /hello -
    Related guide -
  • - -
-
-
-

Selected extensions

-
    -
  • RESTEasy Classic (guide)
  • -
-
Documentation
-

Practical step-by-step guides to help you achieve a specific goal. Use them to help get your work - done.

-
Set up your IDE
-

Everyone has a favorite IDE they like to use to code. Learn how to configure yours to maximize your - Quarkus productivity.

-
-
-
- - diff --git a/completesolution/quarkus/copilot-demo/src/main/resources/application.properties b/completesolution/quarkus/copilot-demo/src/main/resources/application.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/completesolution/quarkus/copilot-demo/src/main/resources/colors.json b/completesolution/quarkus/copilot-demo/src/main/resources/colors.json deleted file mode 100644 index 9d8e8adb..00000000 --- a/completesolution/quarkus/copilot-demo/src/main/resources/colors.json +++ /dev/null @@ -1,56 +0,0 @@ - [ - { - "color": "black", - "category": "hue", - "type": "primary", - "code": { - "rgba": [0,0,0,1], - "hex": "#000000" - } - }, - { - "color": "white", - "category": "value", - "code": { - "rgba": [255,255,255,1], - "hex": "#FFFFFF" - } - }, - { - "color": "red", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,0,0,1], - "hex": "#FF0000" - } - }, - { - "color": "blue", - "category": "hue", - "type": "primary", - "code": { - "rgba": [0,0,255,1], - "hex": "#0000FF" - } - }, - { - "color": "yellow", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,255,0,1], - "hex": "#FFFF00" - } - }, - { - "color": "green", - "category": "hue", - "type": "secondary", - "code": { - "rgba": [0,255,0,1], - "hex": "#00FF00" - } - } - ] - \ No newline at end of file diff --git a/completesolution/quarkus/copilot-demo/src/test/java/com/microsoft/hackathon/quarkus/DemoResourceIT.java b/completesolution/quarkus/copilot-demo/src/test/java/com/microsoft/hackathon/quarkus/DemoResourceIT.java deleted file mode 100644 index 9b7c5307..00000000 --- a/completesolution/quarkus/copilot-demo/src/test/java/com/microsoft/hackathon/quarkus/DemoResourceIT.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.microsoft.hackathon.quarkus; - -import io.quarkus.test.junit.QuarkusIntegrationTest; - -@QuarkusIntegrationTest -public class DemoResourceIT extends DemoResourceTest { - // Execute the same tests but in packaged mode. -} diff --git a/completesolution/quarkus/copilot-demo/src/test/java/com/microsoft/hackathon/quarkus/DemoResourceTest.java b/completesolution/quarkus/copilot-demo/src/test/java/com/microsoft/hackathon/quarkus/DemoResourceTest.java deleted file mode 100644 index 31a9e3d7..00000000 --- a/completesolution/quarkus/copilot-demo/src/test/java/com/microsoft/hackathon/quarkus/DemoResourceTest.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.microsoft.hackathon.quarkus; - -import io.quarkus.test.junit.QuarkusTest; -import org.junit.jupiter.api.Test; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.CoreMatchers.is; - -@QuarkusTest -public class DemoResourceTest { - - @Test - public void testHelloEndpoint() { - given() - .when().get("/hello?key=world") - .then() - .statusCode(200) - .body(is("hello world")); - } - - @Test - public void testHelloEndpointNoKey() { - given() - .when().get("/hello") - .then() - .statusCode(200) - .body(is("key not passed")); - } - - @Test - public void testDiffDatesEndpoint() { - given() - .when().get("/diffdates?date1=01-01-2021&date2=01-02-2021") - .then() - .statusCode(200) - .body(is("31")); - } - - @Test - public void testDiffDatesEndpointInvalidDate() { - given() - .when().get("/diffdates?date1=01-01201&date2=01-02-2021") - .then() - .statusCode(200) - .body(is("invalid date format")); - } - - @Test - public void testDiffDatesEndpointNoDate1() { - given() - .when().get("/diffdates?date2=01-02-2021") - .then() - .statusCode(500); - } - - @Test - public void testDiffDatesEndpointNoDate2() { - given() - .when().get("/diffdates?date1=01-02-2021") - .then() - .statusCode(500); - } - - @Test - public void testDiffDatesEndpointNoDates() { - given() - .when().get("/diffdates") - .then() - .statusCode(500); - } - - @Test - public void testValidatePhoneEndpoint() { - given() - .when().get("/validatephone?phone=+34666666666") - .then() - .statusCode(200) - .body(is("true")); - - given() - .when().get("/validatephone?phone=+34766666666") - .then() - .statusCode(200) - .body(is("true")); - - given() - .when().get("/validatephone?phone=+34966666666") - .then() - .statusCode(200) - .body(is("true")); - } - - @Test - public void testValidatePhoneEndpointInvalidPhone() { - given() - .when().get("/validatephone?phone=+3466666666") - .then() - .statusCode(200) - .body(is("false")); - } - - @Test - public void testValidatePhoneEndpointNoPhone() { - given() - .when().get("/validatephone") - .then() - .statusCode(500); - } - - - @Test - public void testValidatePhoneEndpointNoPrefix() { - given() - .when().get("/validatephone?phone=666666666") - .then() - .statusCode(200) - .body(is("false")); - } - - @Test - public void testValidateDNIEndpoint () { - given() - .when().get("/validatedni?dni=12345678Z") - .then() - .statusCode(200) - .body(is("true")); - } - - @Test - public void testValidateDNIEndpointInvalidDNI () { - given() - .when().get("/validatedni?dni=12345678") - .then() - .statusCode(200) - .body(is("false")); - } - - @Test - public void testValidateDNIEndpointNoDNI () { - given() - .when().get("/validatedni") - .then() - .statusCode(500); - } - - @Test - public void testGetHexColorEndpoint () { - given() - .when().get("/hexcolor?name=red") - .then() - .statusCode(200) - .body(is("#FF0000")); - } - - @Test - public void testGetHexColorEndpointInvalidColor () { - given() - .when().get("/hexcolor?name=red1") - .then() - .statusCode(404); - } - - @Test - public void testGetHexColorEndpointNoColor () { - given() - .when().get("/hexcolor") - .then() - .statusCode(500); - } - - @Test - public void testChuckNorrisEndpoint () { - given() - .when().get("/chucknorris") - .then() - .statusCode(200); - } - - @Test - public void testParseUrlEndpoint () { - given() - .when().get("/parseurl?url=https://learn.microsoft.com/en-us/azure/aks/concepts-clusters-workloads?source=recommendations") - .then() - .statusCode(200) - .body("protocol", is("https")) - .body("host", is("learn.microsoft.com")) - .body("port", is(-1)) - .body("path", is("/en-us/azure/aks/concepts-clusters-workloads")) - .body("query", is("source=recommendations")); - } - - @Test - public void testParseUrlEndpointNoUrl () { - given() - .when().get("/parseurl") - .then() - .statusCode(500); - } - -} \ No newline at end of file diff --git a/completesolution/springboot/copilot-demo/.gitignore b/completesolution/springboot/copilot-demo/.gitignore deleted file mode 100644 index 549e00a2..00000000 --- a/completesolution/springboot/copilot-demo/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ diff --git a/completesolution/springboot/copilot-demo/.mvn/wrapper/maven-wrapper.jar b/completesolution/springboot/copilot-demo/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index cb28b0e3..00000000 Binary files a/completesolution/springboot/copilot-demo/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/completesolution/springboot/copilot-demo/.mvn/wrapper/maven-wrapper.properties b/completesolution/springboot/copilot-demo/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index b27a13f1..00000000 --- a/completesolution/springboot/copilot-demo/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,2 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/completesolution/springboot/copilot-demo/Dockerfile b/completesolution/springboot/copilot-demo/Dockerfile deleted file mode 100644 index f83e60ae..00000000 --- a/completesolution/springboot/copilot-demo/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -# Build a java application image based on openjdk 17 and run it on port 8080 -FROM openjdk:17-jdk-alpine -EXPOSE 8080 -COPY target/*.jar app.jar -ENTRYPOINT ["java","-jar","/app.jar"] \ No newline at end of file diff --git a/completesolution/springboot/copilot-demo/mvnw b/completesolution/springboot/copilot-demo/mvnw deleted file mode 100644 index 66df2854..00000000 --- a/completesolution/springboot/copilot-demo/mvnw +++ /dev/null @@ -1,308 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.2.0 -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "$(uname)" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME - else - JAVA_HOME="/Library/Java/Home"; export JAVA_HOME - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --unix "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --unix "$CLASSPATH") -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && - JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="$(which javac)" - if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=$(which readlink) - if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then - if $darwin ; then - javaHome="$(dirname "\"$javaExecutable\"")" - javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" - else - javaExecutable="$(readlink -f "\"$javaExecutable\"")" - fi - javaHome="$(dirname "\"$javaExecutable\"")" - javaHome=$(expr "$javaHome" : '\(.*\)/bin') - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=$(cd "$wdir/.." || exit 1; pwd) - fi - # end of workaround - done - printf '%s' "$(cd "$basedir" || exit 1; pwd)" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - # Remove \r in case we run on Windows within Git Bash - # and check out the repository with auto CRLF management - # enabled. Otherwise, we may read lines that are delimited with - # \r\n and produce $'-Xarg\r' rather than -Xarg due to word - # splitting rules. - tr -s '\r\n' ' ' < "$1" - fi -} - -log() { - if [ "$MVNW_VERBOSE" = true ]; then - printf '%s\n' "$1" - fi -} - -BASE_DIR=$(find_maven_basedir "$(dirname "$0")") -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR -log "$MAVEN_PROJECTBASEDIR" - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" -if [ -r "$wrapperJarPath" ]; then - log "Found $wrapperJarPath" -else - log "Couldn't find $wrapperJarPath, downloading it ..." - - if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - fi - while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') - case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; - esac - done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" - log "Downloading from: $wrapperUrl" - - if $cygwin; then - wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") - fi - - if command -v wget > /dev/null; then - log "Found wget ... using wget" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - log "Found curl ... using curl" - [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" - fi - else - log "Falling back to using Java to download" - javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" - javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaSource=$(cygpath --path --windows "$javaSource") - javaClass=$(cygpath --path --windows "$javaClass") - fi - if [ -e "$javaSource" ]; then - if [ ! -e "$javaClass" ]; then - log " - Compiling MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/javac" "$javaSource") - fi - if [ -e "$javaClass" ]; then - log " - Running MavenWrapperDownloader.java ..." - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -# If specified, validate the SHA-256 sum of the Maven wrapper jar file -wrapperSha256Sum="" -while IFS="=" read -r key value; do - case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; - esac -done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" -if [ -n "$wrapperSha256Sum" ]; then - wrapperSha256Result=false - if command -v sha256sum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - elif command -v shasum > /dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then - wrapperSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." - echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." - exit 1 - fi - if [ $wrapperSha256Result = false ]; then - echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 - echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 - echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 - exit 1 - fi -fi - -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$JAVA_HOME" ] && - JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") - [ -n "$CLASSPATH" ] && - CLASSPATH=$(cygpath --path --windows "$CLASSPATH") - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -# shellcheck disable=SC2086 # safe args -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/completesolution/springboot/copilot-demo/mvnw.cmd b/completesolution/springboot/copilot-demo/mvnw.cmd deleted file mode 100644 index 95ba6f54..00000000 --- a/completesolution/springboot/copilot-demo/mvnw.cmd +++ /dev/null @@ -1,205 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.2.0 -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %WRAPPER_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file -SET WRAPPER_SHA_256_SUM="" -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B -) -IF NOT %WRAPPER_SHA_256_SUM%=="" ( - powershell -Command "&{"^ - "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ - "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ - " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ - " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ - " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ - " exit 1;"^ - "}"^ - "}" - if ERRORLEVEL 1 goto error -) - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% diff --git a/completesolution/springboot/copilot-demo/pom.xml b/completesolution/springboot/copilot-demo/pom.xml deleted file mode 100644 index 639d30ae..00000000 --- a/completesolution/springboot/copilot-demo/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.1.1 - - - com.microsoft.hackathon - copilot-demo - 0.0.1-SNAPSHOT - copilot-demo - Demo project for Spring Boot - - 17 - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.json - json - 20231013 - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - 2.3.0 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/completesolution/springboot/copilot-demo/src/main/java/com/microsoft/hackathon/copilotdemo/CopilotDemoApplication.java b/completesolution/springboot/copilot-demo/src/main/java/com/microsoft/hackathon/copilotdemo/CopilotDemoApplication.java deleted file mode 100644 index a828eaf7..00000000 --- a/completesolution/springboot/copilot-demo/src/main/java/com/microsoft/hackathon/copilotdemo/CopilotDemoApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.microsoft.hackathon.copilotdemo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class CopilotDemoApplication { - - public static void main(String[] args) { - SpringApplication.run(CopilotDemoApplication.class, args); - } - -} diff --git a/completesolution/springboot/copilot-demo/src/main/java/com/microsoft/hackathon/copilotdemo/controller/DemoController.java b/completesolution/springboot/copilot-demo/src/main/java/com/microsoft/hackathon/copilotdemo/controller/DemoController.java deleted file mode 100644 index 5c4e6697..00000000 --- a/completesolution/springboot/copilot-demo/src/main/java/com/microsoft/hackathon/copilotdemo/controller/DemoController.java +++ /dev/null @@ -1,247 +0,0 @@ -package com.microsoft.hackathon.copilotdemo.controller; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Scanner; -import java.util.concurrent.TimeUnit; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.Resource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - - -/* -* Create a GET operation to return the value of a key passed as query parameter. -* If the key is not passed, return "key not passed". -* If the key is passed, return "hello ". -* -*/ - -@RestController -public class DemoController { - - @GetMapping(value = "/hello", produces = MediaType.TEXT_PLAIN_VALUE) - public String hello(@RequestParam(name = "key", required = false) String key) { - if (key == null) { - return "key not passed"; - } - return "hello " + key; - } - - // New operation under /diffdates that calculates the difference between two dates. The operation should receive two dates as parameter in format dd-MM-yyyy and return the difference in days. - @GetMapping(value = "/diffdates", produces = MediaType.TEXT_PLAIN_VALUE) - public String diffdates(@RequestParam(name = "date1", required = false) String date1, @RequestParam(name = "date2", required = false) String date2) throws ParseException { - if (date1 == null || date2 == null) { - return "date not passed"; - } - SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); - Date date1Obj = sdf.parse(date1); - Date date2Obj = sdf.parse(date2); - long diffInMillies = Math.abs(date2Obj.getTime() - date1Obj.getTime()); - long diff = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS); - return "difference in days: " + diff; - } - - // Validate the format of a spanish phone number (+34 prefix, then 9 digits, starting with 6, 7 or 9). The operation should receive a phone number as parameter and return true if the format is correct, false otherwise. - @GetMapping(value = "/validatephone", produces = MediaType.TEXT_PLAIN_VALUE) - public boolean validatephone(@RequestParam(name = "phone", required = false) String phone) { - if (phone == null || phone.isEmpty()) { - return false; - } - String regex = "^\\+34[679]\\d{8}$"; - return phone.matches(regex); - } - - // Validate the format of a spanish DNI (8 digits and 1 letter). The operation should receive a DNI as parameter and return true if the format is correct, false otherwise. - @GetMapping(value = "/validatedni", produces = MediaType.TEXT_PLAIN_VALUE) - public boolean validatedni(@RequestParam(name = "dni", required = false) String dni) { - if (dni == null || dni.isEmpty()) { - return false; - } - String regex = "^\\d{8}[A-Z]$"; - return dni.matches(regex); - } - - //Based on existing colors.json file under resources, given the name of the color as path parameter, return the hexadecimal code. If the color is not found, return 404 - @GetMapping(value = "/color/{name}", produces = MediaType.TEXT_PLAIN_VALUE) - public ResponseEntity color(@PathVariable("name") String name) throws IOException { - InputStream inputStream = getClass().getClassLoader().getResourceAsStream("colors.json"); - ObjectMapper objectMapper = new ObjectMapper(); - // create JsonNode from mapper - JsonNode rootNode = objectMapper.readTree(inputStream); - for (JsonNode color : rootNode) { - // if color name is found, return the hex code - if (color.get("color").asText().equals(name)) { - return new ResponseEntity(color.get("code").get("hex").asText(), HttpStatus.OK); - } - } - return new ResponseEntity("Color not found", HttpStatus.NOT_FOUND); - } - - // new operation that call the API https://api.chucknorris.io/jokes/random and return the joke - @GetMapping(value = "/joke", produces = MediaType.TEXT_PLAIN_VALUE) - public String getJoke() { - RestTemplate restTemplate = new RestTemplate(); - String url = "https://api.chucknorris.io/jokes/random"; - ResponseEntity response = restTemplate.getForEntity(url, String.class); - // parse response to get the value - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode rootNode; - try { - rootNode = objectMapper.readTree(response.getBody()); - return rootNode.get("value").asText(); - } catch (IOException e) { - return new String("Error getting joke"); - } - } - - - // Given a url as query parameter, parse it and return the protocol, host, port, path and query parameters. The response should be in Json format. - @GetMapping(value = "/parseurl", produces = MediaType.APPLICATION_JSON_VALUE) - public String parseurl(@RequestParam(name = "url", required = false) String url) throws MalformedURLException { - if (url == null || url.isEmpty()) { - return "url not passed"; - } - URL urlObj = new URL(url); - String protocol = urlObj.getProtocol(); - String host = urlObj.getHost(); - int port = urlObj.getPort(); - String path = urlObj.getPath(); - String query = urlObj.getQuery(); - return "{ \"protocol\": \"" + protocol + "\", \"host\": \"" + host + "\", \"port\": \"" + port + "\", \"path\": \"" + path + "\", \"query\": \"" + query + "\" }"; - } - - // List files and folders under a given path. The path should be a query parameter. The response should be in Json format. - @GetMapping(value = "/list-files", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity listFiles(@RequestParam(name = "path") String pathString) { - try { - if (pathString.contains("..") || pathString.contains("/") || pathString.contains("\\")) { - throw new IllegalArgumentException("Invalid pathString"); - } - File path = new File(pathString); - if (!path.exists()) { - return ResponseEntity.notFound().build(); - } - if (!path.isDirectory()) { - return ResponseEntity.badRequest().body("Path is not a directory"); - } - File[] files = path.listFiles(); - JSONArray jsonArray = new JSONArray(); - for (File file : files) { - JSONObject jsonObject = new JSONObject(); - jsonObject.put("name", file.getName()); - jsonObject.put("isDirectory", file.isDirectory()); - jsonArray.put(jsonObject); - } - return ResponseEntity.ok(jsonArray.toString()); - } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error listing files"); - } - } - - // Given the path of a file and count the number of occurrence of a provided word. The path and the word should be query parameters. The response should be in Json format. - @GetMapping(value = "/count-word", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity countWord(@RequestParam(name = "path") String pathString, @RequestParam(name = "word") String word) { - try { - if (pathString.contains("..") || pathString.contains("/") || pathString.contains("\\")) { - throw new IllegalArgumentException("Invalid pathString"); - } - File file = new File(pathString); - if (!file.exists()) { - return ResponseEntity.notFound().build(); - } - if (!file.isFile()) { - return ResponseEntity.badRequest().body("Path is not a file"); - } - int count = 0; - try (Scanner scanner = new Scanner(file)) { - while (scanner.hasNext()) { - if (scanner.next().equals(word)) { - count++; - } - } - } - JSONObject jsonObject = new JSONObject(); - jsonObject.put("count", count); - return ResponseEntity.ok(jsonObject.toString()); - } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error counting word"); - } - } - - // Create a zip file with the content of a given folder. The path of the folder should be a query parameter. - @GetMapping(value = "/zip-folder", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) - public ResponseEntity zipFolder(@RequestParam(name = "path") String pathString) { - try { - if (pathString.contains("..") || pathString.contains("/") || pathString.contains("\\")) { - throw new IllegalArgumentException("Invalid pathString"); - } - File folder = new File(pathString); - if (!folder.exists()) { - return ResponseEntity.notFound().build(); - } - if (!folder.isDirectory()) { - return ResponseEntity.badRequest().body(null); - } - String zipFileName = folder.getName() + ".zip"; - File zipFile = new File(zipFileName); - FileOutputStream fos = new FileOutputStream(zipFile); - ZipOutputStream zos = new ZipOutputStream(fos); - zipFolder(folder, folder.getName(), zos); - zos.close(); - fos.close(); - Path path = Paths.get(zipFileName); - ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(path)); - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + zipFileName); - return ResponseEntity.ok().headers(headers).contentLength(zipFile.length()).contentType(MediaType.parseMediaType("application/octet-stream")).body(resource); - } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); - } - } - - private void zipFolder(File folder, String parentFolder, ZipOutputStream zos) throws IOException { - for (File file : folder.listFiles()) { - if (file.isDirectory()) { - zipFolder(file, parentFolder + "/" + file.getName(), zos); - } else { - ZipEntry zipEntry = new ZipEntry(parentFolder + "/" + file.getName()); - zos.putNextEntry(zipEntry); - FileInputStream fis = new FileInputStream(file); - byte[] buffer = new byte[1024]; - int length; - while ((length = fis.read(buffer)) > 0) { - zos.write(buffer, 0, length); - } - fis.close(); - } - } - } - -} diff --git a/completesolution/springboot/copilot-demo/src/main/resources/application.properties b/completesolution/springboot/copilot-demo/src/main/resources/application.properties deleted file mode 100644 index 8b137891..00000000 --- a/completesolution/springboot/copilot-demo/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/completesolution/springboot/copilot-demo/src/main/resources/colors.json b/completesolution/springboot/copilot-demo/src/main/resources/colors.json deleted file mode 100644 index 9d8e8adb..00000000 --- a/completesolution/springboot/copilot-demo/src/main/resources/colors.json +++ /dev/null @@ -1,56 +0,0 @@ - [ - { - "color": "black", - "category": "hue", - "type": "primary", - "code": { - "rgba": [0,0,0,1], - "hex": "#000000" - } - }, - { - "color": "white", - "category": "value", - "code": { - "rgba": [255,255,255,1], - "hex": "#FFFFFF" - } - }, - { - "color": "red", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,0,0,1], - "hex": "#FF0000" - } - }, - { - "color": "blue", - "category": "hue", - "type": "primary", - "code": { - "rgba": [0,0,255,1], - "hex": "#0000FF" - } - }, - { - "color": "yellow", - "category": "hue", - "type": "primary", - "code": { - "rgba": [255,255,0,1], - "hex": "#FFFF00" - } - }, - { - "color": "green", - "category": "hue", - "type": "secondary", - "code": { - "rgba": [0,255,0,1], - "hex": "#00FF00" - } - } - ] - \ No newline at end of file diff --git a/completesolution/springboot/copilot-demo/src/test/java/com/microsoft/hackathon/copilotdemo/CopilotDemoApplicationTests.java b/completesolution/springboot/copilot-demo/src/test/java/com/microsoft/hackathon/copilotdemo/CopilotDemoApplicationTests.java deleted file mode 100644 index 45048061..00000000 --- a/completesolution/springboot/copilot-demo/src/test/java/com/microsoft/hackathon/copilotdemo/CopilotDemoApplicationTests.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.microsoft.hackathon.copilotdemo; - -import static org.mockito.Mockito.mock; - -import org.hamcrest.Matchers; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers;; - - -@SpringBootTest() -@AutoConfigureMockMvc -class CopilotDemoApplicationTests { - - @Autowired - private MockMvc mockMvc; - - @Test - void hello() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/hello?key=world")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("hello world")); - } - - @Test - void helloNoKey() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/hello")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("key not passed")); - } - - @Test - void diffdates() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/diffdates?date1=01-01-2021&date2=01-02-2021")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("difference in days: 31")); - } - - @Test - void diffdatesNoDate1() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/diffdates?date2=01-02-2021")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("date not passed")); - } - - @Test - void diffdatesNoDate2() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/diffdates?date1=01-01-2021")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("date not passed")); - } - - @Test - void validatephone() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/validatephone?phone=+34666666666")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("true")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatephone?phone=+34766666666")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("true")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatephone?phone=+34966666666")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("true")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatephone?phone=+3466666666")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatephone?phone=+346666666666")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatephone?phone=+3466666666a")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatephone?phone=+34866666666")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - } - - @Test - void validatephoneNoPhone() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/validatephone")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - } - - @Test - void validatedni() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/validatedni?dni=12345678A")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("true")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatedni?dni=12345678a")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatedni?dni=1234567A")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatedni?dni=123456789A")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - - mockMvc.perform(MockMvcRequestBuilders.get("/validatedni?dni=12345678")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - - } - - @Test - void validatedniNoDni() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/validatedni")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("false")); - } - - // test for /color/{color} endpoint - @Test - void color() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/color/red")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("#FF0000")); - } - - @Test - void colorNotFound() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/color/purple")) - .andExpect(MockMvcResultMatchers.status().isNotFound()); - } - - @Test - void joke() throws Exception{ - mockMvc.perform(MockMvcRequestBuilders.get("/joke")) - .andExpect(MockMvcResultMatchers.status().isOk()) - // check that content is a string - .andExpect(MockMvcResultMatchers.content().string(Matchers.any(String.class))); - - } - - @Test - void parseUrl() throws Exception{ - mockMvc.perform(MockMvcRequestBuilders.get("/parseurl?url=https://learn.microsoft.com/en-us/azure/aks/concepts-clusters-workloads?source=recommendations")) - .andExpect(MockMvcResultMatchers.status().isOk()) - // validate json fields - .andExpect(MockMvcResultMatchers.jsonPath("$.protocol").value("https")) - .andExpect(MockMvcResultMatchers.jsonPath("$.host").value("learn.microsoft.com")) - .andExpect(MockMvcResultMatchers.jsonPath("$.path").value("/en-us/azure/aks/concepts-clusters-workloads")) - .andExpect(MockMvcResultMatchers.jsonPath("$.query").value("source=recommendations")); - - } - - @Test - void parseUrlNoUrl() throws Exception{ - mockMvc.perform(MockMvcRequestBuilders.get("/parseurl")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("url not passed")); - } - -} diff --git a/exercisefiles/springboot/README.md b/exercisefiles/springboot/README.md index 46bfe166..9a1c8b1d 100644 --- a/exercisefiles/springboot/README.md +++ b/exercisefiles/springboot/README.md @@ -72,16 +72,6 @@ Given the path of a file and count the number of occurrence of a provided word. Create a zip file with the content of a given folder. The path of the folder should be a query parameter. -### 11. Containerize the application - -Use the Dockerfile provided to create a docker image of the application. There are some comments in the Dockerfile that will help you to complete the exercise. - -In order to build, run and test the docker image, you can use Copilot as well to generate the commands. - -For instance, create a DOCKER.md file where you can store the commands to build, run and test the docker image. You will notice that Copilot will also help you to document your project and commands. - -Examples of steps to document: Build the container image, Run the container, Test the container. -