├── .gitignore ├── commitlint.config.js ├── .husky └── commit-msg ├── frontend ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── index.html ├── src │ ├── utils │ │ └── api.js │ ├── setupTests.js │ ├── App.test.js │ ├── index.css │ ├── reportWebVitals.js │ ├── index.js │ ├── App.js │ ├── App.css │ └── logo.svg ├── Dockerfile ├── .gitignore ├── package.json └── README.md ├── backend ├── Dockerfile ├── database │ ├── connection.js │ └── mysql-seeder │ │ └── languages.sql ├── .eslintrc.json ├── index.js └── package.json ├── .vscode └── settings.json ├── .github └── workflows │ └── main.yml ├── apresentacao ├── export │ ├── libs │ │ ├── reveal.js │ │ │ └── 4.1.3 │ │ │ │ ├── plugin │ │ │ │ ├── anything │ │ │ │ │ ├── d3.patch.js │ │ │ │ │ ├── d3 │ │ │ │ │ │ ├── queue.v1.min.js │ │ │ │ │ │ └── topojson.v1.min.js │ │ │ │ │ └── plugin.js │ │ │ │ ├── chalkboard │ │ │ │ │ └── style.css │ │ │ │ ├── fullscreen │ │ │ │ │ └── plugin.js │ │ │ │ ├── math │ │ │ │ │ └── math.js │ │ │ │ ├── embed-tweet │ │ │ │ │ └── plugin.js │ │ │ │ ├── customcontrols │ │ │ │ │ └── plugin.js │ │ │ │ ├── zoom │ │ │ │ │ └── zoom.js │ │ │ │ ├── chart │ │ │ │ │ └── plugin.js │ │ │ │ └── animate │ │ │ │ │ └── plugin.js │ │ │ │ ├── reset.css │ │ │ │ ├── theme │ │ │ │ └── night.css │ │ │ │ └── reveal.css │ │ ├── highlight.js │ │ │ └── 11.3.1 │ │ │ │ └── styles │ │ │ │ └── monokai.min.css │ │ └── styles │ │ │ └── tasklist.css │ └── index.html └── slides.md ├── docker-compose.yml ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit $1 5 | -------------------------------------------------------------------------------- /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thiago-Mariotto/project-config-base/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thiago-Mariotto/project-config-base/HEAD/frontend/public/logo192.png -------------------------------------------------------------------------------- /frontend/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Thiago-Mariotto/project-config-base/HEAD/frontend/public/logo512.png -------------------------------------------------------------------------------- /frontend/src/utils/api.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const api = axios.create({ 4 | baseURL: 'http://localhost:3333' 5 | 6 | }); 7 | 8 | export default api; -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14-alpine 2 | 3 | WORKDIR /app/api 4 | 5 | COPY package*.json ./ 6 | 7 | RUN npm install 8 | 9 | COPY . . 10 | 11 | EXPOSE 3333 12 | 13 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14-alpine 2 | 3 | WORKDIR /app/web 4 | 5 | COPY package*.json ./ 6 | 7 | RUN npm install 8 | 9 | COPY . . 10 | 11 | EXPOSE 3000 12 | 13 | CMD ["npm", "start"] -------------------------------------------------------------------------------- /backend/database/connection.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql2/promise'); 2 | 3 | const connection = mysql.createPool({ 4 | host: 'database', 5 | user: 'root', 6 | password: 'root', 7 | port: '3306', 8 | }); 9 | 10 | module.exports = connection; 11 | -------------------------------------------------------------------------------- /frontend/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'; 6 | -------------------------------------------------------------------------------- /frontend/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /backend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "airbnb-base" 9 | ], 10 | "parserOptions": { 11 | "ecmaVersion": "latest" 12 | }, 13 | "rules": {} 14 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnPaste": true, 3 | "editor.formatOnSave": true, 4 | "editor.formatOnSaveMode": "file", 5 | "editor.formatOnType": true, 6 | "editor.tabSize": 2, 7 | "editor.codeActionsOnSave": { 8 | "source.fixAll": true, 9 | "source.organizeImports": true 10 | // ... 11 | } 12 | } -------------------------------------------------------------------------------- /frontend/.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 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /backend/database/mysql-seeder/languages.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS technology DEFAULT CHARACTER SET = 'utf8'; 2 | USE technology; 3 | CREATE TABLE IF NOT EXISTS `language` (name VARCHAR(25), creator VARCHAR(25)); 4 | INSERT INTO 5 | `language` (name, creator) 6 | VALUES 7 | ('Java', 'James Gosling'), 8 | ('Javascript', 'Brendan Eich'), 9 | ('PHP', 'Rasmus Lerdorf'), 10 | ('Python', 'Guido van Rossum'), 11 | ('C#', 'Anders Hejlsberg') -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | types: [opened, synchronize] 4 | 5 | jobs: 6 | eslint: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | 11 | - uses: actions/setup-node@v2 12 | with: 13 | node-version: 14 14 | 15 | - name: Install back-end modules 16 | run: npm i --prefix backend 17 | 18 | - name: Run linter on back-end 19 | run: npm run lint --prefix backend 20 | -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /backend/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const cors = require('cors'); 3 | const connection = require('./database/connection'); 4 | 5 | const app = express(); 6 | const PORT = process.env.PORT || 3333; 7 | 8 | app.use(cors()); 9 | 10 | app.get('/', async (_req, res) => { 11 | try { 12 | const [instructors] = await connection.execute( 13 | 'SELECT * FROM technology.language', 14 | ); 15 | 16 | // HI 17 | 18 | return res.status(200).json(instructors); 19 | } catch (e) { 20 | return res.status(500).send(e); 21 | } 22 | }); 23 | 24 | app.listen(PORT); 25 | -------------------------------------------------------------------------------- /frontend/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 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/anything/d3.patch.js: -------------------------------------------------------------------------------- 1 | (function(d3) { 2 | document.scaleX = 1; 3 | document.scaleY = 1; 4 | function d3_eventSource() { 5 | var e = d3.event, s; 6 | while (s = e.sourceEvent) e = s; 7 | return e; 8 | } 9 | 10 | d3.mouse = function(container) { 11 | return d3_mousePoint(container, d3_eventSource()); 12 | }; 13 | 14 | function d3_mousePoint(container, e) { 15 | var rect = container.getBoundingClientRect(); 16 | return [ (e.clientX - rect.left - container.clientLeft)/document.scaleX, (e.clientY - rect.top - container.clientTop)/document.scaleY]; 17 | }; 18 | })(d3); 19 | 20 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | services: 4 | # containers 5 | database: 6 | image: mysql:5.7 7 | container_name: mysql_compose 8 | ports: 9 | - 3306:3306 10 | environment: 11 | - MYSQL_ROOT_PASSWORD=root 12 | volumes: 13 | - ./backend/database/mysql-seeder:/docker-entrypoint-initdb.d 14 | 15 | api: 16 | build: ./backend 17 | container_name: backend_compose 18 | ports: 19 | - 3333:3333 20 | depends_on: 21 | - database 22 | 23 | web: 24 | build: ./frontend 25 | container_name: frontend_compose 26 | ports: 27 | - 3000:3000 28 | depends_on: 29 | - api 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "project-config", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "prepare": "husky install", 9 | "commit": "cz" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "@commitlint/cli": "^16.2.3", 16 | "@commitlint/config-conventional": "^16.2.1", 17 | "commitizen": "^4.2.4", 18 | "cz-conventional-changelog": "^3.3.0", 19 | "husky": "^7.0.4" 20 | }, 21 | "config": { 22 | "commitizen": { 23 | "path": "./node_modules/cz-conventional-changelog" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import './App.css'; 3 | import api from './utils/api'; 4 | 5 | function App() { 6 | 7 | const [instructors, setInstructors] = useState([]); 8 | 9 | useEffect(() => { 10 | api.get('/').then(response => { setInstructors(response.data) }); 11 | }, []); 12 | 13 | 14 | return ( 15 |
16 |
17 |

Proggraming Languages

