├── .gitignore
├── LICENSE
├── README.md
├── modulo-01
├── desafio-01
│ ├── css
│ │ └── app.css
│ ├── index.html
│ └── js
│ │ ├── app.js
│ │ ├── users-controller.js
│ │ └── users-service.js
└── trabalho-pratico-01
│ ├── css
│ ├── app.css
│ └── reset.css
│ ├── index.html
│ └── js
│ ├── app.js
│ └── color-mixer.js
├── modulo-02
├── desafio-02
│ ├── .gitignore
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ └── src
│ │ ├── app.js
│ │ ├── controllers
│ │ └── grades.controller.js
│ │ ├── data
│ │ └── grades.json
│ │ ├── repositories
│ │ └── grades.repository.js
│ │ ├── routes
│ │ └── grades.routes.js
│ │ ├── util
│ │ ├── error-handlers.js
│ │ └── not-found.error.js
│ │ └── validators
│ │ ├── grades.validator.js
│ │ └── id.validator.js
└── trabalho-pratico-02
│ ├── .gitignore
│ ├── data
│ ├── cidades.json
│ └── estados.json
│ ├── index.js
│ ├── package.json
│ ├── states-cities-data-processor.js
│ └── states-cities-file-processor.js
├── modulo-03
├── desafio-03
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── components
│ │ │ ├── form
│ │ │ │ ├── index.js
│ │ │ │ └── styles.css
│ │ │ └── table
│ │ │ │ ├── index.js
│ │ │ │ └── styles.css
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── logo.svg
│ │ ├── serviceWorker.js
│ │ ├── setupTests.js
│ │ └── util
│ │ │ ├── compound-interest.js
│ │ │ └── number-format.js
│ └── yarn.lock
└── trabalho-pratico-03
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
│ ├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── components
│ │ ├── input-read-only
│ │ │ ├── index.js
│ │ │ └── styles.css
│ │ └── progress-bar
│ │ │ ├── index.js
│ │ │ └── styles.css
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── serviceWorker.js
│ ├── setupTests.js
│ └── util
│ │ └── salary.js
│ └── yarn.lock
└── modulo-04
└── trabalho-pratico-04
├── .gitignore
├── README.md
├── index.js
├── package-lock.json
├── package.json
└── src
├── api
├── accounts
│ ├── deposit.js
│ ├── get-statement.js
│ ├── index.js
│ ├── remove-account.js
│ ├── reset-database.js
│ ├── validators
│ │ ├── agency-and-account.validator.js
│ │ └── deposit-or-withdraw.validator.js
│ └── withdraw.js
├── reports
│ ├── get-balance-average.js
│ ├── get-balance-ranking.js
│ ├── index.js
│ └── validators
│ │ ├── agency.validator.js
│ │ └── balance-ranking.validator.js
└── transfers
│ ├── index.js
│ ├── transfer-balance.js
│ ├── transfer-largest-accounts.js
│ └── validators
│ └── transfer.validator.js
├── app.js
├── config
└── db.js
├── models
└── account.js
└── util
├── accounts.json
├── error-handlers.js
├── insufficient-balance.error.js
└── not-found.error.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 |
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Lucas Rodrigues Moura
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IGTI - Bootcamp Online - Desenvolvedor Web Full stack
2 |
3 | Repositório com o conteúdo desenvolvido no bootcamp da [IGTI](https://www.igti.com.br/).
4 |
5 |
--------------------------------------------------------------------------------
/modulo-01/desafio-01/css/app.css:
--------------------------------------------------------------------------------
1 | .photo {
2 | max-width: 75px;
3 | }
--------------------------------------------------------------------------------
/modulo-01/desafio-01/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | IGTI - Trabalho Prático do Módulo 1
11 |
12 |
13 |
14 |
15 |
Pesquisa de Usuários
16 |
17 |
18 |
37 |
38 |
39 |
40 |
41 |
44 |
45 |
46 |
Nenhum usuário encontrado.
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
57 |
58 |
59 |
Nada a ser exibido.
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/modulo-01/desafio-01/js/app.js:
--------------------------------------------------------------------------------
1 | const onLoad = () => {
2 | usersController.init();
3 | };
4 |
5 | window.addEventListener('load', onLoad);
6 |
--------------------------------------------------------------------------------
/modulo-01/desafio-01/js/users-controller.js:
--------------------------------------------------------------------------------
1 | const usersController = (function UsersController() {
2 |
3 | let users = [];
4 |
5 | // window elements
6 | const form = document.querySelector('form');
7 | const searchInput = form.querySelector('input');
8 | const usersList = document.querySelector('.users-list');
9 | const usersLength = document.querySelector('.users-length');
10 | const usersStatistics = document.querySelector('.users-statistics');
11 |
12 | async function init() {
13 | users = await usersService.list();
14 | _render(users);
15 |
16 | // set up listeners
17 | form.addEventListener('submit', event => {
18 | event.preventDefault();
19 | _doSearch();
20 | });
21 |
22 | searchInput.addEventListener('keyup', event => {
23 | // prevents searching twice
24 | if (event.keyCode === 13) return;
25 |
26 | _doSearch();
27 | });
28 | }
29 |
30 | function _doSearch() {
31 | const query = searchInput.value.toLowerCase();
32 | const filteredUsers = users.filter(user => {
33 | return user.name.toLowerCase().includes(query) || user.lastname.toLowerCase().includes(query)
34 | });
35 |
36 | _render(filteredUsers);
37 | }
38 |
39 | function _render(users) {
40 | _renderUsersQuantity(users);
41 | _renderUsers(users);
42 | _renderStatistics(users);
43 | }
44 |
45 | function _renderUsers(users) {
46 | const html = users.map(user => `
47 |
48 |
53 | ${user.name} ${user.lastname},
54 | ${user.age} anos
55 |
56 | `)
57 | .join('');
58 |
59 | usersList.innerHTML = html;
60 | }
61 |
62 | function _renderUsersQuantity(users) {
63 | const html = users.length ?
64 | `${users.length} usuário(s) encontrado(s).` :
65 | `Nenhum usuário encontrado.`;
66 |
67 | usersLength.innerHTML = html;
68 | }
69 |
70 | function _renderStatistics(users) {
71 | let html;
72 |
73 | if (!users.length) {
74 | html = 'Nada a ser exibido.
';
75 | } else {
76 | const statistics = _calcStatistics(users);
77 |
78 | html = `
79 |
80 | - Sexo Masculino:
81 | - ${statistics.mens}
82 |
83 | - Sexo Feminino:
84 | - ${statistics.womens}
85 |
86 | - Soma das Idades:
87 | - ${statistics.agesTotal}
88 |
89 | - Média das Idades:
90 | - ${statistics.agesAvg}
91 |
92 | `;
93 | }
94 |
95 | usersStatistics.innerHTML = html;
96 | }
97 |
98 | function _calcStatistics(users) {
99 | const statistics = users.reduce((statistics, user) => {
100 | statistics.agesTotal += user.age;
101 | user.gender === 'female' ? statistics.womens += 1 : statistics.mens += 1;
102 |
103 | return statistics;
104 | }, {
105 | mens: 0,
106 | womens: 0,
107 | agesTotal: 0
108 | });
109 |
110 | return {
111 | ...statistics,
112 | agesAvg: _formatNumber(statistics.agesTotal / users.length)
113 | }
114 | }
115 |
116 | function _formatNumber(num) {
117 | return Intl
118 | .NumberFormat('pt-BR', {
119 | minimumFractionDigits: 2,
120 | maximumFractionDigits: 2
121 | })
122 | .format(num);
123 | }
124 |
125 | return { init };
126 |
127 | })(usersService);
128 |
--------------------------------------------------------------------------------
/modulo-01/desafio-01/js/users-service.js:
--------------------------------------------------------------------------------
1 | const usersService = (function UsersService() {
2 |
3 | const API_URL = 'https://randomuser.me/api/?seed=javascript&results=100&nat=BR&noinfo';
4 |
5 | async function list() {
6 | const res = await fetch(API_URL);
7 | const users = await res.json();
8 |
9 | return users.results.map(u => ({
10 | name : u.name.first,
11 | lastname : u.name.last,
12 | picture : u.picture.large,
13 | age : u.dob.age,
14 | gender : u.gender
15 | }));
16 | }
17 |
18 | return { list };
19 |
20 | })();
21 |
--------------------------------------------------------------------------------
/modulo-01/trabalho-pratico-01/css/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Arial, Helvetica, sans-serif;
3 | width: 100vw;
4 | height: 100vh;
5 | display: flex;
6 | align-items: center;
7 | justify-content: center;
8 | }
9 |
10 | .container {
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | align-content: center;
15 | }
16 |
17 | .container>.visualizer {
18 | margin-top: 2em;
19 | border: 1px solid #000;
20 | height: 40vw;
21 | width: 40vw;
22 | max-width: 200px;
23 | max-height: 200px;
24 | background-color: #000;
25 | }
26 |
27 | .container>.rangers-container {
28 | display: flex;
29 | flex-direction: column;
30 | }
31 |
32 | .container>.rangers-container>.form-group {
33 | display: grid;
34 | grid-template-columns: 1fr 1fr 1fr;
35 | }
36 |
37 | .container>.rangers-container>.form-group:not(:first-of-type) {
38 | margin-top: .5em;
39 | }
40 |
41 | .container>.rangers-container>.form-group>label {
42 | font-weight: bold;
43 | }
44 |
45 | .container>.rangers-container>.form-group>input[type='text'] {
46 | width: 5em;
47 | margin-left: auto;
48 | }
49 |
--------------------------------------------------------------------------------
/modulo-01/trabalho-pratico-01/css/reset.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html, body, div, span, applet, object, iframe,
7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8 | a, abbr, acronym, address, big, cite, code,
9 | del, dfn, em, img, ins, kbd, q, s, samp,
10 | small, strike, strong, sub, sup, tt, var,
11 | b, u, i, center,
12 | dl, dt, dd, ol, ul, li,
13 | fieldset, form, label, legend,
14 | table, caption, tbody, tfoot, thead, tr, th, td,
15 | article, aside, canvas, details, embed,
16 | figure, figcaption, footer, header, hgroup,
17 | menu, nav, output, ruby, section, summary,
18 | time, mark, audio, video {
19 | margin: 0;
20 | padding: 0;
21 | border: 0;
22 | font-size: 100%;
23 | font: inherit;
24 | vertical-align: baseline;
25 | }
26 | /* HTML5 display-role reset for older browsers */
27 | article, aside, details, figcaption, figure,
28 | footer, header, hgroup, menu, nav, section {
29 | display: block;
30 | }
31 | body {
32 | line-height: 1;
33 | }
34 | ol, ul {
35 | list-style: none;
36 | }
37 | blockquote, q {
38 | quotes: none;
39 | }
40 | blockquote:before, blockquote:after,
41 | q:before, q:after {
42 | content: '';
43 | content: none;
44 | }
45 | table {
46 | border-collapse: collapse;
47 | border-spacing: 0;
48 | }
--------------------------------------------------------------------------------
/modulo-01/trabalho-pratico-01/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | IGTI - Trabalho Prático do Módulo 1
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/modulo-01/trabalho-pratico-01/js/app.js:
--------------------------------------------------------------------------------
1 | const onLoad = () => {
2 | colorMixer.init();
3 | };
4 |
5 | window.addEventListener('load', onLoad);
6 |
--------------------------------------------------------------------------------
/modulo-01/trabalho-pratico-01/js/color-mixer.js:
--------------------------------------------------------------------------------
1 | const colorMixer = (function ColorMixer() {
2 |
3 | const colors = {
4 | red : 0,
5 | green : 0,
6 | blue : 0
7 | };
8 |
9 | // window elements
10 | const inputRanges = document.querySelectorAll('input[type=range]');
11 | const inputRangeValueDisplayers = document.querySelectorAll('input[type=text]');
12 | const visualizer = document.querySelector('.visualizer');
13 |
14 | function init() {
15 | // initialize all input values
16 | inputRanges.forEach(input => _updateInputValue(input, 0));
17 | inputRangeValueDisplayers.forEach(input => _updateInputValue(input, 0));
18 |
19 | // set up rangers listener
20 | inputRanges.forEach(inputRange => inputRange.addEventListener('change', _onRangeChange));
21 | };
22 |
23 | function updateVisualizer(red, green, blue) {
24 | _updateVisualizer({red, green, blue});
25 | }
26 |
27 | function _onRangeChange(event) {
28 | const inputRange = event.target;
29 | const colorRef = inputRange.getAttribute('data-color');
30 | const valueDisplayer = _getValueDisplayerFrom(inputRange);
31 |
32 | _updateColor(colorRef, inputRange.value);
33 | _updateInputValue(valueDisplayer, inputRange.value);
34 | _updateVisualizer();
35 | };
36 |
37 | function _updateColor(color, value) {
38 | colors[color] = value;
39 | }
40 |
41 | function _updateVisualizer({red, green, blue} = colors) {
42 | visualizer.style.backgroundColor = `rgb(${red},${green},${blue})`;
43 | }
44 |
45 | function _updateInputValue(input, value) {
46 | input.value = value;
47 | }
48 |
49 | function _getValueDisplayerFrom(inputRange) {
50 | return inputRange.parentElement.querySelector('input[type=text]');
51 | }
52 |
53 | return { init, updateVisualizer };
54 |
55 | })();
56 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/index.js:
--------------------------------------------------------------------------------
1 | const app = require('./src/app');
2 |
3 | const listener = app.listen(process.env.PORT || 3000, () => {
4 | console.log(`Server listening on port ${listener.address().port}`);
5 | });
6 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "desafio-02",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@hapi/address": {
8 | "version": "2.1.4",
9 | "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
10 | "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ=="
11 | },
12 | "@hapi/bourne": {
13 | "version": "1.3.2",
14 | "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz",
15 | "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA=="
16 | },
17 | "@hapi/hoek": {
18 | "version": "8.5.1",
19 | "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz",
20 | "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow=="
21 | },
22 | "@hapi/joi": {
23 | "version": "15.1.1",
24 | "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz",
25 | "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==",
26 | "requires": {
27 | "@hapi/address": "2.x.x",
28 | "@hapi/bourne": "1.x.x",
29 | "@hapi/hoek": "8.x.x",
30 | "@hapi/topo": "3.x.x"
31 | }
32 | },
33 | "@hapi/topo": {
34 | "version": "3.1.6",
35 | "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz",
36 | "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==",
37 | "requires": {
38 | "@hapi/hoek": "^8.3.0"
39 | }
40 | },
41 | "@sindresorhus/is": {
42 | "version": "0.14.0",
43 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
44 | "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
45 | "dev": true
46 | },
47 | "@szmarczak/http-timer": {
48 | "version": "1.1.2",
49 | "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
50 | "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
51 | "dev": true,
52 | "requires": {
53 | "defer-to-connect": "^1.0.1"
54 | }
55 | },
56 | "@types/color-name": {
57 | "version": "1.1.1",
58 | "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
59 | "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
60 | "dev": true
61 | },
62 | "abbrev": {
63 | "version": "1.1.1",
64 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
65 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
66 | "dev": true
67 | },
68 | "accepts": {
69 | "version": "1.3.7",
70 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
71 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
72 | "requires": {
73 | "mime-types": "~2.1.24",
74 | "negotiator": "0.6.2"
75 | }
76 | },
77 | "ansi-align": {
78 | "version": "3.0.0",
79 | "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",
80 | "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==",
81 | "dev": true,
82 | "requires": {
83 | "string-width": "^3.0.0"
84 | },
85 | "dependencies": {
86 | "string-width": {
87 | "version": "3.1.0",
88 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
89 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
90 | "dev": true,
91 | "requires": {
92 | "emoji-regex": "^7.0.1",
93 | "is-fullwidth-code-point": "^2.0.0",
94 | "strip-ansi": "^5.1.0"
95 | }
96 | }
97 | }
98 | },
99 | "ansi-regex": {
100 | "version": "4.1.0",
101 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
102 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
103 | "dev": true
104 | },
105 | "ansi-styles": {
106 | "version": "4.2.1",
107 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
108 | "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
109 | "dev": true,
110 | "requires": {
111 | "@types/color-name": "^1.1.1",
112 | "color-convert": "^2.0.1"
113 | }
114 | },
115 | "anymatch": {
116 | "version": "3.1.1",
117 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
118 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
119 | "dev": true,
120 | "requires": {
121 | "normalize-path": "^3.0.0",
122 | "picomatch": "^2.0.4"
123 | }
124 | },
125 | "array-flatten": {
126 | "version": "1.1.1",
127 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
128 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
129 | },
130 | "balanced-match": {
131 | "version": "1.0.0",
132 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
133 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
134 | "dev": true
135 | },
136 | "basic-auth": {
137 | "version": "2.0.1",
138 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
139 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
140 | "requires": {
141 | "safe-buffer": "5.1.2"
142 | }
143 | },
144 | "binary-extensions": {
145 | "version": "2.0.0",
146 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
147 | "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
148 | "dev": true
149 | },
150 | "body-parser": {
151 | "version": "1.19.0",
152 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
153 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
154 | "requires": {
155 | "bytes": "3.1.0",
156 | "content-type": "~1.0.4",
157 | "debug": "2.6.9",
158 | "depd": "~1.1.2",
159 | "http-errors": "1.7.2",
160 | "iconv-lite": "0.4.24",
161 | "on-finished": "~2.3.0",
162 | "qs": "6.7.0",
163 | "raw-body": "2.4.0",
164 | "type-is": "~1.6.17"
165 | }
166 | },
167 | "boxen": {
168 | "version": "4.2.0",
169 | "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
170 | "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==",
171 | "dev": true,
172 | "requires": {
173 | "ansi-align": "^3.0.0",
174 | "camelcase": "^5.3.1",
175 | "chalk": "^3.0.0",
176 | "cli-boxes": "^2.2.0",
177 | "string-width": "^4.1.0",
178 | "term-size": "^2.1.0",
179 | "type-fest": "^0.8.1",
180 | "widest-line": "^3.1.0"
181 | }
182 | },
183 | "brace-expansion": {
184 | "version": "1.1.11",
185 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
186 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
187 | "dev": true,
188 | "requires": {
189 | "balanced-match": "^1.0.0",
190 | "concat-map": "0.0.1"
191 | }
192 | },
193 | "braces": {
194 | "version": "3.0.2",
195 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
196 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
197 | "dev": true,
198 | "requires": {
199 | "fill-range": "^7.0.1"
200 | }
201 | },
202 | "bytes": {
203 | "version": "3.1.0",
204 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
205 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
206 | },
207 | "cacheable-request": {
208 | "version": "6.1.0",
209 | "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz",
210 | "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==",
211 | "dev": true,
212 | "requires": {
213 | "clone-response": "^1.0.2",
214 | "get-stream": "^5.1.0",
215 | "http-cache-semantics": "^4.0.0",
216 | "keyv": "^3.0.0",
217 | "lowercase-keys": "^2.0.0",
218 | "normalize-url": "^4.1.0",
219 | "responselike": "^1.0.2"
220 | },
221 | "dependencies": {
222 | "get-stream": {
223 | "version": "5.1.0",
224 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
225 | "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
226 | "dev": true,
227 | "requires": {
228 | "pump": "^3.0.0"
229 | }
230 | },
231 | "lowercase-keys": {
232 | "version": "2.0.0",
233 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
234 | "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
235 | "dev": true
236 | }
237 | }
238 | },
239 | "camelcase": {
240 | "version": "5.3.1",
241 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
242 | "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
243 | "dev": true
244 | },
245 | "chalk": {
246 | "version": "3.0.0",
247 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
248 | "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
249 | "dev": true,
250 | "requires": {
251 | "ansi-styles": "^4.1.0",
252 | "supports-color": "^7.1.0"
253 | },
254 | "dependencies": {
255 | "has-flag": {
256 | "version": "4.0.0",
257 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
258 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
259 | "dev": true
260 | },
261 | "supports-color": {
262 | "version": "7.1.0",
263 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
264 | "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
265 | "dev": true,
266 | "requires": {
267 | "has-flag": "^4.0.0"
268 | }
269 | }
270 | }
271 | },
272 | "chokidar": {
273 | "version": "3.4.0",
274 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
275 | "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==",
276 | "dev": true,
277 | "requires": {
278 | "anymatch": "~3.1.1",
279 | "braces": "~3.0.2",
280 | "fsevents": "~2.1.2",
281 | "glob-parent": "~5.1.0",
282 | "is-binary-path": "~2.1.0",
283 | "is-glob": "~4.0.1",
284 | "normalize-path": "~3.0.0",
285 | "readdirp": "~3.4.0"
286 | }
287 | },
288 | "ci-info": {
289 | "version": "2.0.0",
290 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
291 | "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
292 | "dev": true
293 | },
294 | "cli-boxes": {
295 | "version": "2.2.0",
296 | "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz",
297 | "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==",
298 | "dev": true
299 | },
300 | "clone-response": {
301 | "version": "1.0.2",
302 | "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
303 | "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
304 | "dev": true,
305 | "requires": {
306 | "mimic-response": "^1.0.0"
307 | }
308 | },
309 | "color-convert": {
310 | "version": "2.0.1",
311 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
312 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
313 | "dev": true,
314 | "requires": {
315 | "color-name": "~1.1.4"
316 | }
317 | },
318 | "color-name": {
319 | "version": "1.1.4",
320 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
321 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
322 | "dev": true
323 | },
324 | "concat-map": {
325 | "version": "0.0.1",
326 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
327 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
328 | "dev": true
329 | },
330 | "configstore": {
331 | "version": "5.0.1",
332 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz",
333 | "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==",
334 | "dev": true,
335 | "requires": {
336 | "dot-prop": "^5.2.0",
337 | "graceful-fs": "^4.1.2",
338 | "make-dir": "^3.0.0",
339 | "unique-string": "^2.0.0",
340 | "write-file-atomic": "^3.0.0",
341 | "xdg-basedir": "^4.0.0"
342 | }
343 | },
344 | "content-disposition": {
345 | "version": "0.5.3",
346 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
347 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
348 | "requires": {
349 | "safe-buffer": "5.1.2"
350 | }
351 | },
352 | "content-type": {
353 | "version": "1.0.4",
354 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
355 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
356 | },
357 | "cookie": {
358 | "version": "0.4.0",
359 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
360 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
361 | },
362 | "cookie-signature": {
363 | "version": "1.0.6",
364 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
365 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
366 | },
367 | "crypto-random-string": {
368 | "version": "2.0.0",
369 | "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
370 | "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
371 | "dev": true
372 | },
373 | "debug": {
374 | "version": "2.6.9",
375 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
376 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
377 | "requires": {
378 | "ms": "2.0.0"
379 | }
380 | },
381 | "decompress-response": {
382 | "version": "3.3.0",
383 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
384 | "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
385 | "dev": true,
386 | "requires": {
387 | "mimic-response": "^1.0.0"
388 | }
389 | },
390 | "deep-extend": {
391 | "version": "0.6.0",
392 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
393 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
394 | "dev": true
395 | },
396 | "defer-to-connect": {
397 | "version": "1.1.3",
398 | "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
399 | "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==",
400 | "dev": true
401 | },
402 | "depd": {
403 | "version": "1.1.2",
404 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
405 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
406 | },
407 | "destroy": {
408 | "version": "1.0.4",
409 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
410 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
411 | },
412 | "dot-prop": {
413 | "version": "5.2.0",
414 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz",
415 | "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==",
416 | "dev": true,
417 | "requires": {
418 | "is-obj": "^2.0.0"
419 | }
420 | },
421 | "duplexer3": {
422 | "version": "0.1.4",
423 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
424 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
425 | "dev": true
426 | },
427 | "ee-first": {
428 | "version": "1.1.1",
429 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
430 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
431 | },
432 | "emoji-regex": {
433 | "version": "7.0.3",
434 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
435 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
436 | "dev": true
437 | },
438 | "encodeurl": {
439 | "version": "1.0.2",
440 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
441 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
442 | },
443 | "end-of-stream": {
444 | "version": "1.4.4",
445 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
446 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
447 | "dev": true,
448 | "requires": {
449 | "once": "^1.4.0"
450 | }
451 | },
452 | "escape-goat": {
453 | "version": "2.1.1",
454 | "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
455 | "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==",
456 | "dev": true
457 | },
458 | "escape-html": {
459 | "version": "1.0.3",
460 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
461 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
462 | },
463 | "etag": {
464 | "version": "1.8.1",
465 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
466 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
467 | },
468 | "express": {
469 | "version": "4.17.1",
470 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
471 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
472 | "requires": {
473 | "accepts": "~1.3.7",
474 | "array-flatten": "1.1.1",
475 | "body-parser": "1.19.0",
476 | "content-disposition": "0.5.3",
477 | "content-type": "~1.0.4",
478 | "cookie": "0.4.0",
479 | "cookie-signature": "1.0.6",
480 | "debug": "2.6.9",
481 | "depd": "~1.1.2",
482 | "encodeurl": "~1.0.2",
483 | "escape-html": "~1.0.3",
484 | "etag": "~1.8.1",
485 | "finalhandler": "~1.1.2",
486 | "fresh": "0.5.2",
487 | "merge-descriptors": "1.0.1",
488 | "methods": "~1.1.2",
489 | "on-finished": "~2.3.0",
490 | "parseurl": "~1.3.3",
491 | "path-to-regexp": "0.1.7",
492 | "proxy-addr": "~2.0.5",
493 | "qs": "6.7.0",
494 | "range-parser": "~1.2.1",
495 | "safe-buffer": "5.1.2",
496 | "send": "0.17.1",
497 | "serve-static": "1.14.1",
498 | "setprototypeof": "1.1.1",
499 | "statuses": "~1.5.0",
500 | "type-is": "~1.6.18",
501 | "utils-merge": "1.0.1",
502 | "vary": "~1.1.2"
503 | }
504 | },
505 | "fill-range": {
506 | "version": "7.0.1",
507 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
508 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
509 | "dev": true,
510 | "requires": {
511 | "to-regex-range": "^5.0.1"
512 | }
513 | },
514 | "finalhandler": {
515 | "version": "1.1.2",
516 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
517 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
518 | "requires": {
519 | "debug": "2.6.9",
520 | "encodeurl": "~1.0.2",
521 | "escape-html": "~1.0.3",
522 | "on-finished": "~2.3.0",
523 | "parseurl": "~1.3.3",
524 | "statuses": "~1.5.0",
525 | "unpipe": "~1.0.0"
526 | }
527 | },
528 | "forwarded": {
529 | "version": "0.1.2",
530 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
531 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
532 | },
533 | "fresh": {
534 | "version": "0.5.2",
535 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
536 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
537 | },
538 | "fsevents": {
539 | "version": "2.1.3",
540 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
541 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
542 | "dev": true,
543 | "optional": true
544 | },
545 | "get-stream": {
546 | "version": "4.1.0",
547 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
548 | "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
549 | "dev": true,
550 | "requires": {
551 | "pump": "^3.0.0"
552 | }
553 | },
554 | "glob-parent": {
555 | "version": "5.1.1",
556 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
557 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
558 | "dev": true,
559 | "requires": {
560 | "is-glob": "^4.0.1"
561 | }
562 | },
563 | "global-dirs": {
564 | "version": "2.0.1",
565 | "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz",
566 | "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==",
567 | "dev": true,
568 | "requires": {
569 | "ini": "^1.3.5"
570 | }
571 | },
572 | "got": {
573 | "version": "9.6.0",
574 | "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
575 | "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==",
576 | "dev": true,
577 | "requires": {
578 | "@sindresorhus/is": "^0.14.0",
579 | "@szmarczak/http-timer": "^1.1.2",
580 | "cacheable-request": "^6.0.0",
581 | "decompress-response": "^3.3.0",
582 | "duplexer3": "^0.1.4",
583 | "get-stream": "^4.1.0",
584 | "lowercase-keys": "^1.0.1",
585 | "mimic-response": "^1.0.1",
586 | "p-cancelable": "^1.0.0",
587 | "to-readable-stream": "^1.0.0",
588 | "url-parse-lax": "^3.0.0"
589 | }
590 | },
591 | "graceful-fs": {
592 | "version": "4.2.4",
593 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
594 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
595 | "dev": true
596 | },
597 | "has-flag": {
598 | "version": "3.0.0",
599 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
600 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
601 | "dev": true
602 | },
603 | "has-yarn": {
604 | "version": "2.1.0",
605 | "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
606 | "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==",
607 | "dev": true
608 | },
609 | "http-cache-semantics": {
610 | "version": "4.1.0",
611 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
612 | "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
613 | "dev": true
614 | },
615 | "http-errors": {
616 | "version": "1.7.2",
617 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
618 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
619 | "requires": {
620 | "depd": "~1.1.2",
621 | "inherits": "2.0.3",
622 | "setprototypeof": "1.1.1",
623 | "statuses": ">= 1.5.0 < 2",
624 | "toidentifier": "1.0.0"
625 | }
626 | },
627 | "iconv-lite": {
628 | "version": "0.4.24",
629 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
630 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
631 | "requires": {
632 | "safer-buffer": ">= 2.1.2 < 3"
633 | }
634 | },
635 | "ignore-by-default": {
636 | "version": "1.0.1",
637 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
638 | "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=",
639 | "dev": true
640 | },
641 | "import-lazy": {
642 | "version": "2.1.0",
643 | "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
644 | "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=",
645 | "dev": true
646 | },
647 | "imurmurhash": {
648 | "version": "0.1.4",
649 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
650 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
651 | "dev": true
652 | },
653 | "inherits": {
654 | "version": "2.0.3",
655 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
656 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
657 | },
658 | "ini": {
659 | "version": "1.3.5",
660 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
661 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
662 | "dev": true
663 | },
664 | "ipaddr.js": {
665 | "version": "1.9.1",
666 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
667 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
668 | },
669 | "is-binary-path": {
670 | "version": "2.1.0",
671 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
672 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
673 | "dev": true,
674 | "requires": {
675 | "binary-extensions": "^2.0.0"
676 | }
677 | },
678 | "is-ci": {
679 | "version": "2.0.0",
680 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
681 | "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
682 | "dev": true,
683 | "requires": {
684 | "ci-info": "^2.0.0"
685 | }
686 | },
687 | "is-extglob": {
688 | "version": "2.1.1",
689 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
690 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
691 | "dev": true
692 | },
693 | "is-fullwidth-code-point": {
694 | "version": "2.0.0",
695 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
696 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
697 | "dev": true
698 | },
699 | "is-glob": {
700 | "version": "4.0.1",
701 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
702 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
703 | "dev": true,
704 | "requires": {
705 | "is-extglob": "^2.1.1"
706 | }
707 | },
708 | "is-installed-globally": {
709 | "version": "0.3.2",
710 | "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz",
711 | "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==",
712 | "dev": true,
713 | "requires": {
714 | "global-dirs": "^2.0.1",
715 | "is-path-inside": "^3.0.1"
716 | }
717 | },
718 | "is-npm": {
719 | "version": "4.0.0",
720 | "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz",
721 | "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==",
722 | "dev": true
723 | },
724 | "is-number": {
725 | "version": "7.0.0",
726 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
727 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
728 | "dev": true
729 | },
730 | "is-obj": {
731 | "version": "2.0.0",
732 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
733 | "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
734 | "dev": true
735 | },
736 | "is-path-inside": {
737 | "version": "3.0.2",
738 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz",
739 | "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==",
740 | "dev": true
741 | },
742 | "is-typedarray": {
743 | "version": "1.0.0",
744 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
745 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
746 | "dev": true
747 | },
748 | "is-yarn-global": {
749 | "version": "0.3.0",
750 | "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz",
751 | "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==",
752 | "dev": true
753 | },
754 | "json-buffer": {
755 | "version": "3.0.0",
756 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
757 | "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=",
758 | "dev": true
759 | },
760 | "keyv": {
761 | "version": "3.1.0",
762 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
763 | "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==",
764 | "dev": true,
765 | "requires": {
766 | "json-buffer": "3.0.0"
767 | }
768 | },
769 | "latest-version": {
770 | "version": "5.1.0",
771 | "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz",
772 | "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==",
773 | "dev": true,
774 | "requires": {
775 | "package-json": "^6.3.0"
776 | }
777 | },
778 | "lowercase-keys": {
779 | "version": "1.0.1",
780 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
781 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
782 | "dev": true
783 | },
784 | "make-dir": {
785 | "version": "3.1.0",
786 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
787 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
788 | "dev": true,
789 | "requires": {
790 | "semver": "^6.0.0"
791 | },
792 | "dependencies": {
793 | "semver": {
794 | "version": "6.3.0",
795 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
796 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
797 | "dev": true
798 | }
799 | }
800 | },
801 | "media-typer": {
802 | "version": "0.3.0",
803 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
804 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
805 | },
806 | "merge-descriptors": {
807 | "version": "1.0.1",
808 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
809 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
810 | },
811 | "methods": {
812 | "version": "1.1.2",
813 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
814 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
815 | },
816 | "mime": {
817 | "version": "1.6.0",
818 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
819 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
820 | },
821 | "mime-db": {
822 | "version": "1.44.0",
823 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
824 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
825 | },
826 | "mime-types": {
827 | "version": "2.1.27",
828 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
829 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
830 | "requires": {
831 | "mime-db": "1.44.0"
832 | }
833 | },
834 | "mimic-response": {
835 | "version": "1.0.1",
836 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
837 | "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
838 | "dev": true
839 | },
840 | "minimatch": {
841 | "version": "3.0.4",
842 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
843 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
844 | "dev": true,
845 | "requires": {
846 | "brace-expansion": "^1.1.7"
847 | }
848 | },
849 | "minimist": {
850 | "version": "1.2.5",
851 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
852 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
853 | "dev": true
854 | },
855 | "morgan": {
856 | "version": "1.10.0",
857 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
858 | "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
859 | "requires": {
860 | "basic-auth": "~2.0.1",
861 | "debug": "2.6.9",
862 | "depd": "~2.0.0",
863 | "on-finished": "~2.3.0",
864 | "on-headers": "~1.0.2"
865 | },
866 | "dependencies": {
867 | "depd": {
868 | "version": "2.0.0",
869 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
870 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
871 | }
872 | }
873 | },
874 | "ms": {
875 | "version": "2.0.0",
876 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
877 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
878 | },
879 | "negotiator": {
880 | "version": "0.6.2",
881 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
882 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
883 | },
884 | "nodemon": {
885 | "version": "2.0.4",
886 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz",
887 | "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==",
888 | "dev": true,
889 | "requires": {
890 | "chokidar": "^3.2.2",
891 | "debug": "^3.2.6",
892 | "ignore-by-default": "^1.0.1",
893 | "minimatch": "^3.0.4",
894 | "pstree.remy": "^1.1.7",
895 | "semver": "^5.7.1",
896 | "supports-color": "^5.5.0",
897 | "touch": "^3.1.0",
898 | "undefsafe": "^2.0.2",
899 | "update-notifier": "^4.0.0"
900 | },
901 | "dependencies": {
902 | "debug": {
903 | "version": "3.2.6",
904 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
905 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
906 | "dev": true,
907 | "requires": {
908 | "ms": "^2.1.1"
909 | }
910 | },
911 | "ms": {
912 | "version": "2.1.2",
913 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
914 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
915 | "dev": true
916 | }
917 | }
918 | },
919 | "nopt": {
920 | "version": "1.0.10",
921 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
922 | "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
923 | "dev": true,
924 | "requires": {
925 | "abbrev": "1"
926 | }
927 | },
928 | "normalize-path": {
929 | "version": "3.0.0",
930 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
931 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
932 | "dev": true
933 | },
934 | "normalize-url": {
935 | "version": "4.5.0",
936 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
937 | "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==",
938 | "dev": true
939 | },
940 | "on-finished": {
941 | "version": "2.3.0",
942 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
943 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
944 | "requires": {
945 | "ee-first": "1.1.1"
946 | }
947 | },
948 | "on-headers": {
949 | "version": "1.0.2",
950 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
951 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
952 | },
953 | "once": {
954 | "version": "1.4.0",
955 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
956 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
957 | "dev": true,
958 | "requires": {
959 | "wrappy": "1"
960 | }
961 | },
962 | "p-cancelable": {
963 | "version": "1.1.0",
964 | "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
965 | "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==",
966 | "dev": true
967 | },
968 | "package-json": {
969 | "version": "6.5.0",
970 | "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
971 | "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==",
972 | "dev": true,
973 | "requires": {
974 | "got": "^9.6.0",
975 | "registry-auth-token": "^4.0.0",
976 | "registry-url": "^5.0.0",
977 | "semver": "^6.2.0"
978 | },
979 | "dependencies": {
980 | "semver": {
981 | "version": "6.3.0",
982 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
983 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
984 | "dev": true
985 | }
986 | }
987 | },
988 | "parseurl": {
989 | "version": "1.3.3",
990 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
991 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
992 | },
993 | "path-to-regexp": {
994 | "version": "0.1.7",
995 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
996 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
997 | },
998 | "picomatch": {
999 | "version": "2.2.2",
1000 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
1001 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
1002 | "dev": true
1003 | },
1004 | "prepend-http": {
1005 | "version": "2.0.0",
1006 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
1007 | "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
1008 | "dev": true
1009 | },
1010 | "proxy-addr": {
1011 | "version": "2.0.6",
1012 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
1013 | "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
1014 | "requires": {
1015 | "forwarded": "~0.1.2",
1016 | "ipaddr.js": "1.9.1"
1017 | }
1018 | },
1019 | "pstree.remy": {
1020 | "version": "1.1.8",
1021 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
1022 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
1023 | "dev": true
1024 | },
1025 | "pump": {
1026 | "version": "3.0.0",
1027 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
1028 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
1029 | "dev": true,
1030 | "requires": {
1031 | "end-of-stream": "^1.1.0",
1032 | "once": "^1.3.1"
1033 | }
1034 | },
1035 | "pupa": {
1036 | "version": "2.0.1",
1037 | "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz",
1038 | "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==",
1039 | "dev": true,
1040 | "requires": {
1041 | "escape-goat": "^2.0.0"
1042 | }
1043 | },
1044 | "qs": {
1045 | "version": "6.7.0",
1046 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
1047 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
1048 | },
1049 | "range-parser": {
1050 | "version": "1.2.1",
1051 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1052 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
1053 | },
1054 | "raw-body": {
1055 | "version": "2.4.0",
1056 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
1057 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
1058 | "requires": {
1059 | "bytes": "3.1.0",
1060 | "http-errors": "1.7.2",
1061 | "iconv-lite": "0.4.24",
1062 | "unpipe": "1.0.0"
1063 | }
1064 | },
1065 | "rc": {
1066 | "version": "1.2.8",
1067 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
1068 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
1069 | "dev": true,
1070 | "requires": {
1071 | "deep-extend": "^0.6.0",
1072 | "ini": "~1.3.0",
1073 | "minimist": "^1.2.0",
1074 | "strip-json-comments": "~2.0.1"
1075 | }
1076 | },
1077 | "readdirp": {
1078 | "version": "3.4.0",
1079 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
1080 | "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
1081 | "dev": true,
1082 | "requires": {
1083 | "picomatch": "^2.2.1"
1084 | }
1085 | },
1086 | "registry-auth-token": {
1087 | "version": "4.1.1",
1088 | "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz",
1089 | "integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==",
1090 | "dev": true,
1091 | "requires": {
1092 | "rc": "^1.2.8"
1093 | }
1094 | },
1095 | "registry-url": {
1096 | "version": "5.1.0",
1097 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz",
1098 | "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==",
1099 | "dev": true,
1100 | "requires": {
1101 | "rc": "^1.2.8"
1102 | }
1103 | },
1104 | "responselike": {
1105 | "version": "1.0.2",
1106 | "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
1107 | "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
1108 | "dev": true,
1109 | "requires": {
1110 | "lowercase-keys": "^1.0.0"
1111 | }
1112 | },
1113 | "safe-buffer": {
1114 | "version": "5.1.2",
1115 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1116 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
1117 | },
1118 | "safer-buffer": {
1119 | "version": "2.1.2",
1120 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1121 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1122 | },
1123 | "semver": {
1124 | "version": "5.7.1",
1125 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1126 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
1127 | "dev": true
1128 | },
1129 | "semver-diff": {
1130 | "version": "3.1.1",
1131 | "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
1132 | "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
1133 | "dev": true,
1134 | "requires": {
1135 | "semver": "^6.3.0"
1136 | },
1137 | "dependencies": {
1138 | "semver": {
1139 | "version": "6.3.0",
1140 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
1141 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
1142 | "dev": true
1143 | }
1144 | }
1145 | },
1146 | "send": {
1147 | "version": "0.17.1",
1148 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
1149 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
1150 | "requires": {
1151 | "debug": "2.6.9",
1152 | "depd": "~1.1.2",
1153 | "destroy": "~1.0.4",
1154 | "encodeurl": "~1.0.2",
1155 | "escape-html": "~1.0.3",
1156 | "etag": "~1.8.1",
1157 | "fresh": "0.5.2",
1158 | "http-errors": "~1.7.2",
1159 | "mime": "1.6.0",
1160 | "ms": "2.1.1",
1161 | "on-finished": "~2.3.0",
1162 | "range-parser": "~1.2.1",
1163 | "statuses": "~1.5.0"
1164 | },
1165 | "dependencies": {
1166 | "ms": {
1167 | "version": "2.1.1",
1168 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
1169 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
1170 | }
1171 | }
1172 | },
1173 | "serve-static": {
1174 | "version": "1.14.1",
1175 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
1176 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
1177 | "requires": {
1178 | "encodeurl": "~1.0.2",
1179 | "escape-html": "~1.0.3",
1180 | "parseurl": "~1.3.3",
1181 | "send": "0.17.1"
1182 | }
1183 | },
1184 | "setprototypeof": {
1185 | "version": "1.1.1",
1186 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
1187 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
1188 | },
1189 | "signal-exit": {
1190 | "version": "3.0.3",
1191 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
1192 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
1193 | "dev": true
1194 | },
1195 | "statuses": {
1196 | "version": "1.5.0",
1197 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
1198 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
1199 | },
1200 | "string-width": {
1201 | "version": "4.2.0",
1202 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
1203 | "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
1204 | "dev": true,
1205 | "requires": {
1206 | "emoji-regex": "^8.0.0",
1207 | "is-fullwidth-code-point": "^3.0.0",
1208 | "strip-ansi": "^6.0.0"
1209 | },
1210 | "dependencies": {
1211 | "ansi-regex": {
1212 | "version": "5.0.0",
1213 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
1214 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
1215 | "dev": true
1216 | },
1217 | "emoji-regex": {
1218 | "version": "8.0.0",
1219 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
1220 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
1221 | "dev": true
1222 | },
1223 | "is-fullwidth-code-point": {
1224 | "version": "3.0.0",
1225 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
1226 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
1227 | "dev": true
1228 | },
1229 | "strip-ansi": {
1230 | "version": "6.0.0",
1231 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
1232 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
1233 | "dev": true,
1234 | "requires": {
1235 | "ansi-regex": "^5.0.0"
1236 | }
1237 | }
1238 | }
1239 | },
1240 | "strip-ansi": {
1241 | "version": "5.2.0",
1242 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
1243 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
1244 | "dev": true,
1245 | "requires": {
1246 | "ansi-regex": "^4.1.0"
1247 | }
1248 | },
1249 | "strip-json-comments": {
1250 | "version": "2.0.1",
1251 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
1252 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
1253 | "dev": true
1254 | },
1255 | "supports-color": {
1256 | "version": "5.5.0",
1257 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1258 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1259 | "dev": true,
1260 | "requires": {
1261 | "has-flag": "^3.0.0"
1262 | }
1263 | },
1264 | "term-size": {
1265 | "version": "2.2.0",
1266 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz",
1267 | "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==",
1268 | "dev": true
1269 | },
1270 | "to-readable-stream": {
1271 | "version": "1.0.0",
1272 | "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
1273 | "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==",
1274 | "dev": true
1275 | },
1276 | "to-regex-range": {
1277 | "version": "5.0.1",
1278 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1279 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1280 | "dev": true,
1281 | "requires": {
1282 | "is-number": "^7.0.0"
1283 | }
1284 | },
1285 | "toidentifier": {
1286 | "version": "1.0.0",
1287 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
1288 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
1289 | },
1290 | "touch": {
1291 | "version": "3.1.0",
1292 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
1293 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
1294 | "dev": true,
1295 | "requires": {
1296 | "nopt": "~1.0.10"
1297 | }
1298 | },
1299 | "type-fest": {
1300 | "version": "0.8.1",
1301 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
1302 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
1303 | "dev": true
1304 | },
1305 | "type-is": {
1306 | "version": "1.6.18",
1307 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1308 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1309 | "requires": {
1310 | "media-typer": "0.3.0",
1311 | "mime-types": "~2.1.24"
1312 | }
1313 | },
1314 | "typedarray-to-buffer": {
1315 | "version": "3.1.5",
1316 | "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
1317 | "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
1318 | "dev": true,
1319 | "requires": {
1320 | "is-typedarray": "^1.0.0"
1321 | }
1322 | },
1323 | "undefsafe": {
1324 | "version": "2.0.3",
1325 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz",
1326 | "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==",
1327 | "dev": true,
1328 | "requires": {
1329 | "debug": "^2.2.0"
1330 | }
1331 | },
1332 | "unique-string": {
1333 | "version": "2.0.0",
1334 | "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
1335 | "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
1336 | "dev": true,
1337 | "requires": {
1338 | "crypto-random-string": "^2.0.0"
1339 | }
1340 | },
1341 | "unpipe": {
1342 | "version": "1.0.0",
1343 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1344 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
1345 | },
1346 | "update-notifier": {
1347 | "version": "4.1.0",
1348 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.0.tgz",
1349 | "integrity": "sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==",
1350 | "dev": true,
1351 | "requires": {
1352 | "boxen": "^4.2.0",
1353 | "chalk": "^3.0.0",
1354 | "configstore": "^5.0.1",
1355 | "has-yarn": "^2.1.0",
1356 | "import-lazy": "^2.1.0",
1357 | "is-ci": "^2.0.0",
1358 | "is-installed-globally": "^0.3.1",
1359 | "is-npm": "^4.0.0",
1360 | "is-yarn-global": "^0.3.0",
1361 | "latest-version": "^5.0.0",
1362 | "pupa": "^2.0.1",
1363 | "semver-diff": "^3.1.1",
1364 | "xdg-basedir": "^4.0.0"
1365 | }
1366 | },
1367 | "url-parse-lax": {
1368 | "version": "3.0.0",
1369 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
1370 | "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
1371 | "dev": true,
1372 | "requires": {
1373 | "prepend-http": "^2.0.0"
1374 | }
1375 | },
1376 | "utils-merge": {
1377 | "version": "1.0.1",
1378 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1379 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
1380 | },
1381 | "vary": {
1382 | "version": "1.1.2",
1383 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1384 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
1385 | },
1386 | "widest-line": {
1387 | "version": "3.1.0",
1388 | "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
1389 | "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
1390 | "dev": true,
1391 | "requires": {
1392 | "string-width": "^4.0.0"
1393 | }
1394 | },
1395 | "wrappy": {
1396 | "version": "1.0.2",
1397 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1398 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
1399 | "dev": true
1400 | },
1401 | "write-file-atomic": {
1402 | "version": "3.0.3",
1403 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
1404 | "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
1405 | "dev": true,
1406 | "requires": {
1407 | "imurmurhash": "^0.1.4",
1408 | "is-typedarray": "^1.0.0",
1409 | "signal-exit": "^3.0.2",
1410 | "typedarray-to-buffer": "^3.1.5"
1411 | }
1412 | },
1413 | "xdg-basedir": {
1414 | "version": "4.0.0",
1415 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
1416 | "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
1417 | "dev": true
1418 | }
1419 | }
1420 | }
1421 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "desafio-02",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node index.js",
8 | "dev": "nodemon index.js",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "@hapi/joi": "^15.1.1",
16 | "express": "^4.17.1",
17 | "morgan": "^1.10.0"
18 | },
19 | "devDependencies": {
20 | "nodemon": "^2.0.4"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/src/app.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const morgan = require('morgan');
3 |
4 | const errorHandlers = require('./util/error-handlers');
5 |
6 | const app = express();
7 |
8 | app.use(express.json());
9 | app.use(morgan('dev'));
10 |
11 | // routes
12 | app.use('/grades', require('./routes/grades.routes'));
13 |
14 | app.use(errorHandlers.handler404);
15 | app.use(errorHandlers.handler500);
16 |
17 | module.exports = app;
18 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/src/controllers/grades.controller.js:
--------------------------------------------------------------------------------
1 | const GradesRepository = require('../repositories/grades.repository');
2 |
3 | const create = (req, res) => {
4 | const newGrade = GradesRepository.create(req.body);
5 |
6 | res.status(201).json(newGrade);
7 | };
8 |
9 | const update = (req, res) => {
10 | const updatedGrade = GradesRepository.update(parseInt(req.params.id), req.body);
11 |
12 | res.status(200).json(updatedGrade);
13 | };
14 |
15 | const remove = (req, res) => {
16 | const removedGrade = GradesRepository.remove(parseInt(req.params.id));
17 |
18 | res.status(200).json(removedGrade);
19 | };
20 |
21 | const find = (req, res) => {
22 | const grade = GradesRepository.findById(parseInt(req.params.id));
23 |
24 | res.status(200).json(grade);
25 | };
26 |
27 | const getStudentTotalBySubject = (req, res) => {
28 | const total = GradesRepository
29 | .findAll()
30 | .filter(filterByStudent(req.params.student))
31 | .filter(filterBySubject(req.params.subject))
32 | .reduce(sumGrades, 0);
33 |
34 | res.status(200).json({total});
35 | };
36 |
37 | const getAverageBySubjectAndType = (req, res) => {
38 | const grades = GradesRepository
39 | .findAll()
40 | .filter(filterBySubject(req.params.subject))
41 | .filter(filterByType(req.params.type));
42 |
43 | const avg = grades.reduce(sumGrades, 0) / grades.length;
44 |
45 | res.status(200).json({avg});
46 | };
47 |
48 | const getTopGradesBySubjectAndType = (req, res) => {
49 | const topGrades = GradesRepository
50 | .findAll()
51 | .filter(filterBySubject(req.params.subject))
52 | .filter(filterByType(req.params.type))
53 | .sort(sortGradesDesc)
54 | .slice(0, 3);
55 |
56 | res.status(200).json(topGrades);
57 | };
58 |
59 | const filterByStudent = (student) => (grade) => grade.student === student;
60 | const filterBySubject = (subject) => (grade) => grade.subject === subject;
61 | const filterByType = (type) => (grade) => grade.type === type;
62 | const sumGrades = (sum, curr) => sum += curr.value;
63 | const sortGradesDesc = (gradeA, gradeB) => gradeB.value - gradeA.value;
64 |
65 | module.exports = {
66 | create,
67 | update,
68 | remove,
69 | find,
70 | getStudentTotalBySubject,
71 | getAverageBySubjectAndType,
72 | getTopGradesBySubjectAndType
73 | };
74 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/src/data/grades.json:
--------------------------------------------------------------------------------
1 | {"nextId":49,"grades":[{"id":1,"student":"Loiane Groner","subject":"01 - JavaScript","type":"Fórum","value":15,"timestamp":"2020-05-19T18:21:24.958Z"},{"id":2,"student":"Loiane Groner","subject":"02 - Node","type":"Fórum","value":5,"timestamp":"2020-05-19T18:21:24.964Z"},{"id":3,"student":"Loiane Groner","subject":"03 - React","type":"Fórum","value":14,"timestamp":"2020-05-19T18:21:24.970Z"},{"id":4,"student":"Loiane Groner","subject":"04 - MongoDB","type":"Fórum","value":2,"timestamp":"2020-05-19T18:21:24.975Z"},{"id":5,"student":"Loiane Groner","subject":"01 - JavaScript","type":"Trabalho Prático","value":21,"timestamp":"2020-05-19T18:21:24.981Z"},{"id":6,"student":"Loiane Groner","subject":"02 - Node","type":"Trabalho Prático","value":24,"timestamp":"2020-05-19T18:21:24.987Z"},{"id":7,"student":"Loiane Groner","subject":"03 - React","type":"Trabalho Prático","value":2,"timestamp":"2020-05-19T18:21:24.993Z"},{"id":8,"student":"Loiane Groner","subject":"04 - MongoDB","type":"Trabalho Prático","value":30,"timestamp":"2020-05-19T18:21:24.999Z"},{"id":9,"student":"Loiane Groner","subject":"01 - JavaScript","type":"Desafio","value":5,"timestamp":"2020-05-19T18:21:25.004Z"},{"id":10,"student":"Loiane Groner","subject":"02 - Node","type":"Desafio","value":18,"timestamp":"2020-05-19T18:21:25.012Z"},{"id":11,"student":"Loiane Groner","subject":"03 - React","type":"Desafio","value":40,"timestamp":"2020-05-19T18:21:25.019Z"},{"id":12,"student":"Loiane Groner","subject":"04 - MongoDB","type":"Desafio","value":44,"timestamp":"2020-05-19T18:21:25.025Z"},{"id":13,"student":"Roberta Arcoverde","subject":"01 - JavaScript","type":"Fórum","value":13,"timestamp":"2020-05-19T18:21:25.032Z"},{"id":14,"student":"Roberta Arcoverde","subject":"02 - Node","type":"Fórum","value":16,"timestamp":"2020-05-19T18:21:25.039Z"},{"id":15,"student":"Roberta Arcoverde","subject":"03 - React","type":"Fórum","value":1,"timestamp":"2020-05-19T18:21:25.047Z"},{"id":16,"student":"Roberta Arcoverde","subject":"04 - MongoDB","type":"Fórum","value":7,"timestamp":"2020-05-19T18:21:25.053Z"},{"id":17,"student":"Roberta Arcoverde","subject":"01 - JavaScript","type":"Trabalho Prático","value":12,"timestamp":"2020-05-19T18:21:25.059Z"},{"id":18,"student":"Roberta Arcoverde","subject":"02 - Node","type":"Trabalho Prático","value":21,"timestamp":"2020-05-19T18:21:25.066Z"},{"id":19,"student":"Roberta Arcoverde","subject":"03 - React","type":"Trabalho Prático","value":7,"timestamp":"2020-05-19T18:21:25.072Z"},{"id":20,"student":"Roberta Arcoverde","subject":"04 - MongoDB","type":"Trabalho Prático","value":20,"timestamp":"2020-05-19T18:21:25.077Z"},{"id":21,"student":"Roberta Arcoverde","subject":"01 - JavaScript","type":"Desafio","value":16,"timestamp":"2020-05-19T18:21:25.084Z"},{"id":22,"student":"Roberta Arcoverde","subject":"02 - Node","type":"Desafio","value":9,"timestamp":"2020-05-19T18:21:25.090Z"},{"id":23,"student":"Roberta Arcoverde","subject":"03 - React","type":"Desafio","value":15,"timestamp":"2020-05-19T18:21:25.098Z"},{"id":24,"student":"Roberta Arcoverde","subject":"04 - MongoDB","type":"Desafio","value":14,"timestamp":"2020-05-19T18:21:25.106Z"},{"id":25,"student":"Roberto Achar","subject":"01 - JavaScript","type":"Fórum","value":9,"timestamp":"2020-05-19T18:21:25.113Z"},{"id":26,"student":"Roberto Achar","subject":"02 - Node","type":"Fórum","value":17,"timestamp":"2020-05-19T18:21:25.128Z"},{"id":27,"student":"Roberto Achar","subject":"03 - React","type":"Fórum","value":10,"timestamp":"2020-05-19T18:21:25.140Z"},{"id":28,"student":"Roberto Achar","subject":"04 - MongoDB","type":"Fórum","value":7,"timestamp":"2020-05-19T18:21:25.150Z"},{"id":29,"student":"Roberto Achar","subject":"01 - JavaScript","type":"Trabalho Prático","value":2,"timestamp":"2020-05-19T18:21:25.157Z"},{"id":30,"student":"Roberto Achar","subject":"02 - Node","type":"Trabalho Prático","value":30,"timestamp":"2020-05-19T18:21:25.165Z"},{"id":31,"student":"Roberto Achar","subject":"03 - React","type":"Trabalho Prático","value":27,"timestamp":"2020-05-19T18:21:25.171Z"},{"id":32,"student":"Roberto Achar","subject":"04 - MongoDB","type":"Trabalho Prático","value":16,"timestamp":"2020-05-19T18:21:25.178Z"},{"id":33,"student":"Roberto Achar","subject":"01 - JavaScript","type":"Desafio","value":25,"timestamp":"2020-05-19T18:21:25.184Z"},{"id":34,"student":"Roberto Achar","subject":"02 - Node","type":"Desafio","value":37,"timestamp":"2020-05-19T18:21:25.191Z"},{"id":35,"student":"Roberto Achar","subject":"03 - React","type":"Desafio","value":23,"timestamp":"2020-05-19T18:21:25.198Z"},{"id":36,"student":"Roberto Achar","subject":"04 - MongoDB","type":"Desafio","value":43,"timestamp":"2020-05-19T18:21:25.204Z"},{"id":37,"student":"Rodrigo Branas","subject":"01 - JavaScript","type":"Fórum","value":6,"timestamp":"2020-05-19T18:21:25.211Z"},{"id":38,"student":"Rodrigo Branas","subject":"02 - Node","type":"Fórum","value":16,"timestamp":"2020-05-19T18:21:25.217Z"},{"id":39,"student":"Rodrigo Branas","subject":"03 - React","type":"Fórum","value":3,"timestamp":"2020-05-19T18:21:25.225Z"},{"id":40,"student":"Rodrigo Branas","subject":"04 - MongoDB","type":"Fórum","value":2,"timestamp":"2020-05-19T18:21:25.232Z"},{"id":41,"student":"Rodrigo Branas","subject":"01 - JavaScript","type":"Trabalho Prático","value":13,"timestamp":"2020-05-19T18:21:25.240Z"},{"id":42,"student":"Rodrigo Branas","subject":"02 - Node","type":"Trabalho Prático","value":18,"timestamp":"2020-05-19T18:21:25.247Z"},{"id":43,"student":"Rodrigo Branas","subject":"03 - React","type":"Trabalho Prático","value":6,"timestamp":"2020-05-19T18:21:25.253Z"},{"id":44,"student":"Rodrigo Branas","subject":"04 - MongoDB","type":"Trabalho Prático","value":28,"timestamp":"2020-05-19T18:21:25.260Z"},{"id":45,"student":"Rodrigo Branas","subject":"01 - JavaScript","type":"Desafio","value":16,"timestamp":"2020-05-19T18:21:25.266Z"},{"id":46,"student":"Rodrigo Branas","subject":"02 - Node","type":"Desafio","value":44,"timestamp":"2020-05-19T18:21:25.272Z"},{"id":47,"student":"Rodrigo Branas","subject":"03 - React","type":"Desafio","value":36,"timestamp":"2020-05-19T18:21:25.278Z"},{"id":48,"student":"Rodrigo Branas","subject":"04 - MongoDB","type":"Desafio","value":45,"timestamp":"2020-05-19T18:21:25.284Z"}]}
--------------------------------------------------------------------------------
/modulo-02/desafio-02/src/repositories/grades.repository.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | const NotFoundError = require('../util/not-found.error');
5 |
6 | const filepath = path.resolve(__dirname, '../data/grades.json');
7 |
8 | const loadData = () => {
9 | return JSON.parse(fs.readFileSync(filepath));
10 | };
11 |
12 | const getNextId = () => {
13 | return loadData().nextId;
14 | };
15 |
16 | const getGrades = () => {
17 | return loadData().grades;
18 | };
19 |
20 | const save = (newData) => {
21 | fs.writeFileSync(filepath, JSON.stringify(newData));
22 | };
23 |
24 | const create = (gradeData) => {
25 | const newGrade = {
26 | id: getNextId(),
27 | ...gradeData,
28 | timestamp: new Date()
29 | };
30 |
31 | const data = {
32 | nextId: getNextId() + 1,
33 | grades: [
34 | ...getGrades(),
35 | newGrade
36 | ]
37 | };
38 |
39 | save(data);
40 |
41 | return newGrade;
42 | };
43 |
44 | const update = (id, gradeData) => {
45 | const grades = getGrades();
46 | const index = grades.findIndex(g => g.id === id);
47 |
48 | if (index < 0) throw new NotFoundError(`Grade with id ${id} not found`);
49 |
50 | const updatedGrade = {
51 | ...grades[index],
52 | ...gradeData
53 | };
54 |
55 | grades[index] = updatedGrade;
56 |
57 | save({
58 | nextId: getNextId(),
59 | grades
60 | });
61 |
62 | return updatedGrade;
63 | };
64 |
65 | const remove = (id) => {
66 | const grades = getGrades();
67 | const index = grades.findIndex(g => g.id === id);
68 |
69 | if (index < 0) throw new NotFoundError(`Grade with id ${id} not found`);
70 |
71 | const removedGrade = grades[index];
72 |
73 | save({
74 | nextId: getNextId(),
75 | grades: grades.filter(g => g.id !== id)
76 | });
77 |
78 | return removedGrade;
79 | };
80 |
81 | const findById = (id) => {
82 | const grade = getGrades().find(g => g.id === id);
83 |
84 | if (!grade) throw new NotFoundError(`Grade with id ${id} not found`);
85 |
86 | return grade;
87 | };
88 |
89 | module.exports = {
90 | create,
91 | update,
92 | remove,
93 | findById,
94 | findAll: getGrades
95 | };
96 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/src/routes/grades.routes.js:
--------------------------------------------------------------------------------
1 | const { Router } = require('express');
2 | const GradesController = require('../controllers/grades.controller');
3 |
4 | const idValidator = require('../validators/id.validator');
5 | const gradesValidator = require('../validators/grades.validator');
6 |
7 | const router = Router();
8 |
9 | router.post('/', [
10 | gradesValidator,
11 | GradesController.create
12 | ]);
13 |
14 | router.get('/:id', [
15 | idValidator,
16 | GradesController.find
17 | ]);
18 |
19 | router.put('/:id', [
20 | idValidator,
21 | gradesValidator,
22 | GradesController.update
23 | ]);
24 |
25 | router.delete('/:id', [
26 | idValidator,
27 | GradesController.remove
28 | ]);
29 |
30 | router.get('/:student/:subject/total', GradesController.getStudentTotalBySubject);
31 | router.get('/:subject/:type/avg', GradesController.getAverageBySubjectAndType);
32 | router.get('/:subject/:type/top', GradesController.getTopGradesBySubjectAndType);
33 |
34 | module.exports = router;
35 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/src/util/error-handlers.js:
--------------------------------------------------------------------------------
1 | const NotFoundError = require('./not-found.error');
2 |
3 | exports.handler404 = (req, res, next) => {
4 | res
5 | .status(404)
6 | .json({ status: 404, message: 'Not Found' });
7 | };
8 |
9 | exports.handler500 = (err, req, res, next) => {
10 | console.error(err);
11 |
12 | const status = err instanceof NotFoundError ? 404 : 500;
13 |
14 | res
15 | .status(status)
16 | .json({ status, message: err.message });
17 | };
18 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/src/util/not-found.error.js:
--------------------------------------------------------------------------------
1 | class NotFoundError extends Error {
2 | constructor(msg) {
3 | super(msg);
4 | }
5 | }
6 |
7 | module.exports = NotFoundError;
8 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/src/validators/grades.validator.js:
--------------------------------------------------------------------------------
1 | const Joi = require('@hapi/joi');
2 |
3 | module.exports = function(req, res, next) {
4 |
5 | Joi
6 | .object()
7 | .keys({
8 | student : Joi.string().required(),
9 | subject : Joi.string().required(),
10 | type : Joi.string().required(),
11 | value : Joi.number().required(),
12 | })
13 | .validate(req.body, err => {
14 | if (err) return res.status(422).json(err.details);
15 |
16 | return next();
17 | });
18 | };
19 |
--------------------------------------------------------------------------------
/modulo-02/desafio-02/src/validators/id.validator.js:
--------------------------------------------------------------------------------
1 | const Joi = require('@hapi/joi');
2 |
3 | module.exports = function(req, res, next) {
4 |
5 | Joi
6 | .object()
7 | .keys({
8 | id : Joi.number().integer().positive().required(),
9 | })
10 | .validate(req.params, err => {
11 | if (err) return res.status(422).json(err.details);
12 |
13 | return next();
14 | });
15 | };
16 |
--------------------------------------------------------------------------------
/modulo-02/trabalho-pratico-02/.gitignore:
--------------------------------------------------------------------------------
1 | output/
2 |
--------------------------------------------------------------------------------
/modulo-02/trabalho-pratico-02/data/estados.json:
--------------------------------------------------------------------------------
1 | [{
2 | "ID": "1",
3 | "Sigla": "AC",
4 | "Nome": "Acre"
5 | },
6 | {
7 | "ID": "2",
8 | "Sigla": "AL",
9 | "Nome": "Alagoas"
10 | },
11 | {
12 | "ID": "3",
13 | "Sigla": "AM",
14 | "Nome": "Amazonas"
15 | },
16 | {
17 | "ID": "4",
18 | "Sigla": "AP",
19 | "Nome": "Amapá"
20 | },
21 | {
22 | "ID": "5",
23 | "Sigla": "BA",
24 | "Nome": "Bahia"
25 | },
26 | {
27 | "ID": "6",
28 | "Sigla": "CE",
29 | "Nome": "Ceará"
30 | },
31 | {
32 | "ID": "7",
33 | "Sigla": "DF",
34 | "Nome": "Distrito Federal"
35 | },
36 | {
37 | "ID": "8",
38 | "Sigla": "ES",
39 | "Nome": "Espírito Santo"
40 | },
41 | {
42 | "ID": "9",
43 | "Sigla": "GO",
44 | "Nome": "Goiás"
45 | },
46 | {
47 | "ID": "10",
48 | "Sigla": "MA",
49 | "Nome": "Maranhão"
50 | },
51 | {
52 | "ID": "11",
53 | "Sigla": "MG",
54 | "Nome": "Minas Gerais"
55 | },
56 | {
57 | "ID": "12",
58 | "Sigla": "MS",
59 | "Nome": "Mato Grosso do Sul"
60 | },
61 | {
62 | "ID": "13",
63 | "Sigla": "MT",
64 | "Nome": "Mato Grosso"
65 | },
66 | {
67 | "ID": "14",
68 | "Sigla": "PA",
69 | "Nome": "Pará"
70 | },
71 | {
72 | "ID": "15",
73 | "Sigla": "PB",
74 | "Nome": "Paraíba"
75 | },
76 | {
77 | "ID": "16",
78 | "Sigla": "PE",
79 | "Nome": "Pernambuco"
80 | },
81 | {
82 | "ID": "17",
83 | "Sigla": "PI",
84 | "Nome": "Piauí"
85 | },
86 | {
87 | "ID": "18",
88 | "Sigla": "PR",
89 | "Nome": "Paraná"
90 | },
91 | {
92 | "ID": "19",
93 | "Sigla": "RJ",
94 | "Nome": "Rio de Janeiro"
95 | },
96 | {
97 | "ID": "20",
98 | "Sigla": "RN",
99 | "Nome": "Rio Grande do Norte"
100 | },
101 | {
102 | "ID": "21",
103 | "Sigla": "RO",
104 | "Nome": "Rondônia"
105 | },
106 | {
107 | "ID": "22",
108 | "Sigla": "RR",
109 | "Nome": "Roraima"
110 | },
111 | {
112 | "ID": "23",
113 | "Sigla": "RS",
114 | "Nome": "Rio Grande do Sul"
115 | },
116 | {
117 | "ID": "24",
118 | "Sigla": "SC",
119 | "Nome": "Santa Catarina"
120 | },
121 | {
122 | "ID": "25",
123 | "Sigla": "SE",
124 | "Nome": "Sergipe"
125 | },
126 | {
127 | "ID": "26",
128 | "Sigla": "SP",
129 | "Nome": "São Paulo"
130 | },
131 | {
132 | "ID": "27",
133 | "Sigla": "TO",
134 | "Nome": "Tocantins"
135 | }]
--------------------------------------------------------------------------------
/modulo-02/trabalho-pratico-02/index.js:
--------------------------------------------------------------------------------
1 | const StatesCitiesDataProcessor = require('./states-cities-data-processor');
2 |
3 | /**
4 | * 1. Implementar um método que irá criar um arquivo JSON para cada estado representado
5 | * no arquivo Estados.json, e o seu conteúdo será um array das cidades pertencentes
6 | * aquele estado, de acordo com o arquivo Cidades.json.
7 | * O nome do arquivo deve ser o UF do estado, por exemplo: MG.json.
8 | */
9 | StatesCitiesDataProcessor.generateFiles();
10 |
11 | /**
12 | * 2. Criar um método que recebe como parâmetro o UF do estado, realize a leitura do arquivo
13 | * JSON correspondente e retorne a quantidade de cidades daquele estado.
14 | */
15 | StatesCitiesDataProcessor.getTotalCitiesByState('ac');
16 |
17 | /**
18 | * 3. Criar um método que imprima no console um array com o UF dos cinco estados que mais
19 | * possuem cidades, seguidos da quantidade, em ordem decrescente. Utilize o método criado no
20 | * tópico anterior.
21 | * Exemplo de impressão: [“UF - 93”, “UF - 82”, “UF - 74”, “UF - 72”, “UF - 65”]
22 | */
23 | StatesCitiesDataProcessor.printStatesWithMostCities();
24 |
25 | /**
26 | * 4. Criar um método que imprima no console um array com o UF dos cinco estados que menos
27 | * possuem cidades, seguidos da quantidade, em ordem decrescente. Utilize o método criado no
28 | * tópico anterior.
29 | * Exemplo de impressão: [“UF - 30”, “UF - 27”, “UF - 25”, “UF - 23”, “UF - 21”]
30 | */
31 | StatesCitiesDataProcessor.printStatesWithLessCities();
32 |
33 | /**
34 | * 5. Criar um método que imprima no console um array com a cidade de maior nome de cada estado,
35 | * seguida de seu UF. Em caso de empate, considerar a ordem alfabética para ordená-los e então
36 | * retornar o primeiro.
37 | * Por exemplo: [“Nome da Cidade – UF”, “Nome da Cidade – UF”, ...].
38 | */
39 | StatesCitiesDataProcessor.printBiggestNameCities();
40 |
41 | /**
42 | * 6. Criar um método que imprima no console um array com a cidade de menor nome de cada estado,
43 | * seguida de seu UF. Em caso de empate, considerar a ordem alfabética para ordená-los e então
44 | * retorne o primeiro.
45 | * Por exemplo: [“Nome da Cidade – UF”, “Nome da Cidade – UF”, ...].
46 | */
47 | StatesCitiesDataProcessor.printShortestNameCities();
48 |
49 | /**
50 | * 7. Criar um método que imprima no console a cidade de maior nome entre todos os estados,
51 | * seguido do seu UF. Em caso de empate, considerar a ordem alfabética para ordená-los e então
52 | * retornar o primeiro.
53 | * Exemplo: “Nome da Cidade - UF".
54 | */
55 | StatesCitiesDataProcessor.printBiggestNameCity();
56 |
57 | /**
58 | * 8. Criar um método que imprima no console a cidade de menor nome entre todos os estados,
59 | * seguido do seu UF. Em caso de empate, considerar a ordem alfabética para ordená-los e então
60 | * retornar o primeiro.
61 | * Exemplo: “Nome da Cidade - UF".
62 | */
63 | StatesCitiesDataProcessor.printShortestNameCity();
64 |
--------------------------------------------------------------------------------
/modulo-02/trabalho-pratico-02/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "trabalho-pratico-02",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node index.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC"
13 | }
14 |
--------------------------------------------------------------------------------
/modulo-02/trabalho-pratico-02/states-cities-data-processor.js:
--------------------------------------------------------------------------------
1 | const StatesCitiesFileProcessor = require('./states-cities-file-processor');
2 |
3 | const getTotalCitiesByState = (uf) => {
4 | return StatesCitiesFileProcessor.getStateCities(uf).length;
5 | }
6 |
7 | const getStatesWithTotalCities = () => {
8 | return StatesCitiesFileProcessor
9 | .getAllStates()
10 | .map(state => ({
11 | uf: state.Sigla,
12 | totalCities: getTotalCitiesByState(state.Sigla)
13 | }));
14 | };
15 |
16 | const printStatesWithMostCities = () => {
17 | const top5 = getStatesWithTotalCities()
18 | .sort((a, b) => b.totalCities - a.totalCities)
19 | .slice(0, 5)
20 | .map(data => `${data.uf} - ${data.totalCities}`);
21 |
22 | console.log(top5);
23 | }
24 |
25 | const printStatesWithLessCities = () => {
26 | const bottom5 = getStatesWithTotalCities()
27 | .sort((a, b) => a.totalCities - b.totalCities)
28 | .slice(0, 5)
29 | .map(data => `${data.uf} - ${data.totalCities}`);
30 |
31 | console.log(bottom5);
32 | }
33 |
34 | const getCityWithBiggestName = (uf) => {
35 | return StatesCitiesFileProcessor
36 | .getStateCities(uf)
37 | .sort((a, b) => a.Nome.localeCompare(b.Nome))
38 | .sort((a, b) => b.Nome.length - a.Nome.length)[0];
39 | }
40 |
41 | const getCityWithShortestName = (uf) => {
42 | return StatesCitiesFileProcessor
43 | .getStateCities(uf)
44 | .sort((a, b) => a.Nome.localeCompare(b.Nome))
45 | .sort((a, b) => a.Nome.length - b.Nome.length)[0];
46 | }
47 |
48 | const printBiggestNameCities = () => {
49 | const data = StatesCitiesFileProcessor
50 | .getAllStates()
51 | .map(state => ({
52 | uf : state.Sigla,
53 | name : getCityWithBiggestName(state.Sigla).Nome
54 | }))
55 | .map(city => `${city.name} - ${city.uf}`);
56 |
57 | console.log(data);
58 | }
59 |
60 | const printShortestNameCities = () => {
61 | const data = StatesCitiesFileProcessor
62 | .getAllStates()
63 | .map(state => ({
64 | uf : state.Sigla,
65 | name : getCityWithShortestName(state.Sigla).Nome
66 | }))
67 | .map(city => `${city.name} - ${city.uf}`);
68 |
69 | console.log(data);
70 | }
71 |
72 | const printBiggestNameCity = () => {
73 | const data = StatesCitiesFileProcessor
74 | .getAllStates()
75 | .map(state => ({
76 | uf : state.Sigla,
77 | name : getCityWithBiggestName(state.Sigla).Nome
78 | }))
79 | .sort((a, b) => a.name.localeCompare(b.name))
80 | .sort((a, b) => b.name.length - a.name.length);
81 |
82 | console.log(data[0]);
83 | }
84 |
85 | const printShortestNameCity = () => {
86 | const data = StatesCitiesFileProcessor
87 | .getAllStates()
88 | .map(state => ({
89 | uf : state.Sigla,
90 | name : getCityWithShortestName(state.Sigla).Nome
91 | }))
92 | .sort((a, b) => a.name.localeCompare(b.name))
93 | .sort((a, b) => a.name.length - b.name.length);
94 |
95 | console.log(data[0]);
96 | }
97 |
98 | module.exports = {
99 | generateFiles: StatesCitiesFileProcessor.generateAllCitiesByStateFiles,
100 | getTotalCitiesByState,
101 | printStatesWithMostCities,
102 | printStatesWithLessCities,
103 | printBiggestNameCities,
104 | printShortestNameCities,
105 | printBiggestNameCity,
106 | printShortestNameCity
107 | };
108 |
--------------------------------------------------------------------------------
/modulo-02/trabalho-pratico-02/states-cities-file-processor.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | const inputFolder = 'data';
4 | const outputFolder = 'output';
5 |
6 | const getFileData = (path) => {
7 | return JSON.parse(fs.readFileSync(path));
8 | }
9 |
10 | const generateAllCitiesByStateFiles = () => {
11 | const allStates = getAllStates();
12 | const allCities = getAllCities();
13 |
14 | allStates
15 | .map(processCitiesByStateFileData(allCities))
16 | .forEach(generateCitiesByStateFile);
17 | };
18 |
19 | const getAllStates = () => {
20 | return getFileData(`${inputFolder}/estados.json`);
21 | };
22 |
23 | const getAllCities = () => {
24 | return getFileData(`${inputFolder}/cidades.json`);
25 | };
26 |
27 | const getStateCities = (uf) => {
28 | return getFileData(`${outputFolder}/${uf.toUpperCase()}.json`);
29 | };
30 |
31 | const processCitiesByStateFileData = (allCities) => (state) => ({
32 | filename : `${outputFolder}/${state.Sigla}.json`,
33 | data : JSON.stringify(allCities.filter(city => city.Estado === state.ID))
34 | });
35 |
36 | const generateCitiesByStateFile = ({filename, data}) => {
37 | fs.mkdirSync(outputFolder, {
38 | recursive: true
39 | });
40 |
41 | fs.writeFileSync(filename, data);
42 | };
43 |
44 | module.exports = {
45 | generateAllCitiesByStateFiles,
46 | getStateCities,
47 | getAllStates
48 | };
49 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `yarn start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `yarn test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `yarn build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `yarn eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `yarn build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "desafio-03",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.3.2",
8 | "@testing-library/user-event": "^7.1.2",
9 | "bootstrap": "^4.5.0",
10 | "react": "^16.13.1",
11 | "react-dom": "^16.13.1",
12 | "react-scripts": "3.4.1"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": "react-app"
22 | },
23 | "browserslist": {
24 | "production": [
25 | ">0.2%",
26 | "not dead",
27 | "not op_mini all"
28 | ],
29 | "development": [
30 | "last 1 chrome version",
31 | "last 1 firefox version",
32 | "last 1 safari version"
33 | ]
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/desafio-03/public/favicon.ico
--------------------------------------------------------------------------------
/modulo-03/desafio-03/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/desafio-03/public/logo192.png
--------------------------------------------------------------------------------
/modulo-03/desafio-03/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/desafio-03/public/logo512.png
--------------------------------------------------------------------------------
/modulo-03/desafio-03/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/App.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/desafio-03/src/App.css
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import './App.css';
3 |
4 | import calcCompoundInterest from './util/compound-interest';
5 |
6 | import Form from './components/form';
7 | import Table from './components/table';
8 |
9 | function App() {
10 |
11 | const [compoundInterest, setCompoundInterest] = useState([]);
12 | const [compoundInterestConfig, setCompoundInterestConfig] = useState({
13 | initialValue : 0,
14 | interestRate : 0,
15 | numMonths : 0,
16 | });
17 |
18 | useEffect(() => {
19 | setCompoundInterest(calcCompoundInterest(compoundInterestConfig));
20 | }, [compoundInterestConfig]);
21 |
22 | return (
23 |
24 |
React - Juros Compostos
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 |
34 | export default App;
35 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | const { getByText } = render();
7 | const linkElement = getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/components/form/index.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import './styles.css';
3 |
4 | export default function Form({setCompoundInterest}) {
5 |
6 | const [initialValue, setInitialValue] = useState(5900);
7 | const [interestRate, setInterestRate] = useState(0.8);
8 | const [numMonths, setNumMonths] = useState(12);
9 |
10 | useEffect(() => {
11 | setCompoundInterest({
12 | initialValue, interestRate, numMonths
13 | });
14 | }, [initialValue, interestRate, numMonths, setCompoundInterest]);
15 |
16 | return (
17 |
53 | );
54 | }
55 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/components/form/styles.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/desafio-03/src/components/form/styles.css
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/components/table/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './styles.css';
3 |
4 | import { formatMoney, formatPercentage } from '../../util/number-format';
5 |
6 | export default function Table({ compoundInterest, className }) {
7 | return (
8 |
9 |
10 |
11 | Período |
12 | Montante |
13 | Lucro (R$) |
14 | Lucro (%) |
15 |
16 |
17 |
18 |
19 | {
20 | compoundInterest.map(({month, total, profit, profitPercentage}) => (
21 |
22 | {month} |
23 | {formatMoney(total)} |
24 | {formatMoney(profit)} |
25 | {formatPercentage(profitPercentage)} |
26 |
27 | ))
28 | }
29 |
30 |
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/components/table/styles.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/desafio-03/src/components/table/styles.css
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/index.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/desafio-03/src/index.css
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import 'bootstrap/dist/css/bootstrap.css';
4 | import './index.css';
5 | import App from './App';
6 | import * as serviceWorker from './serviceWorker';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
15 | // If you want your app to work offline and load faster, you can change
16 | // unregister() to register() below. Note this comes with some pitfalls.
17 | // Learn more about service workers: https://bit.ly/CRA-PWA
18 | serviceWorker.unregister();
19 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' },
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/util/compound-interest.js:
--------------------------------------------------------------------------------
1 | function calcCompoundInterestByPeriod({ initialValue, interestRate, numMonths }) {
2 | return Array
3 | .from({ length: numMonths })
4 | .map((item, index) => {
5 | const month = index + 1;
6 | const total = _calcCompoundInterest(initialValue, interestRate, index + 1);
7 | const profit = total - initialValue
8 | const profitPercentage = _calcPercentage(initialValue, profit);
9 |
10 | return {
11 | month, total, profit, profitPercentage
12 | };
13 | });
14 | }
15 |
16 | function _calcCompoundInterest(amount, interestRate, time) {
17 | return amount * Math.pow((1 + interestRate / 100), time);
18 | }
19 |
20 | function _calcPercentage(total, part) {
21 | return total ? (part * 100 / total) / 100 : 0;
22 | }
23 |
24 | export default calcCompoundInterestByPeriod;
25 |
--------------------------------------------------------------------------------
/modulo-03/desafio-03/src/util/number-format.js:
--------------------------------------------------------------------------------
1 | function formatMoney(value) {
2 | return Intl
3 | .NumberFormat('pt-BR', {
4 | style : 'currency',
5 | currency : 'BRL'
6 | })
7 | .format(value);
8 | }
9 |
10 | function formatPercentage(value) {
11 | return Intl
12 | .NumberFormat('pt-BR', {
13 | style : 'percent',
14 | minimumFractionDigits : 2,
15 | maximumFractionDigits : 2
16 | })
17 | .format(value);
18 | }
19 |
20 | export {
21 | formatMoney,
22 | formatPercentage
23 | };
24 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `yarn start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `yarn test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `yarn build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `yarn eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `yarn build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "trabalho-pratico-03",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.3.2",
8 | "@testing-library/user-event": "^7.1.2",
9 | "bootstrap": "^4.5.0",
10 | "react": "^16.13.1",
11 | "react-dom": "^16.13.1",
12 | "react-scripts": "3.4.1"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": "react-app"
22 | },
23 | "browserslist": {
24 | "production": [
25 | ">0.2%",
26 | "not dead",
27 | "not op_mini all"
28 | ],
29 | "development": [
30 | "last 1 chrome version",
31 | "last 1 firefox version",
32 | "last 1 safari version"
33 | ]
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/trabalho-pratico-03/public/favicon.ico
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/trabalho-pratico-03/public/logo192.png
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/trabalho-pratico-03/public/logo512.png
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/App.css:
--------------------------------------------------------------------------------
1 | .discount-inss input {
2 | color: #ffc107;
3 | }
4 |
5 | .discount-irpf input {
6 | color: #dc3545;
7 | }
8 |
9 | .net-salary input {
10 | color: #28a745;
11 | }
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import './App.css';
3 |
4 | import {
5 | calculateSalaryFrom,
6 | calcPercentage,
7 | formatMoney
8 | } from './util/salary';
9 |
10 | import InputReadOnly from './components/input-read-only';
11 | import ProgressBar from './components/progress-bar';
12 |
13 | function App() {
14 | const [grossSalary, setGrossSalary] = useState('');
15 | const [baseINSS, setBaseINSS] = useState(0);
16 | const [baseIRPF, setBaseIRPF] = useState(0);
17 | const [discountINSS, setDiscountINSS] = useState(0);
18 | const [discountIRPF, setDiscountIRPF] = useState(0);
19 | const [netSalary, setNetSalary] = useState(0);
20 |
21 | const [percentageDiscountINSS, setPercentageDiscountINSS] = useState(0);
22 | const [percentageDiscountIRPF, setPercentageDiscountIRPF] = useState(0);
23 | const [percentageNetSalary, setPercentageNetSalary] = useState(0);
24 |
25 | useEffect(() => {
26 | const result = calculateSalaryFrom(grossSalary);
27 |
28 | const percentageDiscountINSS = calcPercentage(grossSalary, result.discountINSS);
29 | const percentageDiscountIRPF = calcPercentage(grossSalary, result.discountIRPF);
30 | const percentageNetSalary = calcPercentage(grossSalary, result.netSalary);
31 |
32 | setPercentageDiscountINSS(percentageDiscountINSS);
33 | setPercentageDiscountIRPF(percentageDiscountIRPF);
34 | setPercentageNetSalary(percentageNetSalary);
35 |
36 | setBaseINSS(formatMoney(result.baseINSS));
37 | setBaseIRPF(formatMoney(result.baseIRPF));
38 | setDiscountINSS(`${formatMoney(result.discountINSS)} (${percentageDiscountINSS}%)`);
39 | setDiscountIRPF(`${formatMoney(result.discountIRPF)} (${percentageDiscountIRPF}%)`);
40 | setNetSalary(`${formatMoney(result.netSalary)} (${percentageNetSalary}%)`);
41 |
42 | }, [grossSalary]);
43 |
44 | return (
45 |
46 |
React Salário
47 |
48 |
49 |
50 |
51 |
52 | setGrossSalary(evt.target.value)}
58 | autoFocus
59 | />
60 |
61 |
62 |
63 |
64 |
69 |
70 |
75 |
76 |
81 |
82 |
87 |
88 |
89 |
90 |
95 |
96 |
97 |
102 |
103 |
104 | );
105 | }
106 |
107 | export default App;
108 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | const { getByText } = render();
7 | const linkElement = getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/components/input-read-only/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './styles.css';
3 |
4 | export default function InputReadOnly({label, value, className}) {
5 | return (
6 |
7 |
8 |
15 |
16 | );
17 | }
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/components/input-read-only/styles.css:
--------------------------------------------------------------------------------
1 | input[readonly] {
2 | font-weight: bold;
3 | }
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/components/progress-bar/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './styles.css';
3 |
4 | export default function ProgressBar({percentageDiscountINSS, percentageDiscountIRPF, percentageNetSalary}) {
5 | return (
6 |
29 | );
30 | }
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/components/progress-bar/styles.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/trabalho-pratico-03/src/components/progress-bar/styles.css
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/index.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lucasrm20/igti-bootcamp-fullstack/bbeaa81b8259e94d4011182dc0bc2406004fc3c8/modulo-03/trabalho-pratico-03/src/index.css
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import 'bootstrap/dist/css/bootstrap.css';
4 | import './index.css';
5 | import App from './App';
6 | import * as serviceWorker from './serviceWorker';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
15 | // If you want your app to work offline and load faster, you can change
16 | // unregister() to register() below. Note this comes with some pitfalls.
17 | // Learn more about service workers: https://bit.ly/CRA-PWA
18 | serviceWorker.unregister();
19 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' },
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/modulo-03/trabalho-pratico-03/src/util/salary.js:
--------------------------------------------------------------------------------
1 | // Fonte: https://www.todacarreira.com/calculo-salario-liquido/
2 |
3 | const INSS_TABLE = [
4 | {
5 | id: 1,
6 | minValue: 0,
7 | maxValue: 1045,
8 | difference: 1045 - 0,
9 | discountPercentage: 0.075,
10 | discountValue: -1,
11 | },
12 | {
13 | id: 2,
14 | minValue: 1045.01,
15 | maxValue: 2089.6,
16 | difference: 2089.6 - 1045,
17 | discountPercentage: 0.09,
18 | },
19 | {
20 | id: 3,
21 | minValue: 2089.61,
22 | maxValue: 3134.4,
23 | difference: 3134.4 - 2089.6,
24 | discountPercentage: 0.12,
25 | },
26 | {
27 | id: 4,
28 | minValue: 3134.41,
29 | maxValue: 6101.06,
30 | difference: 6101.06 - 3134.4,
31 | discountPercentage: 0.14,
32 | },
33 | ];
34 |
35 | function round(value) {
36 | return +value.toFixed(2);
37 | }
38 |
39 | function calculateDiscountINSS(baseINSS) {
40 | let discountINSS = 0;
41 |
42 | if (baseINSS > 6101.07) {
43 | return 713.1;
44 | }
45 |
46 | for (var i = 0; i < INSS_TABLE.length; i++) {
47 | var currentItem = INSS_TABLE[i];
48 | let discountValue = 0;
49 |
50 | if (baseINSS > currentItem.maxValue) {
51 | // prettier-ignore
52 | discountValue =
53 | round(currentItem.difference * currentItem.discountPercentage);
54 |
55 | discountINSS += discountValue;
56 | } else {
57 | // prettier-ignore
58 | discountValue =
59 | round((baseINSS - currentItem.minValue) * currentItem.discountPercentage);
60 |
61 | discountINSS += discountValue;
62 | break;
63 | }
64 | }
65 |
66 | discountINSS = round(discountINSS);
67 |
68 | return discountINSS;
69 | }
70 |
71 | function calculateDiscountIRPF(baseIRPF) {
72 | let discountIRPF =
73 | baseIRPF < 1903.98
74 | ? 0
75 | : baseIRPF < 2826.65
76 | ? round(baseIRPF * 0.075) - 142.8
77 | : baseIRPF < 3751.05
78 | ? round(baseIRPF * 0.15) - 354.8
79 | : baseIRPF < 4664.68
80 | ? round(baseIRPF * 0.225) - 636.13
81 | : round(baseIRPF * 0.275) - 869.36;
82 |
83 | discountIRPF = round(discountIRPF);
84 |
85 | return discountIRPF;
86 | }
87 |
88 | function calculateSalaryFrom(fullSalary) {
89 | const baseINSS = fullSalary;
90 | const discountINSS = calculateDiscountINSS(baseINSS);
91 |
92 | const baseIRPF = baseINSS - discountINSS;
93 | const discountIRPF = calculateDiscountIRPF(baseIRPF);
94 |
95 | const netSalary = baseINSS - discountINSS - discountIRPF;
96 |
97 | return {
98 | baseINSS,
99 | discountINSS,
100 | baseIRPF,
101 | discountIRPF,
102 | netSalary,
103 | };
104 | }
105 |
106 | function calcPercentage(total, part) {
107 | return total ? (part * 100 / total).toFixed(2) : 0;
108 | }
109 |
110 | function formatMoney(value) {
111 | return Intl
112 | .NumberFormat('pt-BR', {
113 | style : 'currency',
114 | currency : 'BRL'
115 | })
116 | .format(value);
117 | }
118 |
119 | export {
120 | calculateSalaryFrom,
121 | calcPercentage,
122 | formatMoney
123 | };
124 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | node_modules/
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/README.md:
--------------------------------------------------------------------------------
1 | # Trabalho Prático 04
2 | ### Como Rodar o Projeto
3 | * Execute `npm install` para instalar as dependências;
4 | * Na raiz do projeto crie o arquivo `.env` com a seguinte estrutura:
5 | ```
6 | # Preencha com a sua string de conexão do MongoDB Atlas
7 | ATLAS_CONNECTION_STRING=
8 | ```
9 | * Rode `npm start` para iniciar o servidor;
10 | * Rode `npm run dev` para iniciar o servidor no modo de desenvolvimento (Nodemon);
11 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/index.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | require('./src/config/db').connect();
3 |
4 | const app = require('./src/app');
5 |
6 | const listener = app.listen(process.env.PORT || 3000, () => {
7 | console.log(`Server listening on port ${listener.address().port}`);
8 | });
9 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "desafio-04",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node index.js",
8 | "dev": "nodemon index.js",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "@hapi/joi": "^15.1.1",
16 | "dotenv": "^8.2.0",
17 | "express": "^4.17.1",
18 | "mongoose": "^5.9.20",
19 | "morgan": "^1.10.0"
20 | },
21 | "devDependencies": {
22 | "nodemon": "^2.0.4"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/accounts/deposit.js:
--------------------------------------------------------------------------------
1 | const Account = require('../../models/account');
2 | const NotFoundError = require('../../util/not-found.error');
3 |
4 | const deposit = async (req, res, next) => {
5 | try {
6 |
7 | const { agency: agencia, account: conta } = req.params;
8 |
9 | const account = await Account.findOne({ agencia, conta });
10 |
11 | if (!account) throw new NotFoundError(`Agency: ${agencia} Account: ${conta} - Not Found`);
12 |
13 | account.balance += req.body.value;
14 |
15 | await account.save();
16 |
17 | res.json({
18 | agencia : account.agencia,
19 | conta : account.conta,
20 | balance : account.balance
21 | });
22 |
23 | } catch (err) {
24 | next(err);
25 | }
26 | };
27 |
28 | module.exports = deposit;
29 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/accounts/get-statement.js:
--------------------------------------------------------------------------------
1 | const Account = require('../../models/account');
2 | const NotFoundError = require('../../util/not-found.error');
3 |
4 | const getStatement = async (req, res, next) => {
5 | try {
6 |
7 | const { agency: agencia, account: conta } = req.params;
8 |
9 | const account = await Account
10 | .findOne({
11 | agencia,
12 | conta
13 | }, {
14 | _id : 0,
15 | agencia : 1,
16 | conta : 1,
17 | balance : 1
18 | });
19 |
20 | if (!account) throw new NotFoundError(`Agency: ${agencia} Account: ${conta} - Not Found`);
21 |
22 | res.json(account);
23 |
24 | } catch (err) {
25 | next(err);
26 | }
27 | };
28 |
29 | module.exports = getStatement;
30 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/accounts/index.js:
--------------------------------------------------------------------------------
1 | const { Router } = require('express');
2 | const router = Router();
3 |
4 | // Controllers
5 | const getStatement = require('./get-statement');
6 | const deposit = require('./deposit');
7 | const withdraw = require('./withdraw');
8 | const removeAccount = require('./remove-account');
9 | const resetDatabase = require('./reset-database');
10 |
11 | // Validators
12 | const agencyAndAccountValidator = require('./validators/agency-and-account.validator');
13 | const depositOrWithdrawValidator = require('./validators/deposit-or-withdraw.validator');
14 |
15 | router.get('/:agency/:account', [
16 | agencyAndAccountValidator,
17 | getStatement
18 | ]);
19 |
20 | router.delete('/:agency/:account', [
21 | agencyAndAccountValidator,
22 | removeAccount
23 | ]);
24 |
25 | router.post('/:agency/:account/deposit', [
26 | agencyAndAccountValidator,
27 | depositOrWithdrawValidator,
28 | deposit
29 | ]);
30 |
31 | router.post('/:agency/:account/withdraw', [
32 | agencyAndAccountValidator,
33 | depositOrWithdrawValidator,
34 | withdraw
35 | ]);
36 |
37 | router.post('/reset-database', [
38 | resetDatabase
39 | ]);
40 |
41 | module.exports = router;
42 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/accounts/remove-account.js:
--------------------------------------------------------------------------------
1 | const Account = require('../../models/account');
2 | const NotFoundError = require('../../util/not-found.error');
3 |
4 | const removeAccount = async (req, res, next) => {
5 | try {
6 |
7 | const { agency: agencia, account: conta } = req.params;
8 |
9 | const accountExists = await Account.exists({ agencia, conta });
10 |
11 | if (!accountExists) throw new NotFoundError(`Agency: ${agencia} Account: ${conta} - Not Found`);
12 |
13 | await Account.findOneAndRemove({ agencia, conta });
14 |
15 | const activeAccounts = await Account.countDocuments({ agencia });
16 |
17 | res.json({ activeAccounts });
18 |
19 | } catch (err) {
20 | next(err);
21 | }
22 | };
23 |
24 | module.exports = removeAccount;
25 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/accounts/reset-database.js:
--------------------------------------------------------------------------------
1 | const Account = require('../../models/account');
2 |
3 | const DATA = require('../../util/accounts.json');
4 |
5 | const resetDatabase = async (req, res, next) => {
6 | try {
7 |
8 | await Account.collection.remove();
9 | await Account.create(DATA);
10 |
11 | res.json({
12 | reset : 'ok',
13 | accounts : await Account.find({})
14 | });
15 |
16 | } catch (err) {
17 | next(err);
18 | }
19 | };
20 |
21 | module.exports = resetDatabase;
22 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/accounts/validators/agency-and-account.validator.js:
--------------------------------------------------------------------------------
1 | const Joi = require('@hapi/joi');
2 |
3 | module.exports = function(req, res, next) {
4 |
5 | Joi
6 | .object({
7 | agency : Joi.number().integer().positive().required(),
8 | account : Joi.number().integer().positive().required()
9 | })
10 | .validate(req.params, err => {
11 | if (err) return res.status(422).json(err.details);
12 |
13 | return next();
14 | });
15 | };
16 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/accounts/validators/deposit-or-withdraw.validator.js:
--------------------------------------------------------------------------------
1 | const Joi = require('@hapi/joi');
2 |
3 | module.exports = function(req, res, next) {
4 |
5 | Joi
6 | .object({
7 | value: Joi.number().integer().positive().required(),
8 | })
9 | .validate(req.body, err => {
10 | if (err) return res.status(422).json(err.details);
11 |
12 | return next();
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/accounts/withdraw.js:
--------------------------------------------------------------------------------
1 | const Account = require('../../models/account');
2 |
3 | const NotFoundError = require('../../util/not-found.error');
4 | const InsufficientBalanceError = require('../../util/insufficient-balance.error');
5 |
6 | const BANK_FEE = 1;
7 |
8 | const withdraw = async (req, res, next) => {
9 | try {
10 |
11 | const { agency: agencia, account: conta } = req.params;
12 | const withdrawValue = req.body.value + BANK_FEE;
13 |
14 | const account = await Account.findOne({ agencia, conta });
15 |
16 | if (!account) throw new NotFoundError(`Agency: ${agencia} Account: ${conta} - Not Found`);
17 |
18 | if (hasInsufficientBalance(account, withdrawValue)) throw new InsufficientBalanceError();
19 |
20 | account.balance -= withdrawValue;
21 |
22 | await account.save();
23 |
24 | res.json({
25 | agencia : account.agencia,
26 | conta : account.conta,
27 | balance : account.balance
28 | });
29 |
30 | } catch (err) {
31 | next(err);
32 | }
33 | };
34 |
35 | const hasInsufficientBalance = (account, withdrawValue) => {
36 | return account.balance < withdrawValue;
37 | }
38 |
39 | module.exports = withdraw;
40 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/reports/get-balance-average.js:
--------------------------------------------------------------------------------
1 | const Account = require('../../models/account');
2 | const NotFoundError = require('../../util/not-found.error');
3 |
4 | const getBalanceAverage = async (req, res, next) => {
5 | try {
6 |
7 | const [averageBalance] = await Account.aggregate([
8 | {
9 | '$match': {
10 | 'agencia': Number(req.params.agency)
11 | }
12 | }, {
13 | '$group': {
14 | '_id': '$agencia',
15 | 'averageBalance': {
16 | '$avg': '$balance'
17 | }
18 | }
19 | }, {
20 | '$project': {
21 | '_id': 0,
22 | 'averageBalance': 1
23 | }
24 | }
25 | ]);
26 |
27 | if (!averageBalance) throw new NotFoundError(`No data found for agency ${req.params.agency} - Not Found`);
28 |
29 | res.json(averageBalance);
30 |
31 | } catch (err) {
32 | next(err);
33 | }
34 | };
35 |
36 | module.exports = getBalanceAverage;
37 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/reports/get-balance-ranking.js:
--------------------------------------------------------------------------------
1 | const Account = require('../../models/account');
2 |
3 | const SORT_ORDER = {
4 | asc : 1,
5 | desc : -1
6 | };
7 |
8 | const getLowestBalances = async (req, res, next) => {
9 | try {
10 |
11 | const limit = Number(req.query.limit) || 50;
12 | const sort = req.query.sort || 'asc';
13 |
14 | const accounts = await Account
15 | .find({}, {
16 | _id : 0,
17 | agencia : 1,
18 | conta : 1,
19 | balance : 1
20 | })
21 | .sort({ balance: SORT_ORDER[sort] })
22 | .limit(limit);
23 |
24 | res.json(accounts);
25 |
26 | } catch (err) {
27 | next(err);
28 | }
29 | };
30 |
31 | module.exports = getLowestBalances;
32 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/reports/index.js:
--------------------------------------------------------------------------------
1 | const { Router } = require('express');
2 | const router = Router();
3 |
4 | // Controllers
5 | const getBalanceAverage = require('./get-balance-average');
6 | const getBalanceRanking = require('./get-balance-ranking');
7 |
8 | // Validators
9 | const agencyValidator = require('./validators/agency.validator');
10 | const balanceRankingValidator = require('./validators/balance-ranking.validator');
11 |
12 | router.get('/balance-average/:agency', [
13 | agencyValidator,
14 | getBalanceAverage
15 | ]);
16 |
17 | router.get('/balance-ranking', [
18 | balanceRankingValidator,
19 | getBalanceRanking
20 | ]);
21 |
22 | module.exports = router;
23 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/reports/validators/agency.validator.js:
--------------------------------------------------------------------------------
1 | const Joi = require('@hapi/joi');
2 |
3 | module.exports = function(req, res, next) {
4 |
5 | Joi
6 | .object({
7 | agency: Joi.number().integer().positive().required()
8 | })
9 | .validate(req.params, err => {
10 | if (err) return res.status(422).json(err.details);
11 |
12 | return next();
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/reports/validators/balance-ranking.validator.js:
--------------------------------------------------------------------------------
1 | const Joi = require('@hapi/joi');
2 |
3 | module.exports = function(req, res, next) {
4 |
5 | Joi
6 | .object({
7 | limit : Joi.number().integer().positive(),
8 | sort : Joi.string().valid([
9 | 'asc',
10 | 'desc'
11 | ])
12 | })
13 | .validate(req.query, err => {
14 | if (err) return res.status(422).json(err.details);
15 |
16 | return next();
17 | });
18 | };
19 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/transfers/index.js:
--------------------------------------------------------------------------------
1 | const { Router } = require('express');
2 | const router = Router();
3 |
4 | // Controllers
5 | const transferBalance = require('./transfer-balance');
6 | const transferLargestAccounts = require('./transfer-largest-accounts');
7 |
8 | // Validators
9 | const transferValidator = require('./validators/transfer.validator');
10 |
11 | router.post('/transfer-balance', [
12 | transferValidator,
13 | transferBalance
14 | ]);
15 |
16 | router.post('/transfer-largest-accounts-agency', [
17 | transferLargestAccounts
18 | ]);
19 |
20 | module.exports = router;
21 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/transfers/transfer-balance.js:
--------------------------------------------------------------------------------
1 | const Account = require('../../models/account');
2 |
3 | const NotFoundError = require('../../util/not-found.error');
4 | const InsufficientBalanceError = require('../../util/insufficient-balance.error');
5 |
6 | const BANK_FEE = 8;
7 |
8 | const transfer = async (req, res, next) => {
9 | try {
10 |
11 | const accountFrom = await find(req.body.accountFrom);
12 | const accountTo = await find(req.body.accountTo);
13 |
14 | const transactionFee = calcTransactionFee(accountFrom, accountTo);
15 | const tranferValueWithFee = req.body.value + transactionFee;
16 |
17 | if (hasInsufficientBalance(accountFrom, tranferValueWithFee)) throw new InsufficientBalanceError();
18 |
19 | accountFrom.balance -= tranferValueWithFee;
20 | accountTo.balance += req.body.value;
21 |
22 | await accountFrom.save();
23 | await accountTo.save();
24 |
25 | res.json({
26 | agencia : accountFrom.agencia,
27 | conta : accountFrom.conta,
28 | balance : accountFrom.balance
29 | });
30 |
31 | } catch (err) {
32 | next(err);
33 | }
34 | };
35 |
36 | const find = async (accountNumber) => {
37 | const account = await Account.findOne({ conta: accountNumber });
38 |
39 | if (!account) throw new NotFoundError(`Account: ${accountNumber} - Not Found`);
40 |
41 | return account;
42 | }
43 |
44 | const calcTransactionFee = (accountFrom, accountTo) => {
45 | return accountFrom.agencia === accountTo.agencia ? 0 : BANK_FEE;
46 | }
47 |
48 | const hasInsufficientBalance = (accountFrom, valueToTransfer) => {
49 | return accountFrom.balance < valueToTransfer;
50 | }
51 |
52 | module.exports = transfer;
53 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/transfers/transfer-largest-accounts.js:
--------------------------------------------------------------------------------
1 | const Account = require('../../models/account');
2 |
3 | const PRIVATE_AGENCY = 99;
4 |
5 | const transfer = async (req, res, next) => {
6 | try {
7 |
8 | const accountsToTransfer = await getLargestBalanceAccounts();
9 |
10 | const promises = accountsToTransfer.map(account => {
11 | return Account.findOneAndUpdate({
12 | _id: account._id
13 | }, {
14 | $set: {
15 | agencia: PRIVATE_AGENCY
16 | }
17 | });
18 | });
19 |
20 | await Promise.all(promises);
21 |
22 | const privateAgencyClients = await Account.find({ agencia: PRIVATE_AGENCY });
23 |
24 | res.json(privateAgencyClients);
25 |
26 | } catch (err) {
27 | next(err);
28 | }
29 | };
30 |
31 | const getLargestBalanceAccounts = () => {
32 | return Account.aggregate([
33 | {
34 | '$match': {
35 | 'agencia': {
36 | '$ne': 99
37 | }
38 | }
39 | }, {
40 | '$sort': {
41 | 'balance': -1
42 | }
43 | }, {
44 | '$group': {
45 | '_id': '$agencia',
46 | 'accounts': {
47 | '$push': '$$ROOT'
48 | }
49 | }
50 | }, {
51 | '$project': {
52 | '_id': 0,
53 | 'agency': '$_id',
54 | 'largestBalanceAccount': {
55 | '$arrayElemAt': [
56 | '$accounts', 0
57 | ]
58 | }
59 | }
60 | }, {
61 | '$project': {
62 | '_id': '$largestBalanceAccount._id'
63 | }
64 | }
65 | ]);
66 | }
67 |
68 | module.exports = transfer;
69 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/api/transfers/validators/transfer.validator.js:
--------------------------------------------------------------------------------
1 | const Joi = require('@hapi/joi');
2 |
3 | module.exports = function(req, res, next) {
4 |
5 | Joi
6 | .object({
7 | accountFrom : Joi.number().integer().positive().required(),
8 | accountTo : Joi.number().integer().positive().required(),
9 | value : Joi.number().integer().positive().required(),
10 | })
11 | .validate(req.body, err => {
12 | if (err) return res.status(422).json(err.details);
13 |
14 | return next();
15 | });
16 | };
17 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/app.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const morgan = require('morgan');
3 |
4 | const errorHandlers = require('./util/error-handlers');
5 |
6 | const app = express();
7 |
8 | app.use(express.json());
9 | app.use(morgan('dev'));
10 |
11 | // routes
12 | app.use('/accounts', require('./api/accounts'));
13 | app.use('/transfers', require('./api/transfers'));
14 | app.use('/reports', require('./api/reports'));
15 |
16 | app.use(errorHandlers.handler404);
17 | app.use(errorHandlers.handler500);
18 |
19 | module.exports = app;
20 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/config/db.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | const connect = () => {
4 |
5 | mongoose.connect(process.env.ATLAS_CONNECTION_STRING, {
6 | useNewUrlParser : true,
7 | useUnifiedTopology : true
8 | });
9 |
10 | mongoose.connection.on('connected', () => {
11 | console.log(`Connected to MongoDB Atlas: ${process.env.ATLAS_CONNECTION_STRING}`);
12 | });
13 |
14 | mongoose.connection.on('disconnected', () => {
15 | console.log(`Database disconnected from: ${process.env.ATLAS_CONNECTION_STRING}`);
16 | });
17 |
18 | mongoose.connection.on('error', err => {
19 | console.log(`Database error on connection: ${err}`);
20 | });
21 |
22 | process.on('SIGINT', () => {
23 |
24 | mongoose.connection.close(() => {
25 | console.log('Database disconnected due the end of application');
26 | process.exit(0);
27 | });
28 |
29 | });
30 |
31 | };
32 |
33 | module.exports = {
34 | connect
35 | };
36 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/models/account.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | const AccountSchema = mongoose.Schema({
4 | agencia: {
5 | type : Number,
6 | required : true
7 | },
8 | conta: {
9 | type : Number,
10 | required : true
11 | },
12 | name: {
13 | type : String,
14 | required : true
15 | },
16 | balance: {
17 | type : Number,
18 | required : true,
19 | min : 0
20 | }
21 | }, { versionKey: false });
22 |
23 | module.exports = mongoose.model('Account', AccountSchema);
24 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/util/accounts.json:
--------------------------------------------------------------------------------
1 | [
2 | {"agencia":10,"conta": 1001 ,"name":"Maria Roberta Fernandes","balance":587},
3 | {"agencia":10,"conta": 1002 ,"name":"Gustavo Falcao Oliveira","balance":396},
4 | {"agencia":10,"conta": 1003 ,"name":"Fernando Carlos Silva","balance":500},
5 | {"agencia":10,"conta": 1004 ,"name":"Aline Batista Bernardes","balance":321},
6 | {"agencia":10,"conta": 1005 ,"name":"Ivo Jose da Costa","balance":987},
7 | {"agencia":10,"conta": 1006 ,"name":"Carlos Eduardo Lino","balance":3},
8 | {"agencia":10,"conta": 1007 ,"name":"Henrique Santos Ferreira","balance":505},
9 | {"agencia":10,"conta": 1008 ,"name":"Priscila Alves da Cunha","balance":1},
10 | {"agencia":10,"conta": 1009 ,"name":"Luis Eduardo Nunes","balance":658},
11 | {"agencia":10,"conta": 1010 ,"name":"Silvana Souto Costa","balance":1023},
12 | {"agencia":10,"conta": 1011 ,"name":"Julia Maria Alves","balance":985},
13 | {"agencia":10,"conta": 1012 ,"name":"Bernardo Almeida Alves","balance":842},
14 | {"agencia":10,"conta": 1013 ,"name":"Lucas Andrade Barbosa","balance":753},
15 | {"agencia":10,"conta": 1014 ,"name":"Fernanda Barbosa Ferreira","balance":951},
16 | {"agencia":10,"conta": 1015 ,"name":"Caroline Aparecida da Cunha","balance":126},
17 | {"agencia":10,"conta": 1016 ,"name":"Ivo Barros","balance":324},
18 | {"agencia":10,"conta": 1017 ,"name":"Augusto Batista","balance":326},
19 | {"agencia":10,"conta": 1018 ,"name":"Vania Borges Moreira","balance":634},
20 | {"agencia":10,"conta": 1019 ,"name":"Valdete Macedo Souto","balance":426},
21 | {"agencia":10,"conta": 1020 ,"name":"Jose Luis Borges","balance":153},
22 | {"agencia":10,"conta": 1021 ,"name":"Marcelo Campos","balance":854},
23 | {"agencia":10,"conta": 1022 ,"name":"Pedro Augusto Cardoso","balance":651},
24 | {"agencia":10,"conta": 1023 ,"name":"Brena Martinho Carvalho ","balance":358},
25 | {"agencia":10,"conta": 1024 ,"name":"Pedro Castro","balance":1985},
26 | {"agencia":10,"conta": 1025 ,"name":"Camila Santini Costa","balance":1874},
27 | {"agencia":10,"conta": 1026 ,"name":"Alessandra Albergaria Dias","balance":1254},
28 | {"agencia":10,"conta": 1027 ,"name":"Giovanna Silva Dias","balance":9852},
29 | {"agencia":10,"conta": 1028 ,"name":"Maria Fernanda Gomes","balance":45},
30 | {"agencia":10,"conta": 1029 ,"name":"Maria Luiza Nunes","balance":658},
31 | {"agencia":10,"conta": 1030 ,"name":"Luiza Duarte","balance":452},
32 | {"agencia":25,"conta": 3001 ,"name":"Roberta Nunes","balance":458},
33 | {"agencia":25,"conta": 3002 ,"name":"Roberta Miranda","balance":985},
34 | {"agencia":25,"conta": 3003 ,"name":"Guilherme Zanin Freitas","balance":3265},
35 | {"agencia":25,"conta": 3004 ,"name":"Guilherme Ferreira Silva","balance":2154},
36 | {"agencia":25,"conta": 3005 ,"name":"Mario Augusto Fernandes","balance":456},
37 | {"agencia":25,"conta": 3006 ,"name":"Luis Eduardo Ferreira","balance":981},
38 | {"agencia":25,"conta": 3007 ,"name":"Claudia Ferreira Garcia","balance":854},
39 | {"agencia":25,"conta": 3008 ,"name":"Wagner Silva e Silva","balance":568},
40 | {"agencia":25,"conta": 3009 ,"name":"Daniel Henrique Gomes","balance":548},
41 | {"agencia":25,"conta": 3010 ,"name":"Lucas Cavalcanti Gonçalves","balance":474},
42 | {"agencia":25,"conta": 3011 ,"name":"Thiago Oliveira Lima","balance":658},
43 | {"agencia":25,"conta": 3012 ,"name":"Rogeiro Olveira Lopes","balance":125},
44 | {"agencia":25,"conta": 3013 ,"name":"Carlos Moniz Machado","balance":365},
45 | {"agencia":25,"conta": 3014 ,"name":"Rafael Henrique Marques","balance":489},
46 | {"agencia":25,"conta": 3015 ,"name":"Maira Imai Marques","balance":965},
47 | {"agencia":25,"conta": 3016 ,"name":"Lucas Portugal Vieira","balance":236},
48 | {"agencia":25,"conta": 3017 ,"name":"Gustavo Teixeira","balance":452},
49 | {"agencia":25,"conta": 3018 ,"name":"Cristina Souza","balance":986},
50 | {"agencia":25,"conta": 3019 ,"name":"Ana Marta Soares","balance":698},
51 | {"agencia":25,"conta": 3020 ,"name":"Ana Maria Santos","balance":965},
52 | {"agencia":25,"conta": 3021 ,"name":"Alberto Santana","balance":452},
53 | {"agencia":25,"conta": 3022 ,"name":"Felipe Ribeiro","balance":365},
54 | {"agencia":25,"conta": 3023 ,"name":"Henrique Bernardo Rocha","balance":265},
55 | {"agencia":25,"conta": 3024 ,"name":"Breno Reis","balance":241},
56 | {"agencia":25,"conta": 3025 ,"name":"Eduardo Olvieira","balance":852},
57 | {"agencia":25,"conta": 3026 ,"name":"Luis Eduardo Ramos","balance":562},
58 | {"agencia":25,"conta": 3027 ,"name":"Marcia Pereira","balance":65},
59 | {"agencia":25,"conta": 3028 ,"name":"Gabriel Gomes Nascimento","balance":325},
60 | {"agencia":25,"conta": 3029 ,"name":"Victor Moura","balance":965},
61 | {"agencia":25,"conta": 3030 ,"name":"Ana Maria Silva","balance":5},
62 | {"agencia":47,"conta": 2201 ,"name":"Jorge Ivan Jimenez","balance":36},
63 | {"agencia":47,"conta": 2202 ,"name":"Pedro Luis Fragoso","balance":45},
64 | {"agencia":47,"conta": 2203 ,"name":"Gesiane Leticia Alves","balance":98},
65 | {"agencia":47,"conta": 2204 ,"name":"Glaucio de Souza","balance":1},
66 | {"agencia":47,"conta": 2205 ,"name":"Richard Greeson","balance":189},
67 | {"agencia":47,"conta": 2206 ,"name":"Roberto Lopes Ramos","balance":120},
68 | {"agencia":47,"conta": 2207 ,"name":"Frederico Saito Rocha Costa","balance":110},
69 | {"agencia":47,"conta": 2208 ,"name":"Garin da Silva","balance":658},
70 | {"agencia":47,"conta": 2209 ,"name":"Franciele dos Santos Saraiva","balance":521},
71 | {"agencia":47,"conta": 2210 ,"name":"Carlos Henrique Soares","balance":136},
72 | {"agencia":47,"conta": 2211 ,"name":"Wellington Oliveira Filho","balance":215},
73 | {"agencia":47,"conta": 2212 ,"name":"Gabriela da Rosa Bulla","balance":425},
74 | {"agencia":47,"conta": 2213 ,"name":"Paola Silva Boff","balance":452},
75 | {"agencia":47,"conta": 2214 ,"name":"Bruna Caroline Silva de Castro","balance":658},
76 | {"agencia":47,"conta": 2215 ,"name":"Michele Cigolini Pulsy","balance":452},
77 | {"agencia":47,"conta": 2216 ,"name":"Eduardo Renan do Nascimento","balance":235},
78 | {"agencia":47,"conta": 2217 ,"name":"Julie Martin","balance":456},
79 | {"agencia":47,"conta": 2218 ,"name":"Ricardo Antonio Garcia","balance":987},
80 | {"agencia":47,"conta": 2219 ,"name":"Belisa Maria de Aguiar","balance":265},
81 | {"agencia":47,"conta": 2220 ,"name":"Ariana Pereira","balance":125},
82 | {"agencia":47,"conta": 2221 ,"name":"Guilherme Geraldo Aguiar","balance":3265},
83 | {"agencia":47,"conta": 2222 ,"name":"Eduardo Renan do Nascimento","balance":111},
84 | {"agencia":47,"conta": 2223 ,"name":"Gabriela Camila Silva de Lima","balance":214},
85 | {"agencia":47,"conta": 2224 ,"name":"Ana Carolina de Melo Santos","balance":421},
86 | {"agencia":47,"conta": 2225 ,"name":"Ana Katia dos Santos Dourado","balance":652},
87 | {"agencia":47,"conta": 2226 ,"name":"Mauricio Jose da Silva","balance":326},
88 | {"agencia":47,"conta": 2227 ,"name":"Ana Paula Sena Silva","balance":325},
89 | {"agencia":47,"conta": 2228 ,"name":"Maria Eduarda de Jesus Santos","balance":253},
90 | {"agencia":47,"conta": 2229 ,"name":"Angela Cardozo da Silva","balance":523},
91 | {"agencia":47,"conta": 2230 ,"name":"Ariadne Fernanda de Freitas","balance":587},
92 | {"agencia":33,"conta": 9101 ,"name":"Denner Saborido de Oliveira","balance":584},
93 | {"agencia":33,"conta": 9102 ,"name":"Bruno Alvares","balance":654},
94 | {"agencia":33,"conta": 9103 ,"name":"Marcelo Santos da Silva","balance":256},
95 | {"agencia":33,"conta": 9104 ,"name":"Utai Oliveira","balance":125},
96 | {"agencia":33,"conta": 9105 ,"name":"Priscila Milagres Godinho","balance":145},
97 | {"agencia":33,"conta": 9106 ,"name":"Paulo Dias Macedo Neto","balance":941},
98 | {"agencia":33,"conta": 9107 ,"name":"Flavio Luis Moreira Pereira","balance":854},
99 | {"agencia":33,"conta": 9108 ,"name":"Arthur Marcos Calazans Belo","balance":456},
100 | {"agencia":33,"conta": 9109 ,"name":"Ana Carolina de Melo Santos","balance":874},
101 | {"agencia":33,"conta": 9110 ,"name":"Ricardo Camacho","balance":325},
102 | {"agencia":33,"conta": 9111 ,"name":"Thiago Menezes","balance":65},
103 | {"agencia":33,"conta": 9112 ,"name":"Luis Fernando Toscani","balance":45},
104 | {"agencia":33,"conta": 9113 ,"name":"Ingrid Martinez Martins","balance":22},
105 | {"agencia":33,"conta": 9114 ,"name":"Itamir Carvalho Junior","balance":42},
106 | {"agencia":33,"conta": 9115 ,"name":"Gabriela Correa Alves","balance":125},
107 | {"agencia":33,"conta": 9116 ,"name":"Vander Lucio Siqueira","balance":965},
108 | {"agencia":33,"conta": 9117 ,"name":"Taisa Viturino da Silva","balance":745},
109 | {"agencia":33,"conta": 9118 ,"name":"Norberto Gustavo da Costa","balance":895},
110 | {"agencia":33,"conta": 9119 ,"name":"Vanessa do Carmo Martins","balance":311},
111 | {"agencia":33,"conta": 9120 ,"name":"Rosa Maria Sandoval","balance":985},
112 | {"agencia":33,"conta": 9121 ,"name":"Brunno Leonardo Melo de Oliveira","balance":568},
113 | {"agencia":33,"conta": 9122 ,"name":"Raissa de Almeida Lima","balance":875},
114 | {"agencia":33,"conta": 9123 ,"name":"Glaucio de Souza","balance":2354},
115 | {"agencia":33,"conta": 9124 ,"name":"Julio Cezar Santos","balance":56},
116 | {"agencia":33,"conta": 9125 ,"name":"Danilo de Souza","balance":98},
117 | {"agencia":33,"conta": 9126 ,"name":"Diego Luiz Siqueira Teixeira","balance":89},
118 | {"agencia":33,"conta": 9127 ,"name":"Ariana de Cesare Pereira","balance":126},
119 | {"agencia":33,"conta": 9128 ,"name":"Eduardo Renan Ferreira","balance":658},
120 | {"agencia":33,"conta": 9129 ,"name":"Nivaldo Soares do Santos","balance":754},
121 | {"agencia":33,"conta": 9130 ,"name":"Moises Castillo","balance":857}
122 | ]
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/util/error-handlers.js:
--------------------------------------------------------------------------------
1 | const NotFoundError = require('./not-found.error');
2 | const InsufficientBalanceError = require('./insufficient-balance.error');
3 |
4 | exports.handler404 = (req, res, next) => {
5 | res
6 | .status(404)
7 | .json({ status: 404, message: 'Not Found' });
8 | };
9 |
10 | exports.handler500 = (err, req, res, next) => {
11 | console.error(err);
12 |
13 | const status = getStatus(err);
14 |
15 | res
16 | .status(status)
17 | .json({ status, message: err.message });
18 | };
19 |
20 | const getStatus = (err) => {
21 | if (err instanceof NotFoundError) return 404;
22 | if (err instanceof InsufficientBalanceError) return 422;
23 |
24 | return 500;
25 | }
26 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/util/insufficient-balance.error.js:
--------------------------------------------------------------------------------
1 | class InsufficientBalanceError extends Error {
2 | constructor(msg = 'Insufficient Balance') {
3 | super(msg);
4 | }
5 | }
6 |
7 | module.exports = InsufficientBalanceError;
8 |
--------------------------------------------------------------------------------
/modulo-04/trabalho-pratico-04/src/util/not-found.error.js:
--------------------------------------------------------------------------------
1 | class NotFoundError extends Error {
2 | constructor(msg) {
3 | super(msg);
4 | }
5 | }
6 |
7 | module.exports = NotFoundError;
8 |
--------------------------------------------------------------------------------