diff --git a/README.md b/README.md index a06a845a..20c186e3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ FS Website Solutions -# **Fabio Sereno** - Software Developer +# **Fabio Sereno** - Software Engineer Highly experienced Full Stack Software Engineer with over 15 years of experience (6+ years in the FinTech sector). Self-motivated, enthusiastic, and professional team player with strong analytical and problem-solving skills. Demonstrates proficiency in coding and a proven ability to successfully complete projects with innovation and creativity. Passionate about software development and constantly eager to learn and adopt the latest technologies. Keen interest in FinTech, HealthTech, Commerce, ML/AI, Blockchain, XR (VR/AR), and IoT. @@ -39,7 +39,6 @@ Some of the technology used in this project and related projects: - SOLID principles - TDD - Test driven development - DDD - Domain driven development ---- ## Contents @@ -47,122 +46,160 @@ Some of the technology used in this project and related projects: - [Installation](#installation) - [Usage](#usage) - [Licence](#licence) ---- ## Prerequisites - Docker (https://www.docker.com/) ---- +- NodeJS (https://nodejs.org/en/) ## Installation - Follow these steps to install this repo locally. ---- ### Clone - Clone this repo to your local machine using `https://github.com/fsereno/portfolio` ---- -### Run inside a Container using Docker +### Compose - Please ensure you have Docker installed and running. - Open your preferred command line: -Launch the production environment +Docker compose files are dynamically built, depending on command line arguments. + +```shell +$ npm run compose -- +``` +Passing no arguments will result in adding all available services to the production compose file. + +Alternatively, passing --mode dev, will build the development compose file. + +```shell +$ npm run compose -- --mode dev +``` +However, once again, this will include all available services in the compose file. + +To include only specific services in the compose file, use the --include argument: + +```shell +$ npm run compose -- --include dataStructures --mode dev +``` +##### This will: +- Compose the development version of the file. +- Simply exclude --mode dev if building for production. +- Include only the dataStructures service. +- The necessary Nginx service will also be included. + +### Start/Stop + +- Please ensure you have Docker installed and running. +- Open your preferred command line: ```shell -$ docker compose up +$ npm run start -- ``` +Passing no arguments will result in the production environment being started. + ##### This will: - Pull all images from Docker Hub. - Spin up all services in containers. -- The application will be available at: http://localhost/ +- The application will be available at: http://localhost -To run one of the following specific Docker tasks -- analysis -- create -- dev -- rel -- test -- test-e2e +To stop one of the above tasks, excluding those which destroy themselves: ```shell -$ sh start +$ npm run stop -- ``` -To stop one of the above tasks, excluding those which destroy themselves (create, test) + +Passing --name will start a particular container. ```shell -$ sh stop +$ npm run start -- --name ``` ---- -### Tasks +##### This will: +- Start only the container for the given application. +- The application will be available at: http://localhost + +To stop a particular container: + +```shell +$ npm run stop -- --name +``` -#### Serve a specific application via the development server +To start the development environment: ```shell -$ sh start dev +$ npm run start -- --mode dev --context dataStructures ``` ##### This will: -- Start the development server. -- Watch for any changes on development resources. -- Hot-reload any changes straight to the browser. -- The default application is the root application - home -- Open your browser and navigate to http://localhost:8080. ---- +- Start the webpack development server. +- Start the necessary backend services. +- Watch for any changes on dataStructures development resources. +- Hot-reload any changes straight to the browser for the dataStructures application. +- The default application is the root application - home. +- Open your browser and navigate to http://localhost -#### Run analysis on a specific application +#### Run dependency analysis on a specific application ```shell -$ sh start analysis +$ npm run start -- --context dataStructures --mode analysis ``` ##### This will: -- Start the analysis server. -- Perform a dependency analysis of the application. -- Open your browser and navigate to http://localhost:8080. ---- +- Start the webpack analysis server. +- Perform a dependency analysis of the dataStructures application frontend. +- The default application is the root application - home. +- Open your browser and navigate to http://localhost + +### Tasks + +- Please ensure you have Docker installed and running. +- Open your preferred command line: + +Tasks create ephemeral containers. Containers which are destroyed after a task has completed. #### Build for release ```shell -$ sh start rel +$ npm run task -- --name build ``` ##### This will: -- Build the production static assets directory. ---- +- Create an ephemeral container to run the task. +- Build the production static assets directory (dist or docs, depending on the configuration). +- The container is automatically destroyed after use. -#### Run all unit tests +#### Run all frontend unit tests ```shell -$ sh start test +$ npm run task -- --name test ``` ##### This will: +- Create an ephemeral container to run the task. - Run all application specific and global unit tests. ---- #### Run all functional end-to-end tests +Ensure the application is already running first. + ```shell -$ sh start test-e2e +$ npm run test-apps-e2e ``` ##### This will: - Run all functional tests from the ./app/tests/functional directory - Currently this feature is a work in progress (WIP) and will not work on ARM architecture ---- #### Create a new application ```shell -$ sh create +$ npm run task -- --name create ``` ##### This will: +- Create an ephemeral container to run the task. - Build applications based on the config.json file. - New applications are built based on the 'masterTemplateDir' property. - If an application already exists, nothing will be overwritten. ---- ## Licence - **[MIT licence](https://fsereno.github.io/portfolio/app_licence/index.html)** -- Copyright 2021 © Fabio Sereno. \ No newline at end of file +- Copyright 2024 © Fabio Sereno. \ No newline at end of file diff --git a/app/app_UniqueDataEntry/tests/e2e/taiko.test.js b/app/app_UniqueDataEntry/tests/e2e/taiko.test.js index 523be785..300beec4 100644 --- a/app/app_UniqueDataEntry/tests/e2e/taiko.test.js +++ b/app/app_UniqueDataEntry/tests/e2e/taiko.test.js @@ -5,7 +5,7 @@ import { openBrowser, goto, write, click, closeBrowser, $, into, textBox, button, waitFor, evaluate, text } from 'taiko'; import { ConfigUtil } from '../../../js/modules/utils/configUtil'; -const APPLICATION = "app_AzureDotNetCoreUniqueDataEntryApi"; +const APPLICATION = "app_uniqueDataEntry"; const CONFIG = ConfigUtil.get(); const URL = `http://${CONFIG.dockerHost}/${APPLICATION}/index.html`; @@ -20,9 +20,6 @@ beforeAll(async () => { describe(APPLICATION, () => { test('Should add an item to the table', async () => { await goto(URL); - await write('14', into(textBox({ id: 'answerInput' }), { force: true })); - await click(button({ id: 'submitPuzzle' })); - await waitFor(2000); await write('James', into(textBox({ id: 'firstNameInput' }))); await write('Brown', into(textBox({ id: 'secondNameInput' }))); await write('(000) 111 222', into(textBox({ id: 'contactInput' }))); @@ -34,9 +31,6 @@ describe(APPLICATION, () => { }, 100000); test('Should not add a duplicate item to the table', async () => { await goto(URL); - await write('14', into(textBox({ id: 'answerInput' }), { force: true })); - await click(button({ id: 'submitPuzzle' })); - await waitFor(2000); await write('John', into(textBox({ id: 'firstNameInput' }))); await write('Doe', into(textBox({ id: 'secondNameInput' }))); await write('000000000', into(textBox({ id: 'contactInput' }))); @@ -52,9 +46,6 @@ describe(APPLICATION, () => { }, 100000); test('Should remove an item to the table', async () => { await goto(URL); - await write('14', into(textBox({ id: 'answerInput' }), { force: true })); - await click(button({ id: 'submitPuzzle' })); - await waitFor(2000); await click($('a.delete[data-index="0"]')); const result = await evaluate($('#itemTable'), (element) => element.innerText); expect(result).toBe('First name\tSecond name\tContact\tPostcode\tAction'); diff --git a/app/app_nodeToDo/backend/api/services/userService.js b/app/app_nodeToDo/backend/api/services/userService.js index 1a812987..0463c137 100644 --- a/app/app_nodeToDo/backend/api/services/userService.js +++ b/app/app_nodeToDo/backend/api/services/userService.js @@ -6,7 +6,13 @@ const { v4: uuidv4 } = require('uuid'); /** * The registered users. */ -const users = []; +const users = [ + { + id: '1792aef2-2842-40ba-92a7-e7c6288f4595', + username: 'tester', + password: 'b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86' + } +]; // private members /** diff --git a/app/app_nodeToDo/tests/e2e/taiko.test.js b/app/app_nodeToDo/tests/e2e/taiko.test.js index 626e68e5..f6148568 100644 --- a/app/app_nodeToDo/tests/e2e/taiko.test.js +++ b/app/app_nodeToDo/tests/e2e/taiko.test.js @@ -1,71 +1,56 @@ -import { openBrowser, near, link, goto, write, click, closeBrowser, $, text, into, textBox, button, waitFor, evaluate } from 'taiko'; +import { openBrowser, goto, write, click, closeBrowser, $, text, into, textBox, button, waitFor, evaluate } from 'taiko'; import { ConfigUtil } from '../../../js/modules/utils/configUtil'; -// This is a WIP - it appears running these tests on an ARM machine will alwasys fail - need to wait for some deps to be released. - const APPLICATION = "app_nodeToDo"; const CONFIG = ConfigUtil.get(); const URL = `http://${CONFIG.dockerHost}/${APPLICATION}/index.html`; -const browserPath = '/usr/bin/chromium'; beforeAll(async () => { - try { - await openBrowser({ - //executablePath: browserPath, - //headless: true, - //slowMo: 250, - args: [ - //'--disable-gpu', - //'--disable-dev-shm-usage', - //'--disable-setuid-sandbox', - //'--no-first-run', - //'--no-sandbox', - //'--no-zygote' - ] - }); - console.log("AFTER") - } catch (error) { - console.error(error); - } -}); + await openBrowser({ + headless: true, + slowMo: 250, + args: ['--no-sandbox'] + }); + }); describe(APPLICATION, () => { test('Should be able to test this application', () => { expect(true).toBeTruthy(); }); - /*test('Should not login successfully when an invalid user is passed', async () => { + test('Should not login successfully when an invalid user is passed', async () => { await goto(URL); await write('Someuser123', into(textBox({ id: 'username' }))); await write('SomePassword123', into(textBox({ id: 'password' }))); await click(button({ id: 'submit' })); await waitFor(2000); await $('.text-danger').exists(); - const error = await text('Incorrect username or password.').exists(); + const error = await text('Username or password does not match.').exists(); expect(error).toBeTruthy(); }, 100000); - test('Should login successfully with TestUser', async () => { - let manageExists = false; + test('Should login successfully with tester', async () => { + let exists = false; await goto(URL); - await write('TestUser', into(textBox({ id: 'username' }))); - await write('Password-1', into(textBox({ id: 'password' }))); + await write('tester', into(textBox({ id: 'username' }))); + await write('password', into(textBox({ id: 'password' }))); await click(button({ id: 'submit' })); await waitFor(2000); - const error = await text('Incorrect username or password.').exists(); + const error = await text('Username or password does not match.').exists(); expect(error).toBeFalsy(); - manageExists = await text('Describe a task to do:').exists(); - expect(manageExists).toBeTruthy(); + exists = await text('Describe a task to do:').exists(); + expect(exists).toBeTruthy(); await click($('#logoutNavLink')); await waitFor(2000); await click(button({ id: 'submit'})); await waitFor(2000); - manageExists = await text('Describe a task to do:').exists(); - expect(manageExists).toBeFalsy(); + exists = await text('Describe a task to do:').exists(); + expect(exists).toBeFalsy(); }, 100000); test('Should be able to add and remove an item', async () => { + let exists = false; await goto(URL); - await write('TestUser', into(textBox({ id: 'username' }))); - await write('Password-1', into(textBox({ id: 'password' }))); + await write('tester', into(textBox({ id: 'username' }))); + await write('password', into(textBox({ id: 'password' }))); await click(button({ id: 'submit' })); await waitFor(2000); await write('A test to do item', into(textBox({id: 'description'}))); @@ -82,13 +67,14 @@ describe(APPLICATION, () => { await waitFor(2000); await click(button({ id: 'submit'})); await waitFor(2000); - manageExists = await text('Describe a task to do:').exists(); - expect(manageExists).toBeFalsy(); + exists = await text('Describe a task to do:').exists(); + expect(exists).toBeFalsy(); }, 100000); test('Should be able to move an item to Completed items', async () => { + let exists = false; await goto(URL); - await write('TestUser', into(textBox({ id: 'username' }))); - await write('Password-1', into(textBox({ id: 'password' }))); + await write('tester', into(textBox({ id: 'username' }))); + await write('password', into(textBox({ id: 'password' }))); await click(button({ id: 'submit' })); await waitFor(2000); await write('A test to do item 2', into(textBox({id: 'description'}))); @@ -105,9 +91,9 @@ describe(APPLICATION, () => { await waitFor(2000); await click(button({ id: 'submit'})); await waitFor(2000); - manageExists = await text('Describe a task to do:').exists(); - expect(manageExists).toBeFalsy(); - }, 100000);*/ + exists = await text('Describe a task to do:').exists(); + expect(exists).toBeFalsy(); + }, 100000); }); afterAll(() => { diff --git a/app/app_stringSort/tests/e2e/taiko.test.js b/app/app_stringSort/tests/e2e/taiko.test.js index c86ad495..5a4e491b 100644 --- a/app/app_stringSort/tests/e2e/taiko.test.js +++ b/app/app_stringSort/tests/e2e/taiko.test.js @@ -5,7 +5,7 @@ import { openBrowser, goto, write, click, closeBrowser, $, into, textBox, button, waitFor, evaluate } from 'taiko'; import { ConfigUtil } from '../../../js/modules/utils/configUtil'; -const APPLICATION = "app_awsDotNetCoreStringSortApi"; +const APPLICATION = "app_stringSort"; const CONFIG = ConfigUtil.get(); const URL = `http://${CONFIG.dockerHost}/${APPLICATION}/index.html`; @@ -20,9 +20,6 @@ beforeAll(async () => { describe(APPLICATION, () => { test('Should add an item', async () => { await goto(URL); - await write('11', into(textBox({ id: 'answerInput' }), { force: true })); - await click(button({ id: 'submitPuzzle' })); - await waitFor(2000); await write('C,B,A,10,1', into(textBox({ id: 'valuesInput' }))); await click(button({ id: 'sort_submit' })); const result = await evaluate($('#resultOutput'), (element) => element.innerText); diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 3d00f6e5..00000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,25 +0,0 @@ -# Node.js -# Build a general Node.js project with npm. -# Add steps that analyze code, save build artifacts, deploy, and more: -# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript - -trigger: -- dev - -pool: - vmImage: 'ubuntu-latest' - -variables: - buildConfiguration: 'Release' - -steps: -- task: NodeTool@0 - inputs: - versionSpec: '14.x' - displayName: 'Install Node.js' - -- script: | - npm install - npm run test - npm run build - displayName: 'Install and build assets' \ No newline at end of file diff --git a/build-image b/build-image deleted file mode 100644 index 668ca70d..00000000 --- a/build-image +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Docker image build script runner - -DOCKER_DIR=$1 -TAG=$2 - -docker image build -f "docker/$DOCKER_DIR/Dockerfile" -t $TAG . \ No newline at end of file diff --git a/build/webpackHelper.js b/build/webpackHelper.js index b9d13ecc..01d6a6e1 100644 --- a/build/webpackHelper.js +++ b/build/webpackHelper.js @@ -88,7 +88,7 @@ module.exports = { }, logAnalysis: (env) => { if (module.exports.isAnalysis(env)) { - console.log(chalk.redBright(`Running analysis at: http://${config.host}:${config.port}`)); + console.log(chalk.greenBright(`Running analysis at: http://${config.host}:${config.port}`)); } }, logDone: () => console.log(chalk.greenBright("All compilations complete!")), diff --git a/config.json b/config.json index 3aee96e8..e3c6fe59 100644 --- a/config.json +++ b/config.json @@ -6,7 +6,7 @@ "cloud": "cloud", "static": "static" }, - "dockerHost": "nginx", + "dockerHost": "localhost", "port": 8080, "prefix": "app_", "entry": "home", @@ -123,7 +123,8 @@ "canItemBeAddedAsync": "uniqueDataEntry/api/canItemBeAddedAsync" }, "labels": ["JavaScript", "C#", "Cloud"], - "featured": false + "featured": false, + "services": ["uniqueDataEntry"] }, { "name": "Data Structures", @@ -142,7 +143,8 @@ "removeStackItem": "dataStructures/api/removeStackItemAsync" }, "labels": ["JavaScript", "C#", "Cloud"], - "featured": false + "featured": false, + "services": ["dataStructures"] }, { "name": "Complex Entity Sorting Algorithm", @@ -159,7 +161,8 @@ "sortSalaryDesc": "entitySort/api/sort/salary/desc" }, "labels": ["JavaScript", "C#", "Cloud"], - "featured": false + "featured": false, + "services":["entitySort"] }, { "name": "Natural Sorting Algorithm", @@ -175,7 +178,8 @@ "sort": "stringSort/api/sort" }, "labels": ["JavaScript", "C#", "Cloud"], - "featured": false + "featured": false, + "services": ["stringSort"] }, { "name": "Coffee Machine", @@ -192,7 +196,8 @@ "runAsync": "coffeeMachine/api/runasync" }, "labels": ["JavaScript", "C#", "Cloud"], - "order": 3 + "order": 3, + "services": ["coffeeMachine"] }, { "name": "AFrame React Example", @@ -244,7 +249,8 @@ "featured": false, "endpoints": { "base": "nodeToDo" - } + }, + "services": ["nodeToDo"] }, { "name": "Master React Template", diff --git a/config.services.json b/config.services.json new file mode 100644 index 00000000..28598f1c --- /dev/null +++ b/config.services.json @@ -0,0 +1,82 @@ +[ + { + "id": "coffeeMachine", + "name": "coffeeMachine", + "type": ".NET", + "ports": ["3001:3001"], + "networks": ["backend"], + "image": "fabiosereno/portfolio.coffee-machine:0.0.15" + }, + { + "id": "dataStructures", + "name": "dataStructures", + "type": ".NET", + "ports": ["3002:3002"], + "networks": ["backend"], + "image": "fabiosereno/portfolio.data-structures:0.0.5" + }, + { + "id": "uniqueDataEntry", + "name": "uniqueDataEntry", + "type": ".NET", + "ports": ["3003:3003"], + "networks": ["backend"], + "image": "fabiosereno/portfolio.unique-data-entry:0.0.2" + }, + { + "id": "stringSort", + "name": "stringSort", + "type": ".NET", + "ports": ["3004:3004"], + "networks": ["backend"], + "image": "fabiosereno/portfolio.string-sort:0.0.1" + }, + { + "id": "entitySort", + "name": "entitySort", + "type": ".NET", + "ports": ["3005:3005"], + "networks": ["backend"], + "image": "fabiosereno/portfolio.entity-sort:0.0.4" + }, + { + "id": "nodeToDo", + "name": "nodeToDo", + "type": "NODE", + "ports": ["3006:3006"], + "networks": ["backend"], + "image": "fabiosereno/portfolio.node-to-do:0.0.2" + }, + { + "id": "nginx.prod", + "name": "nginx", + "type": "NGINX", + "ports": ["80:80"], + "networks": ["frontend", "backend"], + "image": "fabiosereno/portfolio.nginx:1.1.0" + }, + { + "id": "nginx.dev", + "name": "nginx", + "type": "NGINX", + "ports": ["80:80"], + "networks": ["frontend", "backend"], + "image": "nginx:1.23.1" + }, + { + "id": "node.dev", + "name": "node", + "type": "NODE", + "ports": ["8080:8080"], + "networks": ["frontend", "backend"], + "image": "fabiosereno/portfolio.dev:0.0.2" + }, + { + "id": "node.analysis", + "name": "node", + "type": "NODE", + "ports": ["8080:8080"], + "networks": ["frontend", "backend"], + "image": "fabiosereno/portfolio.analysis:0.0.3" + } +] \ No newline at end of file diff --git a/create b/create deleted file mode 100644 index 068ac926..00000000 --- a/create +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -# Docker compose script runner - -cd docker/create - -sh start \ No newline at end of file diff --git a/docker-compose.analysis.yml b/docker-compose.analysis.yml new file mode 100644 index 00000000..f78165a8 --- /dev/null +++ b/docker-compose.analysis.yml @@ -0,0 +1,38 @@ +version: '3.9' +services: + nginx: + image: nginx:1.23.1 + ports: + - '80:80' + container_name: nginx + networks: + - frontend + - backend + mem_limit: 500M + cpus: 0.2 + volumes: + - ./nginx.dev.conf:/etc/nginx/conf.d/default.conf + depends_on: [] + node: + image: fabiosereno/portfolio.analysis:0.0.3 + environment: + - dir=${DIR:-home} + ports: + - '8080:8080' + volumes: + - ./config.json:/usr/src/app/config.json + - ./babel.config.json:/usr/src/app/babel.config.json + - ./setupTests.js:/usr/src/app/setupTests.js + - ./app:/usr/src/app/app + - ./docs:/usr/src/app/docs + - ./build:/usr/src/app/build + container_name: node + networks: + - frontend + - backend + mem_limit: 500M + cpus: 0.2 + depends_on: [] +networks: + frontend: null + backend: null diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 00000000..bf15b1c1 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,151 @@ +version: '3.9' +services: + uniqueDataEntry: + image: fabiosereno/portfolio.dotnet.dev:0.0.1 + container_name: uniqueDataEntry + networks: + - backend + ports: + - '3003:3003' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + volumes: + - >- + ./app/app_uniqueDataEntry/backend/api:/usr/src/app/app/app_uniqueDataEntry/backend/api + - ./backend/Portfolio.Core:/usr/src/app/backend/Portfolio.Core + command: >- + sh -c "dotnet build /usr/src/app/app/app_uniqueDataEntry/backend/api && + dotnet + /usr/src/app/app/app_uniqueDataEntry/backend/api/bin/Debug/net7.0/api.dll" + dataStructures: + image: fabiosereno/portfolio.dotnet.dev:0.0.1 + container_name: dataStructures + networks: + - backend + ports: + - '3002:3002' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + volumes: + - >- + ./app/app_dataStructures/backend/api:/usr/src/app/app/app_dataStructures/backend/api + - ./backend/Portfolio.Core:/usr/src/app/backend/Portfolio.Core + command: >- + sh -c "dotnet build /usr/src/app/app/app_dataStructures/backend/api && + dotnet + /usr/src/app/app/app_dataStructures/backend/api/bin/Debug/net7.0/api.dll" + entitySort: + image: fabiosereno/portfolio.dotnet.dev:0.0.1 + container_name: entitySort + networks: + - backend + ports: + - '3005:3005' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + volumes: + - >- + ./app/app_entitySort/backend/api:/usr/src/app/app/app_entitySort/backend/api + - ./backend/Portfolio.Core:/usr/src/app/backend/Portfolio.Core + command: >- + sh -c "dotnet build /usr/src/app/app/app_entitySort/backend/api && dotnet + /usr/src/app/app/app_entitySort/backend/api/bin/Debug/net7.0/api.dll" + stringSort: + image: fabiosereno/portfolio.dotnet.dev:0.0.1 + container_name: stringSort + networks: + - backend + ports: + - '3004:3004' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + volumes: + - >- + ./app/app_stringSort/backend/api:/usr/src/app/app/app_stringSort/backend/api + - ./backend/Portfolio.Core:/usr/src/app/backend/Portfolio.Core + command: >- + sh -c "dotnet build /usr/src/app/app/app_stringSort/backend/api && dotnet + /usr/src/app/app/app_stringSort/backend/api/bin/Debug/net7.0/api.dll" + coffeeMachine: + image: fabiosereno/portfolio.dotnet.dev:0.0.1 + container_name: coffeeMachine + networks: + - backend + ports: + - '3001:3001' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + volumes: + - >- + ./app/app_coffeeMachine/backend/api:/usr/src/app/app/app_coffeeMachine/backend/api + - ./backend/Portfolio.Core:/usr/src/app/backend/Portfolio.Core + command: >- + sh -c "dotnet build /usr/src/app/app/app_coffeeMachine/backend/api && + dotnet + /usr/src/app/app/app_coffeeMachine/backend/api/bin/Debug/net7.0/api.dll" + nodeToDo: + image: fabiosereno/portfolio.node.dev:0.0.1 + container_name: nodeToDo + networks: + - backend + ports: + - '3006:3006' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + volumes: + - ./app/app_nodeToDo/backend/api:/usr/src/app/app/app_nodeToDo/backend/api + command: sh -c "node /usr/src/app/app/app_nodeToDo/backend/api/index.js" + nginx: + image: nginx:1.23.1 + ports: + - '80:80' + container_name: nginx + networks: + - frontend + - backend + mem_limit: 500M + cpus: 0.2 + volumes: + - ./nginx.dev.conf:/etc/nginx/conf.d/default.conf + depends_on: + - uniqueDataEntry + - dataStructures + - entitySort + - stringSort + - coffeeMachine + - nodeToDo + node: + image: fabiosereno/portfolio.dev:0.0.2 + environment: + - dir=${DIR:-home} + ports: + - '8080:8080' + volumes: + - ./config.json:/usr/src/app/config.json + - ./babel.config.json:/usr/src/app/babel.config.json + - ./setupTests.js:/usr/src/app/setupTests.js + - ./app:/usr/src/app/app + - ./docs:/usr/src/app/docs + - ./build:/usr/src/app/build + container_name: node + networks: + - frontend + - backend + mem_limit: 500M + cpus: 0.2 + depends_on: + - uniqueDataEntry + - dataStructures + - entitySort + - stringSort + - coffeeMachine + - nodeToDo +networks: + frontend: null + backend: null diff --git a/docker-compose.yml b/docker-compose.yml index f72ecaa8..15f1643c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,84 +1,96 @@ version: '3.9' - services: - nginx: - image: 'fabiosereno/portfolio.nginx:0.5.0' - x-aws-pull_credentials: 'arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX' - ports: - - '80:80' - container_name: frontend - networks: - - frontend - - backend - depends_on: - - "coffeeMachine" - - "dataStructures" - - "uniqueDataEntry" - - "stringSort" - - "entitySort" - - "nodeToDo" - mem_limit: 500M - cpus: 0.2 - coffeeMachine: - image: 'fabiosereno/portfolio.coffee-machine:0.0.15' - x-aws-pull_credentials: 'arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX' - ports: - - '3001:3001' - container_name: coffeeMachine - networks: - - backend - mem_limit: 500M - cpus: 0.2 - dataStructures: - image: 'fabiosereno/portfolio.data-structures:0.0.5' - x-aws-pull_credentials: 'arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX' - ports: - - '3002:3002' - container_name: dataStructures - networks: - - backend - mem_limit: 500M - cpus: 0.2 - uniqueDataEntry: - image: 'fabiosereno/portfolio.unique-data-entry:0.0.2' - x-aws-pull_credentials: 'arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX' - ports: - - '3003:3003' - container_name: uniqueDataEntry - networks: - - backend - mem_limit: 500M - cpus: 0.2 - stringSort: - image: 'fabiosereno/portfolio.string-sort:0.0.1' - x-aws-pull_credentials: 'arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX' - ports: - - '3004:3004' - container_name: stringSort - networks: - - backend - mem_limit: 500M - cpus: 0.2 - entitySort: - image: 'fabiosereno/portfolio.entity-sort:0.0.4' - x-aws-pull_credentials: 'arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX' - ports: - - '3005:3005' - container_name: entitySort - networks: - - backend - mem_limit: 500M - cpus: 0.2 - nodeToDo: - image: 'fabiosereno/portfolio.node-to-do:0.0.1' - x-aws-pull_credentials: 'arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX' - ports: - - '3006:3006' - container_name: nodeToDo - networks: - - backend - mem_limit: 500M - cpus: 0.2 + uniqueDataEntry: + image: fabiosereno/portfolio.unique-data-entry:0.0.2 + container_name: uniqueDataEntry + networks: + - backend + ports: + - '3003:3003' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + x-aws-pull_credentials: >- + arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX + dataStructures: + image: fabiosereno/portfolio.data-structures:0.0.5 + container_name: dataStructures + networks: + - backend + ports: + - '3002:3002' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + x-aws-pull_credentials: >- + arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX + entitySort: + image: fabiosereno/portfolio.entity-sort:0.0.4 + container_name: entitySort + networks: + - backend + ports: + - '3005:3005' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + x-aws-pull_credentials: >- + arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX + stringSort: + image: fabiosereno/portfolio.string-sort:0.0.1 + container_name: stringSort + networks: + - backend + ports: + - '3004:3004' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + x-aws-pull_credentials: >- + arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX + coffeeMachine: + image: fabiosereno/portfolio.coffee-machine:0.0.15 + container_name: coffeeMachine + networks: + - backend + ports: + - '3001:3001' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + x-aws-pull_credentials: >- + arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX + nodeToDo: + image: fabiosereno/portfolio.node-to-do:0.0.2 + container_name: nodeToDo + networks: + - backend + ports: + - '3006:3006' + mem_limit: 500M + cpus: 0.2 + depends_on: [] + x-aws-pull_credentials: >- + arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX + nginx: + image: fabiosereno/portfolio.nginx:1.1.0 + ports: + - '80:80' + container_name: nginx + networks: + - frontend + - backend + mem_limit: 500M + cpus: 0.2 + x-aws-pull_credentials: >- + arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX + depends_on: + - uniqueDataEntry + - dataStructures + - entitySort + - stringSort + - coffeeMachine + - nodeToDo networks: - frontend: - backend: \ No newline at end of file + frontend: null + backend: null diff --git a/docker/analysis/start b/docker/analysis/start deleted file mode 100644 index 0ce55885..00000000 --- a/docker/analysis/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -DIR=$1 docker compose up \ No newline at end of file diff --git a/docker/analysis/stop b/docker/analysis/stop deleted file mode 100644 index a986179d..00000000 --- a/docker/analysis/stop +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose down \ No newline at end of file diff --git a/docker/rel/Dockerfile b/docker/build/Dockerfile similarity index 100% rename from docker/rel/Dockerfile rename to docker/build/Dockerfile diff --git a/docker/rel/docker-compose.yml b/docker/build/docker-compose.yml similarity index 91% rename from docker/rel/docker-compose.yml rename to docker/build/docker-compose.yml index ef2208ac..a018385d 100644 --- a/docker/rel/docker-compose.yml +++ b/docker/build/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.9' services: - node: + build: tty: true image: 'fabiosereno/portfolio.release:0.0.2' volumes: @@ -11,4 +11,4 @@ services: - '../../app:/usr/src/app/app' - '../../docs:/usr/src/app/docs' - '../../build:/usr/src/app/build' - container_name: node + container_name: build diff --git a/docker/coffeeMachine/start b/docker/coffeeMachine/start deleted file mode 100644 index 1d1f2f76..00000000 --- a/docker/coffeeMachine/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose up \ No newline at end of file diff --git a/docker/coffeeMachine/stop b/docker/coffeeMachine/stop deleted file mode 100644 index a986179d..00000000 --- a/docker/coffeeMachine/stop +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose down \ No newline at end of file diff --git a/docker/create/Dockerfile b/docker/create/Dockerfile index 27323a18..757aae7e 100644 --- a/docker/create/Dockerfile +++ b/docker/create/Dockerfile @@ -1,6 +1,3 @@ FROM fabiosereno/portfolio.npm:0.0.1 -HEALTHCHECK --interval=12s --timeout=12s --start-period=30s \ - CMD node healthcheck.js - CMD ["sh", "-c", "npm run create"] \ No newline at end of file diff --git a/docker/create/docker-compose.yml b/docker/create/docker-compose.yml index 74e9913a..5eecb902 100644 --- a/docker/create/docker-compose.yml +++ b/docker/create/docker-compose.yml @@ -1,11 +1,10 @@ version: '3.9' services: - node: - tty: true - image: 'fabiosereno/portfolio.create:0.0.2' + create: + image: 'fabiosereno/portfolio.create:0.0.1' volumes: - '../../config.json:/usr/src/app/config.json' - '../../app:/usr/src/app/app' - '../../build:/usr/src/app/build' - container_name: node + container_name: create diff --git a/docker/create/start b/docker/create/start deleted file mode 100644 index 8f3c2e2b..00000000 --- a/docker/create/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker-compose run --rm node \ No newline at end of file diff --git a/docker/dataStructures/start b/docker/dataStructures/start deleted file mode 100644 index 1d1f2f76..00000000 --- a/docker/dataStructures/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose up \ No newline at end of file diff --git a/docker/dataStructures/stop b/docker/dataStructures/stop deleted file mode 100644 index a986179d..00000000 --- a/docker/dataStructures/stop +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose down \ No newline at end of file diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml deleted file mode 100644 index 325b1a77..00000000 --- a/docker/dev/docker-compose.yml +++ /dev/null @@ -1,102 +0,0 @@ -version: '3.9' - -services: - node: - image: 'fabiosereno/portfolio.dev:0.0.2' - environment: - - dir=${DIR:-home} - ports: - - '8080:8080' - volumes: - - '../../config.json:/usr/src/app/config.json' - - '../../babel.config.json:/usr/src/app/babel.config.json' - - '../../setupTests.js:/usr/src/app/setupTests.js' - - '../../app:/usr/src/app/app' - - '../../docs:/usr/src/app/docs' - - '../../build:/usr/src/app/build' - container_name: node - networks: - - frontend - - backend - depends_on: - - "coffeeMachine" - - "dataStructures" - - "uniqueDataEntry" - - "stringSort" - - "entitySort" - mem_limit: 500M - cpus: 0.2 - nginx: - image: 'fabiosereno/portfolio.nginx.dev:0.2.6' - ports: - - '80:80' - container_name: frontend - networks: - - frontend - - backend - depends_on: - - "coffeeMachine" - - "dataStructures" - - "uniqueDataEntry" - - "stringSort" - - "entitySort" - - "nodeToDo" - mem_limit: 500M - cpus: 0.2 - coffeeMachine: - image: 'fabiosereno/portfolio.coffee-machine:0.0.15' - ports: - - '3001:3001' - container_name: coffeeMachine - networks: - - backend - mem_limit: 500M - cpus: 0.2 - dataStructures: - image: 'fabiosereno/portfolio.data-structures:0.0.5' - ports: - - '3002:3002' - container_name: dataStructures - networks: - - backend - mem_limit: 500M - cpus: 0.2 - uniqueDataEntry: - image: 'fabiosereno/portfolio.unique-data-entry:0.0.2' - ports: - - '3003:3003' - container_name: uniqueDataEntry - networks: - - backend - mem_limit: 500M - cpus: 0.2 - stringSort: - image: 'fabiosereno/portfolio.string-sort:0.0.1' - ports: - - '3004:3004' - container_name: stringSort - networks: - - backend - mem_limit: 500M - cpus: 0.2 - entitySort: - image: 'fabiosereno/portfolio.entity-sort:0.0.4' - ports: - - '3005:3005' - container_name: entitySort - networks: - - backend - mem_limit: 500M - cpus: 0.2 - nodeToDo: - image: 'fabiosereno/portfolio.node-to-do:0.0.1' - ports: - - '3006:3006' - container_name: nodeToDo - networks: - - backend - mem_limit: 500M - cpus: 0.2 -networks: - frontend: - backend: \ No newline at end of file diff --git a/docker/dev/start b/docker/dev/start deleted file mode 100644 index 0ce55885..00000000 --- a/docker/dev/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -DIR=$1 docker compose up \ No newline at end of file diff --git a/docker/dev/stop b/docker/dev/stop deleted file mode 100644 index a986179d..00000000 --- a/docker/dev/stop +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose down \ No newline at end of file diff --git a/docker/dotnet/Dockerfile.dev b/docker/dotnet/Dockerfile.dev new file mode 100644 index 00000000..24d4ea78 --- /dev/null +++ b/docker/dotnet/Dockerfile.dev @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base + +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build + +WORKDIR /src + +RUN apt-get update \ + && apt-get install -y curl + +# Entry point to keep the container running +CMD ["tail", "-f", "/dev/null"] \ No newline at end of file diff --git a/docker/entitySort/start b/docker/entitySort/start deleted file mode 100644 index 1d1f2f76..00000000 --- a/docker/entitySort/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose up \ No newline at end of file diff --git a/docker/entitySort/stop b/docker/entitySort/stop deleted file mode 100644 index a986179d..00000000 --- a/docker/entitySort/stop +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose down \ No newline at end of file diff --git a/docker/node/Dockerfile.dev b/docker/node/Dockerfile.dev new file mode 100644 index 00000000..1ec0648b --- /dev/null +++ b/docker/node/Dockerfile.dev @@ -0,0 +1,9 @@ +FROM node:18.14.2 AS base + +WORKDIR /app + +RUN apt-get update \ + && apt-get install -y curl + +# Entry point to keep the container running +CMD ["tail", "-f", "/dev/null"] \ No newline at end of file diff --git a/docker/nodeToDo/start b/docker/nodeToDo/start deleted file mode 100644 index 1d1f2f76..00000000 --- a/docker/nodeToDo/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose up \ No newline at end of file diff --git a/docker/nodeToDo/stop b/docker/nodeToDo/stop deleted file mode 100644 index a986179d..00000000 --- a/docker/nodeToDo/stop +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose down \ No newline at end of file diff --git a/docker/rel/start b/docker/rel/start deleted file mode 100644 index 8f3c2e2b..00000000 --- a/docker/rel/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker-compose run --rm node \ No newline at end of file diff --git a/docker/scripts/compose.js b/docker/scripts/compose.js new file mode 100644 index 00000000..280aeda0 --- /dev/null +++ b/docker/scripts/compose.js @@ -0,0 +1,8 @@ +const handlers = require('./handlers.common'); +const composeHandlers = require('./handlers.compose'); +const verbs = require('./verbs.compose'); +const constants = require('./constants.compose'); + +handlers.ifHasUnsupported(verbs.supported); +handlers.ifHasHelp(verbs.hasHelp, constants.help); +composeHandlers.compose(); \ No newline at end of file diff --git a/docker/scripts/constants.apps.js b/docker/scripts/constants.apps.js new file mode 100644 index 00000000..fd0edb4d --- /dev/null +++ b/docker/scripts/constants.apps.js @@ -0,0 +1,41 @@ +const chalk = require('chalk'); + +const NAME = '--name'; +const CONTEXT = '--context'; +const MODE = '--mode'; +const HELP = '--help'; +const TEST = '--test'; +const test = 'test'; +const REMOVE = '--rm'; + +const help = ` +You run this script by calling node and the script name - node (start/stop).js. This is already configured as a script via npm: + +${chalk.yellow('> npm run (start/stop) -- [OPTIONS]')} + +It is important to pass down the options via the -- seperator: + +Eg. > ${chalk.yellow('npm run (start/stop) -- --help')} + +These are the available options: + +${chalk.yellow(MODE)} - ${chalk.green('This command allows you to target a specific mode. Otherwise the production version is used. Available modes are: dev, analysis.')} + +${chalk.yellow(NAME)} - ${chalk.green('This command is used by specifying the name of the application you want to target.')} + +${chalk.yellow(CONTEXT)} - ${chalk.green(`This command allows you to define a context for a container. Use this if the context is different to that of the application ${NAME} or you require to pass a context to a root compose file.`)} + +${chalk.yellow(TEST)} - ${chalk.green(`This command creates an ephemeral container and executes tests for this application`)} + +${chalk.yellow(HELP)} - ${chalk.green('This is help :-)')}`; + +module.exports = { + NAME, + CONTEXT, + MODE, + HELP, + TEST, + test, + REMOVE, + help +}; \ No newline at end of file diff --git a/docker/scripts/constants.common.js b/docker/scripts/constants.common.js new file mode 100644 index 00000000..bbe20134 --- /dev/null +++ b/docker/scripts/constants.common.js @@ -0,0 +1,19 @@ +const DOT_NET = '.NET'; +const NGINX = 'NGINX' +const NODE = 'NODE'; +const dev = 'dev'; +const test = 'test'; +const analysis = 'analysis'; +const yml = 'yml'; +const conf = 'conf'; + +module.exports = { + DOT_NET, + NGINX, + NODE, + dev, + test, + analysis, + yml, + conf +}; \ No newline at end of file diff --git a/docker/scripts/constants.compose.js b/docker/scripts/constants.compose.js new file mode 100644 index 00000000..afe500c0 --- /dev/null +++ b/docker/scripts/constants.compose.js @@ -0,0 +1,33 @@ +const chalk = require('chalk'); + +const NAME = '--name'; +const MODE = '--mode'; +const INCLUDE = '--include'; +const HELP = '--help'; + +const help = ` +You run this script by calling node and the script name - node (start/stop).js. This is already configured as a script via npm: + +${chalk.yellow('> npm run compose -- [OPTIONS]')} + +It is important to pass down the options via the -- seperator: + +Eg. > ${chalk.yellow('npm run compose -- --help')} + +These are the available options: + +${chalk.yellow(MODE)} - ${chalk.green('This command allows you to target a specific mode. Otherwise the production version is used. Available modes are: dev, analysis.')} + +${chalk.yellow(NAME)} - ${chalk.green('This command is used by specifying the name of the definition to include in the compose file.')} + +${chalk.yellow(INCLUDE)} - ${chalk.green('This command is used once, followed by the service definitions to include in the compose file.')} + +${chalk.yellow(HELP)} - ${chalk.green('This is help :-)')}`; + +module.exports = { + NAME, + MODE, + INCLUDE, + HELP, + help, +}; \ No newline at end of file diff --git a/docker/scripts/constants.image.js b/docker/scripts/constants.image.js new file mode 100644 index 00000000..c4ce7ba7 --- /dev/null +++ b/docker/scripts/constants.image.js @@ -0,0 +1,39 @@ +const chalk = require('chalk'); + +const MODE = '--mode'; +const NAME = '--name'; +const TAG = '--tag'; +const PUSH = '--push'; +const HELP = '--help'; + +const help = ` +Image will build a new image of the specified application. + +You run this script by calling node and the script name - node image.js. This is already configured as a script via npm: + +${chalk.yellow('> npm run image -- [OPTIONS]')} + +It is important to pass down the options via the -- seperator: + +Eg. > ${chalk.yellow('npm run image -- --help')} + +These are the available options: + +${chalk.yellow(MODE)} - ${chalk.green('This command allows you to target a specific mode. Otherwise the production version is used. Available modes are: dev.')} + +${chalk.yellow(NAME)} - ${chalk.green('This command should be followed by the name of the application you intend to image.')} + +${chalk.yellow(TAG)} - ${chalk.green('This command is used to assign a tag to the image.')} + +${chalk.yellow(PUSH)} - ${chalk.green('This command is used to push an image to the repository.')} + +${chalk.yellow(HELP)} - ${chalk.green('This is help :-)')}`; + +module.exports = { + MODE, + NAME, + TAG, + PUSH, + HELP, + help +}; \ No newline at end of file diff --git a/docker/scripts/handlers.apps.js b/docker/scripts/handlers.apps.js new file mode 100644 index 00000000..64b4f197 --- /dev/null +++ b/docker/scripts/handlers.apps.js @@ -0,0 +1,51 @@ +const constants = require('./constants.apps'); +const constantsCommon = require('./constants.common'); +const helpers = require('./helpers.common'); +const verbs = require('./verbs.apps'); +const handlers = require('./handlers.common'); +const hasSomeEphemeral = handlers.ifHasSome(verbs.ephemeral); +const attachmentMode = ( verbs.hasDev || verbs.hasAnalysis || verbs.hasTest || hasSomeEphemeral ) ? '' : '-d'; + +/** + * Generates the name of the Docker Compose file based on the environment configuration. + * @returns {string} The name of the Docker Compose file. + */ +const getComposeFilename = () => helpers.getComposeFilename(helpers.get(constants.MODE)); + +/** + * Generates the path of the Docker Compose file based on the environment configuration. + * @returns {string} The name of the Docker Compose file. + */ +const getComposeFilePath = () => verbs.hasName ? `./docker/${getName()}/${getComposeFilename()}` : `./${getComposeFilename()}`; + +/** + * Determines the name based on the presence of analysis in verbs. + * If analysis is present, returns the analysis constant; otherwise, returns the NAME constant. + * @returns {string} The determined name. + */ +const getName = () => verbs.hasAnalysis ? constantsCommon.analysis : helpers.get(constants.NAME); + +/** + * Starts Docker containers based on the configured environment. + */ +const start = () => { + const composeFile = getComposeFilePath(); + const destroyCallback = hasSomeEphemeral ? () => helpers.run(`docker compose -f ${composeFile} down`) : undefined; + const context = helpers.has(constants.CONTEXT) ? `DIR=${helpers.get(constants.CONTEXT)}` : ''; + const command = `${context} docker compose -f ${composeFile} up ${attachmentMode}`; + helpers.run(command, {}, destroyCallback); +} + +/** + * Stops Docker containers based on the configured environment. + */ +const stop = () => { + const composeFile = getComposeFilePath(); + const command = `docker compose -f ${composeFile} down`; + helpers.run(command); +} + +module.exports = { + start, + stop +}; \ No newline at end of file diff --git a/docker/scripts/handlers.common.js b/docker/scripts/handlers.common.js new file mode 100644 index 00000000..fcf198f8 --- /dev/null +++ b/docker/scripts/handlers.common.js @@ -0,0 +1,53 @@ +const chalk = require('chalk'); +const helpers = require('./helpers.common'); + +/** + * Checks if any unsupported arguments are provided. + * @param {string[]} supported - An array of supported arguments. + */ +const ifHasUnsupported = (supported = []) => { + if (helpers.args.filter(arg => arg.startsWith("--")).some(x => supported.indexOf(x) === -1)) { + console.error(chalk.redBright('ERROR: Unsupported arguments detected.')); + process.exit(1); + } +} + +/** + * Checks if any of the specified arguments are present among the command-line arguments. + * @param {string[]} some - An array of arguments to check for. + * @returns {boolean} True if any of the specified arguments are found, otherwise false. + */ +const ifHasSome = (some = []) => helpers.args.filter(arg => arg.startsWith("--")).some(x => some.indexOf(x) > -1); + +/** + * Checks if the "hasHelp" flag is set to true and prints the help message if provided. + * @param {boolean} hasHelp - A flag indicating whether help message should be displayed. + * @param {string} [help=""] - The help message to display. + */ +const ifHasHelp = (hasHelp = false, help = "") => { + if (hasHelp) { + console.log(help); + process.exit(0); + } +} + +/** + * Validates if the required arguments are present among the command-line arguments. + * @param {string[]} required - An array of required arguments. + */ +const validate = (required = []) => { + const argsArray = helpers.args.filter(arg => arg.startsWith("--")) + var valid = required.every(item => argsArray.includes(item)); + const missingItems = required.filter(item => !helpers.args.includes(item)); + if (!valid) { + console.error(chalk.redBright(`ERROR: Missing required arguments. ${missingItems.join(',')}`)); + process.exit(1); + } +} + +module.exports = { + validate, + ifHasUnsupported, + ifHasHelp, + ifHasSome +}; \ No newline at end of file diff --git a/docker/scripts/handlers.compose.js b/docker/scripts/handlers.compose.js new file mode 100644 index 00000000..b394cdc3 --- /dev/null +++ b/docker/scripts/handlers.compose.js @@ -0,0 +1,167 @@ +const chalk = require('chalk'); +const constants = require('./constants.compose'); +const helpers = require('./helpers.common'); +const helpersCompose = require('./helpers.compose'); +const verbs = require('./verbs.compose'); + +/** + * Asserts the mode based on whether the production flag is present. + * Prints the mode to the console. + */ +const assertMode = () => console.log(chalk.blue('Mode:'), chalk.yellow(verbs.hasProd ? 'Production' : 'Development')); + +/** + * Sets the NGINX root configuration for production mode if the production flag is present. + * @param {string[]} nginxConfig - An array representing the NGINX configuration. + */ +const setProdRoot = (nginxConfig = []) => { + if (verbs.hasProd) { + helpersCompose.appendNginxConfig(nginxConfig, helpersCompose.getNginxProdRoot()); + } +} + +/** + * Asserts that the Docker Compose process is complete and logs a success message to the console. + */ +const assertComplete = () => console.log(chalk.green(`Compose complate...`)); + +/** + * Builds the Docker Compose configuration and associated NGINX configuration based on the environment configuration. + */ +const compose = () => { + + const serviceConfigs = helpers.getServicesConfig(); + const yamlFilename = helpers.getComposeFilename(helpers.get(constants.MODE)); + const yamlRoot = './'; + const yamlPath = `${yamlRoot}${yamlFilename}` + const nginxFilename = helpers.getNginxFilename(helpers.get(constants.MODE)); + const services = {} + const dependsOn = []; + const nginxConfig = helpersCompose.getNginxConfOpen(); + const networks = { + frontend: null, + backend: null + } + + assertMode(); + setProdRoot(nginxConfig); + addServices(serviceConfigs, services, nginxConfig); + buildDependsOn(services, dependsOn); + addNginx(services, serviceConfigs, dependsOn); + addDevServer(services, nginxConfig, dependsOn, serviceConfigs); + + const compose = helpersCompose.compose({services, networks}); + + helpersCompose.getNginxConfClose(nginxConfig); + helpersCompose.createYaml(compose, yamlPath); + helpersCompose.createNginxConfig(nginxConfig, nginxFilename); + assertComplete(); +} + +/** + * Adds development server configurations to the services object and NGINX configuration if in development mode. + * @param {object} services - An object representing the services. + * @param {string[]} nginxConfig - An array representing the NGINX configuration. + * @param {string[]} dependsOn - An array representing the dependencies. + * @param {object[]} serviceConfigs - An array representing the service configurations. + */ +const addDevServer = (services = {}, nginxConfig = [], dependsOn = [], serviceConfigs = []) => { + if (!verbs.hasProd) { + const nodeType = verbs.hasDev ? 'node.dev' : 'node.analysis'; + const nodeServiceConfig = serviceConfigs.find(x => x.id === nodeType); + const node = helpersCompose.getNodeDev(nodeServiceConfig); + services.node = {...node.service, ...helpersCompose.getDependsOn(dependsOn)} + helpersCompose.appendNginxConfig(nginxConfig, node.config); + } +} + +/** + * Adds NGINX service configurations based on the environment configuration. + * @param {object} services - An object representing the services. + * @param {object[]} serviceConfigs - An array representing the service configurations. + * @param {string[]} dependsOn - An array representing the dependencies. + */ +const addNginx = (services = {}, serviceConfigs = [], dependsOn = []) => { + const nginxType = !verbs.hasProd ? 'nginx.dev' : 'nginx.prod'; + const nginxServiceConfig = serviceConfigs.find(x => x.id === nginxType); + const nginxService = helpersCompose.getService(nginxServiceConfig, !verbs.hasProd); + services.nginx = {...nginxService, ...helpersCompose.getDependsOn(dependsOn)} +} + +/** + * Builds a dependency array based on the services provided. + * @param {object} services - An object representing the services. + * @param {string[]} dependsOn - An array representing the dependencies. + */ +const buildDependsOn = (services = {}, dependsOn = []) => { + Object.keys(services).forEach(key => { + const doesNotExist = !dependsOn.some(x => x === key); + if (doesNotExist) { + dependsOn.push(key) + } + }); +} + +/** + * Adds services to the service configurations and NGINX configuration based on the environment configuration. + * @param {object[]} serviceConfigs - An array representing the service configurations. + * @param {object} services - An object representing the services. + * @param {string[]} nginxConfig - An array representing the NGINX configuration. + */ +const addServices = (serviceConfigs = [], services = {}, nginxConfig = []) => { + + if (verbs.hasAnalysis) { + + // analysis requires no other services. + return; + } + + if (verbs.hasInclude) { + + console.log(chalk.blue('Includes detected')) + + const applicationServices = helpers.getAll(constants.INCLUDE); + + addApplicationServices(applicationServices, serviceConfigs, services, nginxConfig); + + } else { + const config = helpers.getConfig(); + + config.applications.forEach(_application => { + const applicationServices = _application.services; + addApplicationServices(applicationServices, serviceConfigs, services, nginxConfig); + }); + } +} + +/** + * This method will mutate the services and nginxConfig params to build up the services definition. + * @param {*} applicationServices - The discovered services to add + * @param {*} services - The dictionary to add to. + * @param {*} nginxConfig - The Nginx config needed for each service. + */ +const addApplicationServices = (applicationServices = [], serviceConfigs = [], services = {}, nginxConfig = []) => { + + if (applicationServices) { + + applicationServices.forEach(_service => { + + const service = serviceConfigs.find(x => x.id === _service); + const doesNotExist = !services[_service]; + + if (doesNotExist) { + console.log(chalk.blue(`adding service:`), chalk.yellow(`${_service}`)); + + const serviceConfig = helpersCompose.getService(service, verbs.hasDev); + services[_service] = serviceConfig.service; + + console.log(chalk.blue(`adding nginx config for:`), chalk.yellow(`${_service}`)); + helpersCompose.appendNginxConfig(nginxConfig, serviceConfig.config); + } + }); + } +} + +module.exports = { + compose +}; \ No newline at end of file diff --git a/docker/scripts/handlers.image.js b/docker/scripts/handlers.image.js new file mode 100644 index 00000000..e09dbd0d --- /dev/null +++ b/docker/scripts/handlers.image.js @@ -0,0 +1,34 @@ +const constants = require('./constants.image'); +const helpers = require('./helpers.common'); +const verbs = require('./verbs.image'); + +/** + * Creates an image with tag. + * Requires --name and --tag. + */ +const runIfHasNameAndTag = () => { + if (verbs.hasName && verbs.hasTag) { + const name = helpers.get(constants.NAME); + const tag = helpers.get(constants.TAG); + const dockerfile = verbs.hasDev ? 'Dockerfile.dev' : 'Dockerfile'; + const command = `docker image build -f "./docker/${name}/${dockerfile}" -t ${tag} .`; + helpers.run(command); + } +} + +/** + * Pushes an image with tag to the repository. + * Requires --push and --tag. + */ +const runIfHasPushAndTag = () => { + if (verbs.hasPush && verbs.hasTag) { + const tag = helpers.get(constants.TAG); + const command = `docker image push ${tag}`; + helpers.run(command); + } +} + +module.exports = { + runIfHasNameAndTag, + runIfHasPushAndTag +}; \ No newline at end of file diff --git a/docker/scripts/helpers.common.js b/docker/scripts/helpers.common.js new file mode 100644 index 00000000..5a214387 --- /dev/null +++ b/docker/scripts/helpers.common.js @@ -0,0 +1,137 @@ +const chalk = require('chalk'); +const { execSync } = require('child_process'); +const args = process.argv.slice(2); +const fs = require('fs'); +const CONFIG_PATH = './config.json'; +const CONFIG_SERVICES_PATH = './config.services.json'; +const constants = require('./constants.common'); + +/** + * Checks if the provided command exists among the command-line arguments. + * @param {string} command - The command to check for. + * @returns {boolean} True if the command exists among the arguments, otherwise false. + */ +const has = (command) => args.some(x => x === command); + +/** + * Retrieves the value associated with the specified command from the command-line arguments. + * @param {string} command - The command to retrieve the value for. + * @returns {string|undefined} The value associated with the command, or undefined if not found. + */ +const get = (command) => args[args.indexOf(command) + 1]; + +/** + * Retrieves all values associated with the specified command from the command-line arguments. + * @param {string} command - The command to retrieve the values for. + * @returns {string[]} An array containing all values associated with the command. + */ +const getAll = (command) => { + const all = [...args]; + const specific = all.splice(all.indexOf(command) + 1); + const values = specific.filter(x => !x.startsWith('--')) + return values; +} + +/** + * Executes the specified command synchronously and exits the process afterward. + * @param {string} command - The command to execute. + * @param {Object} options - Additional options for the command execution. + * @param {Function} [callback=() => undefined] - Optional callback function to execute after command execution. + */ +const run = (command, options, callback = () => undefined) => { + console.log(chalk.green('Running command: ' + command)); + execSync(command, {...options, stdio: 'inherit' }); + if (typeof callback === "function") { + callback(); + } + process.exit(0); +} + +/** + * Retrieves the configuration object from the specified path. + * @returns {Object} The configuration object. + */ +const getConfig = () => getJson(CONFIG_PATH); + +/** + * Retrieves the services configuration object from the specified path. + * @returns {Object} The services configuration object. + */ +const getServicesConfig = () => getJson(CONFIG_SERVICES_PATH); + +/** + * Reads and parses a JSON file from the specified path. + * @param {string} path - The path to the JSON file. + * @returns {Object} The parsed JSON object. + */ +const getJson = (path) => { + try { + const file = fs.readFileSync(path); + return JSON.parse(file); + } catch (error) { + console.error(error); + } +} + +/** + * Generates the name of the Docker Compose file based on the environment configuration. + * @param {*} mode - Generates the specified version. + * @returns The fully formed filename for the compose file. + */ +const getComposeFilename = (mode = "") => { + + let filename = 'docker-compose'; + + switch (mode) { + case constants.dev: + filename = `${filename}.${constants.dev}`; + break; + case constants.test: + filename = `${filename}.${constants.test}`; + break; + case constants.analysis: + filename = `${filename}.${constants.analysis}`; + break; + default: + break; + } + + return `${filename}.${constants.yml}`; +} + +/** + * Generates the filename of the NGINX configuration file based on the environment configuration. + * @param {*} mode - Generates the specified version. + * @returns {string} The filename of the NGINX configuration file. + */ +const getNginxFilename = (mode = "") => { + + let filename = 'nginx'; + +console.log("MDOE", mode) + + switch (mode) { + case constants.dev: + case constants.analysis: + filename = `${filename}.${constants.dev}`; + break; + + default: + break; + } + + return `${filename}.${constants.conf}`; + +} + +module.exports = { + has, + get, + getAll, + run, + args, + getConfig, + getServicesConfig, + getComposeFilename, + getNginxFilename +}; \ No newline at end of file diff --git a/docker/scripts/helpers.compose.js b/docker/scripts/helpers.compose.js new file mode 100644 index 00000000..8e5e6e1c --- /dev/null +++ b/docker/scripts/helpers.compose.js @@ -0,0 +1,297 @@ +const chalk = require('chalk'); +const fs = require('fs'); +const yaml = require('js-yaml'); +const constants = require('./constants.common'); + +/** + * Gets the base compose definition. + * @param {*} obj - The compose object. + * @returns - The full compose object with the version defined. + */ +const compose = (obj = {}) => { + const compose = { + version: "3.9", + ...obj + } + return compose; +} + +/** + * Gets the development node service definition. +* @param {*} dir - The application directory to build the dev server against. + * @returns - The node service definition. + */ +const getNodeDev = ({name, ports, networks, image}) => ({ + service: { + image: image, + environment: ['dir=${DIR:-home}'], + ports: ports, + volumes: [ + './config.json:/usr/src/app/config.json', + './babel.config.json:/usr/src/app/babel.config.json', + './setupTests.js:/usr/src/app/setupTests.js', + './app:/usr/src/app/app', + './docs:/usr/src/app/docs', + './build:/usr/src/app/build', + ], + container_name: name, + networks: networks, + mem_limit: '500M', + cpus: 0.2 + }, + config: ` + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-NginX-Proxy true; + proxy_pass http://node:8080; + proxy_ssl_session_reuse off; + proxy_set_header Host $http_host; + proxy_cache_bypass $http_upgrade; + proxy_redirect off; + add_header Set-Cookie fs_portfolio_deployment_target=cloud; + } + ` +}) + +/** + * Gets the base version of Nginx service definition. + * @returns The development service definition. + */ +const getNginxBase = ({name, ports, networks, image}) => ({ + image: image, + ports: ports, + container_name: name, + networks: networks, + mem_limit: '500M', + cpus: 0.2 +}) + +/** + * Gets the development version of Nginx service definition. + * @returns The development service definition. + */ +const getNginxDev = (service) => ({ + ...getNginxBase(service), + volumes: [ + './nginx.dev.conf:/etc/nginx/conf.d/default.conf' + ] +}) + +/** + * Gets the production version of Nginx service definition. + * @returns The development service definition. + */ +const getNginxProd = (service) => ({ + ...getNginxBase(service), + ['x-aws-pull_credentials']: 'arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX' +}) + +/** + * The development version of a .NET service definition. + * @param {*} - The deconstructed service object. + * @returns - The development service definition. + */ +const getDevDotNetService = (service) => { + const {name} = service; + const base = getServiceBase({...service, image: 'fabiosereno/portfolio.dotnet.dev:0.0.1'}); + const _service = { + ...base.service, + volumes: [`./app/app_${name}/backend/api:/usr/src/app/app/app_${name}/backend/api`, + './backend/Portfolio.Core:/usr/src/app/backend/Portfolio.Core', + ], + command: `sh -c "dotnet build /usr/src/app/app/app_${name}/backend/api && dotnet /usr/src/app/app/app_${name}/backend/api/bin/Debug/net7.0/api.dll"`, + } + return { + service: _service, + config: base.config + } +} + +/** + * The development version of a NodeJS service definition. + * @param {*} - The deconstructed service object. + * @returns - The development service definition. + */ +const getDevNodeService = (service) => { + const {name} = service; + const base = getServiceBase({...service, image: 'fabiosereno/portfolio.node.dev:0.0.1'}); + const _service = { + ...base.service, + volumes: [`./app/app_${name}/backend/api:/usr/src/app/app/app_${name}/backend/api`, + ], + command: `sh -c "node /usr/src/app/app/app_nodeToDo/backend/api/index.js"`, + } + return { + service: _service, + config: base.config + } +} + + +/** + * The production version of the .NET service definition. + * @param {*} - The deconstructed service object. + * @returns - The development service definition. + */ +const getServiceProd = (service) => { + const base = getServiceBase(service); + const _service = { + ...base.service, + ['x-aws-pull_credentials']: 'arn:aws:secretsmanager:eu-west-2:523190279095:secret:dockerhubAccessToken-1JuRZX' + } + return { + service: _service, + config: base.config + } +} + +/** + * The base service definition. + * @param {*} - The deconstructed service object. + * @returns - The development service definition. + */ +const getServiceBase = ({name, ports, networks, dependsOn, image}) => { + const [port] = ports[0].split(':'); + return { + service: { + image: image, + container_name: name, + networks: networks, + ports: ports, + mem_limit: '500M', + cpus: 0.2, + ...getDependsOn(dependsOn) + }, + config:` + location /backend/${name}/ { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-NginX-Proxy true; + proxy_pass http://${name}:${port}/; + proxy_ssl_session_reuse off; + proxy_set_header Host $http_host; + proxy_cache_bypass $http_upgrade; + proxy_redirect off; + } + ` + } +} + +/** + * Gets the development version of a service. + * @param {*} service - The service object. + * @param {*} isDev - Determines to get the development version or poduction version. + * @returns - The necessary service definition. + */ +const getService = (service, isDev) => { + + if (service === undefined) { + throw new Error("argument missing for parameter - service"); + } + + switch (service.type) { + case constants.DOT_NET: + return isDev ? getDevDotNetService(service) : getServiceProd(service); + case constants.NGINX: + return isDev ? getNginxDev(service) : getNginxProd(service); + case constants.NODE: + return isDev ? getDevNodeService(service) : getServiceProd(service); + default: + break; + } +} + +/** + * Builds the depends_on definition. + * @param {*} dependsOn - The array of dependants. + * @returns - The fully formed depends on object. + */ +const getDependsOn = (dependsOn = []) => ({ + depends_on: [...dependsOn] +}) + +/** + * Gets the openning statement for the Nginx config file. + * @returns - A string array, with the openning statement for the Nginx config file. + */ +const getNginxConfOpen = () => { + return [` + server { + listen 80; + server_name frontend; + `] +} + +/** + * Gets the ending statement for the Nginx config file. + * @returns - The config file, followed by the ending statement. + */ +const getNginxConfClose = (existingConfig = []) => existingConfig.push('}') + +/** + * Gets the production root definition for the nginx service. + * @returns - The production root definition for the nginx service. + */ +const getNginxProdRoot =() => { + return ` + location / { + root /usr/share/nginx/html; + index index.html index.htm; + add_header Set-Cookie fs_portfolio_deployment_target=cloud; + } + ` +} + +/** + * Adds the new config to the existing Nginx config array. + * @param {*} existingConfig - The config to append to. + * @param {*} newConfig - The new config to add. + * @returns - The concatenated config. + */ +const appendNginxConfig = (existingConfig = [], newConfig = '') => existingConfig.push(newConfig) + +/** + * Creates the Nginx config file at the root of the project. + * @param {*} config - The config to create. + * @param {*} filename - The filename for the config file. + */ +const createNginxConfig = (config = [], filename = '') => { + try { + const path = `./${filename}`; + fs.writeFileSync(path, config.join("")); + console.log(chalk.green(`Nginx config file created at:`), chalk.yellow(`${path}`)); + } catch (error) { + console.error(`Error creating the Nginx config file at: ${filename}`, error); + } +} + +/** + * Creates the yaml file and writes it to disk. + * @param {*} config - The config for the dump method. + * @param {*} filePath - The file path to write the file to. + */ +const createYaml = (config, filePath) => { + try { + const yamlString = yaml.dump(config, { indent: 2 }); + + fs.writeFileSync(filePath, yamlString); + + console.log(chalk.green(`Docker Compose file created at:`), chalk.yellow(`${filePath}`)); + } catch (error) { + console.error(`Error creating the Docker Compose file at: ${filePath} `, error); + } +} + +module.exports = { + getNodeDev, + compose, + createYaml, + getService, + getDependsOn, + getNginxConfOpen, + getNginxConfClose, + appendNginxConfig, + createNginxConfig, + getNginxProdRoot +} \ No newline at end of file diff --git a/docker/scripts/image.js b/docker/scripts/image.js new file mode 100644 index 00000000..094af4b6 --- /dev/null +++ b/docker/scripts/image.js @@ -0,0 +1,10 @@ +const handlers = require('./handlers.common'); +const imageHandlers = require('./handlers.image'); +const verbs = require('./verbs.image'); +const constants = require('./constants.image'); + +handlers.ifHasUnsupported(verbs.supported); +handlers.ifHasHelp(verbs.hasHelp, constants.help); +handlers.validate(verbs.required); +imageHandlers.runIfHasNameAndTag(); +imageHandlers.runIfHasPushAndTag(); \ No newline at end of file diff --git a/docker/scripts/start.js b/docker/scripts/start.js new file mode 100644 index 00000000..c54ec661 --- /dev/null +++ b/docker/scripts/start.js @@ -0,0 +1,8 @@ +const handlers = require('./handlers.common'); +const appsHandlers = require('./handlers.apps'); +const verbs = require('./verbs.apps'); +const constants = require('./constants.apps'); + +handlers.ifHasUnsupported(verbs.supported); +handlers.ifHasHelp(verbs.hasHelp, constants.help); +appsHandlers.start(); \ No newline at end of file diff --git a/docker/scripts/stop.js b/docker/scripts/stop.js new file mode 100644 index 00000000..49f4056d --- /dev/null +++ b/docker/scripts/stop.js @@ -0,0 +1,8 @@ +const handlers = require('./handlers.common'); +const appsHandlers = require('./handlers.apps'); +const verbs = require('./verbs.apps'); +const constants = require('./constants.apps'); + +handlers.ifHasUnsupported(verbs.supported); +handlers.ifHasHelp(verbs.hasHelp, constants.help); +appsHandlers.stop(); \ No newline at end of file diff --git a/docker/scripts/verbs.apps.js b/docker/scripts/verbs.apps.js new file mode 100644 index 00000000..a7016f72 --- /dev/null +++ b/docker/scripts/verbs.apps.js @@ -0,0 +1,33 @@ +const constants = require('./constants.apps'); +const constantsCommon = require('./constants.common'); +const helpers = require('./helpers.common'); + +const hasDev = helpers.get(constants.MODE) === constantsCommon.dev; +const hasAnalysis = helpers.get(constants.MODE) === constantsCommon.analysis; +const hasProd = !hasDev && !hasAnalysis; +const hasName = helpers.has(constants.NAME); +const hasContext = helpers.has(constants.CONTEXT); +const hasHelp = helpers.has(constants.HELP); +const hasTest = helpers.has(constants.TEST); +const supported = [ + constants.NAME, + constants.CONTEXT, + constants.HELP, + constants.TEST, + constants.REMOVE, + constants.MODE +]; + +const ephemeral = [constants.TEST, constants.REMOVE]; + +module.exports = { + hasProd, + hasDev, + hasName, + hasContext, + hasHelp, + hasAnalysis, + hasTest, + supported, + ephemeral +}; \ No newline at end of file diff --git a/docker/scripts/verbs.compose.js b/docker/scripts/verbs.compose.js new file mode 100644 index 00000000..7ef3dd84 --- /dev/null +++ b/docker/scripts/verbs.compose.js @@ -0,0 +1,26 @@ +const constants = require('./constants.compose'); +const constantsCommon = require('./constants.common'); +const helpers = require('./helpers.common'); + +const hasDev = helpers.get(constants.MODE) === constantsCommon.dev; +const hasAnalysis = helpers.get(constants.MODE) === constantsCommon.analysis; +const hasProd = !hasDev && !hasAnalysis; +const hasName = helpers.has(constants.NAME); +const hasInclude = helpers.has(constants.INCLUDE); +const hasHelp = helpers.has(constants.HELP); +const supported = [ + constants.NAME, + constants.INCLUDE, + constants.HELP, + constants.MODE +]; + +module.exports = { + hasProd, + hasDev, + hasAnalysis, + hasName, + hasInclude, + hasHelp, + supported +}; \ No newline at end of file diff --git a/docker/scripts/verbs.image.js b/docker/scripts/verbs.image.js new file mode 100644 index 00000000..81b90f09 --- /dev/null +++ b/docker/scripts/verbs.image.js @@ -0,0 +1,21 @@ +const constants = require('./constants.image'); +const constantsCommon = require('./constants.common'); +const helpers = require('./helpers.common'); + +const hasDev = helpers.get(constants.MODE) === constantsCommon.dev; +const hasName = helpers.has(constants.NAME); +const hasTag = helpers.has(constants.TAG); +const hasPush = helpers.has(constants.PUSH); +const hasHelp = helpers.has(constants.HELP); +const supported = [constants.MODE, constants.NAME, constants.HELP, constants.TAG, constants.PUSH] +const required = [constants.TAG] + +module.exports = { + hasDev, + hasName, + hasTag, + hasPush, + hasHelp, + supported, + required +}; \ No newline at end of file diff --git a/docker/stringSort/start b/docker/stringSort/start deleted file mode 100644 index 1d1f2f76..00000000 --- a/docker/stringSort/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose up \ No newline at end of file diff --git a/docker/stringSort/stop b/docker/stringSort/stop deleted file mode 100644 index a986179d..00000000 --- a/docker/stringSort/stop +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose down \ No newline at end of file diff --git a/docker/test-dotnet/docker-compose.yml b/docker/test-dotnet/docker-compose.yml new file mode 100644 index 00000000..99383c96 --- /dev/null +++ b/docker/test-dotnet/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3.9' + +services: + test-dotnet: + image: 'fabiosereno/portfolio.dotnet.dev:0.0.1' + volumes: + - '../../app/app_${DIR}/backend/api:/usr/src/app/app/app_${DIR}/backend/api' + - '../../app/app_${DIR}/backend/test:/usr/src/app/app/app_${DIR}/backend/test' + - '../../backend/Portfolio.Core:/usr/src/app/backend/Portfolio.Core' + container_name: test-dotnet + command: sh -c "dotnet build /usr/src/app/app/app_${DIR}/backend/test && dotnet test /usr/src/app/app/app_${DIR}/backend/test/test.csproj" + mem_limit: 500M + cpus: 0.2 \ No newline at end of file diff --git a/docker/test-e2e/start b/docker/test-e2e/start deleted file mode 100644 index 2d00e1c6..00000000 --- a/docker/test-e2e/start +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -# Test docker compose up script - -docker compose up \ No newline at end of file diff --git a/docker/test-e2e/stop b/docker/test-e2e/stop deleted file mode 100644 index df23319f..00000000 --- a/docker/test-e2e/stop +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -# Test docker compose down script - -docker compose down \ No newline at end of file diff --git a/docker/test/Dockerfile b/docker/test/Dockerfile index a03b91cb..78833851 100644 --- a/docker/test/Dockerfile +++ b/docker/test/Dockerfile @@ -1,6 +1,3 @@ FROM fabiosereno/portfolio.npm:0.0.1 -HEALTHCHECK --interval=12s --timeout=12s --start-period=30s \ - CMD node healthcheck.js - CMD ["sh", "-c", "npm run test"] \ No newline at end of file diff --git a/docker/test/docker-compose.yml b/docker/test/docker-compose.yml index 6b232390..c81d9517 100644 --- a/docker/test/docker-compose.yml +++ b/docker/test/docker-compose.yml @@ -1,8 +1,7 @@ version: '3.9' services: - node: - tty: true + test: image: 'fabiosereno/portfolio.test:0.0.2' volumes: - '../../config.json:/usr/src/app/config.json' @@ -11,4 +10,4 @@ services: - '../../app:/usr/src/app/app' - '../../docs:/usr/src/app/docs' - '../../build:/usr/src/app/build' - container_name: node + container_name: test diff --git a/docker/test/start b/docker/test/start deleted file mode 100644 index 8f3c2e2b..00000000 --- a/docker/test/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker-compose run --rm node \ No newline at end of file diff --git a/docker/uniqueDataEntry/start b/docker/uniqueDataEntry/start deleted file mode 100644 index 1d1f2f76..00000000 --- a/docker/uniqueDataEntry/start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose up \ No newline at end of file diff --git a/docker/uniqueDataEntry/stop b/docker/uniqueDataEntry/stop deleted file mode 100644 index a986179d..00000000 --- a/docker/uniqueDataEntry/stop +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -docker compose down \ No newline at end of file diff --git a/docs/app_coffeeMachine/main.js b/docs/app_coffeeMachine/main.js index 4df98b64..9256ea36 100644 --- a/docs/app_coffeeMachine/main.js +++ b/docs/app_coffeeMachine/main.js @@ -1 +1 @@ -(()=>{"use strict";var e,t={994:(e,t,a)=>{var n=a(294),r=a(935);function o(e){var t=e.show?"":"d-none";return n.createElement("div",null,n.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),n.createElement("div",{id:"loader",className:"".concat(t," item loading")},n.createElement("div",{className:"spinner"},n.createElement("div",{className:"circle circle-1"},n.createElement("div",{className:"circle-inner"})),n.createElement("div",{className:"circle circle-2"},n.createElement("div",{className:"circle-inner"})))))}var i=a(492),l=a(754);function c(e){return n.createElement(i.Z,{id:e.id,show:e.show,onHide:e.handleClose},n.createElement(i.Z.Header,null,n.createElement(i.Z.Title,{className:"display-4"},e.title),n.createElement(l.Z,{variant:"link",className:"close",onClick:e.handleClose},n.createElement("span",{className:"lr"},n.createElement("span",{className:"rl"})))),n.createElement(i.Z.Body,null,n.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),n.createElement(i.Z.Footer,null,n.createElement(l.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function s(e){return n.createElement(c,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}function u(e,t){for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25,a=void 0!==e?e.substring(0,t).split(" ").join(""):"";return a}}],null&&u(t.prototype,null),a&&u(t,a),e}();function p(e){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function f(e,t){for(var a=0;a0?n.createElement("h3",{className:"mb-4"},"Log of tasks carried out"):null}},{key:"render",value:function(){return n.createElement(n.Fragment,null,n.createElement("div",{className:"row mb-3"},n.createElement("div",{className:"col-lg-6"},n.createElement("button",{id:"runSync",type:"button",className:"btn btn-dark mr-2",onClick:this.props.handleRun},"Run Sync"),n.createElement("button",{id:"runAsync",type:"button",className:"btn btn-dark mr-2",onClick:this.props.handleRunAsync},"Run Async"))),n.createElement("div",{className:"row"},n.createElement("div",{className:"col-lg-6"},n.createElement("p",{className:"text-muted"},"(Processing is delayed for this demonstration)"),n.createElement(this.renderProcessHeading,null),n.createElement("ul",{id:"resultOutput",className:"list-group"},this.props.log.map((function(e,t){var a=d.generate(e.detail);return n.createElement("li",{key:a,className:"list-group-item d-flex align-items-center"},n.createElement("span",{className:"badge badge-primary badge-pill mr-3 bg-dark"},t+1),e.detail)}))))))}}])&&f(t.prototype,a),l}(n.Component);const S=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"nginx","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"}},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function g(e,t){for(var a=0;a0?t[0]:S}}],null&&g(t.prototype,null),a&&g(t,a),e}(),w=a(755);function C(e,t){for(var a=0;a{if(!a){var i=1/0;for(u=0;u=o)&&Object.keys(n.O).every((e=>n.O[e](a[c])))?a.splice(c--,1):(l=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[a,r,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,a)=>{var r,o,[i,l,c]=a,s=0;for(r in l)n.o(l,r)&&(n.m[r]=l[r]);if(c)var u=c(n);for(t&&t(a);sn(994)));r=n.O(r)})(); \ No newline at end of file +(()=>{"use strict";var e,t={994:(e,t,a)=>{var n=a(294),r=a(935);function o(e){var t=e.show?"":"d-none";return n.createElement("div",null,n.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),n.createElement("div",{id:"loader",className:"".concat(t," item loading")},n.createElement("div",{className:"spinner"},n.createElement("div",{className:"circle circle-1"},n.createElement("div",{className:"circle-inner"})),n.createElement("div",{className:"circle circle-2"},n.createElement("div",{className:"circle-inner"})))))}var i=a(492),l=a(754);function c(e){return n.createElement(i.Z,{id:e.id,show:e.show,onHide:e.handleClose},n.createElement(i.Z.Header,null,n.createElement(i.Z.Title,{className:"display-4"},e.title),n.createElement(l.Z,{variant:"link",className:"close",onClick:e.handleClose},n.createElement("span",{className:"lr"},n.createElement("span",{className:"rl"})))),n.createElement(i.Z.Body,null,n.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),n.createElement(i.Z.Footer,null,n.createElement(l.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function s(e){return n.createElement(c,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}function u(e,t){for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25,a=void 0!==e?e.substring(0,t).split(" ").join(""):"";return a}}],null&&u(t.prototype,null),a&&u(t,a),e}();function p(e){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function f(e,t){for(var a=0;a0?n.createElement("h3",{className:"mb-4"},"Log of tasks carried out"):null}},{key:"render",value:function(){return n.createElement(n.Fragment,null,n.createElement("div",{className:"row mb-3"},n.createElement("div",{className:"col-lg-6"},n.createElement("button",{id:"runSync",type:"button",className:"btn btn-dark mr-2",onClick:this.props.handleRun},"Run Sync"),n.createElement("button",{id:"runAsync",type:"button",className:"btn btn-dark mr-2",onClick:this.props.handleRunAsync},"Run Async"))),n.createElement("div",{className:"row"},n.createElement("div",{className:"col-lg-6"},n.createElement("p",{className:"text-muted"},"(Processing is delayed for this demonstration)"),n.createElement(this.renderProcessHeading,null),n.createElement("ul",{id:"resultOutput",className:"list-group"},this.props.log.map((function(e,t){var a=d.generate(e.detail);return n.createElement("li",{key:a,className:"list-group-item d-flex align-items-center"},n.createElement("span",{className:"badge badge-primary badge-pill mr-3 bg-dark"},t+1),e.detail)}))))))}}])&&f(t.prototype,a),l}(n.Component);const S=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"localhost","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["uniqueDataEntry"]},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["dataStructures"]},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["entitySort"]},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["stringSort"]},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3,"services":["coffeeMachine"]},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"},"services":["nodeToDo"]},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function g(e,t){for(var a=0;a0?t[0]:S}}],null&&g(t.prototype,null),a&&g(t,a),e}(),w=a(755);function E(e,t){for(var a=0;a{if(!a){var i=1/0;for(u=0;u=o)&&Object.keys(n.O).every((e=>n.O[e](a[c])))?a.splice(c--,1):(l=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[a,r,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,a)=>{var r,o,[i,l,c]=a,s=0;for(r in l)n.o(l,r)&&(n.m[r]=l[r]);if(c)var u=c(n);for(t&&t(a);sn(994)));r=n.O(r)})(); \ No newline at end of file diff --git a/docs/app_dataStructures/main.js b/docs/app_dataStructures/main.js index 73d9ab5d..f8f746d7 100644 --- a/docs/app_dataStructures/main.js +++ b/docs/app_dataStructures/main.js @@ -1 +1 @@ -(()=>{"use strict";var e,t={759:(e,t,a)=>{var n=a(294),r=a(935),o=a(555),l=a(51);function i(e){var t=e.show?"":"d-none";return n.createElement("div",null,n.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),n.createElement("div",{id:"loader",className:"".concat(t," item loading")},n.createElement("div",{className:"spinner"},n.createElement("div",{className:"circle circle-1"},n.createElement("div",{className:"circle-inner"})),n.createElement("div",{className:"circle circle-2"},n.createElement("div",{className:"circle-inner"})))))}var c=a(625),s=a(754);function u(e){return n.createElement(c.Z,{id:e.id,show:e.show,onHide:e.handleClose},n.createElement(c.Z.Header,null,n.createElement(c.Z.Title,{className:"display-4"},e.title),n.createElement(s.Z,{variant:"link",className:"close",onClick:e.handleClose},n.createElement("span",{className:"lr"},n.createElement("span",{className:"rl"})))),n.createElement(c.Z.Body,null,n.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),n.createElement(c.Z.Footer,null,n.createElement(s.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function d(e){return n.createElement(u,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}const p=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"nginx","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"}},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function m(e,t){for(var a=0;a0?t[0]:p}}],null&&m(t.prototype,null),a&&m(t,a),e}(),h=a(151);function b(e,t){for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25,a=void 0!==e?e.substring(0,t).split(" ").join(""):"";return a}}],null&&b(t.prototype,null),a&&b(t,a),e}();function S(e,t){for(var a=0;ae.length)&&(t=e.length);for(var a=0,n=new Array(t);a{if(!a){var l=1/0;for(u=0;u=o)&&Object.keys(n.O).every((e=>n.O[e](a[c])))?a.splice(c--,1):(i=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[a,r,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,a)=>{var r,o,[l,i,c]=a,s=0;for(r in i)n.o(i,r)&&(n.m[r]=i[r]);if(c)var u=c(n);for(t&&t(a);sn(759)));r=n.O(r)})(); \ No newline at end of file +(()=>{"use strict";var e,t={759:(e,t,a)=>{var n=a(294),r=a(935),o=a(555),l=a(51);function i(e){var t=e.show?"":"d-none";return n.createElement("div",null,n.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),n.createElement("div",{id:"loader",className:"".concat(t," item loading")},n.createElement("div",{className:"spinner"},n.createElement("div",{className:"circle circle-1"},n.createElement("div",{className:"circle-inner"})),n.createElement("div",{className:"circle circle-2"},n.createElement("div",{className:"circle-inner"})))))}var c=a(625),s=a(754);function u(e){return n.createElement(c.Z,{id:e.id,show:e.show,onHide:e.handleClose},n.createElement(c.Z.Header,null,n.createElement(c.Z.Title,{className:"display-4"},e.title),n.createElement(s.Z,{variant:"link",className:"close",onClick:e.handleClose},n.createElement("span",{className:"lr"},n.createElement("span",{className:"rl"})))),n.createElement(c.Z.Body,null,n.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),n.createElement(c.Z.Footer,null,n.createElement(s.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function d(e){return n.createElement(u,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}const p=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"localhost","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["uniqueDataEntry"]},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["dataStructures"]},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["entitySort"]},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["stringSort"]},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3,"services":["coffeeMachine"]},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"},"services":["nodeToDo"]},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function m(e,t){for(var a=0;a0?t[0]:p}}],null&&m(t.prototype,null),a&&m(t,a),e}(),h=a(151);function b(e,t){for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25,a=void 0!==e?e.substring(0,t).split(" ").join(""):"";return a}}],null&&b(t.prototype,null),a&&b(t,a),e}();function S(e,t){for(var a=0;ae.length)&&(t=e.length);for(var a=0,n=new Array(t);a{if(!a){var l=1/0;for(u=0;u=o)&&Object.keys(n.O).every((e=>n.O[e](a[c])))?a.splice(c--,1):(i=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[a,r,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,a)=>{var r,o,[l,i,c]=a,s=0;for(r in i)n.o(i,r)&&(n.m[r]=i[r]);if(c)var u=c(n);for(t&&t(a);sn(759)));r=n.O(r)})(); \ No newline at end of file diff --git a/docs/app_entitySort/main.js b/docs/app_entitySort/main.js index 68d7f259..28acdc5a 100644 --- a/docs/app_entitySort/main.js +++ b/docs/app_entitySort/main.js @@ -1 +1 @@ -(()=>{"use strict";var e,t={412:(e,t,a)=>{var n=a(294),r=a(935);function l(e,t){for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25,a=void 0!==e?e.substring(0,t).split(" ").join(""):"";return a}}],null&&l(t.prototype,null),a&&l(t,a),e}();function i(e){var t=e.show?"":"d-none";return n.createElement("div",null,n.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),n.createElement("div",{id:"loader",className:"".concat(t," item loading")},n.createElement("div",{className:"spinner"},n.createElement("div",{className:"circle circle-1"},n.createElement("div",{className:"circle-inner"})),n.createElement("div",{className:"circle circle-2"},n.createElement("div",{className:"circle-inner"})))))}var c=a(625),s=a(754);function u(e){return n.createElement(c.Z,{id:e.id,show:e.show,onHide:e.handleClose},n.createElement(c.Z.Header,null,n.createElement(c.Z.Title,{className:"display-4"},e.title),n.createElement(s.Z,{variant:"link",className:"close",onClick:e.handleClose},n.createElement("span",{className:"lr"},n.createElement("span",{className:"rl"})))),n.createElement(c.Z.Body,null,n.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),n.createElement(c.Z.Footer,null,n.createElement(s.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function d(e){return n.createElement(u,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}const m=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"nginx","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"}},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function p(e,t){for(var a=0;a0?t[0]:m}}],null&&p(t.prototype,null),a&&p(t,a),e}(),h=a(151),y=a(555),b=a(318);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var a=0,n=new Array(t);ae.length)&&(t=e.length);for(var a=0,n=new Array(t);a{if(!a){var o=1/0;for(u=0;u=l)&&Object.keys(n.O).every((e=>n.O[e](a[c])))?a.splice(c--,1):(i=!1,l0&&e[u-1][2]>l;u--)e[u]=e[u-1];e[u]=[a,r,l]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,a)=>{var r,l,[o,i,c]=a,s=0;for(r in i)n.o(i,r)&&(n.m[r]=i[r]);if(c)var u=c(n);for(t&&t(a);sn(412)));r=n.O(r)})(); \ No newline at end of file +(()=>{"use strict";var e,t={412:(e,t,a)=>{var n=a(294),r=a(935);function l(e,t){for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25,a=void 0!==e?e.substring(0,t).split(" ").join(""):"";return a}}],null&&l(t.prototype,null),a&&l(t,a),e}();function i(e){var t=e.show?"":"d-none";return n.createElement("div",null,n.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),n.createElement("div",{id:"loader",className:"".concat(t," item loading")},n.createElement("div",{className:"spinner"},n.createElement("div",{className:"circle circle-1"},n.createElement("div",{className:"circle-inner"})),n.createElement("div",{className:"circle circle-2"},n.createElement("div",{className:"circle-inner"})))))}var c=a(625),s=a(754);function u(e){return n.createElement(c.Z,{id:e.id,show:e.show,onHide:e.handleClose},n.createElement(c.Z.Header,null,n.createElement(c.Z.Title,{className:"display-4"},e.title),n.createElement(s.Z,{variant:"link",className:"close",onClick:e.handleClose},n.createElement("span",{className:"lr"},n.createElement("span",{className:"rl"})))),n.createElement(c.Z.Body,null,n.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),n.createElement(c.Z.Footer,null,n.createElement(s.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function d(e){return n.createElement(u,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}const m=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"localhost","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["uniqueDataEntry"]},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["dataStructures"]},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["entitySort"]},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["stringSort"]},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3,"services":["coffeeMachine"]},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"},"services":["nodeToDo"]},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function p(e,t){for(var a=0;a0?t[0]:m}}],null&&p(t.prototype,null),a&&p(t,a),e}(),h=a(151),y=a(555),b=a(318);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var a=0,n=new Array(t);ae.length)&&(t=e.length);for(var a=0,n=new Array(t);a{if(!a){var o=1/0;for(u=0;u=l)&&Object.keys(n.O).every((e=>n.O[e](a[c])))?a.splice(c--,1):(i=!1,l0&&e[u-1][2]>l;u--)e[u]=e[u-1];e[u]=[a,r,l]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,a)=>{var r,l,[o,i,c]=a,s=0;for(r in i)n.o(i,r)&&(n.m[r]=i[r]);if(c)var u=c(n);for(t&&t(a);sn(412)));r=n.O(r)})(); \ No newline at end of file diff --git a/docs/app_nodeToDo/main.js b/docs/app_nodeToDo/main.js index fa679347..0ba6e87d 100644 --- a/docs/app_nodeToDo/main.js +++ b/docs/app_nodeToDo/main.js @@ -1 +1 @@ -(()=>{"use strict";var e,t={1567:(e,t,r)=>{r(5666);var n=r(7294),a=r(3935),o=r(3727),i=r(5977),l=r(103),c=r(8791),u={description:"",done:!1,modifiedOn:0,createdOn:0},s={show:!0,text:"Hide",class:"bi-dash-square"},m={show:!1,text:"Show",class:"bi-plus-square"},f="hide",d="show",p="copy",y="description",h="/register",v="/login",b="/manage",g="/edit",S="/logout",E="Sorry, there was an error. Please try again.",w=r(682);function k(e){var t=e.children;return n.createElement(w.Z,{fluid:!0,className:"py-4"},t)}function C(e){var t=e.title,r=e.content,a=e.centre;return n.createElement(n.Fragment,null,n.createElement("h1",{className:"".concat(a?"text-center":"")},t),n.createElement("p",null,r))}var A=r(1555),T=r(5005),O=r(2151),I=n.createContext(),x=n.createContext(),R=n.createContext();function j(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);rt.modifiedOn?-1:0},ee=r(3068),te=function(e){var t=e.item;return n.createElement(n.Fragment,null,t.done&&n.createElement(n.Fragment,null,n.createElement("input",{type:"checkbox",checked:!0,disabled:!0}),n.createElement("p",{className:"lead flex-fill ml-3 my-0"},n.createElement("del",null,t.description))))};function re(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r0&&n.createElement(Z.Z,{className:"justify-content-md-center mt-3 ".concat(a?"d-none":"")},n.createElement(A.Z,{lg:10},n.createElement("h4",null,r,n.createElement("a",{className:"float-right text-dark",href:"#",onClick:o},i.text,n.createElement("i",{className:"bi ".concat(i.class," mx-2")}))),n.createElement("hr",{className:"border-dark"}),i.show&&n.createElement("div",{className:"list-group"},t.map((function(e){return n.createElement(ae,{key:e.id,item:e})}))))))};function ie(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,a,o=[],i=!0,l=!1;try{for(r=r.call(e);!(i=(n=r.next()).done)&&(o.push(n.value),!t||o.length!==t);i=!0);}catch(e){l=!0,a=e}finally{try{i||null==r.return||r.return()}finally{if(l)throw a}}return o}}(e,t)||function(e,t){if(e){if("string"==typeof e)return le(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?le(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function le(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);r0)}),[l.state.items]),n.createElement("div",{className:"toasts-container","aria-live":"polite","aria-atomic":"true",style:{visibility:t?"visible":"hidden"}},n.createElement("div",{className:"toasts-position"},n.createElement(Ae,{items:o})))}function Oe(e){var t=e.children,r=de((0,n.useReducer)(Ce,{items:[]}),2),a={state:r[0],dispatch:r[1]};return n.createElement(n.Fragment,null,n.createElement(ke.Provider,{value:a},t,n.createElement(Te,null)))}function Ie(e){var t=n.useContext(ke);return(0,n.useEffect)((function(){setTimeout((function(){t.dispatch({type:Ee})}),5e3)}),[]),n.createElement(n.Fragment,null,n.createElement("div",{className:"toast",role:"alert","aria-live":"assertive","aria-atomic":"true",style:{opacity:1}},n.createElement("div",{className:"toast-header"},n.createElement("strong",{className:"mr-auto text-dark lead"},e.item.heading),n.createElement("a",{href:"#",onClick:function(r){return r.preventDefault()&t.dispatch({type:we,index:e.index})},className:"text-dark h3 mb-0"},n.createElement("i",{className:"bi bi-x"}))),n.createElement("div",{className:"toast-body"},e.item.body)))}var xe=r(7975),Re=r(3489);function je(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);r0&&void 0!==arguments[0]?arguments[0]:E,r=De(f);-1===r.indexOf(e)&&r.push(e),d(r),s(!0),t.setShow(!1)}(e.message)}))):e.handleDeploymentModalShow():(l(!0),n.stopPropagation())}},n.createElement(O.Z.Row,null,n.createElement(O.Z.Group,{as:A.Z},n.createElement(O.Z.Label,null,"Username ",n.createElement(Ne,{message:"This is case insensitive"})),n.createElement(O.Z.Control,{name:"username",id:"username",type:"text",onChange:function(e){return h(e.target.value)},required:!0}),n.createElement(O.Z.Control.Feedback,{type:"invalid"},"Please enter a valid value"))),n.createElement(O.Z.Row,null,n.createElement(O.Z.Group,{as:A.Z},n.createElement(O.Z.Label,null,"Password ",n.createElement(Ne,{message:"Alphanumeric and case sensitive. Use a special character!"})),n.createElement(O.Z.Control,{name:"password",id:"password",type:"password",onChange:function(e){return S(e.target.value)},required:!0}),n.createElement(O.Z.Control.Feedback,{type:"invalid"},"Please enter a valid value"))),n.createElement(O.Z.Row,null,n.createElement(O.Z.Group,{as:A.Z},n.createElement(T.Z,{className:"float-right",id:"submit",variant:"dark",type:"submit"},"Register"))),n.createElement(O.Z.Row,null,n.createElement(O.Z.Group,{as:A.Z},u&&n.createElement(n.Fragment,null,n.createElement("h5",{className:"text-danger"},"There were errors"),n.createElement("ul",{id:"errorFeedback",className:"text-danger"},f.map((function(e,t){return n.createElement("li",{key:t},n.createElement("small",null,e))})))))))))}const Le=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"nginx","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"}},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function He(e,t){for(var r=0;r0?t[0]:Le}}],null&&He(t.prototype,null),r&&He(t,r),e}();function We(e,t){for(var r=0;r0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return 200===e&&4===t}},{key:"isFail",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return 200!==e&&4===t}},{key:"request",value:function(e){var t=this,r=e.type,n=e.request,a=e.payload,o=e.headers;return new Promise((function(e,i){var l=new XMLHttpRequest;if(l.onreadystatechange=function(r){var n=r.currentTarget;if(t.isDone(n.status,n.readyState)){var a;try{a=JSON.parse(n.response)}catch(e){a={}}e({success:!0,data:a})}else t.isFail(n.status,n.readyState)&&i({success:!1,data:n})},l.open(r,n),o.length>0)for(var c=0;ce.length)&&(t=e.length);for(var r=0,n=new Array(t);r0},verify:function(e,t){var r=JSON.stringify({token:s}),n=new XMLHttpRequest;n.onreadystatechange=function(r){var n=r.currentTarget;Je.isDone(n.status,n.readyState)?JSON.parse(n.response).result.success?"function"==typeof e&&e():"function"==typeof t&&t():Je.isFail(n.status,n.readyState)&&"function"==typeof t&&t()},n.open("POST",c),n.setRequestHeader("Content-type","application/json"),n.send(r)},onChange:function(e){return m(e)}};return n.createElement(Be.Provider,{value:d},a)}function _e(){return n.createElement(k,null,n.createElement(C,{title:"Create a user",content:"You must create a user to log in and access the API"}),n.createElement(Ge,null,n.createElement(Me,null)))}function Ve(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);r{if(!r){var i=1/0;for(s=0;s=o)&&Object.keys(n.O).every((e=>n.O[e](r[c])))?r.splice(c--,1):(l=!1,o0&&e[s-1][2]>o;s--)e[s]=e[s-1];e[s]=[r,a,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,[i,l,c]=r,u=0;for(a in l)n.o(l,a)&&(n.m[a]=l[a]);if(c)var s=c(n);for(t&&t(r);un(1567)));a=n.O(a)})(); \ No newline at end of file +(()=>{"use strict";var e,t={1567:(e,t,r)=>{r(5666);var n=r(7294),a=r(3935),o=r(3727),i=r(5977),l=r(103),c=r(8791),u={description:"",done:!1,modifiedOn:0,createdOn:0},s={show:!0,text:"Hide",class:"bi-dash-square"},m={show:!1,text:"Show",class:"bi-plus-square"},f="hide",d="show",p="copy",y="description",h="/register",v="/login",b="/manage",g="/edit",S="/logout",E="Sorry, there was an error. Please try again.",w=r(682);function k(e){var t=e.children;return n.createElement(w.Z,{fluid:!0,className:"py-4"},t)}function C(e){var t=e.title,r=e.content,a=e.centre;return n.createElement(n.Fragment,null,n.createElement("h1",{className:"".concat(a?"text-center":"")},t),n.createElement("p",null,r))}var A=r(1555),T=r(5005),O=r(2151),I=n.createContext(),x=n.createContext(),R=n.createContext();function j(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);rt.modifiedOn?-1:0},ee=r(3068),te=function(e){var t=e.item;return n.createElement(n.Fragment,null,t.done&&n.createElement(n.Fragment,null,n.createElement("input",{type:"checkbox",checked:!0,disabled:!0}),n.createElement("p",{className:"lead flex-fill ml-3 my-0"},n.createElement("del",null,t.description))))};function re(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r0&&n.createElement(Z.Z,{className:"justify-content-md-center mt-3 ".concat(a?"d-none":"")},n.createElement(A.Z,{lg:10},n.createElement("h4",null,r,n.createElement("a",{className:"float-right text-dark",href:"#",onClick:o},i.text,n.createElement("i",{className:"bi ".concat(i.class," mx-2")}))),n.createElement("hr",{className:"border-dark"}),i.show&&n.createElement("div",{className:"list-group"},t.map((function(e){return n.createElement(ae,{key:e.id,item:e})}))))))};function ie(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,a,o=[],i=!0,l=!1;try{for(r=r.call(e);!(i=(n=r.next()).done)&&(o.push(n.value),!t||o.length!==t);i=!0);}catch(e){l=!0,a=e}finally{try{i||null==r.return||r.return()}finally{if(l)throw a}}return o}}(e,t)||function(e,t){if(e){if("string"==typeof e)return le(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?le(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function le(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);r0)}),[l.state.items]),n.createElement("div",{className:"toasts-container","aria-live":"polite","aria-atomic":"true",style:{visibility:t?"visible":"hidden"}},n.createElement("div",{className:"toasts-position"},n.createElement(Ae,{items:o})))}function Oe(e){var t=e.children,r=de((0,n.useReducer)(Ce,{items:[]}),2),a={state:r[0],dispatch:r[1]};return n.createElement(n.Fragment,null,n.createElement(ke.Provider,{value:a},t,n.createElement(Te,null)))}function Ie(e){var t=n.useContext(ke);return(0,n.useEffect)((function(){setTimeout((function(){t.dispatch({type:Ee})}),5e3)}),[]),n.createElement(n.Fragment,null,n.createElement("div",{className:"toast",role:"alert","aria-live":"assertive","aria-atomic":"true",style:{opacity:1}},n.createElement("div",{className:"toast-header"},n.createElement("strong",{className:"mr-auto text-dark lead"},e.item.heading),n.createElement("a",{href:"#",onClick:function(r){return r.preventDefault()&t.dispatch({type:we,index:e.index})},className:"text-dark h3 mb-0"},n.createElement("i",{className:"bi bi-x"}))),n.createElement("div",{className:"toast-body"},e.item.body)))}var xe=r(7975),Re=r(3489);function je(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);r0&&void 0!==arguments[0]?arguments[0]:E,r=Ne(f);-1===r.indexOf(e)&&r.push(e),d(r),s(!0),t.setShow(!1)}(e.message)}))):e.handleDeploymentModalShow():(l(!0),n.stopPropagation())}},n.createElement(O.Z.Row,null,n.createElement(O.Z.Group,{as:A.Z},n.createElement(O.Z.Label,null,"Username ",n.createElement(De,{message:"This is case insensitive"})),n.createElement(O.Z.Control,{name:"username",id:"username",type:"text",onChange:function(e){return h(e.target.value)},required:!0}),n.createElement(O.Z.Control.Feedback,{type:"invalid"},"Please enter a valid value"))),n.createElement(O.Z.Row,null,n.createElement(O.Z.Group,{as:A.Z},n.createElement(O.Z.Label,null,"Password ",n.createElement(De,{message:"Alphanumeric and case sensitive. Use a special character!"})),n.createElement(O.Z.Control,{name:"password",id:"password",type:"password",onChange:function(e){return S(e.target.value)},required:!0}),n.createElement(O.Z.Control.Feedback,{type:"invalid"},"Please enter a valid value"))),n.createElement(O.Z.Row,null,n.createElement(O.Z.Group,{as:A.Z},n.createElement(T.Z,{className:"float-right",id:"submit",variant:"dark",type:"submit"},"Register"))),n.createElement(O.Z.Row,null,n.createElement(O.Z.Group,{as:A.Z},u&&n.createElement(n.Fragment,null,n.createElement("h5",{className:"text-danger"},"There were errors"),n.createElement("ul",{id:"errorFeedback",className:"text-danger"},f.map((function(e,t){return n.createElement("li",{key:t},n.createElement("small",null,e))})))))))))}const Le=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"localhost","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["uniqueDataEntry"]},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["dataStructures"]},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["entitySort"]},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["stringSort"]},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3,"services":["coffeeMachine"]},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"},"services":["nodeToDo"]},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function He(e,t){for(var r=0;r0?t[0]:Le}}],null&&He(t.prototype,null),r&&He(t,r),e}();function We(e,t){for(var r=0;r0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return 200===e&&4===t}},{key:"isFail",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return 200!==e&&4===t}},{key:"request",value:function(e){var t=this,r=e.type,n=e.request,a=e.payload,o=e.headers;return new Promise((function(e,i){var l=new XMLHttpRequest;if(l.onreadystatechange=function(r){var n=r.currentTarget;if(t.isDone(n.status,n.readyState)){var a;try{a=JSON.parse(n.response)}catch(e){a={}}e({success:!0,data:a})}else t.isFail(n.status,n.readyState)&&i({success:!1,data:n})},l.open(r,n),o.length>0)for(var c=0;ce.length)&&(t=e.length);for(var r=0,n=new Array(t);r0},verify:function(e,t){var r=JSON.stringify({token:s}),n=new XMLHttpRequest;n.onreadystatechange=function(r){var n=r.currentTarget;Je.isDone(n.status,n.readyState)?JSON.parse(n.response).result.success?"function"==typeof e&&e():"function"==typeof t&&t():Je.isFail(n.status,n.readyState)&&"function"==typeof t&&t()},n.open("POST",c),n.setRequestHeader("Content-type","application/json"),n.send(r)},onChange:function(e){return m(e)}};return n.createElement(Be.Provider,{value:d},a)}function _e(){return n.createElement(k,null,n.createElement(C,{title:"Create a user",content:"You must create a user to log in and access the API"}),n.createElement(Ge,null,n.createElement(Me,null)))}function Ve(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);re.length)&&(t=e.length);for(var r=0,n=new Array(t);r{if(!r){var i=1/0;for(s=0;s=o)&&Object.keys(n.O).every((e=>n.O[e](r[c])))?r.splice(c--,1):(l=!1,o0&&e[s-1][2]>o;s--)e[s]=e[s-1];e[s]=[r,a,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,[i,l,c]=r,u=0;for(a in l)n.o(l,a)&&(n.m[a]=l[a]);if(c)var s=c(n);for(t&&t(r);un(1567)));a=n.O(a)})(); \ No newline at end of file diff --git a/docs/app_stringSort/main.js b/docs/app_stringSort/main.js index fe218384..73871b67 100644 --- a/docs/app_stringSort/main.js +++ b/docs/app_stringSort/main.js @@ -1 +1 @@ -(()=>{"use strict";var e,t={729:(e,t,a)=>{var r=a(294),n=a(935);function o(e){var t=e.show?"":"d-none";return r.createElement("div",null,r.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),r.createElement("div",{id:"loader",className:"".concat(t," item loading")},r.createElement("div",{className:"spinner"},r.createElement("div",{className:"circle circle-1"},r.createElement("div",{className:"circle-inner"})),r.createElement("div",{className:"circle circle-2"},r.createElement("div",{className:"circle-inner"})))))}var l=a(625),i=a(754);function c(e){return r.createElement(l.Z,{id:e.id,show:e.show,onHide:e.handleClose},r.createElement(l.Z.Header,null,r.createElement(l.Z.Title,{className:"display-4"},e.title),r.createElement(i.Z,{variant:"link",className:"close",onClick:e.handleClose},r.createElement("span",{className:"lr"},r.createElement("span",{className:"rl"})))),r.createElement(l.Z.Body,null,r.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),r.createElement(l.Z.Footer,null,r.createElement(i.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function s(e){return r.createElement(c,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}const u=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"nginx","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"}},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function d(e,t){for(var a=0;a0?t[0]:u}}],null&&d(t.prototype,null),a&&d(t,a),e}(),m=a(151),f=a(555);function h(e,t){(null==t||t>e.length)&&(t=e.length);for(var a=0,r=new Array(t);a0&&this.handleSort()}},{key:"handleDeploymentModalClose",value:function(){this.setState({showDeploymentModal:!1})}},{key:"handleDeploymentModalShow",value:function(){this.setState({showDeploymentModal:!0})}},{key:"handleErrorModalClose",value:function(){this.setState({showErrorModal:!1})}},{key:"render",value:function(){return r.createElement("div",null,r.createElement(s,{id:"errorModal",show:this.state.showErrorModal,handleClose:this.handleErrorModalClose}),r.createElement(o,{show:this.state.showSpinner}),r.createElement(g,{show:this.state.showDeploymentModal,handleClose:this.handleDeploymentModalClose}),r.createElement("div",{className:"row splitter"},r.createElement("div",{className:"col-lg-12"},r.createElement("h3",null,"Sorted values:"),r.createElement("p",{id:"resultOutput",className:"lead"},this.state.result))),r.createElement("div",{className:"row splitter"},r.createElement("div",{className:"col-lg-12"},r.createElement("p",null,"Values to sort: ",this.state.values))),r.createElement("div",{className:"row"},r.createElement("div",{className:"col-lg-12"},r.createElement(b,{value:this.state.values,onChange:this.handleValuesChange,handleSubmit:this.handleSubmit}))))}}])&&M(t.prototype,a),c}(r.Component);n.render(r.createElement(O,null),document.getElementById("result"))}},a={};function r(e){var n=a[e];if(void 0!==n)return n.exports;var o=a[e]={exports:{}};return t[e].call(o.exports,o,o.exports,r),o.exports}r.m=t,e=[],r.O=(t,a,n,o)=>{if(!a){var l=1/0;for(u=0;u=o)&&Object.keys(r.O).every((e=>r.O[e](a[c])))?a.splice(c--,1):(i=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[a,n,o]},r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var a in t)r.o(t,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};r.O.j=t=>0===e[t];var t=(t,a)=>{var n,o,[l,i,c]=a,s=0;for(n in i)r.o(i,n)&&(r.m[n]=i[n]);if(c)var u=c(r);for(t&&t(a);sr(729)));n=r.O(n)})(); \ No newline at end of file +(()=>{"use strict";var e,t={729:(e,t,a)=>{var r=a(294),n=a(935);function o(e){var t=e.show?"":"d-none";return r.createElement("div",null,r.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),r.createElement("div",{id:"loader",className:"".concat(t," item loading")},r.createElement("div",{className:"spinner"},r.createElement("div",{className:"circle circle-1"},r.createElement("div",{className:"circle-inner"})),r.createElement("div",{className:"circle circle-2"},r.createElement("div",{className:"circle-inner"})))))}var l=a(625),i=a(754);function c(e){return r.createElement(l.Z,{id:e.id,show:e.show,onHide:e.handleClose},r.createElement(l.Z.Header,null,r.createElement(l.Z.Title,{className:"display-4"},e.title),r.createElement(i.Z,{variant:"link",className:"close",onClick:e.handleClose},r.createElement("span",{className:"lr"},r.createElement("span",{className:"rl"})))),r.createElement(l.Z.Body,null,r.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),r.createElement(l.Z.Footer,null,r.createElement(i.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function s(e){return r.createElement(c,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}const u=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"localhost","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["uniqueDataEntry"]},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["dataStructures"]},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["entitySort"]},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["stringSort"]},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3,"services":["coffeeMachine"]},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"},"services":["nodeToDo"]},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function d(e,t){for(var a=0;a0?t[0]:u}}],null&&d(t.prototype,null),a&&d(t,a),e}(),m=a(151),f=a(555);function h(e,t){(null==t||t>e.length)&&(t=e.length);for(var a=0,r=new Array(t);a0&&this.handleSort()}},{key:"handleDeploymentModalClose",value:function(){this.setState({showDeploymentModal:!1})}},{key:"handleDeploymentModalShow",value:function(){this.setState({showDeploymentModal:!0})}},{key:"handleErrorModalClose",value:function(){this.setState({showErrorModal:!1})}},{key:"render",value:function(){return r.createElement("div",null,r.createElement(s,{id:"errorModal",show:this.state.showErrorModal,handleClose:this.handleErrorModalClose}),r.createElement(o,{show:this.state.showSpinner}),r.createElement(g,{show:this.state.showDeploymentModal,handleClose:this.handleDeploymentModalClose}),r.createElement("div",{className:"row splitter"},r.createElement("div",{className:"col-lg-12"},r.createElement("h3",null,"Sorted values:"),r.createElement("p",{id:"resultOutput",className:"lead"},this.state.result))),r.createElement("div",{className:"row splitter"},r.createElement("div",{className:"col-lg-12"},r.createElement("p",null,"Values to sort: ",this.state.values))),r.createElement("div",{className:"row"},r.createElement("div",{className:"col-lg-12"},r.createElement(b,{value:this.state.values,onChange:this.handleValuesChange,handleSubmit:this.handleSubmit}))))}}])&&M(t.prototype,a),c}(r.Component);n.render(r.createElement(O,null),document.getElementById("result"))}},a={};function r(e){var n=a[e];if(void 0!==n)return n.exports;var o=a[e]={exports:{}};return t[e].call(o.exports,o,o.exports,r),o.exports}r.m=t,e=[],r.O=(t,a,n,o)=>{if(!a){var l=1/0;for(u=0;u=o)&&Object.keys(r.O).every((e=>r.O[e](a[c])))?a.splice(c--,1):(i=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[a,n,o]},r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var a in t)r.o(t,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};r.O.j=t=>0===e[t];var t=(t,a)=>{var n,o,[l,i,c]=a,s=0;for(n in i)r.o(i,n)&&(r.m[n]=i[n]);if(c)var u=c(r);for(t&&t(a);sr(729)));n=r.O(n)})(); \ No newline at end of file diff --git a/docs/app_uniqueDataEntry/main.js b/docs/app_uniqueDataEntry/main.js index b5852989..d5a9c8e7 100644 --- a/docs/app_uniqueDataEntry/main.js +++ b/docs/app_uniqueDataEntry/main.js @@ -1 +1 @@ -(()=>{"use strict";var e,t={425:(e,t,a)=>{var n=a(294),r=a(935);function o(e,t){for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25,a=void 0!==e?e.substring(0,t).split(" ").join(""):"";return a}}],null&&o(t.prototype,null),a&&o(t,a),e}();function i(e){var t=e.show?"":"d-none";return n.createElement("div",null,n.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),n.createElement("div",{id:"loader",className:"".concat(t," item loading")},n.createElement("div",{className:"spinner"},n.createElement("div",{className:"circle circle-1"},n.createElement("div",{className:"circle-inner"})),n.createElement("div",{className:"circle circle-2"},n.createElement("div",{className:"circle-inner"})))))}var c=a(625),s=a(754);function u(e){return n.createElement(c.Z,{id:e.id,show:e.show,onHide:e.handleClose},n.createElement(c.Z.Header,null,n.createElement(c.Z.Title,{className:"display-4"},e.title),n.createElement(s.Z,{variant:"link",className:"close",onClick:e.handleClose},n.createElement("span",{className:"lr"},n.createElement("span",{className:"rl"})))),n.createElement(c.Z.Body,null,n.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),n.createElement(c.Z.Footer,null,n.createElement(s.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function d(e){return n.createElement(u,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}const m=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"nginx","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"}},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function p(e,t){for(var a=0;a0?t[0]:m}}],null&&p(t.prototype,null),a&&p(t,a),e}(),h=a(151),b=a(555);function y(e,t){(null==t||t>e.length)&&(t=e.length);for(var a=0,n=new Array(t);ae.length)&&(t=e.length);for(var a=0,n=new Array(t);a{if(!a){var l=1/0;for(u=0;u=o)&&Object.keys(n.O).every((e=>n.O[e](a[c])))?a.splice(c--,1):(i=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[a,r,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,a)=>{var r,o,[l,i,c]=a,s=0;for(r in i)n.o(i,r)&&(n.m[r]=i[r]);if(c)var u=c(n);for(t&&t(a);sn(425)));r=n.O(r)})(); \ No newline at end of file +(()=>{"use strict";var e,t={425:(e,t,a)=>{var n=a(294),r=a(935);function o(e,t){for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:25,a=void 0!==e?e.substring(0,t).split(" ").join(""):"";return a}}],null&&o(t.prototype,null),a&&o(t,a),e}();function i(e){var t=e.show?"":"d-none";return n.createElement("div",null,n.createElement("div",{id:"spinner",className:"".concat(t," spinner-container overlay")}),n.createElement("div",{id:"loader",className:"".concat(t," item loading")},n.createElement("div",{className:"spinner"},n.createElement("div",{className:"circle circle-1"},n.createElement("div",{className:"circle-inner"})),n.createElement("div",{className:"circle circle-2"},n.createElement("div",{className:"circle-inner"})))))}var c=a(625),s=a(754);function u(e){return n.createElement(c.Z,{id:e.id,show:e.show,onHide:e.handleClose},n.createElement(c.Z.Header,null,n.createElement(c.Z.Title,{className:"display-4"},e.title),n.createElement(s.Z,{variant:"link",className:"close",onClick:e.handleClose},n.createElement("span",{className:"lr"},n.createElement("span",{className:"rl"})))),n.createElement(c.Z.Body,null,n.createElement("p",{className:"lead px-2 ".concat(e.bodyClass)},e.body)),n.createElement(c.Z.Footer,null,n.createElement(s.Z,{variant:"dark",onClick:e.handleClose},"Close")))}function d(e){return n.createElement(u,{id:e.id,show:e.show,onHide:e.handleClose,handleClose:e.handleClose,title:e.title||"We have a problem!",body:e.body||"An error has occurred. Please try again.",bodyClass:"text-danger"})}const m=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"localhost","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["uniqueDataEntry"]},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["dataStructures"]},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["entitySort"]},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["stringSort"]},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3,"services":["coffeeMachine"]},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"},"services":["nodeToDo"]},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function p(e,t){for(var a=0;a0?t[0]:m}}],null&&p(t.prototype,null),a&&p(t,a),e}(),h=a(151),b=a(555);function v(e,t){(null==t||t>e.length)&&(t=e.length);for(var a=0,n=new Array(t);ae.length)&&(t=e.length);for(var a=0,n=new Array(t);a{if(!a){var l=1/0;for(u=0;u=o)&&Object.keys(n.O).every((e=>n.O[e](a[c])))?a.splice(c--,1):(i=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[a,r,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={179:0};n.O.j=t=>0===e[t];var t=(t,a)=>{var r,o,[l,i,c]=a,s=0;for(r in i)n.o(i,r)&&(n.m[r]=i[r]);if(c)var u=c(n);for(t&&t(a);sn(425)));r=n.O(r)})(); \ No newline at end of file diff --git a/docs/main.js b/docs/main.js index 36b3d68d..e8e02154 100644 --- a/docs/main.js +++ b/docs/main.js @@ -1 +1 @@ -(()=>{"use strict";var e,t,n,a={613:(e,t,n)=>{n(666);var a=n(294),r=n(935);function i(e,t){for(var n=0;na?1:0}}],null&&i(t.prototype,null),n&&i(t,n),e}();const c=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"nginx","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"}},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function l(e,t){for(var n=0;n0?t[0]:c}}],null&&l(t.prototype,null),n&&l(t,n),e}(),u=a.createContext();function d(e){var t=e.children,n=e.app,r={config:s.get(),appConfig:s.get(n)};return a.createElement(u.Provider,{value:r},t)}function p(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=e.length>0?e.filter((function(e){return t.split(" ").filter((function(e){return e})).filter((function(t){return-1!==e.toUpperCase().indexOf(t.toUpperCase())})).length>0})):[],a=n.length>0;return a}}],null&&v(t.prototype,null),n&&v(t,n),e}();function b(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var a,r,i=[],o=!0,c=!1;try{for(n=n.call(e);!(o=(a=n.next()).done)&&(i.push(a.value),!t||i.length!==t);o=!0);}catch(e){c=!0,r=e}finally{try{o||null==n.return||n.return()}finally{if(c)throw r}}return i}}(e,t)||function(e,t){if(e){if("string"==typeof e)return g(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?g(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function g(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";if(e.length>0){var t=d.applications.map((function(t){var n=[t.name,t.subHeading,t.description,t.searchTerms];return t.active=!!t.include&&h.searchCriteria(n,e),t}));v(!0),d.setApplications(t)}else C()};return a.createElement("form",{onSubmit:function(e){return e.preventDefault()}},a.createElement("div",{id:t,className:"input-group mb-3 shadow searchBar"},a.createElement("div",{className:"input-group-prepend"},a.createElement("span",{className:"input-group-text"},a.createElement("i",{className:"fa fa-search"}))),a.createElement("input",{type:"text",className:"form-control searchInput ".concat(E),placeholder:"Search applications...",id:n,value:y,onChange:function(e){var t=e.target.value;S(t),k(t)}}),f&&a.createElement("div",{className:"input-group-append cancelBtn",id:r},a.createElement("button",{className:"btn ".concat(w),type:"button",onClick:C},a.createElement("span",{className:"lr"},a.createElement("span",{className:"rl"})))),l&&a.createElement("div",{className:"input-group-append"},a.createElement("button",{id:i,className:"btn btn-dark openFilterBtn",type:"button","data-toggle":"collapse","data-target":"#".concat(o),"aria-expanded":"false","aria-controls":o},a.createElement("i",{className:"fa fa-filter"})))),l&&a.createElement("div",{className:"collapse filterContainer",id:o},a.createElement("div",{className:"pb-3"},a.createElement("label",{className:"d-flex flex-row justify-content-center"},"Quick search"),a.createElement("div",{className:"quick-search-filters d-flex justify-content-center"},s.config.quickSearch.map((function(e){return a.createElement("button",{key:e,type:"button",className:"btn btn-outline-dark ml-2 p-0",value:e,onClick:A},e)}))))))}h.searchDoesNotExist=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return-1===(e||"").toUpperCase().indexOf((t||"").toUpperCase())},h.combineSearchTerms=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n="".concat(e," ").concat(t);return n.trim()},h.removeSearchTerm=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=e.split(t),a=n.map((function(e){return e.trim()}));return a.join(" ").trim()};var S=n(6),w=n(51),E=n(555),C=n(977),A=a.memo((function(e){var t=e.application,n=e.condition,r=a.useContext(u);return a.createElement(a.Fragment,null,n&&a.createElement(S.Z,{className:"grid-item",key:"".concat(t.name)},a.createElement(S.Z.Body,null,a.createElement(S.Z.Title,null,t.name),a.createElement(S.Z.Text,null,t.subHeading),a.createElement(S.Z.Link,{className:"btn btn-outline-dark btn-sm card-link",href:"".concat(r.config.prefix).concat(t.folder,"/index.html")},"View application"),a.createElement(w.Z,{className:"mt-3"},a.createElement(E.Z,null,t.labels?t.labels.map((function(e){var t=r.config.labels[e];return a.createElement(C.Z,{key:e,variant:t,className:"text-light mr-2"},e)})):null)))))}),(function(e,t){return e.condition===t.condition}));function k(){var e=a.useContext(m),t=e.applications.filter((function(e){return e.featured}))||[],n=e.applications.filter((function(e){return!e.featured}))||[];return a.createElement(a.Fragment,null,(t.length>0||n.length>0)&&a.createElement("div",{id:"applicationsContainer"},a.createElement("div",{className:"card-columns"},t.map((function(e){return a.createElement(A,{key:"featured_".concat(e.folder),condition:e.active&&e.include,application:e})}))),a.createElement("div",{className:"card-columns"},n.map((function(e){return a.createElement(A,{key:e.folder,condition:e.active&&e.include,application:e})})))))}var T=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t="fade-element",n=e?"in":"out";return"".concat(t," ").concat(n)};function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n=i))};return a.createElement(a.Fragment,null,a.createElement("button",{className:"btn btn-dark fade-element ".concat(c),id:"topScrollBtn",onClick:function(){window.scrollTo({top:0,left:0,behavior:"smooth"})}},a.createElement("i",{className:"fa fa-3x fa-angle-up"})))}function I(){var e=a.useContext(u);return a.createElement("div",{className:"container-fluid pt-4 bg-white",id:"contentContainer"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col-lg-12"},a.createElement("h5",null,e.config.title),a.createElement("p",{className:"text-muted"},e.config.author," - ",e.config.role),a.createElement("hr",null))),a.createElement(y,{searchBarId:"searchBar",searchInputId:"searchInput",cancelBtnId:"cancelBtn",openFilterBtnId:"openFilterBtn",filterContainerId:"filterContainer"}),a.createElement(k,null),a.createElement(R,{threshold:270}))}var N="scroll-down",P="navBar";function D(){var e=a.useContext(u);return a.createElement("div",{className:"bg-dark",id:"introContainer"},a.createElement("div",{id:"introContent"},a.createElement("div",{id:"canvasContainer",style:{width:"100vw",height:"100vh"}}),a.createElement("div",{id:"introContentInner"},a.createElement("div",{id:"introImage",className:"text-center element"},a.createElement("img",{className:"img-fluid",src:"images/FSLogo.png",alt:"Logo"})),a.createElement("div",{id:"introHeadings",className:"text-center element"},a.createElement("h1",{className:"display-4 mb-0"},e.config.author),a.createElement("h4",{className:"display-4 sub-heading lead text-white"},e.config.role)),a.createElement("div",{id:"btnContainer",className:"text-center element pt-2"},a.createElement("button",{type:"button",className:"btn btn-outline-light",onClick:function(e){e.preventDefault();var t=document.getElementById("contentContainer");window.scrollTo({top:t.offsetTop-50,left:0,behavior:"smooth"})}},"View Portfolio")))))}function M(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:1e4,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:5,a=[],r=0;r0&&void 0!==arguments[0]?arguments[0]:16777215,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1e3,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,o=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,l=new t.SpotLight(e,n,a);l.position.set(r,i,o),l.penumbra=1,l.castShadow=!0,l.shadow.mapSize.width=2560,l.shadow.mapSize.height=2560,l.shadow.camera.near=.5,l.shadow.camera.far=500,l.shadow.focus=1,c.add(l)},x=function(){u.step(.016666666666666666);var e=u.bodies.filter((function(e){return e.updatePhysics})),t=c.children.filter((function(e){return e.updatePhysics}));if(e.length===t.length)for(var n=0;n0){var n=t[0].object;if(n.updatePhysics){var a=u.bodies.filter((function(e){return e.position.x===n.position.x&&e.position.y===n.position.y&&e.position.z===n.position.z}));if(a.length>0){var r=a[0],i=10*p.x,o=10*p.y;r.angularVelocity.set(i,o,0)}}}},P=function(){window.addEventListener("mousemove",N)},D=function(){var e=J(regeneratorRuntime.mark((function e(){var n;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n=new t.TextureLoader,e.next=3,n.loadAsync("images/PaintedWood005_2K_Displacement.jpg");case 3:return f=e.sent,e.next=6,n.loadAsync("images/Asphalt011_1K_Roughness.jpg");case 6:v=e.sent,f.wrapS=t.RepeatWrapping,f.wrapT=t.RepeatWrapping,f.repeat.set(3,2),b(),h(),I(),y(),S(),w(),k(),C(2e4,10),T(16777215,2,500,0,10,5),P(),g(),R();case 22:case"end":return e.stop()}}),e)})));return function(){return e.apply(this,arguments)}}(),e.abrupt("return",{init:D});case 29:case"end":return e.stop()}}),e)})))(),_=function(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],t=document.getElementById(P);e?t.classList.remove(N):t.classList.add(N)},G=function(){_(0===window.scrollY)};function V(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n{if(!n){var o=1/0;for(u=0;u=r)&&Object.keys(i.O).every((e=>i.O[e](n[l])))?n.splice(l--,1):(c=!1,r0&&e[u-1][2]>r;u--)e[u]=e[u-1];e[u]=[n,a,r]},i.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return i.d(t,{a:t}),t},n=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,i.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var r=Object.create(null);i.r(r);var o={};t=t||[null,n({}),n([]),n(n)];for(var c=2&a&&e;"object"==typeof c&&!~t.indexOf(c);c=n(c))Object.getOwnPropertyNames(c).forEach((t=>o[t]=()=>e[t]));return o.default=()=>e,i.d(r,o),r},i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.e=()=>Promise.resolve(),i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e={179:0};i.O.j=t=>0===e[t];var t=(t,n)=>{var a,r,[o,c,l]=n,s=0;for(a in c)i.o(c,a)&&(i.m[a]=c[a]);if(l)var u=l(i);for(t&&t(n);si(613)));o=i.O(o)})(); \ No newline at end of file +(()=>{"use strict";var e,t,n,a={613:(e,t,n)=>{n(666);var a=n(294),r=n(935);function i(e,t){for(var n=0;na?1:0}}],null&&i(t.prototype,null),n&&i(t,n),e}();const c=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"localhost","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["uniqueDataEntry"]},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["dataStructures"]},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["entitySort"]},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false,"services":["stringSort"]},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3,"services":["coffeeMachine"]},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"},"services":["nodeToDo"]},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function l(e,t){for(var n=0;n0?t[0]:c}}],null&&l(t.prototype,null),n&&l(t,n),e}(),u=a.createContext();function d(e){var t=e.children,n=e.app,r={config:s.get(),appConfig:s.get(n)};return a.createElement(u.Provider,{value:r},t)}function p(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=e.length>0?e.filter((function(e){return t.split(" ").filter((function(e){return e})).filter((function(t){return-1!==e.toUpperCase().indexOf(t.toUpperCase())})).length>0})):[],a=n.length>0;return a}}],null&&v(t.prototype,null),n&&v(t,n),e}();function b(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var a,r,i=[],o=!0,c=!1;try{for(n=n.call(e);!(o=(a=n.next()).done)&&(i.push(a.value),!t||i.length!==t);o=!0);}catch(e){c=!0,r=e}finally{try{o||null==n.return||n.return()}finally{if(c)throw r}}return i}}(e,t)||function(e,t){if(e){if("string"==typeof e)return g(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?g(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function g(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";if(e.length>0){var t=d.applications.map((function(t){var n=[t.name,t.subHeading,t.description,t.searchTerms];return t.active=!!t.include&&h.searchCriteria(n,e),t}));v(!0),d.setApplications(t)}else C()};return a.createElement("form",{onSubmit:function(e){return e.preventDefault()}},a.createElement("div",{id:t,className:"input-group mb-3 shadow searchBar"},a.createElement("div",{className:"input-group-prepend"},a.createElement("span",{className:"input-group-text"},a.createElement("i",{className:"fa fa-search"}))),a.createElement("input",{type:"text",className:"form-control searchInput ".concat(E),placeholder:"Search applications...",id:n,value:y,onChange:function(e){var t=e.target.value;S(t),k(t)}}),f&&a.createElement("div",{className:"input-group-append cancelBtn",id:r},a.createElement("button",{className:"btn ".concat(w),type:"button",onClick:C},a.createElement("span",{className:"lr"},a.createElement("span",{className:"rl"})))),l&&a.createElement("div",{className:"input-group-append"},a.createElement("button",{id:i,className:"btn btn-dark openFilterBtn",type:"button","data-toggle":"collapse","data-target":"#".concat(o),"aria-expanded":"false","aria-controls":o},a.createElement("i",{className:"fa fa-filter"})))),l&&a.createElement("div",{className:"collapse filterContainer",id:o},a.createElement("div",{className:"pb-3"},a.createElement("label",{className:"d-flex flex-row justify-content-center"},"Quick search"),a.createElement("div",{className:"quick-search-filters d-flex justify-content-center"},s.config.quickSearch.map((function(e){return a.createElement("button",{key:e,type:"button",className:"btn btn-outline-dark ml-2 p-0",value:e,onClick:A},e)}))))))}h.searchDoesNotExist=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return-1===(e||"").toUpperCase().indexOf((t||"").toUpperCase())},h.combineSearchTerms=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n="".concat(e," ").concat(t);return n.trim()},h.removeSearchTerm=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=e.split(t),a=n.map((function(e){return e.trim()}));return a.join(" ").trim()};var S=n(6),w=n(51),E=n(555),C=n(977),A=a.memo((function(e){var t=e.application,n=e.condition,r=a.useContext(u);return a.createElement(a.Fragment,null,n&&a.createElement(S.Z,{className:"grid-item",key:"".concat(t.name)},a.createElement(S.Z.Body,null,a.createElement(S.Z.Title,null,t.name),a.createElement(S.Z.Text,null,t.subHeading),a.createElement(S.Z.Link,{className:"btn btn-outline-dark btn-sm card-link",href:"".concat(r.config.prefix).concat(t.folder,"/index.html")},"View application"),a.createElement(w.Z,{className:"mt-3"},a.createElement(E.Z,null,t.labels?t.labels.map((function(e){var t=r.config.labels[e];return a.createElement(C.Z,{key:e,variant:t,className:"text-light mr-2"},e)})):null)))))}),(function(e,t){return e.condition===t.condition}));function k(){var e=a.useContext(m),t=e.applications.filter((function(e){return e.featured}))||[],n=e.applications.filter((function(e){return!e.featured}))||[];return a.createElement(a.Fragment,null,(t.length>0||n.length>0)&&a.createElement("div",{id:"applicationsContainer"},a.createElement("div",{className:"card-columns"},t.map((function(e){return a.createElement(A,{key:"featured_".concat(e.folder),condition:e.active&&e.include,application:e})}))),a.createElement("div",{className:"card-columns"},n.map((function(e){return a.createElement(A,{key:e.folder,condition:e.active&&e.include,application:e})})))))}var T=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t="fade-element",n=e?"in":"out";return"".concat(t," ").concat(n)};function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n=i))};return a.createElement(a.Fragment,null,a.createElement("button",{className:"btn btn-dark fade-element ".concat(c),id:"topScrollBtn",onClick:function(){window.scrollTo({top:0,left:0,behavior:"smooth"})}},a.createElement("i",{className:"fa fa-3x fa-angle-up"})))}function I(){var e=a.useContext(u);return a.createElement("div",{className:"container-fluid pt-4 bg-white",id:"contentContainer"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col-lg-12"},a.createElement("h5",null,e.config.title),a.createElement("p",{className:"text-muted"},e.config.author," - ",e.config.role),a.createElement("hr",null))),a.createElement(y,{searchBarId:"searchBar",searchInputId:"searchInput",cancelBtnId:"cancelBtn",openFilterBtnId:"openFilterBtn",filterContainerId:"filterContainer"}),a.createElement(k,null),a.createElement(R,{threshold:270}))}var N="scroll-down",P="navBar";function D(){var e=a.useContext(u);return a.createElement("div",{className:"bg-dark",id:"introContainer"},a.createElement("div",{id:"introContent"},a.createElement("div",{id:"canvasContainer",style:{width:"100vw",height:"100vh"}}),a.createElement("div",{id:"introContentInner"},a.createElement("div",{id:"introImage",className:"text-center element"},a.createElement("img",{className:"img-fluid",src:"images/FSLogo.png",alt:"Logo"})),a.createElement("div",{id:"introHeadings",className:"text-center element"},a.createElement("h1",{className:"display-4 mb-0"},e.config.author),a.createElement("h4",{className:"display-4 sub-heading lead text-white"},e.config.role)),a.createElement("div",{id:"btnContainer",className:"text-center element pt-2"},a.createElement("button",{type:"button",className:"btn btn-outline-light",onClick:function(e){e.preventDefault();var t=document.getElementById("contentContainer");window.scrollTo({top:t.offsetTop-50,left:0,behavior:"smooth"})}},"View Portfolio")))))}function M(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:1e4,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:5,a=[],r=0;r0&&void 0!==arguments[0]?arguments[0]:16777215,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1e3,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,o=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,l=new t.SpotLight(e,n,a);l.position.set(r,i,o),l.penumbra=1,l.castShadow=!0,l.shadow.mapSize.width=2560,l.shadow.mapSize.height=2560,l.shadow.camera.near=.5,l.shadow.camera.far=500,l.shadow.focus=1,c.add(l)},x=function(){u.step(.016666666666666666);var e=u.bodies.filter((function(e){return e.updatePhysics})),t=c.children.filter((function(e){return e.updatePhysics}));if(e.length===t.length)for(var n=0;n0){var n=t[0].object;if(n.updatePhysics){var a=u.bodies.filter((function(e){return e.position.x===n.position.x&&e.position.y===n.position.y&&e.position.z===n.position.z}));if(a.length>0){var r=a[0],i=10*p.x,o=10*p.y;r.angularVelocity.set(i,o,0)}}}},P=function(){window.addEventListener("mousemove",N)},D=function(){var e=J(regeneratorRuntime.mark((function e(){var n;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n=new t.TextureLoader,e.next=3,n.loadAsync("images/PaintedWood005_2K_Displacement.jpg");case 3:return f=e.sent,e.next=6,n.loadAsync("images/Asphalt011_1K_Roughness.jpg");case 6:v=e.sent,f.wrapS=t.RepeatWrapping,f.wrapT=t.RepeatWrapping,f.repeat.set(3,2),b(),h(),I(),y(),S(),w(),k(),C(2e4,10),T(16777215,2,500,0,10,5),P(),g(),R();case 22:case"end":return e.stop()}}),e)})));return function(){return e.apply(this,arguments)}}(),e.abrupt("return",{init:D});case 29:case"end":return e.stop()}}),e)})))(),_=function(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],t=document.getElementById(P);e?t.classList.remove(N):t.classList.add(N)},G=function(){_(0===window.scrollY)};function V(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);n{if(!n){var o=1/0;for(u=0;u=r)&&Object.keys(i.O).every((e=>i.O[e](n[l])))?n.splice(l--,1):(c=!1,r0&&e[u-1][2]>r;u--)e[u]=e[u-1];e[u]=[n,a,r]},i.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return i.d(t,{a:t}),t},n=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,i.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var r=Object.create(null);i.r(r);var o={};t=t||[null,n({}),n([]),n(n)];for(var c=2&a&&e;"object"==typeof c&&!~t.indexOf(c);c=n(c))Object.getOwnPropertyNames(c).forEach((t=>o[t]=()=>e[t]));return o.default=()=>e,i.d(r,o),r},i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.e=()=>Promise.resolve(),i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e={179:0};i.O.j=t=>0===e[t];var t=(t,n)=>{var a,r,[o,c,l]=n,s=0;for(a in c)i.o(c,a)&&(i.m[a]=c[a]);if(l)var u=l(i);for(t&&t(n);si(613)));o=i.O(o)})(); \ No newline at end of file diff --git a/docs/vendor/vendor.js b/docs/vendor/vendor.js index c68bd9ed..212657ef 100644 --- a/docs/vendor/vendor.js +++ b/docs/vendor/vendor.js @@ -1,2 +1,2 @@ /*! For license information please see vendor.js.LICENSE.txt */ -(()=>{var e={799:(e,t,n)=>{"use strict";var r=n(294),i=n(935),o=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t="fade-element",n=e?"in":"out";return"".concat(t," ").concat(n)},a=n(491);function l(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=270))),i||u(o(!0)))};return r.createElement(r.Fragment,null,r.createElement("div",{className:"cookie-banner-container fade-element ".concat(l),id:"cookieBannerComponent"},r.createElement("p",null,"This application uses cookies to determine which services are deployed and do not store any personal data."),r.createElement("button",{type:"button",className:"btn btn-sm btn-dark ml-5",onClick:function(){g.setItem(m,!0),u(o(!1))}},"Accept")))}function y(){var e=null!==document.head.querySelector('[name="isRoot"]');return r.createElement(v,{isHomeActive:e})}i.render(r.createElement(y,null),document.getElementById("cookieBanner"))},514:(e,t,n)=>{"use strict";var r=n(294),i=n(935);function o(e,t){for(var n=0;nr?1:0}}],null&&o(t.prototype,null),n&&o(t,n),e}(),l=n(491),u=r.createContext();function s(e){var t=e.children,n=e.app,i={config:l.K.get(),appConfig:l.K.get(n)};return r.createElement(u.Provider,{value:i},t)}function c(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=e.length>0?e.filter((function(e){return t.split(" ").filter((function(e){return e})).filter((function(t){return-1!==e.toUpperCase().indexOf(t.toUpperCase())})).length>0})):[],r=n.length>0;return r}}],null&&p(t.prototype,null),n&&p(t,n),e}();function m(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,i,o=[],a=!0,l=!1;try{for(n=n.call(e);!(a=(r=n.next()).done)&&(o.push(r.value),!t||o.length!==t);a=!0);}catch(e){l=!0,i=e}finally{try{a||null==n.return||n.return()}finally{if(l)throw i}}return o}}(e,t)||function(e,t){if(e){if("string"==typeof e)return g(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?g(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function g(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";if(e.length>0){var t=d.applications.map((function(t){var n=[t.name,t.subHeading,t.description,t.searchTerms];return t.active=!!t.include&&h.searchCriteria(n,e),t}));v(!0),d.setApplications(t)}else x()};return r.createElement("form",{onSubmit:function(e){return e.preventDefault()}},r.createElement("div",{id:t,className:"input-group mb-3 shadow searchBar"},r.createElement("div",{className:"input-group-prepend"},r.createElement("span",{className:"input-group-text"},r.createElement("i",{className:"fa fa-search"}))),r.createElement("input",{type:"text",className:"form-control searchInput ".concat(E),placeholder:"Search applications...",id:n,value:b,onChange:function(e){var t=e.target.value;w(t),k(t)}}),g&&r.createElement("div",{className:"input-group-append cancelBtn",id:i},r.createElement("button",{className:"btn ".concat(_),type:"button",onClick:x},r.createElement("span",{className:"lr"},r.createElement("span",{className:"rl"})))),s&&r.createElement("div",{className:"input-group-append"},r.createElement("button",{id:o,className:"btn btn-dark openFilterBtn",type:"button","data-toggle":"collapse","data-target":"#".concat(a),"aria-expanded":"false","aria-controls":a},r.createElement("i",{className:"fa fa-filter"})))),s&&r.createElement("div",{className:"collapse filterContainer",id:a},r.createElement("div",{className:"pb-3"},r.createElement("label",{className:"d-flex flex-row justify-content-center"},"Quick search"),r.createElement("div",{className:"quick-search-filters d-flex justify-content-center"},c.config.quickSearch.map((function(e){return r.createElement("button",{key:e,type:"button",className:"btn btn-outline-dark ml-2 p-0",value:e,onClick:T},e)}))))))}function y(e){var t=e.isHomeActive,n=e.folder,i=r.useContext(f),o=r.useContext(u).config,a=i.applications,l=t?".":"..";return r.createElement(r.Fragment,null,r.createElement("div",{className:"mx-2 nav-filter-container"},r.createElement(v,{searchBarId:"searchBarNav",searchInputId:"searchInputNav",cancelBtnId:"cancelBtnNav",openFilterBtnId:"openFilterBtnNav",filterContainerId:"filterContainerNav",showQuickFilters:!1})),r.createElement("div",{className:"filter-scroller"},a.map((function(e,t){if(e.active&&e.include){var i="".concat(l,"/").concat(o.prefix).concat(e.folder,"/index.html"),a=n===e.folder?"active":"";return r.createElement("a",{key:"".concat(e.name,"-").concat(t),className:"".concat(a," dropdown-item"),href:i},e.name)}})),r.createElement("div",{className:"dropdown-divider"}),r.createElement("a",{className:"".concat(t?"active":""," dropdown-item"),href:"".concat(l,"/index.html")},"Home ",r.createElement("i",{className:"fa fa-home ml-2"}))))}function b(){var e=null!==document.head.querySelector('[name="isRoot"]'),t=document.head.querySelector('[name="folder"]').content;return r.createElement(s,null,r.createElement(d,null,r.createElement(y,{isHomeActive:e,folder:t})))}h.searchDoesNotExist=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return-1===(e||"").toUpperCase().indexOf((t||"").toUpperCase())},h.combineSearchTerms=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n="".concat(e," ").concat(t);return n.trim()},h.removeSearchTerm=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=e.split(t),r=n.map((function(e){return e.trim()}));return r.join(" ").trim()},i.render(r.createElement(b,null),document.getElementById("applicationsDropdown"))},491:(e,t,n)=>{"use strict";n.d(t,{K:()=>o});const r=JSON.parse('{"host":"localhost","apiRoot":"/backend/","deploymentTargetCookie":"fs_portfolio_deployment_target","deploymentTargets":{"cloud":"cloud","static":"static"},"dockerHost":"nginx","port":8080,"prefix":"app_","entry":"home","index":"index.html","masterTemplateDir":"master_react","developmentDir":"app","publishDir":"docs","folderRoot":"/tree/master/app/","repoRootUrl":"https://github.com/fsereno/portfolio","linkedInUrl":"https://www.linkedin.com/in/fabio-sereno-6a97b986/","gitHubUrl":"https://github.com/fsereno","gitHubIssuesUrl":"https://github.com/fsereno/portfolio/issues","title":"Portfolio","author":"Fabio Sereno","role":"Software Engineer","description":"Portfolio By Fabio Sereno - Software Engineer","thumbnail":"PortfolioThumbnail.png","labels":{"JavaScript":"warning","NodeJS":"success","C#":"info","Cloud":"danger"},"quickSearch":["React",".NET","Cloud"],"grecaptcha":{"active":false,"key":"","endpoints":{"base":"","verify":"verify"}},"applications":[{"name":"Portfolio","subHeading":"By Fabio Sereno","description":"Highly experienced, highly self-motivated, enthusiastic, professional Full Stack Software Engineer.","folder":"home","active":true,"include":false,"folderRoot":"/","useWebpack":true,"useRoot":true,"isLandingPage":true},{"name":"MIT Licence","subHeading":"MIT Licence for this repository.","description":"","folder":"licence","useWebpack":true,"active":true,"include":false},{"name":"To-Do List (React)","subHeading":"A basic list builder using React","description":"Using React, with Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (React Redux)","subHeading":"A basic list builder using React and Redux","description":"Using Redux with React to manage application state, implementing Undo and Redo functionality.","searchTerms":"Docker,JavaScript,React,Redux,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"reactRedux","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"To-Do List (Vue)","subHeading":"A basic list builder using Vue","description":"Experimenting with Vue, Babel and Webpack.","searchTerms":"Docker,JavaScript,Vue,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"toDoVue","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Tic-Tac-Toe","subHeading":"A Tic-Tac-Toe game built using React","description":"Demonstrating React state management with immutability, allowing for \'time travel\' or \'versioned\' data.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"ticTacToeReact","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"Unique Data Entry Application","subHeading":"Unique data entry implementing IEqualityComparer to manage illegal duplicate data entries, with a React UI","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"uniqueDataEntry","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"canItemBeAddedAsync":"uniqueDataEntry/api/canItemBeAddedAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Data Structures","subHeading":"First in, first out (FIFO) and last in, first out (LIFO) data structures implementing Queue and Stack","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"dataStructures","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"addQueueItem":"dataStructures/api/addQueueItemAsync","removeQueueItem":"dataStructures/api/removeQueueItemAsync","addStackItem":"dataStructures/api/addStackItemAsync","removeStackItem":"dataStructures/api/removeStackItemAsync"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Complex Entity Sorting Algorithm","subHeading":"A sorting mechanism, implementing IComparable and IComparer to sort complex types","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"entitySort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sortSalaryAsc":"entitySort/api/sort/salary/asc","sortSalaryDesc":"entitySort/api/sort/salary/desc"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Natural Sorting Algorithm","subHeading":"A natural string sorting algorithm, implementing IComparer in .NET, passing in a custom comparer","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"stringSort","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"sort":"stringSort/api/sort"},"labels":["JavaScript","C#","Cloud"],"featured":false},{"name":"Coffee Machine","subHeading":"Demonstraiting knowledge of asynchrony, multithreading and the State Machine in .NET","description":".NET Web API with a React UI.","searchTerms":"Docker,Cloud,C#,dotnet,.net,Multithreading,Async,Asynchronous,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"coffeeMachine","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"master_react","endpoints":{"run":"coffeeMachine/api/run","runAsync":"coffeeMachine/api/runasync"},"labels":["JavaScript","C#","Cloud"],"order":3},{"name":"AFrame React Example","subHeading":"An example AFrame application with React, allowing for user input","description":"Exploring WebXR applications using AFrame and React. Compiled with Babel and Webpack.","searchTerms":"Docker,JavaScript,AFrame,Babel,Webpack,PUG,HTML,CSS,SASS,VR,Virtual Reality","folder":"aframeComplex","active":true,"include":true,"useWebpack":true,"labels":["JavaScript"]},{"name":"JS Coding Standards","subHeading":"A JavaScript Code Style Guide","description":"By Fabio Sereno","searchTerms":"Docker,JavaScript,SOLID Principles,YAGNI,DRY,KISS","folder":"jsCodingStandards","active":false,"include":false,"labels":["JavaScript"]},{"name":"Basic React Email Client","subHeading":"An SPA using React and React Router. React Context and useReducer handle state. Optimised with useCallback, useMemo and React.memo","description":"Using React, Babel and Webpack.","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"basicEmailClientReactSpa","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicSpaReact","labels":["JavaScript"],"order":2,"featured":false},{"name":"NodeJS, To-Do List SPA","subHeading":"A simple To-Do list application, with user registration and authentication","description":"NodeJS Web API with a React UI.","searchTerms":"Docker,NodeJS,Express,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"nodeToDo","active":true,"include":true,"useWebpack":true,"masterTemplateDir":"basicEmailClientReactSpa","labels":["JavaScript","Cloud","NodeJS"],"order":1,"featured":false,"endpoints":{"base":"nodeToDo"}},{"name":"Master React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"master_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]},{"name":"Test React Template","subHeading":"Subheading","description":"Description","searchTerms":"Docker,JavaScript,React,Babel,Webpack,PUG,HTML,CSS,SASS","folder":"new_react","masterTemplateDir":"toDoReact","active":true,"include":false,"useWebpack":true,"labels":["JavaScript"]}]}');function i(e,t){for(var n=0;n0?t[0]:r}}],null&&i(t.prototype,null),n&&i(t,n),e}()},734:function(e,t,n){!function(e,t,n){"use strict";function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var i=r(t),o=r(n);function a(e,t){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};f.jQueryDetection(),i.default.fn.emulateTransitionEnd=c,i.default.event.special[f.TRANSITION_END]={bindType:s,delegateType:s,handle:function(e){if(i.default(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}};var d="bs.alert",p=i.default.fn.alert,h=function(){function e(e){this._element=e}var t=e.prototype;return t.close=function(e){var t=this._element;e&&(t=this._getRootElement(e)),this._triggerCloseEvent(t).isDefaultPrevented()||this._removeElement(t)},t.dispose=function(){i.default.removeData(this._element,d),this._element=null},t._getRootElement=function(e){var t=f.getSelectorFromElement(e),n=!1;return t&&(n=document.querySelector(t)),n||(n=i.default(e).closest(".alert")[0]),n},t._triggerCloseEvent=function(e){var t=i.default.Event("close.bs.alert");return i.default(e).trigger(t),t},t._removeElement=function(e){var t=this;if(i.default(e).removeClass("show"),i.default(e).hasClass("fade")){var n=f.getTransitionDurationFromElement(e);i.default(e).one(f.TRANSITION_END,(function(n){return t._destroyElement(e,n)})).emulateTransitionEnd(n)}else this._destroyElement(e)},t._destroyElement=function(e){i.default(e).detach().trigger("closed.bs.alert").remove()},e._jQueryInterface=function(t){return this.each((function(){var n=i.default(this),r=n.data(d);r||(r=new e(this),n.data(d,r)),"close"===t&&r[t](this)}))},e._handleDismiss=function(e){return function(t){t&&t.preventDefault(),e.close(this)}},l(e,null,[{key:"VERSION",get:function(){return"4.6.0"}}]),e}();i.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',h._handleDismiss(new h)),i.default.fn.alert=h._jQueryInterface,i.default.fn.alert.Constructor=h,i.default.fn.alert.noConflict=function(){return i.default.fn.alert=p,h._jQueryInterface};var m="bs.button",g=i.default.fn.button,v="active",y='[data-toggle^="button"]',b='input:not([type="hidden"])',w=".btn",_=function(){function e(e){this._element=e,this.shouldAvoidTriggerChange=!1}var t=e.prototype;return t.toggle=function(){var e=!0,t=!0,n=i.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var r=this._element.querySelector(b);if(r){if("radio"===r.type)if(r.checked&&this._element.classList.contains(v))e=!1;else{var o=n.querySelector(".active");o&&i.default(o).removeClass(v)}e&&("checkbox"!==r.type&&"radio"!==r.type||(r.checked=!this._element.classList.contains(v)),this.shouldAvoidTriggerChange||i.default(r).trigger("change")),r.focus(),t=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(t&&this._element.setAttribute("aria-pressed",!this._element.classList.contains(v)),e&&i.default(this._element).toggleClass(v))},t.dispose=function(){i.default.removeData(this._element,m),this._element=null},e._jQueryInterface=function(t,n){return this.each((function(){var r=i.default(this),o=r.data(m);o||(o=new e(this),r.data(m,o)),o.shouldAvoidTriggerChange=n,"toggle"===t&&o[t]()}))},l(e,null,[{key:"VERSION",get:function(){return"4.6.0"}}]),e}();i.default(document).on("click.bs.button.data-api",y,(function(e){var t=e.target,n=t;if(i.default(t).hasClass("btn")||(t=i.default(t).closest(w)[0]),!t||t.hasAttribute("disabled")||t.classList.contains("disabled"))e.preventDefault();else{var r=t.querySelector(b);if(r&&(r.hasAttribute("disabled")||r.classList.contains("disabled")))return void e.preventDefault();"INPUT"!==n.tagName&&"LABEL"===t.tagName||_._jQueryInterface.call(i.default(t),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",y,(function(e){var t=i.default(e.target).closest(w)[0];i.default(t).toggleClass("focus",/^focus(in)?$/.test(e.type))})),i.default(window).on("load.bs.button.data-api",(function(){for(var e=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),t=0,n=e.length;t0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var t=e.prototype;return t.next=function(){this._isSliding||this._slide(N)},t.nextWhenVisible=function(){var e=i.default(this._element);!document.hidden&&e.is(":visible")&&"hidden"!==e.css("visibility")&&this.next()},t.prev=function(){this._isSliding||this._slide(D)},t.pause=function(e){e||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(f.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},t.cycle=function(e){e||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},t.to=function(e){var t=this;this._activeElement=this._element.querySelector(O);var n=this._getItemIndex(this._activeElement);if(!(e>this._items.length-1||e<0))if(this._isSliding)i.default(this._element).one(A,(function(){return t.to(e)}));else{if(n===e)return this.pause(),void this.cycle();var r=e>n?N:D;this._slide(r,this._items[e])}},t.dispose=function(){i.default(this._element).off(T),i.default.removeData(this._element,x),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},t._getConfig=function(e){return e=u({},S,e),f.typeCheckConfig(E,e,C),e},t._handleSwipe=function(){var e=Math.abs(this.touchDeltaX);if(!(e<=40)){var t=e/this.touchDeltaX;this.touchDeltaX=0,t>0&&this.prev(),t<0&&this.next()}},t._addEventListeners=function(){var e=this;this._config.keyboard&&i.default(this._element).on("keydown.bs.carousel",(function(t){return e._keydown(t)})),"hover"===this._config.pause&&i.default(this._element).on("mouseenter.bs.carousel",(function(t){return e.pause(t)})).on("mouseleave.bs.carousel",(function(t){return e.cycle(t)})),this._config.touch&&this._addTouchEventListeners()},t._addTouchEventListeners=function(){var e=this;if(this._touchSupported){var t=function(t){e._pointerEvent&&I[t.originalEvent.pointerType.toUpperCase()]?e.touchStartX=t.originalEvent.clientX:e._pointerEvent||(e.touchStartX=t.originalEvent.touches[0].clientX)},n=function(t){e._pointerEvent&&I[t.originalEvent.pointerType.toUpperCase()]&&(e.touchDeltaX=t.originalEvent.clientX-e.touchStartX),e._handleSwipe(),"hover"===e._config.pause&&(e.pause(),e.touchTimeout&&clearTimeout(e.touchTimeout),e.touchTimeout=setTimeout((function(t){return e.cycle(t)}),500+e._config.interval))};i.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(e){return e.preventDefault()})),this._pointerEvent?(i.default(this._element).on("pointerdown.bs.carousel",(function(e){return t(e)})),i.default(this._element).on("pointerup.bs.carousel",(function(e){return n(e)})),this._element.classList.add("pointer-event")):(i.default(this._element).on("touchstart.bs.carousel",(function(e){return t(e)})),i.default(this._element).on("touchmove.bs.carousel",(function(t){return function(t){t.originalEvent.touches&&t.originalEvent.touches.length>1?e.touchDeltaX=0:e.touchDeltaX=t.originalEvent.touches[0].clientX-e.touchStartX}(t)})),i.default(this._element).on("touchend.bs.carousel",(function(e){return n(e)})))}},t._keydown=function(e){if(!/input|textarea/i.test(e.target.tagName))switch(e.which){case 37:e.preventDefault(),this.prev();break;case 39:e.preventDefault(),this.next()}},t._getItemIndex=function(e){return this._items=e&&e.parentNode?[].slice.call(e.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(e)},t._getItemByDirection=function(e,t){var n=e===N,r=e===D,i=this._getItemIndex(t),o=this._items.length-1;if((r&&0===i||n&&i===o)&&!this._config.wrap)return t;var a=(i+(e===D?-1:1))%this._items.length;return-1===a?this._items[this._items.length-1]:this._items[a]},t._triggerSlideEvent=function(e,t){var n=this._getItemIndex(e),r=this._getItemIndex(this._element.querySelector(O)),o=i.default.Event("slide.bs.carousel",{relatedTarget:e,direction:t,from:r,to:n});return i.default(this._element).trigger(o),o},t._setActiveIndicatorElement=function(e){if(this._indicatorsElement){var t=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));i.default(t).removeClass(P);var n=this._indicatorsElement.children[this._getItemIndex(e)];n&&i.default(n).addClass(P)}},t._updateInterval=function(){var e=this._activeElement||this._element.querySelector(O);if(e){var t=parseInt(e.getAttribute("data-interval"),10);t?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=t):this._config.interval=this._config.defaultInterval||this._config.interval}},t._slide=function(e,t){var n,r,o,a=this,l=this._element.querySelector(O),u=this._getItemIndex(l),s=t||l&&this._getItemByDirection(e,l),c=this._getItemIndex(s),d=Boolean(this._interval);if(e===N?(n="carousel-item-left",r="carousel-item-next",o="left"):(n="carousel-item-right",r="carousel-item-prev",o="right"),s&&i.default(s).hasClass(P))this._isSliding=!1;else if(!this._triggerSlideEvent(s,o).isDefaultPrevented()&&l&&s){this._isSliding=!0,d&&this.pause(),this._setActiveIndicatorElement(s),this._activeElement=s;var p=i.default.Event(A,{relatedTarget:s,direction:o,from:u,to:c});if(i.default(this._element).hasClass("slide")){i.default(s).addClass(r),f.reflow(s),i.default(l).addClass(n),i.default(s).addClass(n);var h=f.getTransitionDurationFromElement(l);i.default(l).one(f.TRANSITION_END,(function(){i.default(s).removeClass(n+" "+r).addClass(P),i.default(l).removeClass("active "+r+" "+n),a._isSliding=!1,setTimeout((function(){return i.default(a._element).trigger(p)}),0)})).emulateTransitionEnd(h)}else i.default(l).removeClass(P),i.default(s).addClass(P),this._isSliding=!1,i.default(this._element).trigger(p);d&&this.cycle()}},e._jQueryInterface=function(t){return this.each((function(){var n=i.default(this).data(x),r=u({},S,i.default(this).data());"object"==typeof t&&(r=u({},r,t));var o="string"==typeof t?t:r.slide;if(n||(n=new e(this,r),i.default(this).data(x,n)),"number"==typeof t)n.to(t);else if("string"==typeof o){if(void 0===n[o])throw new TypeError('No method named "'+o+'"');n[o]()}else r.interval&&r.ride&&(n.pause(),n.cycle())}))},e._dataApiClickHandler=function(t){var n=f.getSelectorFromElement(this);if(n){var r=i.default(n)[0];if(r&&i.default(r).hasClass("carousel")){var o=u({},i.default(r).data(),i.default(this).data()),a=this.getAttribute("data-slide-to");a&&(o.interval=!1),e._jQueryInterface.call(i.default(r),o),a&&i.default(r).data(x).to(a),t.preventDefault()}}},l(e,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return S}}]),e}();i.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",L._dataApiClickHandler),i.default(window).on("load.bs.carousel.data-api",(function(){for(var e=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),t=0,n=e.length;t0&&(this._selector=a,this._triggerArray.push(o))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var t=e.prototype;return t.toggle=function(){i.default(this._element).hasClass(q)?this.hide():this.show()},t.show=function(){var t,n,r=this;if(!(this._isTransitioning||i.default(this._element).hasClass(q)||(this._parent&&0===(t=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(e){return"string"==typeof r._config.parent?e.getAttribute("data-parent")===r._config.parent:e.classList.contains(z)}))).length&&(t=null),t&&(n=i.default(t).not(this._selector).data(R))&&n._isTransitioning))){var o=i.default.Event("show.bs.collapse");if(i.default(this._element).trigger(o),!o.isDefaultPrevented()){t&&(e._jQueryInterface.call(i.default(t).not(this._selector),"hide"),n||i.default(t).data(R,null));var a=this._getDimension();i.default(this._element).removeClass(z).addClass(W),this._element.style[a]=0,this._triggerArray.length&&i.default(this._triggerArray).removeClass(B).attr("aria-expanded",!0),this.setTransitioning(!0);var l="scroll"+(a[0].toUpperCase()+a.slice(1)),u=f.getTransitionDurationFromElement(this._element);i.default(this._element).one(f.TRANSITION_END,(function(){i.default(r._element).removeClass(W).addClass("collapse show"),r._element.style[a]="",r.setTransitioning(!1),i.default(r._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(u),this._element.style[a]=this._element[l]+"px"}}},t.hide=function(){var e=this;if(!this._isTransitioning&&i.default(this._element).hasClass(q)){var t=i.default.Event("hide.bs.collapse");if(i.default(this._element).trigger(t),!t.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",f.reflow(this._element),i.default(this._element).addClass(W).removeClass("collapse show");var r=this._triggerArray.length;if(r>0)for(var o=0;o0},t._getOffset=function(){var e=this,t={};return"function"==typeof this._config.offset?t.fn=function(t){return t.offsets=u({},t.offsets,e._config.offset(t.offsets,e._element)||{}),t}:t.offset=this._config.offset,t},t._getPopperConfig=function(){var e={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(e.modifiers.applyStyle={enabled:!1}),u({},e,this._config.popperConfig)},e._jQueryInterface=function(t){return this.each((function(){var n=i.default(this).data(K);if(n||(n=new e(this,"object"==typeof t?t:null),i.default(this).data(K,n)),"string"==typeof t){if(void 0===n[t])throw new TypeError('No method named "'+t+'"');n[t]()}}))},e._clearMenus=function(t){if(!t||3!==t.which&&("keyup"!==t.type||9===t.which))for(var n=[].slice.call(document.querySelectorAll(oe)),r=0,o=n.length;r0&&a--,40===t.which&&adocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add(Se);var r=f.getTransitionDurationFromElement(this._dialog);i.default(this._element).off(f.TRANSITION_END),i.default(this._element).one(f.TRANSITION_END,(function(){e._element.classList.remove(Se),n||i.default(e._element).one(f.TRANSITION_END,(function(){e._element.style.overflowY=""})).emulateTransitionEnd(e._element,r)})).emulateTransitionEnd(r),this._element.focus()}},t._showElement=function(e){var t=this,n=i.default(this._element).hasClass(Te),r=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),i.default(this._dialog).hasClass("modal-dialog-scrollable")&&r?r.scrollTop=0:this._element.scrollTop=0,n&&f.reflow(this._element),i.default(this._element).addClass(ke),this._config.focus&&this._enforceFocus();var o=i.default.Event("shown.bs.modal",{relatedTarget:e}),a=function(){t._config.focus&&t._element.focus(),t._isTransitioning=!1,i.default(t._element).trigger(o)};if(n){var l=f.getTransitionDurationFromElement(this._dialog);i.default(this._dialog).one(f.TRANSITION_END,a).emulateTransitionEnd(l)}else a()},t._enforceFocus=function(){var e=this;i.default(document).off(ye).on(ye,(function(t){document!==t.target&&e._element!==t.target&&0===i.default(e._element).has(t.target).length&&e._element.focus()}))},t._setEscapeEvent=function(){var e=this;this._isShown?i.default(this._element).on(_e,(function(t){e._config.keyboard&&27===t.which?(t.preventDefault(),e.hide()):e._config.keyboard||27!==t.which||e._triggerBackdropTransition()})):this._isShown||i.default(this._element).off(_e)},t._setResizeEvent=function(){var e=this;this._isShown?i.default(window).on(be,(function(t){return e.handleUpdate(t)})):i.default(window).off(be)},t._hideModal=function(){var e=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){i.default(document.body).removeClass(xe),e._resetAdjustments(),e._resetScrollbar(),i.default(e._element).trigger(ge)}))},t._removeBackdrop=function(){this._backdrop&&(i.default(this._backdrop).remove(),this._backdrop=null)},t._showBackdrop=function(e){var t=this,n=i.default(this._element).hasClass(Te)?Te:"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),i.default(this._backdrop).appendTo(document.body),i.default(this._element).on(we,(function(e){t._ignoreBackdropClick?t._ignoreBackdropClick=!1:e.target===e.currentTarget&&("static"===t._config.backdrop?t._triggerBackdropTransition():t.hide())})),n&&f.reflow(this._backdrop),i.default(this._backdrop).addClass(ke),!e)return;if(!n)return void e();var r=f.getTransitionDurationFromElement(this._backdrop);i.default(this._backdrop).one(f.TRANSITION_END,e).emulateTransitionEnd(r)}else if(!this._isShown&&this._backdrop){i.default(this._backdrop).removeClass(ke);var o=function(){t._removeBackdrop(),e&&e()};if(i.default(this._element).hasClass(Te)){var a=f.getTransitionDurationFromElement(this._backdrop);i.default(this._backdrop).one(f.TRANSITION_END,o).emulateTransitionEnd(a)}else o()}else e&&e()},t._adjustDialog=function(){var e=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&e&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!e&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var e=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(e.left+e.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Be="show",Ue="out",Qe={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},Ve="fade",$e="show",Ke="hover",Xe="focus",Ye=function(){function e(e,t){if(void 0===o.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=e,this.config=this._getConfig(t),this.tip=null,this._setListeners()}var t=e.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(e){if(this._isEnabled)if(e){var t=this.constructor.DATA_KEY,n=i.default(e.currentTarget).data(t);n||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),i.default(e.currentTarget).data(t,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(i.default(this.getTipElement()).hasClass($e))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),i.default.removeData(this.element,this.constructor.DATA_KEY),i.default(this.element).off(this.constructor.EVENT_KEY),i.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&i.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===i.default(this.element).css("display"))throw new Error("Please use show on visible elements");var t=i.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){i.default(this.element).trigger(t);var n=f.findShadowRoot(this.element),r=i.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!r)return;var a=this.getTipElement(),l=f.getUID(this.constructor.NAME);a.setAttribute("id",l),this.element.setAttribute("aria-describedby",l),this.setContent(),this.config.animation&&i.default(a).addClass(Ve);var u="function"==typeof this.config.placement?this.config.placement.call(this,a,this.element):this.config.placement,s=this._getAttachment(u);this.addAttachmentClass(s);var c=this._getContainer();i.default(a).data(this.constructor.DATA_KEY,this),i.default.contains(this.element.ownerDocument.documentElement,this.tip)||i.default(a).appendTo(c),i.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new o.default(this.element,a,this._getPopperConfig(s)),i.default(a).addClass($e),i.default(a).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&i.default(document.body).children().on("mouseover",null,i.default.noop);var d=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,i.default(e.element).trigger(e.constructor.Event.SHOWN),t===Ue&&e._leave(null,e)};if(i.default(this.tip).hasClass(Ve)){var p=f.getTransitionDurationFromElement(this.tip);i.default(this.tip).one(f.TRANSITION_END,d).emulateTransitionEnd(p)}else d()}},t.hide=function(e){var t=this,n=this.getTipElement(),r=i.default.Event(this.constructor.Event.HIDE),o=function(){t._hoverState!==Be&&n.parentNode&&n.parentNode.removeChild(n),t._cleanTipClass(),t.element.removeAttribute("aria-describedby"),i.default(t.element).trigger(t.constructor.Event.HIDDEN),null!==t._popper&&t._popper.destroy(),e&&e()};if(i.default(this.element).trigger(r),!r.isDefaultPrevented()){if(i.default(n).removeClass($e),"ontouchstart"in document.documentElement&&i.default(document.body).children().off("mouseover",null,i.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,i.default(this.tip).hasClass(Ve)){var a=f.getTransitionDurationFromElement(n);i.default(n).one(f.TRANSITION_END,o).emulateTransitionEnd(a)}else o();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(e){i.default(this.getTipElement()).addClass("bs-tooltip-"+e)},t.getTipElement=function(){return this.tip=this.tip||i.default(this.config.template)[0],this.tip},t.setContent=function(){var e=this.getTipElement();this.setElementContent(i.default(e.querySelectorAll(".tooltip-inner")),this.getTitle()),i.default(e).removeClass("fade show")},t.setElementContent=function(e,t){"object"!=typeof t||!t.nodeType&&!t.jquery?this.config.html?(this.config.sanitize&&(t=Ie(t,this.config.whiteList,this.config.sanitizeFn)),e.html(t)):e.text(t):this.config.html?i.default(t).parent().is(e)||e.empty().append(t):e.text(i.default(t).text())},t.getTitle=function(){var e=this.element.getAttribute("data-original-title");return e||(e="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),e},t._getPopperConfig=function(e){var t=this;return u({},{placement:e,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(e){e.originalPlacement!==e.placement&&t._handlePopperPlacementChange(e)},onUpdate:function(e){return t._handlePopperPlacementChange(e)}},this.config.popperConfig)},t._getOffset=function(){var e=this,t={};return"function"==typeof this.config.offset?t.fn=function(t){return t.offsets=u({},t.offsets,e.config.offset(t.offsets,e.element)||{}),t}:t.offset=this.config.offset,t},t._getContainer=function(){return!1===this.config.container?document.body:f.isElement(this.config.container)?i.default(this.config.container):i.default(document).find(this.config.container)},t._getAttachment=function(e){return ze[e.toUpperCase()]},t._setListeners=function(){var e=this;this.config.trigger.split(" ").forEach((function(t){if("click"===t)i.default(e.element).on(e.constructor.Event.CLICK,e.config.selector,(function(t){return e.toggle(t)}));else if("manual"!==t){var n=t===Ke?e.constructor.Event.MOUSEENTER:e.constructor.Event.FOCUSIN,r=t===Ke?e.constructor.Event.MOUSELEAVE:e.constructor.Event.FOCUSOUT;i.default(e.element).on(n,e.config.selector,(function(t){return e._enter(t)})).on(r,e.config.selector,(function(t){return e._leave(t)}))}})),this._hideModalHandler=function(){e.element&&e.hide()},i.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=u({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var e=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==e)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(e,t){var n=this.constructor.DATA_KEY;(t=t||i.default(e.currentTarget).data(n))||(t=new this.constructor(e.currentTarget,this._getDelegateConfig()),i.default(e.currentTarget).data(n,t)),e&&(t._activeTrigger["focusin"===e.type?Xe:Ke]=!0),i.default(t.getTipElement()).hasClass($e)||t._hoverState===Be?t._hoverState=Be:(clearTimeout(t._timeout),t._hoverState=Be,t.config.delay&&t.config.delay.show?t._timeout=setTimeout((function(){t._hoverState===Be&&t.show()}),t.config.delay.show):t.show())},t._leave=function(e,t){var n=this.constructor.DATA_KEY;(t=t||i.default(e.currentTarget).data(n))||(t=new this.constructor(e.currentTarget,this._getDelegateConfig()),i.default(e.currentTarget).data(n,t)),e&&(t._activeTrigger["focusout"===e.type?Xe:Ke]=!1),t._isWithActiveTrigger()||(clearTimeout(t._timeout),t._hoverState=Ue,t.config.delay&&t.config.delay.hide?t._timeout=setTimeout((function(){t._hoverState===Ue&&t.hide()}),t.config.delay.hide):t.hide())},t._isWithActiveTrigger=function(){for(var e in this._activeTrigger)if(this._activeTrigger[e])return!0;return!1},t._getConfig=function(e){var t=i.default(this.element).data();return Object.keys(t).forEach((function(e){-1!==He.indexOf(e)&&delete t[e]})),"number"==typeof(e=u({},this.constructor.Default,t,"object"==typeof e&&e?e:{})).delay&&(e.delay={show:e.delay,hide:e.delay}),"number"==typeof e.title&&(e.title=e.title.toString()),"number"==typeof e.content&&(e.content=e.content.toString()),f.typeCheckConfig(Le,e,this.constructor.DefaultType),e.sanitize&&(e.template=Ie(e.template,e.whiteList,e.sanitizeFn)),e},t._getDelegateConfig=function(){var e={};if(this.config)for(var t in this.config)this.constructor.Default[t]!==this.config[t]&&(e[t]=this.config[t]);return e},t._cleanTipClass=function(){var e=i.default(this.getTipElement()),t=e.attr("class").match(Fe);null!==t&&t.length&&e.removeClass(t.join(""))},t._handlePopperPlacementChange=function(e){this.tip=e.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(e.placement))},t._fixTransition=function(){var e=this.getTipElement(),t=this.config.animation;null===e.getAttribute("x-placement")&&(i.default(e).removeClass(Ve),this.config.animation=!1,this.hide(),this.show(),this.config.animation=t)},e._jQueryInterface=function(t){return this.each((function(){var n=i.default(this),r=n.data(je),o="object"==typeof t&&t;if((r||!/dispose|hide/.test(t))&&(r||(r=new e(this,o),n.data(je,r)),"string"==typeof t)){if(void 0===r[t])throw new TypeError('No method named "'+t+'"');r[t]()}}))},l(e,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return We}},{key:"NAME",get:function(){return Le}},{key:"DATA_KEY",get:function(){return je}},{key:"Event",get:function(){return Qe}},{key:"EVENT_KEY",get:function(){return Re}},{key:"DefaultType",get:function(){return qe}}]),e}();i.default.fn.tooltip=Ye._jQueryInterface,i.default.fn.tooltip.Constructor=Ye,i.default.fn.tooltip.noConflict=function(){return i.default.fn.tooltip=Me,Ye._jQueryInterface};var Je="popover",Ge="bs.popover",Ze=".bs.popover",et=i.default.fn.popover,tt=new RegExp("(^|\\s)bs-popover\\S+","g"),nt=u({},Ye.Default,{placement:"right",trigger:"click",content:"",template:''}),rt=u({},Ye.DefaultType,{content:"(string|element|function)"}),it={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},ot=function(e){function t(){return e.apply(this,arguments)||this}var n,r;r=e,(n=t).prototype=Object.create(r.prototype),n.prototype.constructor=n,n.__proto__=r;var o=t.prototype;return o.isWithContent=function(){return this.getTitle()||this._getContent()},o.addAttachmentClass=function(e){i.default(this.getTipElement()).addClass("bs-popover-"+e)},o.getTipElement=function(){return this.tip=this.tip||i.default(this.config.template)[0],this.tip},o.setContent=function(){var e=i.default(this.getTipElement());this.setElementContent(e.find(".popover-header"),this.getTitle());var t=this._getContent();"function"==typeof t&&(t=t.call(this.element)),this.setElementContent(e.find(".popover-body"),t),e.removeClass("fade show")},o._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},o._cleanTipClass=function(){var e=i.default(this.getTipElement()),t=e.attr("class").match(tt);null!==t&&t.length>0&&e.removeClass(t.join(""))},t._jQueryInterface=function(e){return this.each((function(){var n=i.default(this).data(Ge),r="object"==typeof e?e:null;if((n||!/dispose|hide/.test(e))&&(n||(n=new t(this,r),i.default(this).data(Ge,n)),"string"==typeof e)){if(void 0===n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},l(t,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return nt}},{key:"NAME",get:function(){return Je}},{key:"DATA_KEY",get:function(){return Ge}},{key:"Event",get:function(){return it}},{key:"EVENT_KEY",get:function(){return Ze}},{key:"DefaultType",get:function(){return rt}}]),t}(Ye);i.default.fn.popover=ot._jQueryInterface,i.default.fn.popover.Constructor=ot,i.default.fn.popover.noConflict=function(){return i.default.fn.popover=et,ot._jQueryInterface};var at="scrollspy",lt="bs.scrollspy",ut="."+lt,st=i.default.fn[at],ct={offset:10,method:"auto",target:""},ft={offset:"number",method:"string",target:"(string|element)"},dt="active",pt=".nav, .list-group",ht=".nav-link",mt="position",gt=function(){function e(e,t){var n=this;this._element=e,this._scrollElement="BODY"===e.tagName?window:e,this._config=this._getConfig(t),this._selector=this._config.target+" "+".nav-link,"+this._config.target+" "+".list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,i.default(this._scrollElement).on("scroll.bs.scrollspy",(function(e){return n._process(e)})),this.refresh(),this._process()}var t=e.prototype;return t.refresh=function(){var e=this,t=this._scrollElement===this._scrollElement.window?"offset":mt,n="auto"===this._config.method?t:this._config.method,r=n===mt?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(e){var t,o=f.getSelectorFromElement(e);if(o&&(t=document.querySelector(o)),t){var a=t.getBoundingClientRect();if(a.width||a.height)return[i.default(t)[n]().top+r,o]}return null})).filter((function(e){return e})).sort((function(e,t){return e[0]-t[0]})).forEach((function(t){e._offsets.push(t[0]),e._targets.push(t[1])}))},t.dispose=function(){i.default.removeData(this._element,lt),i.default(this._scrollElement).off(ut),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},t._getConfig=function(e){if("string"!=typeof(e=u({},ct,"object"==typeof e&&e?e:{})).target&&f.isElement(e.target)){var t=i.default(e.target).attr("id");t||(t=f.getUID(at),i.default(e.target).attr("id",t)),e.target="#"+t}return f.typeCheckConfig(at,e,ft),e},t._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},t._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},t._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},t._process=function(){var e=this._getScrollTop()+this._config.offset,t=this._getScrollHeight(),n=this._config.offset+t-this._getOffsetHeight();if(this._scrollHeight!==t&&this.refresh(),e>=n){var r=this._targets[this._targets.length-1];this._activeTarget!==r&&this._activate(r)}else{if(this._activeTarget&&e0)return this._activeTarget=null,void this._clear();for(var i=this._offsets.length;i--;)this._activeTarget!==this._targets[i]&&e>=this._offsets[i]&&(void 0===this._offsets[i+1]||e li > .active",Tt=function(){function e(e){this._element=e}var t=e.prototype;return t.show=function(){var e=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&i.default(this._element).hasClass(bt)||i.default(this._element).hasClass("disabled"))){var t,n,r=i.default(this._element).closest(".nav, .list-group")[0],o=f.getSelectorFromElement(this._element);if(r){var a="UL"===r.nodeName||"OL"===r.nodeName?xt:Et;n=(n=i.default.makeArray(i.default(r).find(a)))[n.length-1]}var l=i.default.Event("hide.bs.tab",{relatedTarget:this._element}),u=i.default.Event("show.bs.tab",{relatedTarget:n});if(n&&i.default(n).trigger(l),i.default(this._element).trigger(u),!u.isDefaultPrevented()&&!l.isDefaultPrevented()){o&&(t=document.querySelector(o)),this._activate(this._element,r);var s=function(){var t=i.default.Event("hidden.bs.tab",{relatedTarget:e._element}),r=i.default.Event("shown.bs.tab",{relatedTarget:n});i.default(n).trigger(t),i.default(e._element).trigger(r)};t?this._activate(t,t.parentNode,s):s()}}},t.dispose=function(){i.default.removeData(this._element,vt),this._element=null},t._activate=function(e,t,n){var r=this,o=(!t||"UL"!==t.nodeName&&"OL"!==t.nodeName?i.default(t).children(Et):i.default(t).find(xt))[0],a=n&&o&&i.default(o).hasClass(wt),l=function(){return r._transitionComplete(e,o,n)};if(o&&a){var u=f.getTransitionDurationFromElement(o);i.default(o).removeClass(_t).one(f.TRANSITION_END,l).emulateTransitionEnd(u)}else l()},t._transitionComplete=function(e,t,n){if(t){i.default(t).removeClass(bt);var r=i.default(t.parentNode).find("> .dropdown-menu .active")[0];r&&i.default(r).removeClass(bt),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!1)}if(i.default(e).addClass(bt),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!0),f.reflow(e),e.classList.contains(wt)&&e.classList.add(_t),e.parentNode&&i.default(e.parentNode).hasClass("dropdown-menu")){var o=i.default(e).closest(".dropdown")[0];if(o){var a=[].slice.call(o.querySelectorAll(".dropdown-toggle"));i.default(a).addClass(bt)}e.setAttribute("aria-expanded",!0)}n&&n()},e._jQueryInterface=function(t){return this.each((function(){var n=i.default(this),r=n.data(vt);if(r||(r=new e(this),n.data(vt,r)),"string"==typeof t){if(void 0===r[t])throw new TypeError('No method named "'+t+'"');r[t]()}}))},l(e,null,[{key:"VERSION",get:function(){return"4.6.0"}}]),e}();i.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(e){e.preventDefault(),Tt._jQueryInterface.call(i.default(this),"show")})),i.default.fn.tab=Tt._jQueryInterface,i.default.fn.tab.Constructor=Tt,i.default.fn.tab.noConflict=function(){return i.default.fn.tab=yt,Tt._jQueryInterface};var kt="toast",St="bs.toast",Ct=i.default.fn.toast,Nt="click.dismiss.bs.toast",Dt="hide",At="show",Pt="showing",Ot={animation:"boolean",autohide:"boolean",delay:"number"},It={animation:!0,autohide:!0,delay:500},Lt=function(){function e(e,t){this._element=e,this._config=this._getConfig(t),this._timeout=null,this._setListeners()}var t=e.prototype;return t.show=function(){var e=this,t=i.default.Event("show.bs.toast");if(i.default(this._element).trigger(t),!t.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){e._element.classList.remove(Pt),e._element.classList.add(At),i.default(e._element).trigger("shown.bs.toast"),e._config.autohide&&(e._timeout=setTimeout((function(){e.hide()}),e._config.delay))};if(this._element.classList.remove(Dt),f.reflow(this._element),this._element.classList.add(Pt),this._config.animation){var r=f.getTransitionDurationFromElement(this._element);i.default(this._element).one(f.TRANSITION_END,n).emulateTransitionEnd(r)}else n()}},t.hide=function(){if(this._element.classList.contains(At)){var e=i.default.Event("hide.bs.toast");i.default(this._element).trigger(e),e.isDefaultPrevented()||this._close()}},t.dispose=function(){this._clearTimeout(),this._element.classList.contains(At)&&this._element.classList.remove(At),i.default(this._element).off(Nt),i.default.removeData(this._element,St),this._element=null,this._config=null},t._getConfig=function(e){return e=u({},It,i.default(this._element).data(),"object"==typeof e&&e?e:{}),f.typeCheckConfig(kt,e,this.constructor.DefaultType),e},t._setListeners=function(){var e=this;i.default(this._element).on(Nt,'[data-dismiss="toast"]',(function(){return e.hide()}))},t._close=function(){var e=this,t=function(){e._element.classList.add(Dt),i.default(e._element).trigger("hidden.bs.toast")};if(this._element.classList.remove(At),this._config.animation){var n=f.getTransitionDurationFromElement(this._element);i.default(this._element).one(f.TRANSITION_END,t).emulateTransitionEnd(n)}else t()},t._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},e._jQueryInterface=function(t){return this.each((function(){var n=i.default(this),r=n.data(St);if(r||(r=new e(this,"object"==typeof t&&t),n.data(St,r)),"string"==typeof t){if(void 0===r[t])throw new TypeError('No method named "'+t+'"');r[t](this)}}))},l(e,null,[{key:"VERSION",get:function(){return"4.6.0"}},{key:"DefaultType",get:function(){return Ot}},{key:"Default",get:function(){return It}}]),e}();i.default.fn.toast=Lt._jQueryInterface,i.default.fn.toast.Constructor=Lt,i.default.fn.toast.noConflict=function(){return i.default.fn.toast=Ct,Lt._jQueryInterface},e.Alert=h,e.Button=_,e.Carousel=L,e.Collapse=V,e.Dropdown=se,e.Modal=De,e.Popover=ot,e.Scrollspy=gt,e.Tab=Tt,e.Toast=Lt,e.Tooltip=Ye,e.Util=f,Object.defineProperty(e,"__esModule",{value:!0})}(t,n(755),n(981))},755:function(e,t){var n;!function(t,n){"use strict";"object"==typeof e.exports?e.exports=t.document?n(t,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return n(e)}:n(t)}("undefined"!=typeof window?window:this,(function(r,i){"use strict";var o=[],a=Object.getPrototypeOf,l=o.slice,u=o.flat?function(e){return o.flat.call(e)}:function(e){return o.concat.apply([],e)},s=o.push,c=o.indexOf,f={},d=f.toString,p=f.hasOwnProperty,h=p.toString,m=h.call(Object),g={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},b=r.document,w={type:!0,src:!0,nonce:!0,noModule:!0};function _(e,t,n){var r,i,o=(n=n||b).createElement("script");if(o.text=e,t)for(r in w)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function E(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?f[d.call(e)]||"object":typeof e}var x="3.6.0",T=function(e,t){return new T.fn.init(e,t)};function k(e){var t=!!e&&"length"in e&&e.length,n=E(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}T.fn=T.prototype={jquery:x,constructor:T,length:0,toArray:function(){return l.call(this)},get:function(e){return null==e?l.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=T.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return T.each(this,e)},map:function(e){return this.pushStack(T.map(this,(function(t,n){return e.call(t,n,t)})))},slice:function(){return this.pushStack(l.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(T.grep(this,(function(e,t){return(t+1)%2})))},odd:function(){return this.pushStack(T.grep(this,(function(e,t){return t%2})))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n+~]|[\\x20\\t\\r\\n\\f])[\\x20\\t\\r\\n\\f]*"),Q=new RegExp(M+"|>"),V=new RegExp(q),$=new RegExp("^"+F+"$"),K={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),TAG:new RegExp("^("+F+"|[*])"),ATTR:new RegExp("^"+H),PSEUDO:new RegExp("^"+q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\([\\x20\\t\\r\\n\\f]*(even|odd|(([+-]|)(\\d*)n|)[\\x20\\t\\r\\n\\f]*(?:([+-]|)[\\x20\\t\\r\\n\\f]*(\\d+)|))[\\x20\\t\\r\\n\\f]*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^[\\x20\\t\\r\\n\\f]*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\([\\x20\\t\\r\\n\\f]*((?:-\\d)?\\d*)[\\x20\\t\\r\\n\\f]*\\)|)(?=[^-]|$)","i")},X=/HTML$/i,Y=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,G=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}[\\x20\\t\\r\\n\\f]?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){d()},ae=we((function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()}),{dir:"parentNode",next:"legend"});try{I.apply(A=L.call(_.childNodes),_.childNodes),A[_.childNodes.length].nodeType}catch(e){I={apply:A.length?function(e,t){O.apply(e,L.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function le(e,t,r,i){var o,l,s,c,f,h,v,y=t&&t.ownerDocument,_=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==_&&9!==_&&11!==_)return r;if(!i&&(d(t),t=t||p,m)){if(11!==_&&(f=Z.exec(e)))if(o=f[1]){if(9===_){if(!(s=t.getElementById(o)))return r;if(s.id===o)return r.push(s),r}else if(y&&(s=y.getElementById(o))&&b(t,s)&&s.id===o)return r.push(s),r}else{if(f[2])return I.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return I.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!C[e+" "]&&(!g||!g.test(e))&&(1!==_||"object"!==t.nodeName.toLowerCase())){if(v=e,y=t,1===_&&(Q.test(e)||U.test(e))){for((y=ee.test(e)&&ve(t.parentNode)||t)===t&&n.scope||((c=t.getAttribute("id"))?c=c.replace(re,ie):t.setAttribute("id",c=w)),l=(h=a(e)).length;l--;)h[l]=(c?"#"+c:":scope")+" "+be(h[l]);v=h.join(",")}try{return I.apply(r,y.querySelectorAll(v)),r}catch(t){C(e,!0)}finally{c===w&&t.removeAttribute("id")}}}return u(e.replace(W,"$1"),t,r,i)}function ue(){var e=[];return function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}}function se(e){return e[w]=!0,e}function ce(e){var t=p.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){for(var n=e.split("|"),i=n.length;i--;)r.attrHandle[n[i]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function pe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function he(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function me(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ae(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function ge(e){return se((function(t){return t=+t,se((function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))}))}))}function ve(e){return e&&void 0!==e.getElementsByTagName&&e}for(t in n=le.support={},o=le.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!X.test(t||n&&n.nodeName||"HTML")},d=le.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:_;return a!=p&&9===a.nodeType&&a.documentElement?(h=(p=a).documentElement,m=!o(p),_!=p&&(i=p.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",oe,!1):i.attachEvent&&i.attachEvent("onunload",oe)),n.scope=ce((function(e){return h.appendChild(e).appendChild(p.createElement("div")),void 0!==e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length})),n.attributes=ce((function(e){return e.className="i",!e.getAttribute("className")})),n.getElementsByTagName=ce((function(e){return e.appendChild(p.createComment("")),!e.getElementsByTagName("*").length})),n.getElementsByClassName=G.test(p.getElementsByClassName),n.getById=ce((function(e){return h.appendChild(e).id=w,!p.getElementsByName||!p.getElementsByName(w).length})),n.getById?(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&m){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&m){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];for(i=t.getElementsByName(e),r=0;o=i[r++];)if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&m)return t.getElementsByClassName(e)},v=[],g=[],(n.qsa=G.test(p.querySelectorAll))&&(ce((function(e){var t;h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&g.push("[*^$]=[\\x20\\t\\r\\n\\f]*(?:''|\"\")"),e.querySelectorAll("[selected]").length||g.push("\\[[\\x20\\t\\r\\n\\f]*(?:value|"+R+")"),e.querySelectorAll("[id~="+w+"-]").length||g.push("~="),(t=p.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||g.push("\\[[\\x20\\t\\r\\n\\f]*name[\\x20\\t\\r\\n\\f]*=[\\x20\\t\\r\\n\\f]*(?:''|\"\")"),e.querySelectorAll(":checked").length||g.push(":checked"),e.querySelectorAll("a#"+w+"+*").length||g.push(".#.+[+~]"),e.querySelectorAll("\\\f"),g.push("[\\r\\n\\f]")})),ce((function(e){e.innerHTML="";var t=p.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&g.push("name[\\x20\\t\\r\\n\\f]*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&g.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")}))),(n.matchesSelector=G.test(y=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ce((function(e){n.disconnectedMatch=y.call(e,"*"),y.call(e,"[s!='']:x"),v.push("!=",q)})),g=g.length&&new RegExp(g.join("|")),v=v.length&&new RegExp(v.join("|")),t=G.test(h.compareDocumentPosition),b=t||G.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},N=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e==p||e.ownerDocument==_&&b(_,e)?-1:t==p||t.ownerDocument==_&&b(_,t)?1:c?j(c,e)-j(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],l=[t];if(!i||!o)return e==p?-1:t==p?1:i?-1:o?1:c?j(c,e)-j(c,t):0;if(i===o)return de(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)l.unshift(n);for(;a[r]===l[r];)r++;return r?de(a[r],l[r]):a[r]==_?-1:l[r]==_?1:0},p):p},le.matches=function(e,t){return le(e,null,null,t)},le.matchesSelector=function(e,t){if(d(e),n.matchesSelector&&m&&!C[t+" "]&&(!v||!v.test(t))&&(!g||!g.test(t)))try{var r=y.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){C(t,!0)}return le(t,p,null,[e]).length>0},le.contains=function(e,t){return(e.ownerDocument||e)!=p&&d(e),b(e,t)},le.attr=function(e,t){(e.ownerDocument||e)!=p&&d(e);var i=r.attrHandle[t.toLowerCase()],o=i&&D.call(r.attrHandle,t.toLowerCase())?i(e,t,!m):void 0;return void 0!==o?o:n.attributes||!m?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},le.escape=function(e){return(e+"").replace(re,ie)},le.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},le.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(N),f){for(;t=e[o++];)t===e[o]&&(i=r.push(o));for(;i--;)e.splice(r[i],1)}return c=null,e},i=le.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r++];)n+=i(t);return n},(r=le.selectors={cacheLength:50,createPseudo:se,match:K,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||le.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&le.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return K.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=T[e+" "];return t||(t=new RegExp("(^|[\\x20\\t\\r\\n\\f])"+e+"("+M+"|$)"))&&T(e,(function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")}))},ATTR:function(e,t,n){return function(r){var i=le.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace(z," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),l="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var s,c,f,d,p,h,m=o!==a?"nextSibling":"previousSibling",g=t.parentNode,v=l&&t.nodeName.toLowerCase(),y=!u&&!l,b=!1;if(g){if(o){for(;m;){for(d=t;d=d[m];)if(l?d.nodeName.toLowerCase()===v:1===d.nodeType)return!1;h=m="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?g.firstChild:g.lastChild],a&&y){for(b=(p=(s=(c=(f=(d=g)[w]||(d[w]={}))[d.uniqueID]||(f[d.uniqueID]={}))[e]||[])[0]===E&&s[1])&&s[2],d=p&&g.childNodes[p];d=++p&&d&&d[m]||(b=p=0)||h.pop();)if(1===d.nodeType&&++b&&d===t){c[e]=[E,p,b];break}}else if(y&&(b=p=(s=(c=(f=(d=t)[w]||(d[w]={}))[d.uniqueID]||(f[d.uniqueID]={}))[e]||[])[0]===E&&s[1]),!1===b)for(;(d=++p&&d&&d[m]||(b=p=0)||h.pop())&&((l?d.nodeName.toLowerCase()!==v:1!==d.nodeType)||!++b||(y&&((c=(f=d[w]||(d[w]={}))[d.uniqueID]||(f[d.uniqueID]={}))[e]=[E,b]),d!==t)););return(b-=i)===r||b%r==0&&b/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||le.error("unsupported pseudo: "+e);return i[w]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se((function(e,n){for(var r,o=i(e,t),a=o.length;a--;)e[r=j(e,o[a])]=!(n[r]=o[a])})):function(e){return i(e,0,n)}):i}},pseudos:{not:se((function(e){var t=[],n=[],r=l(e.replace(W,"$1"));return r[w]?se((function(e,t,n,i){for(var o,a=r(e,null,i,[]),l=e.length;l--;)(o=a[l])&&(e[l]=!(t[l]=o))})):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}})),has:se((function(e){return function(t){return le(e,t).length>0}})),contains:se((function(e){return e=e.replace(te,ne),function(t){return(t.textContent||i(t)).indexOf(e)>-1}})),lang:se((function(e){return $.test(e||"")||le.error("unsupported lang: "+e),e=e.replace(te,ne).toLowerCase(),function(t){var n;do{if(n=m?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}})),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:me(!1),disabled:me(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Y.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ge((function(){return[0]})),last:ge((function(e,t){return[t-1]})),eq:ge((function(e,t,n){return[n<0?n+t:n]})),even:ge((function(e,t){for(var n=0;nt?t:n;--r>=0;)e.push(r);return e})),gt:ge((function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Ee(e,t,n,r,i){for(var o,a=[],l=0,u=e.length,s=null!=t;l-1&&(o[s]=!(a[s]=f))}}else v=Ee(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):I.apply(a,v)}))}function Te(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],l=a||r.relative[" "],u=a?1:0,c=we((function(e){return e===t}),l,!0),f=we((function(e){return j(t,e)>-1}),l,!0),d=[function(e,n,r){var i=!a&&(r||n!==s)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&_e(d),u>1&&be(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(W,"$1"),n,u0,i=e.length>0,o=function(o,a,l,u,c){var f,h,g,v=0,y="0",b=o&&[],w=[],_=s,x=o||i&&r.find.TAG("*",c),T=E+=null==_?1:Math.random()||.1,k=x.length;for(c&&(s=a==p||a||c);y!==k&&null!=(f=x[y]);y++){if(i&&f){for(h=0,a||f.ownerDocument==p||(d(f),l=!m);g=e[h++];)if(g(f,a||p,l)){u.push(f);break}c&&(E=T)}n&&((f=!g&&f)&&v--,o&&b.push(f))}if(v+=y,n&&y!==v){for(h=0;g=t[h++];)g(b,w,a,l);if(o){if(v>0)for(;y--;)b[y]||w[y]||(w[y]=P.call(u));w=Ee(w)}I.apply(u,w),c&&!o&&w.length>0&&v+t.length>1&&le.uniqueSort(u)}return c&&(E=T,s=_),b};return n?se(o):o}(o,i))).selector=e}return l},u=le.select=function(e,t,n,i){var o,u,s,c,f,d="function"==typeof e&&e,p=!i&&a(e=d.selector||e);if(n=n||[],1===p.length){if((u=p[0]=p[0].slice(0)).length>2&&"ID"===(s=u[0]).type&&9===t.nodeType&&m&&r.relative[u[1].type]){if(!(t=(r.find.ID(s.matches[0].replace(te,ne),t)||[])[0]))return n;d&&(t=t.parentNode),e=e.slice(u.shift().value.length)}for(o=K.needsContext.test(e)?0:u.length;o--&&(s=u[o],!r.relative[c=s.type]);)if((f=r.find[c])&&(i=f(s.matches[0].replace(te,ne),ee.test(u[0].type)&&ve(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&be(u)))return I.apply(n,i),n;break}}return(d||l(e,p))(i,t,!m,n,!t||ee.test(e)&&ve(t.parentNode)||t),n},n.sortStable=w.split("").sort(N).join("")===w,n.detectDuplicates=!!f,d(),n.sortDetached=ce((function(e){return 1&e.compareDocumentPosition(p.createElement("fieldset"))})),ce((function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")}))||fe("type|href|height|width",(function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)})),n.attributes&&ce((function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}))||fe("value",(function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue})),ce((function(e){return null==e.getAttribute("disabled")}))||fe(R,(function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null})),le}(r);T.find=S,T.expr=S.selectors,T.expr[":"]=T.expr.pseudos,T.uniqueSort=T.unique=S.uniqueSort,T.text=S.getText,T.isXMLDoc=S.isXML,T.contains=S.contains,T.escapeSelector=S.escape;var C=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&T(e).is(n))break;r.push(e)}return r},N=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=T.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var P=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function O(e,t,n){return v(t)?T.grep(e,(function(e,r){return!!t.call(e,r,e)!==n})):t.nodeType?T.grep(e,(function(e){return e===t!==n})):"string"!=typeof t?T.grep(e,(function(e){return c.call(t,e)>-1!==n})):T.filter(t,e,n)}T.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?T.find.matchesSelector(r,e)?[r]:[]:T.find.matches(e,T.grep(t,(function(e){return 1===e.nodeType})))},T.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(T(e).filter((function(){for(t=0;t1?T.uniqueSort(n):n},filter:function(e){return this.pushStack(O(this,e||[],!1))},not:function(e){return this.pushStack(O(this,e||[],!0))},is:function(e){return!!O(this,"string"==typeof e&&D.test(e)?T(e):e||[],!1).length}});var I,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(T.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||I,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof T?t[0]:t,T.merge(this,T.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:b,!0)),P.test(r[1])&&T.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=b.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(T):T.makeArray(e,this)}).prototype=T.fn,I=T(b);var j=/^(?:parents|prev(?:Until|All))/,R={children:!0,contents:!0,next:!0,prev:!0};function M(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}T.fn.extend({has:function(e){var t=T(e,this),n=t.length;return this.filter((function(){for(var e=0;e-1:1===n.nodeType&&T.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?T.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?c.call(T(e),this[0]):c.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(T.uniqueSort(T.merge(this.get(),T(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),T.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return C(e,"parentNode")},parentsUntil:function(e,t,n){return C(e,"parentNode",n)},next:function(e){return M(e,"nextSibling")},prev:function(e){return M(e,"previousSibling")},nextAll:function(e){return C(e,"nextSibling")},prevAll:function(e){return C(e,"previousSibling")},nextUntil:function(e,t,n){return C(e,"nextSibling",n)},prevUntil:function(e,t,n){return C(e,"previousSibling",n)},siblings:function(e){return N((e.parentNode||{}).firstChild,e)},children:function(e){return N(e.firstChild)},contents:function(e){return null!=e.contentDocument&&a(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),T.merge([],e.childNodes))}},(function(e,t){T.fn[e]=function(n,r){var i=T.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=T.filter(r,i)),this.length>1&&(R[e]||T.uniqueSort(i),j.test(e)&&i.reverse()),this.pushStack(i)}}));var F=/[^\x20\t\r\n\f]+/g;function H(e){return e}function q(e){throw e}function z(e,t,n,r){var i;try{e&&v(i=e.promise)?i.call(e).done(t).fail(n):e&&v(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}T.Callbacks=function(e){e="string"==typeof e?function(e){var t={};return T.each(e.match(F)||[],(function(e,n){t[n]=!0})),t}(e):T.extend({},e);var t,n,r,i,o=[],a=[],l=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;l=-1)for(n=a.shift();++l-1;)o.splice(n,1),n<=l&&l--})),this},has:function(e){return e?T.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return s.fireWith(this,arguments),this},fired:function(){return!!r}};return s},T.extend({Deferred:function(e){var t=[["notify","progress",T.Callbacks("memory"),T.Callbacks("memory"),2],["resolve","done",T.Callbacks("once memory"),T.Callbacks("once memory"),0,"resolved"],["reject","fail",T.Callbacks("once memory"),T.Callbacks("once memory"),1,"rejected"]],n="pending",i={state:function(){return n},always:function(){return o.done(arguments).fail(arguments),this},catch:function(e){return i.then(null,e)},pipe:function(){var e=arguments;return T.Deferred((function(n){T.each(t,(function(t,r){var i=v(e[r[4]])&&e[r[4]];o[r[1]]((function(){var e=i&&i.apply(this,arguments);e&&v(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[r[0]+"With"](this,i?[e]:arguments)}))})),e=null})).promise()},then:function(e,n,i){var o=0;function a(e,t,n,i){return function(){var l=this,u=arguments,s=function(){var r,s;if(!(e=o&&(n!==q&&(l=void 0,u=[r]),t.rejectWith(l,u))}};e?c():(T.Deferred.getStackHook&&(c.stackTrace=T.Deferred.getStackHook()),r.setTimeout(c))}}return T.Deferred((function(r){t[0][3].add(a(0,r,v(i)?i:H,r.notifyWith)),t[1][3].add(a(0,r,v(e)?e:H)),t[2][3].add(a(0,r,v(n)?n:q))})).promise()},promise:function(e){return null!=e?T.extend(e,i):i}},o={};return T.each(t,(function(e,r){var a=r[2],l=r[5];i[r[1]]=a.add,l&&a.add((function(){n=l}),t[3-e][2].disable,t[3-e][3].disable,t[0][2].lock,t[0][3].lock),a.add(r[3].fire),o[r[0]]=function(){return o[r[0]+"With"](this===o?void 0:this,arguments),this},o[r[0]+"With"]=a.fireWith})),i.promise(o),e&&e.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=l.call(arguments),o=T.Deferred(),a=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?l.call(arguments):n,--t||o.resolveWith(r,i)}};if(t<=1&&(z(e,o.done(a(n)).resolve,o.reject,!t),"pending"===o.state()||v(i[n]&&i[n].then)))return o.then();for(;n--;)z(i[n],a(n),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;T.Deferred.exceptionHook=function(e,t){r.console&&r.console.warn&&e&&W.test(e.name)&&r.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},T.readyException=function(e){r.setTimeout((function(){throw e}))};var B=T.Deferred();function U(){b.removeEventListener("DOMContentLoaded",U),r.removeEventListener("load",U),T.ready()}T.fn.ready=function(e){return B.then(e).catch((function(e){T.readyException(e)})),this},T.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--T.readyWait:T.isReady)||(T.isReady=!0,!0!==e&&--T.readyWait>0||B.resolveWith(b,[T]))}}),T.ready.then=B.then,"complete"===b.readyState||"loading"!==b.readyState&&!b.documentElement.doScroll?r.setTimeout(T.ready):(b.addEventListener("DOMContentLoaded",U),r.addEventListener("load",U));var Q=function(e,t,n,r,i,o,a){var l=0,u=e.length,s=null==n;if("object"===E(n))for(l in i=!0,n)Q(e,t,l,n[l],!0,o,a);else if(void 0!==r&&(i=!0,v(r)||(a=!0),s&&(a?(t.call(e,r),t=null):(s=t,t=function(e,t,n){return s.call(T(e),n)})),t))for(;l1,null,!0)},removeData:function(e){return this.each((function(){Z.remove(this,e)}))}}),T.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=G.get(e,t),n&&(!r||Array.isArray(n)?r=G.access(e,t,T.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=T.queue(e,t),r=n.length,i=n.shift(),o=T._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,(function(){T.dequeue(e,t)}),o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return G.get(e,n)||G.access(e,n,{empty:T.Callbacks("once memory").add((function(){G.remove(e,[t+"queue",n])}))})}}),T.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]*)/i,ye=/^$|^module$|\/(?:java|ecma)script/i;he=b.createDocumentFragment().appendChild(b.createElement("div")),(me=b.createElement("input")).setAttribute("type","radio"),me.setAttribute("checked","checked"),me.setAttribute("name","t"),he.appendChild(me),g.checkClone=he.cloneNode(!0).cloneNode(!0).lastChild.checked,he.innerHTML="",g.noCloneChecked=!!he.cloneNode(!0).lastChild.defaultValue,he.innerHTML="",g.option=!!he.lastChild;var be={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function we(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||"*"):void 0!==e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?T.merge([e],n):n}function _e(e,t){for(var n=0,r=e.length;n",""]);var Ee=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,l,u,s,c,f=t.createDocumentFragment(),d=[],p=0,h=e.length;p-1)i&&i.push(o);else if(s=le(o),a=we(f.appendChild(o),"script"),s&&_e(a),n)for(c=0;o=a[c++];)ye.test(o.type||"")&&n.push(o);return f}var Te=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ce(e,t){return e===function(){try{return b.activeElement}catch(e){}}()==("focus"===t)}function Ne(e,t,n,r,i,o){var a,l;if("object"==typeof t){for(l in"string"!=typeof n&&(r=r||n,n=void 0),t)Ne(e,l,n,r,t[l],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return T().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=T.guid++)),e.each((function(){T.event.add(this,t,i,r,n)}))}function De(e,t,n){n?(G.set(e,t,!1),T.event.add(e,t,{namespace:!1,handler:function(e){var r,i,o=G.get(this,t);if(1&e.isTrigger&&this[t]){if(o.length)(T.event.special[t]||{}).delegateType&&e.stopPropagation();else if(o=l.call(arguments),G.set(this,t,o),r=n(this,t),this[t](),o!==(i=G.get(this,t))||r?G.set(this,t,!1):i={},o!==i)return e.stopImmediatePropagation(),e.preventDefault(),i&&i.value}else o.length&&(G.set(this,t,{value:T.event.trigger(T.extend(o[0],T.Event.prototype),o.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===G.get(e,t)&&T.event.add(e,t,ke)}T.event={global:{},add:function(e,t,n,r,i){var o,a,l,u,s,c,f,d,p,h,m,g=G.get(e);if(Y(e))for(n.handler&&(n=(o=n).handler,i=o.selector),i&&T.find.matchesSelector(ae,i),n.guid||(n.guid=T.guid++),(u=g.events)||(u=g.events=Object.create(null)),(a=g.handle)||(a=g.handle=function(t){return void 0!==T&&T.event.triggered!==t.type?T.event.dispatch.apply(e,arguments):void 0}),s=(t=(t||"").match(F)||[""]).length;s--;)p=m=(l=Te.exec(t[s])||[])[1],h=(l[2]||"").split(".").sort(),p&&(f=T.event.special[p]||{},p=(i?f.delegateType:f.bindType)||p,f=T.event.special[p]||{},c=T.extend({type:p,origType:m,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&T.expr.match.needsContext.test(i),namespace:h.join(".")},o),(d=u[p])||((d=u[p]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(p,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?d.splice(d.delegateCount++,0,c):d.push(c),T.event.global[p]=!0)},remove:function(e,t,n,r,i){var o,a,l,u,s,c,f,d,p,h,m,g=G.hasData(e)&&G.get(e);if(g&&(u=g.events)){for(s=(t=(t||"").match(F)||[""]).length;s--;)if(p=m=(l=Te.exec(t[s])||[])[1],h=(l[2]||"").split(".").sort(),p){for(f=T.event.special[p]||{},d=u[p=(r?f.delegateType:f.bindType)||p]||[],l=l[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=d.length;o--;)c=d[o],!i&&m!==c.origType||n&&n.guid!==c.guid||l&&!l.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(d.splice(o,1),c.selector&&d.delegateCount--,f.remove&&f.remove.call(e,c));a&&!d.length&&(f.teardown&&!1!==f.teardown.call(e,h,g.handle)||T.removeEvent(e,p,g.handle),delete u[p])}else for(p in u)T.event.remove(e,p+t[s],n,r,!0);T.isEmptyObject(u)&&G.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,l=new Array(arguments.length),u=T.event.fix(e),s=(G.get(this,"events")||Object.create(null))[u.type]||[],c=T.event.special[u.type]||{};for(l[0]=u,t=1;t=1))for(;s!==this;s=s.parentNode||this)if(1===s.nodeType&&("click"!==e.type||!0!==s.disabled)){for(o=[],a={},n=0;n-1:T.find(i,this,null,[s]).length),a[i]&&o.push(r);o.length&&l.push({elem:s,handlers:o})}return s=this,u\s*$/g;function Ie(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&T(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function je(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Re(e,t){var n,r,i,o,a,l;if(1===t.nodeType){if(G.hasData(e)&&(l=G.get(e).events))for(i in G.remove(t,"handle events"),l)for(n=0,r=l[i].length;n1&&"string"==typeof h&&!g.checkClone&&Pe.test(h))return e.each((function(i){var o=e.eq(i);m&&(t[0]=h.call(this,i,o.html())),Fe(o,t,n,r)}));if(d&&(o=(i=xe(t,e[0].ownerDocument,!1,e,r)).firstChild,1===i.childNodes.length&&(i=o),o||r)){for(l=(a=T.map(we(i,"script"),Le)).length;f0&&_e(a,!u&&we(e,"script")),l},cleanData:function(e){for(var t,n,r,i=T.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[G.expando]){if(t.events)for(r in t.events)i[r]?T.event.remove(n,r):T.removeEvent(n,r,t.handle);n[G.expando]=void 0}n[Z.expando]&&(n[Z.expando]=void 0)}}}),T.fn.extend({detach:function(e){return He(this,e,!0)},remove:function(e){return He(this,e)},text:function(e){return Q(this,(function(e){return void 0===e?T.text(this):this.empty().each((function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)}))}),null,e,arguments.length)},append:function(){return Fe(this,arguments,(function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Ie(this,e).appendChild(e)}))},prepend:function(){return Fe(this,arguments,(function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Ie(this,e);t.insertBefore(e,t.firstChild)}}))},before:function(){return Fe(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this)}))},after:function(){return Fe(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)}))},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(T.cleanData(we(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map((function(){return T.clone(this,e,t)}))},html:function(e){return Q(this,(function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!be[(ve.exec(e)||["",""])[1].toLowerCase()]){e=T.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-l-.5))||0),u}function nt(e,t,n){var r=ze(e),i=(!g.boxSizingReliable()||n)&&"border-box"===T.css(e,"boxSizing",!1,r),o=i,a=Ue(e,t,r),l="offset"+t[0].toUpperCase()+t.slice(1);if(qe.test(a)){if(!n)return a;a="auto"}return(!g.boxSizingReliable()&&i||!g.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===T.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===T.css(e,"boxSizing",!1,r),(o=l in e)&&(a=e[l])),(a=parseFloat(a)||0)+tt(e,t,n||(i?"border":"content"),o,r,a)+"px"}function rt(e,t,n,r,i){return new rt.prototype.init(e,t,n,r,i)}T.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Ue(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,l=X(t),u=Je.test(t),s=e.style;if(u||(t=Xe(l)),a=T.cssHooks[t]||T.cssHooks[l],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:s[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ce(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(T.cssNumber[l]?"":"px")),g.clearCloneStyle||""!==n||0!==t.indexOf("background")||(s[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?s.setProperty(t,n):s[t]=n))}},css:function(e,t,n,r){var i,o,a,l=X(t);return Je.test(t)||(t=Xe(l)),(a=T.cssHooks[t]||T.cssHooks[l])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Ue(e,t,r)),"normal"===i&&t in Ze&&(i=Ze[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),T.each(["height","width"],(function(e,t){T.cssHooks[t]={get:function(e,n,r){if(n)return!Ye.test(T.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?nt(e,t,r):We(e,Ge,(function(){return nt(e,t,r)}))},set:function(e,n,r){var i,o=ze(e),a=!g.scrollboxSize()&&"absolute"===o.position,l=(a||r)&&"border-box"===T.css(e,"boxSizing",!1,o),u=r?tt(e,t,r,l,o):0;return l&&a&&(u-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-tt(e,t,"border",!1,o)-.5)),u&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=T.css(e,t)),et(0,n,u)}}})),T.cssHooks.marginLeft=Qe(g.reliableMarginLeft,(function(e,t){if(t)return(parseFloat(Ue(e,"marginLeft"))||e.getBoundingClientRect().left-We(e,{marginLeft:0},(function(){return e.getBoundingClientRect().left})))+"px"})),T.each({margin:"",padding:"",border:"Width"},(function(e,t){T.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(T.cssHooks[e+t].set=et)})),T.fn.extend({css:function(e,t){return Q(this,(function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=ze(e),i=t.length;a1)}}),T.Tween=rt,rt.prototype={constructor:rt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||T.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(T.cssNumber[n]?"":"px")},cur:function(){var e=rt.propHooks[this.prop];return e&&e.get?e.get(this):rt.propHooks._default.get(this)},run:function(e){var t,n=rt.propHooks[this.prop];return this.options.duration?this.pos=t=T.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rt.propHooks._default.set(this),this}},rt.prototype.init.prototype=rt.prototype,rt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=T.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){T.fx.step[e.prop]?T.fx.step[e.prop](e):1!==e.elem.nodeType||!T.cssHooks[e.prop]&&null==e.elem.style[Xe(e.prop)]?e.elem[e.prop]=e.now:T.style(e.elem,e.prop,e.now+e.unit)}}},rt.propHooks.scrollTop=rt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},T.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},T.fx=rt.prototype.init,T.fx.step={};var it,ot,at=/^(?:toggle|show|hide)$/,lt=/queueHooks$/;function ut(){ot&&(!1===b.hidden&&r.requestAnimationFrame?r.requestAnimationFrame(ut):r.setTimeout(ut,T.fx.interval),T.fx.tick())}function st(){return r.setTimeout((function(){it=void 0})),it=Date.now()}function ct(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ft(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each((function(){T.removeAttr(this,e)}))}}),T.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return void 0===e.getAttribute?T.prop(e,t,n):(1===o&&T.isXMLDoc(e)||(i=T.attrHooks[t.toLowerCase()]||(T.expr.match.bool.test(t)?pt:void 0)),void 0!==n?null===n?void T.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=T.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!g.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(F);if(i&&1===e.nodeType)for(;n=i[r++];)e.removeAttribute(n)}}),pt={set:function(e,t,n){return!1===t?T.removeAttr(e,n):e.setAttribute(n,n),n}},T.each(T.expr.match.bool.source.match(/\w+/g),(function(e,t){var n=ht[t]||T.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}}));var mt=/^(?:input|select|textarea|button)$/i,gt=/^(?:a|area)$/i;function vt(e){return(e.match(F)||[]).join(" ")}function yt(e){return e.getAttribute&&e.getAttribute("class")||""}function bt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(F)||[]}T.fn.extend({prop:function(e,t){return Q(this,T.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each((function(){delete this[T.propFix[e]||e]}))}}),T.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&T.isXMLDoc(e)||(t=T.propFix[t]||t,i=T.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=T.find.attr(e,"tabindex");return t?parseInt(t,10):mt.test(e.nodeName)||gt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),g.optSelected||(T.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),T.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],(function(){T.propFix[this.toLowerCase()]=this})),T.fn.extend({addClass:function(e){var t,n,r,i,o,a,l,u=0;if(v(e))return this.each((function(t){T(this).addClass(e.call(this,t,yt(this)))}));if((t=bt(e)).length)for(;n=this[u++];)if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){for(a=0;o=t[a++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(l=vt(r))&&n.setAttribute("class",l)}return this},removeClass:function(e){var t,n,r,i,o,a,l,u=0;if(v(e))return this.each((function(t){T(this).removeClass(e.call(this,t,yt(this)))}));if(!arguments.length)return this.attr("class","");if((t=bt(e)).length)for(;n=this[u++];)if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){for(a=0;o=t[a++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");i!==(l=vt(r))&&n.setAttribute("class",l)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):v(e)?this.each((function(n){T(this).toggleClass(e.call(this,n,yt(this),t),t)})):this.each((function(){var t,i,o,a;if(r)for(i=0,o=T(this),a=bt(e);t=a[i++];)o.hasClass(t)?o.removeClass(t):o.addClass(t);else void 0!==e&&"boolean"!==n||((t=yt(this))&&G.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":G.get(this,"__className__")||""))}))},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+vt(yt(n))+" ").indexOf(t)>-1)return!0;return!1}});var wt=/\r/g;T.fn.extend({val:function(e){var t,n,r,i=this[0];return arguments.length?(r=v(e),this.each((function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,T(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=T.map(i,(function(e){return null==e?"":e+""}))),(t=T.valHooks[this.type]||T.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))}))):i?(t=T.valHooks[i.type]||T.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(wt,""):null==n?"":n:void 0}}),T.extend({valHooks:{option:{get:function(e){var t=T.find.attr(e,"value");return null!=t?t:vt(T.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,l=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),T.each(["radio","checkbox"],(function(){T.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=T.inArray(T(e).val(),t)>-1}},g.checkOn||(T.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})})),g.focusin="onfocusin"in r;var _t=/^(?:focusinfocus|focusoutblur)$/,Et=function(e){e.stopPropagation()};T.extend(T.event,{trigger:function(e,t,n,i){var o,a,l,u,s,c,f,d,h=[n||b],m=p.call(e,"type")?e.type:e,g=p.call(e,"namespace")?e.namespace.split("."):[];if(a=d=l=n=n||b,3!==n.nodeType&&8!==n.nodeType&&!_t.test(m+T.event.triggered)&&(m.indexOf(".")>-1&&(g=m.split("."),m=g.shift(),g.sort()),s=m.indexOf(":")<0&&"on"+m,(e=e[T.expando]?e:new T.Event(m,"object"==typeof e&&e)).isTrigger=i?2:3,e.namespace=g.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:T.makeArray(t,[e]),f=T.event.special[m]||{},i||!f.trigger||!1!==f.trigger.apply(n,t))){if(!i&&!f.noBubble&&!y(n)){for(u=f.delegateType||m,_t.test(u+m)||(a=a.parentNode);a;a=a.parentNode)h.push(a),l=a;l===(n.ownerDocument||b)&&h.push(l.defaultView||l.parentWindow||r)}for(o=0;(a=h[o++])&&!e.isPropagationStopped();)d=a,e.type=o>1?u:f.bindType||m,(c=(G.get(a,"events")||Object.create(null))[e.type]&&G.get(a,"handle"))&&c.apply(a,t),(c=s&&a[s])&&c.apply&&Y(a)&&(e.result=c.apply(a,t),!1===e.result&&e.preventDefault());return e.type=m,i||e.isDefaultPrevented()||f._default&&!1!==f._default.apply(h.pop(),t)||!Y(n)||s&&v(n[m])&&!y(n)&&((l=n[s])&&(n[s]=null),T.event.triggered=m,e.isPropagationStopped()&&d.addEventListener(m,Et),n[m](),e.isPropagationStopped()&&d.removeEventListener(m,Et),T.event.triggered=void 0,l&&(n[s]=l)),e.result}},simulate:function(e,t,n){var r=T.extend(new T.Event,n,{type:e,isSimulated:!0});T.event.trigger(r,null,t)}}),T.fn.extend({trigger:function(e,t){return this.each((function(){T.event.trigger(e,t,this)}))},triggerHandler:function(e,t){var n=this[0];if(n)return T.event.trigger(e,t,n,!0)}}),g.focusin||T.each({focus:"focusin",blur:"focusout"},(function(e,t){var n=function(e){T.event.simulate(t,e.target,T.event.fix(e))};T.event.special[t]={setup:function(){var r=this.ownerDocument||this.document||this,i=G.access(r,t);i||r.addEventListener(e,n,!0),G.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this.document||this,i=G.access(r,t)-1;i?G.access(r,t,i):(r.removeEventListener(e,n,!0),G.remove(r,t))}}}));var xt=r.location,Tt={guid:Date.now()},kt=/\?/;T.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new r.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||T.error("Invalid XML: "+(n?T.map(n.childNodes,(function(e){return e.textContent})).join("\n"):e)),t};var St=/\[\]$/,Ct=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,Dt=/^(?:input|select|textarea|keygen)/i;function At(e,t,n,r){var i;if(Array.isArray(t))T.each(t,(function(t,i){n||St.test(e)?r(e,i):At(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)}));else if(n||"object"!==E(t))r(e,t);else for(i in t)At(e+"["+i+"]",t[i],n,r)}T.param=function(e,t){var n,r=[],i=function(e,t){var n=v(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!T.isPlainObject(e))T.each(e,(function(){i(this.name,this.value)}));else for(n in e)At(n,e[n],t,i);return r.join("&")},T.fn.extend({serialize:function(){return T.param(this.serializeArray())},serializeArray:function(){return this.map((function(){var e=T.prop(this,"elements");return e?T.makeArray(e):this})).filter((function(){var e=this.type;return this.name&&!T(this).is(":disabled")&&Dt.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!ge.test(e))})).map((function(e,t){var n=T(this).val();return null==n?null:Array.isArray(n)?T.map(n,(function(e){return{name:t.name,value:e.replace(Ct,"\r\n")}})):{name:t.name,value:n.replace(Ct,"\r\n")}})).get()}});var Pt=/%20/g,Ot=/#.*$/,It=/([?&])_=[^&]*/,Lt=/^(.*?):[ \t]*([^\r\n]*)$/gm,jt=/^(?:GET|HEAD)$/,Rt=/^\/\//,Mt={},Ft={},Ht="*/".concat("*"),qt=b.createElement("a");function zt(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(F)||[];if(v(n))for(;r=o[i++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function Wt(e,t,n,r){var i={},o=e===Ft;function a(l){var u;return i[l]=!0,T.each(e[l]||[],(function(e,l){var s=l(t,n,r);return"string"!=typeof s||o||i[s]?o?!(u=s):void 0:(t.dataTypes.unshift(s),a(s),!1)})),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function Bt(e,t){var n,r,i=T.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&T.extend(!0,e,r),e}qt.href=xt.href,T.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:xt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(xt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Ht,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":T.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Bt(Bt(e,T.ajaxSettings),t):Bt(T.ajaxSettings,e)},ajaxPrefilter:zt(Mt),ajaxTransport:zt(Ft),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var n,i,o,a,l,u,s,c,f,d,p=T.ajaxSetup({},t),h=p.context||p,m=p.context&&(h.nodeType||h.jquery)?T(h):T.event,g=T.Deferred(),v=T.Callbacks("once memory"),y=p.statusCode||{},w={},_={},E="canceled",x={readyState:0,getResponseHeader:function(e){var t;if(s){if(!a)for(a={};t=Lt.exec(o);)a[t[1].toLowerCase()+" "]=(a[t[1].toLowerCase()+" "]||[]).concat(t[2]);t=a[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return s?o:null},setRequestHeader:function(e,t){return null==s&&(e=_[e.toLowerCase()]=_[e.toLowerCase()]||e,w[e]=t),this},overrideMimeType:function(e){return null==s&&(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(s)x.always(e[x.status]);else for(t in e)y[t]=[y[t],e[t]];return this},abort:function(e){var t=e||E;return n&&n.abort(t),k(0,t),this}};if(g.promise(x),p.url=((e||p.url||xt.href)+"").replace(Rt,xt.protocol+"//"),p.type=t.method||t.type||p.method||p.type,p.dataTypes=(p.dataType||"*").toLowerCase().match(F)||[""],null==p.crossDomain){u=b.createElement("a");try{u.href=p.url,u.href=u.href,p.crossDomain=qt.protocol+"//"+qt.host!=u.protocol+"//"+u.host}catch(e){p.crossDomain=!0}}if(p.data&&p.processData&&"string"!=typeof p.data&&(p.data=T.param(p.data,p.traditional)),Wt(Mt,p,t,x),s)return x;for(f in(c=T.event&&p.global)&&0==T.active++&&T.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!jt.test(p.type),i=p.url.replace(Ot,""),p.hasContent?p.data&&p.processData&&0===(p.contentType||"").indexOf("application/x-www-form-urlencoded")&&(p.data=p.data.replace(Pt,"+")):(d=p.url.slice(i.length),p.data&&(p.processData||"string"==typeof p.data)&&(i+=(kt.test(i)?"&":"?")+p.data,delete p.data),!1===p.cache&&(i=i.replace(It,"$1"),d=(kt.test(i)?"&":"?")+"_="+Tt.guid+++d),p.url=i+d),p.ifModified&&(T.lastModified[i]&&x.setRequestHeader("If-Modified-Since",T.lastModified[i]),T.etag[i]&&x.setRequestHeader("If-None-Match",T.etag[i])),(p.data&&p.hasContent&&!1!==p.contentType||t.contentType)&&x.setRequestHeader("Content-Type",p.contentType),x.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Ht+"; q=0.01":""):p.accepts["*"]),p.headers)x.setRequestHeader(f,p.headers[f]);if(p.beforeSend&&(!1===p.beforeSend.call(h,x,p)||s))return x.abort();if(E="abort",v.add(p.complete),x.done(p.success),x.fail(p.error),n=Wt(Ft,p,t,x)){if(x.readyState=1,c&&m.trigger("ajaxSend",[x,p]),s)return x;p.async&&p.timeout>0&&(l=r.setTimeout((function(){x.abort("timeout")}),p.timeout));try{s=!1,n.send(w,k)}catch(e){if(s)throw e;k(-1,e)}}else k(-1,"No Transport");function k(e,t,a,u){var f,d,b,w,_,E=t;s||(s=!0,l&&r.clearTimeout(l),n=void 0,o=u||"",x.readyState=e>0?4:0,f=e>=200&&e<300||304===e,a&&(w=function(e,t,n){for(var r,i,o,a,l=e.contents,u=e.dataTypes;"*"===u[0];)u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in l)if(l[i]&&l[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(p,x,a)),!f&&T.inArray("script",p.dataTypes)>-1&&T.inArray("json",p.dataTypes)<0&&(p.converters["text script"]=function(){}),w=function(e,t,n,r){var i,o,a,l,u,s={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)s[a.toLowerCase()]=e.converters[a];for(o=c.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=s[u+" "+o]||s["* "+o]))for(i in s)if((l=i.split(" "))[1]===o&&(a=s[u+" "+l[0]]||s["* "+l[0]])){!0===a?a=s[i]:!0!==s[i]&&(o=l[0],c.unshift(l[1]));break}if(!0!==a)if(a&&e.throws)t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(p,w,x,f),f?(p.ifModified&&((_=x.getResponseHeader("Last-Modified"))&&(T.lastModified[i]=_),(_=x.getResponseHeader("etag"))&&(T.etag[i]=_)),204===e||"HEAD"===p.type?E="nocontent":304===e?E="notmodified":(E=w.state,d=w.data,f=!(b=w.error))):(b=E,!e&&E||(E="error",e<0&&(e=0))),x.status=e,x.statusText=(t||E)+"",f?g.resolveWith(h,[d,E,x]):g.rejectWith(h,[x,E,b]),x.statusCode(y),y=void 0,c&&m.trigger(f?"ajaxSuccess":"ajaxError",[x,p,f?d:b]),v.fireWith(h,[x,E]),c&&(m.trigger("ajaxComplete",[x,p]),--T.active||T.event.trigger("ajaxStop")))}return x},getJSON:function(e,t,n){return T.get(e,t,n,"json")},getScript:function(e,t){return T.get(e,void 0,t,"script")}}),T.each(["get","post"],(function(e,t){T[t]=function(e,n,r,i){return v(n)&&(i=i||r,r=n,n=void 0),T.ajax(T.extend({url:e,type:t,dataType:i,data:n,success:r},T.isPlainObject(e)&&e))}})),T.ajaxPrefilter((function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")})),T._evalUrl=function(e,t,n){return T.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){T.globalEval(e,t,n)}})},T.fn.extend({wrapAll:function(e){var t;return this[0]&&(v(e)&&(e=e.call(this[0])),t=T(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map((function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e})).append(this)),this},wrapInner:function(e){return v(e)?this.each((function(t){T(this).wrapInner(e.call(this,t))})):this.each((function(){var t=T(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)}))},wrap:function(e){var t=v(e);return this.each((function(n){T(this).wrapAll(t?e.call(this,n):e)}))},unwrap:function(e){return this.parent(e).not("body").each((function(){T(this).replaceWith(this.childNodes)})),this}}),T.expr.pseudos.hidden=function(e){return!T.expr.pseudos.visible(e)},T.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},T.ajaxSettings.xhr=function(){try{return new r.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Qt=T.ajaxSettings.xhr();g.cors=!!Qt&&"withCredentials"in Qt,g.ajax=Qt=!!Qt,T.ajaxTransport((function(e){var t,n;if(g.cors||Qt&&!e.crossDomain)return{send:function(i,o){var a,l=e.xhr();if(l.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(a in e.xhrFields)l[a]=e.xhrFields[a];for(a in e.mimeType&&l.overrideMimeType&&l.overrideMimeType(e.mimeType),e.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest"),i)l.setRequestHeader(a,i[a]);t=function(e){return function(){t&&(t=n=l.onload=l.onerror=l.onabort=l.ontimeout=l.onreadystatechange=null,"abort"===e?l.abort():"error"===e?"number"!=typeof l.status?o(0,"error"):o(l.status,l.statusText):o(Ut[l.status]||l.status,l.statusText,"text"!==(l.responseType||"text")||"string"!=typeof l.responseText?{binary:l.response}:{text:l.responseText},l.getAllResponseHeaders()))}},l.onload=t(),n=l.onerror=l.ontimeout=t("error"),void 0!==l.onabort?l.onabort=n:l.onreadystatechange=function(){4===l.readyState&&r.setTimeout((function(){t&&n()}))},t=t("abort");try{l.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}})),T.ajaxPrefilter((function(e){e.crossDomain&&(e.contents.script=!1)})),T.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return T.globalEval(e),e}}}),T.ajaxPrefilter("script",(function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")})),T.ajaxTransport("script",(function(e){var t,n;if(e.crossDomain||e.scriptAttrs)return{send:function(r,i){t=T("