18 | { 19 | instructors.map(p => ( 20 | {p.name} - {p.creator} 21 | ))} 22 |
23 |
24 | ); 25 | } 26 | 27 | export default App; 28 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "lint": "eslint --no-inline-config --no-error-on-unmatched-pattern -c .eslintrc.json .", 9 | "start": "node index.js" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "eslint": "^8.12.0", 16 | "eslint-config-airbnb-base": "^15.0.0", 17 | "eslint-plugin-import": "^2.26.0" 18 | }, 19 | "dependencies": { 20 | "cors": "^2.8.5", 21 | "express": "^4.17.3", 22 | "mysql2": "^2.3.3" 23 | } 24 | } -------------------------------------------------------------------------------- /frontend/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apresentacao/export/libs/highlight.js/11.3.1/styles/monokai.min.css: -------------------------------------------------------------------------------- 1 | pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#272822;color:#ddd}.hljs-keyword,.hljs-literal,.hljs-name,.hljs-selector-tag,.hljs-strong,.hljs-tag{color:#f92672}.hljs-code{color:#66d9ef}.hljs-attribute,.hljs-link,.hljs-regexp,.hljs-symbol{color:#bf79db}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-emphasis,.hljs-section,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-string,.hljs-subst,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type,.hljs-variable{color:#a6e22e}.hljs-class .hljs-title,.hljs-title.class_{color:#fff}.hljs-comment,.hljs-deletion,.hljs-meta,.hljs-quote{color:#75715e}.hljs-doctag,.hljs-keyword,.hljs-literal,.hljs-section,.hljs-selector-id,.hljs-selector-tag,.hljs-title,.hljs-type{font-weight:700} -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/chalkboard/style.css: -------------------------------------------------------------------------------- 1 | div.palette, div.boardhandle { 2 | position: absolute; 3 | /* 4 | height: 260px; 5 | margin: -130px 0 0 0px; 6 | */ 7 | top: 50%; 8 | transform: translateY(-50%); 9 | font-size: 24px; 10 | border-radius: 10px; 11 | border-top: 4px solid #222; 12 | border-right: 4px solid #222; 13 | border-bottom: 4px solid #222; 14 | background: black; 15 | transition: transform 0.3s; 16 | } 17 | 18 | div.palette { 19 | left: -10px; 20 | padding-left:10px; 21 | } 22 | 23 | div.boardhandle { 24 | right: -10px; 25 | padding-right:10px; 26 | } 27 | 28 | div.palette > ul, 29 | div.boardhandle > ul { 30 | list-style-type: none; 31 | margin: 0; 32 | padding: 0; 33 | } 34 | 35 | div.palette > ul > li, 36 | div.boardhandle > ul > li { 37 | margin: 10px; 38 | } 39 | 40 | @media print { 41 | div.palette, div.boardhandle, .chalkboard-button { 42 | display: none!important; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.4", 7 | "@testing-library/react": "^12.1.4", 8 | "@testing-library/user-event": "^13.5.0", 9 | "axios": "^0.26.1", 10 | "react": "^18.0.0", 11 | "react-dom": "^18.0.0", 12 | "react-scripts": "5.0.0", 13 | "web-vitals": "^2.1.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": [ 23 | "react-app", 24 | "react-app/jest" 25 | ] 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v4.0 | 20180602 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 | main, 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, main, menu, nav, section { 29 | display: block; 30 | } -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/anything/d3/queue.v1.min.js: -------------------------------------------------------------------------------- 1 | !function(n,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define("queue",r):n.queue=r()}(this,function(){"use strict";function n(){}function r(r){function t(){if(!h)try{l()}catch(n){s[v+y-1]&&i(n)}}function l(){for(;h=d&&r>y;){var n=v+y,t=s[n],u=t.length-1,o=t[u];t[u]=f(n),--d,++y,t=o.apply(null,t),s[n]&&(s[n]=t||e)}}function f(n){return function(r,u){s[n]&&(--y,++v,s[n]=null,null==p&&(null!=r?i(r):(w[n]=u,d?t():y||c())))}}function i(n){var r,t=s.length;for(p=n,w=null,d=NaN;--t>=0;)if((r=s[t])&&(s[t]=null,r.abort))try{r.abort()}catch(n){}y=NaN,c()}function c(){null!=p?b(p):g?b(null,w):b.apply(null,o.concat(w))}if(!(r>=1))throw new Error;var a,h,p,s=[],w=[],d=0,y=0,v=0,b=n,g=!0;return a={defer:function(r){if(b!==n)throw new Error;if(null!=p)return a;var e=u.call(arguments,1);return e.push(r),++d,s.push(e),t(),a},abort:function(){return null==p&&i(new Error("abort")),a},await:function(r){if(b!==n)throw new Error;return b=r,g=!1,y||c(),a},awaitAll:function(r){if(b!==n)throw new Error;return b=r,g=!0,y||c(),a}}}function t(n){return r(arguments.length?+n:1/0)}var u=[].slice,e={},o=[null];return t.version="1.2.1",t}); -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/fullscreen/plugin.js: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | ** Author: Asvin Goel, goel@telematique.eu 3 | ** 4 | ** A plugin allowing slides to use the full window size. 5 | ** 6 | ** Version: 1.0.0 7 | ** 8 | ** License: MIT license (see LICENSE.md) 9 | ** 10 | ******************************************************************/ 11 | 12 | window.RevealFullscreen = window.RevealFullscreen || { 13 | id: 'RevealFullscreen', 14 | init: function(deck) { 15 | initFullscreen(deck); 16 | } 17 | }; 18 | 19 | const initFullscreen = function(Reveal){ 20 | var config = null; 21 | var ready = false; 22 | 23 | Reveal.addEventListener( 'ready', function( event ) { 24 | ready = true; 25 | config = { width: Reveal.getConfig().width, height: Reveal.getConfig().height, margin: Reveal.getConfig().margin }; 26 | if ( Reveal.getCurrentSlide().hasAttribute("data-fullscreen") ) { 27 | Reveal.configure( { width: window.innerWidth, height: window.innerHeight, margin: 0 } ); 28 | } 29 | } ); 30 | 31 | Reveal.addEventListener( 'slidechanged', function( event ) { 32 | if ( Reveal.getCurrentSlide().hasAttribute("data-fullscreen") ) { 33 | Reveal.configure( { width: window.innerWidth, height: window.innerHeight, margin: 0 } ); 34 | } 35 | else { 36 | Reveal.configure( config ); 37 | } 38 | } ); 39 | 40 | window.addEventListener( 'resize', function( event ) { 41 | if ( ready && Reveal.getCurrentSlide().hasAttribute("data-fullscreen") ) { 42 | Reveal.configure( { width: window.innerWidth, height: window.innerHeight, margin: 0 } ); 43 | } 44 | } ); 45 | 46 | }; 47 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/math/math.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).RevealMath=t()}(this,(function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var r=1;r 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/embed-tweet/plugin.js: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | ** Author: Asvin Goel, goel@telematique.eu 3 | ** 4 | ** A plugin for embedding tweets. 5 | ** 6 | ** Version: 1.0.0 7 | ** 8 | ** License: MIT license (see LICENSE.md) 9 | ** 10 | ******************************************************************/ 11 | 12 | window.RevealEmbedTweet = window.RevealEmbedTweet || { 13 | id: 'RevealEmbedTweet', 14 | init: function(deck) { 15 | initEmbedTweet(deck); 16 | } 17 | }; 18 | 19 | const initEmbedTweet = function(Reveal){ 20 | var ready = false; 21 | window.twttr = (function(d, s, id) { 22 | var js, fjs = d.getElementsByTagName(s)[0], 23 | t = window.twttr || {}; 24 | if (d.getElementById(id)) return t; 25 | js = d.createElement(s); 26 | js.id = id; 27 | js.src = "https://platform.twitter.com/widgets.js"; 28 | fjs.parentNode.insertBefore(js, fjs); 29 | 30 | t._e = []; 31 | t.ready = function(f) { 32 | t._e.push(f); 33 | }; 34 | }(document, "script", "twitter-wjs")); 35 | 36 | 37 | function load() { 38 | if ( twttr != undefined && !document.querySelector('section[data-markdown]:not([data-markdown-parsed])') ) { 39 | tweets = document.querySelectorAll(".tweet"); 40 | for (i = 0; i < tweets.length; ++i) { 41 | tweets[i].style.cssText = "margin: 0;position: absolute; left: 50%;transform: translate(-50%,0%);" + tweets[i].style.cssText; 42 | tweets[i].innerHTML = ''; 43 | } 44 | twttr.widgets.load() 45 | } 46 | else { 47 | // wait for markdown to be loaded and parsed 48 | setTimeout( load, 100 ); 49 | } 50 | } 51 | 52 | Reveal.addEventListener( 'ready', function( event ) { 53 | load(); 54 | } ); 55 | 56 | this.refresh = load; 57 | 58 | return this; 59 | }; 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /apresentacao/export/libs/styles/tasklist.css: -------------------------------------------------------------------------------- 1 | [class*=task-list-item] { 2 | min-height: 22px; 3 | margin-top: 6px!important; 4 | margin-bottom: 6px!important; 5 | padding-left: 0; 6 | list-style: none; 7 | } 8 | 9 | [class*=task-list-item]>input:first-child { 10 | position: absolute!important; 11 | opacity: 0; 12 | margin: 0; 13 | } 14 | [class*=task-list-item]>label { 15 | padding-left: 29px!important; 16 | min-height: 22px; 17 | line-height: 22px; 18 | display: inline-block; 19 | position: relative; 20 | vertical-align: top; 21 | margin-bottom: 0; 22 | font-weight: 400; 23 | cursor: pointer; 24 | } 25 | 26 | .task-list-item>input:first-child:checked+input[type=hidden]+label::before, .task-list-item>input:first-child:checked+label::before { 27 | background-color: #ecf0f1; 28 | border-color: #ecf0f1; 29 | } 30 | 31 | [class*=task-list-item]>input:first-child+input[type=hidden]+label::before, [class*=task-list-item]>input:first-child+label::before { 32 | content: ""; 33 | display: inline-block; 34 | position: absolute; 35 | width: 22px; 36 | height: 22px; 37 | border: 1px solid #D3CFC8; 38 | border-radius: 0; 39 | margin-left: -29px; 40 | } 41 | 42 | 43 | [class*=task-list-item]>input:first-child:checked+input[type=hidden]+label::after, [class*=task-list-item]>input:first-child:checked+label::after { 44 | content: ""; 45 | display: inline-block; 46 | position: absolute; 47 | top: 0; 48 | left: 0; 49 | width: 7px; 50 | height: 10px; 51 | border: 2px solid #fff; 52 | border-left: none; 53 | border-top: none; 54 | transform: translate(7.75px,4.5px) rotate(45deg); 55 | -ms-transform: translate(7.75px,4.5px) rotate(45deg); 56 | } 57 | 58 | 59 | .task-list-item>input:first-child:checked+input[type=hidden]+label::after, .task-list-item>input:first-child:checked+label::after { 60 | border-bottom-color: #95a5a6; 61 | border-right-color: #95a5a6; 62 | } 63 | 64 | 65 | 66 | .reveal .container{ 67 | display: grid; 68 | grid-auto-flow: column; 69 | } 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Configurações iniciais de um projeto 2 | 3 | ## Boas vindas 4 | 5 | Este é um exemplo de como utilizar o [Docker Compose](https://docs.docker.com/compose/install/) para iniciar três aplicações containerizadas, sendo elas: 6 | 1. [MySQL](https://www.mysql.com/) 7 | 2. [API com Node.js](https://nodejs.org/en/) 8 | 3. [SPA com React.js](https://reactjs.org/) 9 | 10 | ### Pré requisitos 11 | 12 | Você precisa das seguintes ferramentas instaladas 13 | 14 | - [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) 15 | - [Docker](https://docs.docker.com/engine/install/ubuntu/) 16 | - [Docker Compose](https://docs.docker.com/compose/install/) 17 | 18 | ### Instalação 19 | 20 | Siga este passo a passo para testar este repositório. 21 | 22 | Clone o repositório para sua máquina local 23 | 24 | ``` 25 | $ git clone git@github.com:Thiago-Mariotto/docker-compose-example.git 26 | ``` 27 | 28 | Acesse a pasta 29 | 30 | ``` 31 | $ cd docker-compose-example 32 | ``` 33 | 34 | Inicie a aplicação com o Docker Compose 35 | 36 | ``` 37 | $ docker-compose up --build 38 | ``` 39 | O comando acima realiza o build do arquivo `docker-compose.yml` construindo todas as imagens necessárias e inicializa todos os containers configurados. 40 | 41 | ## Como utilizar? 42 | 43 | 1. Cetifique-se de seguir todos os passos de instação. 44 | 2. Verifique se todos os containers foram iniciados. 45 | 46 | ```sh 47 | $ docker ps 48 | ``` 49 | 50 | O retorno deve conter 3 containers ativos `frontend` | `backend` | `mysql`. 51 | 52 | ### Acessando o frontend 53 | 54 | A página do frontend deve ser renderizado no endereço `http://localhost:3000`, sua página inicial renderiza os dados retornados da api. 55 | 56 | ### Acessando o backend 57 | 58 | A API estará sendo executada na porta 3333, é possível verificar o acesso em uma rota GET `http://localhost:3333` o retorno é um Array de pessoas instrutoras e suas frases. 59 | 60 | ### Acessando o banco de dados 61 | 62 | O banco de dados é populado com um script que está localizado na pasta `backend/mysql-dump` quando o container é inicializado. 63 | 64 | É possível acessa-lo pela porta `3306` do seu `localhost` ou `127.0.0.1` a senha de acesso é `docker`. 65 | 66 | ### Realizando pull request 67 | 68 | Certifique-se de executar `npm run lint` na pasta do backend, existe uma action de validação. 69 | 70 | 71 | ## Aproveite :) 72 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/customcontrols/plugin.js: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | ** Author: Asvin Goel, goel@telematique.eu 3 | ** 4 | ** A plugin replacing the default controls by custom controls. 5 | ** 6 | ** Version: 2.0.0 7 | ** 8 | ** License: MIT license (see LICENSE.md) 9 | ** 10 | ******************************************************************/ 11 | window.RevealCustomControls = window.RevealCustomControls || { 12 | id: 'RevealCustomControls', 13 | init: function(deck) { 14 | initCustomControls(deck); 15 | } 16 | }; 17 | 18 | const initCustomControls = function(Reveal){ 19 | var config = Reveal.getConfig().customcontrols || {}; 20 | 21 | var collapseIcon = config.collapseIcon || ''; 22 | var expandIcon = config.expandIcon || ''; 23 | var tooltip = config.tooltip || 'Show/hide controls'; 24 | 25 | var div = document.createElement( 'div' ); 26 | div.id = 'customcontrols'; 27 | 28 | var toggleButton = document.createElement( 'button' ); 29 | toggleButton.title = tooltip; 30 | toggleButton.innerHTML = '' + collapseIcon + '' + '' + expandIcon + ''; 31 | 32 | toggleButton.addEventListener('click', function( event ) { 33 | var div = document.querySelector("div#customcontrols"); 34 | if ( div.classList.contains('collapsed') ) { 35 | div.classList.remove('collapsed'); 36 | } 37 | else { 38 | div.classList.add('collapsed'); 39 | } 40 | }); 41 | 42 | div.appendChild(toggleButton); 43 | 44 | var controls = document.createElement( 'ul' ); 45 | for (var i = 0; i < config.controls.length; i++ ) { 46 | var control = document.createElement( 'li' ); 47 | if ( config.controls[i].id ) { 48 | control.id = config.controls[i].id; 49 | } 50 | control.innerHTML = ''; 51 | controls.appendChild( control ); 52 | } 53 | div.appendChild( controls ); 54 | 55 | 56 | document.querySelector(".reveal").appendChild( div ); 57 | 58 | document.addEventListener( 'resize', function( event ) { 59 | // expand controls to make sure they are visible 60 | var div = document.querySelector("div#customcontrols.collapsed"); 61 | if ( div ) { 62 | div.classList.remove('collapsed'); 63 | } 64 | } ); 65 | 66 | return this; 67 | 68 | }; 69 | 70 | -------------------------------------------------------------------------------- /frontend/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/anything/plugin.js: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | ** Author: Asvin Goel, goel@telematique.eu 3 | ** 4 | ** A plugin for reveal.js allowing to easily integrate any content 5 | ** 6 | ** Version: 1.0.1 7 | ** 8 | ** License: MIT license (see LICENSE.md) 9 | ** 10 | ******************************************************************/ 11 | 12 | window.RevealAnything = window.RevealAnything || { 13 | id: 'RevealAnything', 14 | init: function(deck) { 15 | if ( Reveal.getConfig().anything ) initAnything(deck); 16 | } 17 | }; 18 | 19 | const initAnything = function(Reveal){ 20 | function parseJSON(str) { 21 | str = str.replace(/(\r\n|\n|\r|\t)/gm,""); // remove line breaks and tabs 22 | var json; 23 | try { 24 | json = JSON.parse(str, function (key, value) { 25 | if (value && (typeof value === 'string') && value.indexOf("function") === 0) { 26 | // we can only pass a function as string in JSON ==> doing a real function 27 | // eval("var jsFunc = " + value); 28 | var jsFunc = new Function('return ' + value)(); 29 | return jsFunc; 30 | } 31 | return value; 32 | }); 33 | } catch (e) { 34 | return null; 35 | } 36 | return json; 37 | } 38 | 39 | /* 40 | * Recursively merge properties of two objects without overwriting the first 41 | */ 42 | function mergeRecursive(obj1, obj2) { 43 | 44 | for (var p in obj2) { 45 | try { 46 | // Property in destination object set; update its value. 47 | if ( obj1[p] !== null && typeof obj1[p] === 'object' && typeof obj2[p] === 'object' ) { 48 | obj1[p] = mergeRecursive(obj1[p], obj2[p]); 49 | } 50 | else { 51 | obj1[p] = obj2[p]; 52 | } 53 | } catch(e) { 54 | // Property in destination object not set; create it and set its value. 55 | obj1[p] = obj2[p]; 56 | } 57 | } 58 | 59 | return obj1; 60 | } 61 | 62 | 63 | var config = Reveal.getConfig().anything; 64 | 65 | Reveal.addEventListener( 'ready', function( event ) { 66 | for (var i = 0; i < config.length; i++ ){ 67 | // Get all elements of the class 68 | var elements = document.getElementsByClassName(config[i].className); 69 | var initialize = config[i].initialize; 70 | // deprecated parameters 71 | if ( !initialize && config[i].f ) { 72 | initialize = config[i].f; 73 | console.warn('Setting parameter "f" is deprecated! Use "initialize" instead. '); 74 | } 75 | 76 | for (var j = 0; j < elements.length; j++ ){ 77 | var options = config[i].defaults; 78 | var comments = elements[j].innerHTML.trim().match(//g); 79 | if ( comments !== null ) for (var k = 0; k < comments.length; k++ ){ 80 | comments[k] = comments[k].replace(//,''); 82 | mergeRecursive( options, config[i].defaults); 83 | options = parseJSON(comments[k]); 84 | if ( options ) { 85 | mergeRecursive( options, config[i].defaults); 86 | break; 87 | } 88 | } 89 | // console.log(config[i].className + " options: " + JSON.stringify(options)) 90 | initialize(elements[j], options); 91 | // console.log(elements[j].outerHTML) 92 | } 93 | } 94 | } ); 95 | 96 | 97 | }; 98 | 99 | 100 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | 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. 37 | 38 | 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. 39 | 40 | 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. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/zoom/zoom.js: -------------------------------------------------------------------------------- 1 | !function(e,o){"object"==typeof exports&&"undefined"!=typeof module?module.exports=o():"function"==typeof define&&define.amd?define(o):(e="undefined"!=typeof globalThis?globalThis:e||self).RevealZoom=o()}(this,(function(){"use strict"; 2 | /*! 3 | * reveal.js Zoom plugin 4 | */var e={id:"zoom",init:function(e){e.getRevealElement().addEventListener("mousedown",(function(t){var n=/Linux/.test(window.navigator.platform)?"ctrl":"alt",i=(e.getConfig().zoomKey?e.getConfig().zoomKey:n)+"Key",d=e.getConfig().zoomLevel?e.getConfig().zoomLevel:2;t[i]&&!e.isOverview()&&(t.preventDefault(),o.to({x:t.clientX,y:t.clientY,scale:d,pan:!1}))}))}},o=function(){var e=1,t=0,n=0,i=-1,d=-1,s="WebkitTransform"in document.body.style||"MozTransform"in document.body.style||"msTransform"in document.body.style||"OTransform"in document.body.style||"transform"in document.body.style;function r(o,t){var n=l();if(o.width=o.width||1,o.height=o.height||1,o.x-=(window.innerWidth-o.width*t)/2,o.y-=(window.innerHeight-o.height*t)/2,s)if(1===t)document.body.style.transform="",document.body.style.OTransform="",document.body.style.msTransform="",document.body.style.MozTransform="",document.body.style.WebkitTransform="";else{var i=n.x+"px "+n.y+"px",d="translate("+-o.x+"px,"+-o.y+"px) scale("+t+")";document.body.style.transformOrigin=i,document.body.style.OTransformOrigin=i,document.body.style.msTransformOrigin=i,document.body.style.MozTransformOrigin=i,document.body.style.WebkitTransformOrigin=i,document.body.style.transform=d,document.body.style.OTransform=d,document.body.style.msTransform=d,document.body.style.MozTransform=d,document.body.style.WebkitTransform=d}else 1===t?(document.body.style.position="",document.body.style.left="",document.body.style.top="",document.body.style.width="",document.body.style.height="",document.body.style.zoom=""):(document.body.style.position="relative",document.body.style.left=-(n.x+o.x)/t+"px",document.body.style.top=-(n.y+o.y)/t+"px",document.body.style.width=100*t+"%",document.body.style.height=100*t+"%",document.body.style.zoom=t);e=t,document.documentElement.classList&&(1!==e?document.documentElement.classList.add("zoomed"):document.documentElement.classList.remove("zoomed"))}function m(){var o=.12*window.innerWidth,i=.12*window.innerHeight,d=l();nwindow.innerHeight-i&&window.scroll(d.x,d.y+(1-(window.innerHeight-n)/i)*(14/e)),twindow.innerWidth-o&&window.scroll(d.x+(1-(window.innerWidth-t)/o)*(14/e),d.y)}function l(){return{x:void 0!==window.scrollX?window.scrollX:window.pageXOffset,y:void 0!==window.scrollY?window.scrollY:window.pageYOffset}}return s&&(document.body.style.transition="transform 0.8s ease",document.body.style.OTransition="-o-transform 0.8s ease",document.body.style.msTransition="-ms-transform 0.8s ease",document.body.style.MozTransition="-moz-transform 0.8s ease",document.body.style.WebkitTransition="-webkit-transform 0.8s ease"),document.addEventListener("keyup",(function(t){1!==e&&27===t.keyCode&&o.out()})),document.addEventListener("mousemove",(function(o){1!==e&&(t=o.clientX,n=o.clientY)})),{to:function(t){if(1!==e)o.out();else{if(t.x=t.x||0,t.y=t.y||0,t.element){var n=t.element.getBoundingClientRect();t.x=n.left-20,t.y=n.top-20,t.width=n.width+40,t.height=n.height+40}void 0!==t.width&&void 0!==t.height&&(t.scale=Math.max(Math.min(window.innerWidth/t.width,window.innerHeight/t.height),1)),t.scale>1&&(t.x*=t.scale,t.y*=t.scale,r(t,t.scale),!1!==t.pan&&(i=setTimeout((function(){d=setInterval(m,1e3/60)}),800)))}},out:function(){clearTimeout(i),clearInterval(d),r({x:0,y:0},1),e=1},magnify:function(e){this.to(e)},reset:function(){this.out()},zoomLevel:function(){return e}}}();return function(){return e}})); 5 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/anything/d3/topojson.v1.min.js: -------------------------------------------------------------------------------- 1 | !function(){function n(n,t){function r(t){var r,e=n.arcs[0>t?~t:t],o=e[0];return n.transform?(r=[0,0],e.forEach(function(n){r[0]+=n[0],r[1]+=n[1]})):r=e[e.length-1],0>t?[r,o]:[o,r]}function e(n,t){for(var r in n){var e=n[r];delete t[e.start],delete e.start,delete e.end,e.forEach(function(n){o[0>n?~n:n]=1}),f.push(e)}}var o={},i={},u={},f=[],c=-1;return t.forEach(function(r,e){var o,i=n.arcs[0>r?~r:r];i.length<3&&!i[1][0]&&!i[1][1]&&(o=t[++c],t[c]=r,t[e]=o)}),t.forEach(function(n){var t,e,o=r(n),f=o[0],c=o[1];if(t=u[f])if(delete u[t.end],t.push(n),t.end=c,e=i[c]){delete i[e.start];var a=e===t?t:t.concat(e);i[a.start=t.start]=u[a.end=e.end]=a}else i[t.start]=u[t.end]=t;else if(t=i[c])if(delete i[t.start],t.unshift(n),t.start=f,e=u[f]){delete u[e.end];var s=e===t?t:e.concat(t);i[s.start=e.start]=u[s.end=t.end]=s}else i[t.start]=u[t.end]=t;else t=[n],i[t.start=f]=u[t.end=c]=t}),e(u,i),e(i,u),t.forEach(function(n){o[0>n?~n:n]||f.push([n])}),f}function t(t,r,e){function o(n){var t=0>n?~n:n;(s[t]||(s[t]=[])).push({i:n,g:a})}function i(n){n.forEach(o)}function u(n){n.forEach(i)}function f(n){"GeometryCollection"===n.type?n.geometries.forEach(f):n.type in l&&(a=n,l[n.type](n.arcs))}var c=[];if(arguments.length>1){var a,s=[],l={LineString:i,MultiLineString:u,Polygon:u,MultiPolygon:function(n){n.forEach(u)}};f(r),s.forEach(arguments.length<3?function(n){c.push(n[0].i)}:function(n){e(n[0].g,n[n.length-1].g)&&c.push(n[0].i)})}else for(var h=0,p=t.arcs.length;p>h;++h)c.push(h);return{type:"MultiLineString",arcs:n(t,c)}}function r(t,r){function e(n){n.forEach(function(t){t.forEach(function(t){(u[t=0>t?~t:t]||(u[t]=[])).push(n)})}),f.push(n)}function o(n){return s(i(t,{type:"Polygon",arcs:[n]}).coordinates[0])>0}var u={},f=[],c=[];return r.forEach(function(n){"Polygon"===n.type?e(n.arcs):"MultiPolygon"===n.type&&n.arcs.forEach(e)}),f.forEach(function(n){if(!n._){var t=[],r=[n];for(n._=1,c.push(t);n=r.pop();)t.push(n),n.forEach(function(n){n.forEach(function(n){u[0>n?~n:n].forEach(function(n){n._||(n._=1,r.push(n))})})})}}),f.forEach(function(n){delete n._}),{type:"MultiPolygon",arcs:c.map(function(r){var e,i=[];if(r.forEach(function(n){n.forEach(function(n){n.forEach(function(n){u[0>n?~n:n].length<2&&i.push(n)})})}),i=n(t,i),(e=i.length)>1)for(var f,c=o(r[0][0]),a=0;e>a;++a)if(c===o(i[a])){f=i[0],i[0]=i[a],i[a]=f;break}return i})}}function e(n,t){return"GeometryCollection"===t.type?{type:"FeatureCollection",features:t.geometries.map(function(t){return o(n,t)})}:o(n,t)}function o(n,t){var r={type:"Feature",id:t.id,properties:t.properties||{},geometry:i(n,t)};return null==t.id&&delete r.id,r}function i(n,t){function r(n,t){t.length&&t.pop();for(var r,e=s[0>n?~n:n],o=0,i=e.length;i>o;++o)t.push(r=e[o].slice()),a(r,o);0>n&&u(t,i)}function e(n){return n=n.slice(),a(n,0),n}function o(n){for(var t=[],e=0,o=n.length;o>e;++e)r(n[e],t);return t.length<2&&t.push(t[0].slice()),t}function i(n){for(var t=o(n);t.length<4;)t.push(t[0].slice());return t}function f(n){return n.map(i)}function c(n){var t=n.type;return"GeometryCollection"===t?{type:t,geometries:n.geometries.map(c)}:t in l?{type:t,coordinates:l[t](n)}:null}var a=g(n.transform),s=n.arcs,l={Point:function(n){return e(n.coordinates)},MultiPoint:function(n){return n.coordinates.map(e)},LineString:function(n){return o(n.arcs)},MultiLineString:function(n){return n.arcs.map(o)},Polygon:function(n){return f(n.arcs)},MultiPolygon:function(n){return n.arcs.map(f)}};return c(t)}function u(n,t){for(var r,e=n.length,o=e-t;o<--e;)r=n[o],n[o++]=n[e],n[e]=r}function f(n,t){for(var r=0,e=n.length;e>r;){var o=r+e>>>1;n[o]n&&(n=~n);var r=o[n];r?r.push(t):o[n]=[t]})}function r(n,r){n.forEach(function(n){t(n,r)})}function e(n,t){"GeometryCollection"===n.type?n.geometries.forEach(function(n){e(n,t)}):n.type in u&&u[n.type](n.arcs,t)}var o={},i=n.map(function(){return[]}),u={LineString:t,MultiLineString:r,Polygon:r,MultiPolygon:function(n,t){n.forEach(function(n){r(n,t)})}};n.forEach(e);for(var c in o)for(var a=o[c],s=a.length,l=0;s>l;++l)for(var h=l+1;s>h;++h){var p,g=a[l],v=a[h];(p=i[g])[c=f(p,v)]!==v&&p.splice(c,0,v),(p=i[v])[c=f(p,g)]!==g&&p.splice(c,0,g)}return i}function a(n,t){function r(n){i.remove(n),n[1][2]=t(n),i.push(n)}var e=g(n.transform),o=v(n.transform),i=p();return t||(t=l),n.arcs.forEach(function(n){for(var u,f,c=[],a=0,s=0,l=n.length;l>s;++s)f=n[s],e(n[s]=[f[0],f[1],1/0],s);for(var s=1,l=n.length-1;l>s;++s)u=n.slice(s-1,s+2),u[1][2]=t(u),c.push(u),i.push(u);for(var s=0,l=c.length;l>s;++s)u=c[s],u.previous=c[s-1],u.next=c[s+1];for(;u=i.pop();){var h=u.previous,p=u.next;u[1][2]0;){var r=(t+1>>1)-1,o=e[r];if(h(n,o)>=0)break;e[o._=t]=o,e[n._=t=r]=n}}function t(n,t){for(;;){var r=t+1<<1,i=r-1,u=t,f=e[u];if(o>i&&h(e[i],f)<0&&(f=e[u=i]),o>r&&h(e[r],f)<0&&(f=e[u=r]),u===t)break;e[f._=t]=f,e[n._=t=u]=n}}var r={},e=[],o=0;return r.push=function(t){return n(e[t._=o]=t,o++),o},r.pop=function(){if(!(0>=o)){var n,r=e[0];return--o>0&&(n=e[o],t(e[n._=0]=n,0)),r}},r.remove=function(r){var i,u=r._;if(e[u]===r)return u!==--o&&(i=e[o],(h(i,r)<0?n:t)(e[i._=u]=i,u)),u},r}function g(n){if(!n)return m;var t,r,e=n.scale[0],o=n.scale[1],i=n.translate[0],u=n.translate[1];return function(n,f){f||(t=r=0),n[0]=(t+=n[0])*e+i,n[1]=(r+=n[1])*o+u}}function v(n){if(!n)return m;var t,r,e=n.scale[0],o=n.scale[1],i=n.translate[0],u=n.translate[1];return function(n,f){f||(t=r=0);var c=(n[0]-i)/e|0,a=(n[1]-u)/o|0;n[0]=c-t,n[1]=a-r,t=c,r=a}}function m(){}var y={version:"1.6.20",mesh:function(n){return i(n,t.apply(this,arguments))},meshArcs:t,merge:function(n){return i(n,r.apply(this,arguments))},mergeArcs:r,feature:e,neighbors:c,presimplify:a};"function"==typeof define&&define.amd?define(y):"object"==typeof module&&module.exports?module.exports=y:this.topojson=y}(); -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/chart/plugin.js: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | ** Author: Asvin Goel, goel@telematique.eu 3 | ** Fixed for Reveal4: kotborealis@awooo.ru 4 | ** 5 | ** A plugin for reveal.js allowing to integrate Chart.js 6 | ** 7 | ** Version: 1.3.1 8 | ** 9 | ** License: MIT license (see LICENSE.md) 10 | ** 11 | ******************************************************************/ 12 | 13 | /** 14 | * Reveal Plugin 15 | * https://revealjs.com/creating-plugins/ 16 | */ 17 | window.RevealChart = window.RevealChart || { 18 | id: 'RevealChart', 19 | init: function(deck) { 20 | initChart(deck); 21 | }, 22 | update: function(canvas, idx, data) { update(canvas, idx, data); }, 23 | }; 24 | 25 | const initChart = function(Reveal){ 26 | function parseJSON(str) { 27 | var json; 28 | try { 29 | json = JSON.parse(str); 30 | } catch (e) { 31 | return null; 32 | } 33 | return json; 34 | } 35 | 36 | /* 37 | * Recursively merge properties of two objects 38 | */ 39 | function mergeRecursive(obj1, obj2) { 40 | 41 | for (var p in obj2) { 42 | try { 43 | // Property in destination object set; update its value. 44 | if ( obj1[p] !== null && typeof obj1[p] === 'object' && typeof obj2[p] === 'object' ) { 45 | obj1[p] = mergeRecursive(obj1[p], obj2[p]); 46 | } 47 | else { 48 | obj1[p] = obj2[p]; 49 | } 50 | } catch(e) { 51 | // Property in destination object not set; create it and set its value. 52 | obj1[p] = obj2[p]; 53 | } 54 | } 55 | 56 | return obj1; 57 | } 58 | 59 | 60 | function createChart(canvas, CSV, comments) { 61 | canvas.chart = null; 62 | var ctx = canvas.getContext("2d"); 63 | var chartOptions = { responsive: true, maintainAspectRatio: false }; 64 | var chartData = { labels: null, datasets: []}; 65 | if ( comments !== null ) for (var j = 0; j < comments.length; j++ ){ 66 | comments[j] = comments[j].replace(//,''); 68 | var config = parseJSON(comments[j]); 69 | if ( config ) { 70 | if ( config.data ) { 71 | mergeRecursive( chartData, config.data); 72 | } 73 | if ( config.options ) { 74 | mergeRecursive( chartOptions, config.options); 75 | } 76 | } 77 | } 78 | 79 | var lines = CSV.split('\n').filter(function(v){return v!==''}); 80 | // if labels are not defined, get them from first line 81 | if ( chartData.labels === null && lines.length > 0 ) { 82 | chartData.labels = lines[0].split(','); 83 | chartData.labels.shift(); 84 | lines.shift(); 85 | } 86 | // get data values 87 | for (var j = 0; j < lines.length; j++ ){ 88 | if (chartData.datasets.length <= j) chartData.datasets[j] = {}; 89 | chartData.datasets[j].data = lines[j].split(','); //.filter(function(v){return v!==''}); 90 | chartData.datasets[j].label = chartData.datasets[j].data[0]; 91 | chartData.datasets[j].data.shift(); 92 | for (var k = 0; k < chartData.datasets[j].data.length; k++ ){ 93 | chartData.datasets[j].data[k] = Number(chartData.datasets[j].data[k]); 94 | } 95 | } 96 | 97 | // add chart options 98 | var config = chartConfig[canvas.getAttribute("data-chart")]; 99 | if ( config ) { 100 | for (var j = 0; j < chartData.datasets.length; j++ ){ 101 | for (var attrname in config) { 102 | if ( !chartData.datasets[j][attrname] ) { 103 | chartData.datasets[j][attrname] = config[attrname][j%config[attrname].length]; 104 | } 105 | } 106 | } 107 | } 108 | 109 | canvas.chart = new Chart(ctx, { type: canvas.getAttribute("data-chart"), data: chartData, options: chartOptions }); 110 | 111 | } 112 | 113 | function updateChart(canvas, idx, data) { 114 | canvas.chart.data.datasets[idx].data = data; 115 | recreateChart( canvas ); 116 | } 117 | 118 | var initializeCharts = function(){ 119 | // Get all canvases 120 | var canvases = document.querySelectorAll("canvas"); 121 | for (var i = 0; i < canvases.length; i++ ){ 122 | // check if canvas has data-chart attribute 123 | if ( canvases[i].hasAttribute("data-chart") ){ 124 | var CSV = canvases[i].innerHTML.trim(); 125 | var comments = CSV.match(//g); 126 | CSV = CSV.replace(//g,'').replace(/^\s*\n/gm, "") 127 | if ( ! canvases[i].hasAttribute("data-chart-src") ) { 128 | createChart(canvases[i], CSV, comments); 129 | } 130 | else { 131 | var canvas = canvases[i]; 132 | var xhr = new XMLHttpRequest(); 133 | xhr.onload = function() { 134 | if (xhr.readyState === 4) { 135 | createChart(canvas, xhr.responseText, comments); 136 | } 137 | else { 138 | console.warn( 'Failed to get file ' + canvas.getAttribute("data-chart-src") +". ReadyState: " + xhr.readyState + ", Status: " + xhr.status); 139 | } 140 | }; 141 | 142 | xhr.open( 'GET', canvas.getAttribute("data-chart-src"), false ); 143 | try { 144 | xhr.send(); 145 | } 146 | catch ( error ) { 147 | console.warn( 'Failed to get file ' + canvas.getAttribute("data-chart-src") + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + error ); 148 | } 149 | } 150 | 151 | } 152 | } 153 | } 154 | 155 | function recreateChart(canvas) { 156 | // clear data to redraw animation 157 | var data = canvas.chart.data.datasets; 158 | canvas.chart.data.datasets = []; 159 | canvas.chart.update(); 160 | canvas.style.visibility = "hidden"; 161 | setTimeout( function(canvas, data) { 162 | canvas.chart.data.datasets = data; 163 | canvas.style.visibility = "visible"; 164 | canvas.chart.update(); 165 | }, 500, canvas, data); // wait for slide transition to re-add data and animation 166 | /* 167 | var config = canvas.chart.config; 168 | canvas.chart.destroy(); 169 | setTimeout( function() { canvas.chart = new Chart(canvas, config);}, 500); // wait for slide transition 170 | */ 171 | } 172 | 173 | // check if chart option is given or not 174 | var chartConfig = Reveal.getConfig().chart || {}; 175 | 176 | // set global chart options 177 | var config = chartConfig.defaults; 178 | if ( config ) { 179 | mergeRecursive(Chart.defaults, config); 180 | } 181 | 182 | Reveal.addEventListener('ready', function(){ 183 | initializeCharts(); 184 | Reveal.addEventListener('slidechanged', function(){ 185 | var canvases = Reveal.getCurrentSlide().querySelectorAll("canvas[data-chart]"); 186 | for (var i = 0; i < canvases.length; i++ ){ 187 | if ( canvases[i].chart && canvases[i].chart.config.options.animation !== false ) { 188 | recreateChart( canvases[i] ); 189 | } 190 | } 191 | 192 | }); 193 | }); 194 | 195 | this.update = updateChart; 196 | 197 | return this; 198 | }; 199 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/theme/night.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Black theme for reveal.js. 3 | * 4 | * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se 5 | */ 6 | @import url(https://fonts.googleapis.com/css?family=Montserrat:700); 7 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic); 8 | section.has-light-background, section.has-light-background h1, section.has-light-background h2, section.has-light-background h3, section.has-light-background h4, section.has-light-background h5, section.has-light-background h6 { 9 | color: #222; 10 | } 11 | 12 | /********************************************* 13 | * GLOBAL STYLES 14 | *********************************************/ 15 | :root { 16 | --r-background-color: #111; 17 | --r-main-font: Open Sans, sans-serif; 18 | --r-main-font-size: 40px; 19 | --r-main-color: #eee; 20 | --r-block-margin: 20px; 21 | --r-heading-margin: 0 0 20px 0; 22 | --r-heading-font: Montserrat, Impact, sans-serif; 23 | --r-heading-color: #eee; 24 | --r-heading-line-height: 1.2; 25 | --r-heading-letter-spacing: -0.03em; 26 | --r-heading-text-transform: none; 27 | --r-heading-text-shadow: none; 28 | --r-heading-font-weight: normal; 29 | --r-heading1-text-shadow: none; 30 | --r-heading1-size: 3.77em; 31 | --r-heading2-size: 2.11em; 32 | --r-heading3-size: 1.55em; 33 | --r-heading4-size: 1em; 34 | --r-code-font: monospace; 35 | --r-link-color: #e7ad52; 36 | --r-link-color-dark: #d08a1d; 37 | --r-link-color-hover: #f3d7ac; 38 | --r-selection-background-color: #e7ad52; 39 | --r-selection-color: #fff; 40 | } 41 | 42 | .reveal-viewport { 43 | background: #111; 44 | background-color: var(--r-background-color); 45 | } 46 | 47 | .reveal { 48 | font-family: var(--r-main-font); 49 | font-size: var(--r-main-font-size); 50 | font-weight: normal; 51 | color: var(--r-main-color); 52 | } 53 | 54 | .reveal ::selection { 55 | color: var(--r-selection-color); 56 | background: var(--r-selection-background-color); 57 | text-shadow: none; 58 | } 59 | 60 | .reveal ::-moz-selection { 61 | color: var(--r-selection-color); 62 | background: var(--r-selection-background-color); 63 | text-shadow: none; 64 | } 65 | 66 | .reveal .slides section, 67 | .reveal .slides section > section { 68 | line-height: 1.3; 69 | font-weight: inherit; 70 | } 71 | 72 | /********************************************* 73 | * HEADERS 74 | *********************************************/ 75 | .reveal h1, 76 | .reveal h2, 77 | .reveal h3, 78 | .reveal h4, 79 | .reveal h5, 80 | .reveal h6 { 81 | margin: var(--r-heading-margin); 82 | color: var(--r-heading-color); 83 | font-family: var(--r-heading-font); 84 | font-weight: var(--r-heading-font-weight); 85 | line-height: var(--r-heading-line-height); 86 | letter-spacing: var(--r-heading-letter-spacing); 87 | text-transform: var(--r-heading-text-transform); 88 | text-shadow: var(--r-heading-text-shadow); 89 | word-wrap: break-word; 90 | } 91 | 92 | .reveal h1 { 93 | font-size: var(--r-heading1-size); 94 | } 95 | 96 | .reveal h2 { 97 | font-size: var(--r-heading2-size); 98 | } 99 | 100 | .reveal h3 { 101 | font-size: var(--r-heading3-size); 102 | } 103 | 104 | .reveal h4 { 105 | font-size: var(--r-heading4-size); 106 | } 107 | 108 | .reveal h1 { 109 | text-shadow: var(--r-heading1-text-shadow); 110 | } 111 | 112 | /********************************************* 113 | * OTHER 114 | *********************************************/ 115 | .reveal p { 116 | margin: var(--r-block-margin) 0; 117 | line-height: 1.3; 118 | } 119 | 120 | /* Remove trailing margins after titles */ 121 | .reveal h1:last-child, 122 | .reveal h2:last-child, 123 | .reveal h3:last-child, 124 | .reveal h4:last-child, 125 | .reveal h5:last-child, 126 | .reveal h6:last-child { 127 | margin-bottom: 0; 128 | } 129 | 130 | /* Ensure certain elements are never larger than the slide itself */ 131 | .reveal img, 132 | .reveal video, 133 | .reveal iframe { 134 | max-width: 95%; 135 | max-height: 95%; 136 | } 137 | 138 | .reveal strong, 139 | .reveal b { 140 | font-weight: bold; 141 | } 142 | 143 | .reveal em { 144 | font-style: italic; 145 | } 146 | 147 | .reveal ol, 148 | .reveal dl, 149 | .reveal ul { 150 | display: inline-block; 151 | text-align: left; 152 | margin: 0 0 0 1em; 153 | } 154 | 155 | .reveal ol { 156 | list-style-type: decimal; 157 | } 158 | 159 | .reveal ul { 160 | list-style-type: disc; 161 | } 162 | 163 | .reveal ul ul { 164 | list-style-type: square; 165 | } 166 | 167 | .reveal ul ul ul { 168 | list-style-type: circle; 169 | } 170 | 171 | .reveal ul ul, 172 | .reveal ul ol, 173 | .reveal ol ol, 174 | .reveal ol ul { 175 | display: block; 176 | margin-left: 40px; 177 | } 178 | 179 | .reveal dt { 180 | font-weight: bold; 181 | } 182 | 183 | .reveal dd { 184 | margin-left: 40px; 185 | } 186 | 187 | .reveal blockquote { 188 | display: block; 189 | position: relative; 190 | width: 70%; 191 | margin: var(--r-block-margin) auto; 192 | padding: 5px; 193 | font-style: italic; 194 | background: rgba(255, 255, 255, 0.05); 195 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); 196 | } 197 | 198 | .reveal blockquote p:first-child, 199 | .reveal blockquote p:last-child { 200 | display: inline-block; 201 | } 202 | 203 | .reveal q { 204 | font-style: italic; 205 | } 206 | 207 | .reveal pre { 208 | display: block; 209 | position: relative; 210 | width: 90%; 211 | margin: var(--r-block-margin) auto; 212 | text-align: left; 213 | font-size: 0.55em; 214 | font-family: var(--r-code-font); 215 | line-height: 1.2em; 216 | word-wrap: break-word; 217 | box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15); 218 | } 219 | 220 | .reveal code { 221 | font-family: var(--r-code-font); 222 | text-transform: none; 223 | tab-size: 2; 224 | } 225 | 226 | .reveal pre code { 227 | display: block; 228 | padding: 5px; 229 | overflow: auto; 230 | max-height: 400px; 231 | word-wrap: normal; 232 | } 233 | 234 | .reveal .code-wrapper { 235 | white-space: normal; 236 | } 237 | 238 | .reveal .code-wrapper code { 239 | white-space: pre; 240 | } 241 | 242 | .reveal table { 243 | margin: auto; 244 | border-collapse: collapse; 245 | border-spacing: 0; 246 | } 247 | 248 | .reveal table th { 249 | font-weight: bold; 250 | } 251 | 252 | .reveal table th, 253 | .reveal table td { 254 | text-align: left; 255 | padding: 0.2em 0.5em 0.2em 0.5em; 256 | border-bottom: 1px solid; 257 | } 258 | 259 | .reveal table th[align=center], 260 | .reveal table td[align=center] { 261 | text-align: center; 262 | } 263 | 264 | .reveal table th[align=right], 265 | .reveal table td[align=right] { 266 | text-align: right; 267 | } 268 | 269 | .reveal table tbody tr:last-child th, 270 | .reveal table tbody tr:last-child td { 271 | border-bottom: none; 272 | } 273 | 274 | .reveal sup { 275 | vertical-align: super; 276 | font-size: smaller; 277 | } 278 | 279 | .reveal sub { 280 | vertical-align: sub; 281 | font-size: smaller; 282 | } 283 | 284 | .reveal small { 285 | display: inline-block; 286 | font-size: 0.6em; 287 | line-height: 1.2em; 288 | vertical-align: top; 289 | } 290 | 291 | .reveal small * { 292 | vertical-align: top; 293 | } 294 | 295 | .reveal img { 296 | margin: var(--r-block-margin) 0; 297 | } 298 | 299 | /********************************************* 300 | * LINKS 301 | *********************************************/ 302 | .reveal a { 303 | color: var(--r-link-color); 304 | text-decoration: none; 305 | transition: color 0.15s ease; 306 | } 307 | 308 | .reveal a:hover { 309 | color: var(--r-link-color-hover); 310 | text-shadow: none; 311 | border: none; 312 | } 313 | 314 | .reveal .roll span:after { 315 | color: #fff; 316 | background: var(--r-link-color-dark); 317 | } 318 | 319 | /********************************************* 320 | * Frame helper 321 | *********************************************/ 322 | .reveal .r-frame { 323 | border: 4px solid var(--r-main-color); 324 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); 325 | } 326 | 327 | .reveal a .r-frame { 328 | transition: all 0.15s linear; 329 | } 330 | 331 | .reveal a:hover .r-frame { 332 | border-color: var(--r-link-color); 333 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); 334 | } 335 | 336 | /********************************************* 337 | * NAVIGATION CONTROLS 338 | *********************************************/ 339 | .reveal .controls { 340 | color: var(--r-link-color); 341 | } 342 | 343 | /********************************************* 344 | * PROGRESS BAR 345 | *********************************************/ 346 | .reveal .progress { 347 | background: rgba(0, 0, 0, 0.2); 348 | color: var(--r-link-color); 349 | } 350 | 351 | /********************************************* 352 | * PRINT BACKGROUND 353 | *********************************************/ 354 | @media print { 355 | .backgrounds { 356 | background-color: var(--r-background-color); 357 | } 358 | } -------------------------------------------------------------------------------- /apresentacao/slides.md: -------------------------------------------------------------------------------- 1 | --- 2 | theme: "night" 3 | transition: "slide" 4 | title: "Configuração de projetos" 5 | enableMenu: false 6 | enableSearch: false 7 | enableChalkboard: false 8 | highlightTheme: "monokai" 9 | progressBar: true 10 | --- 11 | 12 | ## Boas vindas 13 | 14 | -- 15 | 16 | ## Muito obrigado pela presença! 17 | 18 | ![tks](https://media0.giphy.com/media/Tk1RH495RjYYM/giphy.gif) 19 | 20 | -- 21 | 22 | ### O que vamos abordar? 23 | 24 | ![pensando](https://gifburg.com/images/gifs/thinking/gifs/0002.gif){width=70%} 25 | 26 | -- 27 | 28 | ### O que vamos abordar? 29 | 30 | - VsCode config 31 | - Commits 32 | - ESLint 33 | - Github Actions 34 | - Docker 35 | 36 | --- 37 | 38 | ### Antes de tudo, quem sou eu? 39 | 40 | -- 41 | 42 | ### Eu sou ... 43 | 44 | - Thiago Mariotto 45 | - 25 Anos 46 | - Ciência da computação 47 | - Instrutor Backend Trybe 48 | 49 | --- 50 | 51 | ### Porque esse tema é importante? 52 | 53 | > É importante termos uma base sólida e estruturada para desenvolvermos nossa aplicação, definindo as configurações iniciais, é mais fácil compartilhar o código e evitar problemas futuros. 54 | 55 | --- 56 | 57 | ### Configurações do Visual Studio Code 58 | 59 | > Pergunta: O que vem na sua cabeça com esse título? 60 | 61 | -- 62 | 63 | ### Configurações do Visual Studio Code 64 | 65 | > Você sabia que é possível compartilhar suas configurações de projeto do VsCode com outras pessoas? 66 | 67 | -- 68 | 69 | ### Configurações do Visual Studio Code 70 | 71 | > É importante pois, caso uma pessoa venha, por exemplo, realizar um Code Review, ela trabalhe em cima das mesmas regras que você definiu. 72 | 73 | -- 74 | 75 | ### Configurações do Visual Studio Code 76 | 77 | > Como fazemos isso? 78 | 79 | -- 80 | 81 | ### Configurações do Visual Studio Code 82 | ```json 83 | { 84 | "editor.formatOnPaste": true, 85 | "editor.formatOnSave": true, 86 | "editor.formatOnSaveMode": true, 87 | "editor.formatOnType": true, 88 | "editor.tabSize": 2, 89 | "editor.codeActionsOnSave": { 90 | "source.fixAll": true, 91 | "source.organizeImports": true 92 | // ... 93 | } 94 | 95 | } 96 | ``` 97 | 98 | -- 99 | 100 | ### Configurações do Visual Studio Code 101 | 102 | - dessa forma podemos compartilhar nossas configurações de ambiente de projeto com outras pessoas. 103 | - o arquivo sobrepõe suas configurações locais. 104 | 105 | --- 106 | 107 | ### Commits 108 | 109 | ![](https://media0.giphy.com/media/487L0pNZKONFN01oHO/giphy.gif){width=40%} 110 | 111 | -- 112 | 113 | ## Padronização de commits 114 | 115 | - Commitlint 116 | - Husky 117 | - Commitizen 118 | 119 | -- 120 | 121 | ### Commits Atômicos 122 | 123 | -- 124 | 125 | ### Commits Atômicos 126 | 127 | - Submeta pequenas alterações que foram realizadas em seu código. 128 | 129 | -- 130 | 131 | ### Commits Atômicos 132 | 133 | - Seus commits devem contar uma história, a história de desenvolvimento do seu projeto; 134 | 135 | -- 136 | 137 | ### Commits Atômicos 138 | 139 | - Nada de commit bomba. 140 | 141 | -- 142 | 143 | ### Conventional Commits 144 | 145 | [Documentação](https://www.conventionalcommits.org/en/v1.0.0/) 146 | 147 | > Ele fornece um conjunto fácil de regras para criar um histórico de commit explícito descrevendo os recursos, correções e alterações feitas nas mensagens de commit. 148 | 149 | -- 150 | 151 | ### Conventional Commits 152 | 153 | ```sh 154 | $ git commit -m "feat: insert validation user register" 155 | 156 | $ git commit -m "fix: remove typo user validation register" 157 | ``` 158 | 159 | -- 160 | 161 | ### Commitlint 162 | 163 | [Documentação](https://commitlint.js.org/#/guides-local-setup) 164 | 165 | > Podemos Definir que utilizaremos o Conventional Commits, mas nada garante que vamos respeitar ou lembrar as regras em todos os commits. 166 | 167 | -- 168 | 169 | ### Commitlint 170 | 171 | > Com ele conseguimos verificar se a mensagem de commit está dentro dos padrões definidos (Linter dos commits). 172 | 173 | -- 174 | 175 | ## Commitizen 176 | 177 | [Documentação](http://commitizen.github.io/cz-cli/) 178 | 179 | > O Commitizen é uma biblioteca que vai nos ajudar a criar os commits seguindo o padrão do Conventional Commit. Ela gera uma interface no terminal e assim vamos conseguir acessar todos os tipos de commits e suas descrições. 180 | 181 | -- 182 | 183 | ### Husky 184 | 185 | [Documentação](https://typicode.github.io/husky/#/) 186 | 187 | > É possível criar gatilhos em determinadas ações, utilizaremos o Husky para disparar uma ação antes de um commit para executar o commitizen e verificar se a mensagem do commit está seguindo o padrão definido. 188 | 189 | -- 190 | 191 | ### Colocando tudo isso em prática 192 | 193 | ![](https://i.pinimg.com/originals/2a/69/13/2a6913ecabc0b8449c741a6686cae8fa.gif) 194 | 195 | -- 196 | 197 | ### Iniciando Commitlint 198 | 199 | ```sh 200 | $ npm init -y 201 | $ git init 202 | 203 | # install commit lint 204 | $ npm install --save-dev @commitlint/cli 205 | $ npm install --save-dev @commitlint/config-conventional 206 | 207 | # atomic commit 208 | $ git add package.json 209 | $ git commit -m "feat: add commit lint lib" 210 | 211 | # Configure commitlint to use conventional config 212 | $ echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js 213 | 214 | ``` 215 | 216 | -- 217 | 218 | ### Testando commitlint 219 | 220 | ```sh 221 | # Para testar a biblioteca 222 | echo "teste" | npx commitlint # deve apontar um erro 223 | 224 | echo "feat: teste" | npx commitlint # deve funcionar corretamente 225 | ``` 226 | 227 | -- 228 | 229 | ### Iniciando Husky 230 | 231 | ```sh 232 | # instalando a lib 233 | $ npm install husky -D 234 | 235 | # atomic commit 236 | $ git add package.json 237 | $ git commit -m "feat: add husky lib" 238 | 239 | # ativando os hooks (gatilhos) 240 | $ npx husky install 241 | 242 | # Add hook que vai disparar o commitlint 243 | $ npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1' 244 | 245 | ``` 246 | 247 | -- 248 | 249 | ### Iniciando Husky 250 | 251 | ```json 252 | // para ativar os hooks automaticamente após instalação 253 | "scripts": { 254 | "prepare": "husky install" 255 | } 256 | 257 | // caso o script não seja adicionado ao package.json, toda vez 258 | // que um clone for realizado é necessário realizar 259 | // `$ npx husky install` 260 | ``` 261 | 262 | -- 263 | 264 | ### Realizando um commit 265 | 266 | ```sh 267 | $ echo "node_modules/" > .gitignore 268 | 269 | $ git status 270 | $ git add .gitignore 271 | $ git commit -m "qualquer coisa" 272 | $ git commit -m "chore: add gitignore" 273 | ``` 274 | 275 | -- 276 | 277 | ### Adicionando o Commitizen 278 | 279 | ```sh 280 | $ npm i commitizen -D 281 | $ npx commitizen init cz-conventional-changelog --save-dev --save-exact 282 | 283 | $ echo "console.log(1);" > index.js 284 | $ git add index.js 285 | 286 | "scripts": { 287 | "commit": "cz" 288 | } 289 | 290 | $ npm run commit 291 | ``` 292 | 293 | -- 294 | 295 | ### Utilizando o Commitizen 296 | 297 | 1. Selecione o tipo de mudança que você está realizando 298 | 2. Qual é o escopo desta mudança (por exemplo, componente ou nome do arquivo) 299 | 3. Escreva uma descrição breve e imperativa da mudança (máx. 82 caracteres): 300 | 301 | -- 302 | 303 | ### Utilizando o Commitizen 304 | 305 | 4. Forneça uma descrição mais longa da mudança: 306 | 5. Existem alterações importantes (importante saber sobre `Semantic Versioning`) 307 | 6. Essa mudança afeta algum problema em aberto? (Issues) 308 | 309 | --- 310 | 311 | ## ESLint 312 | 313 | ![](https://c.tenor.com/dNAEMPMv2YMAAAAC/ei-nerd-nao-errado.gif) 314 | 315 | -- 316 | 317 | ## O que é o ESLint? 318 | 319 | > Analisa seu código estaticamente para encontrar problemas. Você pode executar o ESLint como parte de seu pipeline de integração contínua (CI). Os problemas encontrados pelo ESLint podem ser corrigidos automaticamente. 320 | 321 | -- 322 | 323 | ### Iniciando ESLint Backend 324 | 325 | ```sh 326 | $ mkdir backend && cd backend 327 | $ mv ../index.js backend 328 | 329 | $ npm init -y 330 | $ npm install eslint -D 331 | $ npx eslint --init 332 | 333 | $ git add [...] 334 | $ npm run commit 335 | ``` 336 | 337 | -- 338 | 339 | ### Executando eslint 340 | 341 | ```json 342 | "lint": "eslint --no-inline-config --no-error-on-unmatched-pattern -c .eslintrc.json ." 343 | 344 | $ npm run lint 345 | ``` 346 | 347 | -- 348 | 349 | ### Github Actions 350 | 351 | [Documentação](https://github.com/features/actions) 352 | 353 | ![](https://media.giphy.com/media/XCxcmEQWxDdc8qsd2R/giphy.gif) 354 | 355 | -- 356 | 357 | ### Github Actions 358 | 359 | > O GitHub Actions facilita a automatização de todos os seus fluxos de trabalho de software. Crie, teste e implante seu código diretamente do GitHub. 360 | 361 | -- 362 | 363 | ### Github Actions - Continuous Integration 364 | 365 | - Uma CI é realizada com sucesso quando novas mudanças no código são desenvolvidas, testadas e consolidadas em um repositório, por exemplo, a correção de um bug ou o deploy de uma feature nova. 366 | 367 | -- 368 | 369 | ### Github Action + ESLint 370 | 371 | > Vamos criar uma Action para que, todas as vezes que um PR for aberto ou um push for realizado, o ESLint execute todos os testes em nosso código. 372 | 373 | -- 374 | 375 | ### Por onde começamos? 376 | 377 | ![](https://c.tenor.com/ydJSf1AnEJMAAAAC/where-looking-for.gif) 378 | 379 | -- 380 | 381 | ### Configurando minhas Actions 382 | 383 | -- 384 | 385 | ### Configurando minhas Actions 386 | 387 | ```sh 388 | # vamos voltar para a raiz do projeto ./ 389 | $ mkdir .github/workflows/main.yml 390 | ``` 391 | 392 | -- 393 | 394 | ### Configurando minhas Actions 395 | 396 | ```yml 397 | on: 398 | pull_request: 399 | types: [opened, synchronize] 400 | 401 | jobs: 402 | eslint: 403 | runs-on: ubuntu-latest 404 | steps: 405 | - uses: actions/checkout@v2 406 | 407 | - uses: actions/setup-node@v2 408 | with: 409 | node-version: 14 410 | 411 | - name: Install back-end modules 412 | run: npm i --prefix backend 413 | 414 | - name: Run linter on back-end 415 | run: npm run lint --prefix backend 416 | ``` 417 | 418 | -- 419 | 420 | ### Testando uma action 421 | 422 | > Para isso é necessário realizar um Pull Request em um repositório. 423 | 424 | --- 425 | 426 | ### Docker 427 | 428 | ![](https://miro.medium.com/max/1400/0*bRvhcFgijNKRVD9L.gif){width=70%} 429 | 430 | -- 431 | 432 | ### Docker 433 | 434 | > Não basta só compartilharmos nossas configurações de trabalho. 435 | 436 | -- 437 | 438 | ### Docker 439 | 440 | > Podemos compartilhar nosso código pronto para ser executado, testado ou modificado, mas como? 441 | 442 | -- 443 | 444 | ### "Dockerizando" sua aplicação 445 | 446 | ![](https://i.pinimg.com/originals/92/33/40/923340f1c1385970b953ad2a88be83fb.gif) 447 | 448 | -- 449 | 450 | ## Dockerizando sua aplicação 451 | 452 | > Fornecendo toda a estrutura base do projeto para que qualquer pessoa consiga executa-lo em sua máquina, continuando o desenvolvimento ou realizando testes. 453 | 454 | -- 455 | 456 | ### Case 457 | 458 | > Pense o seguinte caso: você está participando de um processo seletivo em que precisa construir uma aplicação simulando uma loja de vendas de sapatos. 459 | 460 | -- 461 | 462 | ### Case 463 | 464 | > É bem provável que você irá desenvolver um CRUD de vendas e ou estoque. 465 | 466 | -- 467 | 468 | ### Case 469 | 470 | > Para desenvolver, você seleciona 3 ferramentas: Node, React e MySQL. 471 | 472 | -- 473 | 474 | ### Case 475 | 476 | > Após finalizado, como ficaria sua aplicação para ser enviada a pessoa avaliadora? Conte-me ... 477 | 478 | -- 479 | 480 | ### Case 481 | 482 | > Agora, imagine que: a pessoa que irá testar sua aplicação trabalha com Python, não possuí node e nem MySQL instalado na máquina :/ 483 | 484 | -- 485 | 486 | > Ela vai ter um trabalhão não é mesmo? 487 | 488 | -- 489 | 490 | ## Mão ~~na massa~~ no teclado 491 | 492 | ![](https://i.pinimg.com/originals/9d/f1/38/9df13818441fc507a42a5e50c082f062.gif) 493 | 494 | -- 495 | 496 | ### Utilizando Docker 497 | 498 | > Vamos trabalhar com um exemplo parecido 499 | 500 | -- 501 | 502 | ### Utilizando Docker 503 | 504 | > Vamos imaginar que estamos desenvolvendo uma aplicação completa (front e back), utilizando as seguintes ferramentas: 505 | 506 | -- 507 | 508 | ### Nossas ferramentas 509 | 510 | - API com Node rodando na versão 12.22; 511 | - Aplicação WEB com REACT e node na versão 12.22; 512 | - Banco de dados MySQL na versão 5.7; 513 | 514 | -- 515 | 516 | ### Colocando em prática 517 | 518 | 1. Criar o Dockerfile do Backend 519 | 2. Criar o Dockerfile do Frontend 520 | 3. Criar o Docker Compose 521 | 1. Serviço do Back utilizando o Dockerfile 522 | 2. Serviço do Front utilizando o Dockerfile 523 | 3. Serviço MySQL sendo populado com um banco de dados 524 | 525 | -- 526 | 527 | ### Colocando em prática 528 | 529 | > Ponto de atenção: o container do Frontend é dependente do container do Backend e o Backend por sua vez é dependente do MySQL. 530 | 531 | -- 532 | 533 | ## Let's Code 534 | 535 | -- 536 | 537 | ### Dockerfile Frontend 538 | 539 | ```yml 540 | FROM node:12.22-alpine 541 | 542 | 543 | WORKDIR /app 544 | 545 | COPY package*.json ./ 546 | 547 | RUN npm install 548 | 549 | RUN chmod 777 node_modules 550 | 551 | COPY . . 552 | 553 | EXPOSE 3000 554 | 555 | CMD ["npm", "start"] 556 | ``` 557 | 558 | -- 559 | 560 | ### Dockerfile Backend 561 | 562 | ```yml 563 | FROM node:12.22-alpine 564 | 565 | WORKDIR /app 566 | 567 | COPY package*.json ./ 568 | 569 | RUN npm install 570 | 571 | RUN chmod 777 node_modules 572 | 573 | COPY . . 574 | 575 | EXPOSE 3333 576 | 577 | CMD ["npm", "start"] 578 | ``` 579 | 580 | -- 581 | 582 | ### Docker compose 583 | 584 | ```yml 585 | version: '3.1' 586 | 587 | services: 588 | database: 589 | image: mysql:5.7 590 | restart: always 591 | container_name: mysql_compose 592 | ports: 593 | - 3306:3306 594 | environment: 595 | - MYSQL_ROOT_PASSWORD=docker 596 | volumes: 597 | - ./backend/database/mysql-seeder:/docker-entrypoint-initdb.d 598 | 599 | api: 600 | build: ./backend 601 | container_name: backend_compose 602 | ports: 603 | - 3333:3333 604 | depends_on: 605 | - database 606 | volumes: 607 | - /app/node_modules 608 | - ./backend:/app 609 | 610 | web: 611 | build: ./frontend 612 | container_name: frontend_compose 613 | ports: 614 | - 3000:3000 615 | volumes: 616 | - /app/node_modules 617 | - ./frontend:/app 618 | depends_on: 619 | - api 620 | ``` 621 | 622 | 623 | -- 624 | 625 | > Agora nossa pessoa avaliadora poderá testar nosso código executando somente um comando. 626 | 627 | --- -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/plugin/animate/plugin.js: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | ** Author: Asvin Goel, goel@telematique.eu 3 | ** 4 | ** A plugin for animating slide content. 5 | ** 6 | ** Version: 0.1.0 7 | ** 8 | ** License: MIT license (see LICENSE.md) 9 | ** 10 | ******************************************************************/ 11 | 12 | window.RevealAnimate = window.RevealAnimate || { 13 | id: 'RevealAnimate', 14 | init: function(deck) { 15 | initAnimate(deck); 16 | }, 17 | play: function() { play(); }, 18 | pause: function() { pause(); }, 19 | seek: function(timestamp) { seek(timestamp); }, 20 | }; 21 | 22 | const initAnimate = function(Reveal){ 23 | var config = Reveal.getConfig().animate || {}; 24 | var autoplay = config.autoplay; 25 | 26 | var playback = false; 27 | var isRecording = false; 28 | var timer = null; 29 | var initialized = 0; 30 | 31 | function parseJSON(str) { 32 | str = str.replace(/(\r\n|\n|\r|\t)/gm,""); // remove line breaks and tabs 33 | var json; 34 | try { 35 | json = JSON.parse(str, function (key, value) { 36 | if (value && (typeof value === 'string') && value.indexOf("function") === 0) { 37 | // we can only pass a function as string in JSON ==> doing a real function 38 | // eval("var jsFunc = " + value); 39 | var jsFunc = new Function('return ' + value)(); 40 | return jsFunc; 41 | } 42 | return value; 43 | }); 44 | } catch (e) { 45 | return null; 46 | } 47 | return json; 48 | } 49 | 50 | function load( element, config, filename, callback ) { 51 | var xhr = new XMLHttpRequest(); 52 | xhr.onload = function() { 53 | if (xhr.readyState === 4) { 54 | callback( element, config, xhr.responseText ); 55 | } 56 | else { 57 | callback( "Failed to get file. ReadyState: " + xhr.readyState + ", Status: " + xhr.status ); 58 | } 59 | }; 60 | xhr.open( 'GET', filename, true ); 61 | xhr.send(); 62 | } 63 | 64 | function parseComments( element ) { 65 | var config = {}; 66 | var comments = element.innerHTML.trim().match(//g); 67 | //console.log(comments) 68 | if ( comments !== null ) for (var k = 0; k < comments.length; k++ ){ 69 | comments[k] = comments[k].replace(//,''); 71 | var config = parseJSON(comments[k]); 72 | //console.warn(comments[k], config); 73 | 74 | if ( config ) { 75 | if ( config.animation && Array.isArray(config.animation) && config.animation.length && !Array.isArray(config.animation[0]) ) { 76 | // without fragments the animation can be specified as a single array (animation steps) 77 | config.animation = [ config.animation ]; 78 | } 79 | break; 80 | } 81 | } 82 | 83 | //console.warn(element, config); 84 | return config; 85 | } 86 | 87 | function getAnimatedSVG( container ) { 88 | var elements = SVG.find('svg'); 89 | var svg = elements.toArray().find(element => element.node.parentElement == container); 90 | //console.warn("FOUND",svg.node); 91 | return svg; 92 | } 93 | 94 | /***************************************************************** 95 | ** Set up animations 96 | ******************************************************************/ 97 | function setupAnimations( container, config ) { 98 | //console.warn("setupAnimations"); 99 | if ( !config ) return; 100 | 101 | container.svg = getAnimatedSVG( container ); 102 | 103 | // pre-animation setup 104 | var setup = config.setup; 105 | if ( setup ) { 106 | for (var i = 0; i < setup.length; i++ ){ 107 | try { 108 | if ( setup[i].element ) { 109 | //console.log(setup[i].element,setup[i].modifier,setup[i].parameters); 110 | var elements = container.svg.find(setup[i].element); 111 | if ( !elements.length ) { 112 | console.warn("Cannot find element to set up with selector: " + setup[i].element + "!"); 113 | } 114 | 115 | //console.warn(elements); 116 | //console.log("element(" + setup[i].element + ")." + setup[i].modifier + "(" + setup[i].parameters + ")"); 117 | //console.log("element(" + setup[i].element + ")." + setup[i].modifier + "(" + setup[i].parameters + ")"); 118 | for (var j = 0; j < elements.length; j++ ){ 119 | if ( typeof setup[i].modifier === "function" ) { 120 | // if modifier is function execute it 121 | setup[i].modifier.apply(elements[j],setup[i].parameters); 122 | } 123 | else { 124 | // apply modifier to element 125 | elements[j][setup[i].modifier].apply(elements[j],setup[i].parameters); 126 | } 127 | } 128 | 129 | } 130 | else { 131 | // no element is provided 132 | if ( typeof setup[i].modifier === "function" ) { 133 | // if modifier is function execute it 134 | setup[i].modifier.apply(container.svg,setup[i].parameters); 135 | } 136 | else { 137 | // apply modifier to root 138 | container.svg[setup[i].modifier].apply(container.svg,setup[i].parameters); 139 | } 140 | } 141 | } 142 | catch( error ) { 143 | console.error("Error '" + error + "' setting up element " + JSON.stringify(setup[i])); 144 | } 145 | } 146 | //console.warn(container.svg.node.getAttribute("style")); 147 | } 148 | 149 | container.animation = new SVG.Timeline().persist(true); 150 | container.animationSchedule = []; // completion time of each fragment animation 151 | 152 | // setup animation 153 | var animations = config.animation; 154 | if ( animations ) { 155 | 156 | container.animationSchedule.length = animations.length; 157 | var timestamp = 0; 158 | for (var fragment = 0; fragment < animations.length; fragment++ ){ 159 | container.animationSchedule[fragment] = {}; 160 | container.animationSchedule[fragment].begin = timestamp; 161 | for (var i = 0; i < animations[fragment].length; i++ ){ 162 | try { 163 | // add each animation step 164 | var elements = container.svg.find(animations[fragment][i].element); 165 | //console.log("element(" + animations[fragment][i].element + ")." + animations[fragment][i].modifier + "(" + animations[fragment][i].parameters + ")"); 166 | if ( !elements.length ) { 167 | console.warn("Cannot find element to animate with selector: " + animations[fragment][i].element + "!"); 168 | } 169 | for (var j = 0; j < elements.length; j++ ){ 170 | elements[j].timeline( container.animation ); 171 | var anim = elements[j].animate(animations[fragment][i].duration,animations[fragment][i].delay,animations[fragment][i].when) 172 | anim[animations[fragment][i].modifier].apply(anim,animations[fragment][i].parameters); 173 | } 174 | 175 | //console.log("Duration:", anim.duration()); 176 | timestamp = anim.duration(); 177 | } 178 | catch( error ) { 179 | console.error("Error '" + error + "' setting up animation " + JSON.stringify(animations[fragment][i])); 180 | } 181 | } 182 | // set animationSchedule for each fragment animation 183 | var schedule = container.animation.schedule(); 184 | if ( schedule.length ) { 185 | timestamp = schedule[schedule.length-1].end; 186 | } 187 | container.animationSchedule[fragment].end = timestamp; 188 | } 189 | container.animation.stop(); 190 | //console.warn(container.animation.schedule()); 191 | // console.warn("Schedule", container.animationSchedule); 192 | } 193 | 194 | // setup current slide 195 | if ( Reveal.getCurrentSlide().contains( container ) ) { 196 | Reveal.layout(); // Update layout to account for svg size 197 | animateSlide(0); 198 | } 199 | 200 | initialized += 1; 201 | } 202 | 203 | function initialize() { 204 | //console.log("Initialize animations"); 205 | // Get all animations 206 | var elements = document.querySelectorAll("[data-animate]"); 207 | for (var i = 0; i < elements.length; i++ ){ 208 | var config = parseComments( elements[i] ); 209 | var src = elements[i].getAttribute("data-src"); 210 | if ( src ) { 211 | var element = elements[i]; 212 | load( elements[i], config, src, function( element, config, response ) { 213 | if ( printMode ) { 214 | // do not load svg multiple times 215 | element.removeAttribute("data-src") 216 | } 217 | element.innerHTML = response + element.innerHTML; 218 | setupAnimations( element, config ); 219 | }); 220 | } 221 | else { 222 | setupAnimations( elements[i], config ); 223 | } 224 | } 225 | } 226 | 227 | 228 | function play() { 229 | //console.log("Play",Reveal.getCurrentSlide()); 230 | var elements = Reveal.getCurrentSlide().querySelectorAll("[data-animate]"); 231 | for (var i = 0; i < elements.length; i++ ){ 232 | //console.warn("Play",elements[i]); 233 | if ( elements[i].animation ) { 234 | elements[i].animation.play(); 235 | } 236 | } 237 | autoPause(); 238 | } 239 | 240 | function pause() { 241 | //console.log("Pause"); 242 | if ( timer ) { clearTimeout( timer ); timer = null; } 243 | 244 | var elements = Reveal.getCurrentSlide().querySelectorAll("[data-animate]"); 245 | for (var i = 0; i < elements.length; i++ ){ 246 | if ( elements[i].animation ) { 247 | elements[i].animation.pause(); 248 | } 249 | } 250 | } 251 | 252 | function autoPause() { 253 | 254 | if ( timer ) { clearTimeout( timer ); timer = null; } 255 | var fragment = Reveal.getIndices().f + 1 || 0; // in reveal.js fragments start with index 0, here with index 1 256 | 257 | 258 | 259 | var elements = Reveal.getCurrentSlide().querySelectorAll("[data-animate]"); 260 | 261 | for (var i = 0; i < elements.length; i++ ){ 262 | if ( elements[i].animation && elements[i].animationSchedule[fragment] ) { 263 | //console.log( elements[i].animationSchedule[fragment].end, elements[i].animation.time()); 264 | var timeout = elements[i].animationSchedule[fragment].end - elements[i].animation.time(); 265 | timer = setTimeout(pause,timeout); 266 | } 267 | //console.log("Auto pause",elements[i], timeout); 268 | } 269 | 270 | } 271 | 272 | function seek( timestamp ) { 273 | //console.log("Seek", timestamp); 274 | var elements = Reveal.getCurrentSlide().querySelectorAll("[data-animate]"); 275 | var fragment = Reveal.getIndices().f + 1 || 0; // in reveal.js fragments start with index 0, here with index 1 276 | for (var i = 0; i < elements.length; i++ ){ 277 | //console.log("Seek",timestamp,elements[i].animationSchedule[fragment].begin + (timestamp || 0) ); 278 | if ( elements[i].animation && elements[i].animationSchedule[fragment] ) { 279 | elements[i].animation.time( elements[i].animationSchedule[fragment].begin + (timestamp || 0) ); 280 | } 281 | } 282 | if ( timer ) { 283 | // update time if animation is running 284 | autoPause(); 285 | } 286 | } 287 | 288 | 289 | // Control animation 290 | function animateSlide( timestamp ) { 291 | // pause(); 292 | //console.log("Animate slide", timestamp); 293 | if ( timestamp !== undefined ) { 294 | seek( timestamp); 295 | } 296 | if ( Reveal.isAutoSliding() || autoplay || playback || isRecording ) { 297 | //console.log("Start animation"); 298 | play(); 299 | } 300 | else { 301 | pause(); 302 | } 303 | //console.log("Done"); 304 | } 305 | 306 | /***************************************************************** 307 | ** Print 308 | ******************************************************************/ 309 | var printMode = ( /print-pdf/gi ).test( window.location.search ); 310 | //console.log("createPrintout" + printMode) 311 | 312 | function initializePrint( ) { 313 | //return; 314 | //console.log("initializePrint", document.querySelectorAll(".pdf-page").length); 315 | if ( !document.querySelectorAll(".pdf-page").length ) { 316 | // wait for pdf pages to be created 317 | setTimeout( initializePrint, 500 ); 318 | return; 319 | } 320 | initialize(); 321 | createPrintout(); 322 | } 323 | 324 | function createPrintout( ) { 325 | //console.log("createPrintout", document.querySelectorAll(".pdf-page").length, document.querySelectorAll("[data-animate]").length ); 326 | if ( initialized < document.querySelectorAll("[data-animate]").length ) { 327 | //console.log("wait"); 328 | // wait for animations to be loaded 329 | setTimeout( createPrintout, 500 ); 330 | return; 331 | } 332 | var pages = document.querySelectorAll(".pdf-page"); 333 | for ( var i = 0; i < pages.length; i++ ) { 334 | var fragment = -1; 335 | var current = pages[i].querySelectorAll(".current-fragment"); 336 | for ( var j = 0; j < current.length; j++ ) { 337 | if ( Number(current[j].getAttribute("data-fragment-index")) > fragment ) { 338 | fragment = Number(current[j].getAttribute("data-fragment-index") ); 339 | } 340 | } 341 | fragment += 1; 342 | var elements = pages[i].querySelectorAll("[data-animate]"); 343 | for ( var j = 0; j < elements.length; j++ ) { 344 | //console.log(i,fragment, elements[j]); 345 | 346 | if ( elements[j].animation && elements[j].animationSchedule && elements[j].animationSchedule[fragment] ) { 347 | //console.log(i,fragment, elements[j].animationSchedule[fragment].begin); 348 | elements[j].animation.time( elements[j].animationSchedule[fragment].end ); 349 | } 350 | var fragments = elements[j].querySelectorAll("svg > [data-fragment-index]"); 351 | //console.log(i,fragment, elements[j], fragments); 352 | for ( var k = 0; k < fragments.length; k++ ) { 353 | if ( fragments[k].getAttribute("data-fragment-index") < fragment ) { 354 | fragments[k].classList.add("visible"); 355 | } 356 | } 357 | } 358 | } 359 | } 360 | /***************************************************************** 361 | ** Event listeners 362 | ******************************************************************/ 363 | 364 | Reveal.addEventListener( 'ready', function( event ) { 365 | //console.log('ready '); 366 | /* 367 | if ( printMode ) { 368 | initializePrint(); 369 | return; 370 | } 371 | */ 372 | initialize(); 373 | 374 | if ( printMode ) { 375 | initializePrint(); 376 | return; 377 | } 378 | 379 | Reveal.addEventListener('slidechanged', function(){ 380 | //console.log('slidechanged',Reveal.getIndices()); 381 | animateSlide(0); 382 | }); 383 | 384 | Reveal.addEventListener( 'overviewshown', function( event ) { 385 | // pause animation 386 | pause(); 387 | } ); 388 | 389 | /* 390 | Reveal.addEventListener( 'overviewhidden', function( event ) { 391 | } ); 392 | */ 393 | Reveal.addEventListener( 'paused', function( event ) { 394 | //console.log('paused '); 395 | // pause animation 396 | pause(); 397 | } ); 398 | /* 399 | Reveal.addEventListener( 'resumed', function( event ) { 400 | console.log('resumed '); 401 | // resume animation 402 | } ); 403 | */ 404 | Reveal.addEventListener( 'fragmentshown', function( event ) { 405 | //console.log("fragmentshown",event); 406 | animateSlide(0); 407 | } ); 408 | 409 | Reveal.addEventListener( 'fragmenthidden', function( event ) { 410 | //console.log("fragmentshown",event); 411 | animateSlide(0); 412 | } ); 413 | } ); 414 | 415 | 416 | /***************************************************************** 417 | ** Playback 418 | ******************************************************************/ 419 | 420 | document.addEventListener('seekplayback', function( event ) { 421 | //console.log('event seekplayback ' + event.timestamp); 422 | // set animation to event.timestamp 423 | animateSlide(event.timestamp); 424 | }); 425 | 426 | 427 | document.addEventListener('startplayback', function( event ) { 428 | //console.log('event startplayback ' + event.timestamp); 429 | playback = true; 430 | animateSlide(event.timestamp); 431 | }); 432 | 433 | document.addEventListener('stopplayback', function( event ) { 434 | //console.log('event stopplayback ', event); 435 | playback = false; 436 | animateSlide(); 437 | }); 438 | 439 | document.addEventListener('startrecording', function( event ) { 440 | //console.log('event startrecording ' + event.timestamp); 441 | isRecording = true; 442 | animateSlide(0); 443 | }); 444 | 445 | document.addEventListener('stoprecording', function( event ) { 446 | //console.log('event stoprecording ' + event.timestamp); 447 | isRecording = false; 448 | animateSlide(); 449 | }); 450 | 451 | this.play = play; 452 | this.pause = pause; 453 | this.seek = seek; 454 | return this; 455 | }; 456 | 457 | 458 | -------------------------------------------------------------------------------- /apresentacao/export/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Configuração de projetos 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
56 | 57 | 58 |
59 | 60 | 61 | 62 | 63 | 64 |
65 |
66 |

