diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0104402d..a9f560f5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -9,18 +9,19 @@ "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:1": { + "ghcr.io/devcontainers/features/docker-in-docker:2": { "version": "latest" }, "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": { @@ -38,7 +39,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. @@ -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 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/.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/.gitignore b/.gitignore index c4bc6144..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/ @@ -528,3 +531,42 @@ FodyWeavers.xsd # JetBrains Rider *.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 69726af1..c7a6415b 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Demo project for running labs to evaluate Copilot viability - [Work with Github Codespaces](#work-with-github-codespaces) - [Work locally](#work-locally) - [Instructions](#instructions) +- [Quick Links](#quick-links) ## Goal @@ -34,10 +35,24 @@ If you still do not have an active Copilot license, a 30 day trial can be reques ### Work with GitHub Codespaces -Environment is already configured to work with Github Codespaces, you can find the configuration files in the .devcontainer folder. +Environment is already configured to work with Github Codespaces, you can find the configuration files in the `.devcontainer` folder. To start programming just start a new codespace and you are ready to go, don't need to install anything. +### IDE Extensions + +Install the Copilot Extension for you IDE: + +- [Visual Studio Code Copilot Extension](https://docs.github.com/en/copilot/using-github-copilot/getting-code-suggestions-in-your-ide-with-github-copilot?tool=vscode) +- [Visual Studio 2022 Copilot Extension](https://learn.microsoft.com/en-us/visualstudio/ide/visual-studio-github-copilot-extension?view=vs-2022) +- [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** @@ -72,14 +87,19 @@ 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) +- [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) - [Python Data Engineer](./exercisefiles/dataengineer/README.md) - [Python Data Scientist](./exercisefiles/datascientist/README.md) +- [C++](./exercisefiles/c++/README.md) ## Challenges instructions @@ -87,4 +107,21 @@ Run: - [Develop a memory game](./challenges/memorygame/memorygame.md) - [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) \ No newline at end of file +- [Analysis cryptocurrency market](./challenges/cryptoanalisis/crypto.md) +- [Expense Tracker](./challenges/expensetracker/README.md) + +## Quick Links + +1. [About GitHub Copilot](https://docs.github.com/en/copilot/about-github-copilot) + +2. [Getting started with GitHub Copilot](https://docs.github.com/en/copilot/using-github-copilot/getting-started-with-github-copilot) + +3. [About code referencing in GitHub Copilot](https://docs.github.com/en/copilot/using-github-copilot/finding-public-code-that-matches-github-copilot-suggestions) + +4. [Using GitHub Copilot Chat in your IDE](https://docs.github.com/en/copilot/github-copilot-chat/using-github-copilot-chat-in-your-ide) + +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 MS Learn Modules](https://learn.microsoft.com/en-us/training/browse/?terms=github%20copilot) + +7. [GitHub Copilot Certifications](https://resources.github.com/learn/certifications/) diff --git a/Resources/Learning some of GitHub Copilot features.ipynb b/Resources/Learning some of GitHub Copilot features.ipynb new file mode 100644 index 00000000..d2251dc2 --- /dev/null +++ b/Resources/Learning some of GitHub Copilot features.ipynb @@ -0,0 +1,132 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Setting Up GitHub Copilot\n", + "Instructions on how to install and set up GitHub Copilot in your IDE." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Step 1: Open Visual Studio Code\n", + "# Step 2: Click on the Extensions view icon on the Sidebar\n", + "# Step 3: Search for 'GitHub Copilot'\n", + "# Step 4: Click on the first result to open the extension's details\n", + "# Step 5: Click on the install button\n", + "# Step 6: Once installed, GitHub Copilot will automatically start providing suggestions when you write code" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using Inline Ghost Prompts\n", + "Exercises to practice using inline ghost prompts, which provide suggestions as you type." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Step 7: Start a new Python file\n", + "# Step 8: Begin typing a Python function or statement\n", + "# For example, let's define a function to calculate factorial of a number\n", + "\n", + "def factorial(n):\n", + " # As you type, GitHub Copilot will automatically suggest the rest of the code\n", + " # Here, it might suggest the base case for the recursive function\n", + " if n == 0:\n", + " return 1\n", + " # It might then suggest the recursive case\n", + " else:\n", + " return n * factorial(n-1)\n", + "\n", + "# Step 9: Accept the suggestion by pressing the Tab key on your keyboard\n", + "# Step 10: Test the function with some inputs\n", + "\n", + "print(factorial(5)) # Expected output: 120\n", + "print(factorial(3)) # Expected output: 6\n", + "\n", + "# Step 11: Continue practicing with other functions and observe the suggestions provided by GitHub Copilot\n", + "# Remember, the suggestions are based on patterns and code snippets from public code repositories, so they might not always be perfect or optimal. Always review and test the code before using it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Interacting with GitHub Copilot Chat\n", + "Guidelines on how to use the GitHub Copilot chat for interactive programming help." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Step 12: Interacting with GitHub Copilot Chat\n", + "# GitHub Copilot also provides a chat interface for interactive programming help\n", + "# To use this feature, follow these steps:\n", + "\n", + "# Step 12.1: Open the command palette with `Ctrl+Shift+P` (Windows/Linux) or `Cmd+Shift+P` (Mac)\n", + "# Step 12.2: Type `GitHub Copilot: Open Chat` and select the command\n", + "# Step 12.3: In the chat interface, you can ask programming questions or request code snippets\n", + "# For example, you can ask \"How to write a function to calculate Fibonacci series in Python?\"\n", + "\n", + "# Note: The chat interface is a new feature and might not be available in all regions or for all users. If you don't see the `GitHub Copilot: Open Chat` command, make sure you have the latest version of the GitHub Copilot extension and Visual Studio Code.\n", + "\n", + "# Step 13: Practice with GitHub Copilot Chat\n", + "# Try asking some programming questions or requesting code snippets in the chat\n", + "# Remember, just like with the inline suggestions, always review and test the code before using it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Working with Inline Chat\n", + "Exercises to practice using the inline chat feature for collaborative coding." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Step 14: Working with Inline Chat\n", + "# GitHub Copilot also provides an inline chat feature for collaborative coding\n", + "# To use this feature, follow these steps:\n", + "\n", + "# Step 14.1: Open the command palette with `Ctrl+Shift+P` (Windows/Linux) or `Cmd+Shift+P` (Mac)\n", + "# Step 14.2: Type `GitHub Copilot: Start Inline Chat` and select the command\n", + "# Step 14.3: OYou cn also use 'Ctrl+I' (Windows/Linux) or `Cmd+I` (Mac) to start the inline chat\n", + "# Step 14.4: In the inline chat interface, you can ask programming questions or request code snippets\n", + "# For example, you can ask \"How to write a function to calculate the nth prime number in Python?\"\n", + "\n", + "# Note: The inline chat feature is a new feature and might not be available in all regions or for all users. If you don't see the `GitHub Copilot: Start Inline Chat` command, make sure you have the latest version of the GitHub Copilot extension and Visual Studio Code.\n", + "\n", + "# Step 15: Practice with GitHub Copilot Inline Chat\n", + "# Try asking some programming questions or requesting code snippets in the inline chat\n", + "# Remember, just like with the inline suggestions and the chat interface, always review and test the code before using it." + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Resources/README.md b/Resources/README.md new file mode 100644 index 00000000..598746a8 --- /dev/null +++ b/Resources/README.md @@ -0,0 +1,108 @@ +# GitHub Copilot Cheatsheet + +Here are some useful shortcut commands for using GitHub Copilot: + +- `Ctrl + Enter` (or `Cmd + Enter` on Mac): Open the suggestion panel to view alternative suggestions. + +- `Tab`: Accept the current suggestion. + +- `Shift + Tab`: Cycle through the available suggestions. + +- `Ctrl + .` (or `Cmd + .` on Mac): Open the context menu to view more options. + +- `Ctrl + Space` (or `Cmd + Space` on Mac): Trigger GitHub Copilot to generate code based on the context of your code. + +- `Ctrl + Shift + Space` (or `Cmd + Shift + Space` on Mac): Trigger GitHub Copilot to generate code based on the context of your code, but with more context. + +- `Ctrl + Shift + Enter` (or `Cmd + Shift + Enter` on Mac): Trigger GitHub Copilot to generate code based on the context of your code, but with even more context. + + +### Things to try in the Copilot Chat Window + + + +- Select the code throwing error(s) and type `Handle error` in the chat. + +### "/" Commands + +- Type `/api` in the chat to get the API for the code. + +- Type `/explain` in the chat to get an explanation of the code. + +- Type `/fix` in the chat to get a fixed version of the code. + +- Type `/new` in the chat to create a new project with some scaffold code. + +- Type `/newNotebook` in the chat to create a new Jupyter notebook. + +- Type `/test` in the chat to generate unit test. + +- Type `/help` in the chat to get help with the commands. + +- Type `/clear` in the chat to clear the chat window. + +### "@" Commands + +- Type `@workspace` in the chat to run queries on/about workspace. + +- Type `@github` in the chat to run queries on/about GitHub. + +- Type `@terminal` in the chat to handle/run queries on/about terminal output(s)/error(s). + +- Type `@vscode` in the chat to handle/run queries on/about VSCode output(s)/error(s). + +- Type `@azure` in the chat to handle/run queries on/about Azure output(s)/error(s) and also manage your azure resources and deployments. + +- Type `@docker` in the chat to handle/run queries on/about Docker output(s)/error(s) and also manage your docker resources. + +- Type `@copilotext-dev` in the chat to handle/run queries on/about Copilot extension. It also helps in developing your own extension(s). + +- Type `@teamsagent` this is an agent that help developer to develop an teams app. + +- Type `@readme-api` in the chat to handle/run queries on/about README API output(s)/error(s). + +### "#" Commands + +- Type `#kb` in the chat after `@github` to run queries on your knowledge base(s). + +- Type `#web` in the chat after `@github` to run queries directly using Bing search.. + +- Type `#editor` in the chat to handle/run queries on/about editor output(s)/error(s). + +- Type `#file` in the chat to handle/run queries on/about file output(s)/error(s). + +- Type `#selection` in the chat to handle/run queries on/about selected output(s)/error(s). + +- Type `#TerminalLastCommand` in the chat to handle/run queries on/about the last command in the terminal. + +- Type `#TerminlSelection` in the chat to handle/run queries on/about selected terminal output(s)/error(s). + +- Type `#vscodeApi` in the chat to handle/run queries on/about VSCode API output(s)/error(s). + +## In-Line Chat Shortcuts + +Press `Ctrl + I` to open inline GitHub Copilot Chat + +![alt text](image-1.png) + +- Type `/doc` in the chat to get the documentation for the code. + +- Type `/explain` in the chat to get an explanation of the code. + +- Type `/fix` in the chat to get a fixed version of the code. + +- Type `/test` in the chat to generate unit test. + +## Terminal In-Line Assistance + +- Highlight the error message in the terminal and press `Ctrl + I` to open inline GitHub Copilot Chat. + +![alt text](image-2.png) + +## Easter Eggs + +GitHub Copilot has a few easter eggs too! For example, try typing `import antigravity` in a Python file and see what happens. + +## Conclusion + +GitHub Copilot is a powerful tool that can significantly speed up your coding process. With these tips and tricks, you'll be able to get the most out of it. Happy coding! \ No newline at end of file diff --git a/Resources/image-1.png b/Resources/image-1.png new file mode 100644 index 00000000..93cd5ab4 Binary files /dev/null and b/Resources/image-1.png differ diff --git a/Resources/image-2.png b/Resources/image-2.png new file mode 100644 index 00000000..d08f6c0b Binary files /dev/null and b/Resources/image-2.png differ diff --git a/Resources/image.png b/Resources/image.png new file mode 100644 index 00000000..c325c000 Binary files /dev/null and b/Resources/image.png differ diff --git a/challenges/cryptoanalisis/cryto.zip b/challenges/cryptoanalisis/crypto.zip similarity index 100% rename from challenges/cryptoanalisis/cryto.zip rename to challenges/cryptoanalisis/crypto.zip diff --git a/challenges/eshop/automobileParts.json b/challenges/eshop/automobileParts.json new file mode 100644 index 00000000..b9879e51 --- /dev/null +++ b/challenges/eshop/automobileParts.json @@ -0,0 +1,323 @@ +[ + { + "id": 1, + "name": "Brake Pad Set", + "description": "High quality brake pad set.", + "image_url": "https://example.com/images/brake_pad_set.png", + "price": 45.99, + "manufacturer": "Brembo", + "model_compatibility": ["Model A", "Model B", "Model C"], + "part_number": "BP123", + "stock": 20, + "specifications": { + "weight": "1.2kg", + "dimensions": "15x10x2cm", + "material": "Ceramic" + } + }, + { + "id": 2, + "name": "Oil Filter", + "description": "Durable oil filter.", + "image_url": "https://example.com/images/oil_filter.png", + "price": 10.99, + "manufacturer": "Bosch", + "model_compatibility": ["Model D", "Model E", "Model F"], + "part_number": "OF456", + "stock": 50, + "specifications": { + "weight": "0.3kg", + "dimensions": "7x7x9cm", + "material": "Synthetic" + } + }, + { + "id": 3, + "name": "Spark Plug", + "description": "High performance spark plug.", + "image_url": "https://example.com/images/spark_plug.png", + "price": 5.99, + "manufacturer": "NGK", + "model_compatibility": ["Model G", "Model H", "Model I"], + "part_number": "SP789", + "stock": 100, + "specifications": { + "weight": "0.1kg", + "dimensions": "2x2x8cm", + "material": "Ceramic" + } + }, + { + "id": 4, + "name": "Air Filter", + "description": "Efficient air filter.", + "image_url": "https://example.com/images/air_filter.png", + "price": 15.99, + "manufacturer": "K&N", + "model_compatibility": ["Model J", "Model K", "Model L"], + "part_number": "AF012", + "stock": 30, + "specifications": { + "weight": "0.4kg", + "dimensions": "30x30x5cm", + "material": "Synthetic" + } + }, + { + "id": 5, + "name": "Alternator", + "description": "Reliable alternator.", + "image_url": "https://example.com/images/alternator.png", + "price": 120.99, + "manufacturer": "Bosch", + "model_compatibility": ["Model M", "Model N", "Model O"], + "part_number": "AL345", + "stock": 10, + "specifications": { + "weight": "5.0kg", + "dimensions": "20x15x10cm", + "material": "Metal" + } + }, + { + "id": 6, + "name": "Battery", + "description": "Long-lasting car battery.", + "image_url": "https://example.com/images/battery.png", + "price": 80.99, + "manufacturer": "Exide", + "model_compatibility": ["Model P", "Model Q", "Model R"], + "part_number": "BT678", + "stock": 15, + "specifications": { + "weight": "12.0kg", + "dimensions": "30x20x15cm", + "material": "Lead Acid" + } + }, + { + "id": 7, + "name": "Radiator", + "description": "Efficient car radiator.", + "image_url": "https://example.com/images/radiator.png", + "price": 90.99, + "manufacturer": "Denso", + "model_compatibility": ["Model S", "Model T", "Model U"], + "part_number": "RD910", + "stock": 8, + "specifications": { + "weight": "3.0kg", + "dimensions": "60x40x5cm", + "material": "Aluminium" + } + }, + { + "id": 8, + "name": "Fuel Pump", + "description": "High quality fuel pump.", + "image_url": "https://example.com/images/fuel_pump.png", + "price": 70.99, + "manufacturer": "Delphi", + "model_compatibility": ["Model V", "Model W", "Model X"], + "part_number": "FP112", + "stock": 12, + "specifications": { + "weight": "1.0kg", + "dimensions": "10x10x10cm", + "material": "Metal" + } + }, + { + "id": 9, + "name": "Water Pump", + "description": "Durable water pump.", + "image_url": "https://example.com/images/water_pump.png", + "price": 60.99, + "manufacturer": "Gates", + "model_compatibility": ["Model Y", "Model Z"], + "part_number": "WP234", + "stock": 18, + "specifications": { + "weight": "2.0kg", + "dimensions": "15x15x10cm", + "material": "Metal" + } + }, + { + "id": 10, + "name": "Timing Belt", + "description": "High performance timing belt.", + "image_url": "https://example.com/images/timing_belt.png", + "price": 25.99, + "manufacturer": "ContiTech", + "model_compatibility": ["Model A", "Model B", "Model C"], + "part_number": "TB567", + "stock": 25, + "specifications": { + "weight": "0.5kg", + "dimensions": "100x2x1cm", + "material": "Rubber" + } + }, + + { + "id": 11, + "name": "Transmission Fluid", + "description": "High quality transmission fluid.", + "image_url": "https://example.com/images/transmission_fluid.png", + "price": 20.99, + "manufacturer": "Castrol", + "model_compatibility": ["Model D", "Model E", "Model F"], + "part_number": "TF891", + "stock": 30, + "specifications": { + "weight": "1.0kg", + "dimensions": "10x5x20cm", + "material": "Liquid" + } + }, + { + "id": 12, + "name": "Engine Oil", + "description": "High performance engine oil.", + "image_url": "https://example.com/images/engine_oil.png", + "price": 30.99, + "manufacturer": "Mobil 1", + "model_compatibility": ["Model G", "Model H", "Model I"], + "part_number": "EO902", + "stock": 40, + "specifications": { + "weight": "1.0kg", + "dimensions": "10x5x20cm", + "material": "Liquid" + } + }, + { + "id": 13, + "name": "Coolant", + "description": "Long-lasting coolant.", + "image_url": "https://example.com/images/coolant.png", + "price": 15.99, + "manufacturer": "Prestone", + "model_compatibility": ["Model J", "Model K", "Model L"], + "part_number": "CL013", + "stock": 50, + "specifications": { + "weight": "1.0kg", + "dimensions": "10x5x20cm", + "material": "Liquid" + } + }, + { + "id": 14, + "name": "Fuel Filter", + "description": "Efficient fuel filter.", + "image_url": "https://example.com/images/fuel_filter.png", + "price": 10.99, + "manufacturer": "Bosch", + "model_compatibility": ["Model M", "Model N", "Model O"], + "part_number": "FF014", + "stock": 60, + "specifications": { + "weight": "0.2kg", + "dimensions": "5x5x5cm", + "material": "Synthetic" + } + }, + { + "id": 15, + "name": "Air Conditioning Compressor", + "description": "Reliable air conditioning compressor.", + "image_url": "https://example.com/images/ac_compressor.png", + "price": 200.99, + "manufacturer": "Denso", + "model_compatibility": ["Model P", "Model Q", "Model R"], + "part_number": "AC015", + "stock": 10, + "specifications": { + "weight": "5.0kg", + "dimensions": "25x15x20cm", + "material": "Metal" + } + }, + { + "id": 16, + "name": "Power Steering Pump", + "description": "High performance power steering pump.", + "image_url": "https://example.com/images/ps_pump.png", + "price": 150.99, + "manufacturer": "A1 Cardone", + "model_compatibility": ["Model S", "Model T", "Model U"], + "part_number": "PS016", + "stock": 15, + "specifications": { + "weight": "3.0kg", + "dimensions": "20x15x15cm", + "material": "Metal" + } + }, + { + "id": 17, + "name": "Shock Absorber", + "description": "Durable shock absorber.", + "image_url": "https://example.com/images/shock_absorber.png", + "price": 75.99, + "manufacturer": "Bilstein", + "model_compatibility": ["Model V", "Model W", "Model X"], + "part_number": "SA017", + "stock": 20, + "specifications": { + "weight": "2.0kg", + "dimensions": "50x5x5cm", + "material": "Metal" + } + }, + { + "id": 18, + "name": "Brake Rotor", + "description": "High quality brake rotor.", + "image_url": "https://example.com/images/brake_rotor.png", + "price": 45.99, + "manufacturer": "Brembo", + "model_compatibility": ["Model Y", "Model Z"], + "part_number": "BR018", + "stock": 25, + "specifications": { + "weight": "5.0kg", + "dimensions": "30x30x5cm", + "material": "Metal" + } + }, + { + "id": 19, + "name": "Brake Caliper", + "description": "Reliable brake caliper.", + "image_url": "https://example.com/images/brake_caliper.png", + "price": 80.99, + "manufacturer": "A1 Cardone", + "model_compatibility": ["Model A", "Model B", "Model C"], + "part_number": "BC019", + "stock": 15, + "specifications": { + "weight": "3.0kg", + "dimensions": "20x15x10cm", + "material": "Metal" + } + }, + { + "id": 20, + "name": "Brake Master Cylinder", + "description": "High performance brake master cylinder.", + "image_url": "https://example.com/images/brake_master_cylinder.png", + "price": 100.99, + "manufacturer": "A1 Cardone", + "model_compatibility": ["Model D", "Model E", "Model F"], + "part_number": "BMC020", + "stock": 10, + "specifications": { + "weight": "2.0kg", + "dimensions": "20x10x10cm", + "material": "Metal" + } + } +] \ No newline at end of file diff --git a/challenges/eshop/beers.json b/challenges/eshop/beers.json deleted file mode 100644 index 6923572d..00000000 --- a/challenges/eshop/beers.json +++ /dev/null @@ -1,805 +0,0 @@ -[ - { - "id": 1, - "name": "Buzz", - "tagline": "A Real Bitter Experience.", - "first_brewed": "09/2007", - "description": "A light, crisp and bitter IPA brewed with English and American hops. A small batch brewed only once.", - "image_url": "https://images.punkapi.com/v2/keg.png", - "price": 2.5, - "abv": 4.5, - "ibu": 60, - "target_fg": 1010, - "target_og": 1044, - "ebc": 20, - "srm": 10, - "ph": 4.4, - "attenuation_level": 75, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Spicy chicken tikka masala", - "Grilled chicken quesadilla", - "Caramel toffee cake" - ], - "brewers_tips": "The earthy and floral aromas from the hops can be overpowering. Drop a little Cascade in at the end of the boil to lift the profile with a bit of citrus.", - "contributed_by": "Sam Mason " - }, - { - "id": 2, - "name": "Trashy Blonde", - "tagline": "You Know You Shouldn't", - "first_brewed": "04/2008", - "description": "A titillating, neurotic, peroxide punk of a Pale Ale. Combining attitude, style, substance, and a little bit of low self esteem for good measure; what would your mother say? The seductive lure of the sassy passion fruit hop proves too much to resist. All that is even before we get onto the fact that there are no additives, preservatives, pasteurization or strings attached. All wrapped up with the customary BrewDog bite and imaginative twist.", - "image_url": "https://images.punkapi.com/v2/2.png", - "price": 1.30, - "abv": 4.1, - "ibu": 41.5, - "target_fg": 1010, - "target_og": 1041.7, - "ebc": 15, - "srm": 15, - "ph": 4.4, - "attenuation_level": 76, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Fresh crab with lemon", - "Garlic butter dipping sauce", - "Goats cheese salad", - "Creamy lemon bar doused in powdered sugar" - ], - "brewers_tips": "Be careful not to collect too much wort from the mash. Once the sugars are all washed out there are some very unpleasant grainy tasting compounds that can be extracted into the wort.", - "contributed_by": "Sam Mason " - }, - { - "id": 3, - "name": "Berliner Weisse With Yuzu - B-Sides", - "tagline": "Japanese Citrus Berliner Weisse.", - "first_brewed": "11/2015", - "description": "Japanese citrus fruit intensifies the sour nature of this German classic.", - "image_url": "https://images.punkapi.com/v2/keg.png", - "price": 2.5, - "abv": 4.2, - "ibu": 8, - "target_fg": 1007, - "target_og": 1040, - "ebc": 8, - "srm": 4, - "ph": 3.2, - "attenuation_level": 83, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Smoked chicken wings", - "Miso ramen", - "Yuzu cheesecake" - ], - "brewers_tips": "Clean everything twice. All you want is the clean sourness of lactobacillus.", - "contributed_by": "Sam Mason " - }, - { - "id": 4, - "name": "Pilsen Lager", - "tagline": "Unleash the Yeast Series.", - "first_brewed": "09/2013", - "description": "Our Unleash the Yeast series was an epic experiment into the differences in aroma and flavour provided by switching up your yeast. We brewed up a wort with a light caramel note and some toasty biscuit flavour, and hopped it with Amarillo and Centennial for a citrusy bitterness. Everything else is down to the yeast. Pilsner yeast ferments with no fruity esters or spicy phenols, although it can add a hint of butterscotch.", - "image_url": "https://images.punkapi.com/v2/4.png", - "price": 1.15, - "abv": 6.3, - "ibu": 55, - "target_fg": 1012, - "target_og": 1060, - "ebc": 30, - "srm": 15, - "ph": 4.4, - "attenuation_level": 80, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Spicy crab cakes", - "Spicy cucumber and carrot Thai salad", - "Sweet filled dumplings" - ], - "brewers_tips": "Play around with the fermentation temperature to get the best flavour profile from the individual yeasts.", - "contributed_by": "Ali Skinner " - }, - { - "id": 5, - "name": "Avery Brown Dredge", - "tagline": "Bloggers' Imperial Pilsner.", - "first_brewed": "02/2011", - "description": "An Imperial Pilsner in collaboration with beer writers. Tradition. Homage. Revolution. We wanted to showcase the awesome backbone of the Czech brewing tradition, the noble Saaz hop, and also tip our hats to the modern beers that rock our world, and the people who make them.", - "image_url": "https://images.punkapi.com/v2/5.png", - "price": 4.5, - "abv": 7.2, - "ibu": 59, - "target_fg": 1027, - "target_og": 1069, - "ebc": 10, - "srm": 5, - "ph": 4.4, - "attenuation_level": 67, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Vietnamese squid salad", - "Chargrilled corn on the cob with paprika butter", - "Strawberry and rhubarb pie" - ], - "brewers_tips": "Make sure you have a big enough yeast starter to ferment through the OG and lager successfully.", - "contributed_by": "Sam Mason " - }, - { - "id": 6, - "name": "Electric India", - "tagline": "Vibrant Hoppy Saison.", - "first_brewed": "05/2013", - "description": "Re-brewed as a spring seasonal, this beer – which appeared originally as an Equity Punk shareholder creation – retains its trademark spicy, fruity edge. A perfect blend of Belgian Saison and US IPA, crushed peppercorns and heather honey are also added to produce a genuinely unique beer.", - "image_url": "https://images.punkapi.com/v2/6.png", - "price": 6.2, - "abv": 5.2, - "ibu": 38, - "target_fg": 1005, - "target_og": 1045, - "ebc": 15, - "srm": 7.5, - "ph": 4.4, - "attenuation_level": 88.9, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Mussels with a garlic and herb sauce", - "Crab melt sandwich", - "Shortbread cookies" - ], - "brewers_tips": "Source some really good heather honey to get the right spicy esters in the beer.", - "contributed_by": "Sam Mason " - }, - { - "id": 7, - "name": "AB:12", - "tagline": "Imperial Black Belgian Ale.", - "first_brewed": "07/2012", - "description": "An Imperial Black Belgian Ale aged in old Invergordon Scotch whisky barrels with mountains of raspberries, tayberries and blackberries in each cask. Decadent but light and dry, this beer would make a fantastic base for ageing on pretty much any dark fruit - we used raspberries, tayberries and blackberries beause they were local.", - "image_url": "https://images.punkapi.com/v2/7.png", - "price": 2, - "abv": 11.2, - "ibu": 35, - "target_fg": 1017, - "target_og": 1108, - "ebc": 80, - "srm": 40, - "ph": 5.3, - "attenuation_level": 84, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Tandoori lamb with pomegranate", - "Beef Wellington with a red wine jus", - "Raspberry chocolate torte" - ], - "brewers_tips": "Don't worry too much about controlling the temperature with the Belgian yeast strain - just make sure it doesn't rise above 30°C!", - "contributed_by": "Sam Mason " - }, - { - "id": 8, - "name": "Fake Lager", - "tagline": "Bohemian Pilsner.", - "first_brewed": "03/2013", - "description": "Fake is the new black. Fake is where it is at. Fake Art, fake brands, fake breasts, and fake lager. We want to play our part in the ugly fallout from the Lager Dream. Say hello to Fake Lager – a zesty, floral 21st century faux masterpiece with added BrewDog bitterness.", - "image_url": "https://images.punkapi.com/v2/8.png", - "price": 3.75, - "abv": 4.7, - "ibu": 40, - "target_fg": 1010, - "target_og": 1046, - "ebc": 12, - "srm": 6, - "ph": 4.4, - "attenuation_level": 78, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Fried crab cakes with avocado salsa", - "Spicy shredded pork roll with hot dipping sauce", - "Key lime pie" - ], - "brewers_tips": "Once the primary fermentation is complete get this beer as cold as you can and let it mature for as long as you've got.", - "contributed_by": "Sam Mason " - }, - { - "id": 9, - "name": "AB:07", - "tagline": "Whisky Cask-Aged Scotch Ale.", - "first_brewed": "03/2010", - "description": "Whisky cask-aged imperial scotch ale. Beer perfect for when the rain is coming sideways. Liquorice, plum and raisin temper the warming alcohol, producing a beer capable of holding back the Scottish chill.", - "image_url": "https://images.punkapi.com/v2/9.png", - "price": 4.50, - "abv": 12.5, - "ibu": 30, - "target_fg": 1020, - "target_og": 1106, - "ebc": 84, - "srm": 42, - "ph": 5.6, - "attenuation_level": 83, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Kedgeree", - "Scotch broth with sourdough bread", - "Clootie dumpling" - ], - "brewers_tips": "Authentic heather honey adds a beautiful floral top note that is unachievable any other way.", - "contributed_by": "Sam Mason " - }, - { - "id": 10, - "name": "Bramling X", - "tagline": "Single Hop IPA Series - 2011.", - "first_brewed": "01/2011", - "description": "Good old Bramling Cross is elegant, refined, assured, (boring) and understated. Understated that is unless you hop the living daylights out of a beer with it. This is Bramling Cross re-invented and re-imagined, and shows just what can be done with English hops if you use enough of them. Poor Bramling Cross normally gets lost in a woeful stream of conformist brown ales made by sleepy cask ale brewers. But not anymore. This beer shows that British hops do have some soul, and is a fruity riot of blackberries, pears, and plums. Reminds me of the bramble, apple and ginger jam my grandmother used to make.", - "image_url": "https://images.punkapi.com/v2/10.png", - "price": 2, - "abv": 7.5, - "ibu": 75, - "target_fg": 1013, - "target_og": 1068, - "ebc": 22, - "srm": 11, - "ph": 4.4, - "attenuation_level": 80.9, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Warm blackberry pie", - "Vinegar doused fish and chips", - "Aromatic korma curry with lemon and garlic naan" - ], - "brewers_tips": "Getting good Bramling Cross is key. Most English hops are in leaf form (not pelletised), so getting fresh hops close to harvest (September) will give this beer the right amount of dark berry intensity.", - "contributed_by": "Sam Mason " - }, - { - "id": 11, - "name": "Misspent Youth", - "tagline": "Milk & Honey Scotch Ale.", - "first_brewed": "04/2013", - "description": "The brainchild of our small batch brewer, George Woods. A dangerously drinkable milk sugar- infused Scotch Ale.", - "image_url": "https://images.punkapi.com/v2/keg.png", - "price": 10, - "abv": 7.3, - "ibu": 30, - "target_fg": 1020, - "target_og": 1079, - "ebc": 120, - "srm": 60, - "ph": 4.4, - "attenuation_level": 74.7, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Roasted garlic and chilli infused camembert cheese", - "Korean style chicken wings", - "Chocolate milk shake" - ], - "brewers_tips": "Lots of malt in this one. Mash-in in stages, and spread the pale ale malt throughout the mash to provide stability. If the mash starts to sink, stop, wait a few minutes while mixing, then start again.", - "contributed_by": "Sam Mason " - }, - { - "id": 12, - "name": "Arcade Nation", - "tagline": "Seasonal Black IPA.", - "first_brewed": "12/2015", - "description": "Running the knife-edge between an India Pale Ale and a Stout, this particular style is one we truly love. Black IPAs are a great showcase for the skill of our brew team, balancing so many complex and twisting flavours in the same moment. The citrus, mango and pine from the hops – three of our all-time favourites – play off against the roasty dryness from the malt bill at each and every turn.", - "image_url": "https://images.punkapi.com/v2/12.png", - "price": 1.75, - "abv": 5.3, - "ibu": 60, - "target_fg": 1012, - "target_og": 1052, - "ebc": 200, - "srm": 100, - "ph": 4.2, - "attenuation_level": 77, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "King prawn kebabs", - "Halibut with a mango and tomato salad", - "Mint chocloate ice cream" - ], - "brewers_tips": "Be as accurate as possible when weighing out your malts to ensure you strike the right balance.", - "contributed_by": "Sam Mason " - }, - { - "id": 13, - "name": "Movember", - "tagline": "Moustache-Worthy Beer.", - "first_brewed": "11/2009", - "description": "A deliciously robust, black malted beer with a decadent dark, dry cocoa flavour that provides an enticing backdrop to the Cascade hops.", - "image_url": "https://images.punkapi.com/v2/13.png", - "price": 2.85, - "abv": 4.5, - "ibu": 50, - "target_fg": 1012, - "target_og": 1047, - "ebc": 140, - "srm": 70, - "ph": 5.2, - "attenuation_level": 74.5, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Vegetable egg scramble", - "Margherita pizza", - "Fresh berry crisp tart" - ], - "brewers_tips": "If you can’t find really fresh cascade, substitute it for Amarillo or Ahtanum.", - "contributed_by": "Sam Mason " - }, - { - "id": 14, - "name": "Alpha Dog", - "tagline": "Existential Red Ale.", - "first_brewed": "02/2010", - "description": "A fusion of caramel malt flavours and punchy New Zealand hops. A session beer you can get your teeth into.", - "image_url": "https://images.punkapi.com/v2/14.png", - "price": 3.75, - "abv": 4.5, - "ibu": 42, - "target_fg": 1025, - "target_og": 1046, - "ebc": 62, - "srm": 31, - "ph": 4.4, - "attenuation_level": 72.8, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Pastrami", - "Swiss and horseradish sandwich", - "Sharp cheddar cheese and onion/ raisin chutney", - "Peanut brittle" - ], - "brewers_tips": "Crush the malt as close to brewing time as possible. The fresher the malt, the more intense caramel flavours will be released in the wort.", - "contributed_by": "Sam Mason " - }, - { - "id": 15, - "name": "Mixtape 8", - "tagline": "An Epic Fusion Of Old Belgian, American New Wave, And Scotch Whisky.", - "first_brewed": "01/2012", - "description": "This recipe is for the Belgian Tripel base. A blend of two huge oak aged beers – half a hopped up Belgian Tripel, and half a Triple India Pale Ale. Both aged in single grain whisky barrels for two years and blended, each beer brings its own character to the mix. The Belgian Tripel comes loaded with complex spicy, fruity esters, and punchy citrus hop character.", - "image_url": "https://images.punkapi.com/v2/15.png", - "price": 5.50, - "abv": 14.5, - "ibu": 50, - "target_fg": 1014, - "target_og": 1093, - "ebc": 40, - "srm": 20, - "ph": 4.4, - "attenuation_level": 85, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Coriander & chilli crab cakes", - "Goats cheese salad with walnuts, radish and blood orange", - "Pistachio cake" - ], - "brewers_tips": "Brew twice as much Belgian Tripel as you were planning on ageing - it's awesome on its own too!", - "contributed_by": "Sam Mason " - }, - { - "id": 16, - "name": "Libertine Porter", - "tagline": "Dry-Hopped Aggressive Porter.", - "first_brewed": "01/2012", - "description": "An avalanche of cross-continental hop varieties give this porter a complex spicy, resinous and citrusy aroma, with a huge malt bill providing a complex roasty counterpoint. Digging deeper into the flavour draws out cinder toffee, bitter chocolate and hints of woodsmoke.", - "image_url": "https://images.punkapi.com/v2/16.png", - "price": 6.50, - "abv": 6.1, - "ibu": 45, - "target_fg": 1020, - "target_og": 1067, - "ebc": 219, - "srm": 109.5, - "ph": 4.4, - "attenuation_level": 70.1, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Blue cheese beef burger", - "Glazed short ribs", - "Chocolate cake" - ], - "brewers_tips": "Mash in at a higher temperature to leave more unfermentable sugars in the wort. This gives the beer a sweeter porter profile.", - "contributed_by": "Sam Mason " - }, - { - "id": 17, - "name": "AB:06", - "tagline": "Imperial Black IPA.", - "first_brewed": "04/2011", - "description": "Our sixth Abstrakt, this imperial black IPA combined dark malts with a monumental triple dry-hop, using an all-star team of some of our favourite American hops. Roasty and resinous.", - "image_url": "https://images.punkapi.com/v2/17.png", - "price": 3.50, - "abv": 11.2, - "ibu": 150, - "target_fg": 1013, - "target_og": 1098, - "ebc": 70, - "srm": 35, - "ph": null, - "attenuation_level": 87, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Coffee dusted venison loin", - "Memphis-style beef short ribs", - "Chocolate orange brownies" - ], - "brewers_tips": "Boil down to desired OG (about 17 litres).", - "contributed_by": "Sam Mason " - }, - { - "id": 18, - "name": "Russian Doll – India Pale Ale", - "tagline": "Nesting Hop Bomb.", - "first_brewed": "08/2014", - "description": "The levels of hops vary throughout the range. We love hops, so all four beers are big, bitter badasses, but by tweaking the amount of each hop used later in the boil and during dry- hopping, we can balance the malty backbone with some unexpected flavours. Simcoe is used in the whirlpool for all four beers, and yet still lends different characters to each", - "image_url": "https://images.punkapi.com/v2/18.png", - "price": 2.5, - "abv": 6, - "ibu": 70, - "target_fg": 1012, - "target_og": 1058, - "ebc": 25, - "srm": 12.5, - "ph": 5.2, - "attenuation_level": 79.3, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Spicy chicken skewers", - "Fish tacos with hot sauce", - "Lemon pound cake with a ice sugar glaze" - ], - "brewers_tips": "Create balance through experimentation with the hop amounts and malt backbone.", - "contributed_by": "Sam Mason " - }, - { - "id": 19, - "name": "Hello My Name Is Mette-Marit", - "tagline": "Lingonberry Double IPA.", - "first_brewed": "06/2013", - "description": "We sent this beer to Norway where it was known as 'Hello, my name is Censored’. You can make up your own mind as to why. This brew was a red berry explosion, with a reisnous bitter edge layered with dry berry tartness.", - "image_url": "https://images.punkapi.com/v2/19.png", - "price": 0.99, - "abv": 8.2, - "ibu": 70, - "target_fg": 1013, - "target_og": 1076, - "ebc": null, - "srm": null, - "ph": 4.4, - "attenuation_level": 83, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Fårikål (mutton stew) with a spicy twist", - "Fenalår (salted cured lamb)", - "Krumkake with lingonberry jam" - ], - "brewers_tips": "Using crushed cranberries will dry out the beer further, drawing out their natural astringent character.", - "contributed_by": "Sam Mason " - }, - { - "id": 20, - "name": "Rabiator", - "tagline": "Imperial Wheat Beer", - "first_brewed": "03/2011", - "description": "Imperial Wheat beer / Weizenbock brewed by a homesick German in leather trousers. Think banana bread, bubble gum and David Hasselhoff.", - "image_url": "https://images.punkapi.com/v2/keg.png", - "price": 3.15, - "abv": 10.27, - "ibu": 26, - "target_fg": 1014, - "target_og": 1092, - "ebc": 24, - "srm": 12, - "ph": 4.4, - "attenuation_level": 85, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Grilled portabello mushroom burger", - "Chicken sausages with creamy mash", - "Caramel and banana meringue pie" - ], - "brewers_tips": "If you are struggling to get that authentic head retention increase your mash temperature to about 70°C.", - "contributed_by": "Sam Mason " - }, - { - "id": 21, - "name": "Vice Bier", - "tagline": "Hoppy Wheat Bier.", - "first_brewed": "04/2013", - "description": "Our take on the classic German Kristallweizen. A clear German wheat beer, layers of bubblegum and vanilla perfectly balanced with the American and New Zealand hops.", - "image_url": "https://images.punkapi.com/v2/keg.png", - "price": 4.50, - "abv": 4.3, - "ibu": 25, - "target_fg": 1010, - "target_og": 1043, - "ebc": 30, - "srm": 15, - "ph": 4, - "attenuation_level": 81.8, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Citrus salad with balsamic dressing", - "Lobster", - "Ginger and orange cookies" - ], - "brewers_tips": "Ferment at higher or lower temperatures to select the esters that will create clove- like or banana-like flavours.", - "contributed_by": "Sam Mason " - }, - { - "id": 22, - "name": "Devine Rebel (w/ Mikkeller)", - "tagline": "Oak-aged Barley Wine.", - "first_brewed": "12/2008", - "description": "Two of Europe's most experimental, boundary-pushing brewers, BrewDog and Mikkeller, combined forces to produce a rebellious beer that combined their respective talents and brewing skills. The 12.5% Barley Wine fermented well, and the champagne yeast drew it ever closer to 12.5%. The beer was brewed with a single hop variety and was going to be partially aged in oak casks.", - "image_url": "https://images.punkapi.com/v2/22.png", - "price": 4.5, - "abv": 12.5, - "ibu": 100, - "target_fg": 1030, - "target_og": 1093, - "ebc": 36, - "srm": 18, - "ph": 4.4, - "attenuation_level": 68, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Stilton on gingerbread biscuits", - "Pot roasted artichokes", - "Lamb chops with caramelised figs" - ], - "brewers_tips": "Rack off to a secondary fermenter before pitching in some champagne.", - "contributed_by": "Sam Mason " - }, - { - "id": 23, - "name": "Storm", - "tagline": "Islay Whisky Aged IPA.", - "first_brewed": "12/2007", - "description": "Dark and powerful Islay magic infuses this tropical sensation of an IPA. Using the original Punk IPA as a base, we boosted the ABV to 8% giving it some extra backbone to stand up to the peated smoke imported directly from Islay.", - "image_url": "https://images.punkapi.com/v2/23.png", - "price": 6.50, - "abv": 8, - "ibu": 60, - "target_fg": 1010, - "target_og": 1082, - "ebc": 12, - "srm": 6, - "ph": 4.4, - "attenuation_level": 86, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Oysters", - "Hickory smoked ham", - "Rocky Road" - ], - "brewers_tips": "After primary fermentation is complete, rack off into a secondary fermeter and add the oak chips to replicate the authentic Islay barrel experience.", - "contributed_by": "Sam Mason " - }, - { - "id": 24, - "name": "The End Of History", - "tagline": "The World's Strongest Beer.", - "first_brewed": "06/2011", - "description": "The End of History: The name derives from the famous work of philosopher Francis Fukuyama, this is to beer what democracy is to history. Complexity defined. Floral, grapefruit, caramel and cloves are intensified by boozy heat.", - "image_url": "https://images.punkapi.com/v2/24.png", - "price": 8.75, - "abv": 55, - "ibu": null, - "target_fg": 1000, - "target_og": 1112, - "ebc": null, - "srm": null, - "ph": 4.4, - "attenuation_level": 100, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Roasted wood pigeon with black pudding", - "Pan seared venison fillet with juniper sauce", - "Apricot coconut cake" - ], - "brewers_tips": "You'll have to get this one all the way down to -70°C. Taxidermy is not optional.", - "contributed_by": "Sam Mason " - }, - { - "id": 25, - "name": "Bad Pixie", - "tagline": "Spiced Wheat Beer.", - "first_brewed": "10/2008", - "description": "2008 Prototype beer, a 4.7% wheat ale with crushed juniper berries and citrus peel.", - "image_url": "https://images.punkapi.com/v2/25.png", - "price": 3.75, - "abv": 4.7, - "ibu": 45, - "target_fg": 1010, - "target_og": 1047, - "ebc": 8, - "srm": 4, - "ph": 4.4, - "attenuation_level": 79, - "volume": { - "value": 20, - "unit": "litres" - }, - "boil_volume": { - "value": 25, - "unit": "litres" - }, - "food_pairing": [ - "Poached sole fillet with capers", - "Summer fruit salad", - "Banana split" - ], - "brewers_tips": "Make sure you have plenty of room in the fermenter. Beers containing wheat can often foam aggressively during fermentation.", - "contributed_by": "Sam Mason " - } - ] - \ No newline at end of file diff --git a/challenges/eshop/eshop.md b/challenges/eshop/eshop.md index 8c3cbdeb..8ca38f87 100644 --- a/challenges/eshop/eshop.md +++ b/challenges/eshop/eshop.md @@ -8,14 +8,14 @@ ### 1. Choose a programming language of your choice. -### 2. Topic selected is beer. You can use the json beers.json in the root of the project to get the list of beers for building the Rest API. +### 2. Topic selected is automobile parts. You can use the automobileParts.json file in the root of the eshop project to get the list of automobile parts for building the Rest API. ### 3. Develop the shop cart. You can use the following steps as a guide: - - Create an API Rest with methods to: - - get the beers list with page offset and limit. - - get beer details by id. - - Search beers by name, description, tagline, food_pairing, price. + - Create a Rest API with methods to: + - Get the automobile parts list with page offset and limit. + - Get automobile part details by id. + - Search automobile parts by name, description, manufacturer, price. - Create a list of products in the main page. - Create a search bar to filter the products. - Navigate to the description page when the user clicks on a product. diff --git a/challenges/expensetracker/README.md b/challenges/expensetracker/README.md new file mode 100644 index 00000000..f3b57ac6 --- /dev/null +++ b/challenges/expensetracker/README.md @@ -0,0 +1,85 @@ +# 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 + +### 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 && `. +``` +Change the directory to `frontend` when working on the frontend part. + +## 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 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/completesolution/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj b/completesolution/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj index 3c443321..67976258 100644 --- a/completesolution/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj +++ b/completesolution/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable @@ -10,7 +10,7 @@ - + diff --git a/completesolution/dotnet/MinimalAPI/MinimalAPI.csproj b/completesolution/dotnet/MinimalAPI/MinimalAPI.csproj index 4211a49f..06c5c763 100644 --- a/completesolution/dotnet/MinimalAPI/MinimalAPI.csproj +++ b/completesolution/dotnet/MinimalAPI/MinimalAPI.csproj @@ -1,14 +1,14 @@ - net7.0 + net8.0 enable enable - - + + 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/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 dd255bf2..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 @@ -46,7 +46,7 @@ @RestController public class DemoController { - @GetMapping("/hello") + @GetMapping(value = "/hello", produces = MediaType.TEXT_PLAIN_VALUE) public String hello(@RequestParam(name = "key", required = false) String key) { if (key == null) { return "key not passed"; @@ -55,7 +55,7 @@ public String hello(@RequestParam(name = "key", required = false) String key) { } // New operation under /diffdates that calculates the difference between two dates. The operation should receive two dates as parameter in format dd-MM-yyyy and return the difference in days. - @GetMapping("/diffdates") + @GetMapping(value = "/diffdates", produces = MediaType.TEXT_PLAIN_VALUE) public String diffdates(@RequestParam(name = "date1", required = false) String date1, @RequestParam(name = "date2", required = false) String date2) throws ParseException { if (date1 == null || date2 == null) { return "date not passed"; @@ -69,7 +69,7 @@ public String diffdates(@RequestParam(name = "date1", required = false) String d } // Validate the format of a spanish phone number (+34 prefix, then 9 digits, starting with 6, 7 or 9). The operation should receive a phone number as parameter and return true if the format is correct, false otherwise. - @GetMapping("/validatephone") + @GetMapping(value = "/validatephone", produces = MediaType.TEXT_PLAIN_VALUE) public boolean validatephone(@RequestParam(name = "phone", required = false) String phone) { if (phone == null || phone.isEmpty()) { return false; @@ -79,7 +79,7 @@ public boolean validatephone(@RequestParam(name = "phone", required = false) Str } // Validate the format of a spanish DNI (8 digits and 1 letter). The operation should receive a DNI as parameter and return true if the format is correct, false otherwise. - @GetMapping("/validatedni") + @GetMapping(value = "/validatedni", produces = MediaType.TEXT_PLAIN_VALUE) public boolean validatedni(@RequestParam(name = "dni", required = false) String dni) { if (dni == null || dni.isEmpty()) { return false; @@ -89,7 +89,7 @@ public boolean validatedni(@RequestParam(name = "dni", required = false) String } //Based on existing colors.json file under resources, given the name of the color as path parameter, return the hexadecimal code. If the color is not found, return 404 - @GetMapping("/color/{name}") + @GetMapping(value = "/color/{name}", produces = MediaType.TEXT_PLAIN_VALUE) public ResponseEntity color(@PathVariable("name") String name) throws IOException { InputStream inputStream = getClass().getClassLoader().getResourceAsStream("colors.json"); ObjectMapper objectMapper = new ObjectMapper(); @@ -105,7 +105,7 @@ public ResponseEntity color(@PathVariable("name") String name) throws IO } // new operation that call the API https://api.chucknorris.io/jokes/random and return the joke - @GetMapping("/joke") + @GetMapping(value = "/joke", produces = MediaType.TEXT_PLAIN_VALUE) public String getJoke() { RestTemplate restTemplate = new RestTemplate(); String url = "https://api.chucknorris.io/jokes/random"; @@ -123,7 +123,7 @@ public String getJoke() { // Given a url as query parameter, parse it and return the protocol, host, port, path and query parameters. The response should be in Json format. - @GetMapping("/parseurl") + @GetMapping(value = "/parseurl", produces = MediaType.APPLICATION_JSON_VALUE) public String parseurl(@RequestParam(name = "url", required = false) String url) throws MalformedURLException { if (url == null || url.isEmpty()) { return "url not passed"; @@ -138,9 +138,12 @@ public String parseurl(@RequestParam(name = "url", required = false) String url) } // List files and folders under a given path. The path should be a query parameter. The response should be in Json format. - @GetMapping("/list-files") + @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(); @@ -163,9 +166,12 @@ public ResponseEntity listFiles(@RequestParam(name = "path") String path } // Given the path of a file and count the number of occurrence of a provided word. The path and the word should be query parameters. The response should be in Json format. - @GetMapping("/count-word") + @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(); @@ -190,9 +196,12 @@ public ResponseEntity countWord(@RequestParam(name = "path") String path } // Create a zip file with the content of a given folder. The path of the folder should be a query parameter. - @GetMapping("/zip-folder") + @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(); 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/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj b/exercisefiles/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj index 3c443321..67976258 100644 --- a/exercisefiles/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj +++ b/exercisefiles/dotnet/MinimalAPI.Tests/MinimalAPI.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable @@ -10,7 +10,7 @@ - + diff --git a/exercisefiles/dotnet/MinimalAPI/MinimalAPI.csproj b/exercisefiles/dotnet/MinimalAPI/MinimalAPI.csproj index 4211a49f..06c5c763 100644 --- a/exercisefiles/dotnet/MinimalAPI/MinimalAPI.csproj +++ b/exercisefiles/dotnet/MinimalAPI/MinimalAPI.csproj @@ -1,14 +1,14 @@ - net7.0 + net8.0 enable enable - - + + diff --git a/exercisefiles/dotnet/README.md b/exercisefiles/dotnet/README.md index 2b96ceb5..86abccb8 100644 --- a/exercisefiles/dotnet/README.md +++ b/exercisefiles/dotnet/README.md @@ -1,6 +1,6 @@ # Goal -The goal is to create a Minimal WebAPI using .NET 7.0 and a corresponding Docker image with the help of GitHub Copilot. +The goal is to create a Minimal WebAPI using .NET 8.0 and a corresponding Docker image with the help of GitHub Copilot. Follow the instructions below and try to use GitHub Copilot as much as possible. Try different things and see what GitHub Copilot can do for you, like generating a Dockerfile or a class, add comments, etc. @@ -21,10 +21,16 @@ dotnet test To run the app, open a terminal in the `dotnet` folder and run: +**Windows environments** ``` bash dotnet run --project .\MinimalAPI\MinimalAPI.csproj ``` +**Codespaces, Linux & Unix environments** +``` bash +dotnet run --project ./MinimalAPI/MinimalAPI.csproj +``` + ### Exercise 1: Introduction - Inside `MinimalAPI\Program.cs` add a new Hello World endpoint at `/` that returns a `Hello World!` string. You can test the Copilot inline feature by pressing `ctrl + i`. Then write in the text box the desired behaviour. @@ -41,7 +47,7 @@ A total of 1 test files matched the specified pattern. Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms - MinimalAPI.Tests.dll ``` -### Exercise 2: Building new functionlities +### Exercise 2: Building new functionalities Inside `MinimalAPI\Program.cs` add the following endpoints using the help of Copilot: @@ -114,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 @@ -153,6 +175,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/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 diff --git a/exercisefiles/node/README.md b/exercisefiles/node/README.md index 7c9f98f1..4775d0c5 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,23 +24,7 @@ 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 +### Exercise 2: Building new functionalities The exercise consist of building a web server using Nodejs that serves the request of various functionality. @@ -147,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. @@ -171,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 new file mode 100644 index 00000000..b22b1d85 --- /dev/null +++ b/exercisefiles/node_typescript/README.md @@ -0,0 +1,163 @@ +# 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 + +### 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 +- 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 2: Building new functionalities + +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.ts` 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.ts` 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.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**: + + * 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 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.ts` 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 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/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..aac9f6e0 --- /dev/null +++ b/exercisefiles/node_typescript/nodeserver.ts @@ -0,0 +1,9 @@ +// 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" + + +import http from 'http'; \ No newline at end of file diff --git a/exercisefiles/node_typescript/package.json b/exercisefiles/node_typescript/package.json new file mode 100644 index 00000000..e653c8c9 --- /dev/null +++ b/exercisefiles/node_typescript/package.json @@ -0,0 +1,22 @@ +{ + "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/mocha": "^10.0.9", + "@types/node": "^22.8.6", + "mocha": "^10.8.2" + } +} 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..ad52885c --- /dev/null +++ b/exercisefiles/node_typescript/test.ts @@ -0,0 +1,36 @@ +//write npm command line to install mocha +//command to run this test file +//mocha test.js + +import * as assert from 'assert'; +import * as http from 'http'; + +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. */ + } +} 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.