From b2c4e005d9ee0c85517b958de01015541f0cd6e3 Mon Sep 17 00:00:00 2001 From: Colin Dembovsky Date: Wed, 2 Oct 2024 03:15:04 -0400 Subject: [PATCH 01/24] Add C++ exercises (#46) * Update instructions to add more clarity * Initial import of exercise files * Initial devcontainer config for cmake * Updating container config * Completing exercises * Update main README --- .devcontainer/devcontainer.json | 2 +- .devcontainer/scripts/install-cmake.sh | 22 ++++ .devcontainer/scripts/install-vcpkg.sh | 85 ++++++++++++++ .gitignore | 37 ++++++ README.md | 4 + completesolution/c++/CMakeLists.txt | 13 +++ completesolution/c++/src/CMakeLists.txt | 10 ++ .../c++/src/converters/CMakeLists.txt | 11 ++ .../c++/src/converters/distance.cpp | 105 ++++++++++++++++++ .../c++/src/converters/distance.h | 21 ++++ .../c++/src/converters/temperature.cpp | 92 +++++++++++++++ .../c++/src/converters/temperature.h | 22 ++++ completesolution/c++/src/converters/types.h | 11 ++ .../c++/src/converters/weight.cpp | 92 +++++++++++++++ completesolution/c++/src/converters/weight.h | 21 ++++ completesolution/c++/src/main.cpp | 55 +++++++++ completesolution/c++/test/CMakeLists.txt | 38 +++++++ completesolution/c++/test/distance_test.cpp | 32 ++++++ .../c++/test/temperature_test.cpp | 32 ++++++ completesolution/c++/test/weight_test.cpp | 32 ++++++ exercisefiles/c++/CMakeLists.txt | 13 +++ exercisefiles/c++/README.md | 37 ++++++ exercisefiles/c++/src/CMakeLists.txt | 10 ++ .../c++/src/converters/CMakeLists.txt | 9 ++ exercisefiles/c++/src/converters/distance.cpp | 67 +++++++++++ exercisefiles/c++/src/converters/distance.h | 21 ++++ .../c++/src/converters/temperature.cpp | 92 +++++++++++++++ .../c++/src/converters/temperature.h | 22 ++++ exercisefiles/c++/src/converters/types.h | 10 ++ exercisefiles/c++/src/main.cpp | 40 +++++++ exercisefiles/c++/test/CMakeLists.txt | 36 ++++++ exercisefiles/c++/test/temperature_test.cpp | 32 ++++++ exercisefiles/springboot/README.md | 8 +- 33 files changed, 1131 insertions(+), 3 deletions(-) create mode 100755 .devcontainer/scripts/install-cmake.sh create mode 100755 .devcontainer/scripts/install-vcpkg.sh create mode 100644 completesolution/c++/CMakeLists.txt create mode 100644 completesolution/c++/src/CMakeLists.txt create mode 100644 completesolution/c++/src/converters/CMakeLists.txt create mode 100644 completesolution/c++/src/converters/distance.cpp create mode 100644 completesolution/c++/src/converters/distance.h create mode 100644 completesolution/c++/src/converters/temperature.cpp create mode 100644 completesolution/c++/src/converters/temperature.h create mode 100644 completesolution/c++/src/converters/types.h create mode 100644 completesolution/c++/src/converters/weight.cpp create mode 100644 completesolution/c++/src/converters/weight.h create mode 100644 completesolution/c++/src/main.cpp create mode 100644 completesolution/c++/test/CMakeLists.txt create mode 100644 completesolution/c++/test/distance_test.cpp create mode 100644 completesolution/c++/test/temperature_test.cpp create mode 100644 completesolution/c++/test/weight_test.cpp create mode 100644 exercisefiles/c++/CMakeLists.txt create mode 100644 exercisefiles/c++/README.md create mode 100644 exercisefiles/c++/src/CMakeLists.txt create mode 100644 exercisefiles/c++/src/converters/CMakeLists.txt create mode 100644 exercisefiles/c++/src/converters/distance.cpp create mode 100644 exercisefiles/c++/src/converters/distance.h create mode 100644 exercisefiles/c++/src/converters/temperature.cpp create mode 100644 exercisefiles/c++/src/converters/temperature.h create mode 100644 exercisefiles/c++/src/converters/types.h create mode 100644 exercisefiles/c++/src/main.cpp create mode 100644 exercisefiles/c++/test/CMakeLists.txt create mode 100644 exercisefiles/c++/test/temperature_test.cpp diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0104402d..4e9edde9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -38,7 +38,7 @@ ] } }, - "postCreateCommand": "cd ./completesolution/node; npm install; cd ../../; dotnet restore ./completesolution/dotnet/MinimalAPI.sln; dotnet restore ./exercisefiles/dotnet/MinimalAPI.sln" + "postCreateCommand": "sudo ./.devcontainer/scripts/install-cmake.sh; cd ./completesolution/node; npm install; cd ../../; dotnet restore ./completesolution/dotnet/MinimalAPI.sln; dotnet restore ./exercisefiles/dotnet/MinimalAPI.sln" // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, // Use 'forwardPorts' to make a list of ports inside the container available locally. diff --git a/.devcontainer/scripts/install-cmake.sh b/.devcontainer/scripts/install-cmake.sh new file mode 100755 index 00000000..be7cc953 --- /dev/null +++ b/.devcontainer/scripts/install-cmake.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +set -e + +echo "Installing apt packages..." +apt-get update +export DEBIAN_FRONTEND=noninteractive +apt-get -y install build-essential cmake cppcheck valgrind clang lldb llvm gdb +apt-get autoremove -y +apt-get clean -y +rm -rf /var/lib/apt/lists/* + +echo "Installing vcpkg..." +export VCPKG_ROOT=/usr/local/vcpkg +export VCPKG_DOWNLOADS=/usr/local/vcpkg-downloads +export PATH="${PATH}:${VCPKG_ROOT}" +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +"${DIR}/install-vcpkg.sh" vscode \ No newline at end of file diff --git a/.devcontainer/scripts/install-vcpkg.sh b/.devcontainer/scripts/install-vcpkg.sh new file mode 100755 index 00000000..3f628299 --- /dev/null +++ b/.devcontainer/scripts/install-vcpkg.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +set -e + +USERNAME=${1:-"vscode"} + +. /etc/os-release + +# Add to bashrc/zshrc files for all users. +updaterc() { + echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..." + if [[ "$(cat /etc/bash.bashrc)" != *"$1"* ]]; then + echo -e "$1" >> /etc/bash.bashrc + fi + if [ -f "/etc/zsh/zshrc" ] && [[ "$(cat /etc/zsh/zshrc)" != *"$1"* ]]; then + echo -e "$1" >> /etc/zsh/zshrc + fi +} + +# Run apt-get if needed. +apt_get_update_if_needed() { + if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update + else + echo "Skipping apt-get update." + fi +} + +# Check if packages are installed and installs them if not. +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update_if_needed + apt-get -y install --no-install-recommends "$@" + fi +} + +export DEBIAN_FRONTEND=noninteractive +export VCPKG_FORCE_SYSTEM_BINARIES=1 + +# Install additional packages needed by vcpkg: https://github.com/microsoft/vcpkg/blob/master/README.md#installing-linux-developer-tools +check_packages build-essential tar curl zip unzip pkg-config bash-completion ninja-build + +# Setup group and add user +umask 0002 +if ! cat /etc/group | grep -e "^vcpkg:" > /dev/null 2>&1; then + groupadd -r "vcpkg" +fi +usermod -a -G "vcpkg" "${USERNAME}" + +# Start Installation +# Clone repository with ports and installer +mkdir -p "${VCPKG_ROOT}" +mkdir -p "${VCPKG_DOWNLOADS}" +git clone --depth=1 \ + -c core.eol=lf \ + -c core.autocrlf=false \ + -c fsck.zeroPaddedFilemode=ignore \ + -c fetch.fsck.zeroPaddedFilemode=ignore \ + -c receive.fsck.zeroPaddedFilemode=ignore \ + https://github.com/microsoft/vcpkg "${VCPKG_ROOT}" + +## Run installer to get latest stable vcpkg binary +## https://github.com/microsoft/vcpkg/blob/7e7dad5fe20cdc085731343e0e197a7ae655555b/scripts/bootstrap.sh#L126-L144 +"${VCPKG_ROOT}"/bootstrap-vcpkg.sh + +# Add vcpkg to PATH +updaterc "$(cat << EOF +export VCPKG_ROOT="${VCPKG_ROOT}" +if [[ "\${PATH}" != *"\${VCPKG_ROOT}"* ]]; then export PATH="\${PATH}:\${VCPKG_ROOT}"; fi +EOF +)" + +# Give read/write permissions to the user group. +chown -R ":vcpkg" "${VCPKG_ROOT}" "${VCPKG_DOWNLOADS}" +chmod g+r+w+s "${VCPKG_ROOT}" "${VCPKG_DOWNLOADS}" +chmod -R g+r+w "${VCPKG_ROOT}" "${VCPKG_DOWNLOADS}" + +# Enable tab completion for bash and zsh +VCPKG_FORCE_SYSTEM_BINARIES=1 su "${USERNAME}" -c "${VCPKG_ROOT}/vcpkg integrate bash" +VCPKG_FORCE_SYSTEM_BINARIES=1 su "${USERNAME}" -c "${VCPKG_ROOT}/vcpkg integrate zsh" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 78cae49f..0aa96f3b 100644 --- a/.gitignore +++ b/.gitignore @@ -530,3 +530,40 @@ FodyWeavers.xsd *.sln.iml .idea/ +# C++ excludes + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +build + diff --git a/README.md b/README.md index e3e4e1a5..129dbfd7 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,9 @@ Run: **For Python** - [Install Python](https://www.python.org/downloads/) +**For C++** +- [Install cmake](https://cmake.org/download/) + ## Labs instructions - [Node Server](./exercisefiles/node/README.md) @@ -90,6 +93,7 @@ Run: - [Java Quarkus](./exercisefiles/quarkus/README.md) - [Python Data Engineer](./exercisefiles/dataengineer/README.md) - [Python Data Scientist](./exercisefiles/datascientist/README.md) +- [C++](./exercisefiles/c++/README.md) ## Challenges instructions diff --git a/completesolution/c++/CMakeLists.txt b/completesolution/c++/CMakeLists.txt new file mode 100644 index 00000000..958d99ad --- /dev/null +++ b/completesolution/c++/CMakeLists.txt @@ -0,0 +1,13 @@ +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 new file mode 100644 index 00000000..f25cc575 --- /dev/null +++ b/completesolution/c++/src/CMakeLists.txt @@ -0,0 +1,10 @@ +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 new file mode 100644 index 00000000..187e9fc1 --- /dev/null +++ b/completesolution/c++/src/converters/CMakeLists.txt @@ -0,0 +1,11 @@ +## 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 new file mode 100644 index 00000000..073878f0 --- /dev/null +++ b/completesolution/c++/src/converters/distance.cpp @@ -0,0 +1,105 @@ +#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 new file mode 100644 index 00000000..90685182 --- /dev/null +++ b/completesolution/c++/src/converters/distance.h @@ -0,0 +1,21 @@ +#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 new file mode 100644 index 00000000..013163a2 --- /dev/null +++ b/completesolution/c++/src/converters/temperature.cpp @@ -0,0 +1,92 @@ +#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 new file mode 100644 index 00000000..94b8c126 --- /dev/null +++ b/completesolution/c++/src/converters/temperature.h @@ -0,0 +1,22 @@ +#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 new file mode 100644 index 00000000..6f4752f9 --- /dev/null +++ b/completesolution/c++/src/converters/types.h @@ -0,0 +1,11 @@ +#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 new file mode 100644 index 00000000..fb007b1f --- /dev/null +++ b/completesolution/c++/src/converters/weight.cpp @@ -0,0 +1,92 @@ +#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 new file mode 100644 index 00000000..7dadc588 --- /dev/null +++ b/completesolution/c++/src/converters/weight.h @@ -0,0 +1,21 @@ +#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 new file mode 100644 index 00000000..030a77b7 --- /dev/null +++ b/completesolution/c++/src/main.cpp @@ -0,0 +1,55 @@ +#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 new file mode 100644 index 00000000..889ec270 --- /dev/null +++ b/completesolution/c++/test/CMakeLists.txt @@ -0,0 +1,38 @@ +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 new file mode 100644 index 00000000..44e0d092 --- /dev/null +++ b/completesolution/c++/test/distance_test.cpp @@ -0,0 +1,32 @@ +#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 new file mode 100644 index 00000000..381b7c8b --- /dev/null +++ b/completesolution/c++/test/temperature_test.cpp @@ -0,0 +1,32 @@ +#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 new file mode 100644 index 00000000..a0b483a6 --- /dev/null +++ b/completesolution/c++/test/weight_test.cpp @@ -0,0 +1,32 @@ +#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/exercisefiles/c++/CMakeLists.txt b/exercisefiles/c++/CMakeLists.txt new file mode 100644 index 00000000..958d99ad --- /dev/null +++ b/exercisefiles/c++/CMakeLists.txt @@ -0,0 +1,13 @@ +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/exercisefiles/c++/README.md b/exercisefiles/c++/README.md new file mode 100644 index 00000000..45dbefdd --- /dev/null +++ b/exercisefiles/c++/README.md @@ -0,0 +1,37 @@ +# C++ Demo + +These exercises demonstrate usage of GitHub Copilot for C++. The app is a simple CLI Tool that allows users to convert in between different units. + +## Getting Started + +### Build + +`cd` to the `exercisefiles/c++` directory. Run the following two commands to prepare the make file and then build the project: + +```bash +cmake -S . -B build +cmake --build build +``` + +### Run & Test + +- To run the main program: + + ```bash + ./build/main + ``` + +- To execute the tests: + + ```bash + ./build/run-tests + ``` + +## Exercises + +Use GitHub Copilot to assist with the following tasks: + +- [ ] Finish the `Distance` Conversion Class and include it in the `main.cpp` (optionally, first implement tests and do a TDD approach) +- [ ] Add some Tests for the `Distance::convertDistance` +- [ ] Refactor all `printf` and `scanf` and use `std::cout` and `std::cin` instead +- [ ] Add a new Conversion Class for `Weight` to convert in between Kilos and Pounds \ No newline at end of file diff --git a/exercisefiles/c++/src/CMakeLists.txt b/exercisefiles/c++/src/CMakeLists.txt new file mode 100644 index 00000000..f25cc575 --- /dev/null +++ b/exercisefiles/c++/src/CMakeLists.txt @@ -0,0 +1,10 @@ +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/exercisefiles/c++/src/converters/CMakeLists.txt b/exercisefiles/c++/src/converters/CMakeLists.txt new file mode 100644 index 00000000..e271c0e6 --- /dev/null +++ b/exercisefiles/c++/src/converters/CMakeLists.txt @@ -0,0 +1,9 @@ +## Build a library "converters" with all included files +add_library( + converters + distance.cpp + distance.h + temperature.cpp + temperature.h + types.h +) diff --git a/exercisefiles/c++/src/converters/distance.cpp b/exercisefiles/c++/src/converters/distance.cpp new file mode 100644 index 00000000..debcd7ce --- /dev/null +++ b/exercisefiles/c++/src/converters/distance.cpp @@ -0,0 +1,67 @@ +#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); + + printf("%.2f%s is %.2f%s\n", sourceValue, getDistanceUnitSign(from).c_str(), targetValue, getDistanceUnitSign(to).c_str()); + } + + double getSourceValue() + { + double value; + printf("Enter the value to be converted: "); + scanf("%lf", &value); + return value; + } + + DistanceUnit getDistanceUnit(const std::string_view &sourceOrTarget) + { + int choice; + printf("Select %s distance unit:\n", std::string(sourceOrTarget).c_str()); + printf("[1] Meters\n"); + printf("[2] Feet\n"); + printf("[3] Yards\n"); + printf("Enter choice: "); + scanf("%d", &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) + { + // Todo implement the actual conversion logic + return 0; + } +} diff --git a/exercisefiles/c++/src/converters/distance.h b/exercisefiles/c++/src/converters/distance.h new file mode 100644 index 00000000..90685182 --- /dev/null +++ b/exercisefiles/c++/src/converters/distance.h @@ -0,0 +1,21 @@ +#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/exercisefiles/c++/src/converters/temperature.cpp b/exercisefiles/c++/src/converters/temperature.cpp new file mode 100644 index 00000000..fec16ba2 --- /dev/null +++ b/exercisefiles/c++/src/converters/temperature.cpp @@ -0,0 +1,92 @@ +#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); + + printf("%.2f%s is %.2f%s\n", sourceValue, getTemperatureUnitSign(from).c_str(), targetValue, getTemperatureUnitSign(to).c_str()); + } + + double getSourceValue() + { + double value; + printf("Enter the value to be converted: "); + scanf("%lf", &value); + return value; + } + + TemperatureUnit getTemperatureUnit(const std::string_view &sourceOrTarget) + { + int choice; + printf("Select %s temperature unit:\n", std::string(sourceOrTarget).c_str()); + printf("[1] Celsius\n"); + printf("[2] Fahrenheit\n"); + printf("[3] Kelvin\n"); + printf("Enter choice: "); + scanf("%d", &choice); + + switch (choice) + { + case 1: + return TemperatureUnit::Celsius; + case 2: + return TemperatureUnit::Fahrenheit; + case 3: + return TemperatureUnit::Kelvin; + default: + return TemperatureUnit::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; + } +} diff --git a/exercisefiles/c++/src/converters/temperature.h b/exercisefiles/c++/src/converters/temperature.h new file mode 100644 index 00000000..94b8c126 --- /dev/null +++ b/exercisefiles/c++/src/converters/temperature.h @@ -0,0 +1,22 @@ +#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/exercisefiles/c++/src/converters/types.h b/exercisefiles/c++/src/converters/types.h new file mode 100644 index 00000000..80e333ce --- /dev/null +++ b/exercisefiles/c++/src/converters/types.h @@ -0,0 +1,10 @@ +#ifndef TYPES +#define TYPES + +enum class ConversionType +{ + Temperature, + Distance +}; + +#endif diff --git a/exercisefiles/c++/src/main.cpp b/exercisefiles/c++/src/main.cpp new file mode 100644 index 00000000..7bfba3d0 --- /dev/null +++ b/exercisefiles/c++/src/main.cpp @@ -0,0 +1,40 @@ +#include "converters/types.h" +#include "converters/temperature.h" +#include +#include + +ConversionType getConversionType() +{ + int choice; + std::array conversionTypes = { + ConversionType::Temperature, + ConversionType::Distance}; + + while (true) + { + printf("Select type of conversion:\n"); + printf("[1] Temperature\n"); + printf("Enter choice: "); + scanf("%d", &choice); + + if (choice > 0 && choice <= conversionTypes.size()) + { + return conversionTypes[choice - 1]; + } + + printf("Invalid choice. Please try again.\n"); + } +} + +int main() +{ + ConversionType type = getConversionType(); + switch (type) + { + case ConversionType::Temperature: + { + TemperatureConversion::startFlow(); + break; + } + } +} diff --git a/exercisefiles/c++/test/CMakeLists.txt b/exercisefiles/c++/test/CMakeLists.txt new file mode 100644 index 00000000..616ef8f0 --- /dev/null +++ b/exercisefiles/c++/test/CMakeLists.txt @@ -0,0 +1,36 @@ +set(target run-tests) + +add_executable( + ${target} + temperature_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/exercisefiles/c++/test/temperature_test.cpp b/exercisefiles/c++/test/temperature_test.cpp new file mode 100644 index 00000000..381b7c8b --- /dev/null +++ b/exercisefiles/c++/test/temperature_test.cpp @@ -0,0 +1,32 @@ +#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/exercisefiles/springboot/README.md b/exercisefiles/springboot/README.md index afc79e9d..46bfe166 100644 --- a/exercisefiles/springboot/README.md +++ b/exercisefiles/springboot/README.md @@ -12,9 +12,13 @@ Let's start copiloting!!! ### 1. Create the code to handle a simple GET request -Move to the 'DemoController.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. +Move to the [DemoController.java](exercisefiles/springboot/copilot-demo/src/main/java/com/microsoft/hackathon/copilotdemo/controller/DemoController.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. -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. +> Tip: If nothing happens, then change the comment (add a word or 2) - sometimes Copilot needs a little nudge. + +There is already a unit test implemented for this exercise. Open the terminal in the Codespace. `cd` to the correct folder by entering this command: `cd exercisefiles/springboot/copilot-demo`. Now, you can run the test by entering the command `mvn test` before and after you make changes to validate that the code generated by Copilot is correct. + +> Tip: If the tests fail and you get a `404 not found`, try open the [DemoController.java](exercisefiles/springboot/copilot-demo/src/main/java/com/microsoft/hackathon/copilotdemo/controller/DemoController.java) file and the [CopilotDemoApplicationTests.java](exercisefiles/springboot/copilot-demo/src/test/java/com/microsoft/hackathon/copilotdemo/CopilotDemoApplicationTests.java) files. Then open Copilot Chat and ask Copilot: "Why is this the hello test failing Then, create a new unit test for the case when no key is provided in the request. From 2d301ff0e991bd8201cbf7f9ed44db6755422ab7 Mon Sep 17 00:00:00 2001 From: Colin Dembovsky Date: Tue, 8 Oct 2024 05:52:42 -0500 Subject: [PATCH 02/24] Adding CodeQL advanced config (#49) * Update instructions to add more clarity * Initial import of exercise files * Initial devcontainer config for cmake * Updating container config * Completing exercises * Update main README * Create codeql.yml Adding advanced CodeQL scanning since autobuild fails for c++ projects * Update DemoController.java Fixing user-defined path vulnerability * Update DemoController.java Fix user-defined path * Update DemoResource.java Fix user-defined path vulnerability --- .github/workflows/codeql.yml | 57 +++++++++++++++++++ .../hackathon/quarkus/DemoResource.java | 9 +++ .../controller/DemoController.java | 9 +++ 3 files changed, 75 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..24cf3eaa --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,57 @@ +name: "CodeQL Advanced" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '26 17 * * 6' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + security-events: write + packages: read + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: c-cpp + build-mode: manual + - language: csharp + build-mode: none + - language: java-kotlin + build-mode: none + - language: javascript-typescript + build-mode: none + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + + # this is necessary because autobuild does not work + - if: matrix.language == 'c-cpp' + shell: bash + run: | + cd exercisefiles/c++ + cmake -S . -B build + cmake --build build + cd ../../completesolution/c++ + cmake -S . -B build + cmake --build build + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" 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 index 64eb811e..e1600162 100644 --- 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 @@ -186,6 +186,9 @@ public Response parseurl(@QueryParam("url") String url) { @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<>(); @@ -213,6 +216,9 @@ public Response listfiles(@QueryParam("path") String path) { 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; @@ -241,6 +247,9 @@ public Response countWord(@QueryParam("path") String path, @QueryParam("word") S @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()) { 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 index 27945426..5c4e6697 100644 --- 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 @@ -141,6 +141,9 @@ public String parseurl(@RequestParam(name = "url", required = false) String url) @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(); @@ -166,6 +169,9 @@ public ResponseEntity listFiles(@RequestParam(name = "path") String path @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(); @@ -193,6 +199,9 @@ public ResponseEntity countWord(@RequestParam(name = "path") String path @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(); From 1ea1239a3ebfc14e87e9e2c23746be46dd36d277 Mon Sep 17 00:00:00 2001 From: Beburks <157608652+Beburks@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:18:58 -0500 Subject: [PATCH 03/24] Update README.md Changed wording on quick links section for line 6: Changed to GitHub Copilot MS Learn Modules Added line 7: GitHub Copilot Certification and linked to certification page --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 129dbfd7..4087c078 100644 --- a/README.md +++ b/README.md @@ -115,4 +115,6 @@ Run: 5. [Enabling GitHub Copilot in the CLI](https://docs.github.com/en/copilot/github-copilot-in-the-cli/enabling-github-copilot-in-the-cli) -6. [GitHub Copilot Badges and Certifications](https://learn.microsoft.com/en-us/training/browse/?terms=github%20copilot) \ No newline at end of file +6. [GitHub Copilot MS Learn Modules](https://learn.microsoft.com/en-us/training/browse/?terms=github%20copilot) + +7. [GitHub Copilot Certifications](https://resources.github.com/learn/certifications/) From 4534141949966a7361eb04c3a9be474961cf6a05 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Fri, 1 Nov 2024 19:15:11 +0100 Subject: [PATCH 04/24] Add Typescript exercise (copy of node) --- .devcontainer/devcontainer.json | 3 +- README.md | 1 + exercisefiles/dotnet/README.md | 2 +- exercisefiles/node_typescript/README.md | 177 +++++++ exercisefiles/node_typescript/colors.json | 56 +++ exercisefiles/node_typescript/dockerfile | 17 + exercisefiles/node_typescript/nodeserver.ts | 7 + exercisefiles/node_typescript/package.json | 21 + exercisefiles/node_typescript/sample.txt | 500 ++++++++++++++++++++ exercisefiles/node_typescript/test.ts | 39 ++ exercisefiles/node_typescript/tsconfig.json | 110 +++++ 11 files changed, 931 insertions(+), 2 deletions(-) create mode 100644 exercisefiles/node_typescript/README.md create mode 100644 exercisefiles/node_typescript/colors.json create mode 100644 exercisefiles/node_typescript/dockerfile create mode 100644 exercisefiles/node_typescript/nodeserver.ts create mode 100644 exercisefiles/node_typescript/package.json create mode 100644 exercisefiles/node_typescript/sample.txt create mode 100644 exercisefiles/node_typescript/test.ts create mode 100644 exercisefiles/node_typescript/tsconfig.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4e9edde9..9a28f85c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -34,7 +34,8 @@ "ms-dotnettools.csdevkit", "vscjava.vscode-java-pack", "ms-toolsai.jupyter", - "ms-python.python" + "ms-python.python", + "ms-vscode.vscode-typescript-next" ] } }, diff --git a/README.md b/README.md index 4087c078..d23387f8 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ Run: ## Labs instructions - [Node Server](./exercisefiles/node/README.md) +- [Node Server Typescript](./exercisefiles/node_typescript/README.md) - [.NET Web API](./exercisefiles/dotnet/README.md) - [Java Spring Boot](./exercisefiles/springboot/README.md) - [Java Quarkus](./exercisefiles/quarkus/README.md) diff --git a/exercisefiles/dotnet/README.md b/exercisefiles/dotnet/README.md index 75ac262d..5c0faca8 100644 --- a/exercisefiles/dotnet/README.md +++ b/exercisefiles/dotnet/README.md @@ -159,6 +159,6 @@ With the previous exercises you have gone through some common activities that de - Create documentation - Create tests -However, there are many other things that Copilot can helkp you with. Feel free to explore other slash command in the Copilot chat like: +However, there are many other things that Copilot can help you with. Feel free to explore other slash command in the Copilot chat like: - `/fix`: to fix the problems in your code - `/explain`: for Copilot to explain you what the code does \ No newline at end of file diff --git a/exercisefiles/node_typescript/README.md b/exercisefiles/node_typescript/README.md new file mode 100644 index 00000000..9b584281 --- /dev/null +++ b/exercisefiles/node_typescript/README.md @@ -0,0 +1,177 @@ +# Activate GitHub Copilot using Nodejs and Typescript + +Demo project for running labs to evaluate Copilot viability + +> Make sure GitHub Copilot is configure and enabled for the current language, just check the status bar on the bottom right corner of VS Code. + +## Instructions + +- Go to the exercisefile folder +- Open `nodeserver.ts` and begin by writing a Nodejs server, check the first suggestions based on the initial text +- Open `test.ts` file and analyze the current test +- Use `tsc` to compile +- Open a command prompt and run the test (`mocha test.js`) +- See the result, it should display something like: + +``` bash +mocha test.js +server is listening on port 3000 + + Node Server + + √ should return "key not passed" if key is not passed + + 1 passing (34ms) + +``` + +### Exercise 1: Introduction + + +- In the NodeServer.ts develop the rest of the methods described in the Exercise described in the section below (do not forget to open color.json file in Visual Studio Code, so CoPilot get all the context to make better recommendations) +- In the Test.ts file add the methods to test the functionality +- Run the tests to verify that all is working +- Open the dockerfile file, and fill it, in order to create a docker container with a node image that can run the web server +- Create command to run docker in port 4000 +- Test that the application is working in port 4000 +- In the **nodeserver.ts** file, you can type a new line like //run a curl command to test the server + +So we can see how Copilot based on the current file produces a curl command, to be executed in command line +- Also you can be more specific like: //run a curl command to test the daysBetweenDates method + +So it generates a test for a specific method + +### Exercise 2: Building new functionlities + +The exercise consist of building a web server using Nodejs that serves the request of various functionality. + +The requests that the server must attend are the following: + +- **/Get** : + + * Return a hello world message + + +- **/DaysBetweenDates**: + + * Calculate days between two dates + * receive by query string 2 parameters date1 and date 2, and calculate the days between those two dates. + + > **_NOTE:_** Use above information inside the Copilot inline feature in the `nodeserver.js` file. Press enter and wait for Copilot to suggest you the code. + + +- **/Validatephonenumber**: + + * Receive by querystring a parameter called phoneNumber + * validate phoneNumber with Spanish format, for example +34666777888 + * if phoneNumber is valid return "valid" + * if phoneNumber is not valid return "invalid" + + > **_NOTE:_** Use above information inside the Copilot inline feature in the `nodeserver.js` file. Press enter and wait for Copilot to suggest you the code. + + +- **/ValidateSpanishDNI**: + + * Receive by querystring a parameter called dni + * calculate DNI letter + * if DNI is valid return "valid" + * if DNI is not valid return "invalid" + + > NOTE: Use above information inside a comment in the `nodeserver.js` file. In this case, you may want to see multiple solutions from Copilot to pick the one that best fits the way to calculate the letter. In order to see the firs 10 suggestions from Copilot press ctrl + enter. + + +- **/ReturnColorCode**: + + * Receive by querystring a parameter called color + * read colors.json file and return the rgba field + * get color var from querystring + * iterate for each color in colors.json to find the color + * return the code.hex field + + > NOTE: Lets try Copilot chat now. Paste the above information and make it as detailed as possible in the Copilot chat text box. Copilot will use by default the open file as context in order to generate the suggestion. + +- **/TellMeAJoke**: + + * Make a call to the joke api and return a random joke using axios (https://official-joke-api.appspot.com/random_joke) + + +- **/MoviesByDirector**: + + * Receive by querystring a parameter called director + * Make a call to the movie api and return a list of movies of that director using axios + * Return the full list of movies + + > **_NOTE:_** This will require to browse to https://www.omdbapi.com/apikey.aspx and request a FREE API Key + + +- **/ParseUrl**: + + * Retrieves a parameter from querystring called someurl + * Parse the url and return the protocol, host, port, path, querystring and hash + * Return the parsed host + +- **/ListFiles**: + + * Get the current directory + * Get the list of files in the current directory + * Return the list of files + + > **_NOTE:_** Copilot can also help with these kind of commands locally. The feature is called Copilot in the CLI. You can learn more information about this feature [here](https://docs.github.com/en/copilot/github-copilot-in-the-cli/about-github-copilot-in-the-cli). + + +- **/GetFullTextFile**: + + * Read `sample.txt`` and return lines that contains the word "Fusce" + + > **_NOTE:_** Becareful with this implementation, since this normally reads the full content of the file before analizing it, so memory usage is high and may fail when files are too big. + > + > You can use Copilot Code completion or inline chat. Once done you can also use Copilot Inline Chat to refactor the code to put this logic in a function. + +- **/GetLineByLinefromtTextFile**: + + * Read `sample.txt` line by line + * Create a promise to read the file line by line, and return a list of lines that contains the word "Fusce" + * Return the list of lines + + > **_NOTE:_** You can use Copilot Code completion or inline chat. Once done you can also use Copilot Inline Chat to refactor the code to put this logic in a function. + +- **/CalculateMemoryConsumption**: + + * Return the memory consumption of the process in GB, rounded to 2 decimals + + +- **/RandomEuropeanCountry**: + + * Make an array of european countries and its iso codes + * Return a random country from the array + * Return the country and its iso code + + > **_NOTE:_** Copilot can help you to generate data sets. + +### Excercise 2: Document the code + +Documenting code is always a boring and painful task. However, we can use Copilot to document it for us. In the chat, ask Copilot to document the `nodeserver.js` file. + +### Exercise 4: Building tests + +We will create automated tests to check that the functionality of the previous endpoints is correctly implemented. The tests should be together in the `test.ts` file. + +You can leverage Copilot to run the tests. There is a `/tests` command that you can directly run from Copilot Chat or by selecting the piece of code you want to create tests for and using the Copilot inline feature. + +### Exercise 5: Create a Dockerfile + +Now that we have the new functionality added and tests covering it, lets create a Dockerfile for the Node JS Application. + +- Build the image using Copilot and expose the port 3000. + +## Summary + +With the previous exercises you have gone through some common activities that developers usually run: +- Create new features in the code +- Work with external APIs +- Create documentation +- Create tests + +However, there are many other things that Copilot can helkp you with. Feel free to explore other slash command in the Copilot chat like: +- `/fix`: to fix the problems in your code +- `/explain`: for Copilot to explain you what the code does \ No newline at end of file diff --git a/exercisefiles/node_typescript/colors.json b/exercisefiles/node_typescript/colors.json new file mode 100644 index 00000000..9d8e8adb --- /dev/null +++ b/exercisefiles/node_typescript/colors.json @@ -0,0 +1,56 @@ + [ + { + "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/exercisefiles/node_typescript/dockerfile b/exercisefiles/node_typescript/dockerfile new file mode 100644 index 00000000..7caa765a --- /dev/null +++ b/exercisefiles/node_typescript/dockerfile @@ -0,0 +1,17 @@ +# Create a dockerfile with node image + +# Create a directory to hold the application code inside the image, this will be the working directory for your application + +# Set the working directory to /usr/src/app + +# Copy package.json and package-lock.json to the working directory + +# Install npm + +# Copy the current directory contents into the container at /usr/src/app + +# Make port 3000 available to the world outside this container + +# Run Nodeserver.js when the container launches + +# Write a docker comand to build the image and tag it as mynodeapp diff --git a/exercisefiles/node_typescript/nodeserver.ts b/exercisefiles/node_typescript/nodeserver.ts new file mode 100644 index 00000000..f68e5b8f --- /dev/null +++ b/exercisefiles/node_typescript/nodeserver.ts @@ -0,0 +1,7 @@ +// 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 +// if the key is not passed, return "key not passed" +// if the key is passed, return "hello" + key +// if the url has other methods, return "method not supported" +// when server is listening, log "server is listening on port 3000" + diff --git a/exercisefiles/node_typescript/package.json b/exercisefiles/node_typescript/package.json new file mode 100644 index 00000000..ac4b8c2e --- /dev/null +++ b/exercisefiles/node_typescript/package.json @@ -0,0 +1,21 @@ +{ + "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": { + "typescript": "^5.6.3" + }, + "devDependencies": { + "@types/assert": "^1.5.11", + "@types/node": "^22.8.6" + } +} diff --git a/exercisefiles/node_typescript/sample.txt b/exercisefiles/node_typescript/sample.txt new file mode 100644 index 00000000..e0662e8d --- /dev/null +++ b/exercisefiles/node_typescript/sample.txt @@ -0,0 +1,500 @@ +Lorem ipsum dolor sit amet consectetur, adipiscing elit massa. +Rhoncus nunc lacinia pulvinar faucibus praesent, cursus volutpat semper. +Dis parturient convallis nam, malesuada consequat ante, penatibus feugiat. +Elementum conubia convallis suspendisse netus interdum, etiam faucibus cursus ultrices. +Sociosqu odio montes iaculis inceptos eu, ac pharetra malesuada. +Maecenas enim iaculis cras bibendum sociosqu, facilisi nunc dis. +Lectus natoque faucibus et nam, in dui posuere. +Cubilia phasellus montes sollicitudin lacinia nascetur, cursus enim semper hendrerit. +Eros hendrerit lacinia ridiculus, a fringilla posuere, ac varius. +Molestie magnis arcu mi quisque egestas, nascetur dictum himenaeos rutrum. +Nisl fames cubilia sociis et magnis, ridiculus vel congue. +Neque vel purus primis cum convallis, quisque aliquam dictumst. +Mus auctor lacus aptent purus iaculis, litora quam aenean. +Neque facilisi tempor vivamus pulvinar, quis conubia vestibulum. +Molestie himenaeos mi condimentum est, ornare rutrum integer. +Maecenas nisl nascetur dui dapibus suscipit, neque vestibulum sollicitudin. +Eget class himenaeos nostra mauris, tempus a tellus. +Morbi sed curae tincidunt lacinia nullam, class dui rutrum ornare. +Fames curae egestas sociis vivamus, dignissim suspendisse. +Orci accumsan facilisi urna lectus, molestie gravida aliquet. +Mauris litora elementum quisque tortor, nisl volutpat praesent. +Sem morbi parturient egestas pharetra, habitant dapibus per. +Dictum suscipit vel hac senectus vitae, rhoncus dictumst vivamus cum. +Odio curabitur et blandit, in mattis. +Morbi velit dis inceptos massa libero, natoque pulvinar integer. +Pharetra congue natoque mauris rhoncus gravida, vulputate in suscipit facilisi. +Ultrices mollis blandit placerat volutpat, in platea lectus. +Varius tortor phasellus lacus purus, tincidunt rutrum bibendum. +Risus donec sapien vestibulum ultrices et, curabitur conubia turpis a. +Hac nec ullamcorper parturient nisi felis, luctus et est. +Rutrum orci felis praesent, feugiat dapibus nec, turpis quam. +Faucibus mauris habitasse quam justo egestas, euismod ac nunc ultrices. +Fusce euismod dictumst dapibus fringilla, scelerisque fermentum eleifend. +Neque placerat scelerisque ridiculus gravida faucibus, nec iaculis leo sem. +Arcu velit commodo non tortor, tincidunt pulvinar duis himenaeos, nibh imperdiet turpis. +Primis est taciti libero cras luctus, aliquam himenaeos urna litora. +Curae nunc posuere fringilla nisl mattis, feugiat quam felis. +Conubia eros egestas mus porta suspendisse, varius interdum eget habitant. +Class dui eros pretium penatibus pulvinar, faucibus ac libero. +Nec auctor duis phasellus eu torquent vivamus, erat egestas faucibus sociis. +Lobortis tellus felis sapien, molestie vulputate. +Cum hac euismod turpis sodales, pellentesque nostra integer. +Et cum montes interdum, maecenas sollicitudin dapibus tempor, enim vitae. +Himenaeos nisi platea urna, tincidunt habitasse. +Sodales pretium fermentum suscipit fusce, augue facilisi. +Maecenas semper litora elementum donec, hac massa. +Hendrerit est erat platea, ligula augue rutrum, egestas nisi. +Sapien ridiculus etiam blandit morbi dis, venenatis faucibus placerat. +Urna feugiat cum morbi placerat volutpat, vivamus euismod nascetur. +Senectus porttitor tincidunt nisi ornare conubia, imperdiet malesuada risus. +Luctus faucibus lectus vivamus nisi nunc, odio eu nullam urna. +Habitant enim odio facilisis porttitor egestas nibh, nulla semper proin aenean. +Urna in vehicula fames proin, nostra fringilla. +Tellus purus augue erat tempus laoreet, vivamus tincidunt volutpat. +Mi curae cras class viverra lobortis, tellus commodo iaculis posuere. +Sociis nisi enim fermentum gravida, mi vulputate aliquet. +Id ultricies cum tellus, donec laoreet. +Dignissim placerat metus faucibus, iaculis pellentesque libero, pulvinar ultrices. +Elementum lacus eget praesent hendrerit mi, per nulla duis posuere. +Lobortis eget risus quisque imperdiet bibendum, mi litora praesent. +Dapibus bibendum conubia sagittis faucibus senectus, ullamcorper elementum nunc. +Torquent lacus augue nunc facilisis, dis fringilla cras, inceptos ligula dictum. +Augue taciti pretium mollis sem fringilla, orci magnis cum enim. +Litora turpis sapien metus cubilia, ligula risus nostra. +Justo porttitor mollis dis a duis, sem mauris litora eros. +Tristique ad mus molestie iaculis condimentum, sodales nunc cubilia. +Integer etiam condimentum pretium posuere, magnis sociis cursus. +Accumsan nulla metus magna sodales tortor, lacinia dictumst habitant mus. +Sem rhoncus hac a sagittis, at egestas dapibus. +Pharetra nisi cursus conubia, ante imperdiet curae eu, fringilla blandit. +Ligula vivamus aliquam per pellentesque, praesent nascetur vestibulum. +Felis suspendisse lectus leo augue, libero magnis urna, dignissim habitasse at. +Dictum quisque parturient pharetra, platea blandit. +Mattis aptent hendrerit fusce leo libero suspendisse, sociis eget taciti lacinia. +Lacus accumsan cras dui consequat, libero magnis. +Netus ac penatibus vitae montes velit, fermentum in iaculis conubia. +Suscipit mauris tincidunt scelerisque facilisis proin, faucibus orci blandit. +Conubia montes lacus varius integer, turpis sagittis hac. +Diam arcu laoreet class, ut nec quis, scelerisque taciti. +Blandit vehicula purus erat dictumst, quisque leo neque. +Tellus hac conubia torquent mus, arcu eros vehicula. +Vehicula lacinia vitae litora egestas praesent, proin hendrerit turpis. +Auctor placerat luctus nec sed, cras semper pulvinar. +Felis malesuada vitae laoreet lectus sem convallis, eget sodales habitasse potenti. +Nulla nec nam class mollis quisque, justo facilisis mattis. +Platea euismod magna fusce praesent, natoque turpis. +Ridiculus mus fermentum leo bibendum volutpat, platea magnis mattis. +Placerat habitasse massa quisque nam, nibh maecenas rhoncus. +Dictum interdum laoreet purus primis sapien, at mollis convallis molestie. +Pellentesque maecenas volutpat felis auctor nibh faucibus, cras rutrum eleifend elementum. +Eleifend iaculis pulvinar egestas, cursus quisque. +Magna inceptos diam augue dui eu, mauris risus per. +Magnis orci vitae egestas cursus, luctus sem rutrum. +Tortor natoque cubilia et eu nisl, commodo aenean augue tempor. +Hac sem metus primis tellus, eros imperdiet nec. +Suscipit mollis hendrerit gravida purus, proin mauris nascetur, taciti litora ornare. +Non ac est porttitor neque curae, tortor arcu nisl. +Ut vivamus elementum felis interdum eget, ad eu in. +Tempor eget ut ac ultrices, tellus vel. +Purus eros nisl massa, non conubia. +Vel a nibh erat cras bibendum lacus, laoreet dapibus vivamus urna. +Turpis facilisis accumsan in velit, cubilia montes. +Pharetra mattis egestas bibendum faucibus, duis fusce est. +Ultrices nulla vehicula egestas orci justo, risus nec sodales interdum. +Vel eu scelerisque fames vivamus metus, ultrices condimentum tempus elementum. +Dapibus nunc dui etiam vehicula, consequat suspendisse bibendum. +Posuere per torquent arcu metus, hendrerit ultrices ut. +Mi interdum potenti aptent sem, lacinia lobortis dapibus. +Varius condimentum egestas leo ultricies, sapien iaculis duis. +Vehicula ornare sociosqu porta, nam curabitur euismod dui, blandit velit. +Aliquet suspendisse ultricies fermentum varius, platea porta conubia. +Quisque congue hac odio ultrices, placerat nisi aenean. +Habitant morbi potenti praesent laoreet, eros faucibus eu. +Tristique morbi taciti nascetur quis, mauris enim. +Euismod ad at morbi lacus, viverra magna conubia, penatibus dis cras. +Vehicula tortor aptent feugiat dictum vel, dictumst eu tristique. +Primis justo dui hac mollis nullam, class nascetur mattis. +Fames ultricies elementum malesuada habitant sollicitudin, ut lacus nulla. +Primis sed ut magnis ligula torquent, porta nibh molestie leo. +Interdum dictum magna placerat suspendisse, inceptos integer suscipit. +Morbi odio senectus suscipit egestas, non bibendum leo. +Venenatis ultrices metus sagittis nascetur, bibendum duis. +Pretium cubilia laoreet viverra pulvinar, vehicula lobortis egestas. +Neque sollicitudin placerat libero pulvinar nulla, vulputate sociosqu suscipit. +Rhoncus placerat mauris suspendisse iaculis, laoreet metus a. +Quis rhoncus cras libero scelerisque, hac ridiculus morbi. +Platea nibh congue magnis sapien, torquent vestibulum consequat. +At pharetra viverra curae mauris, quam aptent. +Cras sodales hendrerit laoreet phasellus torquent, magna egestas maecenas. +Laoreet habitasse ridiculus ante, commodo donec. +Facilisi neque augue ligula eros, porta maecenas egestas. +Sagittis mollis dictumst hac nostra vivamus, leo donec pretium. +Blandit faucibus habitasse vel mauris donec, rhoncus urna vestibulum. +Arcu condimentum nibh neque curabitur torquent, laoreet dis accumsan. +Venenatis dictumst scelerisque hac egestas aenean, volutpat tempus cursus. +Scelerisque ullamcorper quis molestie litora malesuada, ac dictum tempor et. +Nam sem justo dictumst bibendum, metus imperdiet. +Vestibulum bibendum varius sollicitudin placerat, viverra cubilia. +Quisque sollicitudin sodales convallis suscipit suspendisse, id metus nec posuere. +Integer vulputate potenti inceptos nec pellentesque, libero scelerisque elementum ultrices. +Conubia pellentesque litora class habitant, auctor rhoncus. +Vulputate facilisi fusce porta gravida, venenatis eu pharetra. +At rhoncus primis convallis sem, pellentesque justo erat, imperdiet velit sed. +Penatibus aliquet ultrices tempus viverra aptent, sodales at nam feugiat. +Aliquet feugiat lobortis justo diam, elementum viverra. +In dictumst scelerisque pharetra, molestie conubia. +Curae quam vitae malesuada habitant, ullamcorper curabitur nascetur. +Sed viverra orci litora, porttitor tellus. +Himenaeos a sociosqu lobortis vulputate faucibus, hac vitae cursus. +Consequat et nam fringilla nec, lacinia vestibulum leo. +Nisl leo cubilia congue habitasse, magnis cursus. +Facilisi interdum praesent erat et, fringilla taciti. +Ultricies sagittis tortor vestibulum mauris nostra, luctus vivamus facilisi gravida. +Rhoncus odio lectus condimentum gravida, penatibus inceptos potenti. +Dictum tempus commodo aptent, venenatis eros id, molestie massa. +Nec at hendrerit dignissim vitae mi, phasellus sapien sagittis habitant. +Class lacinia aliquet tempor augue commodo, tincidunt hendrerit mauris. +Justo cubilia sociosqu id cras penatibus, gravida dictum sagittis. +At curae penatibus quisque nisi, mollis volutpat himenaeos. +Ut facilisis eleifend mi dapibus, integer vestibulum fringilla. +Ornare et nunc mi nec aliquam, porttitor cubilia vehicula. +Euismod tempus torquent viverra ligula cubilia, ad massa nisi sollicitudin. +Tempus urna primis interdum netus diam, elementum feugiat praesent. +Rhoncus ut molestie interdum integer, maecenas iaculis. +Phasellus tellus nulla tempor mattis, interdum inceptos. +Duis dictum a lobortis tincidunt nam, sodales magna vestibulum. +Neque sed fusce velit cursus aenean, torquent justo semper. +Quis aliquet vivamus est velit, dis nibh facilisis. +Augue interdum libero laoreet semper risus, duis metus suspendisse. +Magna dignissim risus vivamus vulputate, vehicula pulvinar ante faucibus, fusce nam magnis. +Cras per consequat auctor tempus posuere, semper ridiculus inceptos. +Metus litora dui euismod, turpis semper blandit, faucibus id. +Cubilia platea consequat egestas nostra, ultrices sodales. +Fames felis vehicula etiam commodo diam, convallis cubilia condimentum. +Aliquet congue pulvinar augue quam, felis natoque praesent. +Himenaeos litora ultricies mauris tristique aliquet, faucibus odio parturient aptent. +Placerat curabitur aenean pharetra venenatis parturient, pulvinar suspendisse velit. +Gravida condimentum ullamcorper dapibus in a, cursus venenatis suscipit aptent. +Placerat sodales bibendum hendrerit molestie curabitur, fringilla luctus purus. +Arcu inceptos torquent montes imperdiet consequat, ullamcorper dictumst cum. +Lacinia mollis sagittis porttitor felis, semper rutrum blandit. +Rutrum pellentesque diam semper ante eros, tempor lacus cubilia sodales. +Convallis vulputate ullamcorper velit pellentesque cum, dignissim sagittis magnis. +Tempus cras interdum risus, blandit. +Accumsan augue primis nostra quisque, pretium nibh parturient. +Quisque tortor sociis non blandit, facilisis vestibulum feugiat. +Torquent tincidunt quisque montes pharetra, arcu felis mattis, dignissim tortor sed. +Dui nullam lacinia ridiculus viverra eros, nec quis lectus quam. +Suspendisse montes odio fringilla venenatis morbi a, dictum facilisi augue risus. +Nulla vel justo morbi eget congue, nostra sagittis platea ad. +Suspendisse euismod penatibus aliquam nunc erat congue, semper justo posuere cras. +Tortor penatibus eu tempor ad, nostra senectus sagittis. +Sociosqu pellentesque nibh mattis lacinia sed fermentum, arcu dis morbi potenti. +At diam felis cras elementum, quis primis. +Elementum porttitor scelerisque dis laoreet, fermentum suspendisse sagittis. +Aenean primis at montes pellentesque, sem varius. +Dui aptent vulputate varius condimentum proin, scelerisque imperdiet massa. +Natoque luctus tincidunt congue nam vehicula, sagittis torquent himenaeos. +Montes in mauris molestie vestibulum, ac volutpat. +Congue enim dignissim egestas ridiculus, massa lacinia elementum. +Gravida sodales aenean potenti netus, aliquet leo nibh, tristique vestibulum integer. +Aenean senectus suspendisse porta, nec eros. +Tortor donec varius phasellus tristique facilisi, ornare augue metus. +Ante quisque vestibulum luctus rutrum ridiculus, cras curabitur aenean. +Condimentum euismod primis nullam facilisis, eget potenti vel, velit suspendisse dignissim. +Donec suspendisse lacus platea laoreet natoque, commodo id auctor sociosqu. +Auctor id justo imperdiet mollis, et congue. +Ante quam sapien dis est, velit a penatibus. +Mattis augue massa platea nisi, aliquet primis. +Venenatis ante dictum porttitor id, pellentesque faucibus ultricies, sociis etiam enim. +Elementum porttitor facilisi a mattis cubilia, nunc auctor aliquet. +Conubia praesent id orci nulla quis, aliquet tincidunt dictumst. +Ac natoque elementum phasellus dignissim sem, nunc fermentum dictumst. +Proin elementum dapibus gravida litora, hendrerit fames inceptos. +Iaculis gravida nulla suscipit sodales, justo in. +Tempus sollicitudin gravida montes diam in, parturient morbi nascetur. +Nunc lobortis augue mattis diam, cubilia leo parturient. +Condimentum ligula conubia commodo, integer fermentum. +Nibh bibendum tincidunt phasellus aliquam, nascetur montes elementum. +Sed himenaeos enim sollicitudin massa tempus, libero metus vehicula. +Ultricies pretium ac ullamcorper vehicula ultrices, bibendum lacus risus himenaeos. +Sed ullamcorper torquent curae vulputate, eget tellus. +Fringilla praesent ullamcorper iaculis massa, et enim eros. +Venenatis aptent semper fusce et, lacinia felis posuere. +Ultricies vehicula eu inceptos aliquam dignissim, nullam venenatis ullamcorper conubia. +Libero porttitor elementum nullam eleifend pulvinar, tellus interdum felis. +Et lacinia facilisis sollicitudin penatibus nibh fames, eleifend aenean dapibus vitae. +Suscipit venenatis varius vivamus malesuada erat, mollis vel potenti pretium. +Dictumst praesent sociis diam pulvinar, auctor sociosqu quisque. +Dictumst porta cursus nullam cubilia, mauris mus. +Erat leo diam potenti lobortis, aenean risus. +Conubia nam taciti ornare blandit venenatis morbi, massa sociis lacinia gravida. +Enim curabitur vulputate in suspendisse, ultrices vehicula. +Fringilla massa dignissim curabitur class, mollis sapien. +Massa nullam diam nascetur fusce dui, purus rhoncus ligula. +Auctor integer libero lectus varius malesuada, curabitur fusce eu ultricies. +Nam faucibus quam viverra ornare hac, eget tempus aenean laoreet. +Vivamus arcu aliquet lobortis maecenas blandit, eleifend risus augue convallis. +Class sollicitudin ligula inceptos egestas, cursus metus dui. +Tempor quis nascetur aptent per habitasse, aliquet nostra ornare. +Praesent augue donec congue, nam libero eget, ornare pellentesque. +Nam arcu vulputate mus ut dignissim, luctus senectus molestie. +Risus molestie ligula dui ut, condimentum enim. +Posuere turpis dictumst laoreet sodales, fusce viverra vivamus. +Ullamcorper consequat pulvinar vestibulum penatibus, hac etiam. +Ultricies feugiat magna bibendum commodo, cras nam dui. +Fringilla inceptos feugiat felis posuere porta, risus proin malesuada tincidunt. +Lectus inceptos tortor eget nec ultricies, orci neque luctus. +Vel accumsan phasellus faucibus taciti, metus himenaeos pharetra. +Molestie faucibus nam posuere pellentesque nibh, nisl tristique scelerisque praesent. +Praesent porttitor malesuada donec sollicitudin, justo quis pellentesque. +Ridiculus aliquet orci commodo tortor in, ultrices praesent inceptos. +Ad semper erat parturient gravida, potenti per vulputate. +Phasellus maecenas mollis eu in, sollicitudin rhoncus natoque. +Est arcu eleifend penatibus nulla donec, diam non neque. +Odio mattis nascetur feugiat interdum, vehicula ligula facilisi. +Torquent neque donec aliquet magna, vivamus bibendum non. +Semper iaculis ultrices duis eleifend montes, vivamus justo maecenas. +Eleifend venenatis nisl primis, molestie sociosqu odio ornare, faucibus curae. +Consequat tempus maecenas magnis fringilla netus quam, nec arcu dictum enim. +Dictum aenean accumsan dictumst, integer lacus inceptos curabitur, mattis purus. +Cum placerat sodales elementum velit, eget felis. +Platea aliquet mollis dui nibh, aenean hac ligula. +Vestibulum iaculis conubia aenean facilisi, nullam himenaeos sapien. +Velit mauris turpis posuere ad, habitant inceptos neque. +Conubia mi nulla iaculis, cursus scelerisque. +Tellus fermentum tempus interdum montes, sapien sed. +Blandit maecenas eget nostra tellus, platea purus. +Mus torquent justo scelerisque vel, suscipit non ornare. +Lacus nunc ornare convallis dictum aliquet, phasellus cursus porttitor. +Torquent quam fames sollicitudin faucibus class, dictum per lobortis. +Cubilia suspendisse eget luctus, lectus praesent venenatis, dictum sapien. +Arcu justo quisque ad ridiculus tristique, pulvinar hendrerit vel. +Vivamus porttitor aliquet potenti nunc phasellus, egestas justo libero etiam. +Class ridiculus aenean fusce pulvinar eu, ligula imperdiet rhoncus natoque. +Phasellus mus aliquam montes lacus felis odio, class dignissim cubilia a. +Porttitor porta nostra convallis lectus, netus accumsan vitae. +Molestie habitant vel integer, hendrerit sapien. +Nunc quisque lectus condimentum nulla velit dictumst, sem porttitor dis enim urna. +Rutrum tortor ante litora lacinia lacus, justo gravida sociis. +Lacinia dapibus ligula platea interdum metus, faucibus quisque lacus. +Ullamcorper per est lectus, scelerisque molestie, iaculis lacinia. +Mi consequat eleifend hendrerit egestas odio, cursus blandit sodales bibendum. +Iaculis turpis erat tempor venenatis cum, ad in fringilla. +Platea posuere est mi lobortis, nostra parturient. +Habitasse tristique maecenas nisl, aptent semper quisque porttitor, diam felis. +Blandit sociosqu eget nascetur ultricies, platea per sapien. +Cras turpis dignissim quis rhoncus, inceptos vehicula aenean. +Tristique sollicitudin massa ultrices conubia class, non quisque placerat cras. +Tellus at magnis nibh nulla, congue curabitur viverra. +Rutrum iaculis pharetra auctor faucibus parturient, venenatis accumsan pellentesque porttitor. +Libero feugiat purus ut viverra, erat neque pellentesque. +Interdum blandit magnis nisl eros eleifend, rutrum ac velit faucibus. +Cursus rhoncus lacus iaculis sollicitudin arcu, mauris varius vel. +Natoque sociosqu tortor aptent phasellus, semper lobortis pretium. +Sed accumsan orci maecenas potenti, consequat porta. +Condimentum blandit hac gravida, vehicula nunc ultrices cras, sociosqu donec. +Venenatis morbi cubilia lacinia vitae at, dignissim himenaeos nulla dis. +Enim suscipit hac pharetra eu, vitae dictum posuere. +Nibh nam felis ridiculus, suspendisse fringilla, turpis facilisis. +Fames nisl urna neque nullam, vehicula scelerisque. +Dis dictumst ultricies taciti fermentum integer, metus tellus est eu. +Blandit orci odio hendrerit laoreet iaculis, sociosqu felis mauris vitae. +Ligula tincidunt felis suspendisse pretium maecenas, consequat luctus varius. +Mattis rutrum pharetra id eu montes, aptent integer volutpat. +Condimentum neque quam accumsan vel tellus, fusce lectus nunc. +Sollicitudin senectus vivamus nunc, duis fermentum auctor non, luctus nisi. +Dictum duis sociis sed eget mattis felis, varius commodo pretium nascetur. +Sociosqu eget tempor dui erat scelerisque, feugiat placerat lacus. +Pulvinar felis fames litora mattis pretium, proin congue dictumst. +Ante ridiculus aliquet tristique, luctus scelerisque. +Ornare senectus non convallis nisl, suscipit curae porta. +In platea ante nullam habitasse, cubilia enim. +Varius vehicula orci ultrices metus fames, cras fermentum ut penatibus. +Dignissim laoreet aptent malesuada nullam, curabitur accumsan netus. +Et penatibus ut blandit, turpis metus placerat, suspendisse dapibus. +Velit risus tempor id facilisis, nostra dignissim quisque. +Fusce senectus netus id vel rutrum, odio curae venenatis. +Tellus rutrum purus imperdiet, curae. +Urna odio senectus ridiculus mus ad, hac mattis dui nisi. +Faucibus tortor risus quisque mattis magnis, diam tincidunt in. +Semper blandit interdum urna quam, commodo sociis. +Interdum magna venenatis urna praesent porta, torquent arcu potenti. +Convallis fringilla tempor posuere egestas cursus, faucibus orci donec. +Ridiculus scelerisque nibh est, fermentum arcu potenti, sodales curae. +Semper porttitor rutrum sociis habitasse, interdum curabitur. +Rutrum aliquet netus risus ante nunc, primis venenatis arcu. +Curae mollis eleifend magnis netus, faucibus congue lacus. +Facilisis sem litora ad aptent, natoque a vel. +Dui quis porta congue vivamus suscipit justo, fringilla ultricies convallis maecenas. +Eleifend non primis arcu varius, at tellus pellentesque. +Aenean nibh dis orci justo, feugiat ridiculus urna. +Parturient cursus consequat luctus libero placerat, purus pharetra pulvinar. +Hendrerit velit augue purus, justo proin placerat bibendum, cum ut. +Vestibulum cubilia maecenas pellentesque, vitae orci curabitur, nam suspendisse. +In porta mauris fringilla, praesent cursus. +Consequat at parturient nostra quam, libero senectus. +Accumsan quis eleifend porta integer lobortis, aliquet tristique condimentum litora. +Luctus donec pellentesque ullamcorper nullam, aptent rhoncus eros. +Scelerisque himenaeos sapien parturient nisi senectus, cum per nulla. +Eleifend aptent luctus sollicitudin convallis nisl, ullamcorper egestas dis. +Dapibus egestas proin ac, porttitor magnis imperdiet mi, vel ultrices. +Potenti justo natoque ut torquent malesuada, magnis eget nostra. +Dictum felis sed maecenas turpis etiam, augue aliquam lobortis. +Suscipit vitae elementum mollis mi, sollicitudin non rutrum. +A eleifend fames cum felis, quam class ad. +Parturient malesuada egestas leo platea, rutrum montes mauris. +Ac aliquet sodales ornare pulvinar auctor, dictumst et malesuada. +Curae quis ut venenatis lacus, rutrum turpis. +Etiam dapibus auctor iaculis pretium, dictum hac mus, parturient faucibus sagittis. +Pretium tempus luctus class magna potenti, nunc eleifend maecenas. +Faucibus ultricies sed nascetur, posuere consequat integer, ultrices eros. +Est fusce litora fermentum praesent mus, vivamus lectus gravida. +Diam sollicitudin hendrerit quam taciti iaculis, curae eu imperdiet. +Potenti quisque bibendum habitant facilisi sodales luctus, dignissim dictum est etiam. +Gravida sapien conubia suscipit sem cubilia, magna feugiat porttitor vestibulum. +Eget sollicitudin rhoncus netus in sapien, venenatis habitant morbi semper. +Nibh montes sociis dapibus vel tempor, erat curabitur sociosqu habitasse. +Aliquet et sodales rhoncus auctor, fusce ad. +Litora blandit turpis class cras, montes nullam. +Class semper etiam ultricies dapibus, erat proin sapien. +Fusce nisi lacinia vel arcu, et cubilia. +Aptent mauris pellentesque metus vel, erat nunc nostra. +Vestibulum eros inceptos dictumst platea, nostra sem. +Aptent accumsan netus id faucibus egestas, tempus donec pharetra. +Ultrices lectus penatibus primis malesuada mollis, eleifend facilisi ac. +Senectus lacus neque fusce, nisl nostra. +Dignissim libero litora lacus eu inceptos magnis, blandit gravida lectus eget. +Et at cum cursus nascetur praesent, arcu viverra interdum fames. +Pretium molestie curae enim gravida, volutpat rutrum porttitor. +Interdum maecenas volutpat hendrerit hac, sollicitudin nibh. +Ornare nibh lacus hac volutpat neque, felis consequat aliquam nulla. +Iaculis pharetra netus praesent aliquet aptent, lobortis volutpat viverra. +Odio penatibus pulvinar sociosqu quis, nibh malesuada fames. +Dignissim porttitor platea tempor non imperdiet, ac viverra urna. +Eros congue laoreet praesent posuere netus pulvinar, ligula ad a auctor vulputate. +Nascetur euismod pretium vulputate vestibulum sed, sagittis dapibus primis quisque. +Aliquam sodales sociosqu eu, nisl euismod mollis orci, convallis pharetra. +Turpis non metus dui, sed euismod aenean, porttitor curae. +Scelerisque metus felis leo congue lacinia, laoreet netus tempor. +Vehicula netus eu vitae, metus tincidunt eros habitant, phasellus ligula. +Neque aenean quis porttitor sapien mollis, vestibulum eget lobortis. +Commodo augue et egestas fringilla, phasellus eget venenatis. +Fermentum ultrices ornare ullamcorper nunc viverra, vivamus ridiculus enim. +Pellentesque sodales tincidunt primis facilisi consequat, aliquet cum libero. +Magna dictum porta rutrum fermentum, ornare elementum. +Convallis sem posuere orci mauris, sociosqu laoreet. +Euismod mollis arcu ligula non, lobortis tempor proin. +Gravida vestibulum taciti tortor potenti netus, iaculis habitant quisque. +Torquent eros nunc dictum habitasse quis imperdiet, mollis faucibus maecenas tristique. +Placerat cras hac cubilia justo, sociosqu lacus parturient. +Pharetra vivamus pulvinar tortor dui, nostra sagittis nunc. +Ante ad auctor donec, sodales suspendisse facilisi, purus id. +Molestie nisi vehicula eu sagittis aliquet, non auctor phasellus. +Penatibus dictum nullam lobortis sapien cras risus, curae volutpat nisl tellus. +Vitae tempus ultrices cubilia mattis, libero proin. +Sagittis nibh ornare senectus, in sociis condimentum potenti, dictum iaculis. +Sollicitudin mollis cursus litora nam fringilla, nibh dis nisi consequat. +Consequat diam dictumst molestie vitae, purus maecenas turpis. +Nullam ornare praesent dui torquent fusce vestibulum, velit duis sollicitudin pretium dapibus. +Vivamus aliquet leo nullam vestibulum, semper molestie sapien. +Penatibus pharetra scelerisque venenatis neque, viverra nam. +Primis vitae ut tellus ante auctor, quis etiam feugiat. +Mollis sapien suspendisse massa nisi sociis, mattis quam eu interdum. +Nisl hendrerit aliquam platea cursus sed, erat condimentum conubia. +Eu odio mi praesent pharetra, egestas cursus curabitur. +Potenti scelerisque netus enim cursus, convallis mattis lobortis. +Netus arcu justo tellus non pulvinar, praesent nam nascetur. +Praesent sollicitudin blandit dui varius, ligula magnis. +Dis etiam nec dictumst est vivamus, mollis hendrerit taciti. +Iaculis accumsan convallis mi velit, egestas porttitor congue. +Arcu imperdiet varius sapien sodales faucibus, quis lobortis in. +Inceptos sollicitudin ridiculus mus rhoncus conubia congue, curabitur lectus tellus ultrices. +Pretium gravida urna integer habitasse, justo placerat luctus. +Hac curae malesuada tristique habitant mollis, ullamcorper dictumst dictum. +Conubia varius proin habitasse magna per, odio interdum pharetra dignissim. +Erat nulla nibh fusce molestie natoque, metus habitant hac quis. +Inceptos himenaeos mus posuere, iaculis auctor et porta, elementum duis. +Etiam tempor phasellus pretium potenti, fermentum mus. +Dictum tristique aenean nostra, dictumst orci. +Rhoncus lobortis fames in donec proin natoque, fermentum turpis nunc senectus. +Lacus semper platea volutpat et, dis quis varius. +Accumsan nullam urna senectus massa, consequat penatibus. +Suspendisse praesent cum tempor, tortor vulputate. +Iaculis dictum magnis augue suspendisse, rhoncus neque. +Sodales varius donec mauris egestas nec rutrum, litora vehicula non vestibulum duis. +Ad aenean pharetra venenatis sapien auctor, rutrum elementum ridiculus mauris. +Mollis mi quisque metus, odio convallis aliquam, volutpat at. +Nisl blandit class interdum parturient velit est, faucibus tempus egestas duis. +Faucibus senectus magna non consequat, euismod eu volutpat. +Dictum viverra parturient sed, maecenas eget egestas, sagittis dis. +Tellus netus sollicitudin montes ullamcorper, interdum class felis. +Tempor laoreet fames sodales varius justo, leo lacinia torquent. +Pellentesque potenti auctor cras donec turpis non, diam a dictumst nisi. +Condimentum ligula varius diam neque vitae, lacus quisque praesent. +Eleifend phasellus facilisis mi nisi congue, ad velit platea. +Taciti donec congue faucibus etiam sociosqu, venenatis eget class. +Sociis imperdiet ac in urna nisl, tempor consequat luctus sapien. +Montes est primis arcu accumsan, donec phasellus integer. +Suspendisse fringilla vehicula tristique vulputate class nostra, donec torquent non sociosqu. +Inceptos sociosqu blandit magna velit dui, sapien vehicula tempus. +Ultricies turpis diam egestas penatibus vivamus, facilisi mollis lacinia. +Dignissim eu nibh diam volutpat, habitasse conubia lobortis, dui nisl curabitur. +Blandit risus eget vulputate ornare sociis sagittis, rhoncus pulvinar quis proin. +Non pellentesque purus suscipit nascetur, cras cum lacus. +Dignissim varius lectus augue condimentum, mollis ac auctor. +Tempus nec mus eget, porttitor congue varius vivamus, fusce faucibus. +Nullam egestas magnis cursus nisi, dui integer quisque. +Ut aenean mi auctor a, semper ad purus. +Euismod lacinia neque penatibus placerat, risus litora aenean, potenti in vehicula. +Nascetur quis cubilia porta nisl orci, nam ad augue aliquet. +Pellentesque justo fusce condimentum consequat congue, facilisi per primis suscipit. +Aliquam eget vel gravida curae pellentesque, non nullam enim. +Id conubia arcu neque suspendisse, maecenas et. +Cubilia faucibus volutpat natoque facilisis cras, placerat habitant etiam eros. +Nostra curabitur quisque purus congue vestibulum, per rhoncus scelerisque. +Maecenas vitae feugiat curae scelerisque ultricies tincidunt, lacinia pellentesque netus aenean. +Porta risus cubilia himenaeos in sagittis, facilisi euismod taciti. +Cras praesent a platea justo morbi, eget fusce habitant egestas. +Maecenas diam condimentum fames inceptos, posuere netus convallis, mollis aliquet commodo. +Porta montes volutpat malesuada sagittis mollis eleifend, fringilla et lacus tempor metus. +Sodales ligula molestie curae gravida, morbi erat imperdiet. +Convallis magna tempus proin natoque, consequat dignissim. +Aliquet litora cras primis imperdiet, non nisi tristique. +Phasellus non ad fermentum varius venenatis, eleifend dui taciti odio. +Luctus rhoncus aenean ligula nulla tincidunt, maecenas cubilia nostra ornare. +Eget libero aenean montes, urna vehicula torquent, nec maecenas. +Fringilla pharetra parturient suscipit feugiat ullamcorper, nullam commodo vel dui. +Malesuada habitasse curabitur sapien hendrerit, mattis nullam maecenas. +Fames platea enim mi, nam nisl congue, at ligula. +Vulputate orci nulla sodales fringilla sagittis, platea lacinia quam. +Himenaeos penatibus mi euismod posuere mus, lobortis nibh nunc. +Eget aliquam nostra bibendum nec, ridiculus sociosqu in. +Nec ullamcorper convallis lacinia sodales mus, primis taciti nunc. +Curabitur nulla vivamus sollicitudin porttitor, per dapibus risus, quis sodales aptent. +Lobortis vitae euismod eros metus, volutpat elementum nam. +Pulvinar duis volutpat pretium interdum ridiculus, dignissim posuere metus. +Nam mauris dictumst cursus ut, pharetra hac laoreet. +Fringilla sollicitudin posuere mauris nostra, scelerisque massa commodo. +Dignissim nibh vulputate mauris sociis magnis, eu pretium torquent scelerisque. +Hac cursus convallis natoque ultrices, fusce orci vitae. +Id eu faucibus nunc luctus, lacus et dis. +Nisi sed suspendisse euismod ultricies taciti, fames sollicitudin auctor metus. +Nibh odio blandit pulvinar litora ligula, feugiat vitae tellus. +Volutpat mauris venenatis vulputate eu, semper class aliquam. +Faucibus nisl ac aptent nascetur purus, fusce rutrum est pellentesque. +Lacus ad nascetur molestie etiam felis pellentesque, nibh magnis phasellus nisl. +Per metus nulla lacus, ullamcorper ultrices elementum quisque, magna rhoncus. +Nullam senectus cras molestie rhoncus, ultricies vestibulum et. +Dictumst facilisis dapibus ridiculus id, ullamcorper lacinia quisque, conubia tellus fames. +Etiam integer ligula quisque parturient, fringilla euismod. +Mollis nostra est posuere metus proin, malesuada et aptent platea. +Accumsan interdum viverra pulvinar iaculis cras, mi dictum vel nisi. +Rhoncus arcu cum rutrum mus porttitor, diam dis quis. +Duis at sociosqu nisi magna, laoreet habitant facilisis. +Suspendisse integer curabitur gravida mus est, viverra at tellus. +Lectus condimentum mauris ligula sapien elementum, per vehicula praesent. +Dis lacinia habitasse ultricies class, fermentum duis. +Nisl curae consequat aptent mollis eros, luctus velit per. +Mattis porta ullamcorper integer natoque, sollicitudin cubilia. \ No newline at end of file diff --git a/exercisefiles/node_typescript/test.ts b/exercisefiles/node_typescript/test.ts new file mode 100644 index 00000000..bee5cf89 --- /dev/null +++ b/exercisefiles/node_typescript/test.ts @@ -0,0 +1,39 @@ +//write npm command line to install mocha +//npm install --global mocha +//npm i --save-dev @types/mocha +//command to run this test file +//mocha test.js + +import * as assert from 'assert'; +import * as http from 'http'; +//import server from './nodeserver'; + +describe('Node Server', () => { + it('should return "key not passed" if key is not passed', (done: Mocha.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(); + }); + }); + }); + + //add test to check get when key is equal to world + + //add test to check validatephoneNumber + + //write test to validate validateSpanishDNI + + + //write test for returnColorCode red should return code #FF0000 + + + //write test for daysBetweenDates + + + +}); diff --git a/exercisefiles/node_typescript/tsconfig.json b/exercisefiles/node_typescript/tsconfig.json new file mode 100644 index 00000000..56a8ab81 --- /dev/null +++ b/exercisefiles/node_typescript/tsconfig.json @@ -0,0 +1,110 @@ +{ + "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. */ + } +} From 23495daa8b96261221dca56ae5afbbb813a5a745 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Fri, 1 Nov 2024 19:25:20 +0100 Subject: [PATCH 05/24] removed assert --- exercisefiles/node_typescript/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/exercisefiles/node_typescript/package.json b/exercisefiles/node_typescript/package.json index ac4b8c2e..f3be6ddc 100644 --- a/exercisefiles/node_typescript/package.json +++ b/exercisefiles/node_typescript/package.json @@ -15,7 +15,6 @@ "typescript": "^5.6.3" }, "devDependencies": { - "@types/assert": "^1.5.11", "@types/node": "^22.8.6" } } From f53a156b28ac6f4af89aec751ab00ec67df67645 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Fri, 1 Nov 2024 19:39:34 +0100 Subject: [PATCH 06/24] Fixes instructions --- exercisefiles/node/README.md | 18 +----------------- exercisefiles/node_typescript/README.md | 18 ++---------------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/exercisefiles/node/README.md b/exercisefiles/node/README.md index 7c9f98f1..95c16d81 100644 --- a/exercisefiles/node/README.md +++ b/exercisefiles/node/README.md @@ -4,7 +4,7 @@ Demo project for running labs to evaluate Copilot viability > Make sure GitHub Copilot is configure and enabled for the current language, just check the status bar on the bottom right corner of VS Code. -## Instructions +### Exercise 1: Introduction - Go to the exercisefile folder - Open `nodeserver.js` and begin by writing a Nodejs server, check the first suggestions based on the initial text @@ -24,22 +24,6 @@ server is listening on port 3000 ``` -### Exercise 1: Introduction - - -- In the NodeServer.js develop the rest of the methods described in the Exercise described in the section below (do not forget to open color.json file in Visual Studio Code, so CoPilot get all the context to make better recommendations) -- In the Test.js file add the methods to test the functionality -- Run the tests to verify that all is working -- Open the dockerfile file, and fill it, in order to create a docker container with a node image that can run the web server -- Create command to run docker in port 4000 -- Test that the application is working in port 4000 -- In the **nodeserver.js** file, you can type a new line like //run a curl command to test the server - -So we can see how Copilot based on the current file produces a curl command, to be executed in command line -- Also you can be more specific like: //run a curl command to test the daysBetweenDates method - -So it generates a test for a specific method - ### Exercise 2: Building new functionlities The exercise consist of building a web server using Nodejs that serves the request of various functionality. diff --git a/exercisefiles/node_typescript/README.md b/exercisefiles/node_typescript/README.md index 9b584281..cbee8f44 100644 --- a/exercisefiles/node_typescript/README.md +++ b/exercisefiles/node_typescript/README.md @@ -6,6 +6,8 @@ Demo project for running labs to evaluate Copilot viability ## Instructions +### Exercise 1: Introduction + - Go to the exercisefile folder - Open `nodeserver.ts` and begin by writing a Nodejs server, check the first suggestions based on the initial text - Open `test.ts` file and analyze the current test @@ -25,22 +27,6 @@ server is listening on port 3000 ``` -### Exercise 1: Introduction - - -- In the NodeServer.ts develop the rest of the methods described in the Exercise described in the section below (do not forget to open color.json file in Visual Studio Code, so CoPilot get all the context to make better recommendations) -- In the Test.ts file add the methods to test the functionality -- Run the tests to verify that all is working -- Open the dockerfile file, and fill it, in order to create a docker container with a node image that can run the web server -- Create command to run docker in port 4000 -- Test that the application is working in port 4000 -- In the **nodeserver.ts** file, you can type a new line like //run a curl command to test the server - -So we can see how Copilot based on the current file produces a curl command, to be executed in command line -- Also you can be more specific like: //run a curl command to test the daysBetweenDates method - -So it generates a test for a specific method - ### Exercise 2: Building new functionlities The exercise consist of building a web server using Nodejs that serves the request of various functionality. From 47fc2cdf5d2e07b66b5be6170d521604bba960c9 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Fri, 1 Nov 2024 21:36:55 +0100 Subject: [PATCH 07/24] Fix devcontainer --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9a28f85c..f339d86a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,7 +12,7 @@ "ghcr.io/devcontainers-contrib/features/mocha:2": { "version": "latest" }, - "ghcr.io/devcontainers/features/docker-in-docker:1": { + "ghcr.io/devcontainers/features/docker-in-docker:2": { "version": "latest" }, "ghcr.io/devcontainers/features/java:1": { From 28b4ccba3f2731c612ca1ae1edf1518d8b58b5cf Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Sat, 2 Nov 2024 07:41:21 +0100 Subject: [PATCH 08/24] add first line --- exercisefiles/node_typescript/nodeserver.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exercisefiles/node_typescript/nodeserver.ts b/exercisefiles/node_typescript/nodeserver.ts index f68e5b8f..aac9f6e0 100644 --- a/exercisefiles/node_typescript/nodeserver.ts +++ b/exercisefiles/node_typescript/nodeserver.ts @@ -5,3 +5,5 @@ // if the url has other methods, return "method not supported" // when server is listening, log "server is listening on port 3000" + +import http from 'http'; \ No newline at end of file From 7c7be72c065b7a74a92de16264244ad90d300daa Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Sat, 2 Nov 2024 07:45:56 +0100 Subject: [PATCH 09/24] Fixes renames of files --- exercisefiles/node_typescript/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exercisefiles/node_typescript/README.md b/exercisefiles/node_typescript/README.md index cbee8f44..1cdc883b 100644 --- a/exercisefiles/node_typescript/README.md +++ b/exercisefiles/node_typescript/README.md @@ -43,7 +43,7 @@ The requests that the server must attend are the following: * Calculate days between two dates * receive by query string 2 parameters date1 and date 2, and calculate the days between those two dates. - > **_NOTE:_** Use above information inside the Copilot inline feature in the `nodeserver.js` file. Press enter and wait for Copilot to suggest you the code. + > **_NOTE:_** Use above information inside the Copilot inline feature in the `nodeserver.ts` file. Press enter and wait for Copilot to suggest you the code. - **/Validatephonenumber**: @@ -53,7 +53,7 @@ The requests that the server must attend are the following: * if phoneNumber is valid return "valid" * if phoneNumber is not valid return "invalid" - > **_NOTE:_** Use above information inside the Copilot inline feature in the `nodeserver.js` file. Press enter and wait for Copilot to suggest you the code. + > **_NOTE:_** Use above information inside the Copilot inline feature in the `nodeserver.ts` file. Press enter and wait for Copilot to suggest you the code. - **/ValidateSpanishDNI**: @@ -63,7 +63,7 @@ The requests that the server must attend are the following: * if DNI is valid return "valid" * if DNI is not valid return "invalid" - > NOTE: Use above information inside a comment in the `nodeserver.js` file. In this case, you may want to see multiple solutions from Copilot to pick the one that best fits the way to calculate the letter. In order to see the firs 10 suggestions from Copilot press ctrl + enter. + > NOTE: Use above information inside a comment in the `nodeserver.ts` file. In this case, you may want to see multiple solutions from Copilot to pick the one that best fits the way to calculate the letter. In order to see the firs 10 suggestions from Copilot press ctrl + enter. - **/ReturnColorCode**: From d686f2bfa149e24dc00ba2edc51ea9899bd1a9f7 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Sat, 2 Nov 2024 08:09:15 +0100 Subject: [PATCH 10/24] remove extension --- .devcontainer/devcontainer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f339d86a..724008e0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -34,8 +34,7 @@ "ms-dotnettools.csdevkit", "vscjava.vscode-java-pack", "ms-toolsai.jupyter", - "ms-python.python", - "ms-vscode.vscode-typescript-next" + "ms-python.python" ] } }, From dfdd743cdc09b97bf38badc009050216bd8c6d40 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Wed, 6 Nov 2024 12:28:52 +0100 Subject: [PATCH 11/24] Fix typo's --- exercisefiles/node/README.md | 2 +- exercisefiles/node_typescript/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/exercisefiles/node/README.md b/exercisefiles/node/README.md index 95c16d81..368c6e1b 100644 --- a/exercisefiles/node/README.md +++ b/exercisefiles/node/README.md @@ -24,7 +24,7 @@ server is listening on port 3000 ``` -### Exercise 2: Building new functionlities +### Exercise 2: Building new functionalities The exercise consist of building a web server using Nodejs that serves the request of various functionality. diff --git a/exercisefiles/node_typescript/README.md b/exercisefiles/node_typescript/README.md index 1cdc883b..2f28d7cc 100644 --- a/exercisefiles/node_typescript/README.md +++ b/exercisefiles/node_typescript/README.md @@ -27,7 +27,7 @@ server is listening on port 3000 ``` -### Exercise 2: Building new functionlities +### Exercise 2: Building new functionalities The exercise consist of building a web server using Nodejs that serves the request of various functionality. From f8bacf177d08dfa481260a0ac0766768016f9689 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Fri, 8 Nov 2024 17:55:23 +0100 Subject: [PATCH 12/24] Add complete solution --- .gitignore | 3 + .../node_typescript/.dockerignore | 1 + completesolution/node_typescript/Dockerfile | 29 +++ completesolution/node_typescript/colors.json | 55 +++++ .../node_typescript/nodeserver.ts | 220 ++++++++++++++++++ completesolution/node_typescript/package.json | 25 ++ completesolution/node_typescript/test.ts | 215 +++++++++++++++++ .../node_typescript/tsconfig.json | 110 +++++++++ exercisefiles/node_typescript/test.ts | 2 +- 9 files changed, 659 insertions(+), 1 deletion(-) create mode 100644 completesolution/node_typescript/.dockerignore create mode 100644 completesolution/node_typescript/Dockerfile create mode 100644 completesolution/node_typescript/colors.json create mode 100644 completesolution/node_typescript/nodeserver.ts create mode 100644 completesolution/node_typescript/package.json create mode 100644 completesolution/node_typescript/test.ts create mode 100644 completesolution/node_typescript/tsconfig.json diff --git a/.gitignore b/.gitignore index 0aa96f3b..bd81057a 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,9 @@ build/Release node_modules/ jspm_packages/ +# NPM lock file +package-lock.json + # Snowpack dependency directory (https://snowpack.dev/) web_modules/ diff --git a/completesolution/node_typescript/.dockerignore b/completesolution/node_typescript/.dockerignore new file mode 100644 index 00000000..5309493a --- /dev/null +++ b/completesolution/node_typescript/.dockerignore @@ -0,0 +1 @@ +[D|d]ockerfile \ No newline at end of file diff --git a/completesolution/node_typescript/Dockerfile b/completesolution/node_typescript/Dockerfile new file mode 100644 index 00000000..0086afcd --- /dev/null +++ b/completesolution/node_typescript/Dockerfile @@ -0,0 +1,29 @@ +# 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 new file mode 100644 index 00000000..395bf81f --- /dev/null +++ b/completesolution/node_typescript/colors.json @@ -0,0 +1,55 @@ +[ + { + "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 new file mode 100644 index 00000000..59b4e338 --- /dev/null +++ b/completesolution/node_typescript/nodeserver.ts @@ -0,0 +1,220 @@ +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 new file mode 100644 index 00000000..7da3e48b --- /dev/null +++ b/completesolution/node_typescript/package.json @@ -0,0 +1,25 @@ +{ + "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 new file mode 100644 index 00000000..d68e41ff --- /dev/null +++ b/completesolution/node_typescript/test.ts @@ -0,0 +1,215 @@ +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 new file mode 100644 index 00000000..56a8ab81 --- /dev/null +++ b/completesolution/node_typescript/tsconfig.json @@ -0,0 +1,110 @@ +{ + "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/exercisefiles/node_typescript/test.ts b/exercisefiles/node_typescript/test.ts index bee5cf89..9650c2bb 100644 --- a/exercisefiles/node_typescript/test.ts +++ b/exercisefiles/node_typescript/test.ts @@ -1,5 +1,5 @@ //write npm command line to install mocha -//npm install --global mocha +//npm i --global mocha //npm i --save-dev @types/mocha //command to run this test file //mocha test.js From 155846a6fc0b67a97e5ca892738dbf076d7ddb77 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Sun, 10 Nov 2024 17:56:20 +0100 Subject: [PATCH 13/24] Fix typo and paragraph numbering --- exercisefiles/node/README.md | 4 ++-- exercisefiles/node_typescript/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/exercisefiles/node/README.md b/exercisefiles/node/README.md index 368c6e1b..4775d0c5 100644 --- a/exercisefiles/node/README.md +++ b/exercisefiles/node/README.md @@ -131,7 +131,7 @@ The requests that the server must attend are the following: > **_NOTE:_** Copilot can help you to generate data sets. -### Excercise 2: Document the code +### Excercise 3: Document the code Documenting code is always a boring and painful task. However, we can use Copilot to document it for us. In the chat, ask Copilot to document the `nodeserver.js` file. @@ -155,6 +155,6 @@ With the previous exercises you have gone through some common activities that de - Create documentation - Create tests -However, there are many other things that Copilot can helkp you with. Feel free to explore other slash command in the Copilot chat like: +However, there are many other things that Copilot can help you with. Feel free to explore other slash command in the Copilot chat like: - `/fix`: to fix the problems in your code - `/explain`: for Copilot to explain you what the code does \ No newline at end of file diff --git a/exercisefiles/node_typescript/README.md b/exercisefiles/node_typescript/README.md index 2f28d7cc..e79e8aaa 100644 --- a/exercisefiles/node_typescript/README.md +++ b/exercisefiles/node_typescript/README.md @@ -134,7 +134,7 @@ The requests that the server must attend are the following: > **_NOTE:_** Copilot can help you to generate data sets. -### Excercise 2: Document the code +### Excercise 3: Document the code Documenting code is always a boring and painful task. However, we can use Copilot to document it for us. In the chat, ask Copilot to document the `nodeserver.js` file. @@ -158,6 +158,6 @@ With the previous exercises you have gone through some common activities that de - Create documentation - Create tests -However, there are many other things that Copilot can helkp you with. Feel free to explore other slash command in the Copilot chat like: +However, there are many other things that Copilot can help you with. Feel free to explore other slash command in the Copilot chat like: - `/fix`: to fix the problems in your code - `/explain`: for Copilot to explain you what the code does \ No newline at end of file From 94654eafdb38ba50a766395f906d7dcfcf09b7ab Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Sun, 10 Nov 2024 19:02:26 +0100 Subject: [PATCH 14/24] add import --- exercisefiles/node_typescript/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercisefiles/node_typescript/test.ts b/exercisefiles/node_typescript/test.ts index 9650c2bb..7ace34cb 100644 --- a/exercisefiles/node_typescript/test.ts +++ b/exercisefiles/node_typescript/test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import * as http from 'http'; -//import server from './nodeserver'; +import server from './nodeserver'; describe('Node Server', () => { it('should return "key not passed" if key is not passed', (done: Mocha.Done) => { From 3f4cea80db35b7005e18015cfd75b9baad229bfe Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Sun, 10 Nov 2024 19:03:43 +0100 Subject: [PATCH 15/24] add dependencies --- exercisefiles/node_typescript/package.json | 4 +++- exercisefiles/node_typescript/test.ts | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exercisefiles/node_typescript/package.json b/exercisefiles/node_typescript/package.json index f3be6ddc..e653c8c9 100644 --- a/exercisefiles/node_typescript/package.json +++ b/exercisefiles/node_typescript/package.json @@ -15,6 +15,8 @@ "typescript": "^5.6.3" }, "devDependencies": { - "@types/node": "^22.8.6" + "@types/mocha": "^10.0.9", + "@types/node": "^22.8.6", + "mocha": "^10.8.2" } } diff --git a/exercisefiles/node_typescript/test.ts b/exercisefiles/node_typescript/test.ts index 7ace34cb..0b975d86 100644 --- a/exercisefiles/node_typescript/test.ts +++ b/exercisefiles/node_typescript/test.ts @@ -1,6 +1,4 @@ //write npm command line to install mocha -//npm i --global mocha -//npm i --save-dev @types/mocha //command to run this test file //mocha test.js From 96f80fcea08109df6ae85df8046c0cb914acdc7d Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Sun, 10 Nov 2024 19:08:07 +0100 Subject: [PATCH 16/24] remove import --- exercisefiles/node_typescript/test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/exercisefiles/node_typescript/test.ts b/exercisefiles/node_typescript/test.ts index 0b975d86..ad52885c 100644 --- a/exercisefiles/node_typescript/test.ts +++ b/exercisefiles/node_typescript/test.ts @@ -4,7 +4,6 @@ import * as assert from 'assert'; import * as http from 'http'; -import server from './nodeserver'; describe('Node Server', () => { it('should return "key not passed" if key is not passed', (done: Mocha.Done) => { From 7bacc868b2d9710623728686b41dfcdece6b38d2 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Wed, 13 Nov 2024 08:13:43 +0100 Subject: [PATCH 17/24] Add CLI installation instructions --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d23387f8..5fc3d6b0 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,11 @@ Install the Copilot Extension for you IDE: - [Visual Studio 2022 Copilot Chat Extension](https://learn.microsoft.com/en-us/visualstudio/ide/visual-studio-github-copilot-chat?view=vs-2022) - [JetBrains Copilot Extension](https://docs.github.com/en/copilot/using-github-copilot/getting-code-suggestions-in-your-ide-with-github-copilot?tool=jetbrains) +### Install Copilot CLI + +Follow the instructions for your operating system: +- [Copilot CLI](https://github.com/cli/cli#installation) + ### Work locally **VisualStudio Code** From 6b63f70778e4f749b57a7a76649471845544bd4c Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Wed, 13 Nov 2024 09:46:18 +0100 Subject: [PATCH 18/24] Update dotnet ready to include sample.txt --- exercisefiles/dotnet/README.md | 16 + exercisefiles/dotnet/sample.txt | 500 ++++++++++++++++++++++++++++++++ 2 files changed, 516 insertions(+) create mode 100644 exercisefiles/dotnet/sample.txt diff --git a/exercisefiles/dotnet/README.md b/exercisefiles/dotnet/README.md index 5c0faca8..86abccb8 100644 --- a/exercisefiles/dotnet/README.md +++ b/exercisefiles/dotnet/README.md @@ -120,6 +120,22 @@ _Hint: Pay attention to HttpClient._ > **_NOTE:_** Copilot can also help with these kind of commands locally. The feature is called Copilot in the CLI. You can learn more information about this feature [here](https://docs.github.com/en/copilot/github-copilot-in-the-cli/about-github-copilot-in-the-cli). +- **/GetFullTextFile**: + + * Read `sample.txt`` and return lines that contains the word "Fusce" + + > **_NOTE:_** Becareful with this implementation, since this normally reads the full content of the file before analizing it, so memory usage is high and may fail when files are too big. + > + > You can use Copilot Code completion or inline chat. Once done you can also use Copilot Inline Chat to refactor the code to put this logic in a function. + +- **/GetLineByLinefromtTextFile**: + + * Read `sample.txt` line by line + * Create a promise to read the file line by line, and return a list of lines that contains the word "Fusce" + * Return the list of lines + + > **_NOTE:_** You can use Copilot Code completion or inline chat. Once done you can also use Copilot Inline Chat to refactor the code to put this logic in a function. + - **/calculatememoryconsumption**: * Return the memory consumption of the process in GB, rounded to 2 decimals diff --git a/exercisefiles/dotnet/sample.txt b/exercisefiles/dotnet/sample.txt new file mode 100644 index 00000000..e0662e8d --- /dev/null +++ b/exercisefiles/dotnet/sample.txt @@ -0,0 +1,500 @@ +Lorem ipsum dolor sit amet consectetur, adipiscing elit massa. +Rhoncus nunc lacinia pulvinar faucibus praesent, cursus volutpat semper. +Dis parturient convallis nam, malesuada consequat ante, penatibus feugiat. +Elementum conubia convallis suspendisse netus interdum, etiam faucibus cursus ultrices. +Sociosqu odio montes iaculis inceptos eu, ac pharetra malesuada. +Maecenas enim iaculis cras bibendum sociosqu, facilisi nunc dis. +Lectus natoque faucibus et nam, in dui posuere. +Cubilia phasellus montes sollicitudin lacinia nascetur, cursus enim semper hendrerit. +Eros hendrerit lacinia ridiculus, a fringilla posuere, ac varius. +Molestie magnis arcu mi quisque egestas, nascetur dictum himenaeos rutrum. +Nisl fames cubilia sociis et magnis, ridiculus vel congue. +Neque vel purus primis cum convallis, quisque aliquam dictumst. +Mus auctor lacus aptent purus iaculis, litora quam aenean. +Neque facilisi tempor vivamus pulvinar, quis conubia vestibulum. +Molestie himenaeos mi condimentum est, ornare rutrum integer. +Maecenas nisl nascetur dui dapibus suscipit, neque vestibulum sollicitudin. +Eget class himenaeos nostra mauris, tempus a tellus. +Morbi sed curae tincidunt lacinia nullam, class dui rutrum ornare. +Fames curae egestas sociis vivamus, dignissim suspendisse. +Orci accumsan facilisi urna lectus, molestie gravida aliquet. +Mauris litora elementum quisque tortor, nisl volutpat praesent. +Sem morbi parturient egestas pharetra, habitant dapibus per. +Dictum suscipit vel hac senectus vitae, rhoncus dictumst vivamus cum. +Odio curabitur et blandit, in mattis. +Morbi velit dis inceptos massa libero, natoque pulvinar integer. +Pharetra congue natoque mauris rhoncus gravida, vulputate in suscipit facilisi. +Ultrices mollis blandit placerat volutpat, in platea lectus. +Varius tortor phasellus lacus purus, tincidunt rutrum bibendum. +Risus donec sapien vestibulum ultrices et, curabitur conubia turpis a. +Hac nec ullamcorper parturient nisi felis, luctus et est. +Rutrum orci felis praesent, feugiat dapibus nec, turpis quam. +Faucibus mauris habitasse quam justo egestas, euismod ac nunc ultrices. +Fusce euismod dictumst dapibus fringilla, scelerisque fermentum eleifend. +Neque placerat scelerisque ridiculus gravida faucibus, nec iaculis leo sem. +Arcu velit commodo non tortor, tincidunt pulvinar duis himenaeos, nibh imperdiet turpis. +Primis est taciti libero cras luctus, aliquam himenaeos urna litora. +Curae nunc posuere fringilla nisl mattis, feugiat quam felis. +Conubia eros egestas mus porta suspendisse, varius interdum eget habitant. +Class dui eros pretium penatibus pulvinar, faucibus ac libero. +Nec auctor duis phasellus eu torquent vivamus, erat egestas faucibus sociis. +Lobortis tellus felis sapien, molestie vulputate. +Cum hac euismod turpis sodales, pellentesque nostra integer. +Et cum montes interdum, maecenas sollicitudin dapibus tempor, enim vitae. +Himenaeos nisi platea urna, tincidunt habitasse. +Sodales pretium fermentum suscipit fusce, augue facilisi. +Maecenas semper litora elementum donec, hac massa. +Hendrerit est erat platea, ligula augue rutrum, egestas nisi. +Sapien ridiculus etiam blandit morbi dis, venenatis faucibus placerat. +Urna feugiat cum morbi placerat volutpat, vivamus euismod nascetur. +Senectus porttitor tincidunt nisi ornare conubia, imperdiet malesuada risus. +Luctus faucibus lectus vivamus nisi nunc, odio eu nullam urna. +Habitant enim odio facilisis porttitor egestas nibh, nulla semper proin aenean. +Urna in vehicula fames proin, nostra fringilla. +Tellus purus augue erat tempus laoreet, vivamus tincidunt volutpat. +Mi curae cras class viverra lobortis, tellus commodo iaculis posuere. +Sociis nisi enim fermentum gravida, mi vulputate aliquet. +Id ultricies cum tellus, donec laoreet. +Dignissim placerat metus faucibus, iaculis pellentesque libero, pulvinar ultrices. +Elementum lacus eget praesent hendrerit mi, per nulla duis posuere. +Lobortis eget risus quisque imperdiet bibendum, mi litora praesent. +Dapibus bibendum conubia sagittis faucibus senectus, ullamcorper elementum nunc. +Torquent lacus augue nunc facilisis, dis fringilla cras, inceptos ligula dictum. +Augue taciti pretium mollis sem fringilla, orci magnis cum enim. +Litora turpis sapien metus cubilia, ligula risus nostra. +Justo porttitor mollis dis a duis, sem mauris litora eros. +Tristique ad mus molestie iaculis condimentum, sodales nunc cubilia. +Integer etiam condimentum pretium posuere, magnis sociis cursus. +Accumsan nulla metus magna sodales tortor, lacinia dictumst habitant mus. +Sem rhoncus hac a sagittis, at egestas dapibus. +Pharetra nisi cursus conubia, ante imperdiet curae eu, fringilla blandit. +Ligula vivamus aliquam per pellentesque, praesent nascetur vestibulum. +Felis suspendisse lectus leo augue, libero magnis urna, dignissim habitasse at. +Dictum quisque parturient pharetra, platea blandit. +Mattis aptent hendrerit fusce leo libero suspendisse, sociis eget taciti lacinia. +Lacus accumsan cras dui consequat, libero magnis. +Netus ac penatibus vitae montes velit, fermentum in iaculis conubia. +Suscipit mauris tincidunt scelerisque facilisis proin, faucibus orci blandit. +Conubia montes lacus varius integer, turpis sagittis hac. +Diam arcu laoreet class, ut nec quis, scelerisque taciti. +Blandit vehicula purus erat dictumst, quisque leo neque. +Tellus hac conubia torquent mus, arcu eros vehicula. +Vehicula lacinia vitae litora egestas praesent, proin hendrerit turpis. +Auctor placerat luctus nec sed, cras semper pulvinar. +Felis malesuada vitae laoreet lectus sem convallis, eget sodales habitasse potenti. +Nulla nec nam class mollis quisque, justo facilisis mattis. +Platea euismod magna fusce praesent, natoque turpis. +Ridiculus mus fermentum leo bibendum volutpat, platea magnis mattis. +Placerat habitasse massa quisque nam, nibh maecenas rhoncus. +Dictum interdum laoreet purus primis sapien, at mollis convallis molestie. +Pellentesque maecenas volutpat felis auctor nibh faucibus, cras rutrum eleifend elementum. +Eleifend iaculis pulvinar egestas, cursus quisque. +Magna inceptos diam augue dui eu, mauris risus per. +Magnis orci vitae egestas cursus, luctus sem rutrum. +Tortor natoque cubilia et eu nisl, commodo aenean augue tempor. +Hac sem metus primis tellus, eros imperdiet nec. +Suscipit mollis hendrerit gravida purus, proin mauris nascetur, taciti litora ornare. +Non ac est porttitor neque curae, tortor arcu nisl. +Ut vivamus elementum felis interdum eget, ad eu in. +Tempor eget ut ac ultrices, tellus vel. +Purus eros nisl massa, non conubia. +Vel a nibh erat cras bibendum lacus, laoreet dapibus vivamus urna. +Turpis facilisis accumsan in velit, cubilia montes. +Pharetra mattis egestas bibendum faucibus, duis fusce est. +Ultrices nulla vehicula egestas orci justo, risus nec sodales interdum. +Vel eu scelerisque fames vivamus metus, ultrices condimentum tempus elementum. +Dapibus nunc dui etiam vehicula, consequat suspendisse bibendum. +Posuere per torquent arcu metus, hendrerit ultrices ut. +Mi interdum potenti aptent sem, lacinia lobortis dapibus. +Varius condimentum egestas leo ultricies, sapien iaculis duis. +Vehicula ornare sociosqu porta, nam curabitur euismod dui, blandit velit. +Aliquet suspendisse ultricies fermentum varius, platea porta conubia. +Quisque congue hac odio ultrices, placerat nisi aenean. +Habitant morbi potenti praesent laoreet, eros faucibus eu. +Tristique morbi taciti nascetur quis, mauris enim. +Euismod ad at morbi lacus, viverra magna conubia, penatibus dis cras. +Vehicula tortor aptent feugiat dictum vel, dictumst eu tristique. +Primis justo dui hac mollis nullam, class nascetur mattis. +Fames ultricies elementum malesuada habitant sollicitudin, ut lacus nulla. +Primis sed ut magnis ligula torquent, porta nibh molestie leo. +Interdum dictum magna placerat suspendisse, inceptos integer suscipit. +Morbi odio senectus suscipit egestas, non bibendum leo. +Venenatis ultrices metus sagittis nascetur, bibendum duis. +Pretium cubilia laoreet viverra pulvinar, vehicula lobortis egestas. +Neque sollicitudin placerat libero pulvinar nulla, vulputate sociosqu suscipit. +Rhoncus placerat mauris suspendisse iaculis, laoreet metus a. +Quis rhoncus cras libero scelerisque, hac ridiculus morbi. +Platea nibh congue magnis sapien, torquent vestibulum consequat. +At pharetra viverra curae mauris, quam aptent. +Cras sodales hendrerit laoreet phasellus torquent, magna egestas maecenas. +Laoreet habitasse ridiculus ante, commodo donec. +Facilisi neque augue ligula eros, porta maecenas egestas. +Sagittis mollis dictumst hac nostra vivamus, leo donec pretium. +Blandit faucibus habitasse vel mauris donec, rhoncus urna vestibulum. +Arcu condimentum nibh neque curabitur torquent, laoreet dis accumsan. +Venenatis dictumst scelerisque hac egestas aenean, volutpat tempus cursus. +Scelerisque ullamcorper quis molestie litora malesuada, ac dictum tempor et. +Nam sem justo dictumst bibendum, metus imperdiet. +Vestibulum bibendum varius sollicitudin placerat, viverra cubilia. +Quisque sollicitudin sodales convallis suscipit suspendisse, id metus nec posuere. +Integer vulputate potenti inceptos nec pellentesque, libero scelerisque elementum ultrices. +Conubia pellentesque litora class habitant, auctor rhoncus. +Vulputate facilisi fusce porta gravida, venenatis eu pharetra. +At rhoncus primis convallis sem, pellentesque justo erat, imperdiet velit sed. +Penatibus aliquet ultrices tempus viverra aptent, sodales at nam feugiat. +Aliquet feugiat lobortis justo diam, elementum viverra. +In dictumst scelerisque pharetra, molestie conubia. +Curae quam vitae malesuada habitant, ullamcorper curabitur nascetur. +Sed viverra orci litora, porttitor tellus. +Himenaeos a sociosqu lobortis vulputate faucibus, hac vitae cursus. +Consequat et nam fringilla nec, lacinia vestibulum leo. +Nisl leo cubilia congue habitasse, magnis cursus. +Facilisi interdum praesent erat et, fringilla taciti. +Ultricies sagittis tortor vestibulum mauris nostra, luctus vivamus facilisi gravida. +Rhoncus odio lectus condimentum gravida, penatibus inceptos potenti. +Dictum tempus commodo aptent, venenatis eros id, molestie massa. +Nec at hendrerit dignissim vitae mi, phasellus sapien sagittis habitant. +Class lacinia aliquet tempor augue commodo, tincidunt hendrerit mauris. +Justo cubilia sociosqu id cras penatibus, gravida dictum sagittis. +At curae penatibus quisque nisi, mollis volutpat himenaeos. +Ut facilisis eleifend mi dapibus, integer vestibulum fringilla. +Ornare et nunc mi nec aliquam, porttitor cubilia vehicula. +Euismod tempus torquent viverra ligula cubilia, ad massa nisi sollicitudin. +Tempus urna primis interdum netus diam, elementum feugiat praesent. +Rhoncus ut molestie interdum integer, maecenas iaculis. +Phasellus tellus nulla tempor mattis, interdum inceptos. +Duis dictum a lobortis tincidunt nam, sodales magna vestibulum. +Neque sed fusce velit cursus aenean, torquent justo semper. +Quis aliquet vivamus est velit, dis nibh facilisis. +Augue interdum libero laoreet semper risus, duis metus suspendisse. +Magna dignissim risus vivamus vulputate, vehicula pulvinar ante faucibus, fusce nam magnis. +Cras per consequat auctor tempus posuere, semper ridiculus inceptos. +Metus litora dui euismod, turpis semper blandit, faucibus id. +Cubilia platea consequat egestas nostra, ultrices sodales. +Fames felis vehicula etiam commodo diam, convallis cubilia condimentum. +Aliquet congue pulvinar augue quam, felis natoque praesent. +Himenaeos litora ultricies mauris tristique aliquet, faucibus odio parturient aptent. +Placerat curabitur aenean pharetra venenatis parturient, pulvinar suspendisse velit. +Gravida condimentum ullamcorper dapibus in a, cursus venenatis suscipit aptent. +Placerat sodales bibendum hendrerit molestie curabitur, fringilla luctus purus. +Arcu inceptos torquent montes imperdiet consequat, ullamcorper dictumst cum. +Lacinia mollis sagittis porttitor felis, semper rutrum blandit. +Rutrum pellentesque diam semper ante eros, tempor lacus cubilia sodales. +Convallis vulputate ullamcorper velit pellentesque cum, dignissim sagittis magnis. +Tempus cras interdum risus, blandit. +Accumsan augue primis nostra quisque, pretium nibh parturient. +Quisque tortor sociis non blandit, facilisis vestibulum feugiat. +Torquent tincidunt quisque montes pharetra, arcu felis mattis, dignissim tortor sed. +Dui nullam lacinia ridiculus viverra eros, nec quis lectus quam. +Suspendisse montes odio fringilla venenatis morbi a, dictum facilisi augue risus. +Nulla vel justo morbi eget congue, nostra sagittis platea ad. +Suspendisse euismod penatibus aliquam nunc erat congue, semper justo posuere cras. +Tortor penatibus eu tempor ad, nostra senectus sagittis. +Sociosqu pellentesque nibh mattis lacinia sed fermentum, arcu dis morbi potenti. +At diam felis cras elementum, quis primis. +Elementum porttitor scelerisque dis laoreet, fermentum suspendisse sagittis. +Aenean primis at montes pellentesque, sem varius. +Dui aptent vulputate varius condimentum proin, scelerisque imperdiet massa. +Natoque luctus tincidunt congue nam vehicula, sagittis torquent himenaeos. +Montes in mauris molestie vestibulum, ac volutpat. +Congue enim dignissim egestas ridiculus, massa lacinia elementum. +Gravida sodales aenean potenti netus, aliquet leo nibh, tristique vestibulum integer. +Aenean senectus suspendisse porta, nec eros. +Tortor donec varius phasellus tristique facilisi, ornare augue metus. +Ante quisque vestibulum luctus rutrum ridiculus, cras curabitur aenean. +Condimentum euismod primis nullam facilisis, eget potenti vel, velit suspendisse dignissim. +Donec suspendisse lacus platea laoreet natoque, commodo id auctor sociosqu. +Auctor id justo imperdiet mollis, et congue. +Ante quam sapien dis est, velit a penatibus. +Mattis augue massa platea nisi, aliquet primis. +Venenatis ante dictum porttitor id, pellentesque faucibus ultricies, sociis etiam enim. +Elementum porttitor facilisi a mattis cubilia, nunc auctor aliquet. +Conubia praesent id orci nulla quis, aliquet tincidunt dictumst. +Ac natoque elementum phasellus dignissim sem, nunc fermentum dictumst. +Proin elementum dapibus gravida litora, hendrerit fames inceptos. +Iaculis gravida nulla suscipit sodales, justo in. +Tempus sollicitudin gravida montes diam in, parturient morbi nascetur. +Nunc lobortis augue mattis diam, cubilia leo parturient. +Condimentum ligula conubia commodo, integer fermentum. +Nibh bibendum tincidunt phasellus aliquam, nascetur montes elementum. +Sed himenaeos enim sollicitudin massa tempus, libero metus vehicula. +Ultricies pretium ac ullamcorper vehicula ultrices, bibendum lacus risus himenaeos. +Sed ullamcorper torquent curae vulputate, eget tellus. +Fringilla praesent ullamcorper iaculis massa, et enim eros. +Venenatis aptent semper fusce et, lacinia felis posuere. +Ultricies vehicula eu inceptos aliquam dignissim, nullam venenatis ullamcorper conubia. +Libero porttitor elementum nullam eleifend pulvinar, tellus interdum felis. +Et lacinia facilisis sollicitudin penatibus nibh fames, eleifend aenean dapibus vitae. +Suscipit venenatis varius vivamus malesuada erat, mollis vel potenti pretium. +Dictumst praesent sociis diam pulvinar, auctor sociosqu quisque. +Dictumst porta cursus nullam cubilia, mauris mus. +Erat leo diam potenti lobortis, aenean risus. +Conubia nam taciti ornare blandit venenatis morbi, massa sociis lacinia gravida. +Enim curabitur vulputate in suspendisse, ultrices vehicula. +Fringilla massa dignissim curabitur class, mollis sapien. +Massa nullam diam nascetur fusce dui, purus rhoncus ligula. +Auctor integer libero lectus varius malesuada, curabitur fusce eu ultricies. +Nam faucibus quam viverra ornare hac, eget tempus aenean laoreet. +Vivamus arcu aliquet lobortis maecenas blandit, eleifend risus augue convallis. +Class sollicitudin ligula inceptos egestas, cursus metus dui. +Tempor quis nascetur aptent per habitasse, aliquet nostra ornare. +Praesent augue donec congue, nam libero eget, ornare pellentesque. +Nam arcu vulputate mus ut dignissim, luctus senectus molestie. +Risus molestie ligula dui ut, condimentum enim. +Posuere turpis dictumst laoreet sodales, fusce viverra vivamus. +Ullamcorper consequat pulvinar vestibulum penatibus, hac etiam. +Ultricies feugiat magna bibendum commodo, cras nam dui. +Fringilla inceptos feugiat felis posuere porta, risus proin malesuada tincidunt. +Lectus inceptos tortor eget nec ultricies, orci neque luctus. +Vel accumsan phasellus faucibus taciti, metus himenaeos pharetra. +Molestie faucibus nam posuere pellentesque nibh, nisl tristique scelerisque praesent. +Praesent porttitor malesuada donec sollicitudin, justo quis pellentesque. +Ridiculus aliquet orci commodo tortor in, ultrices praesent inceptos. +Ad semper erat parturient gravida, potenti per vulputate. +Phasellus maecenas mollis eu in, sollicitudin rhoncus natoque. +Est arcu eleifend penatibus nulla donec, diam non neque. +Odio mattis nascetur feugiat interdum, vehicula ligula facilisi. +Torquent neque donec aliquet magna, vivamus bibendum non. +Semper iaculis ultrices duis eleifend montes, vivamus justo maecenas. +Eleifend venenatis nisl primis, molestie sociosqu odio ornare, faucibus curae. +Consequat tempus maecenas magnis fringilla netus quam, nec arcu dictum enim. +Dictum aenean accumsan dictumst, integer lacus inceptos curabitur, mattis purus. +Cum placerat sodales elementum velit, eget felis. +Platea aliquet mollis dui nibh, aenean hac ligula. +Vestibulum iaculis conubia aenean facilisi, nullam himenaeos sapien. +Velit mauris turpis posuere ad, habitant inceptos neque. +Conubia mi nulla iaculis, cursus scelerisque. +Tellus fermentum tempus interdum montes, sapien sed. +Blandit maecenas eget nostra tellus, platea purus. +Mus torquent justo scelerisque vel, suscipit non ornare. +Lacus nunc ornare convallis dictum aliquet, phasellus cursus porttitor. +Torquent quam fames sollicitudin faucibus class, dictum per lobortis. +Cubilia suspendisse eget luctus, lectus praesent venenatis, dictum sapien. +Arcu justo quisque ad ridiculus tristique, pulvinar hendrerit vel. +Vivamus porttitor aliquet potenti nunc phasellus, egestas justo libero etiam. +Class ridiculus aenean fusce pulvinar eu, ligula imperdiet rhoncus natoque. +Phasellus mus aliquam montes lacus felis odio, class dignissim cubilia a. +Porttitor porta nostra convallis lectus, netus accumsan vitae. +Molestie habitant vel integer, hendrerit sapien. +Nunc quisque lectus condimentum nulla velit dictumst, sem porttitor dis enim urna. +Rutrum tortor ante litora lacinia lacus, justo gravida sociis. +Lacinia dapibus ligula platea interdum metus, faucibus quisque lacus. +Ullamcorper per est lectus, scelerisque molestie, iaculis lacinia. +Mi consequat eleifend hendrerit egestas odio, cursus blandit sodales bibendum. +Iaculis turpis erat tempor venenatis cum, ad in fringilla. +Platea posuere est mi lobortis, nostra parturient. +Habitasse tristique maecenas nisl, aptent semper quisque porttitor, diam felis. +Blandit sociosqu eget nascetur ultricies, platea per sapien. +Cras turpis dignissim quis rhoncus, inceptos vehicula aenean. +Tristique sollicitudin massa ultrices conubia class, non quisque placerat cras. +Tellus at magnis nibh nulla, congue curabitur viverra. +Rutrum iaculis pharetra auctor faucibus parturient, venenatis accumsan pellentesque porttitor. +Libero feugiat purus ut viverra, erat neque pellentesque. +Interdum blandit magnis nisl eros eleifend, rutrum ac velit faucibus. +Cursus rhoncus lacus iaculis sollicitudin arcu, mauris varius vel. +Natoque sociosqu tortor aptent phasellus, semper lobortis pretium. +Sed accumsan orci maecenas potenti, consequat porta. +Condimentum blandit hac gravida, vehicula nunc ultrices cras, sociosqu donec. +Venenatis morbi cubilia lacinia vitae at, dignissim himenaeos nulla dis. +Enim suscipit hac pharetra eu, vitae dictum posuere. +Nibh nam felis ridiculus, suspendisse fringilla, turpis facilisis. +Fames nisl urna neque nullam, vehicula scelerisque. +Dis dictumst ultricies taciti fermentum integer, metus tellus est eu. +Blandit orci odio hendrerit laoreet iaculis, sociosqu felis mauris vitae. +Ligula tincidunt felis suspendisse pretium maecenas, consequat luctus varius. +Mattis rutrum pharetra id eu montes, aptent integer volutpat. +Condimentum neque quam accumsan vel tellus, fusce lectus nunc. +Sollicitudin senectus vivamus nunc, duis fermentum auctor non, luctus nisi. +Dictum duis sociis sed eget mattis felis, varius commodo pretium nascetur. +Sociosqu eget tempor dui erat scelerisque, feugiat placerat lacus. +Pulvinar felis fames litora mattis pretium, proin congue dictumst. +Ante ridiculus aliquet tristique, luctus scelerisque. +Ornare senectus non convallis nisl, suscipit curae porta. +In platea ante nullam habitasse, cubilia enim. +Varius vehicula orci ultrices metus fames, cras fermentum ut penatibus. +Dignissim laoreet aptent malesuada nullam, curabitur accumsan netus. +Et penatibus ut blandit, turpis metus placerat, suspendisse dapibus. +Velit risus tempor id facilisis, nostra dignissim quisque. +Fusce senectus netus id vel rutrum, odio curae venenatis. +Tellus rutrum purus imperdiet, curae. +Urna odio senectus ridiculus mus ad, hac mattis dui nisi. +Faucibus tortor risus quisque mattis magnis, diam tincidunt in. +Semper blandit interdum urna quam, commodo sociis. +Interdum magna venenatis urna praesent porta, torquent arcu potenti. +Convallis fringilla tempor posuere egestas cursus, faucibus orci donec. +Ridiculus scelerisque nibh est, fermentum arcu potenti, sodales curae. +Semper porttitor rutrum sociis habitasse, interdum curabitur. +Rutrum aliquet netus risus ante nunc, primis venenatis arcu. +Curae mollis eleifend magnis netus, faucibus congue lacus. +Facilisis sem litora ad aptent, natoque a vel. +Dui quis porta congue vivamus suscipit justo, fringilla ultricies convallis maecenas. +Eleifend non primis arcu varius, at tellus pellentesque. +Aenean nibh dis orci justo, feugiat ridiculus urna. +Parturient cursus consequat luctus libero placerat, purus pharetra pulvinar. +Hendrerit velit augue purus, justo proin placerat bibendum, cum ut. +Vestibulum cubilia maecenas pellentesque, vitae orci curabitur, nam suspendisse. +In porta mauris fringilla, praesent cursus. +Consequat at parturient nostra quam, libero senectus. +Accumsan quis eleifend porta integer lobortis, aliquet tristique condimentum litora. +Luctus donec pellentesque ullamcorper nullam, aptent rhoncus eros. +Scelerisque himenaeos sapien parturient nisi senectus, cum per nulla. +Eleifend aptent luctus sollicitudin convallis nisl, ullamcorper egestas dis. +Dapibus egestas proin ac, porttitor magnis imperdiet mi, vel ultrices. +Potenti justo natoque ut torquent malesuada, magnis eget nostra. +Dictum felis sed maecenas turpis etiam, augue aliquam lobortis. +Suscipit vitae elementum mollis mi, sollicitudin non rutrum. +A eleifend fames cum felis, quam class ad. +Parturient malesuada egestas leo platea, rutrum montes mauris. +Ac aliquet sodales ornare pulvinar auctor, dictumst et malesuada. +Curae quis ut venenatis lacus, rutrum turpis. +Etiam dapibus auctor iaculis pretium, dictum hac mus, parturient faucibus sagittis. +Pretium tempus luctus class magna potenti, nunc eleifend maecenas. +Faucibus ultricies sed nascetur, posuere consequat integer, ultrices eros. +Est fusce litora fermentum praesent mus, vivamus lectus gravida. +Diam sollicitudin hendrerit quam taciti iaculis, curae eu imperdiet. +Potenti quisque bibendum habitant facilisi sodales luctus, dignissim dictum est etiam. +Gravida sapien conubia suscipit sem cubilia, magna feugiat porttitor vestibulum. +Eget sollicitudin rhoncus netus in sapien, venenatis habitant morbi semper. +Nibh montes sociis dapibus vel tempor, erat curabitur sociosqu habitasse. +Aliquet et sodales rhoncus auctor, fusce ad. +Litora blandit turpis class cras, montes nullam. +Class semper etiam ultricies dapibus, erat proin sapien. +Fusce nisi lacinia vel arcu, et cubilia. +Aptent mauris pellentesque metus vel, erat nunc nostra. +Vestibulum eros inceptos dictumst platea, nostra sem. +Aptent accumsan netus id faucibus egestas, tempus donec pharetra. +Ultrices lectus penatibus primis malesuada mollis, eleifend facilisi ac. +Senectus lacus neque fusce, nisl nostra. +Dignissim libero litora lacus eu inceptos magnis, blandit gravida lectus eget. +Et at cum cursus nascetur praesent, arcu viverra interdum fames. +Pretium molestie curae enim gravida, volutpat rutrum porttitor. +Interdum maecenas volutpat hendrerit hac, sollicitudin nibh. +Ornare nibh lacus hac volutpat neque, felis consequat aliquam nulla. +Iaculis pharetra netus praesent aliquet aptent, lobortis volutpat viverra. +Odio penatibus pulvinar sociosqu quis, nibh malesuada fames. +Dignissim porttitor platea tempor non imperdiet, ac viverra urna. +Eros congue laoreet praesent posuere netus pulvinar, ligula ad a auctor vulputate. +Nascetur euismod pretium vulputate vestibulum sed, sagittis dapibus primis quisque. +Aliquam sodales sociosqu eu, nisl euismod mollis orci, convallis pharetra. +Turpis non metus dui, sed euismod aenean, porttitor curae. +Scelerisque metus felis leo congue lacinia, laoreet netus tempor. +Vehicula netus eu vitae, metus tincidunt eros habitant, phasellus ligula. +Neque aenean quis porttitor sapien mollis, vestibulum eget lobortis. +Commodo augue et egestas fringilla, phasellus eget venenatis. +Fermentum ultrices ornare ullamcorper nunc viverra, vivamus ridiculus enim. +Pellentesque sodales tincidunt primis facilisi consequat, aliquet cum libero. +Magna dictum porta rutrum fermentum, ornare elementum. +Convallis sem posuere orci mauris, sociosqu laoreet. +Euismod mollis arcu ligula non, lobortis tempor proin. +Gravida vestibulum taciti tortor potenti netus, iaculis habitant quisque. +Torquent eros nunc dictum habitasse quis imperdiet, mollis faucibus maecenas tristique. +Placerat cras hac cubilia justo, sociosqu lacus parturient. +Pharetra vivamus pulvinar tortor dui, nostra sagittis nunc. +Ante ad auctor donec, sodales suspendisse facilisi, purus id. +Molestie nisi vehicula eu sagittis aliquet, non auctor phasellus. +Penatibus dictum nullam lobortis sapien cras risus, curae volutpat nisl tellus. +Vitae tempus ultrices cubilia mattis, libero proin. +Sagittis nibh ornare senectus, in sociis condimentum potenti, dictum iaculis. +Sollicitudin mollis cursus litora nam fringilla, nibh dis nisi consequat. +Consequat diam dictumst molestie vitae, purus maecenas turpis. +Nullam ornare praesent dui torquent fusce vestibulum, velit duis sollicitudin pretium dapibus. +Vivamus aliquet leo nullam vestibulum, semper molestie sapien. +Penatibus pharetra scelerisque venenatis neque, viverra nam. +Primis vitae ut tellus ante auctor, quis etiam feugiat. +Mollis sapien suspendisse massa nisi sociis, mattis quam eu interdum. +Nisl hendrerit aliquam platea cursus sed, erat condimentum conubia. +Eu odio mi praesent pharetra, egestas cursus curabitur. +Potenti scelerisque netus enim cursus, convallis mattis lobortis. +Netus arcu justo tellus non pulvinar, praesent nam nascetur. +Praesent sollicitudin blandit dui varius, ligula magnis. +Dis etiam nec dictumst est vivamus, mollis hendrerit taciti. +Iaculis accumsan convallis mi velit, egestas porttitor congue. +Arcu imperdiet varius sapien sodales faucibus, quis lobortis in. +Inceptos sollicitudin ridiculus mus rhoncus conubia congue, curabitur lectus tellus ultrices. +Pretium gravida urna integer habitasse, justo placerat luctus. +Hac curae malesuada tristique habitant mollis, ullamcorper dictumst dictum. +Conubia varius proin habitasse magna per, odio interdum pharetra dignissim. +Erat nulla nibh fusce molestie natoque, metus habitant hac quis. +Inceptos himenaeos mus posuere, iaculis auctor et porta, elementum duis. +Etiam tempor phasellus pretium potenti, fermentum mus. +Dictum tristique aenean nostra, dictumst orci. +Rhoncus lobortis fames in donec proin natoque, fermentum turpis nunc senectus. +Lacus semper platea volutpat et, dis quis varius. +Accumsan nullam urna senectus massa, consequat penatibus. +Suspendisse praesent cum tempor, tortor vulputate. +Iaculis dictum magnis augue suspendisse, rhoncus neque. +Sodales varius donec mauris egestas nec rutrum, litora vehicula non vestibulum duis. +Ad aenean pharetra venenatis sapien auctor, rutrum elementum ridiculus mauris. +Mollis mi quisque metus, odio convallis aliquam, volutpat at. +Nisl blandit class interdum parturient velit est, faucibus tempus egestas duis. +Faucibus senectus magna non consequat, euismod eu volutpat. +Dictum viverra parturient sed, maecenas eget egestas, sagittis dis. +Tellus netus sollicitudin montes ullamcorper, interdum class felis. +Tempor laoreet fames sodales varius justo, leo lacinia torquent. +Pellentesque potenti auctor cras donec turpis non, diam a dictumst nisi. +Condimentum ligula varius diam neque vitae, lacus quisque praesent. +Eleifend phasellus facilisis mi nisi congue, ad velit platea. +Taciti donec congue faucibus etiam sociosqu, venenatis eget class. +Sociis imperdiet ac in urna nisl, tempor consequat luctus sapien. +Montes est primis arcu accumsan, donec phasellus integer. +Suspendisse fringilla vehicula tristique vulputate class nostra, donec torquent non sociosqu. +Inceptos sociosqu blandit magna velit dui, sapien vehicula tempus. +Ultricies turpis diam egestas penatibus vivamus, facilisi mollis lacinia. +Dignissim eu nibh diam volutpat, habitasse conubia lobortis, dui nisl curabitur. +Blandit risus eget vulputate ornare sociis sagittis, rhoncus pulvinar quis proin. +Non pellentesque purus suscipit nascetur, cras cum lacus. +Dignissim varius lectus augue condimentum, mollis ac auctor. +Tempus nec mus eget, porttitor congue varius vivamus, fusce faucibus. +Nullam egestas magnis cursus nisi, dui integer quisque. +Ut aenean mi auctor a, semper ad purus. +Euismod lacinia neque penatibus placerat, risus litora aenean, potenti in vehicula. +Nascetur quis cubilia porta nisl orci, nam ad augue aliquet. +Pellentesque justo fusce condimentum consequat congue, facilisi per primis suscipit. +Aliquam eget vel gravida curae pellentesque, non nullam enim. +Id conubia arcu neque suspendisse, maecenas et. +Cubilia faucibus volutpat natoque facilisis cras, placerat habitant etiam eros. +Nostra curabitur quisque purus congue vestibulum, per rhoncus scelerisque. +Maecenas vitae feugiat curae scelerisque ultricies tincidunt, lacinia pellentesque netus aenean. +Porta risus cubilia himenaeos in sagittis, facilisi euismod taciti. +Cras praesent a platea justo morbi, eget fusce habitant egestas. +Maecenas diam condimentum fames inceptos, posuere netus convallis, mollis aliquet commodo. +Porta montes volutpat malesuada sagittis mollis eleifend, fringilla et lacus tempor metus. +Sodales ligula molestie curae gravida, morbi erat imperdiet. +Convallis magna tempus proin natoque, consequat dignissim. +Aliquet litora cras primis imperdiet, non nisi tristique. +Phasellus non ad fermentum varius venenatis, eleifend dui taciti odio. +Luctus rhoncus aenean ligula nulla tincidunt, maecenas cubilia nostra ornare. +Eget libero aenean montes, urna vehicula torquent, nec maecenas. +Fringilla pharetra parturient suscipit feugiat ullamcorper, nullam commodo vel dui. +Malesuada habitasse curabitur sapien hendrerit, mattis nullam maecenas. +Fames platea enim mi, nam nisl congue, at ligula. +Vulputate orci nulla sodales fringilla sagittis, platea lacinia quam. +Himenaeos penatibus mi euismod posuere mus, lobortis nibh nunc. +Eget aliquam nostra bibendum nec, ridiculus sociosqu in. +Nec ullamcorper convallis lacinia sodales mus, primis taciti nunc. +Curabitur nulla vivamus sollicitudin porttitor, per dapibus risus, quis sodales aptent. +Lobortis vitae euismod eros metus, volutpat elementum nam. +Pulvinar duis volutpat pretium interdum ridiculus, dignissim posuere metus. +Nam mauris dictumst cursus ut, pharetra hac laoreet. +Fringilla sollicitudin posuere mauris nostra, scelerisque massa commodo. +Dignissim nibh vulputate mauris sociis magnis, eu pretium torquent scelerisque. +Hac cursus convallis natoque ultrices, fusce orci vitae. +Id eu faucibus nunc luctus, lacus et dis. +Nisi sed suspendisse euismod ultricies taciti, fames sollicitudin auctor metus. +Nibh odio blandit pulvinar litora ligula, feugiat vitae tellus. +Volutpat mauris venenatis vulputate eu, semper class aliquam. +Faucibus nisl ac aptent nascetur purus, fusce rutrum est pellentesque. +Lacus ad nascetur molestie etiam felis pellentesque, nibh magnis phasellus nisl. +Per metus nulla lacus, ullamcorper ultrices elementum quisque, magna rhoncus. +Nullam senectus cras molestie rhoncus, ultricies vestibulum et. +Dictumst facilisis dapibus ridiculus id, ullamcorper lacinia quisque, conubia tellus fames. +Etiam integer ligula quisque parturient, fringilla euismod. +Mollis nostra est posuere metus proin, malesuada et aptent platea. +Accumsan interdum viverra pulvinar iaculis cras, mi dictum vel nisi. +Rhoncus arcu cum rutrum mus porttitor, diam dis quis. +Duis at sociosqu nisi magna, laoreet habitant facilisis. +Suspendisse integer curabitur gravida mus est, viverra at tellus. +Lectus condimentum mauris ligula sapien elementum, per vehicula praesent. +Dis lacinia habitasse ultricies class, fermentum duis. +Nisl curae consequat aptent mollis eros, luctus velit per. +Mattis porta ullamcorper integer natoque, sollicitudin cubilia. \ No newline at end of file From 4beaba54f03d883f4003e47aa6e1db153d1a2ac7 Mon Sep 17 00:00:00 2001 From: Joost Voskuil Date: Wed, 13 Nov 2024 11:24:19 +0100 Subject: [PATCH 19/24] fix typo in README.md --- exercisefiles/node_typescript/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercisefiles/node_typescript/README.md b/exercisefiles/node_typescript/README.md index e79e8aaa..b22b1d85 100644 --- a/exercisefiles/node_typescript/README.md +++ b/exercisefiles/node_typescript/README.md @@ -136,7 +136,7 @@ The requests that the server must attend are the following: ### Excercise 3: Document the code -Documenting code is always a boring and painful task. However, we can use Copilot to document it for us. In the chat, ask Copilot to document the `nodeserver.js` file. +Documenting code is always a boring and painful task. However, we can use Copilot to document it for us. In the chat, ask Copilot to document the `nodeserver.ts` file. ### Exercise 4: Building tests From fec4d694556324a92bcbd04c57c36237806fd574 Mon Sep 17 00:00:00 2001 From: Jeff Brimager Date: Mon, 16 Jun 2025 10:51:28 -0500 Subject: [PATCH 20/24] updated python and maven versions as well as mocha path Signed-off-by: Jeff Brimager --- .devcontainer/devcontainer.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 724008e0..a9f560f5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -9,7 +9,7 @@ "nodeGypDependencies": true, "version": "lts" }, - "ghcr.io/devcontainers-contrib/features/mocha:2": { + "ghcr.io/devcontainers-extra/features/mocha:2": { "version": "latest" }, "ghcr.io/devcontainers/features/docker-in-docker:2": { @@ -17,10 +17,11 @@ }, "ghcr.io/devcontainers/features/java:1": { "version": "17", - "installMaven": true + "installMaven": true, + "mavenVersion": "3.9.10" }, "ghcr.io/devcontainers/features/python:1": { - "version": "3.8" + "version": "3.11" } }, "customizations": { @@ -49,5 +50,5 @@ // } // } // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" + // "remoteUser": "root" } \ No newline at end of file From 0c4181f5a2a805c4fbc5f545b1a59074ca46bf07 Mon Sep 17 00:00:00 2001 From: Raffaele Marcello Date: Mon, 26 May 2025 02:22:08 +0200 Subject: [PATCH 21/24] Add Expense Tracker challenge and placeholders for backend and frontend --- README.md | 1 + challenges/expensetracker/README.md | 78 +++++++++++++++++++ .../expensetracker/backend/placeholder.md | 0 .../expensetracker/frontend/placeholder.md | 0 4 files changed, 79 insertions(+) create mode 100644 challenges/expensetracker/README.md create mode 100644 challenges/expensetracker/backend/placeholder.md create mode 100644 challenges/expensetracker/frontend/placeholder.md diff --git a/README.md b/README.md index 5fc3d6b0..603fe5c5 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ Run: - [Develop a chat based on websockets](./challenges/chatwebsockets/chatwebsockets.md) - [Behavior Driven Development (BDD) challenge](./challenges/bdd/README.md) - [Analysis cryptocurrency market](./challenges/cryptoanalisis/crypto.md) +- [Expnse Tracker](./challenges/expensetracker/README.md) ## Quick Links diff --git a/challenges/expensetracker/README.md b/challenges/expensetracker/README.md new file mode 100644 index 00000000..0938f75a --- /dev/null +++ b/challenges/expensetracker/README.md @@ -0,0 +1,78 @@ +# Develop an Expense Tracker + +## 1. Problem Description + +Build an **Expense Tracker** microservice that helps users log daily expenses and visualize their spending patterns. The system should allow users to add expenses with categories, view spending summaries, and get insights into their financial habits. + +### Core Requirements: +- **Frontend**: Frontend interface for adding expenses and viewing summaries +- **Backend**: RESTful API (.NET Core, Python Flask, or Node.js Express) for expense management +- **Data Management**: Store expenses with amount, category, date, and description +- **Visualization**: Simple charts/graphs showing spending by category and over time +- **Categories**: Predefined spending categories (Food, Transport, Entertainment, etc.) + +### User Stories: +1. As a user, I can add a new expense with amount, category, and description +2. As a user, I can view all my expenses in a list format +3. As a user, I can see total spending for the current month +4. As a user, I can view spending breakdown by category +5. As a user, I can delete expenses I added by mistake + +## 2. Hints + +### Technical Implementation Hints: +- **Data Structure**: Simple expense object with id, amount, category, date, description +- **Storage**: In-memory array/list (no database needed) +- **Categories**: Fixed list like ["Food", "Transport", "Entertainment", "Shopping", "Bills"] +- **Charts**: Use Chart.js, Recharts, or simple CSS bars for visualization +- **Date Handling**: Use current date as default, allow manual date selection + +### Quick Start Tips: +- Start with add/list functionality first +- Use form validation for amount (must be positive number) +- Keep categories simple - just 5-6 predefined options +- Focus on current month data to keep calculations simple +- Use mock data initially to test the UI + +## 3. Time Needed + +**Estimated Duration: 45-60 minutes** + +### Time Breakdown: +- **Setup** (5-10 minutes): Project structure, dependencies +- **Backend CRUD** (15-20 minutes): Add expense, list expenses, delete expense endpoints +- **Frontend Forms** (15-20 minutes): Add expense form, expense list, basic styling +- **Summary/Charts** (10-15 minutes): Category totals, simple visualization + +## 4. Extra Features (Bonus Challenges) + +Quick additions for teams that finish early: + +### Easy Additions (5-10 minutes each): +- **Edit Expenses**: Modify existing expense entries +- **Date Filtering**: Filter expenses by date range +- **Expense Search**: Search expenses by description +- **Export Data**: Download expenses as CSV + +### Medium Additions (10-15 minutes each): +- **Budget Limits**: Set monthly budgets per category with warnings +- **Recurring Expenses**: Add monthly recurring expenses automatically +- **Tags**: Add custom tags to expenses for better organization +- **Receipt Notes**: Add notes or receipt numbers to expenses + +### Why Perfect for 1-Hour Challenge: +- **Relatable Problem**: Everyone tracks expenses or should +- **Clear CRUD Operations**: Standard create, read, delete patterns +- **Simple Calculations**: Basic arithmetic for totals and averages +- **Visual Results**: Charts and summaries provide immediate feedback +- **Practical Utility**: Participants build something actually useful + +### Success Criteria: +- ✅ Can add new expenses +- ✅ Can view list of expenses +- ✅ Can see monthly total +- ✅ Can delete expenses +- ✅ Shows category breakdown +- ✅ Basic styling/layout + +This challenge combines practical business logic, data visualization, and user experience design - perfect for demonstrating real-world application development skills in a short timeframe! \ No newline at end of file diff --git a/challenges/expensetracker/backend/placeholder.md b/challenges/expensetracker/backend/placeholder.md new file mode 100644 index 00000000..e69de29b diff --git a/challenges/expensetracker/frontend/placeholder.md b/challenges/expensetracker/frontend/placeholder.md new file mode 100644 index 00000000..e69de29b From 28959829afd5d64485d04329a03ce67c2496557e Mon Sep 17 00:00:00 2001 From: Raffaele Marcello Date: Mon, 26 May 2025 02:23:22 +0200 Subject: [PATCH 22/24] Fix typo in Expense Tracker link in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 603fe5c5..c7a6415b 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ Run: - [Develop a chat based on websockets](./challenges/chatwebsockets/chatwebsockets.md) - [Behavior Driven Development (BDD) challenge](./challenges/bdd/README.md) - [Analysis cryptocurrency market](./challenges/cryptoanalisis/crypto.md) -- [Expnse Tracker](./challenges/expensetracker/README.md) +- [Expense Tracker](./challenges/expensetracker/README.md) ## Quick Links From f40a01cd013841e213e6464332ac418e4d2b9a48 Mon Sep 17 00:00:00 2001 From: Raffaele Marcello Date: Mon, 26 May 2025 09:15:54 +0200 Subject: [PATCH 23/24] Add instructions for working in the correct directory for frontend and backend --- challenges/expensetracker/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/challenges/expensetracker/README.md b/challenges/expensetracker/README.md index 0938f75a..2650ef11 100644 --- a/challenges/expensetracker/README.md +++ b/challenges/expensetracker/README.md @@ -34,6 +34,13 @@ Build an **Expense Tracker** microservice that helps users log daily expenses an - Focus on current month data to keep calculations simple - Use mock data initially to test the UI +### +If you are using the Agent mode and notice that the agent is working in the wrong directory, try to add the following line to your prompt: +```markdown +Work in the directory backend. When run terminal remember to change the right directory, for example: `cd challenges/expensetracker/backend && `. +``` +Change the directory to `frontend` when working on the frontend part. + ## 3. Time Needed **Estimated Duration: 45-60 minutes** From 9fdf3e045c86716a6f025a5b3ecddd4e201f271a Mon Sep 17 00:00:00 2001 From: Raffaele Marcello Date: Mon, 26 May 2025 09:17:59 +0200 Subject: [PATCH 24/24] Add section header for Agent Mode Note in README.md --- challenges/expensetracker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/challenges/expensetracker/README.md b/challenges/expensetracker/README.md index 2650ef11..f3b57ac6 100644 --- a/challenges/expensetracker/README.md +++ b/challenges/expensetracker/README.md @@ -34,7 +34,7 @@ Build an **Expense Tracker** microservice that helps users log daily expenses an - Focus on current month data to keep calculations simple - Use mock data initially to test the UI -### +### Agent Mode Note: If you are using the Agent mode and notice that the agent is working in the wrong directory, try to add the following line to your prompt: ```markdown Work in the directory backend. When run terminal remember to change the right directory, for example: `cd challenges/expensetracker/backend && `.