Boas vindas

67 | 68 |
69 | 70 |
71 |

Muito obrigado pela presença!

72 |

tks

73 | 74 |
75 | 76 |
77 |

O que vamos abordar?

78 |

pensando

79 | 80 |
81 | 82 |
83 |

O que vamos abordar?

84 |
    85 |
  • VsCode config
  • 86 |
  • Commits
  • 87 |
  • ESLint
  • 88 |
  • Github Actions
  • 89 |
  • Docker
  • 90 |
91 | 92 |
93 | 94 | 95 |
96 | 97 | 98 | 99 | 100 | 101 |
102 |
103 |

Antes de tudo, quem sou eu?

104 | 105 |
106 | 107 |
108 |

Eu sou …

109 |
    110 |
  • Thiago Mariotto
  • 111 |
  • 25 Anos
  • 112 |
  • Ciência da computação
  • 113 |
  • Instrutor Backend Trybe
  • 114 |
115 | 116 |
117 | 118 | 119 |
120 | 121 | 122 | 123 | 124 | 125 |
126 | 127 |

Porque esse tema é importante?

128 |
129 |

É importante termos uma base sólida e estruturada para desenvolvermos nossa aplicação, definindo as configurações iniciais, é mais fácil compartilhar o código e evitar problemas futuros.

