├── packages
├── elections
│ ├── README.md
│ ├── assets
│ │ ├── fonts
│ │ │ ├── stylesheet.css
│ │ │ ├── freesans-webfont.woff2
│ │ │ └── freesansbold-webfont.woff
│ │ ├── icon.icns
│ │ ├── icons
│ │ │ ├── 128x128.png
│ │ │ ├── 16x16.png
│ │ │ ├── 24x24.png
│ │ │ ├── 256x256.png
│ │ │ ├── 32x32.png
│ │ │ ├── 48x48.png
│ │ │ ├── 512x512.png
│ │ │ ├── 64x64.png
│ │ │ ├── 96x96.png
│ │ │ └── 1024x1024.png
│ │ ├── entitlements.mac.plist
│ │ └── assets.d.ts
│ ├── .erb
│ │ ├── mocks
│ │ │ └── fileMock.js
│ │ ├── configs
│ │ │ ├── .eslintrc
│ │ │ ├── webpack.config.eslint.ts
│ │ │ ├── webpack.config.base.ts
│ │ │ ├── webpack.paths.ts
│ │ │ ├── webpack.config.renderer.dev.dll.ts
│ │ │ └── webpack.config.main.prod.ts
│ │ └── scripts
│ │ │ ├── .eslintrc
│ │ │ ├── delete-source-maps.js
│ │ │ ├── link-modules.ts
│ │ │ ├── check-node-env.js
│ │ │ ├── clean.js
│ │ │ ├── check-port-in-use.js
│ │ │ ├── electron-rebuild.js
│ │ │ ├── check-build-exists.ts
│ │ │ ├── notarize.js
│ │ │ └── check-native-dep.js
│ ├── src
│ │ ├── renderer
│ │ │ ├── CidadeCargos.module.scss
│ │ │ ├── Reset.module.scss
│ │ │ ├── fonts
│ │ │ │ ├── KumbhSans.ttf
│ │ │ │ ├── KumbhSans-Black.ttf
│ │ │ │ ├── KumbhSans-Bold.ttf
│ │ │ │ ├── KumbhSans-Light.ttf
│ │ │ │ ├── KumbhSans-Medium.ttf
│ │ │ │ ├── KumbhSans-Thin.ttf
│ │ │ │ ├── NimbusSansBold.ttf
│ │ │ │ ├── NimbusSansLight.ttf
│ │ │ │ ├── KumbhSans-Regular.ttf
│ │ │ │ ├── KumbhSans-SemiBold.ttf
│ │ │ │ ├── NimbusSansRegular.ttf
│ │ │ │ ├── KumbhSans-ExtraBold.ttf
│ │ │ │ ├── KumbhSans-ExtraLight.ttf
│ │ │ │ ├── NimbusSansUltraLight.ttf
│ │ │ │ ├── NimbusSansBoldExtended.ttf
│ │ │ │ ├── NimbusSansLightExtended.ttf
│ │ │ │ └── NimbusSansRegularExtended.ttf
│ │ │ ├── index.tsx
│ │ │ ├── index.ejs
│ │ │ ├── screens
│ │ │ │ ├── index.ts
│ │ │ │ ├── Loader.module.scss
│ │ │ │ ├── Loader.tsx
│ │ │ │ ├── NulledVotesPage
│ │ │ │ │ ├── transformers.ts
│ │ │ │ │ └── NulledVotesPage.tsx
│ │ │ │ ├── helpers.ts
│ │ │ │ ├── NullBoxesPage
│ │ │ │ │ └── transformers.ts
│ │ │ │ ├── ExposedPage
│ │ │ │ │ ├── ExposedPage.tsx
│ │ │ │ │ └── transformers.ts
│ │ │ │ └── SimuladorPage
│ │ │ │ │ └── transformers.ts
│ │ │ ├── features
│ │ │ │ ├── navigation.tsx
│ │ │ │ └── SmartPage.tsx
│ │ │ ├── App.tsx
│ │ │ ├── components
│ │ │ │ ├── Navigation.module.scss
│ │ │ │ ├── Bar.tsx
│ │ │ │ ├── Bar.module.scss
│ │ │ │ ├── helpers
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── Dropper.module.scss
│ │ │ │ └── Navigation.tsx
│ │ │ └── helpers
│ │ │ │ └── data.ts
│ │ └── main
│ │ │ ├── worker.js
│ │ │ ├── util.ts
│ │ │ ├── preload.js
│ │ │ ├── api
│ │ │ └── api.ts
│ │ │ └── data
│ │ │ └── data.ts
│ ├── .gitattributes
│ ├── .gitignore
│ ├── release
│ │ └── app
│ │ │ └── package.json
│ ├── tsconfig.json
│ └── .eslintrc.js
├── ui
│ ├── src
│ │ ├── base
│ │ │ ├── SelectorBase.tsx
│ │ │ ├── CanvasLines.module.scss
│ │ │ ├── Page.module.scss
│ │ │ ├── Loader.tsx
│ │ │ ├── Page.tsx
│ │ │ ├── Section.module.scss
│ │ │ ├── Spacer.tsx
│ │ │ ├── ListItem.module.scss
│ │ │ ├── Spacer.module.scss
│ │ │ ├── Wrapper.module.scss
│ │ │ ├── Empty.module.scss
│ │ │ ├── Wrapper.tsx
│ │ │ ├── Logo.tsx
│ │ │ ├── Tags.module.scss
│ │ │ ├── Elevation.tsx
│ │ │ ├── Loader.module.scss
│ │ │ ├── Empty.tsx
│ │ │ ├── Tags.tsx
│ │ │ ├── index.ts
│ │ │ ├── Section.tsx
│ │ │ ├── Elevation.module.scss
│ │ │ ├── ListItem.tsx
│ │ │ ├── Block.tsx
│ │ │ ├── helpers.js
│ │ │ ├── Logo.module.scss
│ │ │ ├── Selector.module.scss
│ │ │ ├── Button.tsx
│ │ │ ├── ElevatedPressable.tsx
│ │ │ ├── Button.module.scss
│ │ │ └── LineChart.module.scss
│ │ ├── dre
│ │ │ ├── common
│ │ │ │ ├── Image.module.scss
│ │ │ │ ├── Screen.tsx
│ │ │ │ ├── Controls.module.scss
│ │ │ │ ├── Key.module.scss
│ │ │ │ ├── Badge.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── Keyboard.module.scss
│ │ │ │ ├── Person.tsx
│ │ │ │ ├── Screen.module.scss
│ │ │ │ ├── Box.tsx
│ │ │ │ ├── Button.tsx
│ │ │ │ ├── SimulatorLogs.module.scss
│ │ │ │ ├── Keyboard.tsx
│ │ │ │ ├── Badge.module.scss
│ │ │ │ ├── Person.module.scss
│ │ │ │ ├── Keypad.module.scss
│ │ │ │ ├── Controls.tsx
│ │ │ │ ├── Font.tsx
│ │ │ │ ├── SimulatorSummary.tsx
│ │ │ │ ├── SimulatorVotes.tsx
│ │ │ │ ├── helpers.tsx
│ │ │ │ ├── Button.module.scss
│ │ │ │ ├── Font.module.scss
│ │ │ │ ├── Box.module.scss
│ │ │ │ ├── useCustomState.jsx
│ │ │ │ ├── Key.tsx
│ │ │ │ ├── SimulatorLogs.tsx
│ │ │ │ ├── Keypad.tsx
│ │ │ │ └── Image.tsx
│ │ │ ├── index.ts
│ │ │ ├── legacy
│ │ │ │ ├── Simulador.module.scss
│ │ │ │ ├── Elevation.tsx
│ │ │ │ ├── Elevation.module.scss
│ │ │ │ └── Button.module.old.scss
│ │ │ ├── revisited
│ │ │ │ ├── Simulador.module.scss
│ │ │ │ └── Button.module.old.scss
│ │ │ ├── hooks
│ │ │ │ └── useCustomState.jsx
│ │ │ ├── candidate.svg
│ │ │ └── candidate.tsx
│ │ └── module.ts
│ ├── global.d.ts
│ ├── tsconfig.json
│ └── package.json
├── engine
│ ├── src
│ │ ├── data
│ │ │ ├── README.md
│ │ │ ├── alternative.js
│ │ │ ├── eletronica.js
│ │ │ ├── partidos.js
│ │ │ ├── partidos copy.js
│ │ │ └── alagoas.js
│ │ ├── eleicoes
│ │ │ ├── constants.js
│ │ │ ├── investigations
│ │ │ │ ├── transition-boxes.js
│ │ │ │ ├── absent-boxes.js
│ │ │ │ ├── index.js
│ │ │ │ ├── city-info.js
│ │ │ │ └── missing-positions.js
│ │ │ └── printer
│ │ │ │ └── utils.js
│ │ └── index.js
│ └── package.json
├── codex
│ ├── src
│ │ └── integrity
│ │ │ ├── helpers
│ │ │ ├── events.ts
│ │ │ └── types.ts
│ │ │ ├── interpretation
│ │ │ ├── western-electoral-heritage.ts
│ │ │ ├── brazilian-electoral-code.ts
│ │ │ └── brazilian-electoral-court.ts
│ │ │ └── __tests__
│ │ │ └── interpretation.ts
│ ├── tsconfig.json
│ └── package.json
└── core
│ ├── index.js
│ ├── .eslintrc.js
│ ├── utils
│ ├── engine
│ │ └── situations.js
│ ├── transformers
│ │ ├── chart.js
│ │ ├── table.js
│ │ ├── filters.js
│ │ └── boxes.js
│ └── transform.js
│ └── package.json
├── assets
├── legado.png
├── screens.png
└── prototipo.png
├── .vscode
├── extensions.json
├── settings.json
├── tasks.json
└── launch.json
├── lerna.json
├── .editorconfig
├── .gitattributes
├── .gitignore
├── package.json
├── docs
└── excluidos.md
└── README.md
/packages/elections/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui/src/base/SelectorBase.tsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/elections/assets/fonts/stylesheet.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui/global.d.ts:
--------------------------------------------------------------------------------
1 | declare module "@gavetaio/ui";
2 |
--------------------------------------------------------------------------------
/packages/elections/.erb/mocks/fileMock.js:
--------------------------------------------------------------------------------
1 | export default 'test-file-stub';
2 |
--------------------------------------------------------------------------------
/assets/legado.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/assets/legado.png
--------------------------------------------------------------------------------
/assets/screens.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/assets/screens.png
--------------------------------------------------------------------------------
/assets/prototipo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/assets/prototipo.png
--------------------------------------------------------------------------------
/packages/elections/src/renderer/CidadeCargos.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: block;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Image.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .container {
2 | display: block;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/ui/src/module.ts:
--------------------------------------------------------------------------------
1 | export * from "./base/index";
2 | // @ts-ignore
3 | export * from "./dre/index";
4 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["dbaeumer.vscode-eslint", "EditorConfig.EditorConfig"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/elections/assets/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icon.icns
--------------------------------------------------------------------------------
/packages/elections/src/renderer/Reset.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: block;
3 | background-color: red;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/elections/assets/icons/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/128x128.png
--------------------------------------------------------------------------------
/packages/elections/assets/icons/16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/16x16.png
--------------------------------------------------------------------------------
/packages/elections/assets/icons/24x24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/24x24.png
--------------------------------------------------------------------------------
/packages/elections/assets/icons/256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/256x256.png
--------------------------------------------------------------------------------
/packages/elections/assets/icons/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/32x32.png
--------------------------------------------------------------------------------
/packages/elections/assets/icons/48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/48x48.png
--------------------------------------------------------------------------------
/packages/elections/assets/icons/512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/512x512.png
--------------------------------------------------------------------------------
/packages/elections/assets/icons/64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/64x64.png
--------------------------------------------------------------------------------
/packages/elections/assets/icons/96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/96x96.png
--------------------------------------------------------------------------------
/packages/elections/assets/icons/1024x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/icons/1024x1024.png
--------------------------------------------------------------------------------
/packages/engine/src/data/README.md:
--------------------------------------------------------------------------------
1 | Data coletada externamente ao repositório eleitoral (`TRE`), com o objetivo de complementar o estudo.
2 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "packages/*"
4 | ],
5 | "version": "0.0.0",
6 | "npmClient": "yarn",
7 | "useWorkspaces": true
8 | }
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans.ttf
--------------------------------------------------------------------------------
/packages/elections/assets/fonts/freesans-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/fonts/freesans-webfont.woff2
--------------------------------------------------------------------------------
/packages/ui/src/base/CanvasLines.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | position: relative;
3 | width: 800px;
4 | height: 600px;
5 | background-color: red;
6 | }
7 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/index.ts:
--------------------------------------------------------------------------------
1 | export { default as RevisitedBox } from "./revisited/Simulador";
2 | export { default as LegacyBox } from "./legacy/Simulador";
3 |
--------------------------------------------------------------------------------
/packages/elections/assets/fonts/freesansbold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/assets/fonts/freesansbold-webfont.woff
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans-Black.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans-Bold.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans-Light.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans-Medium.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans-Thin.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/NimbusSansBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/NimbusSansBold.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/NimbusSansLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/NimbusSansLight.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans-Regular.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans-SemiBold.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/NimbusSansRegular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/NimbusSansRegular.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans-ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans-ExtraBold.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/KumbhSans-ExtraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/KumbhSans-ExtraLight.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/NimbusSansUltraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/NimbusSansUltraLight.ttf
--------------------------------------------------------------------------------
/packages/elections/.erb/configs/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-console": "off",
4 | "global-require": "off",
5 | "import/no-dynamic-require": "off"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/NimbusSansBoldExtended.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/NimbusSansBoldExtended.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/NimbusSansLightExtended.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/NimbusSansLightExtended.ttf
--------------------------------------------------------------------------------
/packages/elections/src/renderer/fonts/NimbusSansRegularExtended.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gavetaio/electio/HEAD/packages/elections/src/renderer/fonts/NimbusSansRegularExtended.ttf
--------------------------------------------------------------------------------
/packages/elections/.erb/configs/webpack.config.eslint.ts:
--------------------------------------------------------------------------------
1 | /* eslint import/no-unresolved: off, import/no-self-import: off */
2 |
3 | module.exports = require('./webpack.config.renderer.dev').default;
4 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import App from './App';
4 |
5 | render( , document.getElementById('root'));
6 |
--------------------------------------------------------------------------------
/packages/codex/src/integrity/helpers/events.ts:
--------------------------------------------------------------------------------
1 | export const NO_ACTION = 'no-action';
2 | export const PARTIAL_ELECTION_REPEAT = 'partial-election-repeat';
3 | export const FULL_ELECTION_REPEAT = 'full-election-repeat';
4 |
--------------------------------------------------------------------------------
/packages/engine/src/data/alternative.js:
--------------------------------------------------------------------------------
1 | const data = `
2 | ESIO VICENTE DE MATOS, 00001943, PFL
3 | CANDIDO OTTONI, 00001717, PMDB
4 | ALBERTO OTTONI GUIMARAES, 00000068, PDT/PT
5 | Brancos, 38
6 | Nulos, 121
7 | `;
8 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-console": "off",
4 | "global-require": "off",
5 | "import/no-dynamic-require": "off",
6 | "import/no-extraneous-dependencies": "off"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Screen.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Screen.module.scss";
3 |
4 | const Screen = ({ children }: any) => (
5 |
{children}
6 | );
7 |
8 | export default Screen;
9 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Page.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: block;
3 | margin-left: var(--menu-width);
4 | min-height: 100vh;
5 | margin-top: var(--bar-height);
6 | padding: 32px;
7 | position: relative;
8 | z-index: 1;
9 | }
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=lf
2 | *.exe binary
3 | *.png binary
4 | *.jpg binary
5 | *.jpeg binary
6 | *.ico binary
7 | *.icns binary
8 | *.eot binary
9 | *.otf binary
10 | *.ttf binary
11 | *.woff binary
12 | *.woff2 binary
13 |
--------------------------------------------------------------------------------
/packages/elections/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=lf
2 | *.exe binary
3 | *.png binary
4 | *.jpg binary
5 | *.jpeg binary
6 | *.ico binary
7 | *.icns binary
8 | *.eot binary
9 | *.otf binary
10 | *.ttf binary
11 | *.woff binary
12 | *.woff2 binary
13 |
--------------------------------------------------------------------------------
/packages/engine/src/eleicoes/constants.js:
--------------------------------------------------------------------------------
1 | export const RESULTADO = {
2 | partidos: {},
3 | candidatos: {},
4 | boxes: {
5 | maior: {},
6 | menor: {},
7 | },
8 | problemas: [],
9 | coligacoes: {},
10 | multipliers: null,
11 | cargos: {},
12 | };
13 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Loader.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from './Loader.module.scss';
3 |
4 | const Loader = () => {
5 | return (
6 |
7 |
8 |
9 | );
10 | };
11 |
12 | export default Loader;
13 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Page.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from './Page.module.scss';
3 |
4 | const Page = ({ children }) => {
5 | const cls = [styles.container];
6 |
7 | return {children}
;
8 | };
9 |
10 | export default Page;
11 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Controls.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .controls {
2 | width: 100%;
3 | display: flex;
4 | align-items: flex-end;
5 | justify-content: space-between;
6 | padding: 0 calc(var(--unit) * 4) calc(var(--unit) * 8);
7 | top: calc(var(--unit) * -1);
8 | position: relative;
9 | }
10 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Section.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: block;
3 | padding-bottom: var(--unit-v-4);
4 |
5 | .header {
6 | padding-bottom: var(--unit-v-2);
7 |
8 | h4,
9 | h5,
10 | h3 {
11 | color: var(--text-alt);
12 | text-transform: uppercase;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Key.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .key {
2 | min-width: var(--key-width);
3 | height: var(--key-height);
4 | color: var(--white);
5 | margin: calc(var(--key-height) / 4);
6 | position: relative;
7 |
8 | p {
9 | margin: 0 0 0 calc(var(--key-height) / 10);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Electio — @gavetaio
6 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/delete-source-maps.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import rimraf from 'rimraf';
3 | import webpackPaths from '../configs/webpack.paths';
4 |
5 | export default function deleteSourceMaps() {
6 | rimraf.sync(path.join(webpackPaths.distMainPath, '*.js.map'));
7 | rimraf.sync(path.join(webpackPaths.distRendererPath, '*.js.map'));
8 | }
9 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/legacy/Simulador.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: block;
3 | }
4 |
5 | .logs {
6 | min-height: 200px;
7 | }
8 |
9 | .restartButton {
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | padding-top: var(--unit-v-1);
15 | padding-bottom: var(--unit-v-1);
16 | }
17 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/revisited/Simulador.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: block;
3 | }
4 |
5 | .logs {
6 | min-height: 200px;
7 | }
8 |
9 | .restartButton {
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | padding-top: var(--unit-v-1);
15 | padding-bottom: var(--unit-v-1);
16 | }
17 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Spacer.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from './Spacer.module.scss';
3 |
4 | const Spacer = ({ title }: any) => {
5 | const cls = [styles.container];
6 |
7 | return (
8 |
9 |
10 | {title && {title} }
11 |
12 |
13 | );
14 | };
15 |
16 | export default Spacer;
17 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Badge.tsx:
--------------------------------------------------------------------------------
1 | import Font from "./Font";
2 | // @ts-ignore
3 | import styles from "./Badge.module.scss";
4 |
5 | const Badge = ({ title = "Badge" }) => (
6 |
7 |
8 |
9 | {title}
10 |
11 |
12 |
13 | );
14 |
15 | export default Badge;
16 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Font } from "./Font";
2 | export { default as Keyboard } from "./Keyboard";
3 | export { default as Button } from "./Button";
4 | export { default as Screen } from "./Screen";
5 | export { default as Box } from "./Box";
6 | export { default as Keypad } from "./Keypad";
7 | export { default as Image } from "./Image";
8 | export { default as Person } from "./Person";
9 |
--------------------------------------------------------------------------------
/packages/elections/assets/entitlements.mac.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.cs.allow-unsigned-executable-memory
6 |
7 | com.apple.security.cs.allow-jit
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/link-modules.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import webpackPaths from '../configs/webpack.paths';
3 |
4 | const srcNodeModulesPath = webpackPaths.srcNodeModulesPath;
5 | const appNodeModulesPath = webpackPaths.appNodeModulesPath
6 |
7 | if (!fs.existsSync(srcNodeModulesPath) && fs.existsSync(appNodeModulesPath)) {
8 | fs.symlinkSync(appNodeModulesPath, srcNodeModulesPath, 'junction');
9 | }
10 |
--------------------------------------------------------------------------------
/packages/core/index.js:
--------------------------------------------------------------------------------
1 | export * from './utils/general';
2 | export * from './utils/transform';
3 | export * from './utils/transformers/eleicoes';
4 | export * from './utils/transformers/exposed';
5 | export * from './utils/transformers/boxes';
6 | export * from './utils/transformers/table';
7 | export * from './utils/transformers/chart';
8 | export * from './utils/transformers/filters';
9 | export * from './utils/transformers/resumo';
10 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Keyboard.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .keyboard {
2 | align-items: center;
3 | justify-content: center;
4 | display: flex;
5 | flex-wrap: wrap;
6 | flex: 1;
7 | padding-top: calc(var(--unit) * 4);
8 |
9 | > div:nth-child(1) {
10 | width: calc(var(--key-width) * 5);
11 | display: flex;
12 | flex-wrap: wrap;
13 | align-self: center;
14 | justify-content: center;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Person.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Person.module.scss";
3 |
4 | const Person = ({ className = null }) => {
5 | const cls = [styles.container];
6 |
7 | if (className) {
8 | cls.push(className);
9 | }
10 |
11 | return (
12 |
13 |
14 |
15 |
16 |
17 | );
18 | };
19 |
20 | export default Person;
21 |
--------------------------------------------------------------------------------
/packages/elections/src/main/worker.js:
--------------------------------------------------------------------------------
1 | const { Worker, isMainThread, parentPort } = require('worker_threads');
2 |
3 | module.exports = () => {
4 | if (isMainThread) {
5 | const worker = new Worker(__filename);
6 | worker.once('message', (message) => {});
7 | worker.postMessage('Hello, world!');
8 | } else {
9 | parentPort.once('message', (message) => {
10 | parentPort.postMessage(message);
11 | });
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/index.ts:
--------------------------------------------------------------------------------
1 | export { default as SimuladorPage } from './SimuladorPage/SimuladorPage';
2 | export { default as HomePage } from './HomePage';
3 | export { default as NullBoxesPage } from './NullBoxesPage/NullBoxesPage';
4 | export { default as ExposedPage } from './ExposedPage/ExposedPage';
5 | export { default as NulledVotesPage } from './NulledVotesPage/NulledVotesPage';
6 | export { default as AboutPage } from './AboutPage';
7 |
--------------------------------------------------------------------------------
/packages/ui/src/base/ListItem.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: block;
3 | margin-bottom: 24px;
4 | background-color: var(--background-darker);
5 | padding: 12px 16px;
6 | border-radius: 4px;
7 | overflow: hidden;
8 |
9 | h3 {
10 | color: var(--text-alt);
11 | }
12 | }
13 |
14 | .tags {
15 | margin-top: 4px;
16 | }
17 |
18 | .table {
19 | margin-top: 8px;
20 |
21 | section {
22 | margin-bottom: 8px;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Spacer.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | align-items: center;
4 | margin: 48px auto 32px;
5 | width: 80%;
6 |
7 | h6 {
8 | margin: 0 12px;
9 | text-transform: uppercase;
10 | color: var(--background-lighter);
11 | }
12 |
13 | hr {
14 | display: flex;
15 | flex: 1;
16 | border: none;
17 | height: 0;
18 | border-bottom: 1px solid var(--background-lighter);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Wrapper.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | max-width: 1480px;
3 | margin: 0 auto;
4 | width: 100%;
5 |
6 | > section {
7 | &:nth-last-child(1) {
8 | margin-bottom: 0px;
9 | }
10 | }
11 | }
12 |
13 | .flexRow {
14 | display: flex;
15 | flex-direction: row;
16 | align-items: center;
17 | justify-content: space-around;
18 | }
19 |
20 | .padding {
21 | padding-left: 32px;
22 | padding-right: 32px;
23 | }
24 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Empty.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | padding: var(--unit-h-3) var(--unit-v-3);
3 | text-align: center;
4 | font-weight: 600;
5 |
6 | h5 {
7 | color: var(--text-lighter);
8 | }
9 |
10 | footer {
11 | display: flex;
12 | align-items: center;
13 | justify-content: center;
14 | margin-top: var(--unit-v-3);
15 | }
16 |
17 | svg {
18 | fill: var(--text-lighter);
19 | margin-bottom: var(--unit-v-1);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Wrapper.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // @ts-ignore
3 | import styles from './Wrapper.module.scss';
4 |
5 | const Wrapper = ({ children, flexRow, padding }: any) => {
6 | const cls = [styles.container];
7 | if (flexRow) {
8 | cls.push(styles.flexRow);
9 | }
10 |
11 | if (padding) {
12 | cls.push(styles.padding);
13 | }
14 |
15 | return {children}
;
16 | };
17 |
18 | export default Wrapper;
19 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/check-node-env.js:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk';
2 |
3 | export default function checkNodeEnv(expectedEnv) {
4 | if (!expectedEnv) {
5 | throw new Error('"expectedEnv" not set');
6 | }
7 |
8 | if (process.env.NODE_ENV !== expectedEnv) {
9 | console.log(
10 | chalk.whiteBright.bgRed.bold(
11 | `"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`
12 | )
13 | );
14 | process.exit(2);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/codex/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "./lib",
4 | "baseUrl": ".",
5 | "target": "es2021",
6 | "module": "commonjs",
7 | "lib": ["dom", "esnext"],
8 | "declaration": true,
9 | "declarationMap": true,
10 | "pretty": true,
11 | "sourceMap": true,
12 | "noImplicitAny": false,
13 | "esModuleInterop": true,
14 | "allowSyntheticDefaultImports": true,
15 | "resolveJsonModule": true,
16 | "allowJs": true,
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/packages/core/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['airbnb', 'prettier'],
3 | parserOptions: {
4 | ecmaVersion: 2020,
5 | },
6 | rules: {
7 | 'import/no-extraneous-dependencies': 'off',
8 | 'react/react-in-jsx-scope': 'off',
9 | 'react/jsx-props-no-spreading': 'off',
10 | '@typescript-eslint/no-explicit-any': 'off',
11 | 'import/prefer-default-export': 'off',
12 | 'arrow-body-style': 'off',
13 | 'no-shadow': 'off',
14 | 'no-continue': 'off',
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | *.lock
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Coverage directory used by tools like istanbul
12 | coverage
13 | .eslintcache
14 |
15 | # Dependency directory
16 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
17 | node_modules
18 |
19 | # OSX
20 | .DS_Store
21 |
22 | release/app/dist
23 | release/build
24 | .erb/dll
25 |
26 | .idea
27 | npm-debug.log.*
28 | *.css.d.ts
29 | *.sass.d.ts
30 | *.scss.d.ts
31 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/clean.js:
--------------------------------------------------------------------------------
1 | import rimraf from 'rimraf';
2 | import webpackPaths from '../configs/webpack.paths.ts';
3 | import process from 'process';
4 |
5 | const args = process.argv.slice(2);
6 | const commandMap = {
7 | dist: webpackPaths.distPath,
8 | release: webpackPaths.releasePath,
9 | dll: webpackPaths.dllPath,
10 | };
11 |
12 | args.forEach((x) => {
13 | const pathToRemove = commandMap[x];
14 | if (pathToRemove !== undefined) {
15 | rimraf.sync(pathToRemove);
16 | }
17 | });
18 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Screen.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .screen {
2 | background-color: var(--screen);
3 | transition: background-color 50ms ease-in-out;
4 | width: var(--screen-width);
5 | height: var(--screen-height);
6 | position: relative;
7 | margin: calc(var(--unit) * 6);
8 | border: 1px solid var(--border);
9 | padding: calc(var(--unit) / 4);
10 | flex-shrink: 0;
11 | display: flex;
12 |
13 | h2,
14 | p,
15 | strong {
16 | transition: color 50ms ease-in-out;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/check-port-in-use.js:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk';
2 | import detectPort from 'detect-port';
3 |
4 | const port = process.env.PORT || '1212';
5 |
6 | detectPort(port, (err, availablePort) => {
7 | if (port !== String(availablePort)) {
8 | throw new Error(
9 | chalk.whiteBright.bgRed.bold(
10 | `Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 npm start`
11 | )
12 | );
13 | } else {
14 | process.exit(0);
15 | }
16 | });
17 |
--------------------------------------------------------------------------------
/packages/elections/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Coverage directory used by tools like istanbul
11 | coverage
12 | .eslintcache
13 |
14 | # Dependency directory
15 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
16 | node_modules
17 |
18 | # OSX
19 | .DS_Store
20 |
21 | release/app/dist
22 | release/build
23 | .erb/dll
24 |
25 | .idea
26 | npm-debug.log.*
27 | *.css.d.ts
28 | *.sass.d.ts
29 | *.scss.d.ts
30 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Logo.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Logo.module.scss";
3 |
4 | export default function Logo({ canClip = true, circled = false }: any) {
5 | const cls = [styles.container];
6 |
7 | if (!canClip) {
8 | cls.push(styles.noclip);
9 | }
10 |
11 | if (circled) {
12 | cls.push(styles.circled);
13 | }
14 |
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/packages/ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "./lib",
4 | "baseUrl": ".",
5 | "target": "es2021",
6 | "module": "commonjs",
7 | "lib": ["dom", "esnext"],
8 | "declaration": true,
9 | "declarationMap": true,
10 | "jsx": "react-jsx",
11 | "pretty": true,
12 | "sourceMap": true,
13 | "noImplicitAny": false,
14 | "moduleResolution": "node",
15 | "esModuleInterop": true,
16 | "allowSyntheticDefaultImports": true,
17 | "resolveJsonModule": true,
18 | "allowJs": true
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/Loader.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | right: 0;
6 | bottom: 0;
7 | z-index: 4001;
8 | background-color: rgba(0, 0, 0, 0.75);
9 | display: flex;
10 | align-items: center;
11 | justify-content: center;
12 | }
13 |
14 | .content {
15 | display: block;
16 | text-align: center;
17 |
18 | h3 {
19 | margin-top: var(--unit-xxl);
20 | margin-bottom: var(--unit-s);
21 | }
22 | small {
23 | font-family: 'Courier New', Courier, monospace;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/engine/src/eleicoes/investigations/transition-boxes.js:
--------------------------------------------------------------------------------
1 | const { forEachList } = require("../helpers");
2 | const { LoggerSingleton } = require("../../log");
3 |
4 | const { log } = LoggerSingleton.getInstance();
5 |
6 | export const investigateTransitionBoxes = ({ resultados, boxes, callback }) => {
7 | let total = 0;
8 |
9 | forEachList(boxes, (id, data) => {
10 | const { transition } = data;
11 | if (!transition) {
12 | return;
13 | }
14 | total += 1;
15 | });
16 |
17 | if (total) {
18 | log(`TRANSITION BOXES ${total}`);
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/packages/elections/src/main/util.ts:
--------------------------------------------------------------------------------
1 | import { URL } from 'url';
2 | import path from 'path';
3 |
4 | export let resolveHtmlPath: (htmlFileName: string) => string;
5 |
6 | if (process.env.NODE_ENV === 'development') {
7 | const port = process.env.PORT || 1212;
8 | resolveHtmlPath = (htmlFileName: string) => {
9 | const url = new URL(`http://localhost:${port}`);
10 | url.pathname = htmlFileName;
11 | return url.href;
12 | };
13 | } else {
14 | resolveHtmlPath = (htmlFileName: string) => {
15 | return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`;
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | ".eslintrc": "jsonc",
4 | ".prettierrc": "jsonc",
5 | ".eslintignore": "ignore"
6 | },
7 |
8 | "javascript.validate.enable": false,
9 | "javascript.format.enable": false,
10 | "typescript.format.enable": false,
11 |
12 | "search.exclude": {
13 | ".git": true,
14 | ".eslintcache": true,
15 | ".erb/dll": true,
16 | "release/{build,app/dist}": true,
17 | "node_modules": true,
18 | "npm-debug.log.*": true,
19 | "test/**/__snapshots__": true,
20 | "package-lock.json": true,
21 | "*.{css,sass,scss}.d.ts": true
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Box.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | // @ts-ignore
3 | import styles from "./Box.module.scss";
4 |
5 | const Box = React.forwardRef(({ children, className }: any, ref: any) => {
6 | const cls = [styles.container, "electio-sim"];
7 |
8 | if (className) {
9 | cls.push(className);
10 | }
11 |
12 | if (className)
13 | return (
14 |
15 |
16 |
17 | {children}
18 |
19 |
20 |
21 | );
22 | });
23 |
24 | export default Box;
25 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Button.tsx:
--------------------------------------------------------------------------------
1 | import { ElevatedPressable } from "../../base";
2 | import Font from "./Font";
3 | // @ts-ignore
4 | import styles from "./Button.module.scss";
5 |
6 | const Button = ({ onLongPress, onClick, type = "white", children }: any) => {
7 | const cls = [styles.button, styles[type]];
8 |
9 | return (
10 |
15 |
16 | {children}
17 |
18 |
19 | );
20 | };
21 |
22 | export default Button;
23 |
--------------------------------------------------------------------------------
/packages/elections/release/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "electron-react-boilerplate",
3 | "productName": "electron-react-boilerplate",
4 | "version": "4.3.1",
5 | "description": "Electron application boilerplate based on React, React Router, Webpack, React Hot Loader for rapid application development",
6 | "main": "./dist/main/main.js",
7 | "scripts": {
8 | "electron-rebuild": "node -r ts-node/register ../../.erb/scripts/electron-rebuild.js",
9 | "link-modules": "node -r ts-node/register ../../.erb/scripts/link-modules.ts",
10 | "postinstall": "npm run electron-rebuild && npm run link-modules"
11 | },
12 | "license": "MIT"
13 | }
14 |
--------------------------------------------------------------------------------
/packages/elections/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2021",
4 | "module": "commonjs",
5 | "lib": ["dom", "esnext"],
6 | "declaration": true,
7 | "declarationMap": true,
8 | "jsx": "react-jsx",
9 | "pretty": true,
10 | "sourceMap": true,
11 | "baseUrl": "./src",
12 | "noImplicitAny": false,
13 | "moduleResolution": "node",
14 | "esModuleInterop": true,
15 | "allowSyntheticDefaultImports": true,
16 | "resolveJsonModule": true,
17 | "allowJs": true,
18 | "outDir": "release/app/dist"
19 | },
20 | "exclude": ["test", "release/build", "release/app/dist", ".erb/dll"]
21 | }
22 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Tags.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | list-style: none;
3 | display: flex;
4 | flex-direction: row;
5 |
6 | li {
7 | display: block;
8 | background-color: var(--background);
9 | padding: 0 8px;
10 | border-radius: 2px;
11 | display: flex;
12 | flex-direction: row;
13 | align-items: center;
14 | margin-right: 4px;
15 | margin-bottom: 4px;
16 | }
17 |
18 | .danger {
19 | background-color: var(--background-rouge);
20 | }
21 |
22 | .warning {
23 | background-color: var(--background-jaune);
24 | }
25 | }
26 |
27 | .number {
28 | font-weight: 800;
29 | margin-right: 4px;
30 | }
31 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "type": "npm",
6 | "label": "Start Webpack Dev",
7 | "script": "start:renderer",
8 | "options": {
9 | "cwd": "${workspaceFolder}"
10 | },
11 | "isBackground": true,
12 | "problemMatcher": {
13 | "owner": "custom",
14 | "pattern": {
15 | "regexp": "____________"
16 | },
17 | "background": {
18 | "activeOnStart": true,
19 | "beginsPattern": "Compiling\\.\\.\\.$",
20 | "endsPattern": "(Compiled successfully|Failed to compile)\\.$"
21 | }
22 | }
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/packages/elections/assets/assets.d.ts:
--------------------------------------------------------------------------------
1 | type Styles = Record;
2 |
3 | declare module '*.svg' {
4 | const content: string;
5 | export default content;
6 | }
7 |
8 | declare module '*.png' {
9 | const content: string;
10 | export default content;
11 | }
12 |
13 | declare module '*.jpg' {
14 | const content: string;
15 | export default content;
16 | }
17 |
18 | declare module '*.scss' {
19 | const content: Styles;
20 | export default content;
21 | }
22 |
23 | declare module '*.sass' {
24 | const content: Styles;
25 | export default content;
26 | }
27 |
28 | declare module '*.css' {
29 | const content: Styles;
30 | export default content;
31 | }
32 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@gavetaio/electio",
3 | "version": "1.0.0",
4 | "description": "@gavetaio — investigação eleitoral",
5 | "main": "index.js",
6 | "license": "MIT",
7 | "private": true,
8 | "workspaces": [
9 | "packages/*"
10 | ],
11 | "scripts": {
12 | "start": "lerna run --parallel start",
13 | "codex:integrity-test": "lerna run --parallel --scope @gavetaio/codex test",
14 | "build": "lerna run --parallel --scope @gavetaio/election-app build",
15 | "post": "lerna run --parallel --scope @gavetaio/election-app neverpostinstall"
16 | },
17 | "devDependencies": {
18 | "lerna": "^4.0.0",
19 | "typescript": "^4.5.4"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/packages/core/utils/engine/situations.js:
--------------------------------------------------------------------------------
1 | export const isRemovido = (situacao) => {
2 | if (situacao > 1) {
3 | return true;
4 | }
5 | return false;
6 | };
7 |
8 | export const isRecursado = ({ urna, pleito, atual }) => {
9 | if (pleito?.match(/sub(.)j[uú]dice/gim)) {
10 | return true;
11 | }
12 |
13 | if (
14 | urna.match(/^indeferido(.*)recurso$/gim) &&
15 | !pleito.match(/^deferido/gim)
16 | ) {
17 | return true;
18 | }
19 |
20 | return false;
21 | };
22 |
23 | export const isUrnado = ({ pleito }) => {
24 | if (
25 | pleito.match(/^(indeferido|cassado|ren[úu]ncia|falecido|cancelado)$/gim)
26 | ) {
27 | return true;
28 | }
29 | return false;
30 | };
31 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Elevation.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Elevation.module.scss";
3 |
4 | const Elevation = ({
5 | children,
6 | caseColor,
7 | darkColor,
8 | pressed = false,
9 | }: any) => {
10 | const style: any = {
11 | "--elevation-bg-case": caseColor,
12 | "--elevation-bg-dark": darkColor,
13 | "--elevation-state": pressed ? "0.75" : "0",
14 | };
15 |
16 | const cls = [styles.container];
17 |
18 | if (pressed) {
19 | cls.push(styles.pressed);
20 | }
21 |
22 | return (
23 |
26 | );
27 | };
28 |
29 | export default Elevation;
30 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Loader.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | height: 72px;
6 |
7 | span {
8 | display: block;
9 | border: 4px solid #fff;
10 | opacity: 1;
11 | border-radius: 50%;
12 | animation: ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
13 | }
14 |
15 | span:nth-child(2) {
16 | animation-delay: -0.5s;
17 | }
18 | }
19 |
20 | @keyframes ripple {
21 | 0% {
22 | top: 36px;
23 | left: 36px;
24 | width: 0;
25 | height: 0;
26 | opacity: 1;
27 | }
28 | 100% {
29 | top: 0px;
30 | left: 0px;
31 | width: 72px;
32 | height: 72px;
33 | opacity: 0;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/SimulatorLogs.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .container {
2 | display: block;
3 | background-color: var(--background-dark);
4 | }
5 |
6 | :global(#sim-urna) .item {
7 | display: flex;
8 | align-items: center;
9 |
10 | li,
11 | span,
12 | strong,
13 | p,
14 | label {
15 | color: var(--text-primary);
16 | }
17 |
18 | label {
19 | min-width: 300px;
20 | }
21 |
22 | ul {
23 | list-style: none;
24 | }
25 |
26 | li {
27 | display: inline-block;
28 | margin-right: 8px;
29 | background-color: var(--background);
30 | padding: 2px 4px;
31 | border-radius: 4px;
32 |
33 | span {
34 | margin-right: 4px;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/Loader.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { LayoutContext } from 'renderer/context/layout';
3 | import styles from './Loader.module.scss';
4 | import { Loader } from '@gavetaio/ui';
5 |
6 | const LoaderScreen = () => {
7 | const { getLayout }: any = useContext(LayoutContext);
8 | const { loader } = getLayout();
9 |
10 | if (!loader?.visible) {
11 | return null;
12 | }
13 |
14 | return (
15 |
16 |
17 |
18 |
{loader.title}
19 | {loader.text}
20 |
21 |
22 | );
23 | };
24 |
25 | export default LoaderScreen;
26 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Empty.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Empty.module.scss";
3 | import Button from "./Button";
4 | import { DesktopDownloadIcon } from "@primer/octicons-react";
5 |
6 | const Empty = ({
7 | message = "Para visualizar esta página, carregue os dados de pelo menos um ciclo eleitoral com problemas.",
8 | action = null,
9 | label = "Carregar Dados",
10 | Icon = DesktopDownloadIcon,
11 | }) => {
12 | return (
13 |
14 | {Icon && }
15 |
{message}
16 | {action && (
17 |
20 | )}
21 |
22 | );
23 | };
24 |
25 | export default Empty;
26 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/legacy/Elevation.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from "react";
2 | // @ts-ignore
3 | import styles from "./Elevation.module.scss";
4 |
5 | const Elevation = ({
6 | children,
7 | caseColor,
8 | darkColor,
9 | pressed = false,
10 | }: any) => {
11 | const style = {
12 | "--elevation-bg-case": caseColor,
13 | "--elevation-bg-dark": darkColor,
14 | "--elevation-state": pressed ? "0.75" : "0",
15 | } as CSSProperties;
16 |
17 | const cls = [styles.container];
18 |
19 | if (pressed) {
20 | cls.push(styles.pressed);
21 | }
22 |
23 | return (
24 |
27 | );
28 | };
29 |
30 | export default Elevation;
31 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/electron-rebuild.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { execSync } from 'child_process';
3 | import fs from 'fs';
4 | import { dependencies } from '../../release/app/package.json';
5 | import webpackPaths from '../configs/webpack.paths';
6 |
7 | if (
8 | Object.keys(dependencies || {}).length > 0 &&
9 | fs.existsSync(webpackPaths.appNodeModulesPath)
10 | ) {
11 | const electronRebuildCmd =
12 | '../../node_modules/.bin/electron-rebuild --parallel --force --types prod,dev,optional --module-dir .';
13 | const cmd =
14 | process.platform === 'win32'
15 | ? electronRebuildCmd.replace(/\//g, '\\')
16 | : electronRebuildCmd;
17 | execSync(cmd, {
18 | cwd: webpackPaths.appPath,
19 | stdio: 'inherit',
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Tags.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/destructuring-assignment */
2 | // @ts-ignore
3 | import styles from './Tags.module.scss';
4 |
5 | export const Tag = ({ label, type, number = null }: any) => {
6 | const cls = [];
7 | if (type) {
8 | cls.push(styles[type]);
9 | }
10 | return (
11 |
12 | {number !== null && {number} }
13 | {label}
14 |
15 | );
16 | };
17 |
18 | const Tags = ({ items }: any) => {
19 | return (
20 |
21 | {items?.length &&
22 | items.map((item) => {
23 | return ;
24 | })}
25 |
26 | );
27 | };
28 |
29 | export default Tags;
30 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Electron: Main",
6 | "type": "node",
7 | "request": "launch",
8 | "protocol": "inspector",
9 | "runtimeExecutable": "npm",
10 | "runtimeArgs": [
11 | "run start:main --inspect=5858 --remote-debugging-port=9223"
12 | ],
13 | "preLaunchTask": "Start Webpack Dev"
14 | },
15 | {
16 | "name": "Electron: Renderer",
17 | "type": "chrome",
18 | "request": "attach",
19 | "port": 9223,
20 | "webRoot": "${workspaceFolder}",
21 | "timeout": 15000
22 | }
23 | ],
24 | "compounds": [
25 | {
26 | "name": "Electron: All",
27 | "configurations": ["Electron: Main", "Electron: Renderer"]
28 | }
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/packages/engine/src/data/eletronica.js:
--------------------------------------------------------------------------------
1 | const data1996 = `AM;MANAUS
2 | AP;MACAPA
3 | BA;FEIRA DE SANTANA;SALVADOR
4 | CE;FORTALEZA
5 | ES;VITORIA
6 | GO;GOIANIA
7 | MA;SAO LUIS
8 | MG;UBERLANDIA;BELO HORIZONTE;CONTAGEM;JUIZ DE FORA
9 | MS;CAMPO GRANDE
10 | MT;CUIABA
11 | PA;BELEM
12 | PB;CAMPINA GRANDE;JOAO PESSOA
13 | PE;JABOATAO;OLINDA;RECIFE
14 | PI;TERESINA
15 | PR;CURITIBA;LONDRINA
16 | RJ;NOVA IGUACU;BELFORD ROXO;CAMPOS;DUQUE DE CAXIAS;SAO GONCALO;SAO JOAO DE MERITI;RIO DE JANEIRO;NITEROI
17 | RN;NATAL
18 | RO;PORTO VELHO
19 | RR;BOA VISTA
20 | RS;CAXIAS DO SUL;PELOTAS;PORTO ALEGRE
21 | SC;JOINVILLE;BRUSQUE;FLORIANOPOLIS
22 | SE;ARACAJU
23 | SP;DIADEMA;GUARULHOS;JUNDIAI;OSASCO;RIBEIRAO PRETO;SANTO ANDRE;SANTOS;SAO BERNARDO DO CAMPO;SAO JOSE DO RIO PRETO;SAO JOSE DOS CAMPOS;SAO PAULO;SOROCABA;CAMPINAS
24 | TO;PALMAS`;
25 |
--------------------------------------------------------------------------------
/packages/codex/src/integrity/interpretation/western-electoral-heritage.ts:
--------------------------------------------------------------------------------
1 | import { ElectoralIntegrityData } from '../helpers/types';
2 | import {
3 | NO_ACTION,
4 | PARTIAL_ELECTION_REPEAT,
5 | FULL_ELECTION_REPEAT,
6 | } from '../helpers/events';
7 |
8 | class WesternElectoralHeritage {
9 | shouldRepeatElection(electionData: ElectoralIntegrityData) {
10 | const {
11 | canInvalidatedVotesChangeElectionResult,
12 | canPartialElectionRepeatRemedyElectionResult,
13 | } = electionData;
14 |
15 | if (canInvalidatedVotesChangeElectionResult === false) {
16 | return NO_ACTION;
17 | }
18 |
19 | if (canPartialElectionRepeatRemedyElectionResult) {
20 | return PARTIAL_ELECTION_REPEAT;
21 | }
22 |
23 | return FULL_ELECTION_REPEAT;
24 | }
25 | }
26 |
27 | export default WesternElectoralHeritage;
28 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/check-build-exists.ts:
--------------------------------------------------------------------------------
1 | // Check if the renderer and main bundles are built
2 | import path from 'path';
3 | import chalk from 'chalk';
4 | import fs from 'fs';
5 | import webpackPaths from '../configs/webpack.paths';
6 |
7 | const mainPath = path.join(webpackPaths.distMainPath, 'main.js');
8 | const rendererPath = path.join(webpackPaths.distRendererPath, 'renderer.js');
9 |
10 | if (!fs.existsSync(mainPath)) {
11 | throw new Error(
12 | chalk.whiteBright.bgRed.bold(
13 | 'The main process is not built yet. Build it by running "npm run build:main"'
14 | )
15 | );
16 | }
17 |
18 | if (!fs.existsSync(rendererPath)) {
19 | throw new Error(
20 | chalk.whiteBright.bgRed.bold(
21 | 'The renderer process is not built yet. Build it by running "npm run build:renderer"'
22 | )
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/packages/ui/src/base/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Button } from "./Button";
2 | export { default as ListItem } from "./ListItem";
3 | export { default as Loader } from "./Loader";
4 | export { default as Logo } from "./Logo";
5 | export { default as Page } from "./Page";
6 | export { default as Selector } from "./Selector";
7 | export { default as Spacer } from "./Spacer";
8 | export { default as Table } from "./Table";
9 | export { default as Tags } from "./Tags";
10 | export { default as Wrapper } from "./Wrapper";
11 | export { default as Elevation } from "./Elevation";
12 | export { default as LineChart } from "./LineChart";
13 | export { default as Block } from "./Block";
14 | export { default as ElevatedPressable } from "./ElevatedPressable";
15 | export { default as Section } from "./Section";
16 | export { default as Empty } from "./Empty";
17 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Keyboard.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Keyboard.module.scss";
3 | import Key from "./Key";
4 | const KEYS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];
5 |
6 | const Keyboard = ({ onKeyPress, controls, handleAction = null }: any) => {
7 | const onKeyPressHandler = (number) => {
8 | if (!handleAction) {
9 | onKeyPress(number);
10 | return;
11 | }
12 |
13 | handleAction(onKeyPress(number));
14 | };
15 |
16 | return (
17 |
18 |
19 | {KEYS.map((key) => (
20 |
21 | {key}
22 |
23 | ))}
24 |
25 | {controls()}
26 |
27 | );
28 | };
29 |
30 | export default Keyboard;
31 |
--------------------------------------------------------------------------------
/packages/engine/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@gavetaio/engine",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "src/index.js",
6 | "module": "src/index.js",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "@gavetaio",
11 | "license": "ISC",
12 | "dependencies": {
13 | "array-unique": "^0.3.2",
14 | "react": "^18.1.0",
15 | "react-dom": "^18.1.0"
16 | },
17 | "devDependencies": {
18 | "eslint": "^8.6.0",
19 | "eslint-config-airbnb-base": "^15.0.0",
20 | "eslint-config-erb": "^4.0.0-alpha.0",
21 | "eslint-plugin-compat": "^4.0.1",
22 | "eslint-plugin-import": "^2.25.4",
23 | "eslint-plugin-jsx-a11y": "^6.5.1",
24 | "eslint-plugin-promise": "^6.0.0",
25 | "eslint-plugin-react": "^7.28.0",
26 | "eslint-plugin-react-hooks": "^4.3.0",
27 | "typescript-plugin-css-modules": "^3.4.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/core/utils/transformers/chart.js:
--------------------------------------------------------------------------------
1 | export const chartObjectToData = (chart) => {
2 | const keys = Object.keys(chart);
3 |
4 | const lines = [];
5 | if (keys?.length) {
6 | keys.forEach((key) => {
7 | const line = { label: key, points: [] };
8 | const keys = Object.keys(chart[key]);
9 | keys.forEach((k) => {
10 | const { count, total } = chart[key][k];
11 | let value = count;
12 | if (total) {
13 | value = count / total;
14 | }
15 | line.points.push([k, value]);
16 | });
17 | if (line?.points?.length) {
18 | lines.push(line);
19 | }
20 | });
21 | }
22 |
23 | return { data: lines };
24 | };
25 |
26 | export const createChartObject = ({ x, y, data }) => {
27 | const dataObj = Array.isArray(data) ? { data } : chartObjectToData(data);
28 | return {
29 | ...dataObj,
30 | labelX: x,
31 | labelY: y,
32 | };
33 | };
34 |
--------------------------------------------------------------------------------
/packages/codex/src/integrity/helpers/types.ts:
--------------------------------------------------------------------------------
1 | export type ElectoralIntegrityVotes = {
2 | blank: number;
3 | anulled: number;
4 | invalidated: number;
5 | valid: number;
6 | nominal: number;
7 | party: number;
8 | total: number;
9 | };
10 |
11 | export type ElectoralIntegrityData = {
12 | name: string;
13 | type: 'majoritarian' | 'proportional';
14 | voters: number;
15 | votes: ElectoralIntegrityVotes;
16 | repeatEvent: 'partial-election-repeat' | 'full-election-repeat' | 'no-action';
17 | pollingStations: number;
18 | invalidatedPollingStations: number;
19 | canInvalidatedVotesChangeElectionResult: boolean;
20 | canPartialElectionRepeatRemedyElectionResult: boolean;
21 | minimalVoteLossToChangeElectoralResult: null | number;
22 | wasMajoritarianElectedCandidateInvalidated?: undefined | boolean;
23 | };
24 |
25 | export interface ElectoralIntegrityClass {
26 | shouldRepeatElection: (electionData: ElectoralIntegrityData) => string;
27 | }
28 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/notarize.js:
--------------------------------------------------------------------------------
1 | const { notarize } = require('electron-notarize');
2 | const { build } = require('../../package.json');
3 |
4 | exports.default = async function notarizeMacos(context) {
5 | const { electronPlatformName, appOutDir } = context;
6 | if (electronPlatformName !== 'darwin') {
7 | return;
8 | }
9 |
10 | if (!process.env.CI) {
11 | console.warn('Skipping notarizing step. Packaging is not running in CI');
12 | return;
13 | }
14 |
15 | if (!('APPLE_ID' in process.env && 'APPLE_ID_PASS' in process.env)) {
16 | console.warn('Skipping notarizing step. APPLE_ID and APPLE_ID_PASS env variables must be set');
17 | return;
18 | }
19 |
20 | const appName = context.packager.appInfo.productFilename;
21 |
22 | await notarize({
23 | appBundleId: build.appId,
24 | appPath: `${appOutDir}/${appName}.app`,
25 | appleId: process.env.APPLE_ID,
26 | appleIdPassword: process.env.APPLE_ID_PASS,
27 | });
28 | };
29 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Badge.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .badge {
2 | --badge-height: calc(var(--unit) * 24);
3 | --badge-gap: calc(var(--unit) * 4);
4 | --font-badge: 2;
5 |
6 | width: 100%;
7 | height: var(--badge-height);
8 | display: flex;
9 | align-items: center;
10 | border: none;
11 | justify-content: center;
12 | padding: 0 calc(var(--unit) * 6);
13 |
14 | h2 {
15 | text-transform: uppercase;
16 | text-align: left;
17 | padding: calc(var(--unit) * 2) calc(var(--unit) * 8);
18 | padding-top: calc(var(--unit) * 2 + 2px);
19 | border-bottom: 2px solid #000;
20 | background-color: var(--color-key);
21 | border-radius: 4px;
22 |
23 | &:nth-child(1) {
24 | letter-spacing: calc(var(--font-body) * -0.05);
25 | font-weight: 600;
26 | }
27 | &:nth-child(2) {
28 | letter-spacing: calc(var(--font-body) * -0.05);
29 | font-weight: 400;
30 | margin-top: var(--unit);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Person.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .container {
2 | --person-width: calc(var(--thumb-width) - 2px);
3 | --person-height: calc(var(--thumb-height) - 2px);
4 |
5 | display: block;
6 | height: var(--person-height);
7 | width: var(--person-width);
8 | background-color: transparent;
9 | position: relative;
10 | overflow: hidden;
11 |
12 | span {
13 | display: block;
14 | position: absolute;
15 | }
16 |
17 | span:nth-child(2) {
18 | display: block;
19 | background-color: #cfcfcf;
20 | border-radius: 50%;
21 | left: calc(var(--person-width) * 0.25);
22 | top: calc(var(--person-height) * 0.075);
23 | width: calc(var(--person-width) * 0.5);
24 | height: calc(var(--person-width) * 0.5);
25 | }
26 |
27 | span:nth-child(3) {
28 | display: block;
29 | background-color: #999999;
30 | height: 80%;
31 | width: 90%;
32 | bottom: -35%;
33 | left: 5%;
34 | border-top-right-radius: 50%;
35 | border-top-left-radius: 50%;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Keypad.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .keypad {
2 | --dre-font-family: var(--keypad-font-family);
3 | background-color: var(--keypad);
4 | position: relative;
5 | margin: calc(var(--unit) * 6);
6 | border: calc(var(--unit) / 2) solid var(--border);
7 | width: var(--keypad-width);
8 | height: 100%;
9 |
10 | > header {
11 | height: calc(var(--unit) * 20);
12 | background-color: white;
13 | font-weight: bold;
14 | display: flex;
15 | align-items: center;
16 | justify-content: center;
17 |
18 | h2 {
19 | font-weight: 600;
20 | }
21 | }
22 |
23 | > div {
24 | flex: 1;
25 | }
26 | }
27 |
28 | .carbon {
29 | background: radial-gradient(black 6%, transparent 12%) 0 0,
30 | radial-gradient(black 6%, transparent 12%) 6px 6px,
31 | radial-gradient(rgba(255, 255, 255, 0.1) 6%, transparent 10%) 0 1px,
32 | radial-gradient(rgba(255, 255, 255, 0.1) 6%, transparent 10%) 6px 7px;
33 | background-color: #282828;
34 | background-size: 12px 12px;
35 | }
36 |
--------------------------------------------------------------------------------
/packages/core/utils/transform.js:
--------------------------------------------------------------------------------
1 | import { deepClone } from './general';
2 |
3 | export const transformGraphLegacy = (chart) => {
4 | if (!chart?.data) {
5 | return null;
6 | }
7 |
8 | const cloned = deepClone(chart);
9 |
10 | if (cloned?.labels?.length) {
11 | const lines = [];
12 | cloned.data.forEach((item) => {
13 | const line = [];
14 | cloned.labels.forEach((label, index) => {
15 | line.push([label, item.data[index]]);
16 | });
17 | lines.push(line);
18 | });
19 |
20 | cloned.data = lines;
21 | }
22 |
23 | return cloned;
24 | };
25 |
26 | export const getDataObject = (list, initial) => {
27 | const getInitial = (item) => {
28 | if (initial?.length) {
29 | return initial.indexOf(item) !== -1;
30 | }
31 | if (!initial) {
32 | return false;
33 | }
34 | return true;
35 | };
36 |
37 | return list.map((item) => {
38 | return {
39 | value: item,
40 | label: item,
41 | selected: getInitial(item),
42 | };
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/packages/engine/src/eleicoes/investigations/absent-boxes.js:
--------------------------------------------------------------------------------
1 | const { forEachList, getOtherBox } = require("@gavetaio/core");
2 |
3 | export const investigateAbsentBoxes = ({ resultados, boxes, callback }) => {
4 | forEachList(boxes, (id, data) => {
5 | const { turno, scope, codigo, absolutos, municipio } = data;
6 | const { tamanho, aptos } = absolutos;
7 |
8 | if (!aptos) {
9 | return;
10 | }
11 |
12 | const presence = ((100 * tamanho) / aptos).toFixed(2);
13 |
14 | if (presence < 30) {
15 | const other = getOtherBox(data, boxes);
16 |
17 | const extra = {
18 | codigo,
19 | aptos,
20 | tamanho,
21 | municipio,
22 | };
23 |
24 | if (other) {
25 | extra.other = {
26 | tamanho: other.absolutos.tamanho,
27 | };
28 | }
29 |
30 | callback({
31 | turno,
32 | scope,
33 | path: `boxes.faltantes`,
34 | push: {
35 | id,
36 | count: presence,
37 | extra,
38 | },
39 | });
40 | }
41 | });
42 | };
43 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/features/navigation.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/prefer-default-export */
2 | import { useCallback } from 'react';
3 | import {
4 | useParams,
5 | useNavigate,
6 | useResolvedPath,
7 | useLocation,
8 | } from 'react-router-dom';
9 |
10 | const scrollTop = () => {
11 | const el = document.querySelector('html');
12 | el.scrollTo({
13 | top: 0,
14 | });
15 | };
16 |
17 | export const useNavigation = () => {
18 | const { pathname: url } = useLocation();
19 |
20 | const history = useNavigate();
21 |
22 | const navigate = useCallback(
23 | (to, params = null) => {
24 | if (params?.event) {
25 | params.event.preventDefault();
26 | }
27 |
28 | if (to.match(/^\//gim)) {
29 | scrollTop();
30 | history(to);
31 | return;
32 | }
33 | scrollTop();
34 | history(`${url}/${to}`);
35 | },
36 | [history, url]
37 | );
38 |
39 | const getRoute = useCallback(() => {
40 | return url;
41 | }, [url]);
42 |
43 | return {
44 | navigate,
45 | getRoute,
46 | };
47 | };
48 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Section.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Section.module.scss";
3 |
4 | const Section = ({ title, description, type = null, children = null }: any) => {
5 | const cls = [styles.container];
6 |
7 | if (type) {
8 | cls.push(styles[type]);
9 | }
10 |
11 | if (type) {
12 | cls.push(styles[type]);
13 | }
14 |
15 | const renderTitle = () => {
16 | if (!title) {
17 | return null;
18 | }
19 | if (type === "main") {
20 | return {title} ;
21 | }
22 | if (type === "small") {
23 | return {title} ;
24 | }
25 |
26 | return {title} ;
27 | };
28 |
29 | const renderedTitle = renderTitle();
30 |
31 | return (
32 |
33 | {renderedTitle && (
34 |
35 | )}
36 |
37 | {description &&
{description} }
38 | {children}
39 |
40 |
41 | );
42 | };
43 |
44 | export default Section;
45 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Controls.tsx:
--------------------------------------------------------------------------------
1 | import Button from "./Button";
2 | // @ts-ignore
3 | import styles from "./Controls.module.scss";
4 |
5 | const Controls = ({
6 | handleAction,
7 | onBlankPress,
8 | onBlankLongPress,
9 | onFixPress,
10 | onFixLongPress,
11 | onConfirmPress,
12 | onConfirmLongPress,
13 | }: any) => {
14 | return (
15 |
16 |
21 | BRANCO
22 |
23 |
24 | CORRIGE
25 |
26 | {
29 | if (handleAction) {
30 | handleAction(onConfirmPress());
31 | return;
32 | }
33 | onConfirmPress();
34 | }}
35 | type="action"
36 | >
37 | CONFIRMA
38 |
39 |
40 | );
41 | };
42 |
43 | export default Controls;
44 |
--------------------------------------------------------------------------------
/packages/elections/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: 'erb',
3 | rules: {
4 | 'import/no-extraneous-dependencies': 'off',
5 | 'react/react-in-jsx-scope': 'off',
6 | 'react/jsx-props-no-spreading': 'off',
7 | '@typescript-eslint/no-explicit-any': 'off',
8 | 'import/prefer-default-export': 'off',
9 | 'class-methods-use-this': 'off',
10 | '@typescript-eslint/ban-ts-comment': 'off',
11 | 'no-continue': 'off',
12 | 'react-hooks/exhaustive-deps': 'off',
13 | '@typescript-eslint/naming-convention': 'off',
14 | 'react/jsx-no-target-blank': 'off',
15 | },
16 | parserOptions: {
17 | ecmaVersion: 2020,
18 | sourceType: 'module',
19 | project: './tsconfig.json',
20 | tsconfigRootDir: __dirname,
21 | createDefaultProgram: true,
22 | },
23 | settings: {
24 | 'import/resolver': {
25 | node: {},
26 | webpack: {
27 | config: require.resolve('./.erb/configs/webpack.config.eslint.ts'),
28 | },
29 | },
30 | 'import/parsers': {
31 | '@typescript-eslint/parser': ['.ts', '.tsx'],
32 | },
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/features/SmartPage.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import { Page } from '@gavetaio/ui';
3 | import { useEffect, useRef } from 'react';
4 | import { useLocation, useNavigate } from 'react-router-dom';
5 | import { useLayoutContext } from 'renderer/context/layout';
6 |
7 | const SmartPage = ({ children }) => {
8 | const rendered = useRef(false);
9 | const location = useLocation();
10 | const { saveLayout, getLayout }: any = useLayoutContext();
11 | const navigate = useNavigate();
12 | const layout = getLayout();
13 |
14 | useEffect(() => {
15 | rendered.current = true;
16 | if (layout?.saved?.latest && layout.saved.latest !== location.pathname) {
17 | navigate(layout.saved.latest);
18 | }
19 | }, []);
20 |
21 | useEffect(() => {
22 | if (!rendered.current) {
23 | return;
24 | }
25 | if (layout?.saved?.latest && layout.saved.latest !== location.pathname) {
26 | saveLayout({
27 | latest: location.pathname,
28 | });
29 | }
30 | }, [location]);
31 |
32 | return {children} ;
33 | };
34 |
35 | export default SmartPage;
36 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Elevation.module.scss:
--------------------------------------------------------------------------------
1 | .content {
2 | position: relative;
3 | background-color: var(--elevation-bg-case);
4 | height: 100%;
5 | width: 100%;
6 | z-index: 4;
7 | border-radius: 4px;
8 | transform: translate3d(
9 | 0,
10 | calc(var(--elevation) * var(--elevation-state) * 1px),
11 | 0
12 | );
13 | transition: transform 165ms cubic-bezier(0.5, 0.25, 0.05, 1);
14 | display: flex;
15 | align-items: center;
16 | justify-content: stretch;
17 |
18 | > * {
19 | position: relative;
20 | z-index: 2;
21 | }
22 | }
23 |
24 | .container {
25 | --elevation-bg-case: #333;
26 | --elevation-bg-dark: #000;
27 | --elevation: 7;
28 | --elevation-state: 0;
29 |
30 | display: block;
31 | position: absolute;
32 | width: 100%;
33 | height: 100%;
34 | top: 0;
35 | left: 0;
36 |
37 | &:before {
38 | content: '';
39 | position: absolute;
40 | width: 100%;
41 | height: 100%;
42 | left: 0px;
43 | bottom: calc(var(--elevation) * -1px);
44 | z-index: 1;
45 | background-color: var(--elevation-bg-dark);
46 | border-radius: 4px;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Font.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Font.module.scss";
3 |
4 | const Font = ({
5 | children,
6 | name,
7 | type = "body",
8 | weight = "400",
9 | caps = false,
10 | bold = false,
11 | thin = false,
12 | }: any) => {
13 | const cls = [styles.font];
14 | const style = {
15 | "--font-size": `var(--font-${name})`,
16 | "--font-weight": weight,
17 | } as React.CSSProperties;
18 |
19 | if (caps) {
20 | cls.push(styles.caps);
21 | }
22 |
23 | if (bold) {
24 | cls.push(styles.bold);
25 | }
26 |
27 | if (thin) {
28 | cls.push(styles.thin);
29 | }
30 |
31 | if (type === "body") {
32 | return (
33 |
34 | {children}
35 |
36 | );
37 | }
38 |
39 | if (type === "label") {
40 | return (
41 |
42 | {children}
43 |
44 | );
45 | }
46 |
47 | return (
48 |
49 | {children}
50 |
51 | );
52 | };
53 |
54 | export default Font;
55 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/legacy/Elevation.module.scss:
--------------------------------------------------------------------------------
1 | .content {
2 | position: relative;
3 | background-color: var(--elevation-bg-case);
4 | height: 100%;
5 | width: 100%;
6 | z-index: 4;
7 | border-radius: 4px;
8 | transform: translate3d(
9 | 0,
10 | calc(var(--elevation) * var(--elevation-state) * 1px),
11 | 0
12 | );
13 | transition: transform 165ms cubic-bezier(0.5, 0.25, 0.05, 1);
14 | display: flex;
15 | align-items: center;
16 | justify-content: stretch;
17 |
18 | > * {
19 | position: relative;
20 | z-index: 2;
21 | }
22 | }
23 |
24 | .container {
25 | --elevation-bg-case: #333;
26 | --elevation-bg-dark: #000;
27 | --elevation: 7;
28 | --elevation-state: 0;
29 |
30 | display: block;
31 | position: absolute;
32 | width: 100%;
33 | height: 100%;
34 | top: 0;
35 | left: 0;
36 |
37 | &:before {
38 | content: '';
39 | position: absolute;
40 | width: 100%;
41 | height: 100%;
42 | left: 0px;
43 | bottom: calc(var(--elevation) * -1px);
44 | z-index: 1;
45 | background-color: var(--elevation-bg-dark);
46 | border-radius: 4px;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/codex/src/integrity/interpretation/brazilian-electoral-code.ts:
--------------------------------------------------------------------------------
1 | import { ElectoralIntegrityData } from '../helpers/types';
2 | import {
3 | NO_ACTION,
4 | PARTIAL_ELECTION_REPEAT,
5 | FULL_ELECTION_REPEAT,
6 | } from '../helpers/events';
7 |
8 | class BrazilianElectoralCode {
9 | static invalidatedVotesThreshold = 50;
10 |
11 | shouldRepeatElection(electionData: ElectoralIntegrityData) {
12 | const {
13 | votes,
14 | canInvalidatedVotesChangeElectionResult,
15 | canPartialElectionRepeatRemedyElectionResult,
16 | } = electionData;
17 |
18 | if (!canInvalidatedVotesChangeElectionResult) {
19 | return NO_ACTION;
20 | }
21 |
22 | const invalidatedVotesPercentage = (100 * votes.invalidated) / votes.valid;
23 |
24 | if (
25 | invalidatedVotesPercentage >
26 | BrazilianElectoralCode.invalidatedVotesThreshold
27 | ) {
28 | return FULL_ELECTION_REPEAT;
29 | }
30 |
31 | if (canPartialElectionRepeatRemedyElectionResult) {
32 | return PARTIAL_ELECTION_REPEAT;
33 | }
34 |
35 | return FULL_ELECTION_REPEAT;
36 | }
37 | }
38 |
39 | export default BrazilianElectoralCode;
40 |
--------------------------------------------------------------------------------
/packages/elections/.erb/configs/webpack.config.base.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Base webpack config used across other specific configs
3 | */
4 |
5 | import webpack from 'webpack';
6 | import webpackPaths from './webpack.paths';
7 | import { dependencies as externals } from '../../release/app/package.json';
8 |
9 | export default {
10 | externals: [...Object.keys(externals || {})],
11 |
12 | stats: 'errors-only',
13 |
14 | module: {
15 | rules: [
16 | {
17 | test: /\.[jt]sx?$/,
18 | exclude: /node_modules/,
19 | use: {
20 | loader: 'ts-loader',
21 | },
22 | },
23 | ],
24 | },
25 |
26 | output: {
27 | path: webpackPaths.srcPath,
28 | // https://github.com/webpack/webpack/issues/1114
29 | library: {
30 | type: 'commonjs2',
31 | },
32 | },
33 |
34 | /**
35 | * Determine the array of extensions that should be used to resolve modules.
36 | */
37 | resolve: {
38 | extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
39 | modules: [webpackPaths.srcPath, 'node_modules'],
40 | },
41 |
42 | plugins: [
43 | new webpack.EnvironmentPlugin({
44 | NODE_ENV: 'production',
45 | }),
46 | ],
47 | };
48 |
--------------------------------------------------------------------------------
/packages/elections/.erb/configs/webpack.paths.ts:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const rootPath = path.join(__dirname, '../..');
4 |
5 | const dllPath = path.join(__dirname, '../dll');
6 |
7 | const srcPath = path.join(rootPath, 'src');
8 | const srcMainPath = path.join(srcPath, 'main');
9 | const srcRendererPath = path.join(srcPath, 'renderer');
10 |
11 | const releasePath = path.join(rootPath, 'release');
12 | const appPath = path.join(releasePath, 'app');
13 | const appPackagePath = path.join(appPath, 'package.json');
14 | const appNodeModulesPath = path.join(appPath, 'node_modules');
15 | const srcNodeModulesPath = path.join(srcPath, 'node_modules');
16 |
17 | const distPath = path.join(appPath, 'dist');
18 | const distMainPath = path.join(distPath, 'main');
19 | const distRendererPath = path.join(distPath, 'renderer');
20 |
21 | const buildPath = path.join(releasePath, 'build');
22 |
23 | export default {
24 | rootPath,
25 | dllPath,
26 | srcPath,
27 | srcMainPath,
28 | srcRendererPath,
29 | releasePath,
30 | appPath,
31 | appPackagePath,
32 | appNodeModulesPath,
33 | srcNodeModulesPath,
34 | distPath,
35 | distMainPath,
36 | distRendererPath,
37 | buildPath,
38 | };
39 |
--------------------------------------------------------------------------------
/packages/core/utils/transformers/table.js:
--------------------------------------------------------------------------------
1 | import { forEachList, getPercentageString } from '../general';
2 |
3 | export const getTableCell = ({
4 | label = null,
5 | value = 0,
6 | extra = null,
7 | connected = false,
8 | } = {}) => {
9 | return {
10 | label: label || value || '—',
11 | value,
12 | extra,
13 | connected,
14 | };
15 | };
16 |
17 | export const getInfoCell = (label, votes, total, type = null) => {
18 | return {
19 | type,
20 | data: [
21 | label,
22 | {
23 | value: votes,
24 | extra: getPercentageString(votes, total),
25 | },
26 | ],
27 | };
28 | };
29 |
30 | export const createTableCellObject = (obj) => {
31 | const cell = {};
32 | forEachList(obj, (key, value) => {
33 | if (typeof value === 'object') {
34 | cell[key] = getTableCell(value);
35 | return;
36 | }
37 | cell[key] = getTableCell({ value });
38 | });
39 | return cell;
40 | };
41 |
42 | export const objectToTable = (obj) => {
43 | const keys = Object.keys(obj);
44 | const result = [];
45 | for (let i = 0; i < keys.length; i += 1) {
46 | const key = keys[i];
47 | result.push(obj[key]);
48 | }
49 | return result;
50 | };
51 |
--------------------------------------------------------------------------------
/packages/ui/src/base/ListItem.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/destructuring-assignment */
2 | // @ts-ignore
3 | import styles from "./ListItem.module.scss";
4 | import Table from "./Table";
5 | import Tags from "./Tags";
6 |
7 | const ListItem = ({
8 | title,
9 | description,
10 | table,
11 | action,
12 | tags,
13 | href = "",
14 | }: any) => {
15 | const content = (
16 |
17 |
18 |
{title}
19 | {description}
20 |
21 | {tags?.length && (
22 |
23 |
24 |
25 | )}
26 | {table && (table.length || table.data?.length) && (
27 |
30 | )}
31 |
32 | );
33 |
34 | if (action) {
35 | return (
36 | {
38 | event.preventDefault();
39 | action(href);
40 | }}
41 | href={href}
42 | >
43 | {content}
44 |
45 | );
46 | }
47 |
48 | return content;
49 | };
50 |
51 | export default ListItem;
52 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/SimulatorSummary.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/jsx-props-no-spreading */
2 | import { forEachList } from "@gavetaio/core";
3 | import { Table } from "../../base";
4 |
5 | const infoToSimulatorTable: any = ({ config, extra }) => {
6 | const header = ["Tipo", "Valor"];
7 | const data = [];
8 |
9 | const { candidatos, partidos, settings } = config;
10 |
11 | forEachList(extra, (key, value) => {
12 | data.push([key, value]);
13 | });
14 |
15 | data.push(["candidatos", candidatos?.length || 0]);
16 | data.push(["partidos", partidos?.length || 0]);
17 | data.push(["votos", settings?.length || 0]);
18 |
19 | const cargoList = [];
20 | settings.forEach(({ cargo }) => {
21 | if (cargoList.indexOf(cargo) === -1) {
22 | cargoList.push(cargo);
23 | }
24 | });
25 |
26 | data.push(["cargos", cargoList.join(", ")]);
27 |
28 | settings.forEach(() => {
29 | //
30 | });
31 |
32 | return {
33 | header,
34 | data,
35 | };
36 | };
37 |
38 | const SimulatorSummary: any = ({ config, extra }: any) => {
39 | const data: any = infoToSimulatorTable({
40 | config,
41 | extra,
42 | });
43 |
44 | return ;
45 | };
46 |
47 | export default SimulatorSummary;
48 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/SimulatorVotes.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/jsx-props-no-spreading */
2 | import { forEachList } from "@gavetaio/core";
3 | import { Table } from "../../base";
4 |
5 | const getState = (number) => {
6 | if (number === "96") {
7 | return "nulo";
8 | }
9 | if (number === "95") {
10 | return "branco";
11 | }
12 | return "válido";
13 | };
14 |
15 | const getCargoDisplay = (id, settings) => {
16 | const item = settings.find((setting) => setting.id === id);
17 | return item?.label || null;
18 | };
19 |
20 | const votesToTable: any = ({ votes, settings }) => {
21 | const header = ["Cargo", "Número Digitado", "Número Gravado", "Status"];
22 | const data = [];
23 |
24 | forEachList(votes, (key, { digitado, gravado }) => {
25 | data.push([
26 | getCargoDisplay(key, settings),
27 | digitado,
28 | gravado,
29 | getState(gravado),
30 | ]);
31 | });
32 |
33 | return {
34 | header,
35 | data,
36 | };
37 | };
38 |
39 | const SimulatorVotes: any = ({ votes, config }: any) => {
40 | const { settings } = config;
41 |
42 | const data: any = votesToTable({ votes, settings });
43 |
44 | return ;
45 | };
46 |
47 | export default SimulatorVotes;
48 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/helpers.tsx:
--------------------------------------------------------------------------------
1 | export const getPartidoFromList = ({ numero, list }) => {
2 | const test = typeof numero === "number" ? `${numero}` : numero;
3 |
4 | if (!test) {
5 | return null;
6 | }
7 | return list.find((partido) => partido.numero === test);
8 | };
9 |
10 | export const genderFlip = (nome) => {
11 | const split = nome.split(" ");
12 | if (split[0].trim().match(/(or)$/gim)) {
13 | split[0] = split[0].replace(/(.*)(or)$/gim, "$1ora");
14 | }
15 |
16 | if (split[0].trim().match(/(o)$/gim)) {
17 | split[0] = split[0].replace(/(.*)(o)$/gim, "$1a");
18 | }
19 |
20 | return split.join(" ");
21 | };
22 |
23 | export const getCargoDisplayTitle = ({ current, state }) => {
24 | const title = current?.label;
25 | if (state?.candidato?.genero && state?.candidato?.genero !== 2) {
26 | return genderFlip(title);
27 | }
28 |
29 | return title;
30 | };
31 |
32 | export const getTransformedNumero = (status, numbers) => {
33 | const { isNulo, isBranco, isLegenda, hasCandidato } = status;
34 |
35 | if (isBranco) {
36 | return "95";
37 | }
38 |
39 | if (isNulo) {
40 | return "96";
41 | }
42 |
43 | if (isLegenda && !hasCandidato) {
44 | return numbers.slice(0, 2).join("");
45 | }
46 |
47 | return numbers.join("");
48 | };
49 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Block.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Block.module.scss";
3 |
4 | const Block = ({
5 | title,
6 | description,
7 | children,
8 | noMargin = false,
9 | marginDouble = false,
10 | noPadding = false,
11 | halfMargin = false,
12 | lighter = false,
13 | footer = null,
14 | darker = false,
15 | type = null,
16 | }: any) => {
17 | const cls = [styles.container];
18 |
19 | if (noMargin) {
20 | cls.push(styles.noMargin);
21 | }
22 |
23 | if (marginDouble) {
24 | cls.push(styles.marginDouble);
25 | }
26 |
27 | if (halfMargin) {
28 | cls.push(styles.halfMargin);
29 | }
30 |
31 | if (noPadding) {
32 | cls.push(styles.noPadding);
33 | }
34 |
35 | if (lighter) {
36 | cls.push(styles.lighter);
37 | }
38 |
39 | if (darker) {
40 | cls.push(styles.darker);
41 | }
42 |
43 | if (type && styles[type]) {
44 | cls.push(styles[type]);
45 | }
46 |
47 | return (
48 |
49 |
50 | {description}
51 | {title && {title} }
52 |
53 |
{children}
54 | {footer &&
}
55 |
56 | );
57 | };
58 |
59 | export default Block;
60 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/App.tsx:
--------------------------------------------------------------------------------
1 | import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
2 | import './App.global.css';
3 | import './Reset.module.scss';
4 | import { LayoutProvider } from './context/layout';
5 | import LoaderScreen from './screens/Loader';
6 | import {
7 | SimuladorPage,
8 | HomePage,
9 | NullBoxesPage,
10 | ExposedPage,
11 | NulledVotesPage,
12 | AboutPage,
13 | } from './screens';
14 | import Navigation from './components/Navigation';
15 | import SmartPage from './features/SmartPage';
16 | import Bar from './components/Bar';
17 |
18 | export default function App() {
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 | } />
27 | } />
28 | } />
29 | } />
30 | } />
31 | } />
32 |
33 |
34 |
35 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/legacy/Button.module.old.scss:
--------------------------------------------------------------------------------
1 | .btn {
2 | --button-default-height: 42px;
3 | --button-horizontal-padding: calc(
4 | var(--button-default-height) - var(--button-raise-level)
5 | );
6 |
7 | &.left {
8 | > span > span {
9 | padding-right: calc(var(--button-horizontal-padding));
10 | padding-left: calc(var(--button-horizontal-padding) * 3 / 2);
11 | }
12 | .content {
13 | > span:nth-child(2) {
14 | left: 0;
15 | padding-right: 0;
16 | }
17 | }
18 | }
19 |
20 | &.right {
21 | > span > span {
22 | padding-left: calc(var(--button-horizontal-padding));
23 | padding-right: calc(var(--button-horizontal-padding) * 3 / 2);
24 | }
25 | .content {
26 | > span:nth-child(2) {
27 | right: 0;
28 | padding-left: 0;
29 | }
30 | }
31 | }
32 | }
33 |
34 | .content {
35 | display: block;
36 | font-size: 13px;
37 | line-height: 25;
38 |
39 | > span:nth-child(1) {
40 | display: block;
41 | font-size: inherit;
42 | }
43 |
44 | > span:nth-child(2) {
45 | padding-right: calc(var(--button-horizontal-padding));
46 | padding-left: calc(var(--button-horizontal-padding));
47 | height: var(--button-horizontal-padding);
48 | display: flex;
49 | position: absolute;
50 | top: 0;
51 | align-items: center;
52 | justify-content: center;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/revisited/Button.module.old.scss:
--------------------------------------------------------------------------------
1 | .btn {
2 | --button-default-height: 42px;
3 | --button-horizontal-padding: calc(
4 | var(--button-default-height) - var(--button-raise-level)
5 | );
6 |
7 | &.left {
8 | > span > span {
9 | padding-right: calc(var(--button-horizontal-padding));
10 | padding-left: calc(var(--button-horizontal-padding) * 3 / 2);
11 | }
12 | .content {
13 | > span:nth-child(2) {
14 | left: 0;
15 | padding-right: 0;
16 | }
17 | }
18 | }
19 |
20 | &.right {
21 | > span > span {
22 | padding-left: calc(var(--button-horizontal-padding));
23 | padding-right: calc(var(--button-horizontal-padding) * 3 / 2);
24 | }
25 | .content {
26 | > span:nth-child(2) {
27 | right: 0;
28 | padding-left: 0;
29 | }
30 | }
31 | }
32 | }
33 |
34 | .content {
35 | display: block;
36 | font-size: 13px;
37 | line-height: 25;
38 |
39 | > span:nth-child(1) {
40 | display: block;
41 | font-size: inherit;
42 | }
43 |
44 | > span:nth-child(2) {
45 | padding-right: calc(var(--button-horizontal-padding));
46 | padding-left: calc(var(--button-horizontal-padding));
47 | height: var(--button-horizontal-padding);
48 | display: flex;
49 | position: absolute;
50 | top: 0;
51 | align-items: center;
52 | justify-content: center;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/packages/codex/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@gavetaio/codex",
3 | "version": "1.0.0",
4 | "description": "",
5 | "type": "module",
6 | "scripts": {
7 | "start": "ts-node ./src/index.ts",
8 | "test": "jest --noStackTrace",
9 | "lint": "eslint src public"
10 | },
11 | "author": "@gavetaio",
12 | "license": "ISC",
13 | "devDependencies": {
14 | "@types/jest": "^29.0.2",
15 | "@types/node": "^18.7.16",
16 | "@typescript-eslint/eslint-plugin": "^5.36.2",
17 | "@typescript-eslint/parser": "^5.36.2",
18 | "eslint": "^8.23.0",
19 | "eslint-config-prettier": "^8.5.0",
20 | "eslint-plugin-node": "^11.1.0",
21 | "jest": "^29.0.3",
22 | "prettier": "^2.7.1",
23 | "ts-node": "^10.9.1",
24 | "tslib": "^2.4.0",
25 | "typescript": "^4.8.2"
26 | },
27 | "jest": {
28 | "transform": {
29 | ".(ts|tsx)": "ts-jest"
30 | },
31 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
32 | "moduleFileExtensions": [
33 | "ts",
34 | "tsx",
35 | "js",
36 | "json"
37 | ]
38 | },
39 | "prettier": {
40 | "overrides": [
41 | {
42 | "files": [
43 | ".prettierrc",
44 | ".eslintrc"
45 | ],
46 | "options": {
47 | "parser": "json"
48 | }
49 | }
50 | ],
51 | "singleQuote": true
52 | },
53 | "dependencies": {
54 | "ts-jest": "^29.0.1"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/components/Navigation.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | background-color: var(--background-darker);
3 | display: flex;
4 | flex-direction: column;
5 | align-items: center;
6 | position: fixed;
7 | width: var(--menu-width);
8 | height: 100vh;
9 | z-index: 1000;
10 | top: 0;
11 | left: 0;
12 | overflow: hidden;
13 |
14 | .wrapper {
15 | padding: 16px;
16 | width: 100%;
17 | overflow: auto;
18 | background-color: var(--background-darker);
19 |
20 | a {
21 | display: block;
22 | cursor: default;
23 | color: var(--text-primary);
24 | padding: 8px 20px;
25 | border-radius: 32px;
26 | margin: 8px 0;
27 | background-color: var(--background-dark);
28 | }
29 | }
30 |
31 | header {
32 | display: flex;
33 | width: 100%;
34 |
35 | justify-content: flex-end;
36 | align-items: center;
37 | min-height: var(--bar-height);
38 | padding: 0 16px;
39 |
40 | h2 {
41 | letter-spacing: -1.5px;
42 | color: var(--text-primary);
43 | }
44 | }
45 |
46 | section {
47 | margin-bottom: 24px;
48 | }
49 |
50 | h6 {
51 | padding-left: 20px;
52 | margin-bottom: 4px;
53 | text-transform: uppercase;
54 | color: var(--text-alt);
55 | }
56 |
57 | .active {
58 | background-color: var(--background);
59 | h5 {
60 | color: var(--text-secondary);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Button.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .button {
2 | --button-width: 29;
3 | --button-height: 12;
4 | --button-background: #ffffff;
5 | --button-background-dark: #ffffff;
6 |
7 | position: relative;
8 | width: calc(var(--unit) * var(--button-width));
9 | height: calc(var(--unit) * var(--button-height));
10 | margin: 0 calc(var(--key-height) / 4);
11 |
12 | > div {
13 | --elevation-bg-dark: var(--button-background-dark) !important;
14 | --elevation-bg-case: var(--button-background) !important;
15 | }
16 |
17 | p {
18 | color: var(--black);
19 | text-align: center;
20 | width: 100%;
21 | align-self: flex-start;
22 | margin-top: calc(var(--unit) / 2);
23 | }
24 |
25 | &.white {
26 | --button-background: var(--button-white);
27 | --button-background-dark: var(--button-white-dark);
28 |
29 | p {
30 | transform: scaleX(1) scaleY(1.1);
31 | }
32 | }
33 |
34 | &.danger {
35 | --button-background: var(--button-danger);
36 | --button-background-dark: var(--button-danger-dark);
37 | display: block;
38 |
39 | p {
40 | transform: scaleX(0.92) scaleY(1.1);
41 | }
42 | }
43 |
44 | &.action {
45 | --button-background: var(--button-action);
46 | --button-background-dark: var(--button-action-dark);
47 | --button-height: 16;
48 |
49 | p {
50 | transform: scaleX(0.86) scaleY(1.1);
51 | transform-origin: 50% 10%;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/packages/core/utils/transformers/filters.js:
--------------------------------------------------------------------------------
1 | const compareStatic = (list, item) => {
2 | if (list.indexOf(item) === -1) {
3 | return false;
4 | }
5 | return true;
6 | };
7 |
8 | const compareArrays = (list, items) => {
9 | let result = false;
10 | list.forEach((listItem) => {
11 | items.forEach((item) => {
12 | if (item === listItem) {
13 | result = true;
14 | }
15 | });
16 | });
17 | return result;
18 | };
19 |
20 | export const applyFilter = ({
21 | filters,
22 | ano = null,
23 | cargo = null,
24 | uf = null,
25 | anos = null,
26 | cargos = null,
27 | ufs = null,
28 | }) => {
29 | if (ano && filters.years?.length && !compareStatic(filters.years, ano)) {
30 | return false;
31 | }
32 |
33 | if (
34 | cargo &&
35 | filters.cargos?.length &&
36 | !compareStatic(filters.cargos, cargo)
37 | ) {
38 | return false;
39 | }
40 |
41 | if (uf && filters.ufs?.length && !compareStatic(filters.ufs, uf)) {
42 | return false;
43 | }
44 |
45 | if (
46 | anos?.length &&
47 | filters.years?.length &&
48 | !compareArrays(filters.years, anos)
49 | ) {
50 | return false;
51 | }
52 |
53 | if (
54 | cargos?.length &&
55 | filters.cargos?.length &&
56 | !compareArrays(filters.cargos, cargos)
57 | ) {
58 | return false;
59 | }
60 |
61 | if (ufs?.length && filters.ufs?.length && !compareArrays(filters.ufs, ufs)) {
62 | return false;
63 | }
64 |
65 | return true;
66 | };
67 |
--------------------------------------------------------------------------------
/packages/ui/src/base/helpers.js:
--------------------------------------------------------------------------------
1 | function end(element, type, { tolerance = 0, propertyName } = {}) {
2 | return new Promise((resolve) => {
3 | if (!element) {
4 | resolve(false);
5 | return;
6 | }
7 | let eventName = null;
8 | const capitalized = type.charAt(0).toUpperCase() + type.slice(1);
9 | let run = 0;
10 | function end(event) {
11 | const target = event.srcElement || event.target;
12 | if (target === element) {
13 | if (run >= tolerance) {
14 | if (propertyName && propertyName !== event.propertyName) {
15 | return;
16 | }
17 | element.removeEventListener(eventName, end);
18 | resolve(event);
19 | }
20 | run += 1;
21 | }
22 | }
23 | if (element.style[`Webkit${capitalized}`] !== undefined) {
24 | eventName = `webkit${capitalized}End`;
25 | }
26 | if (element.style.OTransition !== undefined) {
27 | eventName = `o${type}End`;
28 | }
29 | if (element.style[type] !== undefined) {
30 | eventName = `${type}end`;
31 | }
32 | if (element.clearEvent) {
33 | element.clearEvent();
34 | }
35 | element.clearEvent = function () {
36 | element.removeEventListener(eventName, end);
37 | };
38 | element.addEventListener(eventName, end);
39 | });
40 | }
41 |
42 | export function onTransitionEnd(element, options = {}) {
43 | return new Promise((resolve) => {
44 | end(element, "transition", options).then(resolve);
45 | });
46 | }
47 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/NulledVotesPage/transformers.ts:
--------------------------------------------------------------------------------
1 | import {
2 | forEachList,
3 | objectToTable,
4 | createTableCellObject,
5 | } from '@gavetaio/core';
6 | import { chartObjectToData } from 'renderer/helpers/data';
7 |
8 | export const filteredNulledSummary = ({ byYear }) => {
9 | const list = byYear;
10 |
11 | const header = ['Ano / Turno', 'Eleitores', 'Votos', 'Excluídos'];
12 | const result = [];
13 | const groups = {};
14 |
15 | const chart: any = {
16 | federal: {},
17 | municipal: {},
18 | };
19 |
20 | for (let i = 0; i < list.length; i += 1) {
21 | const item = list[i];
22 |
23 | const { turno, id, comparecimento, votos, recursados, isFederal } = item;
24 |
25 | const chartName = isFederal ? 'federal' : 'municipal';
26 |
27 | const key = `${id}-${turno}`;
28 |
29 | if (!chart[chartName][id]) {
30 | chart[chartName][id] = {
31 | count: 0,
32 | total: 0,
33 | };
34 | }
35 |
36 | chart[chartName][id].count += recursados;
37 |
38 | const cell = createTableCellObject({
39 | id: key,
40 | comparecimento,
41 | votos,
42 | removidos: {
43 | value: recursados,
44 | connected: true,
45 | },
46 | });
47 |
48 | result.push(objectToTable(cell));
49 | }
50 |
51 | return {
52 | table: {
53 | header,
54 | firstRow: 12,
55 | title: 'Dados',
56 | data: result,
57 | footer: ['count', 'sum', null, 'sum'],
58 | },
59 |
60 | chart: chartObjectToData(chart),
61 | };
62 | };
63 |
--------------------------------------------------------------------------------
/packages/codex/src/integrity/__tests__/interpretation.ts:
--------------------------------------------------------------------------------
1 | import BrazilianElectoralCode from '../interpretation/brazilian-electoral-code';
2 | import BrazilianElectoralCourt from '../interpretation/brazilian-electoral-court';
3 | import WesternElectoralHeritage from '../interpretation/western-electoral-heritage';
4 | import data from '../data/brazilian-election-2018';
5 |
6 | const brazilianElectoralCode = new BrazilianElectoralCode();
7 | const brazilianElectoralCourt = new BrazilianElectoralCourt();
8 | const westernElectoralHeritage = new WesternElectoralHeritage();
9 |
10 | describe('Brazilian Electoral CODE interpretation', () => {
11 | data.forEach((election, index) => {
12 | const brazilianCodeEvent =
13 | brazilianElectoralCode.shouldRepeatElection(election);
14 | const westernHeritageEvent =
15 | westernElectoralHeritage.shouldRepeatElection(election);
16 |
17 | test(`T${index}: repeat event should match WesternElectoralHeritage`, () => {
18 | expect(brazilianCodeEvent).toBe(westernHeritageEvent);
19 | });
20 | });
21 | });
22 |
23 | describe('Brazilian Electoral COURT interpretation', () => {
24 | data.forEach((election, index) => {
25 | const brazilianCourtEvent =
26 | brazilianElectoralCourt.shouldRepeatElection(election);
27 | const westernHeritageEvent =
28 | westernElectoralHeritage.shouldRepeatElection(election);
29 |
30 | test(`T${index}: ${election.name}: repeat event should match WesternElectoralHeritage`, () => {
31 | expect(brazilianCourtEvent).toBe(westernHeritageEvent);
32 | });
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/packages/codex/src/integrity/interpretation/brazilian-electoral-court.ts:
--------------------------------------------------------------------------------
1 | import { ElectoralIntegrityData } from '../helpers/types';
2 | import {
3 | NO_ACTION,
4 | // PARTIAL_ELECTION_REPEAT,
5 | FULL_ELECTION_REPEAT,
6 | } from '../helpers/events';
7 |
8 | class BrazilianElectoralCodeCourtInterpretation {
9 | static INVALIDATED_VOTES_THRESHOLD = 50;
10 |
11 | shouldRepeatElection(electionData: ElectoralIntegrityData) {
12 | const {
13 | votes,
14 | // canInvalidatedVotesChangeElectionResult,
15 | canPartialElectionRepeatRemedyElectionResult,
16 | invalidatedPollingStations,
17 | wasMajoritarianElectedCandidateInvalidated = null,
18 | } = electionData;
19 |
20 | // if (!canInvalidatedVotesChangeElectionResult) {
21 | // return NO_ACTION;
22 | // }
23 |
24 | const invalidatedVotesPercentage = (100 * votes.invalidated) / votes.valid;
25 |
26 | if (
27 | invalidatedVotesPercentage >
28 | BrazilianElectoralCodeCourtInterpretation.INVALIDATED_VOTES_THRESHOLD
29 | ) {
30 | return FULL_ELECTION_REPEAT;
31 | }
32 |
33 | if (wasMajoritarianElectedCandidateInvalidated === true) {
34 | return FULL_ELECTION_REPEAT;
35 | }
36 |
37 | if (canPartialElectionRepeatRemedyElectionResult) {
38 | // return PARTIAL_ELECTION_REPEAT;
39 | if (invalidatedPollingStations === 1) {
40 | return NO_ACTION;
41 | }
42 |
43 | return NO_ACTION;
44 | }
45 |
46 | // return FULL_ELECTION_REPEAT;
47 | return NO_ACTION;
48 | }
49 | }
50 |
51 | export default BrazilianElectoralCodeCourtInterpretation;
52 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Font.module.scss:
--------------------------------------------------------------------------------
1 | :global(#sim-urna) .font {
2 | --font-size: 1;
3 | --line-height: 1.35;
4 | --font-weight: 500;
5 |
6 | font-family: var(--dre-font-family);
7 | font-size: calc(var(--font-body) * var(--font-size));
8 | line-height: calc(var(--font-body) * var(--font-size) * var(--line-height));
9 | font-weight: var(--font-weight);
10 | min-height: calc(var(--font-body) * var(--font-size) * var(--line-height));
11 | position: relative;
12 | margin-bottom: 0 !important;
13 | padding: 0;
14 |
15 | &.caps {
16 | text-transform: uppercase;
17 | }
18 |
19 | &.bold {
20 | font-weight: 600;
21 | }
22 |
23 | &.thin {
24 | font-weight: 300;
25 | }
26 |
27 | b,
28 | i,
29 | span,
30 | mark,
31 | em {
32 | color: inherit;
33 | font-size: inherit;
34 | }
35 |
36 | mark {
37 | background-color: var(--black);
38 | color: var(--white);
39 | display: inline-flex;
40 | padding: var(--unit);
41 | align-items: center;
42 | justify-content: center;
43 | min-height: calc(var(--unit) * 7);
44 | min-height: calc(var(--unit) * 7);
45 | font-weight: 500;
46 | border-radius: calc(var(--unit) / 2);
47 |
48 | span {
49 | display: block;
50 | font-weight: 600;
51 | }
52 | }
53 |
54 | mark[data-type="confirm"] {
55 | background-color: var(--button-action);
56 | color: var(--black);
57 | min-height: calc(var(--unit) * 5);
58 | }
59 |
60 | mark[data-type="danger"] {
61 | background-color: var(--button-danger);
62 | color: var(--black);
63 | min-height: calc(var(--unit) * 5);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/packages/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@gavetaio/core",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "module": "./index.js",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1",
9 | "lint": "eslint src public"
10 | },
11 | "author": "@gavetaio",
12 | "license": "ISC",
13 | "devDependencies": {
14 | "eslint": "^8.6.0",
15 | "eslint-config-airbnb-base": "^15.0.0",
16 | "eslint-config-erb": "^4.0.0-alpha.0",
17 | "eslint-config-prettier": "^8.3.0",
18 | "eslint-plugin-compat": "^4.0.1",
19 | "eslint-plugin-import": "^2.25.4",
20 | "eslint-plugin-jsx-a11y": "^6.5.1",
21 | "eslint-plugin-promise": "^6.0.0",
22 | "eslint-plugin-react": "^7.28.0",
23 | "eslint-plugin-react-hooks": "^4.3.0",
24 | "prettier": "^2.5.1",
25 | "typescript-plugin-css-modules": "^3.4.0"
26 | },
27 | "prettier": {
28 | "overrides": [
29 | {
30 | "files": [
31 | ".prettierrc",
32 | ".eslintrc"
33 | ],
34 | "options": {
35 | "parser": "json"
36 | }
37 | }
38 | ],
39 | "singleQuote": true
40 | },
41 | "lint-staged": {
42 | "*.{js,jsx,ts,tsx}": [
43 | "cross-env NODE_ENV=development eslint --cache"
44 | ],
45 | "*.json,.{eslintrc,prettierrc}": [
46 | "prettier --ignore-path .eslintignore --parser json --write"
47 | ],
48 | "*.{css,scss}": [
49 | "prettier --ignore-path .eslintignore --single-quote --write"
50 | ],
51 | "*.{html,md,yml}": [
52 | "prettier --ignore-path .eslintignore --single-quote --write"
53 | ]
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/packages/engine/src/eleicoes/investigations/index.js:
--------------------------------------------------------------------------------
1 | const { investigateSidedVotes } = require("./sided-vote");
2 | const { investigateNullBoxes } = require("./null-boxes");
3 | const { investigateRemovedVotes } = require("./removed-votes");
4 | const { investigateBoxVoting } = require("./box-voting");
5 | const { investigateIndeferidos } = require("./indeferidos");
6 | const { investigateMissingVotes } = require("./missing-votes");
7 | const { investigateSizeDeviation } = require("./size-deviation");
8 | const { investigateAbsentBoxes } = require("./absent-boxes");
9 | const { investigateMissingBoxes } = require("./missing-boxes");
10 | const { investigateColigVotes } = require("./colig-votes");
11 | const { investigateMissingPositions } = require("./missing-positions");
12 | const { investigateTransitionBoxes } = require("./transition-boxes");
13 | const { investigateVoteDeviation } = require("./vote-deviation");
14 | const { populateCityInfo } = require("./city-info");
15 |
16 | module.exports = (investigationData) => {
17 | investigateSidedVotes(investigationData);
18 | investigateMissingVotes(investigationData);
19 | investigateMissingPositions(investigationData);
20 | investigateTransitionBoxes(investigationData);
21 | investigateNullBoxes(investigationData);
22 | investigateSizeDeviation(investigationData);
23 | investigateVoteDeviation(investigationData);
24 | investigateAbsentBoxes(investigationData);
25 | investigateMissingBoxes(investigationData);
26 | investigateColigVotes(investigationData);
27 | investigateRemovedVotes(investigationData);
28 | populateCityInfo(investigationData);
29 | investigateBoxVoting(investigationData);
30 | };
31 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Logo.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | --logo-size: 74px;
3 | --logo-border-radius: calc(var(--logo-size) / 32);
4 | --logo-handler-bg: #fff;
5 |
6 | --logo-bg: #fff;
7 | --logo-bg-secondary: #fff;
8 | --logo-spacer: calc(1px * 2);
9 |
10 | display: flex;
11 | height: var(--logo-size);
12 | width: var(--logo-size);
13 | position: relative;
14 |
15 | > div {
16 | display: flex;
17 | flex-direction: column;
18 | justify-content: space-between;
19 | position: relative;
20 | flex: 1;
21 | }
22 |
23 | &.circled {
24 | background-color: var(--logo-bg);
25 | border-radius: 50%;
26 |
27 | > div {
28 | margin: calc(var(--logo-size) / 4);
29 | }
30 |
31 | span {
32 | background-color: var(--logo-bg-secondary);
33 | }
34 | }
35 |
36 | span {
37 | display: block;
38 | position: relative;
39 | height: calc((100% - var(--logo-spacer)) / 3);
40 | background-color: var(--logo-bg);
41 | border-radius: var(--logo-border-radius);
42 | clip-path: polygon(
43 | 0% 0%,
44 | 0% 100%,
45 | 40% 100%,
46 | 40% 40%,
47 | 60% 40%,
48 | 60% 60%,
49 | 40% 60%,
50 | 40% 100%,
51 | 100% 100%,
52 | 100% 0%
53 | );
54 | }
55 |
56 | &.noclip {
57 | span {
58 | clip-path: none;
59 | }
60 |
61 | span:before {
62 | content: "";
63 | position: absolute;
64 | width: 25%;
65 | height: 20%;
66 | top: 40%;
67 | left: calc(50% - 12.5%);
68 | border-radius: var(--logo-border-radius);
69 | background-color: var(--logo-handler-bg);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Box.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | --unit: 3px;
3 | --unit-m: calc(var(--unit) * 4);
4 | --black: #111111;
5 | --keypad: #444444;
6 | --grey: #cfcfcf;
7 | --grey-dark: #aaaaaa;
8 | --border: #aaaaaa;
9 | --white: #ffffff;
10 | --ice: #f4f4f4;
11 | --screen: #efefef;
12 | --color-key: #333;
13 | --dark-grey: #3a3a3a;
14 | --lighthen-10: rgba(255, 255, 255, 0.5);
15 | --screen-ratio: 0.6;
16 | --screen-base: 180;
17 | --screen-width: calc(var(--unit) * var(--screen-base));
18 | --screen-height: calc(var(--screen-width) * var(--screen-ratio));
19 | --keypad-width: calc(var(--screen-width) * 0.6);
20 | --key-ratio: calc(228 / 180);
21 | --key-width: calc(var(--unit) * 18);
22 | --key-height: calc(var(--key-width) / var(--key-ratio));
23 | --button-white: #fafbff;
24 | --button-white-dark: #b9b9b9;
25 | --button-danger: #f59a62;
26 | --button-danger-dark: #b46534;
27 | --button-action: #51d9a1;
28 | --button-action-dark: #268d62;
29 |
30 | padding: calc(var(--unit) * 5);
31 | display: flex;
32 | align-items: center;
33 | justify-content: center;
34 |
35 | @media all and (max-width: 1360px) {
36 | --unit: 2.5px;
37 | }
38 |
39 | @media all and (max-width: 1190px) {
40 | --unit: 2px;
41 | }
42 |
43 | @media all and (max-width: 1020px) {
44 | --unit: 1.8px;
45 | }
46 |
47 | > div {
48 | background-color: var(--grey);
49 | display: block;
50 | border-radius: calc(var(--unit) / 2);
51 | }
52 | }
53 |
54 | .box {
55 | padding: calc(var(--unit) * 10) calc(var(--unit) * 16);
56 | display: flex;
57 | align-items: center;
58 | position: relative;
59 | }
60 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Selector.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | flex-direction: row;
4 | align-items: center;
5 | justify-content: flex-start;
6 | padding: var(--unit-v-0) 0;
7 | flex-wrap: wrap;
8 | width: 100%;
9 | border-radius: var(--unit-v-0);
10 | background-color: var(--background-dark);
11 |
12 | > div {
13 | display: flex;
14 | flex-direction: row;
15 | align-items: center;
16 | justify-content: flex-start;
17 | width: 100%;
18 | flex-wrap: wrap;
19 |
20 | > :nth-child(1) {
21 | margin-left: 0;
22 | }
23 | }
24 |
25 | button {
26 | display: flex;
27 | padding: 12px;
28 | margin: 0 4px 4px 0;
29 | border-radius: 4px;
30 | background-color: var(--background-dark);
31 | color: var(--text-lighter);
32 | align-items: center;
33 |
34 | > svg {
35 | margin: 0px 0 0 2px;
36 | fill: var(--text-lighter);
37 | }
38 | }
39 |
40 | button.selected {
41 | background-color: var(--background-light);
42 | color: var(--text-alt);
43 |
44 | span {
45 | color: var(--text-alt);
46 | }
47 |
48 | svg {
49 | fill: var(--text-alt);
50 | }
51 | }
52 |
53 | &.radio {
54 | > div:nth-child(1) .selected {
55 | color: var(--text-secondary);
56 |
57 | span {
58 | color: var(--text-secondary);
59 | }
60 |
61 | svg {
62 | fill: var(--text-secondary);
63 | }
64 | }
65 | }
66 |
67 | &.icon {
68 | button {
69 | position: relative;
70 |
71 | svg {
72 | position: absolute;
73 | right: 2px;
74 | top: 4px;
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/components/Bar.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useContext } from 'react';
2 | import { LayoutContext } from 'renderer/context/layout';
3 | import { useNavigate, useLocation } from 'react-router';
4 | import { Wrapper } from '@gavetaio/ui';
5 | import styles from './Bar.module.scss';
6 |
7 | const Bar = () => {
8 | const [search, setSearch] = useState('');
9 | const navigate = useNavigate();
10 | const location = useLocation();
11 | const { setLayout }: any = useContext(LayoutContext);
12 |
13 | const handleKeyDown = (event: any) => {
14 | if (event.keyCode === 13) {
15 | handleSearch();
16 | }
17 | };
18 |
19 | const handleSearch = () => {
20 | setLayout({ search });
21 | };
22 |
23 | const handleBack = () => {
24 | navigate(-1);
25 | };
26 |
27 | return (
28 |
29 |
30 |
31 |
32 | Voltar
33 |
34 |
35 |
36 |
{location.pathname}
37 |
38 |
setSearch(e.target.value)}
43 | onKeyDown={handleKeyDown}
44 | />
45 |
46 |
47 | Buscar
48 |
49 |
50 |
51 |
52 | );
53 | };
54 |
55 | export default Bar;
56 |
--------------------------------------------------------------------------------
/packages/ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@gavetaio/ui",
3 | "version": "0.1.0",
4 | "private": false,
5 | "main": "./lib/index.js",
6 | "module": "./src/module.ts",
7 | "types": "./global.d.ts",
8 | "author": "@gavetaio",
9 | "dependencies": {
10 | "@primer/octicons-react": "^16.2.0",
11 | "@types/node": "^16.11.19",
12 | "@types/react": "^18.0.9",
13 | "@types/react-dom": "^18.0.3",
14 | "array-unique": "^0.3.2",
15 | "clipboard-copy": "^4.0.1",
16 | "node-sass": "^7.0.1",
17 | "react": "^18.1.0",
18 | "react-dom": "^18.1.0",
19 | "react-dropzone": "^11.4.2",
20 | "react-json-pretty": "^2.2.0",
21 | "react-scripts": "5.0.0",
22 | "typescript": "^4.5.4"
23 | },
24 | "scripts": {
25 | "build": "react-scripts build",
26 | "eject": "react-scripts eject"
27 | },
28 | "eslintConfig": {
29 | "extends": [
30 | "react-app",
31 | "react-app/jest"
32 | ]
33 | },
34 | "browserslist": {
35 | "production": [
36 | ">0.2%",
37 | "not dead",
38 | "not op_mini all"
39 | ],
40 | "development": [
41 | "last 1 chrome version",
42 | "last 1 firefox version",
43 | "last 1 safari version"
44 | ]
45 | },
46 | "devDependencies": {
47 | "eslint": "^8.6.0",
48 | "eslint-config-airbnb-base": "^15.0.0",
49 | "eslint-config-erb": "^4.0.0-alpha.0",
50 | "eslint-plugin-compat": "^4.0.1",
51 | "eslint-plugin-import": "^2.25.4",
52 | "eslint-plugin-jsx-a11y": "^6.5.1",
53 | "eslint-plugin-promise": "^6.0.0",
54 | "eslint-plugin-react": "^7.28.0",
55 | "eslint-plugin-react-hooks": "^4.3.0",
56 | "typescript-plugin-css-modules": "^3.4.0"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/useCustomState.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef, useState } from "react";
2 | import { deepClone } from "@gavetaio/core";
3 |
4 | export default function useCustomState(init, debounced = false) {
5 | const [state, setState] = useState(init);
6 | const callbackRef = useRef(null);
7 | const stateRef = useRef(init);
8 | const debouncedRef = useRef(null);
9 |
10 | const debouncedStateUpdate = () => {
11 | if (debouncedRef.current) {
12 | return;
13 | }
14 |
15 | debouncedRef.current = setTimeout(updateState, 115);
16 | };
17 |
18 | const setCustomState = (newState, callback = null, destroy = null) => {
19 | callbackRef.current = callback;
20 |
21 | if (Array.isArray(init)) {
22 | if (Array.isArray(newState)) {
23 | stateRef.current = newState;
24 | } else {
25 | stateRef.current.push(newState);
26 | }
27 | } else if (destroy) {
28 | stateRef.current = {
29 | ...init,
30 | ...newState,
31 | };
32 | } else {
33 | stateRef.current = deepClone({
34 | ...stateRef.current,
35 | ...newState,
36 | });
37 | }
38 |
39 | if (debounced) {
40 | debouncedStateUpdate();
41 | } else {
42 | updateState();
43 | }
44 |
45 | return stateRef.current;
46 | };
47 |
48 | const updateState = () => {
49 | setState(stateRef.current);
50 | };
51 |
52 | const resetState = (data = {}, callback) => {
53 | setCustomState({ ...init, ...data }, callback, true);
54 | };
55 |
56 | useEffect(() => {
57 | if (callbackRef.current) {
58 | callbackRef.current(state);
59 | }
60 |
61 | callbackRef.current = undefined;
62 | }, [state]);
63 |
64 | return [state, setCustomState, resetState, stateRef];
65 | }
66 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/hooks/useCustomState.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef, useState } from "react";
2 | import { deepClone } from "@gavetaio/core";
3 |
4 | export default function useCustomState(init, debounced = false) {
5 | const [state, setState] = useState(init);
6 | const callbackRef = useRef(null);
7 | const stateRef = useRef(init);
8 | const debouncedRef = useRef(null);
9 |
10 | const debouncedStateUpdate = () => {
11 | if (debouncedRef.current) {
12 | return;
13 | }
14 |
15 | debouncedRef.current = setTimeout(updateState, 115);
16 | };
17 |
18 | const setCustomState = (newState, callback = null, destroy = null) => {
19 | callbackRef.current = callback;
20 |
21 | if (Array.isArray(init)) {
22 | if (Array.isArray(newState)) {
23 | stateRef.current = newState;
24 | } else {
25 | stateRef.current.push(newState);
26 | }
27 | } else if (destroy) {
28 | stateRef.current = {
29 | ...init,
30 | ...newState,
31 | };
32 | } else {
33 | stateRef.current = deepClone({
34 | ...stateRef.current,
35 | ...newState,
36 | });
37 | }
38 |
39 | if (debounced) {
40 | debouncedStateUpdate();
41 | } else {
42 | updateState();
43 | }
44 |
45 | return stateRef.current;
46 | };
47 |
48 | const updateState = () => {
49 | setState(stateRef.current);
50 | };
51 |
52 | const resetState = (data = {}, callback) => {
53 | setCustomState({ ...init, ...data }, callback, true);
54 | };
55 |
56 | useEffect(() => {
57 | if (callbackRef.current) {
58 | callbackRef.current(state);
59 | }
60 |
61 | callbackRef.current = undefined;
62 | }, [state]);
63 |
64 | return [state, setCustomState, resetState, stateRef];
65 | }
66 |
--------------------------------------------------------------------------------
/packages/elections/src/main/preload.js:
--------------------------------------------------------------------------------
1 | const { contextBridge, ipcRenderer } = require('electron');
2 | const fs = require('fs');
3 |
4 | contextBridge.exposeInMainWorld('electron', {
5 | unzipFile: ({ section, files }) => {
6 | ipcRenderer.send('unzip-call', { section, files });
7 | },
8 | fs,
9 | gc: () => {
10 | ipcRenderer.send('garbage', null);
11 | },
12 | files: {
13 | get(params) {
14 | ipcRenderer.send('files-get', params);
15 | },
16 | folder() {
17 | ipcRenderer.send('folder-get');
18 | },
19 | on(channel, func) {
20 | ipcRenderer.on(channel, (event, args) => {
21 | return func(args);
22 | });
23 | },
24 | },
25 | api: {
26 | get(params) {
27 | ipcRenderer.send('api-call', params);
28 | },
29 | on(channel, func) {
30 | ipcRenderer.on(channel, (event, args) => {
31 | return func(args);
32 | });
33 | },
34 | },
35 | elections: {
36 | run(data) {
37 | ipcRenderer.send('elections-run', data);
38 | },
39 | on(channel, func) {
40 | ipcRenderer.on(channel, (event, ...args) => {
41 | return func(...args);
42 | });
43 | },
44 | off(channel) {
45 | ipcRenderer.removeAllListeners(channel);
46 | },
47 | },
48 | ipcRenderer: {
49 | myPing() {
50 | ipcRenderer.send('ipc-example', 'ping');
51 | },
52 | on(channel, func) {
53 | const validChannels = ['ipc-example'];
54 | if (validChannels.includes(channel)) {
55 | ipcRenderer.on(channel, (event, ...args) => func(...args));
56 | }
57 | },
58 | once(channel, func) {
59 | const validChannels = ['ipc-example'];
60 | if (validChannels.includes(channel)) {
61 | ipcRenderer.once(channel, (event, ...args) => func(...args));
62 | }
63 | },
64 | },
65 | });
66 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Key.tsx:
--------------------------------------------------------------------------------
1 | import { useCallback, useState, useEffect, useRef } from "react";
2 | import Font from "./Font";
3 | import { Elevation } from "../../base";
4 | // @ts-ignore
5 | import styles from "./Key.module.scss";
6 |
7 | const Key = ({ children, onClick }: any) => {
8 | const [pressed, setPressed] = useState(false);
9 | const ref: any = useRef();
10 |
11 | const press = useCallback(() => {
12 | return !pressed && setPressed(true);
13 | }, [pressed]);
14 |
15 | const release = useCallback(() => {
16 | return pressed && setPressed(false);
17 | }, [pressed]);
18 |
19 | const action = useCallback(() => {
20 | onClick(children);
21 | release();
22 | }, [release, children]);
23 |
24 | useEffect(() => {
25 | if (ref.current) {
26 | ref.current.addEventListener("btnPress", (event) => {
27 | setPressed(true);
28 | setTimeout(() => {
29 | onClick(children);
30 | setPressed(false);
31 | if (event?.detail?.callback) {
32 | requestAnimationFrame(() => {
33 | event.detail.callback();
34 | });
35 | }
36 | }, 325);
37 | });
38 | }
39 | }, []);
40 |
41 | return (
42 |
53 |
58 |
59 | {children}
60 |
61 |
62 |
63 | );
64 | };
65 |
66 | export default Key;
67 |
--------------------------------------------------------------------------------
/packages/core/utils/transformers/boxes.js:
--------------------------------------------------------------------------------
1 | import find from 'lodash/find';
2 | import { pushUnique } from '../general';
3 |
4 | export const getBoxById = (id, boxes) => {
5 | return find(boxes, { id });
6 | };
7 |
8 | const getExtra = (reg, problemas) => {
9 | let cargoList = [];
10 | const item = problemas.find((info) => {
11 | return info?.type ? !!info.type.match(reg) : !!info.match(reg);
12 | });
13 |
14 | if (!item) {
15 | return null;
16 | }
17 |
18 | if (Array.isArray(item.extra) && item.extra?.length) {
19 | item.extra.forEach(({ nome }) => {
20 | pushUnique(cargoList, nome);
21 | });
22 | } else {
23 | cargoList = item.extra;
24 | }
25 |
26 | return cargoList;
27 | };
28 |
29 | export const transformBoxesTable = (boxes, problema) => {
30 | const result = [];
31 | const reg = new RegExp(problema, 'mig');
32 |
33 | const name = problema.match(/exposed/gim) ? 'expostos' : 'perdidos';
34 |
35 | for (let i = 0; i < boxes.length; i += 1) {
36 | const {
37 | uf,
38 | id,
39 | municipio,
40 | absolutos,
41 | problemas,
42 | cargos,
43 | status,
44 | other = null,
45 | } = boxes[i];
46 | const splitId = id.split('-');
47 | let extra = null;
48 |
49 | if (problemas?.length) {
50 | extra = getExtra(reg, problemas);
51 | }
52 |
53 | const isFederal = !cargos?.prefeito && !cargos?.vereador;
54 |
55 | const row = {
56 | id,
57 | ano: splitId[1],
58 | uf,
59 | turno: splitId[2],
60 | municipio,
61 | extra,
62 | zona: splitId[4],
63 | secao: splitId[5],
64 | comparecimento: absolutos.tamanho,
65 | count: absolutos[`${name}`] || extra?.count || 0,
66 | isFederal,
67 | status,
68 | other,
69 | };
70 |
71 | result.push(row);
72 | }
73 |
74 | return result;
75 | };
76 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/components/Bar.module.scss:
--------------------------------------------------------------------------------
1 | .statusBar {
2 | height: 32px;
3 | display: flex;
4 | align-items: center;
5 | background-color: var(--background-active);
6 | min-height: calc(var(--bar-height) / 2);
7 | justify-content: flex-start;
8 | padding: 8px 32px;
9 | }
10 |
11 | .statusContent {
12 | display: flex;
13 | flex-direction: row;
14 | align-items: center;
15 | justify-content: space-between;
16 | }
17 |
18 | .container {
19 | -webkit-app-region: drag;
20 | position: fixed;
21 | background-color: var(--background-darker);
22 | width: calc(100% - var(--menu-width));
23 | top: 0;
24 | left: var(--menu-width);
25 | z-index: 1000;
26 | }
27 |
28 | .path {
29 | background-color: var(--background);
30 | padding: 4px 12px;
31 | border-radius: 32px;
32 | min-width: 100px;
33 |
34 | h6 {
35 | color: var(--text-alt);
36 | font-size: var(--font-xxs);
37 | font-family: 'Courier New', Courier, monospace;
38 | font-weight: 800;
39 | text-transform: none;
40 | }
41 | }
42 | .input {
43 | display: flex;
44 | align-items: center;
45 | justify-content: flex-start;
46 | flex: 1;
47 | background-color: var(--background-dark);
48 | padding: 0 16px 0 0;
49 | height: 36px;
50 | line-height: 24px;
51 | border-radius: 32px;
52 |
53 | input {
54 | flex: 1;
55 | outline: none;
56 | }
57 | }
58 | .wrapper {
59 | display: flex;
60 | align-items: center;
61 | min-height: var(--bar-height);
62 | justify-content: flex-start;
63 | padding: 8px 24px;
64 |
65 | button:nth-child(1) {
66 | margin-right: 12px;
67 | }
68 |
69 | button:nth-child(3) {
70 | margin-left: 12px;
71 | }
72 |
73 | input {
74 | border: none;
75 | background-color: rgba(0, 0, 0, 0);
76 | height: 36px;
77 | line-height: 28px;
78 | padding-left: 10px;
79 | flex: 1;
80 | color: var(--text-primary);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/components/helpers/utils.ts:
--------------------------------------------------------------------------------
1 | export const objectToOrderedArray = (obj, labels) => {
2 | const keys = Object.keys(obj);
3 | const result = [];
4 | for (let i = 0; i < keys.length; i += 1) {
5 | const key = keys[i];
6 | result.push({ [`${labels[0]}`]: key, [`${labels[1]}`]: obj[key] });
7 | }
8 | return result.sort((a, b) => b[labels[1]] - a[labels[1]]);
9 | };
10 |
11 | export const deepClone = (object) => {
12 | return JSON.parse(JSON.stringify(object));
13 | };
14 |
15 | export const richObjectToArray = (obj, labels, prop) => {
16 | const cloned = deepClone(obj);
17 | const keys = Object.keys(cloned);
18 | const result = [];
19 | for (let i = 0; i < keys.length; i += 1) {
20 | const key = keys[i];
21 | result.push({ [`${labels[0]}`]: key, [`${labels[1]}`]: cloned[key][prop] });
22 | }
23 | return result;
24 | };
25 |
26 | const VAGAS = {
27 | deputado_distrital: {
28 | DF: 24,
29 | },
30 | deputado_federal: {
31 | AC: 8,
32 | AL: 9,
33 | AM: 8,
34 | AP: 8,
35 | BA: 39,
36 | CE: 22,
37 | DF: 8,
38 | ES: 10,
39 | GO: 17,
40 | MA: 18,
41 | MG: 53,
42 | MS: 8,
43 | MT: 8,
44 | PA: 17,
45 | PB: 12,
46 | PE: 25,
47 | PI: 10,
48 | PR: 30,
49 | RJ: 46,
50 | RN: 8,
51 | RO: 8,
52 | RR: 8,
53 | RS: 31,
54 | SC: 16,
55 | SE: 8,
56 | SP: 70,
57 | TO: 8,
58 | },
59 | deputado_estadual: {
60 | AC: 24,
61 | AL: 27,
62 | AM: 24,
63 | AP: 24,
64 | BA: 63,
65 | CE: 46,
66 | DF: 24,
67 | ES: 30,
68 | GO: 41,
69 | MA: 42,
70 | MG: 77,
71 | MS: 24,
72 | MT: 24,
73 | PA: 41,
74 | PB: 36,
75 | PE: 49,
76 | PI: 30,
77 | PR: 54,
78 | RJ: 70,
79 | RN: 24,
80 | RO: 24,
81 | RR: 24,
82 | RS: 55,
83 | SC: 40,
84 | SE: 24,
85 | SP: 94,
86 | TO: 24,
87 | },
88 | };
89 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/SimulatorLogs.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable jsx-a11y/label-has-associated-control */
2 | /* eslint-disable react-hooks/exhaustive-deps */
3 | /* eslint-disable react/button-has-type */
4 | import { TrashIcon } from "@primer/octicons-react";
5 | import { forEachList } from "@gavetaio/core";
6 | import { Table } from "../../base";
7 |
8 | const logsToTable = ({ logs, events }) => {
9 | const result = {
10 | header: ["Índice", "Tipo", "Evento", "Valor", "Extra"],
11 | data: [],
12 | };
13 |
14 | if (!logs?.length) {
15 | return result;
16 | }
17 |
18 | logs.forEach((log, index) => {
19 | if (events?.length) {
20 | if (events.indexOf(log.value?.event) === -1) {
21 | return;
22 | }
23 | }
24 | const main = {
25 | event: "",
26 | value: "",
27 | extra: [],
28 | };
29 | forEachList(log.value, (key, value) => {
30 | if (key === "event" || key === "value") {
31 | main[key] = value;
32 | return;
33 | }
34 | main.extra.push({ key, value });
35 | });
36 |
37 | let type = null;
38 |
39 | const row = [];
40 | row.push(index);
41 | row.push(log.label);
42 | row.push(main.event || "");
43 | row.push(main.value || "");
44 | row.push(main.extra);
45 | result.data.push({ type, data: row });
46 | });
47 |
48 | result.data.reverse();
49 |
50 | return result;
51 | };
52 |
53 | const SimulatorLogs = (props: any) => {
54 | const { logs = [], events = [], onClearLogs = null } = props;
55 |
56 | const actions = [
57 | {
58 | icon: ,
59 | action: () => {
60 | if (typeof onClearLogs === "function") {
61 | onClearLogs();
62 | }
63 | },
64 | },
65 | ];
66 |
67 | return (
68 |
74 | );
75 | };
76 |
77 | export default SimulatorLogs;
78 |
--------------------------------------------------------------------------------
/packages/elections/.erb/configs/webpack.config.renderer.dev.dll.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Builds the DLL for development electron renderer process
3 | */
4 |
5 | import webpack from 'webpack';
6 | import path from 'path';
7 | import { merge } from 'webpack-merge';
8 | import baseConfig from './webpack.config.base';
9 | import webpackPaths from './webpack.paths';
10 | import { dependencies } from '../../package.json';
11 | import checkNodeEnv from '../scripts/check-node-env';
12 |
13 | checkNodeEnv('development');
14 |
15 | const dist = webpackPaths.dllPath;
16 |
17 | export default merge(baseConfig, {
18 | context: webpackPaths.rootPath,
19 |
20 | devtool: 'eval',
21 |
22 | mode: 'development',
23 |
24 | target: 'electron-renderer',
25 |
26 | externals: ['fsevents', 'crypto-browserify'],
27 |
28 | /**
29 | * Use `module` from `webpack.config.renderer.dev.js`
30 | */
31 | module: require('./webpack.config.renderer.dev').default.module,
32 |
33 | entry: {
34 | renderer: Object.keys(dependencies || {}),
35 | },
36 |
37 | output: {
38 | path: dist,
39 | filename: '[name].dev.dll.js',
40 | library: {
41 | name: 'renderer',
42 | type: 'var',
43 | },
44 | },
45 |
46 | plugins: [
47 | new webpack.DllPlugin({
48 | path: path.join(dist, '[name].json'),
49 | name: '[name]',
50 | }),
51 |
52 | /**
53 | * Create global constants which can be configured at compile time.
54 | *
55 | * Useful for allowing different behaviour between development builds and
56 | * release builds
57 | *
58 | * NODE_ENV should be production so that modules do not perform certain
59 | * development checks
60 | */
61 | new webpack.EnvironmentPlugin({
62 | NODE_ENV: 'development',
63 | }),
64 |
65 | new webpack.LoaderOptionsPlugin({
66 | debug: true,
67 | options: {
68 | context: webpackPaths.srcPath,
69 | output: {
70 | path: webpackPaths.dllPath,
71 | },
72 | },
73 | }),
74 | ],
75 | });
76 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Button.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Button.module.scss";
3 | import ElevatedPressable from "./ElevatedPressable";
4 | import { useCallback } from "react";
5 |
6 | const Button = ({
7 | className,
8 | type = "primary",
9 | icon,
10 | id = null,
11 | iconPosition = "right",
12 | element = null,
13 | label,
14 | children,
15 | ref,
16 | transform = false,
17 | size = "medium",
18 | attrs = {},
19 | ...extra
20 | }: any) => {
21 | let content = label || children;
22 | let wrapper = null;
23 | const cls = [styles.container];
24 |
25 | if (className) {
26 | cls.push(className);
27 | }
28 |
29 | wrapper = (
30 |
31 | {content}
32 |
33 | );
34 |
35 | if (type) {
36 | cls.push(styles[type]);
37 | }
38 |
39 | if (size) {
40 | cls.push(styles[size]);
41 | }
42 |
43 | if (extra.disabled) {
44 | cls.push(styles.disabled);
45 | }
46 |
47 | const handleClick = useCallback(
48 | (ev) => {
49 | if (extra.disabled || !extra.onClick) {
50 | return false;
51 | }
52 | extra.onClick(ev);
53 | },
54 | [extra.onClick, extra.disabled]
55 | );
56 |
57 | const handleLongClick = useCallback(() => {}, [
58 | extra.onLongPress,
59 | extra.disabled,
60 | ]);
61 |
62 | const handlePressDown = () => {
63 | if (extra.onPress) {
64 | extra.onPress();
65 | }
66 | };
67 |
68 | const handlePressRelease = () => {
69 | if (extra.onRelease) {
70 | extra.onRelease();
71 | }
72 | };
73 |
74 | return (
75 |
85 | {wrapper}
86 |
87 | );
88 | };
89 |
90 | export default Button;
91 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/helpers.ts:
--------------------------------------------------------------------------------
1 | const formatter = new Intl.RelativeTimeFormat('pt-BR', {
2 | numeric: 'auto',
3 | });
4 |
5 | const DIVISIONS = [
6 | { amount: 60, name: 'seconds' },
7 | { amount: 60, name: 'minutes' },
8 | { amount: 24, name: 'hours' },
9 | { amount: 7, name: 'days' },
10 | { amount: 4.34524, name: 'weeks' },
11 | { amount: 12, name: 'months' },
12 | { amount: Number.POSITIVE_INFINITY, name: 'years' },
13 | ];
14 |
15 | function formatTimeAgo(date: Date) {
16 | // @ts-ignore
17 | let duration = (date - new Date()) / 1000;
18 |
19 | for (let i = 0; i <= DIVISIONS.length; i += 1) {
20 | const division = DIVISIONS[i];
21 | if (Math.abs(duration) < division.amount) {
22 | // @ts-ignore
23 | return formatter.format(Math.round(duration), division.name);
24 | }
25 | duration /= division.amount;
26 | }
27 | return null;
28 | }
29 |
30 | const roundTwo = (num) => Math.round((num + Number.EPSILON) * 100) / 100;
31 |
32 | export const transformFileList = ({ jsons }) => {
33 | const loaded = {
34 | files: [],
35 | years: [],
36 | sum: 0,
37 | };
38 |
39 | const years = [];
40 | jsons.map((item: any) => {
41 | loaded.sum += item.size;
42 | const time = formatTimeAgo(new Date(item.time));
43 | const year = item.name.replace(/(.*)([0-9]{4})(.*)/gim, '$2');
44 |
45 | if (years.indexOf(year) === -1) {
46 | loaded.years.push({ label: year, value: year });
47 | years.push(year);
48 | }
49 |
50 | // const id = item.name.replace(/\.json/, '').trim();
51 | // let type = null;
52 |
53 | const isLoaded = false;
54 | const size: number = roundTwo(item.size / 1000 / 1000);
55 | loaded.files.push({
56 | type: isLoaded ? null : 'disabled',
57 | data: [
58 | item.name,
59 | {
60 | value: size,
61 | label: `${Math.round(size * 1024)}`,
62 | },
63 | {
64 | label: time,
65 | value: Math.round(item.time),
66 | },
67 | ],
68 | });
69 | });
70 | return loaded;
71 | };
72 |
--------------------------------------------------------------------------------
/packages/engine/src/data/partidos.js:
--------------------------------------------------------------------------------
1 | export const PARTIDOS = `Movimento Democrático Brasileiro | MDB | 15
2 | Partido dos Trabalhadores | PT | 13
3 | Partido da Social Democracia Brasileira | PSDB | 45
4 | Progressistas | PP | 11
5 | Partido Democrático Trabalhista | PDT | 12
6 | Partido Trabalhista Brasileiro | PTB | 14
7 | Democratas | DEM | 25
8 | Partido Liberal | PL | 22
9 | Partido Socialista Brasileiro | PSB | 40
10 | Republicanos | Republicanos | 10
11 | Cidadania | Cidadania | 23
12 | Partido Social Cristão | PSC | 20
13 | Partido Comunista do Brasil | PCdoB | 65
14 | Podemos | PODE | 19
15 | Partido Social Democrático | PSD | 55
16 | Partido Verde | PV | 43
17 | Patriota | Patriota | 51
18 | Solidariedade | Solidariedade | 77
19 | Partido Socialismo e Liberdade | PSOL | 50
20 | Avante | Avante | 70
21 | Partido da Mobilização Nacional | PMN | 33
22 | Partido Trabalhista Cristão | PTC | 36
23 | Democracia Cristã | DC | 27
24 | Partido Renovador Trabalhista Brasileiro | PRTB | 28
25 | Partido Republicano da Ordem Social | PROS | 90
26 | Partido Social Liberal | PSL | 17
27 | Partido da Mulher Brasileira | PMB | 35
28 | Rede Sustentabilidade | REDE | 18
29 | Partido Novo | NOVO | 30
30 | Partido Socialista dos Trabalhadores Unificado | PSTU | 16
31 | Partido Comunista Brasileiro | PCB | 21
32 | Partido da Causa Operária | PCO | 29
33 | Unidade Popular | UP | 80
34 | Partido Pátria Livre | PPL | 54
35 | Partido Republicano Progressista | PRP | 44
36 | REDE SUSTENTABILIDADE | REDE | 31`;
37 |
38 | export const getPartidosInfo = () => {
39 | const list = PARTIDOS.split('\n');
40 | const result = [];
41 | list.forEach((line) => {
42 | const split = line.split('|');
43 | const partido = {
44 | nome: split[0].trim(),
45 | sigla: split[1].trim(),
46 | numero: split[2].trim(),
47 | };
48 | result.push(partido);
49 | });
50 |
51 | return result;
52 | };
53 |
54 | export const getPartidoData = (number) => {
55 | const partidos = getPartidosInfo();
56 | const result = partidos.find((partido) => partido.numero === `${number}`);
57 |
58 | return result || null;
59 | };
60 |
--------------------------------------------------------------------------------
/packages/engine/src/data/partidos copy.js:
--------------------------------------------------------------------------------
1 | export const PARTIDOS = `Movimento Democrático Brasileiro | MDB | 15
2 | Partido dos Trabalhadores | PT | 13
3 | Partido da Social Democracia Brasileira | PSDB | 45
4 | Progressistas | PP | 11
5 | Partido Democrático Trabalhista | PDT | 12
6 | Partido Trabalhista Brasileiro | PTB | 14
7 | Democratas | DEM | 25
8 | Partido Liberal | PL | 22
9 | Partido Socialista Brasileiro | PSB | 40
10 | Republicanos | Republicanos | 10
11 | Cidadania | Cidadania | 23
12 | Partido Social Cristão | PSC | 20
13 | Partido Comunista do Brasil | PCdoB | 65
14 | Podemos | PODE | 19
15 | Partido Social Democrático | PSD | 55
16 | Partido Verde | PV | 43
17 | Patriota | Patriota | 51
18 | Solidariedade | Solidariedade | 77
19 | Partido Socialismo e Liberdade | PSOL | 50
20 | Avante | Avante | 70
21 | Partido da Mobilização Nacional | PMN | 33
22 | Partido Trabalhista Cristão | PTC | 36
23 | Democracia Cristã | DC | 27
24 | Partido Renovador Trabalhista Brasileiro | PRTB | 28
25 | Partido Republicano da Ordem Social | PROS | 90
26 | Partido Social Liberal | PSL | 17
27 | Partido da Mulher Brasileira | PMB | 35
28 | Rede Sustentabilidade | REDE | 18
29 | Partido Novo | NOVO | 30
30 | Partido Socialista dos Trabalhadores Unificado | PSTU | 16
31 | Partido Comunista Brasileiro | PCB | 21
32 | Partido da Causa Operária | PCO | 29
33 | Unidade Popular | UP | 80
34 | Partido Pátria Livre | PPL | 54
35 | Partido Republicano Progressista | PRP | 44
36 | REDE SUSTENTABILIDADE | REDE | 31`;
37 |
38 | export const getPartidosInfo = () => {
39 | const list = PARTIDOS.split('\n');
40 | const result = [];
41 | list.forEach((line) => {
42 | const split = line.split('|');
43 | const partido = {
44 | nome: split[0].trim(),
45 | sigla: split[1].trim(),
46 | numero: split[2].trim(),
47 | };
48 | result.push(partido);
49 | });
50 |
51 | return result;
52 | };
53 |
54 | export const getPartidoData = (number) => {
55 | const partidos = getPartidosInfo();
56 | const result = partidos.find((partido) => partido.numero === `${number}`);
57 |
58 | return result || null;
59 | };
60 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/NullBoxesPage/transformers.ts:
--------------------------------------------------------------------------------
1 | import { applyFilter } from '@gavetaio/core';
2 | import { chartObjectToData } from 'renderer/helpers/data';
3 |
4 | export const filteredNullBoxes = ({ boxes, filters }) => {
5 | const header = [
6 | 'Cidade',
7 | 'Ano',
8 | 'UF',
9 | 'Turno',
10 | 'Zona',
11 | 'Seção',
12 | 'Comparecimento',
13 | 'Votos Perdidos',
14 | 'Status',
15 | ];
16 |
17 | const result: any = [];
18 | const groupBy = filters?.groups?.length ? filters.groups[0] : 'ano';
19 |
20 | const chart: any = {
21 | federal: {},
22 | municipal: {},
23 | };
24 |
25 | boxes.forEach((box) => {
26 | const {
27 | ano,
28 | uf,
29 | turno,
30 | municipio,
31 | zona,
32 | secao,
33 | comparecimento,
34 | count,
35 | status,
36 | isFederal,
37 | } = box;
38 |
39 | if (ano === '1994') {
40 | return;
41 | }
42 |
43 | const chartType = isFederal ? 'federal' : 'municipal';
44 | const group = groupBy === 'uf' ? uf : ano;
45 |
46 | if (!applyFilter({ filters, ano, uf })) {
47 | return;
48 | }
49 |
50 | if (!chart[chartType][group]) {
51 | chart[chartType][group] = {
52 | count: 0,
53 | };
54 | }
55 |
56 | chart[chartType][group].count += count;
57 |
58 | const row = [
59 | municipio,
60 | ano,
61 | uf,
62 | { value: turno },
63 | { value: zona },
64 | { value: secao },
65 | { value: comparecimento, label: comparecimento || '-' },
66 | { value: count },
67 | status,
68 | '-',
69 | ];
70 |
71 | result.push({
72 | data: row,
73 | });
74 | });
75 |
76 | return {
77 | table: {
78 | header,
79 | data: result,
80 | sortDefault: 1,
81 | footer: ['count', '', '', '', '', '', 'average', 'sum', ''],
82 | },
83 | chart: {
84 | title: 'Gráfico',
85 | labelX: 'ano eleitoral',
86 | labelY: 'número de votos anulados',
87 | ...chartObjectToData(chart),
88 | },
89 | };
90 | };
91 |
--------------------------------------------------------------------------------
/packages/elections/.erb/scripts/check-native-dep.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import chalk from 'chalk';
3 | import { execSync } from 'child_process';
4 | import { dependencies } from '../../package.json';
5 |
6 | if (dependencies) {
7 | const dependenciesKeys = Object.keys(dependencies);
8 | const nativeDeps = fs
9 | .readdirSync('node_modules')
10 | .filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`));
11 | if (nativeDeps.length === 0) {
12 | process.exit(0);
13 | }
14 | try {
15 | // Find the reason for why the dependency is installed. If it is installed
16 | // because of a devDependency then that is okay. Warn when it is installed
17 | // because of a dependency
18 | const { dependencies: dependenciesObject } = JSON.parse(
19 | execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString()
20 | );
21 | const rootDependencies = Object.keys(dependenciesObject);
22 | const filteredRootDependencies = rootDependencies.filter((rootDependency) =>
23 | dependenciesKeys.includes(rootDependency)
24 | );
25 | if (filteredRootDependencies.length > 0) {
26 | const plural = filteredRootDependencies.length > 1;
27 | console.log(`
28 | ${chalk.whiteBright.bgYellow.bold(
29 | 'Webpack does not work with native dependencies.'
30 | )}
31 | ${chalk.bold(filteredRootDependencies.join(', '))} ${
32 | plural ? 'are native dependencies' : 'is a native dependency'
33 | } and should be installed inside of the "./release/app" folder.
34 | First, uninstall the packages from "./package.json":
35 | ${chalk.whiteBright.bgGreen.bold('npm uninstall your-package')}
36 | ${chalk.bold(
37 | 'Then, instead of installing the package to the root "./package.json":'
38 | )}
39 | ${chalk.whiteBright.bgRed.bold('npm install your-package')}
40 | ${chalk.bold('Install the package to "./release/app/package.json"')}
41 | ${chalk.whiteBright.bgGreen.bold('cd ./release/app && npm install your-package')}
42 | Read more about native dependencies at:
43 | ${chalk.bold(
44 | 'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure'
45 | )}
46 | `);
47 | process.exit(1);
48 | }
49 | } catch (e) {
50 | console.log('Native dependencies could not be checked');
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/components/Dropper.module.scss:
--------------------------------------------------------------------------------
1 | .footer {
2 | padding: var(--unit-v-3) var(--unit-h-3);
3 | margin-top: 12px;
4 | display: flex;
5 | align-items: center;
6 | justify-content: flex-end;
7 |
8 | > button {
9 | &:nth-child(1) {
10 | margin-left: 0;
11 | }
12 | margin-left: var(--unit-h-3);
13 | }
14 | }
15 |
16 | .container {
17 | position: relative;
18 | height: 144px;
19 | width: 100%;
20 | z-index: 10;
21 | border: 2px solid var(--background-dark);
22 | border-radius: 12px;
23 | padding: var(--unit-v-3) var(--unit-h-3);
24 | background-color: var(--background-light);
25 | transition: background-color 175ms ease-out, border-color 175ms ease-out;
26 | cursor: pointer;
27 |
28 | h5 {
29 | margin-top: var(--unit-v-2);
30 | font-size: var(--font-s);
31 | color: var(--text-lighter);
32 | transition: color 175ms ease-out;
33 | }
34 |
35 | &:hover {
36 | background-color: var(--background-dark);
37 |
38 | h5 {
39 | color: var(--text-primary);
40 | }
41 | .icon {
42 | svg {
43 | fill: var(--text-primary);
44 | }
45 | }
46 | }
47 | }
48 |
49 | .icon {
50 | svg {
51 | fill: var(--text-lighter);
52 |
53 | path {
54 | transition: fill 175ms ease-out;
55 | }
56 | }
57 | }
58 |
59 | .files {
60 | padding-top: var(--unit-v-4);
61 | }
62 |
63 | .controls {
64 | display: block;
65 | padding: 24px;
66 | text-align: center;
67 |
68 | button {
69 | margin: 12px;
70 | }
71 | }
72 |
73 | .active {
74 | background-color: var(--background-lighter);
75 | }
76 |
77 | .wrapper {
78 | display: flex;
79 | position: absolute;
80 | top: 0;
81 | left: 0;
82 | right: 0;
83 | bottom: 0;
84 | align-items: center;
85 | text-align: center;
86 | justify-content: center;
87 | flex-direction: column;
88 | }
89 |
90 | .loading {
91 | display: flex;
92 | position: fixed;
93 | top: 0;
94 | left: 0;
95 | right: 0;
96 | bottom: 0;
97 | background-color: rgba(255, 0, 0, 0.25);
98 | z-index: 9001;
99 | align-items: center;
100 | justify-content: center;
101 |
102 | .status {
103 | padding: 16px;
104 | margin-top: 24px;
105 | background-color: var(--background-light);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/packages/ui/src/base/ElevatedPressable.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useRef, useCallback, useEffect } from "react";
2 | import Elevation from "./Elevation";
3 |
4 | const ElevatedPressable = ({
5 | onClick = () => null,
6 | onLongPress = () => null,
7 | children,
8 | attrs = {},
9 | ...extra
10 | }: any) => {
11 | const [pressed, setPressed] = useState(false);
12 | const ref = useRef(null);
13 | const time = useRef({
14 | timer: null,
15 | pressed: false,
16 | });
17 |
18 | const longPress = useCallback(() => {
19 | time.current.pressed = true;
20 | onLongPress();
21 | }, [onLongPress]);
22 |
23 | const press = useCallback(() => {
24 | time.current.pressed = false;
25 | time.current.timer = setTimeout(longPress, 5000);
26 | return !pressed && setPressed(true);
27 | }, [pressed, longPress]);
28 |
29 | const release = useCallback(() => {
30 | clearTimeout(time.current.timer);
31 | return pressed && setPressed(false);
32 | }, [pressed]);
33 |
34 | const action = useCallback(
35 | (event) => {
36 | if (time.current.pressed) {
37 | release();
38 | return;
39 | }
40 | onClick(event);
41 | release();
42 | },
43 | [release]
44 | );
45 |
46 | const emulateTrigger = (event) => {
47 | setPressed(true);
48 | setTimeout(() => {
49 | onClick(children);
50 | setPressed(false);
51 | if (event?.detail?.callback) {
52 | requestAnimationFrame(() => {
53 | event.detail.callback();
54 | });
55 | }
56 | }, 325);
57 | };
58 |
59 | useEffect(() => {
60 | if (ref?.current) {
61 | ref.current.addEventListener("btnPress", emulateTrigger);
62 | }
63 | }, []);
64 |
65 | return (
66 |
80 |
85 | {children}
86 |
87 |
88 | );
89 | };
90 |
91 | export default ElevatedPressable;
92 |
--------------------------------------------------------------------------------
/packages/elections/.erb/configs/webpack.config.main.prod.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Webpack config for production electron main process
3 | */
4 |
5 | import path from 'path';
6 | import webpack from 'webpack';
7 | import { merge } from 'webpack-merge';
8 | import TerserPlugin from 'terser-webpack-plugin';
9 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
10 | import baseConfig from './webpack.config.base';
11 | import webpackPaths from './webpack.paths';
12 | import checkNodeEnv from '../scripts/check-node-env';
13 | import deleteSourceMaps from '../scripts/delete-source-maps';
14 |
15 | checkNodeEnv('production');
16 | deleteSourceMaps();
17 |
18 | const devtoolsConfig =
19 | process.env.DEBUG_PROD === 'true'
20 | ? {
21 | devtool: 'source-map',
22 | }
23 | : {};
24 |
25 | export default merge(baseConfig, {
26 | ...devtoolsConfig,
27 |
28 | mode: 'production',
29 |
30 | target: 'electron-main',
31 |
32 | entry: {
33 | main: path.join(webpackPaths.srcMainPath, 'main.ts'),
34 | preload: path.join(webpackPaths.srcMainPath, 'preload.js'),
35 | },
36 |
37 | output: {
38 | path: webpackPaths.distMainPath,
39 | filename: '[name].js',
40 | },
41 |
42 | optimization: {
43 | minimizer: [
44 | new TerserPlugin({
45 | parallel: true,
46 | }),
47 | ],
48 | },
49 |
50 | plugins: [
51 | new BundleAnalyzerPlugin({
52 | analyzerMode:
53 | process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
54 | openAnalyzer: process.env.OPEN_ANALYZER === 'true',
55 | }),
56 |
57 | /**
58 | * Create global constants which can be configured at compile time.
59 | *
60 | * Useful for allowing different behaviour between development builds and
61 | * release builds
62 | *
63 | * NODE_ENV should be production so that modules do not perform certain
64 | * development checks
65 | */
66 | new webpack.EnvironmentPlugin({
67 | NODE_ENV: 'production',
68 | DEBUG_PROD: false,
69 | START_MINIMIZED: false,
70 | }),
71 | ],
72 |
73 | /**
74 | * Disables webpack processing of __dirname and __filename.
75 | * If you run the bundle in node.js it falls back to these values of node.js.
76 | * https://github.com/webpack/webpack/issues/2010
77 | */
78 | node: {
79 | __dirname: false,
80 | __filename: false,
81 | },
82 | });
83 |
--------------------------------------------------------------------------------
/packages/ui/src/base/Button.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | --button-default-height: 42px;
3 | --color-key: var(--background-active);
4 | --elevation-state: 0.3;
5 | --button-raise-level: 4;
6 | --button-default-height: calc(var(--unit-v-4) * 1.25);
7 | --button-horizontal-padding: calc(
8 | var(--button-default-height) - var(--button-raise-level)
9 | );
10 |
11 | display: block;
12 | position: relative;
13 | height: var(--button-default-height);
14 | width: 144px;
15 | text-align: center;
16 |
17 | .icon {
18 | > span > span {
19 | transform: translateX(0);
20 | }
21 | }
22 |
23 | > div {
24 | --elevation: var(--button-raise-level);
25 | }
26 |
27 | &:hover {
28 | > div {
29 | --elevation-state: 0.7;
30 | }
31 | }
32 |
33 | &.primary {
34 | > div {
35 | --elevation-bg-case: var(--background-active) !important;
36 | }
37 | }
38 |
39 | &.secondary {
40 | > div {
41 | --elevation-bg-case: var(--background-light) !important;
42 | }
43 | }
44 |
45 | &.danger {
46 | > div {
47 | --elevation-bg-case: var(--background-sang-light) !important;
48 | }
49 | }
50 |
51 | &.link {
52 | > div {
53 | --elevation-bg-case: var(--background-nuit);
54 | }
55 | }
56 |
57 | &.disabled {
58 | .icon {
59 | > span {
60 | --icon-bg: var(--text-dark);
61 | }
62 | }
63 | span {
64 | color: var(--text-dark);
65 | }
66 | > div {
67 | --elevation-bg-case: var(--background-light);
68 | }
69 | }
70 |
71 | &.small {
72 | //
73 | }
74 |
75 | &.medium {
76 | width: 144px;
77 | }
78 |
79 | &.large {
80 | width: 188px;
81 | }
82 |
83 | &.huge {
84 | width: 240px;
85 | }
86 |
87 | > div {
88 | }
89 |
90 | > div > div {
91 | align-items: center;
92 | justify-content: center;
93 | }
94 |
95 | &.left {
96 | .icon {
97 | transform: translateX(-50%);
98 | }
99 | }
100 |
101 | &.right {
102 | .icon {
103 | transform: translateX(50%);
104 | }
105 | }
106 | }
107 |
108 | .content {
109 | display: flex;
110 | font-size: calc(var(--font-xxs));
111 | line-height: calc(var(--font-xxs) * 1.5);
112 | align-items: center;
113 | justify-content: center;
114 | color: var(--text-primary);
115 | }
116 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/components/Navigation.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, useLocation } from 'react-router-dom';
3 | import styles from './Navigation.module.scss';
4 |
5 | const links = [
6 | {
7 | section: 'PRÆAMBULUS',
8 | links: [
9 | {
10 | to: '/sobre',
11 | name: 'Sobre este projeto',
12 | },
13 | ],
14 | },
15 | {
16 | section: 'INPUT',
17 | links: [
18 | {
19 | to: '/',
20 | name: 'Dados carregados',
21 | },
22 | ],
23 | },
24 | {
25 | section: 'SIMULADOR',
26 | links: [
27 | {
28 | to: '/simulador/legado',
29 | name: 'Legado',
30 | },
31 | {
32 | to: '/simulador/refatorado',
33 | name: 'Refatorado',
34 | },
35 | ],
36 | },
37 | {
38 | section: 'ANÁLISE DE DADOS',
39 | links: [
40 | {
41 | to: '/urnas-anuladas',
42 | name: 'Urnas Anuladas',
43 | },
44 | {
45 | to: '/sigilo-quebrado',
46 | name: 'Sigilo Quebrado',
47 | },
48 | {
49 | to: '/votos-excluidos',
50 | name: 'Votos Excluídos',
51 | },
52 | ],
53 | },
54 | ];
55 |
56 | const Navigation = () => {
57 | const location = useLocation();
58 |
59 | const renderLink = ({ to, name }) => {
60 | const cls = [];
61 |
62 | if (location.pathname === to) {
63 | cls.push(styles.active);
64 | }
65 | return (
66 |
67 | {name}
68 |
69 | );
70 | };
71 |
72 | return (
73 |
74 |
81 |
82 | {links.map((params) => {
83 | const result = [];
84 | if (params.section) {
85 | result.push(
{params.section} );
86 | params.links.forEach((link) => {
87 | result.push(renderLink(link));
88 | });
89 | } else {
90 | // @ts-ignore
91 | result.push(renderLink(params));
92 | }
93 | return ;
94 | })}
95 |
96 |
97 | );
98 | };
99 |
100 | export default Navigation;
101 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/ExposedPage/ExposedPage.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 | import { useLayoutContext } from 'renderer/context/layout';
3 | import { filteredExposedByBoxExposed } from './transformers';
4 | import {
5 | Wrapper,
6 | Table,
7 | Block,
8 | Loader,
9 | LineChart,
10 | Section,
11 | Empty,
12 | } from '@gavetaio/ui';
13 | import { useNavigation } from 'renderer/features/navigation';
14 |
15 | const ExposedPage = () => {
16 | const { getData, apiGet }: any = useLayoutContext();
17 | const { boxesExposed } = getData();
18 | const { navigate } = useNavigation();
19 |
20 | useEffect(() => {
21 | if (!boxesExposed?.length) {
22 | apiGet({ action: 'get/boxes/exposed' });
23 | }
24 | }, []);
25 |
26 | const renderData = () => {
27 | if (typeof boxesExposed === 'undefined') {
28 | return ;
29 | }
30 |
31 | if (!boxesExposed?.length) {
32 | return navigate('/')} />;
33 | }
34 |
35 | const transformed = filteredExposedByBoxExposed({
36 | boxes: boxesExposed,
37 | navigate,
38 | filters: { groups: ['uf'] },
39 | });
40 |
41 | return (
42 | <>
43 |
46 |
49 | >
50 | );
51 | };
52 |
53 | return (
54 |
55 |
56 |
57 |
58 | Esta análise explora a quebra do sigilo do voto de forma
59 | direta em eleições recentes. São seções onde para um determinado
60 | cargo, todos eleitores tenham votado em um mesmo candidato; para a
61 | confirmação desta ocorrência ser completa, também checamos se a
62 | mesma seção possui zero votos inválidos (brancos ou nulos)
63 | para o mesmo cargo. Veja maiores detalhes no documento{' '}
64 |
65 | gaveta.io/G2V2
66 | {' '}
67 | —{' '}
68 |
69 | Da quebra do sigilo do voto nas eleições brasileiras
70 |
71 |
72 |
73 |
74 | {renderData()}
75 |
76 | );
77 | };
78 |
79 | export default ExposedPage;
80 |
--------------------------------------------------------------------------------
/packages/engine/src/eleicoes/investigations/city-info.js:
--------------------------------------------------------------------------------
1 | const { forEachList } = require("../helpers");
2 |
3 | const injectCandidateCount = ({ turno, data, scope = null, callback }) => {
4 | const total = {
5 | all: 0,
6 | inelegiveis: 0,
7 | deferidos: 0,
8 | };
9 |
10 | forEachList(data.candidatos, (cargo, candidatos) => {
11 | let inelegiveis = 0;
12 | let deferidos = 0;
13 |
14 | forEachList(candidatos, (nome, info) => {
15 | if (info.situacao !== 0) {
16 | inelegiveis += 1;
17 | }
18 | if (
19 | info.raw &&
20 | info.raw.pleito.match(/^deferido$/gim) &&
21 | info.raw.urna.match(/^deferido$/gim) &&
22 | info.raw.atual.match(/^deferido$/gim)
23 | ) {
24 | deferidos += 1;
25 | }
26 | });
27 |
28 | const count = Object.keys(candidatos).length;
29 |
30 | total.all += count;
31 | total.inelegiveis += inelegiveis;
32 | total.deferidos += deferidos;
33 |
34 | callback({
35 | turno,
36 | scope,
37 | path: `cargos.${cargo}.`,
38 | data: [
39 | { path: "candidatos", add: count },
40 | { path: "inelegiveis", add: inelegiveis },
41 | { path: "deferidos", add: deferidos },
42 | ],
43 | });
44 | });
45 |
46 | callback({
47 | turno,
48 | scope,
49 | path: `absolutos.`,
50 | data: [
51 | { path: "candidatos", add: total.all },
52 | { path: "inelegiveis", add: total.inelegiveis },
53 | { path: "deferidos", add: total.deferidos },
54 | ],
55 | });
56 | };
57 |
58 | const injectCandidate = ({ isFederal, turno, data, callback }) => {
59 | if (isFederal) {
60 | injectCandidateCount({ turno, data, scope: null, callback });
61 | } else {
62 | forEachList(data.cidades, (codigo, cidade) => {
63 | injectCandidateCount({ turno, data: cidade, scope: codigo, callback });
64 | });
65 | }
66 | };
67 |
68 | export const populateCityInfo = ({
69 | resultados,
70 | callback,
71 | suplementares,
72 | accumulator,
73 | }) => {
74 | const isFederal = accumulator.headers.federal;
75 |
76 | forEachList(suplementares, (codigo, data) => {
77 | const { TURNO, SCOPE } = data;
78 | callback({
79 | turno: TURNO,
80 | scope: SCOPE,
81 | path: `suplementar`,
82 | value: true,
83 | scoped: true,
84 | });
85 | });
86 |
87 | forEachList(resultados, (turno, data) => {
88 | const turnoNumber = turno.split("_")[1];
89 | injectCandidate({ isFederal, turno: turnoNumber, data, callback });
90 | });
91 | };
92 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Keypad.tsx:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from "react";
2 | // @ts-ignore
3 | import styles from "./Keypad.module.scss";
4 | import Keyboard from "./Keyboard";
5 | import Controls from "./Controls";
6 | import Badge from "./Badge";
7 |
8 | function sleep(ms) {
9 | return new Promise((resolve) => setTimeout(resolve, ms));
10 | }
11 |
12 | const Keypad = ({
13 | onKeyPress,
14 | onFixPress,
15 | onFixLongPress,
16 | onBlankPress,
17 | onBlankLongPress,
18 | onConfirmLongPress,
19 | onConfirmPress,
20 | handleAction,
21 | badgeTitle = null,
22 | }: any) => {
23 | const ref = useRef(null);
24 |
25 | const callEvent = (num) => {
26 | return new Promise((resolve) => {
27 | const buttons = ref.current.querySelectorAll("button");
28 | const ev = new CustomEvent("btnPress", { detail: { callback: resolve } });
29 | if (num === "CO") {
30 | buttons[12].dispatchEvent(ev);
31 | return;
32 | }
33 | if (num === "CR") {
34 | buttons[11].dispatchEvent(ev);
35 | return;
36 | }
37 | if (num === "BR") {
38 | buttons[10].dispatchEvent(ev);
39 | return;
40 | }
41 | if (num >= 0 && num < 10) {
42 | buttons[num - 1].dispatchEvent(ev);
43 | }
44 | });
45 | };
46 |
47 | useEffect(() => {
48 | //
49 | ref.current.addEventListener("bundlePress", async (event) => {
50 | if (!event?.detail?.value?.length) {
51 | return;
52 | }
53 | const { value, callback } = event.detail;
54 | if (!value?.length) {
55 | return;
56 | }
57 |
58 | for (let i = 0; i < value.length; i += 1) {
59 | await callEvent(value[i]);
60 | await sleep(375);
61 | }
62 | });
63 | }, []);
64 |
65 | return (
66 |
70 |
71 | {
75 | return (
76 |
87 | );
88 | }}
89 | />
90 |
91 | );
92 | };
93 |
94 | export default Keypad;
95 |
--------------------------------------------------------------------------------
/packages/elections/src/main/api/api.ts:
--------------------------------------------------------------------------------
1 | import {
2 | transformEleicoesList,
3 | transformBoxesTable,
4 | getTitleTags,
5 | capitalize,
6 | transformEleicoesDataList,
7 | filterExposedByYear,
8 | filterExposedByUf,
9 | } from '@gavetaio/core';
10 |
11 | const transformActionToProblem = (action) => {
12 | if (action === 'nulled') {
13 | return 'NULL_BOX';
14 | }
15 | if (action === 'exposed') {
16 | return 'EXPOSED_VOTES';
17 | }
18 |
19 | if (action === 'size') {
20 | return 'SIZE_DIFFERENCE';
21 | }
22 |
23 | if (action === 'manual') {
24 | return 'MANUAL_COUNT';
25 | }
26 |
27 | return null;
28 | };
29 |
30 | class LocalApi {
31 | static folder: any;
32 |
33 | static memory: any;
34 |
35 | constructor({ folder, memory }) {
36 | LocalApi.folder = folder;
37 | LocalApi.memory = memory;
38 | }
39 |
40 | get({ action, params = {}, callback }) {
41 | if (action.match(/get\/election\/.*/gim)) {
42 | const info = action.split('/');
43 | const eleicaoIds = info[2].split(',');
44 |
45 | LocalApi.memory.getDataFromIds({ ids: eleicaoIds }, (data) => {
46 | callback({ upsert: { name: 'elections', data } });
47 | });
48 |
49 | return;
50 | }
51 |
52 | if (action === 'get/elections') {
53 | LocalApi.memory.getElectionList((data) => {
54 | const result = transformEleicoesList(data);
55 | const years = getTitleTags(data, 'year', /[a-z]{2}-(.*)-.*/gim);
56 | const ufs = getTitleTags(data, 'uf', /([a-z]{2})-.*/gim);
57 |
58 | callback({ electionList: { data: result, tags: { years, ufs } } });
59 | });
60 | return;
61 | }
62 |
63 | if (action.match(/get\/boxes/gim)) {
64 | const info = action.split('/');
65 | const problem = transformActionToProblem(info[2]);
66 | const name = `boxes${capitalize(info[2])}`;
67 |
68 | LocalApi.memory.getBoxesByProblem(problem, (data) => {
69 | try {
70 | const transformed = transformBoxesTable(data, problem);
71 | callback({ [`${name}`]: transformed });
72 | } catch (e) {}
73 | });
74 | return;
75 | }
76 |
77 | if (action === 'get/votes/excluded') {
78 | LocalApi.memory.getAllElections((data) => {
79 | const result = transformEleicoesDataList(data);
80 | const byYear = filterExposedByYear(result);
81 | const byUf = filterExposedByUf(result);
82 | callback({ votesExcluded: { byYear, byUf } });
83 | });
84 | return;
85 | }
86 | }
87 | }
88 |
89 | export default LocalApi;
90 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/ExposedPage/transformers.ts:
--------------------------------------------------------------------------------
1 | import { createChartObject, applyFilter } from '@gavetaio/core';
2 |
3 | export const filteredExposedByBoxExposed = ({
4 | boxes,
5 | navigate,
6 | filters,
7 | }: any) => {
8 | const header = [
9 | 'Ano',
10 | 'Cargos',
11 | 'UF/Turno',
12 | 'Cidade',
13 | 'Zona/Seção',
14 | 'Comparecimento',
15 | 'Votos Expostos',
16 | ];
17 | const result: any = [];
18 | const chart: any = {
19 | federal: {},
20 | municipal: {},
21 | };
22 |
23 | const groupBy = filters?.groups?.length ? 'ano' : filters.groups[0];
24 |
25 | boxes.forEach((box) => {
26 | const {
27 | id,
28 | ano,
29 | uf,
30 | turno,
31 | municipio,
32 | extra,
33 | zona,
34 | secao,
35 | comparecimento,
36 | count,
37 | isFederal,
38 | } = box;
39 |
40 | if (!applyFilter({ filters, ano, uf, cargos: extra })) {
41 | return;
42 | }
43 |
44 | const extraList = extra.map((item) => {
45 | const split = item.split('-');
46 | let initial = split[0].slice(0, 1);
47 | if (split[0].match(/federal/)) {
48 | initial = 'f';
49 | }
50 | if (split[0].match(/estadual/)) {
51 | initial = 'e';
52 | }
53 | return `${split[0]}-${split[1]}`;
54 | });
55 |
56 | const row = [
57 | {
58 | value: ano * 1,
59 | label: ano,
60 | onClick: (event) => {
61 | navigate(id, { event });
62 | },
63 | },
64 | { list: extraList },
65 | `${uf}/${turno}`,
66 | municipio,
67 | `${zona}/${secao}`,
68 | comparecimento,
69 | count,
70 | ];
71 |
72 | const chartType = isFederal ? 'federal' : 'municipal';
73 |
74 | const group = groupBy === 'uf' ? uf : ano;
75 |
76 | if (!chart[chartType][group]) {
77 | chart[chartType][group] = {
78 | count: 0,
79 | total: 0,
80 | };
81 | }
82 |
83 | chart[chartType][group].count += count;
84 |
85 | result.push({
86 | data: row,
87 | });
88 | });
89 |
90 | const chartObj = createChartObject({
91 | x: 'Ano Eleitoral',
92 | y: 'Votos com sigilo quebrado',
93 | data: chart,
94 | });
95 |
96 | return {
97 | table: {
98 | title: 'Dados',
99 | header,
100 | data: result,
101 | sortDefault: 7,
102 | footer: ['count', '', '', '', '', 'sum', 'sum'],
103 | },
104 | chart: chartObj,
105 | };
106 | };
107 |
--------------------------------------------------------------------------------
/docs/excluidos.md:
--------------------------------------------------------------------------------
1 | ### Votos excluídos por indeferimento de candidatura
2 |
3 | A tabela abaixo lista apenas os **votos excluídos por indeferimento de candidatura** de 1994 a 2020.
4 |
5 | - A fonte de informação para a situação de cada candidato foi o arquivo **consulta_cand** do repositório de dados eleitorais.
6 | - Nos anos de **1994** e **1996** a informação sobre o indeferimento da candidatura não está disponível nos dados eleitorais disponíveis.
7 | - Nos anos sem informação granular foram consinderados os candidatos com status **sub-júdice**, no demais com o status **indeferido com recurso**.
8 | - A coluna de **Votos** mostra o total de votos analisados
9 | - A coluna **Excluídos** mostra o total de votos excluídos por indeferimento judicial de candidatura; consideradas tanto a invalidação de canditatos quanto partidos
10 |
11 | Seguindo as garantias estabelecidas pela **Lei de Transparência Pública** `Nº 12.527`, qualquer cidadão pode requisitar estes dados, diretamente com os órgãos oficiais responsáveis; a requisição pode ser feita da seguinte forma: `Lista do número total de votos válidos anulados por terem sido direcionados a candidatos ou partidos que se encontravam com o status de INDEFERIDOS COM RECURSO quando da data de votação do primeiro turno das eleições de 1994 a 2020; agrupados por ano eleitoral.`
12 |
13 | A partir do momento que forem captadas as razões oficiais para as anulações destas urnas, caso seja encontrado algum erro nesta listagem, qualquer pessoa pode pedir sua correção através do envio de uma `PR` para este `repositório`.
14 |
15 | | **Ano / Turno** | **Eleitores** | **Votos** | **Excluídos** |
16 | | --------------- | ------------- | --------- | ------------- |
17 | | 2020/1 | 113675327 | 227350652 | 1804923 |
18 | | 2018/1 | 117161795 | 702721150 | 3210987 |
19 | | 2016/1 | 118757770 | 237515540 | 2335801 |
20 | | 2014/1 | 114981383 | 574607706 | 1381150 |
21 | | 2012/1 | 115807514 | 231615028 | 2901057 |
22 | | 2010/1 | 111038684 | 666232102 | 3890259 |
23 | | 2008/1 | 110085205 | 220170363 | 2801402 |
24 | | 2006/1 | 104779073 | 523895343 | 539650 |
25 | | 2004/1 | 101670039 | 203338741 | 382468 |
26 | | 2002/1 | 94767056 | 568599360 | 236773 |
27 | | 2000/1 | 87416380 | 174828046 | 31810 |
28 | | 1998/1 | 83288358 | 416392739 | 86188 |
29 | | 1996/1 | 5993367 | 11986674 | — |
30 | | 1994/1 | 40904527 | 245383410 | — |
31 | | **14** | | | **19602468** |
32 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/helpers/data.ts:
--------------------------------------------------------------------------------
1 | import find from 'lodash/find';
2 |
3 | export const getBoxById = (id, boxes) => {
4 | return find(boxes, { id });
5 | };
6 |
7 | export const average = (arr: any) => {
8 | return arr.reduce((a: number, b: number) => a + b, 0) / arr.length;
9 | };
10 |
11 | export const pushUnique = (array, item) => {
12 | if (array.indexOf(item) === -1) {
13 | array.push(item);
14 | }
15 | };
16 |
17 | export const getBoxProblemas = (box) => {
18 | const problemas = [];
19 | if (box.absolutos.perdidos) {
20 | problemas.push(['Votos Perdidos', box.absolutos.perdidos]);
21 | }
22 | return problemas;
23 | };
24 |
25 | export const getBoxProblemasTable = (box) => {
26 | const table = {
27 | danger: true,
28 | header: ['Problema', ''],
29 | data: null,
30 | };
31 | const problemas = getBoxProblemas(box);
32 |
33 | if (problemas?.length) {
34 | table.data = problemas;
35 | }
36 |
37 | return table;
38 | };
39 |
40 | export const getElectionProblemasDataRow = (election) => {
41 | const problemas = [];
42 | if (election.problemas) {
43 | election.problemas.forEach((problema) => {
44 | let label = problema.type;
45 | let impact = `${problema.count} votos`;
46 | if (problema.type === 'EXPOSED_VOTES') {
47 | label = 'SIGILO QUEBRADO';
48 | }
49 | if (problema.type === 'NULL_BOX') {
50 | label = 'URNAS ANULADAS';
51 | impact = `${problema.count} votos perdidos`;
52 | }
53 | const splitted = problema.id.split('-');
54 | const city = election.cidades[splitted[3]];
55 | problemas.push([problema.id, city.nome, label, impact]);
56 | });
57 | }
58 | return problemas;
59 | };
60 |
61 | export const getElectionsProblemasTable = (election) => {
62 | const table = {
63 | danger: true,
64 | header: ['Urna', 'Cidade', 'Problema', 'Impacto'],
65 | data: null,
66 | };
67 | const problemas = getElectionProblemasDataRow(election);
68 |
69 | if (problemas?.length) {
70 | table.data = problemas;
71 | }
72 |
73 | return table;
74 | };
75 |
76 | export const chartObjectToData = (chart) => {
77 | const keys = Object.keys(chart);
78 | const lines = [];
79 | if (keys?.length) {
80 | keys.forEach((key) => {
81 | const line = { label: key, points: [] };
82 | const keys = Object.keys(chart[key]);
83 | keys.forEach((k) => {
84 | const { count, total } = chart[key][k];
85 | let value = count;
86 | if (total) {
87 | value = count / total;
88 | }
89 | line.points.push([k, value]);
90 | });
91 | if (line?.points?.length) {
92 | lines.push(line);
93 | }
94 | });
95 | }
96 |
97 | return { data: lines };
98 | };
99 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/NulledVotesPage/NulledVotesPage.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 | import { useLayoutContext } from 'renderer/context/layout';
3 | import {
4 | Wrapper,
5 | Table,
6 | Block,
7 | Loader,
8 | Section,
9 | LineChart,
10 | Empty,
11 | } from '@gavetaio/ui';
12 | import { filteredNulledSummary } from './transformers';
13 | import { useNavigation } from 'renderer/features/navigation';
14 |
15 | const NullVotesPage = () => {
16 | const { apiGet, getData }: any = useLayoutContext();
17 | const { votesExcluded } = getData();
18 | const { navigate } = useNavigation();
19 |
20 | useEffect(() => {
21 | if (!votesExcluded?.length) {
22 | apiGet({ action: 'get/votes/excluded' });
23 | }
24 | }, []);
25 |
26 | const renderSummary = () => {
27 | if (typeof votesExcluded === 'undefined') {
28 | return ;
29 | }
30 |
31 | if (!votesExcluded?.length) {
32 | return navigate('/')} />;
33 | }
34 |
35 | const transformed = filteredNulledSummary(votesExcluded);
36 |
37 | return (
38 | <>
39 |
42 |
45 | >
46 | );
47 | };
48 |
49 | return (
50 |
51 |
52 |
53 |
54 | Analisamos aqui os votos anulados por{' '}
55 | indeferimento de candidatura . São candidatos que tiveram seu
56 | nome adicionado na urna eletrônica, mesmo com o indeferimento {' '}
57 | de sua candidatura, por terem apresentado recurso e estarem
58 | aguardando decisão de instância superior. Esta ocorrência tornou-se
59 | comum a partir de 2004 com a publicação da resolução{' '}
60 | 21.608/2004 , e, posteriormente, pela lei 12.034/2009 .
61 | Entenda os detalhes no documento:{' '}
62 |
63 | gaveta.io/g2v5
64 | {' '}
65 | —{' '}
66 |
67 | Da desproporcionalidade do direito político brasileiro
68 |
69 |
70 |
71 | Para localizar esta ocorrência nos dados eleitorais, precisamos
72 | separar os candidatos que estavam com o status{' '}
73 | indeferido com recurso (consulta_cand.zip ) no momento
74 | da inserção na urna eletrônica, e, posteriormente, não tiveram seus
75 | votos computados situação 2, 3 ou 4 . Somados a estes,
76 | também os votos direcionado para a legenda de partidos que
77 | tiveram sua inscrição indeferida.
78 |
79 |
80 |
81 | {!votesExcluded ? : renderSummary()}
82 |
83 | );
84 | };
85 |
86 | export default NullVotesPage;
87 |
--------------------------------------------------------------------------------
/packages/engine/src/eleicoes/investigations/missing-positions.js:
--------------------------------------------------------------------------------
1 | const { forEachList } = require("../helpers");
2 | const { LoggerSingleton } = require("../../log");
3 |
4 | const { log } = LoggerSingleton.getInstance();
5 |
6 | const getYearFromId = (id) => {
7 | return id.replace(/^([^-]+)(-)([^-]+)(-)([^-]+)(-)(.*)/gim, "$3") * 1;
8 | };
9 |
10 | const investigateBox = ({
11 | accumulator,
12 | box,
13 | resultados,
14 | callback,
15 | getParentData,
16 | }) => {
17 | const { cargos, turno, codigo, scope } = box;
18 |
19 | const turnoData = resultados[`turno_${turno}`];
20 |
21 | const parentCargos = getParentData({
22 | turno,
23 | scope,
24 | path: "cargos",
25 | });
26 |
27 | const { multipliers } = turnoData;
28 | const year = getYearFromId(box.id);
29 | const diff = {};
30 | const size = box.absolutos.tamanho;
31 |
32 | if (!turnoData.cidades) {
33 | }
34 |
35 | const citySize = turnoData.cidades[codigo]?.comparecimento || 0;
36 |
37 | const extra = [];
38 | let error = 0;
39 |
40 | if (!parentCargos) {
41 | throw "#65564";
42 | }
43 |
44 | let missingCargos = 0;
45 |
46 | forEachList(parentCargos, (cargo) => {
47 | if (cargos[cargo]) {
48 | extra.push({ cargo, votos: cargos[cargo].total });
49 | return;
50 | }
51 |
52 | if (!multipliers[cargo]) {
53 | throw "#87657";
54 | }
55 |
56 | let perdidos = size * multipliers[cargo];
57 |
58 | error += perdidos;
59 | missingCargos += 1;
60 |
61 | diff[cargo] = perdidos;
62 |
63 | extra.push({
64 | cargo,
65 | votos: 0,
66 | perdidos,
67 | });
68 | });
69 |
70 | if (!error) {
71 | return;
72 | }
73 |
74 | if (year >= 2010 && missingCargos) {
75 | callback({
76 | id: box.id,
77 | path: "transition",
78 | value: true,
79 | });
80 | return;
81 | }
82 |
83 | callback({
84 | id: box.id,
85 | turno,
86 | scope: box.scope,
87 | path: "absolutos.perdidos",
88 | add: error,
89 | });
90 |
91 | callback({
92 | id: box.id,
93 | path: `problemas`,
94 | push: {
95 | type: "MISSING_POSITION",
96 | count: error,
97 | extra,
98 | },
99 | });
100 |
101 | callback({
102 | turno,
103 | scope: box.scope,
104 | path: `problemas`,
105 | push: {
106 | id: box.id,
107 | type: "MISSING_POSITION",
108 | count: error,
109 | extra,
110 | },
111 | });
112 |
113 | log(`MISSING ${missingCargos} - ${box.id}`, {
114 | emoji: "🧨",
115 | });
116 | };
117 |
118 | export const investigateMissingPositions = ({
119 | boxes,
120 | resultados,
121 | callback,
122 | getParentData,
123 | accumulator,
124 | }) => {
125 | forEachList(boxes, (id, data) => {
126 | try {
127 | investigateBox({
128 | box: data,
129 | resultados,
130 | callback,
131 | getParentData,
132 | accumulator,
133 | });
134 | } catch (e) {
135 | throw "#8927";
136 | }
137 | });
138 | };
139 |
--------------------------------------------------------------------------------
/packages/engine/src/index.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const { getDataFromFiles, clearFolder } = require("./utils");
3 | const { Election } = require("./eleicoes/eleicoes");
4 | const { LoggerSingleton } = require("./log");
5 | const {
6 | PARTIALS_FOLDER,
7 | ORIGINAL_FILES_FOLDER,
8 | TEMP_FILE_PATH,
9 | FEDERAL_YEARS,
10 | } = require("./constants");
11 | import { getAncientData } from "./data/ancient";
12 |
13 | const { log, setLogger } = LoggerSingleton.getInstance();
14 |
15 | export function clearFolders(folder) {
16 | clearFolder(`${folder}/${PARTIALS_FOLDER}`);
17 | clearFolder(`${folder}/${ORIGINAL_FILES_FOLDER}`);
18 | }
19 |
20 | export function getAncientHistory(folder) {
21 | return getAncientData();
22 | }
23 |
24 | export function setupFolders(folder) {
25 | if (!fs.existsSync(`${folder}/outputs`)) {
26 | fs.mkdirSync(`${folder}/outputs`);
27 | }
28 |
29 | if (!fs.existsSync(`${folder}/outputs/data`)) {
30 | fs.mkdirSync(`${folder}/outputs/data`);
31 | }
32 | if (!fs.existsSync(`${folder}/${ORIGINAL_FILES_FOLDER}`)) {
33 | fs.mkdirSync(`${folder}/${ORIGINAL_FILES_FOLDER}`);
34 | }
35 | if (!fs.existsSync(`${folder}/${PARTIALS_FOLDER}`)) {
36 | fs.mkdirSync(`${folder}/${PARTIALS_FOLDER}`);
37 | }
38 | if (!fs.existsSync(`${folder}/${TEMP_FILE_PATH}`)) {
39 | fs.mkdirSync(`${folder}/${TEMP_FILE_PATH}`);
40 | }
41 | }
42 |
43 | export async function runPath({ files, section, folder, logger, callback }) {
44 | setLogger(logger);
45 |
46 | global.appFolder = folder;
47 |
48 | const election = new Election();
49 |
50 | if (!files?.length) {
51 | log(["NO FILES FOUND", "REVIEW YOUR data FOLDER AND --input ARGUMENT"], {
52 | emoji: "🛑",
53 | });
54 | return;
55 | }
56 |
57 | log(["FILES FOUND", files.join(", ")], {
58 | emoji: "🚀",
59 | });
60 |
61 | const splitted = section.split("-");
62 |
63 | const uf = splitted[0];
64 | const ano = splitted[1];
65 | const federal = FEDERAL_YEARS.indexOf(ano) !== -1;
66 | log(files, { emoji: "🛑", marginTop: true });
67 | const header = { uf, ano, federal };
68 | if (files.length === 1 && files[0].match(/_BR/gim)) {
69 | header.presidential = true;
70 | }
71 |
72 | election.resetAccumulator(header);
73 |
74 | try {
75 | await getDataFromFiles(
76 | files,
77 | header,
78 | (data) => {
79 | election.populateFromLine(data);
80 | },
81 | (data) => {
82 | election.isCountryCodeWithinScope(data);
83 | }
84 | );
85 | } catch (e) {
86 | log("UNKOWN ERROR", { emoji: "🛑", marginTop: true });
87 | clearFolders(folder);
88 | callback({ error: true });
89 | }
90 |
91 | election.updateGeneralInfo();
92 |
93 | election.printer({
94 | type: "print_ballots",
95 | extra: [],
96 | removed: ["zonas", "coligacoes"],
97 | });
98 |
99 | log("ALL DONE 🐍🪵", { emoji: "☑️ " });
100 |
101 | log("SPEAK UP, SPEAK LOUD → @GAVETAIO", {
102 | emoji: "📣",
103 | });
104 |
105 | clearFolders(folder);
106 | callback({ error: false });
107 | }
108 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/candidate.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/engine/src/eleicoes/printer/utils.js:
--------------------------------------------------------------------------------
1 | const find = require("lodash/find");
2 | const findIndex = require("lodash/findIndex");
3 | const fs = require("fs");
4 | const { LoggerSingleton } = require("../../log");
5 | const { deepClone } = require("../../utils");
6 |
7 | const { log } = LoggerSingleton.getInstance();
8 | const FILE_OUTPUTS = "outputs/data";
9 |
10 | export const pushUniqueBox = (box, boxes) => {
11 | const element = find(boxes, { id: box.id });
12 | const cloned = deepClone(box);
13 | if (!element) {
14 | boxes.push(cloned);
15 | return;
16 | }
17 |
18 | boxes[findIndex(boxes, { id: box.id })] = cloned;
19 | };
20 |
21 | export const getFromFile = (file) => {
22 | const fullpath = `${global.appFolder}/${FILE_OUTPUTS}/${file}`;
23 | if (!fs.existsSync(fullpath)) {
24 | return null;
25 | }
26 |
27 | const content = fs.readFileSync(fullpath, { encoding: "utf8" });
28 |
29 | if (content) {
30 | let result = null;
31 | try {
32 | result = JSON.parse(content);
33 | } catch (e) {
34 | throw "#991";
35 | }
36 | return result;
37 | }
38 | return null;
39 | };
40 |
41 | export const saveToFile = ({ data, filename }) => {
42 | const partials = [`${global.appFolder}/${FILE_OUTPUTS}`, filename.split("/")];
43 |
44 | let acc = "";
45 | for (let i = 0; i < partials.length - 1; i += 1) {
46 | acc += i === 0 ? partials[i] : `/${partials[i]}`;
47 | try {
48 | fs.mkdirSync(acc);
49 | } catch (e) {}
50 | }
51 |
52 | const content = JSON.stringify(data);
53 |
54 | fs.writeFileSync(
55 | `${global.appFolder}/${FILE_OUTPUTS}/${filename}`,
56 | content,
57 | "utf8"
58 | );
59 | };
60 |
61 | export const saveFiles = (list) => {
62 | if (!list || !list.length) {
63 | return false;
64 | }
65 |
66 | list.forEach(({ object, name }) => {
67 | log(["SAVING FILE", `${name}.json`], {
68 | system: true,
69 | });
70 | saveToFile({
71 | data: object,
72 | filename: `${name}.json`,
73 | });
74 |
75 | log("SAVED", { emoji: "☑️ " });
76 | });
77 | };
78 |
79 | export const refactorObject = (object, removed = []) => {
80 | const keys = Object.keys(object);
81 | const result = {};
82 | keys.forEach((key) => {
83 | if (removed.indexOf(key) === -1) {
84 | result[key] = object[key];
85 | }
86 | });
87 | return result;
88 | };
89 |
90 | export const customObjectToOrderedArray = (obj, names, limit = 100) => {
91 | const cloned = deepClone(obj);
92 |
93 | const recursively = (obj) => {
94 | const keys = Object.keys(obj);
95 | let list = [];
96 | for (let i = 0; i < keys.length; i += 1) {
97 | const key = keys[i];
98 | const value = obj[key];
99 | if (typeof value === "object") {
100 | list = recursively(value);
101 | }
102 | if (typeof value !== "object") {
103 | list.push({
104 | [`${names[0]}`]: key,
105 | [`${names[1]}`]: value,
106 | });
107 | }
108 | if (list) {
109 | obj[key] = {
110 | total: list.length,
111 | list: list.sort((a, b) => b[names[1]] - a[names[1]]).slice(0, limit),
112 | };
113 | }
114 | }
115 | return list;
116 | };
117 |
118 | recursively(cloned);
119 | return cloned;
120 | };
121 |
--------------------------------------------------------------------------------
/packages/ui/src/base/LineChart.module.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | flex-direction: column;
4 | background-color: var(--background-dark);
5 | border: 1px solid var(--background-darker);
6 | margin: 24px 0;
7 |
8 | > footer {
9 | display: flex;
10 | justify-content: flex-start;
11 | padding: 4px 24px !important;
12 | background-color: var(--background-darker);
13 | }
14 |
15 | button {
16 | margin-right: 8px;
17 | }
18 | }
19 |
20 | .graph {
21 | width: 80%;
22 | margin: 0 auto;
23 | display: block;
24 | }
25 |
26 | .title {
27 | span {
28 | color: inherit;
29 | font-size: inherit;
30 | }
31 |
32 | button {
33 | margin-left: 12px;
34 | }
35 | }
36 |
37 | .graph {
38 | line {
39 | transition: opacity 125ms ease-out;
40 | }
41 |
42 | &.graphHover {
43 | .grid {
44 | > g > line {
45 | opacity: 0.1;
46 | }
47 | }
48 | }
49 | .textHover {
50 | fill: #fff;
51 | transition: fill 125ms ease-out;
52 | }
53 | }
54 |
55 | .labels {
56 | text {
57 | font-weight: bold;
58 | }
59 |
60 | > g > :nth-last-child(1) {
61 | fill: var(--text-primary);
62 | }
63 | }
64 |
65 | .lineLabel {
66 | display: block;
67 | cursor: pointer;
68 | transition: opacity 125ms ease-out;
69 |
70 | &:hover {
71 | opacity: 1;
72 | }
73 | }
74 |
75 | .grid {
76 | > g {
77 | > line {
78 | transition: opacity 125ms ease-out;
79 | opacity: 0.35;
80 | }
81 | }
82 | }
83 |
84 | .helper {
85 | transition: opacity 125ms ease-out;
86 | opacity: 0;
87 | }
88 |
89 | .helperAnglular {
90 | opacity: 0;
91 | }
92 |
93 | .helperVisible {
94 | opacity: 1;
95 | transform: scaleX(1);
96 | }
97 |
98 | .circleGroup {
99 | text {
100 | opacity: 0;
101 | visibility: hidden;
102 | transition: opacity 125ms ease-out;
103 | }
104 | circle {
105 | cursor: pointer;
106 | transition: all 100ms ease-out;
107 | }
108 | }
109 |
110 | .line {
111 | text {
112 | transition: fill 125ms ease-out;
113 | }
114 | > :nth-child(n) {
115 | transition: opacity 125ms ease-out;
116 | }
117 |
118 | &.inactive {
119 | position: relative;
120 | z-index: -1;
121 |
122 | > :nth-child(1) {
123 | animation: hideInfo 125ms ease-out forwards;
124 | }
125 | > :nth-child(2) {
126 | animation: hideInfo 125ms ease-out forwards;
127 | }
128 | > :nth-child(3) {
129 | opacity: 0.35;
130 | }
131 | }
132 | }
133 |
134 | .lineHover {
135 | text {
136 | transition: fill 125ms ease-out;
137 | fill: #fff;
138 | }
139 | }
140 |
141 | .circleHover {
142 | text {
143 | animation: showInfo 1s forwards;
144 | }
145 | circle {
146 | transform: scale(1.6);
147 | stroke: white;
148 | fill: white;
149 | }
150 | }
151 |
152 | .animateIn {
153 | animation: showInfo 1s linear forwards;
154 | }
155 |
156 | @keyframes showInfo {
157 | 0% {
158 | visibility: hidden;
159 | opacity: 0;
160 | }
161 | 1% {
162 | visibility: visible;
163 | }
164 | 100% {
165 | opacity: 1;
166 | visibility: visible;
167 | }
168 | }
169 |
170 | @keyframes hideInfo {
171 | 0% {
172 | visibility: visible;
173 | opacity: 1;
174 | }
175 | 99% {
176 | visibility: visible;
177 | opacity: 0;
178 | }
179 | 100% {
180 | opacity: 0;
181 | visibility: hidden;
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/packages/elections/src/main/data/data.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-continue */
2 | /* eslint-disable import/prefer-default-export */
3 |
4 | const fs = require('fs');
5 |
6 | const getInfoFromFileName = (filename) => {
7 | const info = {
8 | id: filename.replace(/^([a-z]{2}-[0-9]{4}-[0-9]{1})(.*)/gim, '$1'),
9 | type: 'eleicao',
10 | };
11 |
12 | if (filename.match(/-cidades/)) {
13 | info.type = 'cidades';
14 | }
15 |
16 | if (filename.match(/-candidatos/)) {
17 | info.type = 'candidatos';
18 | }
19 |
20 | if (filename.match(/-boxes/)) {
21 | info.type = 'boxes';
22 | }
23 |
24 | return info;
25 | };
26 |
27 | export const loadFilesFromReg = ({ folder, callback, reg }) => {
28 | const path = `${folder}/outputs/data`;
29 | const list = fs.readdirSync(path);
30 | const result = {};
31 | let loaded = 0;
32 | let loading = 0;
33 |
34 | if (!list?.length) {
35 | callback(result);
36 | return;
37 | }
38 |
39 | const push = ({ data, type, id }) => {
40 | if (!result[id]) {
41 | result[id] = {};
42 | }
43 | if (!result[id][type]) {
44 | result[id][type] = {};
45 | }
46 | result[id][type] = data;
47 |
48 | loaded += 1;
49 | if (loaded === loading) {
50 | //
51 | callback(result);
52 | }
53 | };
54 |
55 | //
56 | for (let i = 0; i < list.length; i += 1) {
57 | const file = list[i];
58 | if (!file.match(reg)) {
59 | continue;
60 | }
61 |
62 | loading += 1;
63 | const info = getInfoFromFileName(file);
64 | fs.readFile(`${path}/${file}`, { encoding: 'utf8' }, (err, content) => {
65 | push({ data: JSON.parse(content), ...info });
66 | });
67 | }
68 |
69 | if (!loading) {
70 | callback(result);
71 | }
72 | };
73 |
74 | export const loadFile = ({ folder, file, callback, reg }) => {
75 | const path = `${folder}/outputs/data/${file}`;
76 | const result = {
77 | data: null,
78 | ...getInfoFromFileName(file),
79 | };
80 | fs.readFile(`${path}/${file}`, { encoding: 'utf8' }, (err, content) => {
81 | result.data = JSON.parse(content);
82 | callback(result);
83 | });
84 | };
85 |
86 | export const loadElectionList = ({ folder, callback }) => {
87 | const path = `${folder}/outputs/data`;
88 | const list = fs.readdirSync(path);
89 | const result = { loaded: 0 };
90 | let loading = 0;
91 |
92 | if (!list?.length) {
93 | callback(result);
94 | return;
95 | }
96 |
97 | const push = ({ data, type, id }) => {
98 | if (!result[id]) {
99 | result[id] = {};
100 | }
101 | if (!result[id][type]) {
102 | result[id][type] = {};
103 | }
104 | result[id][type] = data;
105 |
106 | result.loaded += 1;
107 | if (result.loaded === loading) {
108 | //
109 | callback(result);
110 | }
111 | };
112 |
113 | //
114 | for (let i = 0; i < list.length; i += 1) {
115 | const file = list[i];
116 | if (!file.match(/[a-z]{2}-[0-9]{4}-[0-9]{1}.json/gim)) {
117 | continue;
118 | }
119 |
120 | loading += 1;
121 | const info = getInfoFromFileName(file);
122 | fs.readFile(`${path}/${file}`, { encoding: 'utf8' }, (err, content) => {
123 | try {
124 | const parsed = JSON.parse(content);
125 | if (parsed?.situacao?.list) {
126 | parsed.situacao.list = null;
127 | }
128 | push({ data: parsed, ...info });
129 | } catch (e) {
130 | result.loaded += 1;
131 | }
132 | });
133 | }
134 |
135 | if (!loading) {
136 | callback(result);
137 | }
138 | };
139 |
--------------------------------------------------------------------------------
/packages/elections/src/renderer/screens/SimuladorPage/transformers.ts:
--------------------------------------------------------------------------------
1 | import { deepClone, forEachList, forEachListBreakable } from '@gavetaio/core';
2 | import { PARTIDOS } from '@gavetaio/engine/src/constants';
3 |
4 | const CARGO_LABEL = {
5 | cargos: {
6 | senador: 'Senador',
7 | deputado_federal: 'Deputado Federal',
8 | deputado_estadual: 'Deputado Estadual',
9 | vereador: 'Vereador',
10 | prefeito: 'Prefeito',
11 | governador: 'Governador',
12 | presidente: 'Presidente',
13 | },
14 | };
15 |
16 | const WEIGHT = {
17 | senador: 3,
18 | deputado_federal: 2,
19 | deputado_estadual: 1,
20 | vereador: 1,
21 | prefeito: 2,
22 | governador: 4,
23 | presidente: 5,
24 | };
25 |
26 | export const transformEleicao = ({ candidatos, multipliers }) => {
27 | const settings = [];
28 | const candidatosList = [];
29 | const partidosList = [];
30 |
31 | forEachList(multipliers, (cargo, value) => {
32 | const item: any = {};
33 |
34 | item.cargo = cargo;
35 | item.label = CARGO_LABEL.cargos[cargo];
36 | item.legenda = !!cargo.match(/vereador|deputado/gim);
37 |
38 | forEachListBreakable(candidatos[cargo], (candidato) => {
39 | const split = candidato.split('-');
40 | item.digitos = split[1].length;
41 | return true;
42 | });
43 |
44 | for (let i = 0; i < value; i += 1) {
45 | const cloned = deepClone(item);
46 | if (value > 1) {
47 | cloned.label = `${cloned.label} — ${i + 1}ª vaga`;
48 | }
49 | cloned.id = `${cloned.cargo}_${i}`;
50 | settings.push(cloned);
51 | }
52 |
53 | forEachListBreakable(candidatos[cargo], (candidato, data) => {
54 | const candidatoObject: any = {};
55 | const nomeSplit = candidato.split('-');
56 | const numero = nomeSplit[1];
57 | const partido = numero.slice(0, 2);
58 |
59 | candidatoObject.nome = data?.nome || candidato;
60 | candidatoObject.numero = numero;
61 | candidatoObject.partido = partido;
62 | candidatoObject.cargo = cargo;
63 | candidatoObject.genero = data.genero || 2;
64 | candidatoObject.situacao = data.situacao || 0;
65 | candidatoObject.extras = data?.extras || null;
66 | candidatoObject.image = 'https://gaveta.io';
67 |
68 | candidatosList.push(candidatoObject);
69 | return true;
70 | });
71 |
72 | forEachListBreakable(candidatos[cargo], (candidato, data) => {
73 | const candidatoObject: any = {};
74 | const nomeSplit = candidato.split('-');
75 | const numero = nomeSplit[1];
76 | const partido = numero.slice(0, 2);
77 |
78 | if (!partidosList.find((info) => info.numero === partido)) {
79 | const partidoData = PARTIDOS.find((info) => info.numero === partido);
80 |
81 | const partidoItem = {
82 | nome: partidoData?.sigla || partido,
83 | numero: partido,
84 | };
85 | partidosList.push(partidoItem);
86 | }
87 |
88 | candidatoObject.nome = data?.nome || candidato;
89 | candidatoObject.numero = numero;
90 | candidatoObject.partido = partido;
91 | candidatoObject.cargo = cargo;
92 | candidatoObject.genero = data.genero || 2;
93 | candidatoObject.situacao = data.situacao || 0;
94 | candidatoObject.extras = data?.extras || null;
95 | candidatoObject.image = 'https://gaveta.io';
96 |
97 | candidatosList.push(candidatoObject);
98 | return false;
99 | });
100 | });
101 |
102 | settings.sort((a, b) => WEIGHT[a.cargo] - WEIGHT[b.cargo]);
103 |
104 | return { settings, candidatos: candidatosList, partidos: partidosList };
105 | };
106 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/candidate.tsx:
--------------------------------------------------------------------------------
1 | export default ({ className, color }) => (
2 |
10 |
11 |
12 |
16 |
20 |
24 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 |
--------------------------------------------------------------------------------
/packages/engine/src/data/alagoas.js:
--------------------------------------------------------------------------------
1 | const data1996 = `27014 7524 6867 406 251
2 | 27030 7983 7377 259 347
3 | 27057 58474 51935 2473 4066
4 | 27073 13084 11015 1007 1062
5 | 27090 4589 4193 171 225
6 | 27111 2887 2739 56 92
7 | 27138 6038 5761 106 171
8 | 27154 1071 929 77 65
9 | 27170 3066 2959 63 44
10 | 27197 10002 9316 236 450
11 | 27219 2947 2679 145 123
12 | 27235 3830 3196 416 218
13 | 27251 6800 6260 234 306
14 | 27081 2191 2093 59 39
15 | 27278 10960 9742 553 665
16 | 27294 4914 4762 107 45
17 | 27316 6920 6465 302 153
18 | 27332 7169 6341 367 461
19 | 27359 3557 3382 86 89
20 | 27375 4351 4105 100 146
21 | 27391 4479 4174 126 179
22 | 27413 7682 7065 217 400
23 | 27430 2556 2400 66 90
24 | 27456 18280 15960 837 1483
25 | 28894 6291 5549 310 432
26 | 27472 18547 16901 541 1105
27 | 27499 4641 4408 133 100
28 | 27049 4335 4012 212 111
29 | 27510 7791 7340 238 213
30 | 27537 1901 1812 23 66
31 | 27553 5979 4996 550 433
32 | 27570 11794 11084 408 302
33 | 27596 5499 5162 161 176
34 | 27618 9040 8527 281 232
35 | 27634 9016 8452 341 223
36 | 27650 6530 6099 258 173
37 | 27693 2400 2274 59 67
38 | 27731 2638 2500 72 66
39 | 27758 6963 6302 284 377
40 | 27774 1834 1740 33 61
41 | 27790 9586 8747 401 438
42 | 27812 6789 6180 408 201
43 | 27839 8065 7654 182 229
44 | 27855 252969 218517 5506 28946
45 | 27871 8822 8245 186 391
46 | 27979 2183 2120 20 43
47 | 27898 4944 4480 169 295
48 | 27910 5121 4860 128 133
49 | 27936 11488 10553 343 592
50 | 27952 6772 6391 142 239
51 | 27995 9393 8801 147 445
52 | 28010 8617 7788 303 526
53 | 28037 4987 4411 161 415
54 | 28070 3185 3035 94 56
55 | 28096 10416 9389 349 678
56 | 28118 5360 4916 203 241
57 | 28134 8597 8209 197 191
58 | 28150 3053 2923 45 85
59 | 28177 2371 2271 62 38
60 | 28193 4863 4708 64 91
61 | 28215 4783 4636 75 72
62 | 28231 2401 2311 72 18
63 | 28258 21769 19452 687 1630
64 | 28274 10022 9569 210 243
65 | 27022 3983 3753 100 130
66 | 27006 3794 3427 113 254
67 | 28290 6029 5512 244 273
68 | 28312 4662 4235 254 173
69 | 28339 17053 14994 622 1437
70 | 28355 6812 6222 279 311
71 | 28371 11130 9821 473 836
72 | 28398 1303 1210 31 62
73 | 28410 7277 6842 129 306
74 | 28436 5541 5299 103 139
75 | 28452 9687 8630 460 597
76 | 28479 3494 3295 101 98
77 | 28495 8382 7774 239 369
78 | 28517 6255 5880 181 194
79 | 28533 22743 19481 768 2494
80 | 28550 3278 2861 224 193
81 | 28576 3004 2722 84 198
82 | 28592 14869 13780 270 819
83 | 28614 5454 5057 159 238
84 | 28630 3654 3572 47 35
85 | 28657 9933 8871 555 507
86 | 28673 10039 9035 486 518
87 | 28690 10694 9623 339 732
88 | 28711 22810 19911 955 1944
89 | 28754 10902 10243 282 377
90 | 28770 4710 4254 147 309
91 | 28916 3085 2919 91 75
92 | 28932 11886 10364 553 969
93 | 28797 3139 2955 87 97
94 | 28819 6376 6038 128 210
95 | 28835 10192 9374 478 340
96 | 28851 20589 17803 966 1820
97 | 28878 11252 10350 283 619
98 | `;
99 |
100 | const getAno = (data) => {
101 | const result = {};
102 | const dataSplit = data.split("\n").map((item) => item.trim());
103 | dataSplit.forEach((line) => {
104 | const [codigo, comparecimento, validos, brancos, nulos] = line.split(" ");
105 |
106 | const votos = validos * 1 + brancos * 1 + nulos * 1;
107 |
108 | if (!result[codigo]) {
109 | result[codigo] = {
110 | prefeito: {
111 | brancos: 0,
112 | nulos: 0,
113 | validos: 0,
114 | nominais: 0,
115 | total: 0,
116 | },
117 | };
118 | }
119 |
120 | const current = result[codigo].prefeito;
121 |
122 | current.total += votos;
123 |
124 | current.validos += validos * 1;
125 | current.nominais += validos * 1;
126 |
127 | current.brancos += brancos * 1;
128 |
129 | current.nulos += nulos * 1;
130 | });
131 | return result;
132 | };
133 |
134 | export const getDataAlagoas = () => {
135 | return {
136 | 1996: getAno(data1996),
137 | };
138 | };
139 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Electoral Tools — @gavetaio
2 |
3 | The purpose of this repository is to share all parallel code strategies produced while crafting the word sets of the Election Drawer from the @gavetaio/liber artistic-scientific project; allowing for anyone to question and properly attempt to falsify its conclusions.
4 |
5 | - Read the full document at gaveta.io/G2V6
6 |
7 | ## Falseability — To coders
8 |
9 | Way too many words were crafted into this project, but, on its pluriversal sum, it all converges to one singularity: `the quantitative electoral integrity natural language interpretation breakdown through algorithmic code`. The main goal of this coding exercise is to question how easily we, humans, have been playing loose with natural language interpretation.
10 |
11 | The Brazilian `Superior Electoral Court`’s understanding of its own `Electoral Code` is so problematic that it opens an opportunity for this algorithmic analysis since it can be easily expressed, compared, and tested, in the face of its clear conflicts with cemented international principles and human rights guarantees.
12 |
13 | - Access the integrity challenge `README.md` with instructions on how to run the tests at packages/codex/integrity/README.md
14 | - More details on gaveta.io/G2V6/velum/election-integrity
15 |
16 | ## Falseability — To non-coders and fact-checking organizations
17 |
18 | Given the fact that we, as sentient human beings, seem unable to grasp a multidisciplinary abstraction without fancifully imagining the existence of a multitude of infinite solutions, we have deliberately pushed the falsifiable paths to be done through international comparison; but, you can still abstractly argue about them, which will also be formally reviewed.
19 |
20 | - View the 11 boolean falsifiable statements at docs/g2v6.md
21 | - Extra details at gaveta.io/G2V6
22 |
23 | ## Brazilian DRE black-box — Refactored prototype
24 |
25 | The DRE prototype was crafted as a personal challenge to understand if it would be possible to properly close the user experience on the same grounds as the current legacy UI; but, instead of ignoring, following every electoral norm from the Brazilian Electoral Code that acts in the protection of its voter intent.
26 |
27 | - For accessing the DRE emulator/prototype, run the ElectronJS app and access the `Simulador` tabs.
28 | - Extra information and online simulation on gaveta.io/G2V6/velum/brazilian-dre-blackbox
29 |
30 |
31 |
32 | ## Brazilian Electoral Database — ElectronJS application
33 |
34 | The official **Brazilian Electoral Database** available at dadosabertos.tse.jus.br lacks completeness and a unified structure. For properly interrogating its contents, it was initially developed as a cmd-line NodeJS tool, but ended up evolving into a full ElectronJS application due to the increased complexity of its investigations. The app isn't intended for non-coding users though; as it was built with a focus on being a flexible research tool.
35 |
36 | - For installing it, just run `yarn install && yarn post && yarn start`.
37 | - All the app's text is in its original **Portuguese** natural language.
38 |
39 |
40 |
--------------------------------------------------------------------------------
/packages/ui/src/dre/common/Image.tsx:
--------------------------------------------------------------------------------
1 | // @ts-ignore
2 | import styles from "./Image.module.scss";
3 |
4 | export default ({ className = null, color = "blue", type = null }) => {
5 | const cls = [styles.container];
6 |
7 | if (className) {
8 | cls.push(className);
9 | }
10 |
11 | return (
12 |
20 |
21 |
22 |
26 |
30 |
34 |
38 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | );
50 | };
51 |
--------------------------------------------------------------------------------