130 |
131 | 132 |
133 | 134 | 135 | 136 | 137 | 138 |
139 |
140 |

Configurações do Visual Studio Code

141 |
142 |

Pergunta: O que vem na sua cabeça com esse título?

143 |
144 | 145 |
146 | 147 |
148 |

Configurações do Visual Studio Code

149 |
150 |

Você sabia que é possível compartilhar suas configurações de projeto do VsCode com outras pessoas?

151 |
152 | 153 |
154 | 155 |
156 |

Configurações do Visual Studio Code

157 |
158 |

É importante pois, caso uma pessoa venha, por exemplo, realizar um Code Review, ela trabalhe em cima das mesmas regras que você definiu.

159 |
160 | 161 |
162 | 163 |
164 |

Configurações do Visual Studio Code

165 |
166 |

Como fazemos isso?

167 |
168 | 169 |
170 | 171 |
172 |

Configurações do Visual Studio Code

173 |
{
 174 | 	"editor.formatOnPaste": true,
 175 | 	"editor.formatOnSave": true,
 176 | 	"editor.formatOnSaveMode": true,
 177 | 	"editor.formatOnType": true,
 178 | 	"editor.tabSize": 2,
 179 | 	"editor.codeActionsOnSave": {
 180 | 		"source.fixAll": true,
 181 | 		"source.organizeImports": true
 182 | 	// ...
 183 | 	}
 184 | 
 185 | }
 186 | 
187 | 188 |
189 | 190 |
191 |

Configurações do Visual Studio Code

192 |
    193 |
  • dessa forma podemos compartilhar nossas configurações de ambiente de projeto com outras pessoas.
  • 194 |
  • o arquivo sobrepõe suas configurações locais.
  • 195 |
196 | 197 |
198 | 199 | 200 |
201 | 202 | 203 | 204 | 205 | 206 |
207 |
208 |

Commits

209 |

210 | 211 |
212 | 213 |
214 |

Padronização de commits

215 |
    216 |
  • Commitlint
  • 217 |
  • Husky
  • 218 |
  • Commitizen
  • 219 |
220 | 221 |
222 | 223 |
224 |

Commits Atômicos

225 | 226 |
227 | 228 |
229 |

Commits Atômicos

230 |
    231 |
  • Submeta pequenas alterações que foram realizadas em seu código.
  • 232 |
233 | 234 |
235 | 236 |
237 |

Commits Atômicos

238 |
    239 |
  • Seus commits devem contar uma história, a história de desenvolvimento do seu projeto;
  • 240 |
241 | 242 |
243 | 244 |
245 |

Commits Atômicos

246 |
    247 |
  • Nada de commit bomba.
  • 248 |
249 | 250 |
251 | 252 |
253 |

Conventional Commits

254 |

Documentação

255 |
256 |

Ele fornece um conjunto fácil de regras para criar um histórico de commit explícito descrevendo os recursos, correções e alterações feitas nas mensagens de commit.

257 |
258 | 259 |
260 | 261 |
262 |

Conventional Commits

263 |
$ git commit -m "feat: insert validation user register"
 264 | 
 265 | $ git commit -m "fix: remove typo user validation register"
 266 | 
267 | 268 |
269 | 270 |
271 |

Commitlint

272 |

Documentação

273 |
274 |

Podemos Definir que utilizaremos o Conventional Commits, mas nada garante que vamos respeitar ou lembrar as regras em todos os commits.

275 |
276 | 277 |
278 | 279 |
280 |

Commitlint

281 |
282 |

Com ele conseguimos verificar se a mensagem de commit está dentro dos padrões definidos (Linter dos commits).

283 |
284 | 285 |
286 | 287 |
288 |

Commitizen

289 |

Documentação

290 |
291 |

O Commitizen é uma biblioteca que vai nos ajudar a criar os commits seguindo o padrão do Conventional Commit. Ela gera uma interface no terminal e assim vamos conseguir acessar todos os tipos de commits e suas descrições.

292 |
293 | 294 |
295 | 296 |
297 |

Husky

298 |

Documentação

299 |
300 |

É possível criar gatilhos em determinadas ações, utilizaremos o Husky para disparar uma ação antes de um commit para executar o commitizen e verificar se a mensagem do commit está seguindo o padrão definido.

301 |
302 | 303 |
304 | 305 |
306 |

Colocando tudo isso em prática

307 |

308 | 309 |
310 | 311 |
312 |

Iniciando Commitlint

313 |
$ npm init -y
 314 | $ git init
 315 | 
 316 | # install commit lint
 317 | $ npm install --save-dev @commitlint/cli
 318 | $ npm install --save-dev @commitlint/config-conventional
 319 | 
 320 | # atomic commit
 321 | $ git add package.json
 322 | $ git commit -m "feat: add commit lint lib"
 323 | 
 324 | # Configure commitlint to use conventional config
 325 | $ echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
 326 | 
 327 | 
328 | 329 |
330 | 331 |
332 |

Testando commitlint

333 |
# Para testar a biblioteca
 334 | echo "teste" | npx commitlint # deve apontar um erro
 335 | 
 336 | echo "feat: teste" | npx commitlint # deve funcionar corretamente
 337 | 
338 | 339 |
340 | 341 |
342 |

Iniciando Husky

343 |
# instalando a lib
 344 | $ npm install husky -D
 345 | 
 346 | # atomic commit
 347 | $ git add package.json
 348 | $ git commit -m "feat: add husky lib"
 349 | 
 350 | # ativando os hooks (gatilhos)
 351 | $ npx husky install
 352 | 
 353 | # Add hook que vai disparar o commitlint
 354 | $ npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
 355 | 
 356 | 
357 | 358 |
359 | 360 |
361 |

Iniciando Husky

362 |
// para ativar os hooks automaticamente após instalação
 363 | "scripts": {
 364 |   "prepare": "husky install"
 365 | }
 366 | 
 367 | // caso o script não seja adicionado ao package.json, toda vez 
 368 | // que um clone for realizado é necessário realizar 
 369 | // `$ npx husky install`
 370 | 
371 | 372 |
373 | 374 |
375 |

Realizando um commit

376 |
$ echo "node_modules/" > .gitignore
 377 | 
 378 | $ git status
 379 | $ git add .gitignore
 380 | $ git commit -m "qualquer coisa"
 381 | $ git commit -m "chore: add gitignore"
 382 | 
383 | 384 |
385 | 386 |
387 |

Adicionando o Commitizen

388 |
$ npm i commitizen -D
 389 | $ npx commitizen init cz-conventional-changelog --save-dev --save-exact
 390 | 
 391 | $ echo "console.log(1);" > index.js
 392 | $ git add index.js
 393 | 
 394 | "scripts": {
 395 |     "commit": "cz"
 396 |   }
 397 | 
 398 | $ npm run commit
 399 | 
400 | 401 |
402 | 403 |
404 |

Utilizando o Commitizen

405 |
    406 |
  1. Selecione o tipo de mudança que você está realizando
  2. 407 |
  3. Qual é o escopo desta mudança (por exemplo, componente ou nome do arquivo)
  4. 408 |
  5. Escreva uma descrição breve e imperativa da mudança (máx. 82 caracteres):
  6. 409 |
410 | 411 |
412 | 413 |
414 |

Utilizando o Commitizen

415 |
    416 |
  1. Forneça uma descrição mais longa da mudança:
  2. 417 |
  3. Existem alterações importantes (importante saber sobre Semantic Versioning)
  4. 418 |
  5. Essa mudança afeta algum problema em aberto? (Issues)
  6. 419 |
420 | 421 |
422 | 423 | 424 |
425 | 426 | 427 | 428 | 429 | 430 |
431 |
432 |

ESLint

433 |

434 | 435 |
436 | 437 |
438 |

O que é o ESLint?

439 |
440 |

Analisa seu código estaticamente para encontrar problemas. Você pode executar o ESLint como parte de seu pipeline de integração contínua (CI). Os problemas encontrados pelo ESLint podem ser corrigidos automaticamente.

441 |
442 | 443 |
444 | 445 |
446 |

Iniciando ESLint Backend

447 |
$ mkdir backend && cd backend
 448 | $ mv ../index.js backend
 449 | 
 450 | $ npm init -y
 451 | $ npm install eslint -D
 452 | $ npx eslint --init
 453 | 
 454 | $ git add [...]
 455 | $ npm run commit
 456 | 
457 | 458 |
459 | 460 |
461 |

Executando eslint

462 |
"lint": "eslint --no-inline-config --no-error-on-unmatched-pattern -c .eslintrc.json ."
 463 | 
 464 | $ npm run lint
 465 | 
466 | 467 |
468 | 469 |
470 |

Github Actions

471 |

Documentação

472 |

473 | 474 |
475 | 476 |
477 |

Github Actions

478 |
479 |

O GitHub Actions facilita a automatização de todos os seus fluxos de trabalho de software. Crie, teste e implante seu código diretamente do GitHub.

480 |
481 | 482 |
483 | 484 |
485 |

Github Actions - Continuous Integration

486 |
    487 |
  • Uma CI é realizada com sucesso quando novas mudanças no código são desenvolvidas, testadas e consolidadas em um repositório, por exemplo, a correção de um bug ou o deploy de uma feature nova.
  • 488 |
489 | 490 |
491 | 492 |
493 |

Github Action + ESLint

494 |
495 |

Vamos criar uma Action para que, todas as vezes que um PR for aberto ou um push for realizado, o ESLint execute todos os testes em nosso código.

496 |
497 | 498 |
499 | 500 |
501 |

Por onde começamos?

502 |

503 | 504 |
505 | 506 |
507 |

Configurando minhas Actions

508 | 509 |
510 | 511 |
512 |

Configurando minhas Actions

513 |
# vamos voltar para a raiz do projeto ./
 514 | $ mkdir .github/workflows/main.yml
 515 | 
516 | 517 |
518 | 519 |
520 |

Configurando minhas Actions

521 |
on:
 522 |   pull_request:
 523 |     types: [opened, synchronize]
 524 | 
 525 | jobs:
 526 |   eslint:
 527 |     runs-on: ubuntu-latest
 528 |     steps:
 529 |       - uses: actions/checkout@v2
 530 | 
 531 |       - uses: actions/setup-node@v2
 532 |         with:
 533 |           node-version: 14
 534 | 
 535 |       - name: Install back-end modules
 536 |         run: npm i --prefix backend    
 537 | 
 538 |       - name: Run linter on back-end
 539 |         run: npm run lint --prefix backend
 540 | 
541 | 542 |
543 | 544 |
545 |

Testando uma action

546 |
547 |

Para isso é necessário realizar um Pull Request em um repositório.

548 |
549 | 550 |
551 | 552 | 553 |
554 | 555 | 556 | 557 | 558 | 559 |
560 |
561 |

Docker

562 |

563 | 564 |
565 | 566 |
567 |

Docker

568 |
569 |

Não basta só compartilharmos nossas configurações de trabalho.

570 |
571 | 572 |
573 | 574 |
575 |

Docker

576 |
577 |

Podemos compartilhar nosso código pronto para ser executado, testado ou modificado, mas como?

578 |
579 | 580 |
581 | 582 |
583 |

“Dockerizando” sua aplicação

584 |

585 | 586 |
587 | 588 |
589 |

Dockerizando sua aplicação

590 |
591 |

Fornecendo toda a estrutura base do projeto para que qualquer pessoa consiga executa-lo em sua máquina, continuando o desenvolvimento ou realizando testes.

592 |
593 | 594 |
595 | 596 |
597 |

Case

598 |
599 |

Pense o seguinte caso: você está participando de um processo seletivo em que precisa construir uma aplicação simulando uma loja de vendas de sapatos.

600 |
601 | 602 |
603 | 604 |
605 |

Case

606 |
607 |

É bem provável que você irá desenvolver um CRUD de vendas e ou estoque.

608 |
609 | 610 |
611 | 612 |
613 |

Case

614 |
615 |

Para desenvolver, você seleciona 3 ferramentas: Node, React e MySQL.

616 |
617 | 618 |
619 | 620 |
621 |

Case

622 |
623 |

Após finalizado, como ficaria sua aplicação para ser enviada a pessoa avaliadora? Conte-me …

624 |
625 | 626 |
627 | 628 |
629 |

Case

630 |
631 |

Agora, imagine que: a pessoa que irá testar sua aplicação trabalha com Python, não possuí node e nem MySQL instalado na máquina :/

632 |
633 | 634 |
635 | 636 |
637 |
638 |

Ela vai ter um trabalhão não é mesmo?

639 |
640 | 641 |
642 | 643 |
644 |

Mão na massa no teclado

645 |

646 | 647 |
648 | 649 |
650 |

Utilizando Docker

651 |
652 |

Vamos trabalhar com um exemplo parecido

653 |
654 | 655 |
656 | 657 |
658 |

Utilizando Docker

659 |
660 |

Vamos imaginar que estamos desenvolvendo uma aplicação completa (front e back), utilizando as seguintes ferramentas:

661 |
662 | 663 |
664 | 665 |
666 |

Nossas ferramentas

667 |
    668 |
  • API com Node rodando na versão 12.22;
  • 669 |
  • Aplicação WEB com REACT e node na versão 12.22;
  • 670 |
  • Banco de dados MySQL na versão 5.7;
  • 671 |
672 | 673 |
674 | 675 |
676 |

Colocando em prática

677 |
    678 |
  1. Criar o Dockerfile do Backend
  2. 679 |
  3. Criar o Dockerfile do Frontend
  4. 680 |
  5. Criar o Docker Compose 681 |
      682 |
    1. Serviço do Back utilizando o Dockerfile
    2. 683 |
    3. Serviço do Front utilizando o Dockerfile
    4. 684 |
    5. Serviço MySQL sendo populado com um banco de dados
    6. 685 |
    686 |
  6. 687 |
688 | 689 |
690 | 691 |
692 |

Colocando em prática

693 |
694 |

Ponto de atenção: o container do Frontend é dependente do container do Backend e o Backend por sua vez é dependente do MySQL.

695 |
696 | 697 |
698 | 699 |
700 |

Let’s Code

701 | 702 |
703 | 704 |
705 |

Dockerfile Frontend

706 |
FROM node:12.22-alpine
 707 | 
 708 | 
 709 | WORKDIR /app
 710 | 
 711 | COPY package*.json ./
 712 | 
 713 | RUN npm install
 714 | 
 715 | RUN chmod 777 node_modules
 716 | 
 717 | COPY . .
 718 | 
 719 | EXPOSE 3000
 720 | 
 721 | CMD ["npm", "start"]
 722 | 
723 | 724 |
725 | 726 |
727 |

Dockerfile Backend

728 |
FROM node:12.22-alpine
 729 | 
 730 | WORKDIR /app
 731 | 
 732 | COPY package*.json ./
 733 | 
 734 | RUN npm install
 735 | 
 736 | RUN chmod 777 node_modules
 737 | 
 738 | COPY . .
 739 | 
 740 | EXPOSE 3333
 741 | 
 742 | CMD ["npm", "start"]
 743 | 
744 | 745 |
746 | 747 |
748 |

Docker compose

749 |
version: '3.1'
 750 | 
 751 | services:
 752 |   database:
 753 |     image: mysql:5.7
 754 |     restart: always
 755 |     container_name: mysql_compose
 756 |     ports:
 757 |       - 3306:3306
 758 |     environment:
 759 |       - MYSQL_ROOT_PASSWORD=docker
 760 |     volumes:
 761 |       - ./backend/database/mysql-seeder:/docker-entrypoint-initdb.d
 762 | 
 763 |   api:
 764 |     build: ./backend
 765 |     container_name: backend_compose
 766 |     ports:
 767 |       - 3333:3333
 768 |     depends_on:
 769 |       - database
 770 |     volumes:
 771 |       - /app/node_modules
 772 |       - ./backend:/app
 773 | 
 774 |   web:
 775 |     build: ./frontend
 776 |     container_name: frontend_compose
 777 |     ports:
 778 |       - 3000:3000
 779 |     volumes:
 780 |       - /app/node_modules
 781 |       - ./frontend:/app
 782 |     depends_on:
 783 |       - api
 784 | 
785 | 786 |
787 | 788 |
789 |
790 |

Agora nossa pessoa avaliadora poderá testar nosso código executando somente um comando.

791 |
792 |
793 | 794 |
795 | 796 | 797 |
798 | 799 | 800 | 801 |
802 | 803 | 804 |
805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 1034 | 1035 | 1036 | 1037 | -------------------------------------------------------------------------------- /apresentacao/export/libs/reveal.js/4.1.3/reveal.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * reveal.js 4.1.1 3 | * https://revealjs.com 4 | * MIT licensed 5 | * 6 | * Copyright (C) 2020 Hakim El Hattab, https://hakim.se 7 | */ 8 | .reveal .r-stretch,.reveal .stretch{max-width:none;max-height:none}.reveal pre.r-stretch code,.reveal pre.stretch code{height:100%;max-height:100%;box-sizing:border-box}.reveal .r-fit-text{display:inline-block;white-space:nowrap}.reveal .r-stack{display:grid}.reveal .r-stack>*{grid-area:1/1;margin:auto}.reveal .r-hstack,.reveal .r-vstack{display:flex}.reveal .r-hstack img,.reveal .r-hstack video,.reveal .r-vstack img,.reveal .r-vstack video{min-width:0;min-height:0;-o-object-fit:contain;object-fit:contain}.reveal .r-vstack{flex-direction:column;align-items:center;justify-content:center}.reveal .r-hstack{flex-direction:row;align-items:center;justify-content:center}.reveal .items-stretch{align-items:stretch}.reveal .items-start{align-items:flex-start}.reveal .items-center{align-items:center}.reveal .items-end{align-items:flex-end}.reveal .justify-between{justify-content:space-between}.reveal .justify-around{justify-content:space-around}.reveal .justify-start{justify-content:flex-start}.reveal .justify-center{justify-content:center}.reveal .justify-end{justify-content:flex-end}html.reveal-full-page{width:100%;height:100%;height:100vh;height:calc(var(--vh,1vh) * 100);overflow:hidden}.reveal-viewport{height:100%;overflow:hidden;position:relative;line-height:1;margin:0;background-color:#fff;color:#000}.reveal .slides section .fragment{opacity:0;visibility:hidden;transition:all .2s ease;will-change:opacity}.reveal .slides section .fragment.visible{opacity:1;visibility:inherit}.reveal .slides section .fragment.disabled{transition:none}.reveal .slides section .fragment.grow{opacity:1;visibility:inherit}.reveal .slides section .fragment.grow.visible{transform:scale(1.3)}.reveal .slides section .fragment.shrink{opacity:1;visibility:inherit}.reveal .slides section .fragment.shrink.visible{transform:scale(.7)}.reveal .slides section .fragment.zoom-in{transform:scale(.1)}.reveal .slides section .fragment.zoom-in.visible{transform:none}.reveal .slides section .fragment.fade-out{opacity:1;visibility:inherit}.reveal .slides section .fragment.fade-out.visible{opacity:0;visibility:hidden}.reveal .slides section .fragment.semi-fade-out{opacity:1;visibility:inherit}.reveal .slides section .fragment.semi-fade-out.visible{opacity:.5;visibility:inherit}.reveal .slides section .fragment.strike{opacity:1;visibility:inherit}.reveal .slides section .fragment.strike.visible{text-decoration:line-through}.reveal .slides section .fragment.fade-up{transform:translate(0,40px)}.reveal .slides section .fragment.fade-up.visible{transform:translate(0,0)}.reveal .slides section .fragment.fade-down{transform:translate(0,-40px)}.reveal .slides section .fragment.fade-down.visible{transform:translate(0,0)}.reveal .slides section .fragment.fade-right{transform:translate(-40px,0)}.reveal .slides section .fragment.fade-right.visible{transform:translate(0,0)}.reveal .slides section .fragment.fade-left{transform:translate(40px,0)}.reveal .slides section .fragment.fade-left.visible{transform:translate(0,0)}.reveal .slides section .fragment.current-visible,.reveal .slides section .fragment.fade-in-then-out{opacity:0;visibility:hidden}.reveal .slides section .fragment.current-visible.current-fragment,.reveal .slides section .fragment.fade-in-then-out.current-fragment{opacity:1;visibility:inherit}.reveal .slides section .fragment.fade-in-then-semi-out{opacity:0;visibility:hidden}.reveal .slides section .fragment.fade-in-then-semi-out.visible{opacity:.5;visibility:inherit}.reveal .slides section .fragment.fade-in-then-semi-out.current-fragment{opacity:1;visibility:inherit}.reveal .slides section .fragment.highlight-blue,.reveal .slides section .fragment.highlight-current-blue,.reveal .slides section .fragment.highlight-current-green,.reveal .slides section .fragment.highlight-current-red,.reveal .slides section .fragment.highlight-green,.reveal .slides section .fragment.highlight-red{opacity:1;visibility:inherit}.reveal .slides section .fragment.highlight-red.visible{color:#ff2c2d}.reveal .slides section .fragment.highlight-green.visible{color:#17ff2e}.reveal .slides section .fragment.highlight-blue.visible{color:#1b91ff}.reveal .slides section .fragment.highlight-current-red.current-fragment{color:#ff2c2d}.reveal .slides section .fragment.highlight-current-green.current-fragment{color:#17ff2e}.reveal .slides section .fragment.highlight-current-blue.current-fragment{color:#1b91ff}.reveal:after{content:"";font-style:italic}.reveal iframe{z-index:1}.reveal a{position:relative}@keyframes bounce-right{0%,10%,25%,40%,50%{transform:translateX(0)}20%{transform:translateX(10px)}30%{transform:translateX(-5px)}}@keyframes bounce-left{0%,10%,25%,40%,50%{transform:translateX(0)}20%{transform:translateX(-10px)}30%{transform:translateX(5px)}}@keyframes bounce-down{0%,10%,25%,40%,50%{transform:translateY(0)}20%{transform:translateY(10px)}30%{transform:translateY(-5px)}}.reveal .controls{display:none;position:absolute;top:auto;bottom:12px;right:12px;left:auto;z-index:11;color:#000;pointer-events:none;font-size:10px}.reveal .controls button{position:absolute;padding:0;background-color:transparent;border:0;outline:0;cursor:pointer;color:currentColor;transform:scale(.9999);transition:color .2s ease,opacity .2s ease,transform .2s ease;z-index:2;pointer-events:auto;font-size:inherit;visibility:hidden;opacity:0;-webkit-appearance:none;-webkit-tap-highlight-color:transparent}.reveal .controls .controls-arrow:after,.reveal .controls .controls-arrow:before{content:"";position:absolute;top:0;left:0;width:2.6em;height:.5em;border-radius:.25em;background-color:currentColor;transition:all .15s ease,background-color .8s ease;transform-origin:.2em 50%;will-change:transform}.reveal .controls .controls-arrow{position:relative;width:3.6em;height:3.6em}.reveal .controls .controls-arrow:before{transform:translateX(.5em) translateY(1.55em) rotate(45deg)}.reveal .controls .controls-arrow:after{transform:translateX(.5em) translateY(1.55em) rotate(-45deg)}.reveal .controls .controls-arrow:hover:before{transform:translateX(.5em) translateY(1.55em) rotate(40deg)}.reveal .controls .controls-arrow:hover:after{transform:translateX(.5em) translateY(1.55em) rotate(-40deg)}.reveal .controls .controls-arrow:active:before{transform:translateX(.5em) translateY(1.55em) rotate(36deg)}.reveal .controls .controls-arrow:active:after{transform:translateX(.5em) translateY(1.55em) rotate(-36deg)}.reveal .controls .navigate-left{right:6.4em;bottom:3.2em;transform:translateX(-10px)}.reveal .controls .navigate-left.highlight{animation:bounce-left 2s 50 both ease-out}.reveal .controls .navigate-right{right:0;bottom:3.2em;transform:translateX(10px)}.reveal .controls .navigate-right .controls-arrow{transform:rotate(180deg)}.reveal .controls .navigate-right.highlight{animation:bounce-right 2s 50 both ease-out}.reveal .controls .navigate-up{right:3.2em;bottom:6.4em;transform:translateY(-10px)}.reveal .controls .navigate-up .controls-arrow{transform:rotate(90deg)}.reveal .controls .navigate-down{right:3.2em;bottom:-1.4em;padding-bottom:1.4em;transform:translateY(10px)}.reveal .controls .navigate-down .controls-arrow{transform:rotate(-90deg)}.reveal .controls .navigate-down.highlight{animation:bounce-down 2s 50 both ease-out}.reveal .controls[data-controls-back-arrows=faded] .navigate-up.enabled{opacity:.3}.reveal .controls[data-controls-back-arrows=faded] .navigate-up.enabled:hover{opacity:1}.reveal .controls[data-controls-back-arrows=hidden] .navigate-up.enabled{opacity:0;visibility:hidden}.reveal .controls .enabled{visibility:visible;opacity:.9;cursor:pointer;transform:none}.reveal .controls .enabled.fragmented{opacity:.5}.reveal .controls .enabled.fragmented:hover,.reveal .controls .enabled:hover{opacity:1}.reveal:not(.rtl) .controls[data-controls-back-arrows=faded] .navigate-left.enabled{opacity:.3}.reveal:not(.rtl) .controls[data-controls-back-arrows=faded] .navigate-left.enabled:hover{opacity:1}.reveal:not(.rtl) .controls[data-controls-back-arrows=hidden] .navigate-left.enabled{opacity:0;visibility:hidden}.reveal.rtl .controls[data-controls-back-arrows=faded] .navigate-right.enabled{opacity:.3}.reveal.rtl .controls[data-controls-back-arrows=faded] .navigate-right.enabled:hover{opacity:1}.reveal.rtl .controls[data-controls-back-arrows=hidden] .navigate-right.enabled{opacity:0;visibility:hidden}.reveal[data-navigation-mode=linear].has-horizontal-slides .navigate-down,.reveal[data-navigation-mode=linear].has-horizontal-slides .navigate-up{display:none}.reveal:not(.has-vertical-slides) .controls .navigate-left,.reveal[data-navigation-mode=linear].has-horizontal-slides .navigate-left{bottom:1.4em;right:5.5em}.reveal:not(.has-vertical-slides) .controls .navigate-right,.reveal[data-navigation-mode=linear].has-horizontal-slides .navigate-right{bottom:1.4em;right:.5em}.reveal:not(.has-horizontal-slides) .controls .navigate-up{right:1.4em;bottom:5em}.reveal:not(.has-horizontal-slides) .controls .navigate-down{right:1.4em;bottom:.5em}.reveal.has-dark-background .controls{color:#fff}.reveal.has-light-background .controls{color:#000}.reveal.no-hover .controls .controls-arrow:active:before,.reveal.no-hover .controls .controls-arrow:hover:before{transform:translateX(.5em) translateY(1.55em) rotate(45deg)}.reveal.no-hover .controls .controls-arrow:active:after,.reveal.no-hover .controls .controls-arrow:hover:after{transform:translateX(.5em) translateY(1.55em) rotate(-45deg)}@media screen and (min-width:500px){.reveal .controls[data-controls-layout=edges]{top:0;right:0;bottom:0;left:0}.reveal .controls[data-controls-layout=edges] .navigate-down,.reveal .controls[data-controls-layout=edges] .navigate-left,.reveal .controls[data-controls-layout=edges] .navigate-right,.reveal .controls[data-controls-layout=edges] .navigate-up{bottom:auto;right:auto}.reveal .controls[data-controls-layout=edges] .navigate-left{top:50%;left:.8em;margin-top:-1.8em}.reveal .controls[data-controls-layout=edges] .navigate-right{top:50%;right:.8em;margin-top:-1.8em}.reveal .controls[data-controls-layout=edges] .navigate-up{top:.8em;left:50%;margin-left:-1.8em}.reveal .controls[data-controls-layout=edges] .navigate-down{bottom:-.3em;left:50%;margin-left:-1.8em}}.reveal .progress{position:absolute;display:none;height:3px;width:100%;bottom:0;left:0;z-index:10;background-color:rgba(0,0,0,.2);color:#fff}.reveal .progress:after{content:"";display:block;position:absolute;height:10px;width:100%;top:-10px}.reveal .progress span{display:block;height:100%;width:100%;background-color:currentColor;transition:transform .8s cubic-bezier(.26,.86,.44,.985);transform-origin:0 0;transform:scaleX(0)}.reveal .slide-number{position:absolute;display:block;right:8px;bottom:8px;z-index:31;font-family:Helvetica,sans-serif;font-size:12px;line-height:1;color:#fff;background-color:rgba(0,0,0,.4);padding:5px}.reveal .slide-number a{color:currentColor}.reveal .slide-number-delimiter{margin:0 3px}.reveal{position:relative;width:100%;height:100%;overflow:hidden;touch-action:pinch-zoom}.reveal.embedded{touch-action:pan-y}.reveal .slides{position:absolute;width:100%;height:100%;top:0;right:0;bottom:0;left:0;margin:auto;pointer-events:none;overflow:visible;z-index:1;text-align:center;perspective:600px;perspective-origin:50% 40%}.reveal .slides>section{perspective:600px}.reveal .slides>section,.reveal .slides>section>section{display:none;position:absolute;width:100%;pointer-events:auto;z-index:10;transform-style:flat;transition:transform-origin .8s cubic-bezier(.26,.86,.44,.985),transform .8s cubic-bezier(.26,.86,.44,.985),visibility .8s cubic-bezier(.26,.86,.44,.985),opacity .8s cubic-bezier(.26,.86,.44,.985)}.reveal[data-transition-speed=fast] .slides section{transition-duration:.4s}.reveal[data-transition-speed=slow] .slides section{transition-duration:1.2s}.reveal .slides section[data-transition-speed=fast]{transition-duration:.4s}.reveal .slides section[data-transition-speed=slow]{transition-duration:1.2s}.reveal .slides>section.stack{padding-top:0;padding-bottom:0;pointer-events:none;height:100%}.reveal .slides>section.present,.reveal .slides>section>section.present{display:block;z-index:11;opacity:1}.reveal .slides>section:empty,.reveal .slides>section>section:empty,.reveal .slides>section>section[data-background-interactive],.reveal .slides>section[data-background-interactive]{pointer-events:none}.reveal.center,.reveal.center .slides,.reveal.center .slides section{min-height:0!important}.reveal .slides>section:not(.present),.reveal .slides>section>section:not(.present){pointer-events:none}.reveal.overview .slides>section,.reveal.overview .slides>section>section{pointer-events:auto}.reveal .slides>section.future,.reveal .slides>section.past,.reveal .slides>section>section.future,.reveal .slides>section>section.past{opacity:0}.reveal.slide section{-webkit-backface-visibility:hidden;backface-visibility:hidden}.reveal .slides>section[data-transition=slide].past,.reveal .slides>section[data-transition~=slide-out].past,.reveal.slide .slides>section:not([data-transition]).past{transform:translate(-150%,0)}.reveal .slides>section[data-transition=slide].future,.reveal .slides>section[data-transition~=slide-in].future,.reveal.slide .slides>section:not([data-transition]).future{transform:translate(150%,0)}.reveal .slides>section>section[data-transition=slide].past,.reveal .slides>section>section[data-transition~=slide-out].past,.reveal.slide .slides>section>section:not([data-transition]).past{transform:translate(0,-150%)}.reveal .slides>section>section[data-transition=slide].future,.reveal .slides>section>section[data-transition~=slide-in].future,.reveal.slide .slides>section>section:not([data-transition]).future{transform:translate(0,150%)}.reveal.linear section{-webkit-backface-visibility:hidden;backface-visibility:hidden}.reveal .slides>section[data-transition=linear].past,.reveal .slides>section[data-transition~=linear-out].past,.reveal.linear .slides>section:not([data-transition]).past{transform:translate(-150%,0)}.reveal .slides>section[data-transition=linear].future,.reveal .slides>section[data-transition~=linear-in].future,.reveal.linear .slides>section:not([data-transition]).future{transform:translate(150%,0)}.reveal .slides>section>section[data-transition=linear].past,.reveal .slides>section>section[data-transition~=linear-out].past,.reveal.linear .slides>section>section:not([data-transition]).past{transform:translate(0,-150%)}.reveal .slides>section>section[data-transition=linear].future,.reveal .slides>section>section[data-transition~=linear-in].future,.reveal.linear .slides>section>section:not([data-transition]).future{transform:translate(0,150%)}.reveal .slides section[data-transition=default].stack,.reveal.default .slides section.stack{transform-style:preserve-3d}.reveal .slides>section[data-transition=default].past,.reveal .slides>section[data-transition~=default-out].past,.reveal.default .slides>section:not([data-transition]).past{transform:translate3d(-100%,0,0) rotateY(-90deg) translate3d(-100%,0,0)}.reveal .slides>section[data-transition=default].future,.reveal .slides>section[data-transition~=default-in].future,.reveal.default .slides>section:not([data-transition]).future{transform:translate3d(100%,0,0) rotateY(90deg) translate3d(100%,0,0)}.reveal .slides>section>section[data-transition=default].past,.reveal .slides>section>section[data-transition~=default-out].past,.reveal.default .slides>section>section:not([data-transition]).past{transform:translate3d(0,-300px,0) rotateX(70deg) translate3d(0,-300px,0)}.reveal .slides>section>section[data-transition=default].future,.reveal .slides>section>section[data-transition~=default-in].future,.reveal.default .slides>section>section:not([data-transition]).future{transform:translate3d(0,300px,0) rotateX(-70deg) translate3d(0,300px,0)}.reveal .slides section[data-transition=convex].stack,.reveal.convex .slides section.stack{transform-style:preserve-3d}.reveal .slides>section[data-transition=convex].past,.reveal .slides>section[data-transition~=convex-out].past,.reveal.convex .slides>section:not([data-transition]).past{transform:translate3d(-100%,0,0) rotateY(-90deg) translate3d(-100%,0,0)}.reveal .slides>section[data-transition=convex].future,.reveal .slides>section[data-transition~=convex-in].future,.reveal.convex .slides>section:not([data-transition]).future{transform:translate3d(100%,0,0) rotateY(90deg) translate3d(100%,0,0)}.reveal .slides>section>section[data-transition=convex].past,.reveal .slides>section>section[data-transition~=convex-out].past,.reveal.convex .slides>section>section:not([data-transition]).past{transform:translate3d(0,-300px,0) rotateX(70deg) translate3d(0,-300px,0)}.reveal .slides>section>section[data-transition=convex].future,.reveal .slides>section>section[data-transition~=convex-in].future,.reveal.convex .slides>section>section:not([data-transition]).future{transform:translate3d(0,300px,0) rotateX(-70deg) translate3d(0,300px,0)}.reveal .slides section[data-transition=concave].stack,.reveal.concave .slides section.stack{transform-style:preserve-3d}.reveal .slides>section[data-transition=concave].past,.reveal .slides>section[data-transition~=concave-out].past,.reveal.concave .slides>section:not([data-transition]).past{transform:translate3d(-100%,0,0) rotateY(90deg) translate3d(-100%,0,0)}.reveal .slides>section[data-transition=concave].future,.reveal .slides>section[data-transition~=concave-in].future,.reveal.concave .slides>section:not([data-transition]).future{transform:translate3d(100%,0,0) rotateY(-90deg) translate3d(100%,0,0)}.reveal .slides>section>section[data-transition=concave].past,.reveal .slides>section>section[data-transition~=concave-out].past,.reveal.concave .slides>section>section:not([data-transition]).past{transform:translate3d(0,-80%,0) rotateX(-70deg) translate3d(0,-80%,0)}.reveal .slides>section>section[data-transition=concave].future,.reveal .slides>section>section[data-transition~=concave-in].future,.reveal.concave .slides>section>section:not([data-transition]).future{transform:translate3d(0,80%,0) rotateX(70deg) translate3d(0,80%,0)}.reveal .slides section[data-transition=zoom],.reveal.zoom .slides section:not([data-transition]){transition-timing-function:ease}.reveal .slides>section[data-transition=zoom].past,.reveal .slides>section[data-transition~=zoom-out].past,.reveal.zoom .slides>section:not([data-transition]).past{visibility:hidden;transform:scale(16)}.reveal .slides>section[data-transition=zoom].future,.reveal .slides>section[data-transition~=zoom-in].future,.reveal.zoom .slides>section:not([data-transition]).future{visibility:hidden;transform:scale(.2)}.reveal .slides>section>section[data-transition=zoom].past,.reveal .slides>section>section[data-transition~=zoom-out].past,.reveal.zoom .slides>section>section:not([data-transition]).past{transform:scale(16)}.reveal .slides>section>section[data-transition=zoom].future,.reveal .slides>section>section[data-transition~=zoom-in].future,.reveal.zoom .slides>section>section:not([data-transition]).future{transform:scale(.2)}.reveal.cube .slides{perspective:1300px}.reveal.cube .slides section{padding:30px;min-height:700px;-webkit-backface-visibility:hidden;backface-visibility:hidden;box-sizing:border-box;transform-style:preserve-3d}.reveal.center.cube .slides section{min-height:0}.reveal.cube .slides section:not(.stack):before{content:"";position:absolute;display:block;width:100%;height:100%;left:0;top:0;background:rgba(0,0,0,.1);border-radius:4px;transform:translateZ(-20px)}.reveal.cube .slides section:not(.stack):after{content:"";position:absolute;display:block;width:90%;height:30px;left:5%;bottom:0;background:0 0;z-index:1;border-radius:4px;box-shadow:0 95px 25px rgba(0,0,0,.2);transform:translateZ(-90px) rotateX(65deg)}.reveal.cube .slides>section.stack{padding:0;background:0 0}.reveal.cube .slides>section.past{transform-origin:100% 0;transform:translate3d(-100%,0,0) rotateY(-90deg)}.reveal.cube .slides>section.future{transform-origin:0 0;transform:translate3d(100%,0,0) rotateY(90deg)}.reveal.cube .slides>section>section.past{transform-origin:0 100%;transform:translate3d(0,-100%,0) rotateX(90deg)}.reveal.cube .slides>section>section.future{transform-origin:0 0;transform:translate3d(0,100%,0) rotateX(-90deg)}.reveal.page .slides{perspective-origin:0 50%;perspective:3000px}.reveal.page .slides section{padding:30px;min-height:700px;box-sizing:border-box;transform-style:preserve-3d}.reveal.page .slides section.past{z-index:12}.reveal.page .slides section:not(.stack):before{content:"";position:absolute;display:block;width:100%;height:100%;left:0;top:0;background:rgba(0,0,0,.1);transform:translateZ(-20px)}.reveal.page .slides section:not(.stack):after{content:"";position:absolute;display:block;width:90%;height:30px;left:5%;bottom:0;background:0 0;z-index:1;border-radius:4px;box-shadow:0 95px 25px rgba(0,0,0,.2);-webkit-transform:translateZ(-90px) rotateX(65deg)}.reveal.page .slides>section.stack{padding:0;background:0 0}.reveal.page .slides>section.past{transform-origin:0 0;transform:translate3d(-40%,0,0) rotateY(-80deg)}.reveal.page .slides>section.future{transform-origin:100% 0;transform:translate3d(0,0,0)}.reveal.page .slides>section>section.past{transform-origin:0 0;transform:translate3d(0,-40%,0) rotateX(80deg)}.reveal.page .slides>section>section.future{transform-origin:0 100%;transform:translate3d(0,0,0)}.reveal .slides section[data-transition=fade],.reveal.fade .slides section:not([data-transition]),.reveal.fade .slides>section>section:not([data-transition]){transform:none;transition:opacity .5s}.reveal.fade.overview .slides section,.reveal.fade.overview .slides>section>section{transition:none}.reveal .slides section[data-transition=none],.reveal.none .slides section:not([data-transition]){transform:none;transition:none}.reveal .pause-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:#000;visibility:hidden;opacity:0;z-index:100;transition:all 1s ease}.reveal .pause-overlay .resume-button{position:absolute;bottom:20px;right:20px;color:#ccc;border-radius:2px;padding:6px 14px;border:2px solid #ccc;font-size:16px;background:0 0;cursor:pointer}.reveal .pause-overlay .resume-button:hover{color:#fff;border-color:#fff}.reveal.paused .pause-overlay{visibility:visible;opacity:1}.reveal .no-transition,.reveal .no-transition *,.reveal .slides.disable-slide-transitions section{transition:none!important}.reveal .slides.disable-slide-transitions section{transform:none!important}.reveal .backgrounds{position:absolute;width:100%;height:100%;top:0;left:0;perspective:600px}.reveal .slide-background{display:none;position:absolute;width:100%;height:100%;opacity:0;visibility:hidden;overflow:hidden;background-color:rgba(0,0,0,0);transition:all .8s cubic-bezier(.26,.86,.44,.985)}.reveal .slide-background-content{position:absolute;width:100%;height:100%;background-position:50% 50%;background-repeat:no-repeat;background-size:cover}.reveal .slide-background.stack{display:block}.reveal .slide-background.present{opacity:1;visibility:visible;z-index:2}.print-pdf .reveal .slide-background{opacity:1!important;visibility:visible!important}.reveal .slide-background video{position:absolute;width:100%;height:100%;max-width:none;max-height:none;top:0;left:0;-o-object-fit:cover;object-fit:cover}.reveal .slide-background[data-background-size=contain] video{-o-object-fit:contain;object-fit:contain}.reveal>.backgrounds .slide-background[data-background-transition=none],.reveal[data-background-transition=none]>.backgrounds .slide-background:not([data-background-transition]){transition:none}.reveal>.backgrounds .slide-background[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background:not([data-background-transition]){opacity:1;-webkit-backface-visibility:hidden;backface-visibility:hidden}.reveal>.backgrounds .slide-background.past[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background.past:not([data-background-transition]){transform:translate(-100%,0)}.reveal>.backgrounds .slide-background.future[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background.future:not([data-background-transition]){transform:translate(100%,0)}.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]){transform:translate(0,-100%)}.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]){transform:translate(0,100%)}.reveal>.backgrounds .slide-background.past[data-background-transition=convex],.reveal[data-background-transition=convex]>.backgrounds .slide-background.past:not([data-background-transition]){opacity:0;transform:translate3d(-100%,0,0) rotateY(-90deg) translate3d(-100%,0,0)}.reveal>.backgrounds .slide-background.future[data-background-transition=convex],.reveal[data-background-transition=convex]>.backgrounds .slide-background.future:not([data-background-transition]){opacity:0;transform:translate3d(100%,0,0) rotateY(90deg) translate3d(100%,0,0)}.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=convex],.reveal[data-background-transition=convex]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]){opacity:0;transform:translate3d(0,-100%,0) rotateX(90deg) translate3d(0,-100%,0)}.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=convex],.reveal[data-background-transition=convex]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]){opacity:0;transform:translate3d(0,100%,0) rotateX(-90deg) translate3d(0,100%,0)}.reveal>.backgrounds .slide-background.past[data-background-transition=concave],.reveal[data-background-transition=concave]>.backgrounds .slide-background.past:not([data-background-transition]){opacity:0;transform:translate3d(-100%,0,0) rotateY(90deg) translate3d(-100%,0,0)}.reveal>.backgrounds .slide-background.future[data-background-transition=concave],.reveal[data-background-transition=concave]>.backgrounds .slide-background.future:not([data-background-transition]){opacity:0;transform:translate3d(100%,0,0) rotateY(-90deg) translate3d(100%,0,0)}.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=concave],.reveal[data-background-transition=concave]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]){opacity:0;transform:translate3d(0,-100%,0) rotateX(-90deg) translate3d(0,-100%,0)}.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=concave],.reveal[data-background-transition=concave]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]){opacity:0;transform:translate3d(0,100%,0) rotateX(90deg) translate3d(0,100%,0)}.reveal>.backgrounds .slide-background[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background:not([data-background-transition]){transition-timing-function:ease}.reveal>.backgrounds .slide-background.past[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background.past:not([data-background-transition]){opacity:0;visibility:hidden;transform:scale(16)}.reveal>.backgrounds .slide-background.future[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background.future:not([data-background-transition]){opacity:0;visibility:hidden;transform:scale(.2)}.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]){opacity:0;visibility:hidden;transform:scale(16)}.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]){opacity:0;visibility:hidden;transform:scale(.2)}.reveal[data-transition-speed=fast]>.backgrounds .slide-background{transition-duration:.4s}.reveal[data-transition-speed=slow]>.backgrounds .slide-background{transition-duration:1.2s}.reveal [data-auto-animate-target^=unmatched]{will-change:opacity}.reveal section[data-auto-animate]:not(.stack):not([data-auto-animate=running]) [data-auto-animate-target^=unmatched]{opacity:0}.reveal.overview{perspective-origin:50% 50%;perspective:700px}.reveal.overview .slides{-moz-transform-style:preserve-3d}.reveal.overview .slides section{height:100%;top:0!important;opacity:1!important;overflow:hidden;visibility:visible!important;cursor:pointer;box-sizing:border-box}.reveal.overview .slides section.present,.reveal.overview .slides section:hover{outline:10px solid rgba(150,150,150,.4);outline-offset:10px}.reveal.overview .slides section .fragment{opacity:1;transition:none}.reveal.overview .slides section:after,.reveal.overview .slides section:before{display:none!important}.reveal.overview .slides>section.stack{padding:0;top:0!important;background:0 0;outline:0;overflow:visible}.reveal.overview .backgrounds{perspective:inherit;-moz-transform-style:preserve-3d}.reveal.overview .backgrounds .slide-background{opacity:1;visibility:visible;outline:10px solid rgba(150,150,150,.1);outline-offset:10px}.reveal.overview .backgrounds .slide-background.stack{overflow:visible}.reveal.overview .slides section,.reveal.overview-deactivating .slides section{transition:none}.reveal.overview .backgrounds .slide-background,.reveal.overview-deactivating .backgrounds .slide-background{transition:none}.reveal.rtl .slides,.reveal.rtl .slides h1,.reveal.rtl .slides h2,.reveal.rtl .slides h3,.reveal.rtl .slides h4,.reveal.rtl .slides h5,.reveal.rtl .slides h6{direction:rtl;font-family:sans-serif}.reveal.rtl code,.reveal.rtl pre{direction:ltr}.reveal.rtl ol,.reveal.rtl ul{text-align:right}.reveal.rtl .progress span{transform-origin:100% 0}.reveal.has-parallax-background .backgrounds{transition:all .8s ease}.reveal.has-parallax-background[data-transition-speed=fast] .backgrounds{transition-duration:.4s}.reveal.has-parallax-background[data-transition-speed=slow] .backgrounds{transition-duration:1.2s}.reveal>.overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:1000;background:rgba(0,0,0,.9);transition:all .3s ease}.reveal>.overlay .spinner{position:absolute;display:block;top:50%;left:50%;width:32px;height:32px;margin:-16px 0 0 -16px;z-index:10;background-image:url(data:image/gif;base64,R0lGODlhIAAgAPMAAJmZmf%2F%2F%2F6%2Bvr8nJybW1tcDAwOjo6Nvb26ioqKOjo7Ozs%2FLy8vz8%2FAAAAAAAAAAAACH%2FC05FVFNDQVBFMi4wAwEAAAAh%2FhpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh%2BQQJCgAAACwAAAAAIAAgAAAE5xDISWlhperN52JLhSSdRgwVo1ICQZRUsiwHpTJT4iowNS8vyW2icCF6k8HMMBkCEDskxTBDAZwuAkkqIfxIQyhBQBFvAQSDITM5VDW6XNE4KagNh6Bgwe60smQUB3d4Rz1ZBApnFASDd0hihh12BkE9kjAJVlycXIg7CQIFA6SlnJ87paqbSKiKoqusnbMdmDC2tXQlkUhziYtyWTxIfy6BE8WJt5YJvpJivxNaGmLHT0VnOgSYf0dZXS7APdpB309RnHOG5gDqXGLDaC457D1zZ%2FV%2FnmOM82XiHRLYKhKP1oZmADdEAAAh%2BQQJCgAAACwAAAAAIAAgAAAE6hDISWlZpOrNp1lGNRSdRpDUolIGw5RUYhhHukqFu8DsrEyqnWThGvAmhVlteBvojpTDDBUEIFwMFBRAmBkSgOrBFZogCASwBDEY%2FCZSg7GSE0gSCjQBMVG023xWBhklAnoEdhQEfyNqMIcKjhRsjEdnezB%2BA4k8gTwJhFuiW4dokXiloUepBAp5qaKpp6%2BHo7aWW54wl7obvEe0kRuoplCGepwSx2jJvqHEmGt6whJpGpfJCHmOoNHKaHx61WiSR92E4lbFoq%2BB6QDtuetcaBPnW6%2BO7wDHpIiK9SaVK5GgV543tzjgGcghAgAh%2BQQJCgAAACwAAAAAIAAgAAAE7hDISSkxpOrN5zFHNWRdhSiVoVLHspRUMoyUakyEe8PTPCATW9A14E0UvuAKMNAZKYUZCiBMuBakSQKG8G2FzUWox2AUtAQFcBKlVQoLgQReZhQlCIJesQXI5B0CBnUMOxMCenoCfTCEWBsJColTMANldx15BGs8B5wlCZ9Po6OJkwmRpnqkqnuSrayqfKmqpLajoiW5HJq7FL1Gr2mMMcKUMIiJgIemy7xZtJsTmsM4xHiKv5KMCXqfyUCJEonXPN2rAOIAmsfB3uPoAK%2B%2BG%2Bw48edZPK%2BM6hLJpQg484enXIdQFSS1u6UhksENEQAAIfkECQoAAAAsAAAAACAAIAAABOcQyEmpGKLqzWcZRVUQnZYg1aBSh2GUVEIQ2aQOE%2BG%2BcD4ntpWkZQj1JIiZIogDFFyHI0UxQwFugMSOFIPJftfVAEoZLBbcLEFhlQiqGp1Vd140AUklUN3eCA51C1EWMzMCezCBBmkxVIVHBWd3HHl9JQOIJSdSnJ0TDKChCwUJjoWMPaGqDKannasMo6WnM562R5YluZRwur0wpgqZE7NKUm%2BFNRPIhjBJxKZteWuIBMN4zRMIVIhffcgojwCF117i4nlLnY5ztRLsnOk%2BaV%2BoJY7V7m76PdkS4trKcdg0Zc0tTcKkRAAAIfkECQoAAAAsAAAAACAAIAAABO4QyEkpKqjqzScpRaVkXZWQEximw1BSCUEIlDohrft6cpKCk5xid5MNJTaAIkekKGQkWyKHkvhKsR7ARmitkAYDYRIbUQRQjWBwJRzChi9CRlBcY1UN4g0%2FVNB0AlcvcAYHRyZPdEQFYV8ccwR5HWxEJ02YmRMLnJ1xCYp0Y5idpQuhopmmC2KgojKasUQDk5BNAwwMOh2RtRq5uQuPZKGIJQIGwAwGf6I0JXMpC8C7kXWDBINFMxS4DKMAWVWAGYsAdNqW5uaRxkSKJOZKaU3tPOBZ4DuK2LATgJhkPJMgTwKCdFjyPHEnKxFCDhEAACH5BAkKAAAALAAAAAAgACAAAATzEMhJaVKp6s2nIkolIJ2WkBShpkVRWqqQrhLSEu9MZJKK9y1ZrqYK9WiClmvoUaF8gIQSNeF1Er4MNFn4SRSDARWroAIETg1iVwuHjYB1kYc1mwruwXKC9gmsJXliGxc%2BXiUCby9ydh1sOSdMkpMTBpaXBzsfhoc5l58Gm5yToAaZhaOUqjkDgCWNHAULCwOLaTmzswadEqggQwgHuQsHIoZCHQMMQgQGubVEcxOPFAcMDAYUA85eWARmfSRQCdcMe0zeP1AAygwLlJtPNAAL19DARdPzBOWSm1brJBi45soRAWQAAkrQIykShQ9wVhHCwCQCACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiRMDjI0Fd30%2FiI2UA5GSS5UDj2l6NoqgOgN4gksEBgYFf0FDqKgHnyZ9OX8HrgYHdHpcHQULXAS2qKpENRg7eAMLC7kTBaixUYFkKAzWAAnLC7FLVxLWDBLKCwaKTULgEwbLA4hJtOkSBNqITT3xEgfLpBtzE%2FjiuL04RGEBgwWhShRgQExHBAAh%2BQQJCgAAACwAAAAAIAAgAAAE7xDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfZiCqGk5dTESJeaOAlClzsJsqwiJwiqnFrb2nS9kmIcgEsjQydLiIlHehhpejaIjzh9eomSjZR%2BipslWIRLAgMDOR2DOqKogTB9pCUJBagDBXR6XB0EBkIIsaRsGGMMAxoDBgYHTKJiUYEGDAzHC9EACcUGkIgFzgwZ0QsSBcXHiQvOwgDdEwfFs0sDzt4S6BK4xYjkDOzn0unFeBzOBijIm1Dgmg5YFQwsCMjp1oJ8LyIAACH5BAkKAAAALAAAAAAgACAAAATwEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GGl6NoiPOH16iZKNlH6KmyWFOggHhEEvAwwMA0N9GBsEC6amhnVcEwavDAazGwIDaH1ipaYLBUTCGgQDA8NdHz0FpqgTBwsLqAbWAAnIA4FWKdMLGdYGEgraigbT0OITBcg5QwPT4xLrROZL6AuQAPUS7bxLpoWidY0JtxLHKhwwMJBTHgPKdEQAACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GAULDJCRiXo1CpGXDJOUjY%2BYip9DhToJA4RBLwMLCwVDfRgbBAaqqoZ1XBMHswsHtxtFaH1iqaoGNgAIxRpbFAgfPQSqpbgGBqUD1wBXeCYp1AYZ19JJOYgH1KwA4UBvQwXUBxPqVD9L3sbp2BNk2xvvFPJd%2BMFCN6HAAIKgNggY0KtEBAAh%2BQQJCgAAACwAAAAAIAAgAAAE6BDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfYIDMaAFdTESJeaEDAIMxYFqrOUaNW4E4ObYcCXaiBVEgULe0NJaxxtYksjh2NLkZISgDgJhHthkpU4mW6blRiYmZOlh4JWkDqILwUGBnE6TYEbCgevr0N1gH4At7gHiRpFaLNrrq8HNgAJA70AWxQIH1%2BvsYMDAzZQPC9VCNkDWUhGkuE5PxJNwiUK4UfLzOlD4WvzAHaoG9nxPi5d%2BjYUqfAhhykOFwJWiAAAIfkECQoAAAAsAAAAACAAIAAABPAQyElpUqnqzaciSoVkXVUMFaFSwlpOCcMYlErAavhOMnNLNo8KsZsMZItJEIDIFSkLGQoQTNhIsFehRww2CQLKF0tYGKYSg%2BygsZIuNqJksKgbfgIGepNo2cIUB3V1B3IvNiBYNQaDSTtfhhx0CwVPI0UJe0%2Bbm4g5VgcGoqOcnjmjqDSdnhgEoamcsZuXO1aWQy8KAwOAuTYYGwi7w5h%2BKr0SJ8MFihpNbx%2B4Erq7BYBuzsdiH1jCAzoSfl0rVirNbRXlBBlLX%2BBP0XJLAPGzTkAuAOqb0WT5AH7OcdCm5B8TgRwSRKIHQtaLCwg1RAAAOwAAAAAAAAAAAA%3D%3D);visibility:visible;opacity:.6;transition:all .3s ease}.reveal>.overlay header{position:absolute;left:0;top:0;width:100%;padding:5px;z-index:2;box-sizing:border-box}.reveal>.overlay header a{display:inline-block;width:40px;height:40px;line-height:36px;padding:0 10px;float:right;opacity:.6;box-sizing:border-box}.reveal>.overlay header a:hover{opacity:1}.reveal>.overlay header a .icon{display:inline-block;width:20px;height:20px;background-position:50% 50%;background-size:100%;background-repeat:no-repeat}.reveal>.overlay header a.close .icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABkklEQVRYR8WX4VHDMAxG6wnoJrABZQPYBCaBTWAD2g1gE5gg6OOsXuxIlr40d81dfrSJ9V4c2VLK7spHuTJ/5wpM07QXuXc5X0opX2tEJcadjHuV80li/FgxTIEK/5QBCICBD6xEhSMGHgQPgBgLiYVAB1dpSqKDawxTohFw4JSEA3clzgIBPCURwE2JucBR7rhPJJv5OpJwDX+SfDjgx1wACQeJG1aChP9K/IMmdZ8DtESV1WyP3Bt4MwM6sj4NMxMYiqUWHQu4KYA/SYkIjOsm3BXYWMKFDwU2khjCQ4ELJUJ4SmClRArOCmSXGuKma0fYD5CbzHxFpCSGAhfAVSSUGDUk2BWZaff2g6GE15BsBQ9nwmpIGDiyHQddwNTMKkbZaf9fajXQca1EX44puJZUsnY0ObGmITE3GVLCbEhQUjGVt146j6oasWN+49Vph2w1pZ5EansNZqKBm1txbU57iRRcZ86RWMDdWtBJUHBHwoQPi1GV+JCbntmvok7iTX4/Up9mgyTc/FJYDTcndgH/AA5A/CHsyEkVAAAAAElFTkSuQmCC)}.reveal>.overlay header a.external .icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAcElEQVRYR+2WSQoAIQwEzf8f7XiOMkUQxUPlGkM3hVmiQfQR9GYnH1SsAQlI4DiBqkCMoNb9y2e90IAEJPAcgdznU9+engMaeJ7Azh5Y1U67gAho4DqBqmB1buAf0MB1AlVBek83ZPkmJMGc1wAR+AAqod/B97TRpQAAAABJRU5ErkJggg==)}.reveal>.overlay .viewport{position:absolute;display:flex;top:50px;right:0;bottom:0;left:0}.reveal>.overlay.overlay-preview .viewport iframe{width:100%;height:100%;max-width:100%;max-height:100%;border:0;opacity:0;visibility:hidden;transition:all .3s ease}.reveal>.overlay.overlay-preview.loaded .viewport iframe{opacity:1;visibility:visible}.reveal>.overlay.overlay-preview.loaded .viewport-inner{position:absolute;z-index:-1;left:0;top:45%;width:100%;text-align:center;letter-spacing:normal}.reveal>.overlay.overlay-preview .x-frame-error{opacity:0;transition:opacity .3s ease .3s}.reveal>.overlay.overlay-preview.loaded .x-frame-error{opacity:1}.reveal>.overlay.overlay-preview.loaded .spinner{opacity:0;visibility:hidden;transform:scale(.2)}.reveal>.overlay.overlay-help .viewport{overflow:auto;color:#fff}.reveal>.overlay.overlay-help .viewport .viewport-inner{width:600px;margin:auto;padding:20px 20px 80px 20px;text-align:center;letter-spacing:normal}.reveal>.overlay.overlay-help .viewport .viewport-inner .title{font-size:20px}.reveal>.overlay.overlay-help .viewport .viewport-inner table{border:1px solid #fff;border-collapse:collapse;font-size:16px}.reveal>.overlay.overlay-help .viewport .viewport-inner table td,.reveal>.overlay.overlay-help .viewport .viewport-inner table th{width:200px;padding:14px;border:1px solid #fff;vertical-align:middle}.reveal>.overlay.overlay-help .viewport .viewport-inner table th{padding-top:20px;padding-bottom:20px}.reveal .playback{position:absolute;left:15px;bottom:20px;z-index:30;cursor:pointer;transition:all .4s ease;-webkit-tap-highlight-color:transparent}.reveal.overview .playback{opacity:0;visibility:hidden}.reveal .hljs{min-height:100%}.reveal .hljs table{margin:initial}.reveal .hljs-ln-code,.reveal .hljs-ln-numbers{padding:0;border:0}.reveal .hljs-ln-numbers{opacity:.6;padding-right:.75em;text-align:right;vertical-align:top}.reveal .hljs.has-highlights tr:not(.highlight-line){opacity:.4}.reveal .hljs:not(:first-child).fragment{position:absolute;top:0;left:0;width:100%;box-sizing:border-box}.reveal pre[data-auto-animate-target]{overflow:hidden}.reveal pre[data-auto-animate-target] code{height:100%}.reveal .roll{display:inline-block;line-height:1.2;overflow:hidden;vertical-align:top;perspective:400px;perspective-origin:50% 50%}.reveal .roll:hover{background:0 0;text-shadow:none}.reveal .roll span{display:block;position:relative;padding:0 2px;pointer-events:none;transition:all .4s ease;transform-origin:50% 0;transform-style:preserve-3d;-webkit-backface-visibility:hidden;backface-visibility:hidden}.reveal .roll:hover span{background:rgba(0,0,0,.5);transform:translate3d(0,0,-45px) rotateX(90deg)}.reveal .roll span:after{content:attr(data-title);display:block;position:absolute;left:0;top:0;padding:0 2px;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform-origin:50% 0;transform:translate3d(0,110%,0) rotateX(-90deg)}.reveal aside.notes{display:none}.reveal .speaker-notes{display:none;position:absolute;width:33.3333333333%;height:100%;top:0;left:100%;padding:14px 18px 14px 18px;z-index:1;font-size:18px;line-height:1.4;border:1px solid rgba(0,0,0,.05);color:#222;background-color:#f5f5f5;overflow:auto;box-sizing:border-box;text-align:left;font-family:Helvetica,sans-serif;-webkit-overflow-scrolling:touch}.reveal .speaker-notes .notes-placeholder{color:#ccc;font-style:italic}.reveal .speaker-notes:focus{outline:0}.reveal .speaker-notes:before{content:"Speaker notes";display:block;margin-bottom:10px;opacity:.5}.reveal.show-notes{max-width:75%;overflow:visible}.reveal.show-notes .speaker-notes{display:block}@media screen and (min-width:1600px){.reveal .speaker-notes{font-size:20px}}@media screen and (max-width:1024px){.reveal.show-notes{border-left:0;max-width:none;max-height:70%;max-height:70vh;overflow:visible}.reveal.show-notes .speaker-notes{top:100%;left:0;width:100%;height:42.8571428571%;height:30vh;border:0}}@media screen and (max-width:600px){.reveal.show-notes{max-height:60%;max-height:60vh}.reveal.show-notes .speaker-notes{top:100%;height:66.6666666667%;height:40vh}.reveal .speaker-notes{font-size:14px}}.zoomed .reveal *,.zoomed .reveal :after,.zoomed .reveal :before{-webkit-backface-visibility:visible!important;backface-visibility:visible!important}.zoomed .reveal .controls,.zoomed .reveal .progress{opacity:0}.zoomed .reveal .roll span{background:0 0}.zoomed .reveal .roll span:after{visibility:hidden}html.print-pdf *{-webkit-print-color-adjust:exact}html.print-pdf{width:100%;height:100%;overflow:visible}html.print-pdf body{margin:0 auto!important;border:0;padding:0;float:none!important;overflow:visible}html.print-pdf .nestedarrow,html.print-pdf .reveal .controls,html.print-pdf .reveal .playback,html.print-pdf .reveal .progress,html.print-pdf .reveal.overview,html.print-pdf .state-background{display:none!important}html.print-pdf .reveal pre code{overflow:hidden!important;font-family:Courier,"Courier New",monospace!important}html.print-pdf .reveal{width:auto!important;height:auto!important;overflow:hidden!important}html.print-pdf .reveal .slides{position:static;width:100%!important;height:auto!important;zoom:1!important;pointer-events:initial;left:auto;top:auto;margin:0!important;padding:0!important;overflow:visible;display:block;perspective:none;perspective-origin:50% 50%}html.print-pdf .reveal .slides .pdf-page{position:relative;overflow:hidden;z-index:1;page-break-after:always}html.print-pdf .reveal .slides section{visibility:visible!important;display:block!important;position:absolute!important;margin:0!important;padding:0!important;box-sizing:border-box!important;min-height:1px;opacity:1!important;transform-style:flat!important;transform:none!important}html.print-pdf .reveal section.stack{position:relative!important;margin:0!important;padding:0!important;page-break-after:avoid!important;height:auto!important;min-height:auto!important}html.print-pdf .reveal img{box-shadow:none}html.print-pdf .reveal .backgrounds{display:none}html.print-pdf .reveal .slide-background{display:block!important;position:absolute;top:0;left:0;width:100%;height:100%;z-index:auto!important}html.print-pdf .reveal.show-notes{max-width:none;max-height:none}html.print-pdf .reveal .speaker-notes-pdf{display:block;width:100%;height:auto;max-height:none;top:auto;right:auto;bottom:auto;left:auto;z-index:100}html.print-pdf .reveal .speaker-notes-pdf[data-layout=separate-page]{position:relative;color:inherit;background-color:transparent;padding:20px;page-break-after:always;border:0}html.print-pdf .reveal .slide-number-pdf{display:block;position:absolute;font-size:14px}html.print-pdf .aria-status{display:none}@media print{html:not(.print-pdf){background:#fff;width:auto;height:auto;overflow:visible}html:not(.print-pdf) body{background:#fff;font-size:20pt;width:auto;height:auto;border:0;margin:0 5%;padding:0;overflow:visible;float:none!important}html:not(.print-pdf) .controls,html:not(.print-pdf) .fork-reveal,html:not(.print-pdf) .nestedarrow,html:not(.print-pdf) .reveal .backgrounds,html:not(.print-pdf) .reveal .progress,html:not(.print-pdf) .reveal .slide-number,html:not(.print-pdf) .share-reveal,html:not(.print-pdf) .state-background{display:none!important}html:not(.print-pdf) body,html:not(.print-pdf) li,html:not(.print-pdf) p,html:not(.print-pdf) td{font-size:20pt!important;color:#000}html:not(.print-pdf) h1,html:not(.print-pdf) h2,html:not(.print-pdf) h3,html:not(.print-pdf) h4,html:not(.print-pdf) h5,html:not(.print-pdf) h6{color:#000!important;height:auto;line-height:normal;text-align:left;letter-spacing:normal}html:not(.print-pdf) h1{font-size:28pt!important}html:not(.print-pdf) h2{font-size:24pt!important}html:not(.print-pdf) h3{font-size:22pt!important}html:not(.print-pdf) h4{font-size:22pt!important;font-variant:small-caps}html:not(.print-pdf) h5{font-size:21pt!important}html:not(.print-pdf) h6{font-size:20pt!important;font-style:italic}html:not(.print-pdf) a:link,html:not(.print-pdf) a:visited{color:#000!important;font-weight:700;text-decoration:underline}html:not(.print-pdf) div,html:not(.print-pdf) ol,html:not(.print-pdf) p,html:not(.print-pdf) ul{visibility:visible;position:static;width:auto;height:auto;display:block;overflow:visible;margin:0;text-align:left!important}html:not(.print-pdf) .reveal pre,html:not(.print-pdf) .reveal table{margin-left:0;margin-right:0}html:not(.print-pdf) .reveal pre code{padding:20px}html:not(.print-pdf) .reveal blockquote{margin:20px 0}html:not(.print-pdf) .reveal .slides{position:static!important;width:auto!important;height:auto!important;left:0!important;top:0!important;margin-left:0!important;margin-top:0!important;padding:0!important;zoom:1!important;transform:none!important;overflow:visible!important;display:block!important;text-align:left!important;perspective:none;perspective-origin:50% 50%}html:not(.print-pdf) .reveal .slides section{visibility:visible!important;position:static!important;width:auto!important;height:auto!important;display:block!important;overflow:visible!important;left:0!important;top:0!important;margin-left:0!important;margin-top:0!important;padding:60px 20px!important;z-index:auto!important;opacity:1!important;page-break-after:always!important;transform-style:flat!important;transform:none!important;transition:none!important}html:not(.print-pdf) .reveal .slides section.stack{padding:0!important}html:not(.print-pdf) .reveal section:last-of-type{page-break-after:avoid!important}html:not(.print-pdf) .reveal section .fragment{opacity:1!important;visibility:visible!important;transform:none!important}html:not(.print-pdf) .reveal section img{display:block;margin:15px 0;background:#fff;border:1px solid #666;box-shadow:none}html:not(.print-pdf) .reveal section small{font-size:.8em}html:not(.print-pdf) .reveal .hljs{max-height:100%;white-space:pre-wrap;word-wrap:break-word;word-break:break-word;font-size:15pt}html:not(.print-pdf) .reveal .hljs .hljs-ln-numbers{white-space:nowrap}html:not(.print-pdf) .reveal .hljs td{font-size:inherit!important;color:inherit!important}} --------------------------------------------------------------------------------