From 3da7d323e81b412ba35b20a2deac8aeb5574d3bb Mon Sep 17 00:00:00 2001 From: ruimoraes Date: Wed, 29 Oct 2025 21:30:14 -0300 Subject: [PATCH] desenvolvimento pre-lancamento MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit inicial - add do repo privado para o repo NT style: changes header's logo and colors style: changes home page first session layout feat: creates about us home page section chore: creates home page section for whom chore: creates student materails home page section chore: creates teachers materials home page section chore: creates teacher materials home page section style: changes primary color style: changes color at activities page style: changes about page color style: changes name to Decoda fix: changes route to about page at footer fix: changes background color style: changes game page header colors style: changes footer colors chore: adds home page sections title style: changes main font family to Lato style: adds title font fix: changes sizes to be more responsive for mobile ajuste no build vercel atualiza regras envio homol Adiciona instrucoes de uso add JupyterLite fix solucao turtle Add Mole Mash e Modal de Falhas Add Progress Bar na pagina de Atividades fix game name chore: atualiza lockfile removendo vercel analytics inclusão de efeito ao mudar de fase add mecanismo de solução de fases em debug vite config test add BaseGame e refator do MoleMash refatoração turtle refatoração automato refatoração automato add tag bug 1 e 2 automato mostrar apenas games em homologação na pagina de atividades aumentar timeout das fases finais do Turtle fix bug scroll add video refactor semaforo arrumar ordem das cores add build docs update vercel update vercel update vercel update vercel update vercel add vercel jupyter add vercel jupyter fix deploy Vercel fix deploy Vercel fix deploy Vercel add cripto add cripto refatoração fix tour Mole Mash . remover arquivos de controle chore: adds development tag for activity card remover arquivos de status indevidamente versionados atualizar cores nas atividades add Quebra Cabeças add Quebra Cabeças add iniciativas add Iniciativas alteração de fotos pesadas fix menu mobile fix menu mobile fix menu mobile add Aspirador update icons update identidade visual documentação update jupyter add kernel python local add kernel python local add kernel python local feat: add health check feat: add primeiros passos add letramento mover letramento de lugar update path games update path games fix: ajuste clique rapido no botão executar remover dead code fix: refactor: extract shared utilities for storage, phase unlock and mobile detection stabilize context references and fix stale closure extrair GameProgressContext do GameStateContext (SRP) refactor(game): extrair usePhaser e useGameModals de GameBase + corrigir bugs descobertos refactor(game): remove todos os aliases PT/EN duplicados Remover aliases PT/EN da camada de modais refactor + tests security: add CodeSanitizer and integrate into GameInterpreter - CodeSanitizer.js: 4 built-in rules (max_length, infinite_while, infinite_for, excessive_nesting) with pluggable extra rules - GameInterpreter.executeCode: calls sanitizeCode() before js-interpreter, differentiates CodeSanitizationError (warn) from other errors (error) - 21 unit tests for CodeSanitizer (100% coverage) - 4 integration tests in GameInterpreter for sanitization paths add CodeSanitizer fix: fase 10 aspirador fix: bug semaforo teste feat: add version Ajusta a landing page para ficar mais próxima ao protótipo ajusta raio da borda do botão de Acesse nosso Laboratório pequenos ajustes de layout na página de iniciativas atualiza tabela de jogos educativos com os jogos disponíveis atualmente ajustados pequenos detalhes e informações do jogos na seção de guias pedagógicos troca nome playground para laboratório e adiciona imagens do lab adiciona documentação de conceitos básicos de programação ajustado pequenos erros de digitação adiciona tooltip com conceitos escondidos em hover na tag +N de conceitos update docs dev desativar tour setup matriz MoleMash setup matriz MoleMash fix: link update version update docs update docs mudou o layout de quem somos mudei as imgs dos icons e baixei o botao centraliza titulo com imagem e ajusta sessão com gradiente vermelho-rosa adiciona responsividade para a pagina quem somos ajusta botão de conheça nossa história ajustes ajustes na home + add. teclado update version security security feat: add tapume para telas pequenas v1.1.0 feat: decoda offline feat: doc offline offline fix: ajustes para release fix: navbar; config ordenação; versão fix: rotas docs e jupyter para pwa delete private files Co-authored-by: Indra Araujo Co-authored-by: solange dos santos --- .gitignore | 285 +- LICENSE | 18 - README.md | 542 +- app/.env.offline | 1 + app/.gitignore | 156 + app/.vscode/settings.json | 13 + app/Dockerfile | 25 + app/Makefile | 32 + app/README.md | 101 + app/THIRD_PARTY_NOTICES.md | 29 + app/assets/icon.png | Bin 0 -> 15404 bytes app/eslint-report.json | 1 + app/eslint.config.js | 33 + app/index.html | 14 + app/licenses/APACHE-2.0.txt | 201 + app/licenses/README.md | 23 + app/licenses/js-interpreter-LICENSE.txt | 201 + app/main.cjs | 72 + app/nginx-spa.conf | 9 + app/package.json | 128 + app/pnpm-lock.yaml | 10176 +++++++++ app/pnpm-workspace.yaml | 5 + app/postcss.config.js | 6 + app/public/examples/contador.json | 149 + app/public/examples/fatorial.json | 224 + app/public/examples/fibonacci.json | 312 + app/public/examples/maior-numero.json | 254 + app/public/examples/nome.json | 26 + app/public/examples/par-impar.json | 172 + app/public/examples/soma-lista.json | 221 + app/public/examples/temperatura.json | 181 + app/public/health.json | 3 + .../programacao/aspirador-thumbnail.png | Bin 0 -> 92037 bytes .../programacao/automato-thumbnail.png | Bin 0 -> 112913 bytes .../programacao/cripto-thumbnail.png | Bin 0 -> 101917 bytes .../programacao/molemash-thumbnail.png | Bin 0 -> 93758 bytes .../programacao/ordenacao-thumbnail.png | Bin 0 -> 74678 bytes .../programacao/puzzle-thumbnail.png | Bin 0 -> 73100 bytes .../programacao/semaforo-thumbnail.png | Bin 0 -> 73188 bytes .../programacao/turtle-thumbnail.png | Bin 0 -> 77942 bytes app/public/img/logo.png | Bin 0 -> 8932 bytes app/public/img/logo_192x192.png | Bin 0 -> 8932 bytes app/public/img/logo_512x512.png | Bin 0 -> 15404 bytes app/public/img/logo_decoda.png | Bin 0 -> 3740 bytes app/public/img/logo_nav.png | Bin 0 -> 12844 bytes app/public/manifest.json | 21 + app/public/offline.html | 78 + app/public/puzzle.svg | 14 + app/scripts/test-cache.mjs | 48 + app/serve.json | 5 + app/src/App.css | 145 + app/src/App.jsx | 121 + app/src/assets/baner_quemsomos.png | Bin 0 -> 465928 bytes app/src/assets/banner_quemsomos_mobile.png | Bin 0 -> 206196 bytes app/src/assets/car.png | Bin 0 -> 4864 bytes app/src/assets/fail.mp3 | Bin 0 -> 6268 bytes .../fonts/SF Slapstick Comic Shaded.ttf | Bin 0 -> 37224 bytes app/src/assets/game_loop.mp3 | Bin 0 -> 513253 bytes app/src/assets/icon_cabeca.svg | 3 + app/src/assets/icon_circulo.svg | 3 + app/src/assets/icon_elo.svg | 3 + app/src/assets/icon_livro.svg | 3 + app/src/assets/icon_mao.svg | 3 + app/src/assets/icon_pasta.svg | 3 + app/src/assets/iniciativas-banner-mobile.png | Bin 0 -> 206196 bytes app/src/assets/logo_decoda.svg | 18 + app/src/assets/logont.svg | 1 + app/src/assets/motoca.png | Bin 0 -> 4037 bytes app/src/assets/police.png | Bin 0 -> 10089 bytes app/src/assets/react.svg | 1 + app/src/assets/truck.png | Bin 0 -> 3775 bytes app/src/assets/win.mp3 | Bin 0 -> 9662 bytes .../letramento/letramentoRegistry.js | 53 + .../mouse/mouse-arrastar/activity.js | 92 + .../mouse/mouse-arrastar/index.html | 36 + .../letramento/mouse/mouse-basico/activity.js | 212 + .../letramento/mouse/mouse-basico/index.html | 68 + .../mouse/mouse-botao-direito/activity.js | 73 + .../mouse/mouse-botao-direito/index.html | 37 + .../mouse/mouse-clique-multiplo/activity.js | 64 + .../mouse/mouse-clique-multiplo/index.html | 35 + .../mouse/mouse-completo/activity.js | 592 + .../mouse/mouse-completo/index.html | 36 + .../mouse/mouse-controle/activity.js | 144 + .../mouse/mouse-controle/index.html | 61 + .../mouse/mouse-desenhar/activity.js | 97 + .../mouse/mouse-desenhar/index.html | 36 + .../mouse/mouse-precisao/activity.js | 53 + .../mouse/mouse-precisao/index.html | 37 + .../mouse/mouse-sequencia/activity.js | 70 + .../mouse/mouse-sequencia/index.html | 37 + .../mouse/mouse-velocidade/activity.js | 80 + .../mouse/mouse-velocidade/index.html | 37 + .../letramento/mouse/mouseRegistry.js | 152 + .../letramento/shared/letramento.css | 8109 +++++++ .../atividades/letramento/shared/lucide.js | 18134 ++++++++++++++++ .../letramento/shared/tailwind-input.css | 3 + .../teclado/atividade-final/activity.js | 86 + .../teclado/atividade-final/index.html | 50 + .../letramento/teclado/chuva/activity.js | 331 + .../letramento/teclado/chuva/index.html | 83 + .../letramento/teclado/enter-esc/activity.js | 97 + .../letramento/teclado/enter-esc/index.html | 59 + .../letramento/teclado/labirinto/activity.js | 190 + .../letramento/teclado/labirinto/index.html | 49 + .../teclado/recado-completo/activity.js | 53 + .../teclado/recado-completo/index.html | 52 + .../teclado/setas-texto/activity.js | 84 + .../letramento/teclado/setas-texto/index.html | 53 + .../teclado/teclado-backspace/activity.js | 129 + .../teclado/teclado-backspace/index.html | 66 + .../teclado/teclado-escrever-nome/activity.js | 75 + .../teclado/teclado-escrever-nome/index.html | 47 + .../teclado/teclado-navegacao/activity.js | 110 + .../teclado/teclado-navegacao/index.html | 53 + .../teclado/teclado-numeros/activity.js | 207 + .../teclado/teclado-numeros/index.html | 40 + .../teclado/teclado-regioes/activity.js | 150 + .../teclado/teclado-regioes/index.html | 46 + .../teclado/teclado-simbolos/activity.js | 74 + .../teclado/teclado-simbolos/index.html | 44 + .../letramento/teclado/tecladoRegistry.js | 182 + .../programacao/aspirador/AspiradorGame.jsx | 74 + .../aspirador/assets/image/aspirador.png | Bin 0 -> 34897 bytes .../aspirador/assets/image/obstaculo1.png | Bin 0 -> 35300 bytes .../aspirador/assets/image/obstaculo2.png | Bin 0 -> 32475 bytes .../aspirador/assets/image/piso.png | Bin 0 -> 6750 bytes .../aspirador/assets/image/piso_2.png | Bin 0 -> 4297 bytes .../aspirador/assets/image/sujeira.png | Bin 0 -> 59642 bytes .../aspirador/assets/sound/bg_sound.mp3 | Bin 0 -> 257280 bytes .../aspirador/assets/sound/pop.mp3 | Bin 0 -> 34560 bytes .../programacao/aspirador/blocks/blocks.js | 170 + .../programacao/aspirador/config/config.js | 271 + .../aspirador/config/debugSolutions.js | 17 + .../aspirador/config/starterBlocks.js | 13 + .../programacao/aspirador/config/tourSteps.js | 73 + .../atividades/programacao/aspirador/game.js | 355 + .../aspirador/hooks/setupAspiradorAPI.js | 24 + .../aspirador/hooks/useAspiradorTour.js | 17 + .../programacao/aspirador/ui/constants.js | 39 + .../programacao/aspirador/ui/layout.js | 22 + .../aspirador/validation/validators.js | 53 + .../programacao/automato/AutomatoGame.jsx | 84 + .../automato/__tests__/integration.test.js | 520 + .../programacao/automato/assets/marker.png | Bin 0 -> 859 bytes .../programacao/automato/assets/pegman.png | Bin 0 -> 10058 bytes .../automato/assets/tiles_pegman.png | Bin 0 -> 1837 bytes .../programacao/automato/blocks/blocks.js | 406 + .../programacao/automato/config/config.js | 293 + .../automato/config/debugSolutions.js | 400 + .../programacao/automato/config/tourSteps.js | 71 + .../atividades/programacao/automato/game.js | 654 + .../automato/hooks/interpreterSetup.js | 73 + .../automato/hooks/useAutomatoTour.js | 17 + .../automato/validation/validators.js | 64 + app/src/atividades/programacao/bkp.7z | Bin 0 -> 1315899 bytes .../programacao/cripto/CriptoGame.jsx | 80 + .../cripto/assets/background_loop.mp3 | Bin 0 -> 246595 bytes .../programacao/cripto/blocks/blocks.js | 821 + .../cripto/config/codeValidations.js | 175 + .../programacao/cripto/config/config.js | 419 + .../cripto/config/debugSolutions.js | 2430 +++ .../cripto/config/starterBlocks.js | 1910 ++ .../programacao/cripto/config/tourSteps.js | 73 + app/src/atividades/programacao/cripto/game.js | 293 + .../cripto/hooks/interpreterSetup.js | 84 + .../programacao/cripto/hooks/useCriptoTour.js | 17 + .../programacao/cripto/ui/CRTMonitor.js | 103 + .../programacao/cripto/ui/GridBackground.js | 120 + .../programacao/cripto/ui/MatrixEffect.js | 54 + .../programacao/cripto/ui/animations.js | 215 + .../programacao/cripto/ui/constants.js | 67 + .../atividades/programacao/cripto/ui/index.js | 8 + .../programacao/cripto/ui/layout.js | 241 + .../cripto/validation/validators.js | 252 + .../programacao/mole-mash/MoleMash.jsx | 85 + .../mole-mash/assets/background.png | Bin 0 -> 63527 bytes .../mole-mash/assets/ground_pop.mp3 | Bin 0 -> 46080 bytes .../programacao/mole-mash/assets/sprites.png | Bin 0 -> 436970 bytes .../programacao/mole-mash/blocks/blocks.js | 291 + .../programacao/mole-mash/config/config.js | 299 + .../mole-mash/config/debugSolutions.js | 1597 ++ .../mole-mash/config/matrixConfig.js | 55 + .../programacao/mole-mash/config/tourSteps.js | 73 + .../atividades/programacao/mole-mash/game.js | 431 + .../mole-mash/hooks/interpreterSetup.js | 37 + .../mole-mash/hooks/useMoleMashTour.js | 17 + .../mole-mash/validation/validators.js | 193 + .../programacao/ordenacao/OrdenacaoGame.jsx | 50 + .../programacao/ordenacao/algoritmos.md | 544 + .../programacao/ordenacao/blocks/blocks.js | 438 + .../programacao/ordenacao/config/config.js | 302 + .../ordenacao/config/debugSolutions.js | 10 + .../ordenacao/config/starterBlock.js | 121 + .../programacao/ordenacao/estudo.md | 327 + .../atividades/programacao/ordenacao/game.js | 285 + .../ordenacao/hooks/interpreterSetup.js | 207 + .../atividades/programacao/ordenacao/poc.html | 366 + .../programacao/ordenacao/solucoes-testes.md | 287 + .../programacao/ordenacao/ui/constants.js | 28 + .../validation/core/ExecutionTrace.js | 66 + .../validation/core/InstrumentedList.js | 132 + .../core/SortingValidationEngine.js | 167 + .../core/createTraceableArrayProxy.js | 80 + .../validation/poc/runValidationPoc.js | 560 + .../validation/profiles/bubbleProfile.js | 111 + .../validation/profiles/countingProfile.js | 103 + .../validation/profiles/insertionProfile.js | 113 + .../validation/profiles/selectionProfile.js | 117 + .../validation/profiles/shellProfile.js | 72 + .../ordenacao/validation/validators.js | 109 + .../programacao/puzzle/PuzzleGame.jsx | 75 + .../puzzle/assets/animais/abelha.png | Bin 0 -> 21179 bytes .../puzzle/assets/animais/aranha.png | Bin 0 -> 23149 bytes .../puzzle/assets/animais/cachorro.png | Bin 0 -> 19484 bytes .../puzzle/assets/animais/caracol.png | Bin 0 -> 23186 bytes .../puzzle/assets/animais/cobra.png | Bin 0 -> 17290 bytes .../puzzle/assets/animais/gato.png | Bin 0 -> 23196 bytes .../puzzle/assets/animais/leao.png | Bin 0 -> 126033 bytes .../puzzle/assets/animais/pato.png | Bin 0 -> 17289 bytes .../puzzle/assets/animais/peixe.png | Bin 0 -> 19122 bytes .../puzzle/assets/animais/sapo.png | Bin 0 -> 15350 bytes .../assets/backgrounds/background_1.png | Bin 0 -> 220655 bytes .../assets/backgrounds/background_2.png | Bin 0 -> 190834 bytes .../assets/backgrounds/background_3.png | Bin 0 -> 183817 bytes .../assets/backgrounds/background_4.png | Bin 0 -> 245776 bytes .../puzzle/assets/sound/abelha.mp3 | Bin 0 -> 13440 bytes .../puzzle/assets/sound/bg_sound.mp3 | Bin 0 -> 257280 bytes .../puzzle/assets/sound/cachorro.mp3 | Bin 0 -> 54528 bytes .../programacao/puzzle/assets/sound/gato.mp3 | Bin 0 -> 21600 bytes .../programacao/puzzle/assets/sound/leao.mp3 | Bin 0 -> 29257 bytes .../programacao/puzzle/assets/sound/pato.mp3 | Bin 0 -> 54335 bytes .../programacao/puzzle/assets/sound/sapo.mp3 | Bin 0 -> 67709 bytes .../programacao/puzzle/blocks/blocks.js | 220 + .../programacao/puzzle/config/config.js | 216 + .../puzzle/config/debugSolutions.js | 18 + .../programacao/puzzle/config/starterBlock.js | 12 + .../programacao/puzzle/config/tourSteps.js | 75 + app/src/atividades/programacao/puzzle/game.js | 276 + .../puzzle/hooks/interpreterSetup.js | 63 + .../programacao/puzzle/hooks/usePuzzleTour.js | 17 + .../programacao/puzzle/ui/animations.js | 266 + .../programacao/puzzle/ui/constants.js | 105 + .../programacao/puzzle/ui/layout.js | 51 + .../puzzle/validation/validators.js | 93 + .../programacao/semaforo/SemaforoGame.jsx | 75 + .../semaforo/__tests__/integration.test.js | 332 + .../programacao/semaforo/assets/beep.mp3 | Bin 0 -> 46811 bytes .../semaforo/assets/city_sound.mp3 | Bin 0 -> 392881 bytes .../programacao/semaforo/blocks/blocks.js | 305 + .../programacao/semaforo/config/config.js | 152 + .../semaforo/config/debugSolutions.js | 307 + .../programacao/semaforo/config/tourSteps.js | 86 + .../atividades/programacao/semaforo/game.js | 916 + .../semaforo/hooks/interpreterSetup.js | 91 + .../semaforo/hooks/useSemaforoTour.js | 17 + .../semaforo/validation/validators.js | 358 + .../programacao/turtle/TurtleGame.jsx | 113 + .../programacao/turtle/assets/1.png | Bin 0 -> 5798 bytes .../programacao/turtle/assets/2.png | Bin 0 -> 5261 bytes .../programacao/turtle/assets/fail.mp3 | Bin 0 -> 6268 bytes .../programacao/turtle/assets/win.mp3 | Bin 0 -> 12290 bytes .../programacao/turtle/blocks/blocks.js | 366 + .../programacao/turtle/config/config.js | 441 + .../turtle/config/debugSolutions.js | 1094 + .../programacao/turtle/config/tourSteps.js | 73 + .../programacao/turtle/exemplo_logo.txt | 76 + app/src/atividades/programacao/turtle/game.js | 908 + .../turtle/hooks/interpreterSetup.js | 76 + .../programacao/turtle/hooks/useTurtleTour.js | 17 + .../turtle/validation/validators.js | 132 + app/src/blockly/__tests__/generator.test.js | 146 + app/src/blockly/__tests__/toolbox.test.js | 194 + app/src/blockly/__tests__/validation.test.js | 195 + app/src/blockly/blockFactory.js | 212 + app/src/blockly/blocklyColors.js | 86 + app/src/blockly/blocklyConfig.js | 12 + app/src/blockly/fieldAngle.js | 63 + app/src/blockly/generator.js | 140 + app/src/blockly/mobileToolbox.js | 195 + app/src/blockly/toolbox.js | 161 + app/src/blockly/validation.js | 198 + app/src/components/DesktopOnlyTapume.jsx | 58 + app/src/components/Navbar.jsx | 240 + app/src/components/ScrollToTop.jsx | 22 + app/src/components/game/ConfettiOverlay.jsx | 99 + app/src/components/game/ConfirmacaoModal.jsx | 72 + app/src/components/game/FalhaModal.jsx | 100 + app/src/components/game/GameArea.jsx | 138 + app/src/components/game/GameBase.jsx | 213 + app/src/components/game/GameEditor.jsx | 147 + app/src/components/game/GameFaseInfo.jsx | 85 + app/src/components/game/GameFooter.jsx | 73 + app/src/components/game/GameNavBar.jsx | 152 + app/src/components/game/ResizeHandle.jsx | 61 + app/src/components/game/SeletorDeFases.jsx | 178 + app/src/components/game/SucessoModal.jsx | 88 + .../components/game/editors/BlocklyEditor.jsx | 332 + .../game/editors/BlocklyEditor.mobile.css | 237 + .../components/game/editors/CodeEditor.jsx | 201 + .../game/editors/custom_category.js | 79 + .../components/game/editors/toolboxIcons.js | 48 + app/src/components/game/modal/CodeArea.jsx | 44 + app/src/components/game/modal/FeedbackBox.jsx | 38 + app/src/components/game/modal/ModalBase.jsx | 31 + app/src/components/game/modal/ModalHeader.jsx | 69 + .../letramento/AtividadeRuntimeFrame.jsx | 111 + .../letramento/AtividadeStatusModal.jsx | 98 + .../letramento/AtividadesSidebar.jsx | 204 + .../letramento/LetramentoNavBar.jsx | 29 + .../components/letramento/TrilhaPassos.jsx | 63 + .../__tests__/AtividadeRuntimeFrame.test.jsx | 94 + app/src/config/__tests__/gameRegistry.test.js | 197 + app/src/config/categories.js | 52 + app/src/config/difficulty.js | 45 + app/src/config/gameRegistry.js | 164 + app/src/config/type.js | 45 + app/src/contexts/EditorContext.jsx | 70 + app/src/contexts/GameProgressContext.jsx | 167 + app/src/contexts/GameStateContext.jsx | 372 + app/src/contexts/LetramentoStateContext.jsx | 97 + .../contexts/__tests__/EditorContext.test.jsx | 151 + .../__tests__/GameProgressContext.test.jsx | 221 + .../__tests__/GameStateContext.test.jsx | 452 + app/src/games/automato_code_editor/config.js | 375 + app/src/games/bird/config/config.js | 239 + .../games/detector-de-sentimentos/config.js | 97 + app/src/games/emoji-match/config/config.js | 226 + app/src/games/motoca/config/config.js | 132 + app/src/games/semaforo_code_editor/config.js | 214 + app/src/hooks/__tests__/useGameModals.test.js | 278 + app/src/hooks/__tests__/usePhaser.test.js | 329 + app/src/hooks/useGameModals.js | 122 + app/src/hooks/useGameTour.js | 54 + app/src/hooks/useIsMobile.js | 37 + app/src/hooks/usePhaser.js | 107 + app/src/hooks/useTour.js | 72 + app/src/interpreters/ApiHelpers.js | 123 + app/src/interpreters/CodeSanitizer.js | 97 + app/src/interpreters/GameInterpreter.js | 207 + .../interpreters/__tests__/ApiHelpers.test.js | 238 + .../__tests__/CodeSanitizer.test.js | 169 + .../__tests__/GameInterpreter.test.js | 322 + app/src/main.jsx | 20 + app/src/pages/About/About.jsx | 242 + app/src/pages/Atividades/Atividades.jsx | 472 + app/src/pages/Atividades/config/tourSteps.js | 358 + .../Atividades/hooks/useAtividadesTour.js | 30 + app/src/pages/Atividades/utils/progress.js | 48 + app/src/pages/Educadores/Educadores.jsx | 188 + .../pages/Educadores/assets/educadores.png | Bin 0 -> 537526 bytes app/src/pages/Faq/Faq.jsx | 188 + app/src/pages/HomePage/About.jsx | 52 + app/src/pages/HomePage/CtaPlayground.jsx | 471 + app/src/pages/HomePage/CtaVideoPreview.jsx | 59 + app/src/pages/HomePage/Features.jsx | 213 + app/src/pages/HomePage/Footer.jsx | 106 + app/src/pages/HomePage/ForWhom.jsx | 56 + app/src/pages/HomePage/Hero.jsx | 81 + app/src/pages/HomePage/HomePage.jsx | 46 + app/src/pages/HomePage/SectionTitle.jsx | 48 + app/src/pages/HomePage/StudentsMaterials.jsx | 77 + app/src/pages/HomePage/TeachersMaterials.jsx | 54 + app/src/pages/HomePage/assets/atividades.mp4 | Bin 0 -> 647747 bytes app/src/pages/HomePage/assets/fatorial.svg | 1 + .../pages/HomePage/assets/first-person.png | Bin 0 -> 67790 bytes app/src/pages/HomePage/assets/group.png | Bin 0 -> 182958 bytes app/src/pages/HomePage/assets/hero.png | Bin 0 -> 348422 bytes .../pages/HomePage/assets/puzzled-image.png | Bin 0 -> 258680 bytes .../pages/HomePage/assets/second-person.png | Bin 0 -> 55800 bytes .../pages/HomePage/assets/third-person.png | Bin 0 -> 56821 bytes app/src/pages/Iniciativas/Hero.jsx | 48 + .../pages/Iniciativas/IniciativaDetalhe.jsx | 137 + app/src/pages/Iniciativas/Iniciativas.jsx | 37 + .../pages/Iniciativas/IniciativasDestaque.jsx | 109 + app/src/pages/Iniciativas/IniciativasList.jsx | 52 + .../pages/Iniciativas/assets/destaque1.png | Bin 0 -> 504594 bytes .../pages/Iniciativas/assets/destaque2.png | Bin 0 -> 643780 bytes .../pages/Iniciativas/assets/destaque3.png | Bin 0 -> 487413 bytes app/src/pages/Iniciativas/assets/escolas.png | Bin 0 -> 1302124 bytes app/src/pages/Iniciativas/assets/escolas1.jpg | Bin 0 -> 95880 bytes app/src/pages/Iniciativas/assets/escolas2.png | Bin 0 -> 537526 bytes app/src/pages/Iniciativas/assets/escolas3.jpg | Bin 0 -> 171880 bytes app/src/pages/Iniciativas/assets/formacao.png | Bin 0 -> 1864563 bytes .../pages/Iniciativas/assets/formacao1.jpg | Bin 0 -> 117632 bytes .../pages/Iniciativas/assets/formacao2.jpg | Bin 0 -> 153881 bytes .../pages/Iniciativas/assets/formacao3.jpg | Bin 0 -> 206446 bytes .../pages/Iniciativas/assets/hero-image.png | Bin 0 -> 1948565 bytes app/src/pages/Iniciativas/assets/ocupaLab.svg | 19 + .../pages/Iniciativas/assets/ocupalab1.jpeg | Bin 0 -> 184344 bytes .../pages/Iniciativas/assets/ocupalab2.jpeg | Bin 0 -> 127958 bytes .../pages/Iniciativas/assets/ocupalab3.jpeg | Bin 0 -> 296179 bytes app/src/pages/Iniciativas/iniciativasData.js | 63 + app/src/pages/LabPython/LabPython.jsx | 43 + app/src/pages/Playground/Playground.css | 13 + app/src/pages/Playground/Playground.jsx | 305 + .../Playground/components/CodeViewer.css | 118 + .../Playground/components/CodeViewer.jsx | 79 + .../Playground/components/ExamplesModal.jsx | 168 + .../components/PlaygroundConsole.css | 276 + .../components/PlaygroundConsole.jsx | 88 + .../components/PlaygroundEditor.css | 43 + .../components/PlaygroundEditor.jsx | 446 + .../Playground/components/PlaygroundModal.jsx | 108 + .../components/PlaygroundViewer.css | 5 + .../components/PlaygroundViewer.jsx | 137 + .../Playground/config/defaultWorkspace.js | 163 + .../Playground/config/playgroundToolbox.js | 260 + app/src/pages/Playground/config/tourSteps.js | 578 + .../Playground/hooks/useCodeExecution.js | 97 + .../Playground/hooks/useCodeGeneration.js | 45 + .../Playground/hooks/usePlaygroundTour.js | 30 + .../Playground/services/playgroundStorage.js | 49 + .../AtividadeLetramentoView.jsx | 100 + .../CategoriaLetramentoView.jsx | 148 + .../pages/PrimeirosPassos/PrimeirosPassos.jsx | 28 + .../PrimeirosPassos/PrimeirosPassosList.jsx | 95 + .../services/__tests__/blockstorage.test.js | 82 + .../services/__tests__/codestorage.test.js | 93 + .../__tests__/createStorageService.test.js | 108 + app/src/services/blockstorage.js | 57 + app/src/services/codestorage.js | 69 + app/src/services/createStorageService.js | 69 + app/src/services/letramentoStorage.js | 256 + app/src/shared/BaseGameScene.js | 311 + app/src/shared/BaseGameValidator.js | 123 + .../shared/__tests__/BaseGameScene.test.js | 709 + .../__tests__/BaseGameValidator.test.js | 120 + app/src/shared/gameController.js | 66 + app/src/styles/globals.css | 313 + app/src/styles/shepherd-theme.css | 271 + app/src/utils/__tests__/drawAxes.test.js | 103 + app/src/utils/__tests__/gameEvents.test.js | 92 + app/src/utils/__tests__/isMobile.test.js | 63 + .../utils/__tests__/letramentoEvents.test.js | 63 + app/src/utils/__tests__/loadFont.test.js | 85 + app/src/utils/__tests__/localStorage.test.js | 73 + app/src/utils/__tests__/phaseUtils.test.js | 102 + app/src/utils/__tests__/phaserUtils.test.js | 58 + app/src/utils/__tests__/tourHelpers.test.js | 605 + app/src/utils/drawAxes.js | 90 + app/src/utils/gameEvents.js | 114 + app/src/utils/isMobile.js | 24 + app/src/utils/letramentoEvents.js | 26 + app/src/utils/loadFont.js | 53 + app/src/utils/localStorage.js | 37 + app/src/utils/phaseUtils.js | 66 + app/src/utils/phaserUtils.js | 21 + app/src/utils/tourHelpers.js | 646 + app/stats.html | 4949 +++++ app/tailwind.config.js | 88 + app/tailwind.letramento.config.js | 22 + app/vite.config.js | 180 + docker-compose.yaml | 32 + docs/.dockerignore | 5 + docs/.gitignore | 20 + docs/.vscode/settings.json | 2 + docs/Dockerfile | 16 + docs/README.md | 51 + docs/assets/area-programacao-jogo.png | Bin 0 -> 64688 bytes docs/assets/area-visualizacao-jogo.png | Bin 0 -> 1836027 bytes docs/assets/coluna-blocos-jogo.png | Bin 0 -> 58064 bytes docs/assets/console-laboratorio.png | Bin 0 -> 41368 bytes docs/assets/editor-bloco-laboratorio.png | Bin 0 -> 286150 bytes docs/assets/tela-inteira-jogo.png | Bin 0 -> 2117055 bytes docs/assets/tela-inteira-laboratorio.png | Bin 0 -> 415745 bytes .../visualizador-codigo-laboratorio.png | Bin 0 -> 89056 bytes docs/docs/documentacao/_category_.json | 14 + docs/docs/documentacao/codigo-aberto.md | 114 + .../documentacao/entendendo-docusaurus.md | 69 + docs/docs/documentacao/git-flow.md | 93 + docs/docs/documentacao/monorepo.md | 80 + docs/docs/intro.md | 54 + docs/docs/plataforma/_category_.json | 14 + .../plataforma/arquitetura/_category_.json | 14 + .../plataforma/arquitetura/build-offline.md | 162 + .../arquitetura/camadas-do-sistema.md | 65 + .../arquitetura/estrutura-de-pastas.md | 67 + docs/docs/plataforma/arquitetura/intro.md | 33 + .../arquitetura/otimizacao-bundle.md | 50 + docs/docs/plataforma/arquitetura/patterns.md | 481 + .../arquitetura/sistema-persistencia.md | 70 + .../plataforma/arquitetura/sistema-tours.md | 21 + .../arquitetura/suporte-responsivo.md | 81 + .../arquitetura/tecnologias-principais.md | 73 + .../atividades_programacao/_category_.json | 14 + .../atividades_programacao/base-game-scene.md | 155 + .../atividades_programacao/blockly.md | 111 + .../atividades_programacao/componentes.md | 163 + .../estrutura-de-jogo.md | 65 + .../atividades_programacao/extensibilidade.md | 136 + .../atividades_programacao/intro.md | 42 + .../atividades_programacao/phaser.md | 123 + .../plataforma/letramento/_category_.json | 8 + .../plataforma/letramento/como-adicionar.md | 98 + .../letramento/contrato-postmessage.md | 108 + docs/docs/plataforma/letramento/intro.md | 110 + docs/docs/plataforma/letramento/modelo-lms.md | 82 + docs/docs/plataforma/pre-requisitos.md | 100 + docs/docs/releases/_category_.json | 14 + docs/docs/releases/intro.md | 62 + docs/docs/releases/v1.0.0.md | 70 + docs/docs/releases/v1.1.0.md | 43 + docs/docusaurus.config.js | 153 + docs/edu/como-usar.md | 97 + .../fundamentos-programacao/_category_.json | 12 + .../computacao-desplugada.md | 162 + .../conceitos-basicos/_category_.json | 14 + .../conceitos-basicos/algoritmos.md | 345 + .../conceitos-basicos/dados.md | 346 + .../conceitos-basicos/operadores.md | 362 + .../conceitos-basicos/variaveis.md | 282 + docs/edu/fundamentos-programacao/intro.md | 80 + .../programacao-com-blocos.md | 198 + .../quatro-fundamentos/_category_.json | 14 + .../quatro-fundamentos/condicionais.md | 226 + .../quatro-fundamentos/funcoes.md | 378 + .../quatro-fundamentos/loops.md | 302 + .../quatro-fundamentos/procedural.md | 478 + docs/edu/guias-pedagogicos/_category_.json | 12 + .../avaliacao-aprendizado.md | 65 + docs/edu/guias-pedagogicos/preparando-aula.md | 96 + docs/edu/intro.md | 107 + docs/edu/recursos/_category_.json | 12 + docs/edu/recursos/atividades/_category_.json | 12 + .../atividades/letramento/_category_.json | 5 + .../recursos/atividades/letramento/index.md | 33 + .../recursos/atividades/letramento/mouse.md | 50 + .../recursos/atividades/letramento/teclado.md | 49 + .../atividades/programacao/_category_.json | 5 + .../atividades/programacao/aspirador.md | 54 + .../atividades/programacao/automato.md | 55 + .../recursos/atividades/programacao/cripto.md | 55 + .../recursos/atividades/programacao/index.md | 83 + .../atividades/programacao/ordenacao.md | 251 + .../atividades/programacao/quebra-cabecas.md | 55 + .../atividades/programacao/semaforo.md | 50 + .../atividades/programacao/tartaruga.md | 55 + .../atividades/programacao/toupeira.md | 54 + docs/edu/recursos/playground/_category_.json | 7 + docs/edu/recursos/playground/blocos.md | 341 + docs/edu/recursos/playground/index.md | 31 + docs/edu/recursos/playground/python.md | 60 + docs/package.json | 47 + docs/pnpm-lock.yaml | 13701 ++++++++++++ docs/sidebars.js | 32 + docs/src/components/Home/index.js | 51 + docs/src/components/Home/styles.module.css | 105 + docs/src/css/custom.css | 130 + docs/src/js/navbar-scroll.js | 87 + docs/src/pages/index.js | 20 + docs/src/pages/index.module.css | 23 + docs/src/theme/Root.js | 9 + docs/static/.nojekyll | 0 docs/static/health.json | 3 + .../programacao/aspirador-thumbnail.png | Bin 0 -> 92037 bytes .../programacao/automato-thumbnail.png | Bin 0 -> 112913 bytes .../programacao/cripto-thumbnail.png | Bin 0 -> 101917 bytes .../programacao/molemash-thumbnail.png | Bin 0 -> 93758 bytes .../programacao/ordenacao-thumbnail.png | Bin 0 -> 74678 bytes .../programacao/puzzle-thumbnail.png | Bin 0 -> 73100 bytes .../programacao/semaforo-thumbnail.png | Bin 0 -> 73188 bytes .../programacao/turtle-thumbnail.png | Bin 0 -> 77942 bytes docs/static/img/home.png | Bin 0 -> 115478 bytes docs/static/img/logo_decoda.png | Bin 0 -> 3740 bytes docs/static/img/puzzle.svg | 14 + docs/static/js/navbar-scroll.js | 87 + jupyter/Dockerfile | 25 + jupyter/build.sh | 22 + jupyter/content/Python_Básico_Aula_01.ipynb | 456 + jupyter/content/Python_Básico_Aula_02.ipynb | 161 + jupyter/content/Python_Básico_Aula_03.ipynb | 488 + jupyter/jupyter_lite_config.json | 15 + jupyter/overrides.json | 5 + jupyter/requirements.txt | 4 + jupyter/vercel.json | 19 + nginx.conf | 28 + 577 files changed, 121994 insertions(+), 158 deletions(-) delete mode 100644 LICENSE create mode 100644 app/.env.offline create mode 100644 app/.gitignore create mode 100644 app/.vscode/settings.json create mode 100644 app/Dockerfile create mode 100644 app/Makefile create mode 100644 app/README.md create mode 100644 app/THIRD_PARTY_NOTICES.md create mode 100644 app/assets/icon.png create mode 100644 app/eslint-report.json create mode 100644 app/eslint.config.js create mode 100644 app/index.html create mode 100644 app/licenses/APACHE-2.0.txt create mode 100644 app/licenses/README.md create mode 100644 app/licenses/js-interpreter-LICENSE.txt create mode 100644 app/main.cjs create mode 100644 app/nginx-spa.conf create mode 100644 app/package.json create mode 100644 app/pnpm-lock.yaml create mode 100644 app/pnpm-workspace.yaml create mode 100644 app/postcss.config.js create mode 100644 app/public/examples/contador.json create mode 100644 app/public/examples/fatorial.json create mode 100644 app/public/examples/fibonacci.json create mode 100644 app/public/examples/maior-numero.json create mode 100644 app/public/examples/nome.json create mode 100644 app/public/examples/par-impar.json create mode 100644 app/public/examples/soma-lista.json create mode 100644 app/public/examples/temperatura.json create mode 100644 app/public/health.json create mode 100644 app/public/images/atividades/programacao/aspirador-thumbnail.png create mode 100644 app/public/images/atividades/programacao/automato-thumbnail.png create mode 100644 app/public/images/atividades/programacao/cripto-thumbnail.png create mode 100644 app/public/images/atividades/programacao/molemash-thumbnail.png create mode 100644 app/public/images/atividades/programacao/ordenacao-thumbnail.png create mode 100644 app/public/images/atividades/programacao/puzzle-thumbnail.png create mode 100644 app/public/images/atividades/programacao/semaforo-thumbnail.png create mode 100644 app/public/images/atividades/programacao/turtle-thumbnail.png create mode 100644 app/public/img/logo.png create mode 100644 app/public/img/logo_192x192.png create mode 100644 app/public/img/logo_512x512.png create mode 100644 app/public/img/logo_decoda.png create mode 100644 app/public/img/logo_nav.png create mode 100644 app/public/manifest.json create mode 100644 app/public/offline.html create mode 100644 app/public/puzzle.svg create mode 100644 app/scripts/test-cache.mjs create mode 100644 app/serve.json create mode 100644 app/src/App.css create mode 100644 app/src/App.jsx create mode 100644 app/src/assets/baner_quemsomos.png create mode 100644 app/src/assets/banner_quemsomos_mobile.png create mode 100644 app/src/assets/car.png create mode 100644 app/src/assets/fail.mp3 create mode 100644 app/src/assets/fonts/SF Slapstick Comic Shaded.ttf create mode 100644 app/src/assets/game_loop.mp3 create mode 100644 app/src/assets/icon_cabeca.svg create mode 100644 app/src/assets/icon_circulo.svg create mode 100644 app/src/assets/icon_elo.svg create mode 100644 app/src/assets/icon_livro.svg create mode 100644 app/src/assets/icon_mao.svg create mode 100644 app/src/assets/icon_pasta.svg create mode 100644 app/src/assets/iniciativas-banner-mobile.png create mode 100644 app/src/assets/logo_decoda.svg create mode 100644 app/src/assets/logont.svg create mode 100644 app/src/assets/motoca.png create mode 100644 app/src/assets/police.png create mode 100644 app/src/assets/react.svg create mode 100644 app/src/assets/truck.png create mode 100644 app/src/assets/win.mp3 create mode 100644 app/src/atividades/letramento/letramentoRegistry.js create mode 100644 app/src/atividades/letramento/mouse/mouse-arrastar/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-arrastar/index.html create mode 100644 app/src/atividades/letramento/mouse/mouse-basico/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-basico/index.html create mode 100644 app/src/atividades/letramento/mouse/mouse-botao-direito/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-botao-direito/index.html create mode 100644 app/src/atividades/letramento/mouse/mouse-clique-multiplo/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-clique-multiplo/index.html create mode 100644 app/src/atividades/letramento/mouse/mouse-completo/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-completo/index.html create mode 100644 app/src/atividades/letramento/mouse/mouse-controle/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-controle/index.html create mode 100644 app/src/atividades/letramento/mouse/mouse-desenhar/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-desenhar/index.html create mode 100644 app/src/atividades/letramento/mouse/mouse-precisao/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-precisao/index.html create mode 100644 app/src/atividades/letramento/mouse/mouse-sequencia/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-sequencia/index.html create mode 100644 app/src/atividades/letramento/mouse/mouse-velocidade/activity.js create mode 100644 app/src/atividades/letramento/mouse/mouse-velocidade/index.html create mode 100644 app/src/atividades/letramento/mouse/mouseRegistry.js create mode 100644 app/src/atividades/letramento/shared/letramento.css create mode 100644 app/src/atividades/letramento/shared/lucide.js create mode 100644 app/src/atividades/letramento/shared/tailwind-input.css create mode 100644 app/src/atividades/letramento/teclado/atividade-final/activity.js create mode 100644 app/src/atividades/letramento/teclado/atividade-final/index.html create mode 100644 app/src/atividades/letramento/teclado/chuva/activity.js create mode 100644 app/src/atividades/letramento/teclado/chuva/index.html create mode 100644 app/src/atividades/letramento/teclado/enter-esc/activity.js create mode 100644 app/src/atividades/letramento/teclado/enter-esc/index.html create mode 100644 app/src/atividades/letramento/teclado/labirinto/activity.js create mode 100644 app/src/atividades/letramento/teclado/labirinto/index.html create mode 100644 app/src/atividades/letramento/teclado/recado-completo/activity.js create mode 100644 app/src/atividades/letramento/teclado/recado-completo/index.html create mode 100644 app/src/atividades/letramento/teclado/setas-texto/activity.js create mode 100644 app/src/atividades/letramento/teclado/setas-texto/index.html create mode 100644 app/src/atividades/letramento/teclado/teclado-backspace/activity.js create mode 100644 app/src/atividades/letramento/teclado/teclado-backspace/index.html create mode 100644 app/src/atividades/letramento/teclado/teclado-escrever-nome/activity.js create mode 100644 app/src/atividades/letramento/teclado/teclado-escrever-nome/index.html create mode 100644 app/src/atividades/letramento/teclado/teclado-navegacao/activity.js create mode 100644 app/src/atividades/letramento/teclado/teclado-navegacao/index.html create mode 100644 app/src/atividades/letramento/teclado/teclado-numeros/activity.js create mode 100644 app/src/atividades/letramento/teclado/teclado-numeros/index.html create mode 100644 app/src/atividades/letramento/teclado/teclado-regioes/activity.js create mode 100644 app/src/atividades/letramento/teclado/teclado-regioes/index.html create mode 100644 app/src/atividades/letramento/teclado/teclado-simbolos/activity.js create mode 100644 app/src/atividades/letramento/teclado/teclado-simbolos/index.html create mode 100644 app/src/atividades/letramento/teclado/tecladoRegistry.js create mode 100644 app/src/atividades/programacao/aspirador/AspiradorGame.jsx create mode 100644 app/src/atividades/programacao/aspirador/assets/image/aspirador.png create mode 100644 app/src/atividades/programacao/aspirador/assets/image/obstaculo1.png create mode 100644 app/src/atividades/programacao/aspirador/assets/image/obstaculo2.png create mode 100644 app/src/atividades/programacao/aspirador/assets/image/piso.png create mode 100644 app/src/atividades/programacao/aspirador/assets/image/piso_2.png create mode 100644 app/src/atividades/programacao/aspirador/assets/image/sujeira.png create mode 100644 app/src/atividades/programacao/aspirador/assets/sound/bg_sound.mp3 create mode 100644 app/src/atividades/programacao/aspirador/assets/sound/pop.mp3 create mode 100644 app/src/atividades/programacao/aspirador/blocks/blocks.js create mode 100644 app/src/atividades/programacao/aspirador/config/config.js create mode 100644 app/src/atividades/programacao/aspirador/config/debugSolutions.js create mode 100644 app/src/atividades/programacao/aspirador/config/starterBlocks.js create mode 100644 app/src/atividades/programacao/aspirador/config/tourSteps.js create mode 100644 app/src/atividades/programacao/aspirador/game.js create mode 100644 app/src/atividades/programacao/aspirador/hooks/setupAspiradorAPI.js create mode 100644 app/src/atividades/programacao/aspirador/hooks/useAspiradorTour.js create mode 100644 app/src/atividades/programacao/aspirador/ui/constants.js create mode 100644 app/src/atividades/programacao/aspirador/ui/layout.js create mode 100644 app/src/atividades/programacao/aspirador/validation/validators.js create mode 100644 app/src/atividades/programacao/automato/AutomatoGame.jsx create mode 100644 app/src/atividades/programacao/automato/__tests__/integration.test.js create mode 100644 app/src/atividades/programacao/automato/assets/marker.png create mode 100644 app/src/atividades/programacao/automato/assets/pegman.png create mode 100644 app/src/atividades/programacao/automato/assets/tiles_pegman.png create mode 100644 app/src/atividades/programacao/automato/blocks/blocks.js create mode 100644 app/src/atividades/programacao/automato/config/config.js create mode 100644 app/src/atividades/programacao/automato/config/debugSolutions.js create mode 100644 app/src/atividades/programacao/automato/config/tourSteps.js create mode 100644 app/src/atividades/programacao/automato/game.js create mode 100644 app/src/atividades/programacao/automato/hooks/interpreterSetup.js create mode 100644 app/src/atividades/programacao/automato/hooks/useAutomatoTour.js create mode 100644 app/src/atividades/programacao/automato/validation/validators.js create mode 100644 app/src/atividades/programacao/bkp.7z create mode 100644 app/src/atividades/programacao/cripto/CriptoGame.jsx create mode 100644 app/src/atividades/programacao/cripto/assets/background_loop.mp3 create mode 100644 app/src/atividades/programacao/cripto/blocks/blocks.js create mode 100644 app/src/atividades/programacao/cripto/config/codeValidations.js create mode 100644 app/src/atividades/programacao/cripto/config/config.js create mode 100644 app/src/atividades/programacao/cripto/config/debugSolutions.js create mode 100644 app/src/atividades/programacao/cripto/config/starterBlocks.js create mode 100644 app/src/atividades/programacao/cripto/config/tourSteps.js create mode 100644 app/src/atividades/programacao/cripto/game.js create mode 100644 app/src/atividades/programacao/cripto/hooks/interpreterSetup.js create mode 100644 app/src/atividades/programacao/cripto/hooks/useCriptoTour.js create mode 100644 app/src/atividades/programacao/cripto/ui/CRTMonitor.js create mode 100644 app/src/atividades/programacao/cripto/ui/GridBackground.js create mode 100644 app/src/atividades/programacao/cripto/ui/MatrixEffect.js create mode 100644 app/src/atividades/programacao/cripto/ui/animations.js create mode 100644 app/src/atividades/programacao/cripto/ui/constants.js create mode 100644 app/src/atividades/programacao/cripto/ui/index.js create mode 100644 app/src/atividades/programacao/cripto/ui/layout.js create mode 100644 app/src/atividades/programacao/cripto/validation/validators.js create mode 100644 app/src/atividades/programacao/mole-mash/MoleMash.jsx create mode 100644 app/src/atividades/programacao/mole-mash/assets/background.png create mode 100644 app/src/atividades/programacao/mole-mash/assets/ground_pop.mp3 create mode 100644 app/src/atividades/programacao/mole-mash/assets/sprites.png create mode 100644 app/src/atividades/programacao/mole-mash/blocks/blocks.js create mode 100644 app/src/atividades/programacao/mole-mash/config/config.js create mode 100644 app/src/atividades/programacao/mole-mash/config/debugSolutions.js create mode 100644 app/src/atividades/programacao/mole-mash/config/matrixConfig.js create mode 100644 app/src/atividades/programacao/mole-mash/config/tourSteps.js create mode 100644 app/src/atividades/programacao/mole-mash/game.js create mode 100644 app/src/atividades/programacao/mole-mash/hooks/interpreterSetup.js create mode 100644 app/src/atividades/programacao/mole-mash/hooks/useMoleMashTour.js create mode 100644 app/src/atividades/programacao/mole-mash/validation/validators.js create mode 100644 app/src/atividades/programacao/ordenacao/OrdenacaoGame.jsx create mode 100644 app/src/atividades/programacao/ordenacao/algoritmos.md create mode 100644 app/src/atividades/programacao/ordenacao/blocks/blocks.js create mode 100644 app/src/atividades/programacao/ordenacao/config/config.js create mode 100644 app/src/atividades/programacao/ordenacao/config/debugSolutions.js create mode 100644 app/src/atividades/programacao/ordenacao/config/starterBlock.js create mode 100644 app/src/atividades/programacao/ordenacao/estudo.md create mode 100644 app/src/atividades/programacao/ordenacao/game.js create mode 100644 app/src/atividades/programacao/ordenacao/hooks/interpreterSetup.js create mode 100644 app/src/atividades/programacao/ordenacao/poc.html create mode 100644 app/src/atividades/programacao/ordenacao/solucoes-testes.md create mode 100644 app/src/atividades/programacao/ordenacao/ui/constants.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/core/ExecutionTrace.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/core/InstrumentedList.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/core/SortingValidationEngine.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/core/createTraceableArrayProxy.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/poc/runValidationPoc.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/profiles/bubbleProfile.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/profiles/countingProfile.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/profiles/insertionProfile.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/profiles/selectionProfile.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/profiles/shellProfile.js create mode 100644 app/src/atividades/programacao/ordenacao/validation/validators.js create mode 100644 app/src/atividades/programacao/puzzle/PuzzleGame.jsx create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/abelha.png create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/aranha.png create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/cachorro.png create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/caracol.png create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/cobra.png create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/gato.png create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/leao.png create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/pato.png create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/peixe.png create mode 100644 app/src/atividades/programacao/puzzle/assets/animais/sapo.png create mode 100644 app/src/atividades/programacao/puzzle/assets/backgrounds/background_1.png create mode 100644 app/src/atividades/programacao/puzzle/assets/backgrounds/background_2.png create mode 100644 app/src/atividades/programacao/puzzle/assets/backgrounds/background_3.png create mode 100644 app/src/atividades/programacao/puzzle/assets/backgrounds/background_4.png create mode 100644 app/src/atividades/programacao/puzzle/assets/sound/abelha.mp3 create mode 100644 app/src/atividades/programacao/puzzle/assets/sound/bg_sound.mp3 create mode 100644 app/src/atividades/programacao/puzzle/assets/sound/cachorro.mp3 create mode 100644 app/src/atividades/programacao/puzzle/assets/sound/gato.mp3 create mode 100644 app/src/atividades/programacao/puzzle/assets/sound/leao.mp3 create mode 100644 app/src/atividades/programacao/puzzle/assets/sound/pato.mp3 create mode 100644 app/src/atividades/programacao/puzzle/assets/sound/sapo.mp3 create mode 100644 app/src/atividades/programacao/puzzle/blocks/blocks.js create mode 100644 app/src/atividades/programacao/puzzle/config/config.js create mode 100644 app/src/atividades/programacao/puzzle/config/debugSolutions.js create mode 100644 app/src/atividades/programacao/puzzle/config/starterBlock.js create mode 100644 app/src/atividades/programacao/puzzle/config/tourSteps.js create mode 100644 app/src/atividades/programacao/puzzle/game.js create mode 100644 app/src/atividades/programacao/puzzle/hooks/interpreterSetup.js create mode 100644 app/src/atividades/programacao/puzzle/hooks/usePuzzleTour.js create mode 100644 app/src/atividades/programacao/puzzle/ui/animations.js create mode 100644 app/src/atividades/programacao/puzzle/ui/constants.js create mode 100644 app/src/atividades/programacao/puzzle/ui/layout.js create mode 100644 app/src/atividades/programacao/puzzle/validation/validators.js create mode 100644 app/src/atividades/programacao/semaforo/SemaforoGame.jsx create mode 100644 app/src/atividades/programacao/semaforo/__tests__/integration.test.js create mode 100644 app/src/atividades/programacao/semaforo/assets/beep.mp3 create mode 100644 app/src/atividades/programacao/semaforo/assets/city_sound.mp3 create mode 100644 app/src/atividades/programacao/semaforo/blocks/blocks.js create mode 100644 app/src/atividades/programacao/semaforo/config/config.js create mode 100644 app/src/atividades/programacao/semaforo/config/debugSolutions.js create mode 100644 app/src/atividades/programacao/semaforo/config/tourSteps.js create mode 100644 app/src/atividades/programacao/semaforo/game.js create mode 100644 app/src/atividades/programacao/semaforo/hooks/interpreterSetup.js create mode 100644 app/src/atividades/programacao/semaforo/hooks/useSemaforoTour.js create mode 100644 app/src/atividades/programacao/semaforo/validation/validators.js create mode 100644 app/src/atividades/programacao/turtle/TurtleGame.jsx create mode 100644 app/src/atividades/programacao/turtle/assets/1.png create mode 100644 app/src/atividades/programacao/turtle/assets/2.png create mode 100644 app/src/atividades/programacao/turtle/assets/fail.mp3 create mode 100644 app/src/atividades/programacao/turtle/assets/win.mp3 create mode 100644 app/src/atividades/programacao/turtle/blocks/blocks.js create mode 100644 app/src/atividades/programacao/turtle/config/config.js create mode 100644 app/src/atividades/programacao/turtle/config/debugSolutions.js create mode 100644 app/src/atividades/programacao/turtle/config/tourSteps.js create mode 100644 app/src/atividades/programacao/turtle/exemplo_logo.txt create mode 100644 app/src/atividades/programacao/turtle/game.js create mode 100644 app/src/atividades/programacao/turtle/hooks/interpreterSetup.js create mode 100644 app/src/atividades/programacao/turtle/hooks/useTurtleTour.js create mode 100644 app/src/atividades/programacao/turtle/validation/validators.js create mode 100644 app/src/blockly/__tests__/generator.test.js create mode 100644 app/src/blockly/__tests__/toolbox.test.js create mode 100644 app/src/blockly/__tests__/validation.test.js create mode 100644 app/src/blockly/blockFactory.js create mode 100644 app/src/blockly/blocklyColors.js create mode 100644 app/src/blockly/blocklyConfig.js create mode 100644 app/src/blockly/fieldAngle.js create mode 100644 app/src/blockly/generator.js create mode 100644 app/src/blockly/mobileToolbox.js create mode 100644 app/src/blockly/toolbox.js create mode 100644 app/src/blockly/validation.js create mode 100644 app/src/components/DesktopOnlyTapume.jsx create mode 100644 app/src/components/Navbar.jsx create mode 100644 app/src/components/ScrollToTop.jsx create mode 100644 app/src/components/game/ConfettiOverlay.jsx create mode 100644 app/src/components/game/ConfirmacaoModal.jsx create mode 100644 app/src/components/game/FalhaModal.jsx create mode 100644 app/src/components/game/GameArea.jsx create mode 100644 app/src/components/game/GameBase.jsx create mode 100644 app/src/components/game/GameEditor.jsx create mode 100644 app/src/components/game/GameFaseInfo.jsx create mode 100644 app/src/components/game/GameFooter.jsx create mode 100644 app/src/components/game/GameNavBar.jsx create mode 100644 app/src/components/game/ResizeHandle.jsx create mode 100644 app/src/components/game/SeletorDeFases.jsx create mode 100644 app/src/components/game/SucessoModal.jsx create mode 100644 app/src/components/game/editors/BlocklyEditor.jsx create mode 100644 app/src/components/game/editors/BlocklyEditor.mobile.css create mode 100644 app/src/components/game/editors/CodeEditor.jsx create mode 100644 app/src/components/game/editors/custom_category.js create mode 100644 app/src/components/game/editors/toolboxIcons.js create mode 100644 app/src/components/game/modal/CodeArea.jsx create mode 100644 app/src/components/game/modal/FeedbackBox.jsx create mode 100644 app/src/components/game/modal/ModalBase.jsx create mode 100644 app/src/components/game/modal/ModalHeader.jsx create mode 100644 app/src/components/letramento/AtividadeRuntimeFrame.jsx create mode 100644 app/src/components/letramento/AtividadeStatusModal.jsx create mode 100644 app/src/components/letramento/AtividadesSidebar.jsx create mode 100644 app/src/components/letramento/LetramentoNavBar.jsx create mode 100644 app/src/components/letramento/TrilhaPassos.jsx create mode 100644 app/src/components/letramento/__tests__/AtividadeRuntimeFrame.test.jsx create mode 100644 app/src/config/__tests__/gameRegistry.test.js create mode 100644 app/src/config/categories.js create mode 100644 app/src/config/difficulty.js create mode 100644 app/src/config/gameRegistry.js create mode 100644 app/src/config/type.js create mode 100644 app/src/contexts/EditorContext.jsx create mode 100644 app/src/contexts/GameProgressContext.jsx create mode 100644 app/src/contexts/GameStateContext.jsx create mode 100644 app/src/contexts/LetramentoStateContext.jsx create mode 100644 app/src/contexts/__tests__/EditorContext.test.jsx create mode 100644 app/src/contexts/__tests__/GameProgressContext.test.jsx create mode 100644 app/src/contexts/__tests__/GameStateContext.test.jsx create mode 100644 app/src/games/automato_code_editor/config.js create mode 100644 app/src/games/bird/config/config.js create mode 100644 app/src/games/detector-de-sentimentos/config.js create mode 100644 app/src/games/emoji-match/config/config.js create mode 100644 app/src/games/motoca/config/config.js create mode 100644 app/src/games/semaforo_code_editor/config.js create mode 100644 app/src/hooks/__tests__/useGameModals.test.js create mode 100644 app/src/hooks/__tests__/usePhaser.test.js create mode 100644 app/src/hooks/useGameModals.js create mode 100644 app/src/hooks/useGameTour.js create mode 100644 app/src/hooks/useIsMobile.js create mode 100644 app/src/hooks/usePhaser.js create mode 100644 app/src/hooks/useTour.js create mode 100644 app/src/interpreters/ApiHelpers.js create mode 100644 app/src/interpreters/CodeSanitizer.js create mode 100644 app/src/interpreters/GameInterpreter.js create mode 100644 app/src/interpreters/__tests__/ApiHelpers.test.js create mode 100644 app/src/interpreters/__tests__/CodeSanitizer.test.js create mode 100644 app/src/interpreters/__tests__/GameInterpreter.test.js create mode 100644 app/src/main.jsx create mode 100644 app/src/pages/About/About.jsx create mode 100644 app/src/pages/Atividades/Atividades.jsx create mode 100644 app/src/pages/Atividades/config/tourSteps.js create mode 100644 app/src/pages/Atividades/hooks/useAtividadesTour.js create mode 100644 app/src/pages/Atividades/utils/progress.js create mode 100644 app/src/pages/Educadores/Educadores.jsx create mode 100644 app/src/pages/Educadores/assets/educadores.png create mode 100644 app/src/pages/Faq/Faq.jsx create mode 100644 app/src/pages/HomePage/About.jsx create mode 100644 app/src/pages/HomePage/CtaPlayground.jsx create mode 100644 app/src/pages/HomePage/CtaVideoPreview.jsx create mode 100644 app/src/pages/HomePage/Features.jsx create mode 100644 app/src/pages/HomePage/Footer.jsx create mode 100644 app/src/pages/HomePage/ForWhom.jsx create mode 100644 app/src/pages/HomePage/Hero.jsx create mode 100644 app/src/pages/HomePage/HomePage.jsx create mode 100644 app/src/pages/HomePage/SectionTitle.jsx create mode 100644 app/src/pages/HomePage/StudentsMaterials.jsx create mode 100644 app/src/pages/HomePage/TeachersMaterials.jsx create mode 100644 app/src/pages/HomePage/assets/atividades.mp4 create mode 100644 app/src/pages/HomePage/assets/fatorial.svg create mode 100644 app/src/pages/HomePage/assets/first-person.png create mode 100644 app/src/pages/HomePage/assets/group.png create mode 100644 app/src/pages/HomePage/assets/hero.png create mode 100644 app/src/pages/HomePage/assets/puzzled-image.png create mode 100644 app/src/pages/HomePage/assets/second-person.png create mode 100644 app/src/pages/HomePage/assets/third-person.png create mode 100644 app/src/pages/Iniciativas/Hero.jsx create mode 100644 app/src/pages/Iniciativas/IniciativaDetalhe.jsx create mode 100644 app/src/pages/Iniciativas/Iniciativas.jsx create mode 100644 app/src/pages/Iniciativas/IniciativasDestaque.jsx create mode 100644 app/src/pages/Iniciativas/IniciativasList.jsx create mode 100644 app/src/pages/Iniciativas/assets/destaque1.png create mode 100644 app/src/pages/Iniciativas/assets/destaque2.png create mode 100644 app/src/pages/Iniciativas/assets/destaque3.png create mode 100644 app/src/pages/Iniciativas/assets/escolas.png create mode 100644 app/src/pages/Iniciativas/assets/escolas1.jpg create mode 100644 app/src/pages/Iniciativas/assets/escolas2.png create mode 100644 app/src/pages/Iniciativas/assets/escolas3.jpg create mode 100644 app/src/pages/Iniciativas/assets/formacao.png create mode 100644 app/src/pages/Iniciativas/assets/formacao1.jpg create mode 100644 app/src/pages/Iniciativas/assets/formacao2.jpg create mode 100644 app/src/pages/Iniciativas/assets/formacao3.jpg create mode 100644 app/src/pages/Iniciativas/assets/hero-image.png create mode 100644 app/src/pages/Iniciativas/assets/ocupaLab.svg create mode 100644 app/src/pages/Iniciativas/assets/ocupalab1.jpeg create mode 100644 app/src/pages/Iniciativas/assets/ocupalab2.jpeg create mode 100644 app/src/pages/Iniciativas/assets/ocupalab3.jpeg create mode 100644 app/src/pages/Iniciativas/iniciativasData.js create mode 100644 app/src/pages/LabPython/LabPython.jsx create mode 100644 app/src/pages/Playground/Playground.css create mode 100644 app/src/pages/Playground/Playground.jsx create mode 100644 app/src/pages/Playground/components/CodeViewer.css create mode 100644 app/src/pages/Playground/components/CodeViewer.jsx create mode 100644 app/src/pages/Playground/components/ExamplesModal.jsx create mode 100644 app/src/pages/Playground/components/PlaygroundConsole.css create mode 100644 app/src/pages/Playground/components/PlaygroundConsole.jsx create mode 100644 app/src/pages/Playground/components/PlaygroundEditor.css create mode 100644 app/src/pages/Playground/components/PlaygroundEditor.jsx create mode 100644 app/src/pages/Playground/components/PlaygroundModal.jsx create mode 100644 app/src/pages/Playground/components/PlaygroundViewer.css create mode 100644 app/src/pages/Playground/components/PlaygroundViewer.jsx create mode 100644 app/src/pages/Playground/config/defaultWorkspace.js create mode 100644 app/src/pages/Playground/config/playgroundToolbox.js create mode 100644 app/src/pages/Playground/config/tourSteps.js create mode 100644 app/src/pages/Playground/hooks/useCodeExecution.js create mode 100644 app/src/pages/Playground/hooks/useCodeGeneration.js create mode 100644 app/src/pages/Playground/hooks/usePlaygroundTour.js create mode 100644 app/src/pages/Playground/services/playgroundStorage.js create mode 100644 app/src/pages/PrimeirosPassos/AtividadeLetramentoView.jsx create mode 100644 app/src/pages/PrimeirosPassos/CategoriaLetramentoView.jsx create mode 100644 app/src/pages/PrimeirosPassos/PrimeirosPassos.jsx create mode 100644 app/src/pages/PrimeirosPassos/PrimeirosPassosList.jsx create mode 100644 app/src/services/__tests__/blockstorage.test.js create mode 100644 app/src/services/__tests__/codestorage.test.js create mode 100644 app/src/services/__tests__/createStorageService.test.js create mode 100644 app/src/services/blockstorage.js create mode 100644 app/src/services/codestorage.js create mode 100644 app/src/services/createStorageService.js create mode 100644 app/src/services/letramentoStorage.js create mode 100644 app/src/shared/BaseGameScene.js create mode 100644 app/src/shared/BaseGameValidator.js create mode 100644 app/src/shared/__tests__/BaseGameScene.test.js create mode 100644 app/src/shared/__tests__/BaseGameValidator.test.js create mode 100644 app/src/shared/gameController.js create mode 100644 app/src/styles/globals.css create mode 100644 app/src/styles/shepherd-theme.css create mode 100644 app/src/utils/__tests__/drawAxes.test.js create mode 100644 app/src/utils/__tests__/gameEvents.test.js create mode 100644 app/src/utils/__tests__/isMobile.test.js create mode 100644 app/src/utils/__tests__/letramentoEvents.test.js create mode 100644 app/src/utils/__tests__/loadFont.test.js create mode 100644 app/src/utils/__tests__/localStorage.test.js create mode 100644 app/src/utils/__tests__/phaseUtils.test.js create mode 100644 app/src/utils/__tests__/phaserUtils.test.js create mode 100644 app/src/utils/__tests__/tourHelpers.test.js create mode 100644 app/src/utils/drawAxes.js create mode 100644 app/src/utils/gameEvents.js create mode 100644 app/src/utils/isMobile.js create mode 100644 app/src/utils/letramentoEvents.js create mode 100644 app/src/utils/loadFont.js create mode 100644 app/src/utils/localStorage.js create mode 100644 app/src/utils/phaseUtils.js create mode 100644 app/src/utils/phaserUtils.js create mode 100644 app/src/utils/tourHelpers.js create mode 100644 app/stats.html create mode 100644 app/tailwind.config.js create mode 100644 app/tailwind.letramento.config.js create mode 100644 app/vite.config.js create mode 100644 docker-compose.yaml create mode 100644 docs/.dockerignore create mode 100644 docs/.gitignore create mode 100644 docs/.vscode/settings.json create mode 100644 docs/Dockerfile create mode 100644 docs/README.md create mode 100644 docs/assets/area-programacao-jogo.png create mode 100644 docs/assets/area-visualizacao-jogo.png create mode 100644 docs/assets/coluna-blocos-jogo.png create mode 100644 docs/assets/console-laboratorio.png create mode 100644 docs/assets/editor-bloco-laboratorio.png create mode 100644 docs/assets/tela-inteira-jogo.png create mode 100644 docs/assets/tela-inteira-laboratorio.png create mode 100644 docs/assets/visualizador-codigo-laboratorio.png create mode 100644 docs/docs/documentacao/_category_.json create mode 100644 docs/docs/documentacao/codigo-aberto.md create mode 100644 docs/docs/documentacao/entendendo-docusaurus.md create mode 100644 docs/docs/documentacao/git-flow.md create mode 100644 docs/docs/documentacao/monorepo.md create mode 100644 docs/docs/intro.md create mode 100644 docs/docs/plataforma/_category_.json create mode 100644 docs/docs/plataforma/arquitetura/_category_.json create mode 100644 docs/docs/plataforma/arquitetura/build-offline.md create mode 100644 docs/docs/plataforma/arquitetura/camadas-do-sistema.md create mode 100644 docs/docs/plataforma/arquitetura/estrutura-de-pastas.md create mode 100644 docs/docs/plataforma/arquitetura/intro.md create mode 100644 docs/docs/plataforma/arquitetura/otimizacao-bundle.md create mode 100644 docs/docs/plataforma/arquitetura/patterns.md create mode 100644 docs/docs/plataforma/arquitetura/sistema-persistencia.md create mode 100644 docs/docs/plataforma/arquitetura/sistema-tours.md create mode 100644 docs/docs/plataforma/arquitetura/suporte-responsivo.md create mode 100644 docs/docs/plataforma/arquitetura/tecnologias-principais.md create mode 100644 docs/docs/plataforma/atividades_programacao/_category_.json create mode 100644 docs/docs/plataforma/atividades_programacao/base-game-scene.md create mode 100644 docs/docs/plataforma/atividades_programacao/blockly.md create mode 100644 docs/docs/plataforma/atividades_programacao/componentes.md create mode 100644 docs/docs/plataforma/atividades_programacao/estrutura-de-jogo.md create mode 100644 docs/docs/plataforma/atividades_programacao/extensibilidade.md create mode 100644 docs/docs/plataforma/atividades_programacao/intro.md create mode 100644 docs/docs/plataforma/atividades_programacao/phaser.md create mode 100644 docs/docs/plataforma/letramento/_category_.json create mode 100644 docs/docs/plataforma/letramento/como-adicionar.md create mode 100644 docs/docs/plataforma/letramento/contrato-postmessage.md create mode 100644 docs/docs/plataforma/letramento/intro.md create mode 100644 docs/docs/plataforma/letramento/modelo-lms.md create mode 100644 docs/docs/plataforma/pre-requisitos.md create mode 100644 docs/docs/releases/_category_.json create mode 100644 docs/docs/releases/intro.md create mode 100644 docs/docs/releases/v1.0.0.md create mode 100644 docs/docs/releases/v1.1.0.md create mode 100644 docs/docusaurus.config.js create mode 100644 docs/edu/como-usar.md create mode 100644 docs/edu/fundamentos-programacao/_category_.json create mode 100644 docs/edu/fundamentos-programacao/computacao-desplugada.md create mode 100644 docs/edu/fundamentos-programacao/conceitos-basicos/_category_.json create mode 100644 docs/edu/fundamentos-programacao/conceitos-basicos/algoritmos.md create mode 100644 docs/edu/fundamentos-programacao/conceitos-basicos/dados.md create mode 100644 docs/edu/fundamentos-programacao/conceitos-basicos/operadores.md create mode 100644 docs/edu/fundamentos-programacao/conceitos-basicos/variaveis.md create mode 100644 docs/edu/fundamentos-programacao/intro.md create mode 100644 docs/edu/fundamentos-programacao/programacao-com-blocos.md create mode 100644 docs/edu/fundamentos-programacao/quatro-fundamentos/_category_.json create mode 100644 docs/edu/fundamentos-programacao/quatro-fundamentos/condicionais.md create mode 100644 docs/edu/fundamentos-programacao/quatro-fundamentos/funcoes.md create mode 100644 docs/edu/fundamentos-programacao/quatro-fundamentos/loops.md create mode 100644 docs/edu/fundamentos-programacao/quatro-fundamentos/procedural.md create mode 100644 docs/edu/guias-pedagogicos/_category_.json create mode 100644 docs/edu/guias-pedagogicos/avaliacao-aprendizado.md create mode 100644 docs/edu/guias-pedagogicos/preparando-aula.md create mode 100644 docs/edu/intro.md create mode 100644 docs/edu/recursos/_category_.json create mode 100644 docs/edu/recursos/atividades/_category_.json create mode 100644 docs/edu/recursos/atividades/letramento/_category_.json create mode 100644 docs/edu/recursos/atividades/letramento/index.md create mode 100644 docs/edu/recursos/atividades/letramento/mouse.md create mode 100644 docs/edu/recursos/atividades/letramento/teclado.md create mode 100644 docs/edu/recursos/atividades/programacao/_category_.json create mode 100644 docs/edu/recursos/atividades/programacao/aspirador.md create mode 100644 docs/edu/recursos/atividades/programacao/automato.md create mode 100644 docs/edu/recursos/atividades/programacao/cripto.md create mode 100644 docs/edu/recursos/atividades/programacao/index.md create mode 100644 docs/edu/recursos/atividades/programacao/ordenacao.md create mode 100644 docs/edu/recursos/atividades/programacao/quebra-cabecas.md create mode 100644 docs/edu/recursos/atividades/programacao/semaforo.md create mode 100644 docs/edu/recursos/atividades/programacao/tartaruga.md create mode 100644 docs/edu/recursos/atividades/programacao/toupeira.md create mode 100644 docs/edu/recursos/playground/_category_.json create mode 100644 docs/edu/recursos/playground/blocos.md create mode 100644 docs/edu/recursos/playground/index.md create mode 100644 docs/edu/recursos/playground/python.md create mode 100644 docs/package.json create mode 100644 docs/pnpm-lock.yaml create mode 100644 docs/sidebars.js create mode 100644 docs/src/components/Home/index.js create mode 100644 docs/src/components/Home/styles.module.css create mode 100644 docs/src/css/custom.css create mode 100644 docs/src/js/navbar-scroll.js create mode 100644 docs/src/pages/index.js create mode 100644 docs/src/pages/index.module.css create mode 100644 docs/src/theme/Root.js create mode 100644 docs/static/.nojekyll create mode 100644 docs/static/health.json create mode 100644 docs/static/images/atividades/programacao/aspirador-thumbnail.png create mode 100644 docs/static/images/atividades/programacao/automato-thumbnail.png create mode 100644 docs/static/images/atividades/programacao/cripto-thumbnail.png create mode 100644 docs/static/images/atividades/programacao/molemash-thumbnail.png create mode 100644 docs/static/images/atividades/programacao/ordenacao-thumbnail.png create mode 100644 docs/static/images/atividades/programacao/puzzle-thumbnail.png create mode 100644 docs/static/images/atividades/programacao/semaforo-thumbnail.png create mode 100644 docs/static/images/atividades/programacao/turtle-thumbnail.png create mode 100644 docs/static/img/home.png create mode 100644 docs/static/img/logo_decoda.png create mode 100644 docs/static/img/puzzle.svg create mode 100644 docs/static/js/navbar-scroll.js create mode 100644 jupyter/Dockerfile create mode 100644 jupyter/build.sh create mode 100644 jupyter/content/Python_Básico_Aula_01.ipynb create mode 100644 jupyter/content/Python_Básico_Aula_02.ipynb create mode 100644 jupyter/content/Python_Básico_Aula_03.ipynb create mode 100644 jupyter/jupyter_lite_config.json create mode 100644 jupyter/overrides.json create mode 100644 jupyter/requirements.txt create mode 100644 jupyter/vercel.json create mode 100644 nginx.conf diff --git a/.gitignore b/.gitignore index 2309cc8..85e3640 100644 --- a/.gitignore +++ b/.gitignore @@ -1,138 +1,147 @@ -# ---> Node -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# vitepress build output -**/.vitepress/dist - -# vitepress cache directory -**/.vitepress/cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - +# ---> Node +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# vitepress build output +**/.vitepress/dist + +# vitepress cache directory +**/.vitepress/cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +deploy_homolog.sh +.vscode/settings.json + +/jupyter/.venv + +/SDD +app/.vscode/settings.json + +app/specs \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index a23d371..0000000 --- a/LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -MIT License - -Copyright (c) 2025 educacacao - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 7ae96f4..a61f7ad 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,541 @@ -# plataforma-edu +# Decoda - Plataforma Educacional -Repositório da plataforma de Educação do Núcleo de Técnologoia \ No newline at end of file +> Plataforma para ensinar lógica de programação através de jogos educativos e blocos visuais. + +## 📋 Índice + +- [Sobre o Projeto](#sobre-o-projeto) +- [Arquitetura](#arquitetura) +- [Pré-requisitos](#pré-requisitos) +- [Instalação e Build](#instalação-e-build) + - [Opção 1: Docker Compose (Recomendado)](#opção-1-docker-compose-recomendado) + - [Opção 2: Desenvolvimento Local](#opção-2-desenvolvimento-local) +- [Estrutura do Projeto](#estrutura-do-projeto) +- [Git Flow](#git-flow) +- [Comandos Úteis](#comandos-úteis) +- [Troubleshooting](#troubleshooting) +- [Contribuindo](#contribuindo) + +--- + +## 🎯 Sobre o Projeto + +O **Decoda** é uma plataforma educacional que oferece: + +- 🎮 **Jogos educativos** interativos para aprender programação +- 📚 **Documentação completa** para educadores e desenvolvedores +- 🧩 **Programação visual** com blocos arrastar-e-soltar (sem necessidade de sintaxe), utilizando Blockly. +- 🆓 **100% gratuito** e sem necessidade de cadastro + +### Tecnologias Principais + +- **Frontend (App):** React + Vite + Blockly +- **Documentação:** Docusaurus +- **Servidor Web:** Nginx +- **Containerização:** Docker + Docker Compose + +--- + +## Arquitetura + +O projeto é dividido em 3 serviços principais: + +``` +┌─────────────────────────────────────┐ +│ Nginx Proxy (porta 80) │ +│ │ +│ /app/ → App (React/Vite) │ +│ /docs/ → Docs (Docusaurus) │ +└─────────────────────────────────────┘ +``` + +- **app/** - Aplicação React principal com os jogos +- **docs/** - Documentação educacional e técnica +- **proxy** - Nginx fazendo roteamento entre app e docs + +--- + +## ✅ Pré-requisitos + +### Para executar com Docker (Recomendado) + +Você precisa apenas de: + +- **Docker** (versão 20.10 ou superior) +- **Docker Compose** (versão 2.0 ou superior) + +> **💡 Não precisa instalar Node.js, npm ou qualquer outra ferramenta!** + +#### Verificar se Docker está instalado + +```bash +docker --version +docker compose version +``` + +Se não tiver instalado, siga os guias oficiais: + +- [Instalar Docker](https://docs.docker.com/get-docker/) +- Docker Compose já vem incluído nas versões recentes do Docker + +--- + +## 🚀 Instalação e Build + +### Opção 1: Docker Compose (Recomendado) + +Esta é a forma mais simples e não requer conhecimento de React ou Node.js. + +#### 1. Clone o repositório + +```bash +git clone https://git.mtst.tec.br/rui.moraes/plataforma-edu.git +cd plataforma-edu +``` + +#### 2. Build e execução + +Execute um único comando para construir e iniciar tudo: + +```bash +docker compose up --build -d +``` + +**O que esse comando faz:** + +- `docker compose up` - Inicia os serviços +- `--build` - Reconstrói as imagens se houver mudanças +- `-d` - Roda em segundo plano (detached mode) + +#### 3. Aguarde o build + +O primeiro build pode demorar **5-10 minutos** dependendo da sua internet e máquina. + +Você verá logs parecidos com: + +``` +[+] Building 245.3s + => [app] downloading dependencies... + => [app] building application... + => [docs] downloading dependencies... + => [docs] building documentation... +``` + +#### 4. Acesse a aplicação + +Depois que o build terminar: + +- **Aplicação:** http://localhost +- **Documentação:** http://localhost/docs + +#### 5. Verificar status + +```bash +docker compose ps +``` + +Você deve ver algo como: + +``` +NAME STATUS PORTS +plataforma-edu-app-1 Up 2 minutes +plataforma-edu-docs-1 Up 2 minutes +plataforma-edu-proxy-1 Up 2 minutes 0.0.0.0:80->80/tcp +``` + +--- + +### Opção 2: Desenvolvimento Local + +Para desenvolvedores que querem editar o código e ver mudanças em tempo real. + +#### Pré-requisitos adicionais + +- **Node.js** 20.x ou superior +- **pnpm** (gerenciador de pacotes) + +#### Instalar pnpm + +```bash +npm install -g pnpm +``` + +#### Rodar App (React) + +```bash +cd app +pnpm install +pnpm run dev +``` + +A aplicação estará disponível em http://localhost:5173 + +#### Rodar Documentação (Docusaurus) + +Em outro terminal: + +```bash +cd docs +pnpm install +pnpm run start +``` + +A documentação estará disponível em http://localhost:3000 + +--- + +## 📁 Estrutura do Projeto + +``` +plataforma-edu/ +├── app/ # Aplicação React principal +│ ├── src/ # Código fonte +│ │ ├── pages/ # Páginas (Home, Educadores, FAQ, etc) +│ │ ├── games/ # Jogos educativos +│ │ ├── components/ # Componentes reutilizáveis +│ │ └── styles/ # Estilos globais +│ ├── public/ # Arquivos estáticos +│ ├── Dockerfile # Build da imagem Docker +│ ├── package.json # Dependências npm +│ └── vite.config.js # Configuração do Vite +│ +├── docs/ # Documentação Docusaurus +│ ├── docs/ # Documentação para desenvolvedores +│ ├── edu/ # Guias para educadores +│ ├── src/ # Componentes customizados +│ ├── Dockerfile # Build da imagem Docker +│ ├── package.json # Dependências npm +│ └── docusaurus.config.js # Configuração +│ +├── docker-compose.yaml # Orquestração dos containers +├── nginx.conf # Configuração do proxy Nginx +└── README.md # Este arquivo +``` + +--- + +## 🌳 Git Flow + +### Fluxo de Desenvolvimento + +```mermaid +gitGraph + commit + branch develop + checkout develop + commit + branch feature/nova-funcionalidade + checkout feature/nova-funcionalidade + commit id: "Implementa funcionalidade A" + commit id: "Ajusta funcionalidade A" + checkout develop + merge feature/nova-funcionalidade + commit id: "Prepara para um novo pacote" + checkout main + merge develop + commit id: "Release v1.0" +``` + +### Fluxo Simplificado + +``` +1. Criar Feature + git checkout -b feature/xyz (a partir de develop) + ↓ +2. Desenvolver e Commitar + git commit -m "feat: descrição" + ↓ +3. Push e PR para Develop + git push origin feature/xyz + (Abrir PR no GitHub) + ↓ +4. Code Review + Merge em Develop + Aprovação e merge automático + ↓ +5. PR de Develop para Main + (Abrir PR: develop → main) + ↓ +6. Merge em Main + Release pronta para produção +``` + +### Regras e Configurações + +Para informações detalhadas sobre: +- ✅ Como criar branches (a partir de develop) +- ✅ Padrão de commits +- ✅ Regras de PR +- ✅ Deploy em homologação com script +- ✅ Variáveis de ambiente e token GitHub + +**👉 Consulte: [README-HOMOLOGACAO.md](README-HOMOLOGACAO.md)** + +--- + +## 🛠️ Comandos Úteis + +### Docker Compose + +#### Iniciar aplicação + +```bash +docker compose up -d +``` + +#### Parar aplicação + +```bash +docker compose down +``` + +#### Ver logs em tempo real + +```bash +# Todos os serviços +docker compose logs -f + +# Apenas app +docker compose logs -f app + +# Apenas documentação +docker compose logs -f docs + +# Apenas proxy +docker compose logs -f proxy +``` + +#### Rebuild completo (após mudanças no código) + +```bash +docker compose up --build -d +``` + +#### Rebuild apenas um serviço + +```bash +docker compose up --build app -d +``` + +#### Verificar status + +```bash +docker compose ps +``` + +#### Entrar dentro de um container + +```bash +# App +docker compose exec app sh + +# Docs +docker compose exec docs sh +``` + +#### Remover tudo (containers, volumes, imagens) + +```bash +docker compose down --volumes --rmi all +``` + +--- + +## Troubleshooting + +### Erro: "port 80 already in use" + +**Problema:** Outra aplicação está usando a porta 80. + +**Solução:** + +```bash +# Linux/Mac - Ver o que está usando a porta 80 +sudo lsof -i :80 + +# Parar o serviço (exemplo com Apache) +sudo systemctl stop apache2 +``` + +Ou edite `docker-compose.yaml` para usar outra porta: + +```yaml +proxy: + ports: + - "8080:80" # Mude para 8080 ou qualquer porta livre +``` + +--- + +### Erro: "COPY nginx-spa.conf: not found" + +**Problema:** Arquivo `nginx-spa.conf` não está no diretório `app/`. + +**Solução:** + +```bash +# Certifique-se de que o arquivo está na pasta correta +ls app/nginx-spa.conf + +# Se não estiver, mova da raiz +mv nginx-spa.conf app/ +``` + +--- + +### Erro: "Minimum Node.js version not met" + +**Problema:** O Dockerfile está usando Node.js 18, mas o projeto requer Node 20. + +**Solução:** Os Dockerfiles já foram corrigidos para usar Node 20. Se ainda encontrar este erro: + +```bash +# Rebuild forçando recriação das imagens +docker compose build --no-cache +docker compose up -d +``` + +--- + +### Build muito lento + +**Dicas para acelerar:** + +1. **Use cache de build do Docker:** + + ```bash + # Docker irá reusar layers anteriores + docker compose up --build + ``` + +2. **Aumente recursos do Docker:** + + - Docker Desktop → Settings → Resources + - Aumente CPU e Memória + +3. **Limpe imagens antigas:** + ```bash + docker system prune -a + ``` + +--- + +### Acesso retorna 403 ao acessar /docs + +**Problema:** Configuração incorreta do proxy Nginx. + +**Solução:** Verifique se `nginx.conf` tem a barra final no `proxy_pass`: + +```nginx +location /docs/ { + proxy_pass http://docs/; +} +``` + +Se necessário, rebuild: + +```bash +docker compose restart proxy +``` + +--- + +### Mudanças no código não aparecem + +**Problema:** Docker está usando build antigo em cache. + +**Solução:** + +```bash +# Rebuild sem cache +docker compose build --no-cache app +docker compose up -d +``` + +--- + +## 🔄 Fluxo de Deploy em Produção + +### 1. Preparação + +```bash +# Garantir que está na branch correta +git checkout main +git pull origin main +``` + +### 2. Build + +```bash +# Rebuild completo sem cache +docker compose build --no-cache +``` + +### 3. Deploy + +```bash +# Parar versão antiga +docker compose down + +# Iniciar nova versão +docker compose up -d + +# Verificar logs +docker compose logs -f +``` + +### 4. Verificação + +```bash +# Checar se todos os containers estão rodando +docker compose ps + +# Testar endpoints +curl http://localhost +curl http://localhost/docs +``` + +--- + +## 📝 Variáveis de Ambiente + +O projeto atualmente não usa variáveis de ambiente complexas, mas se precisar: + +Crie um arquivo `.env` na raiz: + +```env +# Exemplo +APP_PORT=80 +NODE_ENV=production +``` + +E referencie no `docker-compose.yaml`: + +```yaml +services: + app: + env_file: + - .env +``` + +--- + +## 🤝 Contribuindo + +1. Fork o projeto +2. Crie uma branch para sua feature (`git checkout -b feature/nova-funcionalidade`) +3. Commit suas mudanças (`git commit -m 'Adiciona nova funcionalidade'`) +4. Push para a branch (`git push origin feature/nova-funcionalidade`) +5. Abra um Pull Request + +--- + +## Para Educadores + +Se você é educador e quer usar a plataforma, acesse: + +- http://localhost/educadores - Guia de como começar +- http://localhost/docs/edu - Documentação pedagógica completa + +--- + +**Desenvolvido com ❤️ para educação em programação** diff --git a/app/.env.offline b/app/.env.offline new file mode 100644 index 0000000..ec45a98 --- /dev/null +++ b/app/.env.offline @@ -0,0 +1 @@ +VITE_IS_OFFLINE=true \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..9a3f2f0 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,156 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Letramento activities (auto-generated from src) +public/letramento/ + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Sveltekit cache directory +.svelte-kit/ + +# vitepress build output +**/.vitepress/dist + +# vitepress cache directory +**/.vitepress/cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# Firebase cache directory +.firebase/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v3 +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Vite logs files +vite.config.js.timestamp-* +vite.config.ts.timestamp-* + +# Ignorar build local de docs +docs/build/ +docs/.docusaurus/ +docs/node_modules +.docusaurus +.cache-loader + +TODO.md +.vercel + +# Arquivos de rastreamento de refatoração (MANTER COMMITADOS) +# docs/JSDOC_GUIDELINE.md - Guideline para implementação +# docs/JDocs_Refatoracao.md - Plano de refatoração JSDoc com progresso + +.specify +.github +.specs +.vscode \ No newline at end of file diff --git a/app/.vscode/settings.json b/app/.vscode/settings.json new file mode 100644 index 0000000..388adce --- /dev/null +++ b/app/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "chat.promptFilesRecommendations": { + "speckit.constitution": true, + "speckit.specify": true, + "speckit.plan": true, + "speckit.tasks": true, + "speckit.implement": true + }, + "chat.tools.terminal.autoApprove": { + ".specify/scripts/bash/": true, + ".specify/scripts/powershell/": true + } +} diff --git a/app/Dockerfile b/app/Dockerfile new file mode 100644 index 0000000..4cc47da --- /dev/null +++ b/app/Dockerfile @@ -0,0 +1,25 @@ +FROM node:20-alpine AS builder + +WORKDIR /app + +ARG GIT_COMMIT_HASH=unknown +ARG APP_VERSION=1.1.2 +ENV VITE_APP_VERSION=$APP_VERSION +ENV VITE_GIT_HASH=$GIT_COMMIT_HASH + +RUN npm install -g pnpm + +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install + +COPY . . + +RUN echo "{\"version\": \"$APP_VERSION\", \"commit\": \"$GIT_COMMIT_HASH\", \"buildDate\": \"$(date)\"}" > public/version.json + +RUN pnpm run build + +FROM nginx:alpine + +COPY --from=builder /app/dist /usr/share/nginx/html + +COPY nginx-spa.conf /etc/nginx/conf.d/default.conf diff --git a/app/Makefile b/app/Makefile new file mode 100644 index 0000000..c1f1390 --- /dev/null +++ b/app/Makefile @@ -0,0 +1,32 @@ +# Variáveis +IMAGE_NAME = decoda-app +VERSION = $(shell grep 'ARG APP_VERSION=' Dockerfile | cut -d'=' -f2) + +.PHONY: build run stop clean + +# Build da imagem docker +build: + @echo "Construindo imagem $(IMAGE_NAME):$(VERSION)..." + docker build --build-arg APP_VERSION=$(VERSION) -t $(IMAGE_NAME):$(VERSION) . + docker tag $(IMAGE_NAME):$(VERSION) $(IMAGE_NAME):latest + +# Executar o container +run: + @echo "Iniciando container $(IMAGE_NAME):$(VERSION) na porta 8080..." + docker run -d --name $(IMAGE_NAME) -p 8080:80 $(IMAGE_NAME):$(VERSION) + @echo "Aplicação disponível em http://localhost:8080" + +# Parar e remover o container +stop: + @echo "Parando container..." + docker stop $(IMAGE_NAME) || true + docker rm $(IMAGE_NAME) || true + +# Ver logs +logs: + docker logs -f $(IMAGE_NAME) + +# Limpar imagens antigas +clean: + @echo "Removendo imagem $(IMAGE_NAME):$(VERSION)..." + docker rmi $(IMAGE_NAME):$(VERSION) $(IMAGE_NAME):latest || true diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000..1883566 --- /dev/null +++ b/app/README.md @@ -0,0 +1,101 @@ +# Decoda - App + +Uma plataforma educacional de programação visual desenvolvida em React, combinando Blockly, Phaser e tours interativos para ensinar lógica de programação através de jogos. + +![React](https://img.shields.io/badge/React-19-blue) +![Blockly](https://img.shields.io/badge/Blockly-12.3-orange) +![Vite](https://img.shields.io/badge/Vite-7.1-purple) +![Bundle](https://img.shields.io/badge/Bundle-5.89kB-green) + +## Sobre o Projeto + +Decoda é uma plataforma educacional inspirada no [Blockly Games](https://blockly.games/) do Google, expandida com recursos modernos e jogos adicionais. A plataforma combina programação visual (Blockly) com jogos interativos para ensinar conceitos fundamentais de programação. + +### Jogos Disponíveis + +- **Automato** - Navegação em labirinto com lógica de movimentação +- **Bird** - Jogo de coleta com física e animações +- **Semáforo** - Controle de trânsito e sequências lógicas +- **Turtle** - Desenho programático (Logo graphics) +- **Motoca** - Jogo de esquiva e timing +- **Emoji Match** - Jogo de memória e correspondência +- **Detector de Sentimentos** - Análise de texto com IA +- **Playground** - Editor livre para experimentação + +### Características + +- **Programação Visual**: Editor Blockly com blocos customizados +- **Tours Guiados**: Sistema completo de onboarding com Shepherd.js +- **Responsivo**: Interface adaptada para desktop e mobile +- **Persistência**: Salvamento automático do progresso +- **Otimizado**: Bundle inicial de apenas 5.89 kB (98.4% de redução) + +## 🚀 Desenvolvimento + +### Pré-requisitos + +- Node.js 20 ou superior +- pnpm + +### Instalação e Execução + +```bash +# Clone o repositório +git clone https://git.mtst.tec.br/rui.moraes/plataforma-edu.git +cd plataforma-edu/app + +# Instale as dependências +pnpm install + +# Execute em modo de desenvolvimento +pnpm run dev + +# Acesse no navegador +http://localhost:5173 +``` + +## 📄 Scripts Disponíveis + +```bash +pnpm dev # Executa aplicação em desenvolvimento (porta 5173) +pnpm build # Build de produção +pnpm preview # Preview do build de produção +pnpm test # Executa testes com Vitest +pnpm lint # Verifica código com ESLint +``` + +## 🏗️ Tecnologias + +- **React 19** - Framework UI com lazy loading +- **Blockly 12.3** - Editor de programação visual +- **Phaser 3.90** - Engine para jogos 2D +- **Shepherd.js 14.5** - Tours guiados interativos +- **Vite 7.1** - Build tool otimizado +- **TailwindCSS 3.4** - Estilização utilitária + +## 📊 Performance + +- **Lazy Loading**: Componentes carregados sob demanda +- **Code Splitting**: Vendors separados (Blockly 3.5 MB, Phaser 850 KB) +- **Tree Shaking**: Imports otimizados de blockly/core +- **Image Optimization**: Compressão automática com Sharp + +**Resultado**: Bundle inicial reduzido de 3.870 MB para 5.89 kB (98.4% de redução) + +## 📚 Documentação + +A documentação completa do projeto está em `/docs` na raiz do repositório. + +Para rodar a documentação localmente: + +```bash +cd ../docs +pnpm install +pnpm start +``` + +Acesse em: http://localhost:3000 + +--- + +**Desenvolvido com ❤️ para educação em programação** diff --git a/app/THIRD_PARTY_NOTICES.md b/app/THIRD_PARTY_NOTICES.md new file mode 100644 index 0000000..320a387 --- /dev/null +++ b/app/THIRD_PARTY_NOTICES.md @@ -0,0 +1,29 @@ +# Third-Party Notices + +Este arquivo centraliza os avisos de dependências de terceiros usadas no app. + +## Dependências Apache 2.0 + +### Blockly + +- Pacote: `blockly` +- Versão usada no app: `12.3.1` +- Licença declarada: `Apache-2.0` +- Projeto: https://developers.google.com/blockly/ +- Repositório: https://github.com/google/blockly +- Texto da licença Apache 2.0 incluído em: `licenses/APACHE-2.0.txt` +- Referência oficial da licença do projeto: https://github.com/google/blockly/blob/master/LICENSE + +### JS-Interpreter + +- Pacote: `js-interpreter` +- Versão usada no app: `6.0.1` +- Licença declarada: `Apache-2.0` +- Repositório: https://github.com/NeilFraser/JS-Interpreter +- Texto da licença original do pacote incluído em: `licenses/js-interpreter-LICENSE.txt` +- Texto da Apache 2.0 incluído em: `licenses/APACHE-2.0.txt` + +## Observações de distribuição + +- Ao distribuir o app (source ou binário), inclua este arquivo junto com os arquivos da pasta `licenses/`. +- Se houver modificação direta em código de dependência Apache 2.0, registre a alteração no release/changelog. diff --git a/app/assets/icon.png b/app/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8d584d26d3f64f2dddc514f38d518021b613cdde GIT binary patch literal 15404 zcmcJ$bySpJ+ctd73^8@T} z%?91n1O4{&@A zZ~_jXK4{@Sj?W$7fgbOp$5?2U?=cW~3i$6seGakx(87PfK1Wc$18m_TcJ%3u+U@0eOms*e>@sXsUM&{((uC-l=kTaegW<>GBSz^N`HOP3AEDK9b)&yUx4oct-ulWJ+zCzUa-6mXavv$1vCTH$6oZo-$dy66%`fH4CwJ! z07w}&tMaTaQ&l?Sh;Wk2J0{HdOm;)NVzX_tPaD35`z~M^s#BNih z&S+*d=75e*K|%354gy^nbQan&s%Uu)qa_-Tjs%VWj^}-Z`8S=gZ>!Vg$TZDjaIm{xJ^#Jo`@GO@_zmL_5S_)w{P2QtZhDj{(OCXJv}}B{rmUR)6>$@ zvRALF8X8_F#3vXVKYa71sk5`Qwzf`LNyXH}tfi&(>C;$yJNt`^i=LhyOG_(FO|6ZM zF9ijK=)SD2tsx^K)6+AG3XAsl_tC{qOHGT2KvsRNlR$5fUOxjJLxAn-28_GEMgO5| z2m9od>yU){*Zm8>8Mvw|m|#7Jr7|h(B9`!+sb3WPhJtdnDPItSH60`BtKp9w%h5d> zujO)bf*VBG&^_ynpR$YO!|>uEUG+AH&nu~|0>35ScYSf{?dN_oVlp~^qA$kC^Fww` z>Eq~fWBqu+N9cI{yK~1<`dYK3@gb9Zsi4h?z>}z9uZ#x=0`}8OLdOf=UoK4V8}EIY zogH5KX%QbavOIq^Q}bhS>(WVPOylrsHZ8LZ2>=*xU5rfqOdn`V+j)8L+t_>AI`9X2 zAkZlSfUH6w!p6?c!4GEZ;N;>d$9dG%#|d+>m*X@Mdm#7#q3q!7q7m%lU>K}pWEbpa zCuPs6Adf2>D2*oYaPYH%1$wx9`br1NasIg@^KOnl9G}V5EK>=7Un}E_b?R;Di zelA{~u)mx(wqE{za-5vFuzyo4`uX{|*#3vz)0f}oABq286Ml5k0yg%(0z&+Pf5U>o zWdDViR#rOmz_=E*z1^yS+UmyQvpc?3>X)iBn>nJ2DEH1<+EMz0XC+a9D#wRH( zBFQH#EN&+yENm+xXlMT)qJNqEPZ~8_G>e$9n6S8*l#r;9gp`=%e|i2#`9JYSUjBB@ ze^Zec{txee$^OC03jD3EyUV|d^3UYoRr!y_ze@Hm;D2k&|9PwI?f%mygujpbKTE*g zPQbz4!NbAR?{AZY{@o;dJ83@`KX-@!YLTM5-~Vh8dhJQO+ju(3aR&0)J2=|-yZdp< z8#;KvJiR;|U|eEC!mvQt-*-eHH;fM^^uI~)-<+}n|IOY1kMt1#ZIS<7hX3rfzY7qp zK<6g%@7&NcX+?iOXD=Ul1AiCT11}#N2VdF0p#N8lUi$wu;Qv#R(R=ehRsJ7Q1ll0} z+crSMr2kpIUOq-%UheYBHl6`CFncdMITb~9zW^Z{2^|ALn7^-skDRfhlBBS@m5H#S zKFrp~#?xL->90i1N6SD@5a#FLfpACf0y$ZM|CRH9o5#OWLmv(3Lqgy`M+tiJpTo!j z?Saz=ebiWp@eKn24A4|jGztVAgasifhC93_rv#&$1tH1z205aj2~e`~d$>vfNZ;s` zRBz)8;h}d}g35C?e*NQMUm@4z5tUz-o<9$}IwsAJq(pe)%M^z(lfO2!s|eW^amf4r znUZ={+qGA_x7YBxvv#)n%1-C~$M>zFeOAU#!p@9aHvK+k1arm-O$%OjbzVT-f=}^s_5(;BBucP-77}B|7^`m(si=8N zD=jL>had4#rsSb|zqqc5Xrp`q(2+S+Ra5_zkf23_7}ln!J}$0HCJJT= zh6yqhJA4{em$($VFc06Cg71#cxhn`|5h6@qT0RB~pU*am*VQbA8q6WTl9j;o%kvDX z+W1H{AvL;4Fhq^z{jg(Z6qaoRgdD*cQEpJx&PS>WfueOp9OXtMjv3up;%T0Bq^@nF zacrp!S_u$i>x)%$1-zHi;+ZjG$Wsi&3qloYDL@S=Uq(<0myYwn?gIK7nMA1}@&fB-Lss!3;;D^%sOnya@dSe#_#&HuS#Z*G0xa31AjX2e?IR$O7g z8sb$(Yf1|;-L3e*QNR_;^VDBOmO?25(pIxLzLsBtg{8?tEB0v&=!5r$iYHXsi z%}Im1Bx9w%wY~|d_P|L&JfA)hmz^Lbu{QMg?FT~(P;P~1mMp^~#sI4coO8o+&3@{x z0-aCqO2gVGun#Kdmr!i}r(CKXwG(oWue-gIbkV=;|3bW(D7N(qn@P2$~LoLb9_#}a%S z6H5wnYQyIMI~FMYjwz2zA7Ess!7ji!RD6Q9)i}HyLk5WGkYM`&%2Wbx#BCVm{}cw^ zUeow`nG5~*yPw4OaSInbKe`-ac05ube9=ba7afr^UEnPe0_jxA z;e`$%A@gp3>&(DMwkkcxneU^#vVHh{+eI_N$8c`IIy( zL}#c)${BXU=R1En=}<7wSegg)io5E5fJ&sbo{`D>tqN0aAjb1L@_H9S*pV4J^ZLeN z0V)UFZn{L+bUH%*kLzP?O6qfTT1vZXFZbi|zN^t+adTJ%;L1ZDDpK!e5%hbhQu@^8 z_r(v01fQN_?(oT}2rTIx8V8k~s^ZzNUk$gI#<(-NB8eCH+&tjl-+ZAdYBIogi>Y-( ze238aMH75eXzZLJE1G?Cs)}4K_T%UHO!f#`;iC6IAWCG>^7d+>+iv-75_QyZbDBqe_qZitubJ#^d2 zacWTNdaR(%S2Z$8+Svn|=4H285!qEbV83E{Wq*8)VCJ++gY5`+Q(jPKS59@0X50I@ zcs7PUt*n8{_17vqcC2V>{3H{byOXXu4<*v_}6<@P|fh%bV| z{KlqZqTtJd#Me5EPT>g@A%XEO7_cAeYSbWEHKToXECN=PgFRAg5V|2$5_GTn5&Kho zR^Wv5aOYrmEg7{p;YTi!3=Ba9QTR(?t<+|k4C`)5W*DZs?E&_N&?aMgm3 zE928VPSV!X`u#Gv>iX9e~c(RGXFMpDGZvNa*7ft}H=T-2^A zJ8biwZU_ajU>qQlARbrET=C~HQCfe69$c_P0-F{ARg4*Gt}%}gqnt3>b#R}Gk`eqI z%ez7f{SD$^J>KY*&QbUa?A{f?4hl~OY8OEZMT6rMzQM`d7^V*$D>heZ802HXJl{^K z4WaP2klbzjiEXWy1&nr3P-O z=_}=Ev;@m&q|!zNy5WoUU_;~!dD@%uB)JcclGa$Dc#)l@B?Mc9o$5Y?P!!-cMnhj+ zNWc)MP|Ld^hJu3A7)lE(53osp*#^dr-Wt4r21A7xF&fI#7~xAG&MaPkGb6}_1I4_0 zv6i5aojGBaT2#&t4>0IM7VoD0E=8jxBR>6+v3x!Vg7%I%vB+zk4l--QqJ|^$yBjj! zn4nl7!o6J90BEcfW)_0EZv%IG8wOe6L>}p-)%AcWe14g$=B2;UTgGUgen<5?7F9fZ>lKF}QSP0SpLJ6o0lSbP z+rgz?(CfRaYoP=N(fK%fujhPN71~G#74s!J@SXh8EyGnUx633+0X98FefN#~MsWCTn5sP(*d;}}L-*ru z62|Tx4Jj1&eQ$}Gp&PIKiznvYAR)nCncI2^f)y8s&6?r#;4;E3otwzCvH;q8q=Enu zaCr2*xza9G0Cwlf;eh?*b!9c_hRSQ&9lZWS`n2l@Qf_)I#ihk?osN@7j=``8;LDj9 zlqJ-Yd522LP=_u*-uRg9-519nIUFFz!1pvD!fM=suk>k+8;9>k*lZ~Z_Qkk)Bgt_P z2h_TnOEOVz-6kku>`Dv0{GnQF-{_B($ruJ~C~aNU2h+HP44r3IlkJ)7T>^-VKnmFj zU$2u#P604gFtHWNg*cw43B_xjfWZ&JvLPd=viqV7A?zLUj&*Ls)w#&aj)c2nEX^9ufV7;OB`!FT zBBfwROCPSI>!|Z13|QQN-(oX0kLE2Aq)S)N8U=Mf8!+Jb`nEwP|cK9`tU3?`h@AGY}d{tP{M4iccQ{wb(77Uf=(6$;#wUU_hO~BO8!;exH z?xT!V`fVLaNEBa5PAy3O=SBn-nM}_@t%Ss;oZ_UU1DnJACLS2F`XEDLo_cVny>xS+ zQE~ox^NP5iwvj-3@gNC^?*%OhvGx3lVXW4}Ki@F*B?Ys#f+?&b-ZWf`#EY}-+aN!T z!^L|=rkGK!Zr{mrJfd=7ez%WyZ8pRO^0BtYb5DT{1KWv@xbLY~NRylmB=}r@(z<#A zEU3l&vC12$m{-?>pZ-Wax0dHD+hpTJ06*k#*9OJ$EHm=nK9xOA<9?`DpC!g=NCso@ zyIs;j-~~jSS;h^05SBW@Uw{Z|w{a-Nwl}J1wdLhhk@vm2^r{J|>hYb>IGxm*xwO+e zFl0K5@skMF;%+{^C~0&~#v`${eNI%Xh^~=0A#TwpTPQ(GxBtPJ#up{(MD#y zS^I-hdqy&YU6~<~oUWovUD}r;3^tgJX6;*khvktO`7OL8Wr~CnM=;ZFH_2?aBT5Ka z2eDYdA3^Kc2-k1^B8N13f)qJy**Myjm*t~Wqrl_L$a4~*)0`DP4|{{y zM?0lNsMN@$ZiB<)-%za*sc*o>&x#>r$`>vQ8{v-DK{sD9%)D$xd{}P@;ZNy}b*+m) zahn9t3_X@Cd4H_yKw(SkCI=E^-ylS-+Gfcyjs2#5;(p4V+MBhc&pr4g5HoKA*b?(o z)BHIHHm8+n8@HL~>U3H`RtccZmO6abi}xa8Pfw6l?5iWkmbfU9;zbtPY43o4lLI5ln6Wo6>Y&hp~;`D z?g5cwC;sX+bPsqJyjVjaVlK?6|LW6(>lD~4Vd*=5N;i{U7=X}3s3m|1o1WIhf$ujz zrFHc>|YHt>v&Xt z#XGH`WIVT0bs!Y`Tm=6|{lR6u0P*DPEaad2*&qfBb>zdAzs@fvpN&}2)i4>(bS+1u z7xo)J1TDQ9A)4ITcunx^p3~!lzV?}oXSopM{rJyvf#MtT)jl1=mLH56;A_P6pNWtM zH>%_7fjipD0Tk|q+YXPXBblohYK3~4fK<>$$PPZ-l0o+UWJez4z8(%z9%x^uzDmcQ z_1UWDeb-Y^DPrOR2HI=_%L$_&lFQ_qAOCV&Q3 z6t38F)hAR$X*>N@Wbb`~e2l*yiqU>NInQT-QoN>+NI5s^-h@xt)YdS8+fx7qy&==k z5SMqRM3{meR5!Ij9F5e?yzlAx)b!3=KbdvIBYjDpMZK3LgNGIWe#tXnbFpp`K>{N4ySoq`E^_zO-KZ_d1@)&x$SbZjt4~Xm`)iLiponcx?4fjEd1nkq zXShWS{VOuJO;g{qAnd}V_z0a>B)N{rS;ZkaBZQ=Z$OjY6KF;YO*$m^?XgR8XouwW@ zf3Nrh=vKQHmK?;UAuz3G9Sfqm1Svh5bFFI%1Lr>6U~`9qNLRwLi$U+ai@=;$zv?cJ zW$9m@Z7nbb@xlQ&NdsB)-el5+A5$AX;qQ-=c8${02)N*w#UV&Ms+7LKu*YIBEB8&) zq3y-s>v{lG_a%N^4&_bx);ig_yfzLP6goAYP)_9(#P8C5B(GirU6xE9?$1jOHP7F$74oGzs#g)^739r zE9mNE_WRw80!GO_qP8O9u_gmn?2Rw4Ka&W?OEUZtz?agYi}Lohe`$N@^)WD+s**IW zMFzZ(i@kaA=ks<8fss>ySOI->JK;)%9dTNPT{C17JVWh|rR|K1s9|A^|AA`%-ak~5 z>NRT$;>Ex+>J{2B+1s?2!shGhFP|^D95;Jio}#Z{-v0F&D6sdrlt;cIYg)-^=^J6p zSRRp$DxZfGzmo!4hICmrDg>${M$?i$>22Ey998LU-Jdpy(B)A8TvK!$D3GNFb8I_{ z)xsrBM5(k!vAQ=B+uSf_r8%~$8Dx5vEJn%Id|4<35?Mu#n}@-$EyBjLM2*~m`gD*w zwoBXzE;;3s-xU6pZL1wHwx{5g+Ip@JI>6BjhnPXJK`#dXB4C28s?(vuRt|D}4tdpq z3-yi@#*yB9ZyCU|NR5;LTCDI((<+nEvY9NcUj-AQSokIj33uNXsX(R;`W%X{3==>U zyEJn|(-fzaBHD08N<9umRV<^g;-GF2Dn=Cv`~B4P$~<~4d4uP!ghH%)WwO!$d^2aE z7%|1O4jup0s#qs&yoT{d?*(S_j4i$gpb;!kBHPjZT085Q=Cv(}G%N{*x0fsdu=P^u z6@i{>&bb&!s#Nq8!}Dpn{Q?)`U;=XIPLW$*vNSYbU=&JY-XUv+k8G<@NSS?)3w4doPFHi`JNT*?Qg~!}RRo z;A{f;2DJNod7IU4*{%HN+Yi}=jG{Q0TuefvyAsUgt~ybPS55TG0IC^uc>C@?`8nI~ zUGosKs9qy{4?+a(o)i$5h;1LZcwu}Kb3T_n!M;%kJ_?IR5yZ-e$?N0JeFI*3tsEfE zvfda%-2mqf>H+WB5ZI35mrPxF+g`@%kzIr?!mycs@P!e@31hq?L=qdkzndDZ_sjN( z{ZeP=&!Tk#?xY=I6k01;@Wo#i6i7RkB#WZC+U#P!-AP})5evqrruP-P){-vYAEvVv zFSNng!sZgW&Z%zPl#+8+?pU~GP7#r+q-}}_UD3qPIKi0HNjq>rybMbo0mW5HUuQ%&V5p64er}o4z;}^V1T7E$Kh|NJ`vv$PUN&u!JCu!+k`d zg^04@>ZI#cSatZ3?y0K}{#ZnDKlj@B0^dz;aueH5k|=P^nsoOo+}U9eM;>#h)n=52 zQOlRB-`{K?zxqdTmFB#|!G8LN`IE7zL*0uJ$860!wq}9S)_IcI2ZEEgk)}-8_78y1 z^1n8Dn8F{Bt-#-o3T5`snCjRNLXQ-cJzbF?2WW9-{Ea(_4h zy%UKEY^=$L#%h&X2~r>6meDewkBD=KctrgIV^2`}iL~hAtBMj5)QHIlQH(klmzk2G z-hO0->#&De(yh6VEbfx<`!sW0(sIzr3d*EmyLMW9#mT|P?h z8Owdd<95A2BF^t6XBga-mD%d;mMo^SwTWEPSGFlXU|mNJkT+^%s@x1(U^V_w5|Wqd zTy$@LvFtw*@RUF>x)t<&Jz?Qfe@p6{@!v1s~3RV8MAK_$eCT`2*J|$63ev`JPWY zx^OHtURul1*_hZt0D20HDKHSY37!ph&d2_IHS?VRbXAk2OVh6Kja*TUsj{CTl^{8s z2-!U$toMR|NfB_#xgmJTCLzsLHn_qijwiy-)vz%KffYNw1#)84Oz`YS_&9k8*quAxhSno!*xyi+4rz$n7C{GGt$`(+RpO%J>$nTGlC`Hd;!aVeJc@UdvL9#);A&@?j!)I}6p2+UC=w zqcSB8mEyd2@`#Vb)T3LhDj-)yWFP~<2n6|ypy(2$V}vTCFGU0Jspn<18E${PTf(2p zz(4sY?${p0THcXiEpXJ&&mFNtW;ug1{;3C?BGMoiRkSBFJ&@lpom+MOpz7elXMX7( zj%dOD*=z?5XF%jC?}j9#j5-EiLG3pjIv3x>1f9E-!>@mS+KO=zbDWPVVEJ}l%7wmy z6!Lo|!o5c9Ai8-BUc!bi(p+f+O3y^C?ld7kuReoNWpzawR0`z-hnc+M0ak>D6EGkWPF8xSR zt%!-{h`I#@a29}q+lNg_ufIZ$Je9$Jwc_QE3&SIvTm>JlVzCv0NVgbSGiAo-a<&`| zmDZg^cO-v)kLSZW)G=$3pUc@)*;2s0)){(*%B(Coe2v{Gx-Z%EO5;qE#^Y_^*)Qv0 z)k~JeLud1$yFHU`?k~}^wyirY@9zgNY-T?#mwF4Y$1eu`F8O?3y0u}Yk-eWz-1{go zIxV$CC4)f5a<6 zAvi9=HsC70bmz-E;E!3k#3+x|4Ow$eBwiBRm-HaB=F>Oul~sQJ3RzFL3I3@>4OvUf z_f@(8nPbww@)CI}M(t6IiO*CWk46Yt0$P_bd<5*_^xF1o@LR=zHSwz)Un zq_?VhUe-E8FPHXD`d(3tKAv@5^nMr_Rz#Wd)boMG2R66vvRbQ@bjGo^pAJQ zvH*rVe`wR-ZxmM^#FNR3}&hDBtLhMqt|_r&8V|%stbb$m58)@YYWpc}C*D ztxNbjt~Vn=LLowAMX<#R1YL;*05a*n_X23|*_BrlffButJq;zIB+Q)zqLAJu0VT?B zY?xLMdK^5r31#G-C2De0xsl===gRGx{#`d&IDvELBhlbV|H=!*bP;Opqo5qE57tIOEix>yw-A;EQ_a_t^xnS9ruW0*He0@CIpnv!Xl4;!%s6&26S7vfDAR-z;3)R zpEG25xYF!@#NQBtyTi68d4G^PZLMr0-qOaO%reyjw9Nh6aY#L3aDwu(Yufxm{^x!+ zXHmqyfNsy-mypj^A-h?leaCBN?N)V>RuESr64&{j+&n9IotI5W{gqIyq}2Gg(T>f& zkS{hJ+Ij{Q$hG&7(f~tT(TK(_*X8UpG(IKi?*k&&lTXqC6fkzQsz$qjOPbhe#SH=CLB~$2^9Co<7}J zKhuJVJ&I}D8B#WbMPyo4Z=zH|PQe;PZuRAjnru8h=_GYwE9|Ixo8AqX%RS=`mf!gwDkGP#Vj_PZ5Hmi+_Mq`E zn2EGSUn|EYlp6-uwrhQ@^|k^o!s+MOsXvu1%m-blt*7FDsE38dnyBgDvJ$s6{<6!s zYpN@lrH#WHBqZgHeB$pGcz3i%Dr*~b6+5Y1nA#C2LS;#wgB9xD2~XJm3X(X1*gLiQ zG-i>EwgQJi8S@-4=&p_JnQsG&Jg9Sk{{0LPhioLU(~Qv9wk^!K|CF}F7fyXI0QdVH zBSo*Zrx8`??sfxxplFM@LJUn~QSIEoQ+9^q$9WZ6o^T;_v^^}<*K(yiDFqv1<7Mm_ zPd{@z7Gsq?#l{iTSn*0p3znIB9&^4-)k7(@>9J*LVtn->BhW0-8lx zAEj=CU<=W@f$Ub`<&nf*%s~zd>TZf&^*B+#phVrsZ{<$S(^+Zm*)M?X#Z*tc70xh9 zO-az!hZ@x5%?3G*K+0cA45rFKJnopu2N2qE(mw?l7F3k~b>Y zZ|JciUn+i}+@(|R@86*9_$E@lmi-XH%zWN|Tyo)EK^v5?Zk;zm68f4lM#q^b4|^?& zzkqs3RO{Y13_+$hc%I+6#3}>nzLIUEHu+0l22-~~Fn%-QtVi85mc;*>(^UUz;ozje zrMrj?|GKEtO6a$Vjmt~nN+F6GSn_QUR^VG|0y~?% zY0GjYNZTMjwRH09O~@B>y_Y8s0B-`|Dm8}ZDSvETTg;w(+6H8Z6IiFar)RGlv&p)r z{q+yF*pDappN3vpjb$z60~e~fpzI~2D^4J7nW?r}#cVbTTV1luf%%|zfT32|`kSR^ z$`5dMsyKv;h4r+E|NKY!xev*;JoV-`jvXoX(sWHE$4M2k~bh?QY9h zBa^u))%h{ckaAC`^4`}z`t)2Xl&)7~exqXuV!d5_BQL~`^*GHcvdKoJ7zq{MnOp9m z)W;hQ#dZYNX&V(nAsM2#kd2@5e4OK(VO&3r56|f`n(cR1^-Q^ps zB_tCMsH5IwOgLtGWcq+@nV}L`;XhC9yu#XVN@sf!Ug6iuz4fcKh-#m#LJ_8U}$FG_WS#IUWt^8NpehlYWSqGjGk3O?E8H!RJFSf^Ff_0=EQzOr=%yoana^fBsDIsK$V zN-1v0=CliGaa@qAWRlc?eo@59OfEkPb9jgWuz)hYs`d7(r`W;PF6b(;| zS-ilAba&z=?Zz>O{WHPfy@hrr%q|Dk3KJ=_YfuSt=!aKC?-SqfSyuDj(7o-C_Ss~; z_HJkK)CYg26S4K{cIqas$Bz9rY{e30ZFhR?tbk1bOr0TvcJ*G<}d?`0`Tx6HkB zDvl>opd)5MScwZMO~uNmNc@qvX<(L^uXISf&MV(stv9blS-H-258xMg>4%)DN zfLvB5O2^DNBjhYxYPIfWzi*32!EA>vf5^TR@$I-hs{A^Qk(Z6kd%gP#S0dyNtFc0` zl;t*e65#_E&KH-@>eA)OY7rs6k3W-#6d_vU7R=z@pjP&thQxZ=yKqHPl1plRD&09vGXDp} z;Zu4@!};69*$5NX+*(0$PZ{|bs&Hp|77z8Z3G1@2{jvOc3F|k;I^Pdsx=)u!5eB2g zqo1I$$cWxXo!8%w91>=%0Ba)0li5&|HSGhSnEe2}O!bqrhz#O#nH@`6<9lC4==kF~ z#uBp}B`YKT(>ITwIgw!X#N?oy)pACJK<6f5cLII{i{D@O@!sDoj_8lbcg=latM=p0 zbI-1QNAXb66c0?tCM}zVfq56YwF=LGj>|Z>XHV(#eEN}o;^=iLmI}Jb~EQ4*_W6wacvj8@NutSH|S!ZCTmN{9q z$$arz;ad7~iHO$KbOE=8s8uhx@YDLD#uq$EYbg|!McmH?tqIl$lD(N?Ro5ggp*`|@ z(3e{@47wOc21%MkGAxCs7G0@$Yf6=FYyA&+{UfK-xS6>E_4@CMJuiJ-aj90P18?RW zs5U>V2C4MK3gg`SkkrLB6#jVMp1U9@p*`9q767OHA~# zUJSE#npk`+|7?bV8FkB4X*;$pa#ag$KZnQNCK}qsX`5ibgA%foxjc-&=(KpLit0h% zvlK}xHuA$XwfI_AJXznqR7?8^p3mM6#IzBF@_xlZI>ac4TMg;W zAA}xP#lgFeaD2}55t7GrL%V&i3UicCtNgA~w{0`Rf%ew$c8j+YN8VQ3!pLAK{uT$h z1#zM3Ln~p@tl~j<5M%nPJk@-UZfII_Gq7r%6LMv{Wajc_L9pIb?~uD@I}Py z4iE zR1D67`V@K{^{pg0TxljtaZx)8uQ%k&XDZ&(d+laF?v?Nkal-SJn`C@oB(Mk^Y&sbP2c#9^ru zIW~uivg-w>^WFZbI&VrvuhR=R8p9{fBh%&yEWj*~1>9K;dbaU+feQ znDNAzNX*`1{&st|ht0Ti-Wz|~OCB*TX){mU7zr%VmS8D>-T7cI(&qR~c0&JL zWz5L^ANzb?XiY za|BuoGRNNaRTX)>c6C5e-Gc_>9EZGxVhmS%yHnj( z(vlxfv>8rG;j>U!3#Q~+6=Np{K9e{#TeRnACW5i9U>sBtS!oUstOoRVD0+V67>#>C zN(5pZd&dHmPLRuWzj*Qq*(sIDPA0=N%Le*+kyLUP8Z#WOsH{92xf>?6s&F=X(O6=m zWt!35^VTSS^Za z6Lg#t3DxVrBe3T*;T68VdL~r=K?OxVDZvX43UZ<-2AK2Vt|@X{pvF>`x7I0_+LrfV z!8j!z7-Pl5qaVC!wUU%fe8`^G0d;eG7mzQ9zXG#=Y}D3+CZ; zG8le8Q$fG`C4_h?^F{}&9v4mQi&X|xeUH+A=^ylm}^z|n4N)~-N*|}z$7tc!E zhb7I5N34ra49H>!B$yp{bt>LCLe7XU*;FpfSm0xB)~Sl^sl`BMUf60cdFY(v<(V{Q zBR{jE+71k5*w1ootK??AyOL`b1F8cxUgfB1Upqf@4~gD;8$YkUGf)*+2}Q_&sBqs? z$a4vQ>RQm#J-hR=D*BMY^wN*xceeD`RE4vvhE(KZg|6Izs3>g`IKoneX#eSBt0Fh& z&l$7|pk*%&$Je@gJsCpVvl4wq16RB1E&4Op3@H?omdU3JlUZl1{JNHTF)dM1&RZ^&5?eklfIu= z;J3dG?!Mi$$M!MyH7=yQp>X0j{LTO<%ah(!#hdK1-yw6DyQo#(bK7AMA5aLSmH8?) zG-|dufvh#fe~06wEy<|dDlzBXq59q)bN=RGn56~{&6M(=CJ}kR0{Qyz^+}Bup1kV& zpj(^Iw0@;(y_22NJ>=N&?t+Ed5jwRb1HWxok|6r?hw1Kjgjqecz$ew7o^gF^?3QDt zO7L33mz8f$?ij=j^csQl%x??}D&8{x-~Ri^{{ep_o7geaKK!Hv_c9yr??3-ERdrMv Il&quvAIE`TP5=M^ literal 0 HcmV?d00001 diff --git a/app/eslint-report.json b/app/eslint-report.json new file mode 100644 index 0000000..804c61c --- /dev/null +++ b/app/eslint-report.json @@ -0,0 +1 @@ +[{"filePath":"/home/rui/src/new/plataforma-edu/app/coverage/block-navigation.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/coverage/prettify.js","messages":[],"suppressedMessages":[{"ruleId":"no-redeclare","severity":2,"message":"'ar' is already defined.","line":2,"column":3893,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":3895,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'ar' is already defined.","line":2,"column":4061,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4063,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'at' is already defined.","line":2,"column":4089,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4091,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'ak' is already defined.","line":2,"column":4604,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4606,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'ak' is already defined.","line":2,"column":4665,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4667,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'am' is already defined.","line":2,"column":4670,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4672,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'ag' is already defined.","line":2,"column":4691,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4693,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'af' is already defined.","line":2,"column":4789,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4791,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'ak' is already defined.","line":2,"column":4854,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4856,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'am' is already defined.","line":2,"column":4859,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4861,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'ak' is already defined.","line":2,"column":4949,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4951,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'ag' is already defined.","line":2,"column":4970,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":4972,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'V' is already defined.","line":2,"column":5216,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":5217,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'U' is already defined.","line":2,"column":5220,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":5221,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'ae' is already defined.","line":2,"column":5244,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":5246,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-prototype-builtins","severity":2,"message":"Do not access Object.prototype method 'hasOwnProperty' from target object.","line":2,"column":6621,"nodeType":"CallExpression","messageId":"prototypeBuildIn","endLine":2,"endColumn":6635,"suggestions":[{"messageId":"callObjectPrototype","data":{"prop":"hasOwnProperty"},"fix":{"range":[6638,6656],"text":"Object.prototype.hasOwnProperty.call(ag, "},"desc":"Call Object.prototype.hasOwnProperty explicitly."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7590,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7591,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7610,7611],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7610,7610],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7592,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7593,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7612,7613],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7612,7612],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7594,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7595,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7614,7615],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7614,7614],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7601,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7602,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7621,7622],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7621,7621],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7616,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7617,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7636,7637],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7636,7636],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7628,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7629,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7648,7649],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7648,7648],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7637,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7638,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7657,7658],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7657,7657],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7639,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7640,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7659,7660],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7659,7659],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7641,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7642,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7661,7662],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7661,7661],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7647,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7648,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7667,7668],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7667,7667],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7649,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7650,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7669,7670],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7669,7669],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7651,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7652,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7671,7672],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7671,7671],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7658,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7659,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7678,7679],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7678,7678],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7673,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7674,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7693,7694],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7693,7693],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7685,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7686,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7705,7706],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7705,7705],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7694,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7695,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7714,7715],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7714,7714],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7696,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7697,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7716,7717],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7716,7716],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7698,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7699,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7718,7719],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7718,7718],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7704,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7705,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7724,7725],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7724,7724],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7713,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7714,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7733,7734],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7733,7733],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7730,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7731,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7750,7751],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7750,7750],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7736,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7737,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7756,7757],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7756,7756],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7745,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7746,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7765,7766],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7765,7765],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7762,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7763,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7782,7783],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7782,7782],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7826,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7827,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7846,7847],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7846,7846],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7835,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7836,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7855,7856],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7855,7855],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7852,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7853,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7872,7873],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7872,7872],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7858,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7859,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7878,7879],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7878,7878],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7867,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7868,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7887,7888],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7887,7887],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7884,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7885,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7904,7905],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7904,7904],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\`.","line":2,"column":7890,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7891,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7910,7911],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7910,7910],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\`.","line":2,"column":7899,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7900,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7919,7920],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7919,7919],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\`.","line":2,"column":7916,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7917,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7936,7937],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7936,7936],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7958,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7959,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7978,7979],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7978,7978],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7967,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7968,"suggestions":[{"messageId":"removeEscape","fix":{"range":[7987,7988],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[7987,7987],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":7983,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7984,"suggestions":[{"messageId":"removeEscape","fix":{"range":[8003,8004],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[8003,8003],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7989,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7990,"suggestions":[{"messageId":"removeEscape","fix":{"range":[8009,8010],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[8009,8009],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":7998,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":7999,"suggestions":[{"messageId":"removeEscape","fix":{"range":[8018,8019],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[8018,8018],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":8014,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":8015,"suggestions":[{"messageId":"removeEscape","fix":{"range":[8034,8035],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[8034,8034],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":8071,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":8072,"suggestions":[{"messageId":"removeEscape","fix":{"range":[8091,8092],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[8091,8091],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":8078,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":8079,"suggestions":[{"messageId":"removeEscape","fix":{"range":[8098,8099],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[8098,8098],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":8082,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":8083,"suggestions":[{"messageId":"removeEscape","fix":{"range":[8102,8103],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[8102,8102],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":8084,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":8085,"suggestions":[{"messageId":"removeEscape","fix":{"range":[8104,8105],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[8104,8104],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":8091,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":8092,"suggestions":[{"messageId":"removeEscape","fix":{"range":[8111,8112],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[8111,8111],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\..","line":2,"column":9231,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":9232,"suggestions":[{"messageId":"removeEscape","fix":{"range":[9251,9252],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[9251,9251],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":9235,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":9236,"suggestions":[{"messageId":"removeEscape","fix":{"range":[9255,9256],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[9255,9255],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":9237,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":9238,"suggestions":[{"messageId":"removeEscape","fix":{"range":[9257,9258],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[9257,9257],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\`.","line":2,"column":9239,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":9240,"suggestions":[{"messageId":"removeEscape","fix":{"range":[9259,9260],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[9259,9259],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\/.","line":2,"column":9241,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":9242,"suggestions":[{"messageId":"removeEscape","fix":{"range":[9261,9262],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[9261,9261],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\#.","line":2,"column":9243,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":9244,"suggestions":[{"messageId":"removeEscape","fix":{"range":[9263,9264],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[9263,9263],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'Y' is already defined.","line":2,"column":10812,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":10813,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ae' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":2,"column":11414,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":11416,"suggestions":[{"messageId":"removeVar","data":{"varName":"ae"},"fix":{"range":[11430,11442],"text":""},"desc":"Remove unused variable 'ae'."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-unused-vars","severity":1,"message":"'af' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":2,"column":11438,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":11440,"suggestions":[{"messageId":"removeVar","data":{"varName":"af"},"fix":{"range":[11454,11468],"text":""},"desc":"Remove unused variable 'af'."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ag' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":2,"column":11471,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":11473,"suggestions":[{"messageId":"removeVar","data":{"varName":"ag"},"fix":{"range":[11487,11499],"text":""},"desc":"Remove unused variable 'ag'."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-redeclare","severity":2,"message":"'W' is already defined.","line":2,"column":11501,"nodeType":"Identifier","messageId":"redeclared","endLine":2,"endColumn":11502,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-prototype-builtins","severity":2,"message":"Do not access Object.prototype method 'hasOwnProperty' from target object.","line":2,"column":11964,"nodeType":"CallExpression","messageId":"prototypeBuildIn","endLine":2,"endColumn":11978,"suggestions":[{"messageId":"callObjectPrototype","data":{"prop":"hasOwnProperty"},"fix":{"range":[11982,11999],"text":"Object.prototype.hasOwnProperty.call(t, "},"desc":"Call Object.prototype.hasOwnProperty explicitly."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-prototype-builtins","severity":2,"message":"Do not access Object.prototype method 'hasOwnProperty' from target object.","line":2,"column":12097,"nodeType":"CallExpression","messageId":"prototypeBuildIn","endLine":2,"endColumn":12111,"suggestions":[{"messageId":"callObjectPrototype","data":{"prop":"hasOwnProperty"},"fix":{"range":[12115,12132],"text":"Object.prototype.hasOwnProperty.call(t, "},"desc":"Call Object.prototype.hasOwnProperty explicitly."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\!.","line":2,"column":12253,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12254,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12273,12274],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12273,12273],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\-.","line":2,"column":12269,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12270,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12289,12290],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12289,12289],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":12685,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12686,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12705,12706],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12705,12705],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":12689,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12690,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12709,12710],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12709,12709],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":12693,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12694,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12713,12714],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12713,12713],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":12697,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12698,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12717,12718],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12717,12717],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":12701,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12702,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12721,12722],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12721,12721],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":12705,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12706,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12725,12726],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12725,12725],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":12835,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12836,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12855,12856],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12855,12855],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":12837,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12838,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12857,12858],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12857,12857],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":12849,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12850,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12869,12870],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12869,12869],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":12851,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12852,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12871,12872],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12871,12871],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\/.","line":2,"column":12855,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12856,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12875,12876],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12875,12875],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\/.","line":2,"column":12881,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12882,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12901,12902],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12901,12901],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":12913,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12914,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12933,12934],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12933,12933],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":12918,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12919,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12938,12939],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12938,12938],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":12923,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12924,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12943,12944],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12943,12943],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":12954,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12955,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12974,12975],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12974,12974],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":12959,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12960,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12979,12980],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12979,12979],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":12964,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12965,"suggestions":[{"messageId":"removeEscape","fix":{"range":[12984,12985],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[12984,12984],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":12998,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":12999,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13018,13019],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13018,13018],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":13000,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":13001,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13020,13021],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13020,13020],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":13038,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":13039,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13058,13059],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13058,13058],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":13043,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":13044,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13063,13064],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13063,13063],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":13048,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":13049,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13068,13069],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13068,13068],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":13080,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":13081,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13100,13101],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13100,13100],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":13085,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":13086,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13105,13106],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13105,13105],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":13090,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":13091,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13110,13111],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13110,13110],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":13125,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":13126,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13145,13146],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13145,13145],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":13127,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":13128,"suggestions":[{"messageId":"removeEscape","fix":{"range":[13147,13148],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[13147,13147],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ae' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":2,"column":14757,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":14759,"suggestions":[{"messageId":"removeVar","data":{"varName":"ae"},"fix":{"range":[14773,14798],"text":""},"desc":"Remove unused variable 'ae'."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":15786,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":15788,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":15809,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":15811,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":15835,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":15837,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":15875,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":15877,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\!.","line":2,"column":15892,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":15893,"suggestions":[{"messageId":"removeEscape","fix":{"range":[15912,15913],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[15912,15912],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\-.","line":2,"column":15908,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":15909,"suggestions":[{"messageId":"removeEscape","fix":{"range":[15928,15929],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[15928,15928],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":15918,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":15920,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16362,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16364,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16410,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16412,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16453,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16455,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16498,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16500,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16551,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16553,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16574,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16576,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16597,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16599,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16646,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16648,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":16661,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16662,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16681,16682],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16681,16681],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":16676,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16677,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16696,16697],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16696,16696],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":16708,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16709,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16728,16729],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16728,16728],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16719,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16721,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":16734,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16735,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16754,16755],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16754,16754],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":16749,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16750,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16769,16770],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16769,16769],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":16781,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16782,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16801,16802],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16801,16801],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\).","line":2,"column":16817,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16818,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16837,16838],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16837,16837],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":16819,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16820,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16839,16840],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16839,16839],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":16821,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16822,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16841,16842],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16841,16841],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":16833,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":16835,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\!.","line":2,"column":16860,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16861,"suggestions":[{"messageId":"removeEscape","fix":{"range":[16880,16881],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[16880,16880],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\-.","line":2,"column":16991,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":16992,"suggestions":[{"messageId":"removeEscape","fix":{"range":[17011,17012],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[17011,17011],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17026,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17028,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\/.","line":2,"column":17059,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":17060,"suggestions":[{"messageId":"removeEscape","fix":{"range":[17079,17080],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[17079,17079],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17079,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17081,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17111,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17113,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17161,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17163,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17203,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17205,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\-.","line":2,"column":17256,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":17257,"suggestions":[{"messageId":"removeEscape","fix":{"range":[17276,17277],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[17276,17276],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17285,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17287,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":17311,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":17312,"suggestions":[{"messageId":"removeEscape","fix":{"range":[17331,17332],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[17331,17331],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":17313,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":17314,"suggestions":[{"messageId":"removeEscape","fix":{"range":[17333,17334],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[17333,17333],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17331,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17333,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17354,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17356,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17380,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17382,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\-.","line":2,"column":17435,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":17436,"suggestions":[{"messageId":"removeEscape","fix":{"range":[17455,17456],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[17455,17455],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17477,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17479,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17500,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17502,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-undef","severity":2,"message":"'PR' is not defined.","line":2,"column":17526,"nodeType":"Identifier","messageId":"undef","endLine":2,"endColumn":17528,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\).","line":2,"column":17543,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":17544,"suggestions":[{"messageId":"removeEscape","fix":{"range":[17563,17564],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[17563,17563],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\\".","line":2,"column":17545,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":17546,"suggestions":[{"messageId":"removeEscape","fix":{"range":[17565,17566],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[17565,17565],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\'.","line":2,"column":17547,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":2,"endColumn":17548,"suggestions":[{"messageId":"removeEscape","fix":{"range":[17567,17568],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[17567,17567],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/coverage/sorter.js","messages":[],"suppressedMessages":[{"ruleId":"no-unused-vars","severity":1,"message":"'error' is defined but never used.","line":36,"column":18,"nodeType":"Identifier","messageId":"unusedVar","endLine":36,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/eslint.config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/postcss.config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/App.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'Suspense' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":16,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":24,"suggestions":[{"messageId":"removeVar","data":{"varName":"Suspense"},"fix":{"range":[13,23],"text":""},"desc":"Remove unused variable 'Suspense'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Router' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":27,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":33,"suggestions":[{"messageId":"removeVar","data":{"varName":"Router"},"fix":{"range":[49,73],"text":""},"desc":"Remove unused variable 'Router'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Routes' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":35,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":41,"suggestions":[{"messageId":"removeVar","data":{"varName":"Routes"},"fix":{"range":[72,80],"text":""},"desc":"Remove unused variable 'Routes'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Route' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":43,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":48,"suggestions":[{"messageId":"removeVar","data":{"varName":"Route"},"fix":{"range":[80,87],"text":""},"desc":"Remove unused variable 'Route'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'HomePage' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":16,"suggestions":[{"messageId":"removeVar","data":{"varName":"HomePage"},"fix":{"range":[142,156],"text":""},"desc":"Remove unused variable 'HomePage'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'LabPython' is defined but never used. Allowed unused vars must match /^_/u.","line":5,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":17,"suggestions":[{"messageId":"removeVar","data":{"varName":"LabPython"},"fix":{"range":[192,207],"text":""},"desc":"Remove unused variable 'LabPython'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Playground' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":7,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":7,"endColumn":17,"suggestions":[{"messageId":"removeVar","data":{"varName":"Playground"},"fix":{"range":[239,310],"text":""},"desc":"Remove unused variable 'Playground'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'About' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":8,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":8,"endColumn":12,"suggestions":[{"messageId":"removeVar","data":{"varName":"About"},"fix":{"range":[311,367],"text":""},"desc":"Remove unused variable 'About'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Faq' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":9,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":10,"suggestions":[{"messageId":"removeVar","data":{"varName":"Faq"},"fix":{"range":[368,418],"text":""},"desc":"Remove unused variable 'Faq'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Atividades' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":10,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":10,"endColumn":17,"suggestions":[{"messageId":"removeVar","data":{"varName":"Atividades"},"fix":{"range":[419,490],"text":""},"desc":"Remove unused variable 'Atividades'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Educadores' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":11,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":11,"endColumn":17,"suggestions":[{"messageId":"removeVar","data":{"varName":"Educadores"},"fix":{"range":[491,562],"text":""},"desc":"Remove unused variable 'Educadores'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'AutomatoGame' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":14,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":14,"endColumn":19,"suggestions":[{"messageId":"removeVar","data":{"varName":"AutomatoGame"},"fix":{"range":[577,650],"text":""},"desc":"Remove unused variable 'AutomatoGame'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'SemaforoGame' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":15,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":15,"endColumn":19,"suggestions":[{"messageId":"removeVar","data":{"varName":"SemaforoGame"},"fix":{"range":[651,724],"text":""},"desc":"Remove unused variable 'SemaforoGame'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'MoleMashGame' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":16,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":16,"endColumn":19,"suggestions":[{"messageId":"removeVar","data":{"varName":"MoleMashGame"},"fix":{"range":[725,795],"text":""},"desc":"Remove unused variable 'MoleMashGame'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'TurtleGame' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":17,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":17,"endColumn":17,"suggestions":[{"messageId":"removeVar","data":{"varName":"TurtleGame"},"fix":{"range":[796,863],"text":""},"desc":"Remove unused variable 'TurtleGame'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'CriptoGame' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":18,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":18,"endColumn":17,"suggestions":[{"messageId":"removeVar","data":{"varName":"CriptoGame"},"fix":{"range":[864,931],"text":""},"desc":"Remove unused variable 'CriptoGame'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'LoadingFallback' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":20,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":20,"endColumn":22,"suggestions":[{"messageId":"removeVar","data":{"varName":"LoadingFallback"},"fix":{"range":[933,1639],"text":""},"desc":"Remove unused variable 'LoadingFallback'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":17,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { lazy, Suspense } from \"react\";\nimport { BrowserRouter as Router, Routes, Route } from \"react-router-dom\";\nimport \"./App.css\";\nimport HomePage from \"./pages/HomePage/HomePage\";\nimport LabPython from \"./pages/LabPython/LabPython\";\n\nconst Playground = lazy(() => import(\"./pages/Playground/Playground\"));\nconst About = lazy(() => import(\"./pages/About/About\"));\nconst Faq = lazy(() => import(\"./pages/Faq/Faq\"));\nconst Atividades = lazy(() => import(\"./pages/Atividades/Atividades\"));\nconst Educadores = lazy(() => import(\"./pages/Educadores/Educadores\"));\n\n//Atividades\nconst AutomatoGame = lazy(() => import(\"./games/automato/AutomatoGame\"));\nconst SemaforoGame = lazy(() => import(\"./games/semaforo/SemaforoGame\"));\nconst MoleMashGame = lazy(() => import(\"./games/mole-mash/MoleMash\"));\nconst TurtleGame = lazy(() => import(\"./games/turtle/TurtleGame\"));\nconst CriptoGame = lazy(() => import(\"./games/cripto/CriptoGame\"));\n\nconst LoadingFallback = () => (\n \n
\n
\n Carregando...\n \n \n);\n\nexport default function App() {\n return (\n \n }>\n \n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n } />\n \n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/Navbar.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'Link' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":14,"suggestions":[{"messageId":"removeVar","data":{"varName":"Link"},"fix":{"range":[0,40],"text":""},"desc":"Remove unused variable 'Link'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Menu' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":14,"suggestions":[{"messageId":"removeVar","data":{"varName":"Menu"},"fix":{"range":[50,55],"text":""},"desc":"Remove unused variable 'Menu'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'X' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":16,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":17,"suggestions":[{"messageId":"removeVar","data":{"varName":"X"},"fix":{"range":[54,57],"text":""},"desc":"Remove unused variable 'X'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ChevronDown' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":19,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":30,"suggestions":[{"messageId":"removeVar","data":{"varName":"ChevronDown"},"fix":{"range":[57,70],"text":""},"desc":"Remove unused variable 'ChevronDown'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'scrolled' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":8,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":8,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"scrolled"},"fix":{"range":[273,281],"text":""},"desc":"Remove unused variable 'scrolled'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'openDropdown' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":9,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":22,"suggestions":[{"messageId":"removeVar","data":{"varName":"openDropdown"},"fix":{"range":[324,336],"text":""},"desc":"Remove unused variable 'openDropdown'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'handleMouseEnter' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":23,"column":9,"nodeType":"Identifier","messageId":"unusedVar","endLine":23,"endColumn":25,"suggestions":[{"messageId":"removeVar","data":{"varName":"handleMouseEnter"},"fix":{"range":[731,900],"text":""},"desc":"Remove unused variable 'handleMouseEnter'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'handleMouseLeave' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":31,"column":9,"nodeType":"Identifier","messageId":"unusedVar","endLine":31,"endColumn":25,"suggestions":[{"messageId":"removeVar","data":{"varName":"handleMouseLeave"},"fix":{"range":[904,1052],"text":""},"desc":"Remove unused variable 'handleMouseLeave'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":8,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Link } from \"react-router-dom\";\nimport { Menu, X, ChevronDown } from \"lucide-react\";\nimport { useState, useEffect } from \"react\";\nimport logo from \"../assets/logo_decoda.svg\";\n\nconst Navbar = () => {\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n const [scrolled, setScrolled] = useState(false);\n const [openDropdown, setOpenDropdown] = useState(null);\n const [closeTimeout, setCloseTimeout] = useState(null);\n\n useEffect(() => {\n const handleScroll = () => {\n setScrolled(window.scrollY > 50);\n };\n\n window.addEventListener(\"scroll\", handleScroll, { passive: true });\n handleScroll(); // Check initial state\n\n return () => window.removeEventListener(\"scroll\", handleScroll);\n }, []);\n\n const handleMouseEnter = (dropdown) => {\n if (closeTimeout) {\n clearTimeout(closeTimeout);\n setCloseTimeout(null);\n }\n setOpenDropdown(dropdown);\n };\n\n const handleMouseLeave = () => {\n const timeout = setTimeout(() => {\n setOpenDropdown(null);\n }, 150);\n setCloseTimeout(timeout);\n };\n\n return (\n \n
\n {/* Logo - Esquerda */}\n
\n \n \n \n
\n\n {/* Espaço Central vazio para empurrar o menu para a direita */}\n
\n\n {/* Menu Desktop - Direita */}\n
\n
\n {/* Links diretos - Atividades */}\n \n Atividades\n \n\n {/* Links diretos - Laboratório de Blocos */}\n \n Laboratório de Blocos\n \n\n {/* Links diretos - Laboratório Pytohn */}\n \n Laboratório Python\n \n\n \n Quem somos\n \n\n \n Perguntas frequentes\n \n\n \n Para educadores\n \n
\n\n {/* Botão Mobile Menu */}\n setIsMenuOpen(!isMenuOpen)}\n className=\"md:hidden p-2 rounded-lg hover:bg-white/10 transition-colors\"\n aria-label=\"Toggle menu\"\n >\n {isMenuOpen ? (\n \n ) : (\n \n )}\n \n
\n
\n\n {/* Menu Mobile */}\n {isMenuOpen && (\n
\n
\n {/* Links diretos Mobile */}\n setIsMenuOpen(false)}\n >\n Atividades\n \n setIsMenuOpen(false)}\n >\n Laboratório\n \n setIsMenuOpen(false)}\n >\n Quem somos\n \n setIsMenuOpen(false)}\n >\n Perguntas frequentes\n \n setIsMenuOpen(false)}\n >\n Para educadores\n \n
\n
\n )}\n \n );\n};\n\nexport default Navbar;\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/ConfettiOverlay.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,13],"text":""},"desc":"Remove unused variable 'React'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useEffect, useRef } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { confetti } from \"@tsparticles/confetti\";\n\nconst ConfettiOverlay = ({ isActive, onComplete }) => {\n const canvasRef = useRef(null);\n const animationRef = useRef(null);\n\n useEffect(() => {\n if (isActive && canvasRef.current) {\n const canvas = canvasRef.current;\n\n const randomInRange = (min, max) => {\n return Math.random() * (max - min) + min;\n };\n\n const triggerConfettiBlast = async () => {\n const defaultOptions = {\n angle: randomInRange(55, 125),\n spread: randomInRange(50, 70),\n particleCount: randomInRange(50, 100),\n origin: { y: 0.6 },\n canvas: canvas,\n };\n\n await confetti(defaultOptions);\n };\n\n triggerConfettiBlast();\n\n animationRef.current = setTimeout(() => {\n if (onComplete) {\n onComplete();\n }\n }, 500);\n } else if (!isActive && canvasRef.current) {\n const canvas = canvasRef.current;\n const ctx = canvas.getContext(\"2d\");\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n\n return () => {\n if (animationRef.current) {\n clearTimeout(animationRef.current);\n }\n };\n }, [isActive, onComplete]);\n\n useEffect(() => {\n const updateCanvasSize = () => {\n if (canvasRef.current) {\n canvasRef.current.width = window.innerWidth;\n canvasRef.current.height = window.innerHeight;\n }\n };\n\n updateCanvasSize();\n window.addEventListener(\"resize\", updateCanvasSize);\n return () => window.removeEventListener(\"resize\", updateCanvasSize);\n }, []);\n\n return (\n \n );\n};\n\nConfettiOverlay.propTypes = {\n isActive: PropTypes.bool.isRequired,\n onComplete: PropTypes.func,\n};\n\nexport default ConfettiOverlay;\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/ConfirmacaoModal.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'X' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":11,"suggestions":[{"messageId":"removeVar","data":{"varName":"X"},"fix":{"range":[40,73],"text":""},"desc":"Remove unused variable 'X'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"// components/game/ConfirmacaoModal.jsx\nimport { X } from \"lucide-react\";\n\nexport default function ConfirmacaoModal({\n isVisible,\n onClose,\n onConfirm,\n titulo,\n mensagem,\n}) {\n if (!isVisible) return null;\n\n return (\n \n e.stopPropagation()}\n >\n {/* Header */}\n
\n

{titulo}

\n \n \n \n
\n\n {/* Mensagem */}\n

{mensagem}

\n\n {/* Ações */}\n
\n \n Cancelar\n \n {\n onConfirm();\n onClose();\n }}\n >\n Confirmar\n \n
\n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/FalhaModal.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,18],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'RefreshCw' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":19,"suggestions":[{"messageId":"removeVar","data":{"varName":"RefreshCw"},"fix":{"range":[63,104],"text":""},"desc":"Remove unused variable 'RefreshCw'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ModalBase' is defined but never used. Allowed unused vars must match /^_/u.","line":5,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":19,"suggestions":[{"messageId":"removeVar","data":{"varName":"ModalBase"},"fix":{"range":[106,152],"text":""},"desc":"Remove unused variable 'ModalBase'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ModalHeader' is defined but never used. Allowed unused vars must match /^_/u.","line":6,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":6,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"ModalHeader"},"fix":{"range":[153,203],"text":""},"desc":"Remove unused variable 'ModalHeader'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'CodeArea' is defined but never used. Allowed unused vars must match /^_/u.","line":7,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":7,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"CodeArea"},"fix":{"range":[204,248],"text":""},"desc":"Remove unused variable 'CodeArea'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'FeedbackBox' is defined but never used. Allowed unused vars must match /^_/u.","line":8,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":8,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"FeedbackBox"},"fix":{"range":[249,299],"text":""},"desc":"Remove unused variable 'FeedbackBox'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport { RefreshCw } from \"lucide-react\";\n\nimport { ModalBase } from \"./modal/ModalBase\";\nimport { ModalHeader } from \"./modal/ModalHeader\";\nimport { CodeArea } from \"./modal/CodeArea\";\nimport { FeedbackBox } from \"./modal/FeedbackBox\";\n\nconst FalhaModal = ({\n isOpen,\n onClose,\n onRetry,\n mensagemCustomizada,\n currentPhase,\n codigoGerado,\n}) => {\n const handleRetry = () => {\n onClose();\n if (onRetry) {\n onRetry();\n }\n };\n\n const mensagemExibida =\n mensagemCustomizada ||\n \"Ops! Parece que algo não funcionou como esperado. Tente novamente!\";\n\n return (\n \n \n\n
\n
\n
\n

{mensagemExibida}

\n
\n\n \n\n \n
    \n
  • Revise o enunciado.
  • \n
  • Verifique se os blocos estão corretamente conectados.
  • \n
  • \n Certifique-se de que a lógica atende a todos os requisitos da\n fase.\n
  • \n
\n
\n
\n
\n\n {/* 3. Rodapé (Botões de Ação) */}\n
\n \n Fechar\n \n\n \n \n Tentar Novamente\n \n
\n
\n );\n};\n\nFalhaModal.propTypes = {\n isOpen: PropTypes.bool.isRequired,\n onClose: PropTypes.func.isRequired,\n onRetry: PropTypes.func,\n mensagemCustomizada: PropTypes.string,\n currentPhase: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n codigoGerado: PropTypes.string,\n};\n\nexport default FalhaModal;\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/GameArea.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'ConfettiOverlay' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":23,"suggestions":[{"messageId":"removeVar","data":{"varName":"ConfettiOverlay"},"fix":{"range":[192,213],"text":""},"desc":"Remove unused variable 'ConfettiOverlay'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useEffect, useState, useRef } from \"react\";\nimport { useGameState, GAME_STATES } from \"../../contexts/GameStateContext\";\nimport { gameEventBus } from \"../../utils/gameEvents\";\nimport ConfettiOverlay from \"./ConfettiOverlay\";\n\nexport default function GameArea({\n children,\n blocosRestantes = null,\n faseId = null,\n}) {\n const {\n executionState,\n generatedCode,\n finalizeWithSuccess,\n finalizeWithFailure,\n } = useGameState();\n\n const [showConfetti, setShowConfetti] = useState(false);\n const [isTransitioning, setIsTransitioning] = useState(false);\n const previousFaseId = useRef(faseId);\n\n useEffect(() => {\n if (faseId !== null && faseId !== previousFaseId.current) {\n setIsTransitioning(true);\n\n const timer = setTimeout(() => {\n setIsTransitioning(false);\n previousFaseId.current = faseId;\n }, 600);\n\n return () => clearTimeout(timer);\n }\n }, [faseId]);\n\n useEffect(() => {\n const handleGameSuccess = () => {\n finalizeWithSuccess();\n setShowConfetti(true);\n };\n\n const handleGameFailure = () => {\n finalizeWithFailure();\n };\n\n gameEventBus.addEventListener(\"gameSuccess\", handleGameSuccess);\n gameEventBus.addEventListener(\"gameFailure\", handleGameFailure);\n\n return () => {\n gameEventBus.removeEventListener(\"gameSuccess\", handleGameSuccess);\n gameEventBus.removeEventListener(\"gameFailure\", handleGameFailure);\n };\n }, [finalizeWithSuccess, finalizeWithFailure]);\n\n useEffect(() => {\n switch (executionState) {\n case GAME_STATES.EXECUTANDO:\n if (generatedCode) {\n const codigo =\n typeof generatedCode === \"string\"\n ? generatedCode\n : generatedCode.codigo;\n const ws =\n typeof generatedCode === \"object\" ? generatedCode.workspace : null;\n\n gameEventBus.executeCode(codigo, ws);\n }\n break;\n case GAME_STATES.PARADO:\n gameEventBus.resetGame();\n setShowConfetti(false);\n break;\n }\n }, [executionState, generatedCode]);\n\n return (\n \n {/* Confetti de sucesso de uma fase */}\n \n\n {/* Overlay de transição */}\n \n
\n
\n\n {/* Indicador de blocos restantes */}\n {blocosRestantes !== null && !isNaN(blocosRestantes) && (\n
\n
\n Blocos restantes:{\" \"}\n {blocosRestantes}\n
\n
\n )}\n\n \n {children}\n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/GameBase.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'Panel' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":15,"suggestions":[{"messageId":"removeVar","data":{"varName":"Panel"},"fix":{"range":[111,117],"text":""},"desc":"Remove unused variable 'Panel'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'PanelGroup' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":17,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":27,"suggestions":[{"messageId":"removeVar","data":{"varName":"PanelGroup"},"fix":{"range":[116,128],"text":""},"desc":"Remove unused variable 'PanelGroup'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameNavBar' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameNavBar"},"fix":{"range":[169,185],"text":""},"desc":"Remove unused variable 'GameNavBar'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameFaseInfo' is defined but never used. Allowed unused vars must match /^_/u.","line":5,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameFaseInfo"},"fix":{"range":[208,226],"text":""},"desc":"Remove unused variable 'GameFaseInfo'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameArea' is defined but never used. Allowed unused vars must match /^_/u.","line":6,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":6,"endColumn":16,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameArea"},"fix":{"range":[251,265],"text":""},"desc":"Remove unused variable 'GameArea'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameFooter' is defined but never used. Allowed unused vars must match /^_/u.","line":7,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":7,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameFooter"},"fix":{"range":[286,302],"text":""},"desc":"Remove unused variable 'GameFooter'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'SeletorDeFases' is defined but never used. Allowed unused vars must match /^_/u.","line":8,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":8,"endColumn":22,"suggestions":[{"messageId":"removeVar","data":{"varName":"SeletorDeFases"},"fix":{"range":[325,345],"text":""},"desc":"Remove unused variable 'SeletorDeFases'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'SucessoModal' is defined but never used. Allowed unused vars must match /^_/u.","line":9,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"SucessoModal"},"fix":{"range":[372,390],"text":""},"desc":"Remove unused variable 'SucessoModal'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'FalhaModal' is defined but never used. Allowed unused vars must match /^_/u.","line":10,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":10,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"FalhaModal"},"fix":{"range":[415,431],"text":""},"desc":"Remove unused variable 'FalhaModal'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ResizeHandle' is defined but never used. Allowed unused vars must match /^_/u.","line":11,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":11,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"ResizeHandle"},"fix":{"range":[454,472],"text":""},"desc":"Remove unused variable 'ResizeHandle'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'EditorProvider' is defined but never used. Allowed unused vars must match /^_/u.","line":14,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":14,"endColumn":24,"suggestions":[{"messageId":"removeVar","data":{"varName":"EditorProvider"},"fix":{"range":[622,684],"text":""},"desc":"Remove unused variable 'EditorProvider'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameBaseContent' is defined but never used. Allowed unused vars must match /^_/u.","line":16,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":16,"endColumn":25,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameBaseContent"},"fix":{"range":[686,7736],"text":""},"desc":"Remove unused variable 'GameBaseContent'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'title' is defined but never used. Allowed unused args must match /^_/u.","line":271,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":271,"endColumn":8,"suggestions":[{"messageId":"removeVar","data":{"varName":"title"},"fix":{"range":[7800,7809],"text":""},"desc":"Remove unused variable 'title'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":13,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useEffect, useRef, useCallback, useState } from \"react\";\nimport Phaser from \"phaser\";\nimport { Panel, PanelGroup } from \"react-resizable-panels\";\nimport GameNavBar from \"./GameNavBar\";\nimport GameFaseInfo from \"./GameFaseInfo\";\nimport GameArea from \"./GameArea\";\nimport GameFooter from \"./GameFooter\";\nimport SeletorDeFases from \"./SeletorDeFases\";\nimport SucessoModal from \"./SucessoModal\";\nimport FalhaModal from \"./FalhaModal\";\nimport ResizeHandle from \"./ResizeHandle\";\nimport { useIsMobile } from \"../../hooks/useIsMobile\";\nimport { useGameState, GAME_STATES } from \"../../contexts/GameStateContext\";\nimport { EditorProvider } from \"../../contexts/EditorContext\";\n\nfunction GameBaseContent({\n gameFactory,\n gameConfig,\n children,\n onHelpClick,\n customFailureHandler,\n}) {\n const gameContainerRef = useRef(null);\n const gameInstanceRef = useRef(null);\n const isInitializingRef = useRef(false);\n const isMobile = useIsMobile();\n const [modalFasesAberto, setModalFasesAberto] = useState(false);\n const [modalSucessoAberto, setModalSucessoAberto] = useState(false);\n const [modalFalhaAberto, setModalFalhaAberto] = useState(false);\n const [blocosRestantesCount, setBlocosRestantesCount] = useState(null);\n\n const {\n currentPhase,\n setCurrentPhase,\n resetProgress,\n executionState,\n generatedCode,\n failureMessage,\n restart,\n setOnWorkspaceChange,\n } = useGameState();\n\n const phaseConfig = gameConfig.fases[currentPhase - 1];\n const usaModalFalha = !!customFailureHandler;\n\n useEffect(() => {\n if (gameInstanceRef.current && gameContainerRef.current) {\n const phaserScale = gameInstanceRef.current.scale;\n phaserScale.resize(\n gameContainerRef.current.clientWidth,\n gameContainerRef.current.clientHeight,\n );\n }\n }, [isMobile]);\n\n useEffect(() => {\n if (isInitializingRef.current) {\n return;\n }\n\n isInitializingRef.current = true;\n\n if (gameInstanceRef.current) {\n try {\n gameInstanceRef.current.destroy(true);\n } catch (error) {\n console.warn(\"Erro ao destruir Phaser:\", error);\n }\n gameInstanceRef.current = null;\n }\n\n // Aguardar um frame para garantir que o cleanup foi concluído\n const timeoutId = setTimeout(() => {\n try {\n if (!gameContainerRef.current) {\n console.warn(\"Container do jogo não disponível\");\n isInitializingRef.current = false;\n return;\n }\n\n const config = gameFactory(\n gameContainerRef.current,\n phaseConfig,\n customFailureHandler,\n currentPhase,\n gameConfig,\n );\n gameInstanceRef.current = new Phaser.Game(config);\n } catch (error) {\n console.error(\"Erro ao inicializar Phaser:\", error);\n } finally {\n isInitializingRef.current = false;\n }\n }, 10); // Pequeno delay para garantir cleanup\n\n return () => {\n clearTimeout(timeoutId);\n\n if (gameInstanceRef.current) {\n try {\n gameInstanceRef.current.destroy(true);\n } catch (error) {\n console.warn(\"Erro durante cleanup do Phaser:\", error);\n }\n gameInstanceRef.current = null;\n }\n\n isInitializingRef.current = false;\n };\n }, [gameFactory, currentPhase, customFailureHandler]);\n\n const handleWorkspaceChange = useCallback(\n (blockCount) => {\n if (phaseConfig.maxBlocks === Infinity) {\n setBlocosRestantesCount(null);\n return;\n }\n const blocosUsados = typeof blockCount === \"number\" ? blockCount : 0;\n const blocosRestantes = phaseConfig.maxBlocks - blocosUsados;\n setBlocosRestantesCount(blocosRestantes);\n },\n [phaseConfig.maxBlocks],\n );\n\n useEffect(() => {\n if (setOnWorkspaceChange) {\n setOnWorkspaceChange(() => handleWorkspaceChange);\n }\n return () => {\n if (setOnWorkspaceChange) {\n setOnWorkspaceChange(null);\n }\n };\n }, [setOnWorkspaceChange, handleWorkspaceChange]);\n\n const handleResetProgresso = () => {\n resetProgress();\n\n window.dispatchEvent(\n new CustomEvent(\"resetBlocklyWorkspace\", {\n detail: { gameId: gameConfig.gameId },\n }),\n );\n };\n\n useEffect(() => {\n if (executionState === GAME_STATES.SUCESSO) {\n setModalSucessoAberto(true);\n }\n\n if (executionState === GAME_STATES.FALHA && usaModalFalha) {\n setModalFalhaAberto(true);\n }\n }, [executionState, usaModalFalha]);\n\n const handleProximaFase = () => {\n const proximaFase = currentPhase + 1;\n if (proximaFase <= gameConfig.fases.length) {\n setCurrentPhase(proximaFase);\n }\n\n setModalSucessoAberto(false);\n restart();\n };\n\n const handleFecharModalSucesso = () => {\n setModalSucessoAberto(false);\n };\n\n const handleFecharModalFalha = () => {\n setModalFalhaAberto(false);\n };\n\n const handleTentarNovamente = () => {\n setModalFalhaAberto(false);\n restart();\n };\n\n const codigoParaExibir = React.useMemo(() => {\n if (!generatedCode) return \"Nenhum código gerado\";\n\n let codigo = \"\";\n\n if (typeof generatedCode === \"string\") {\n codigo = generatedCode;\n } else if (typeof generatedCode === \"object\" && generatedCode.codigo) {\n codigo = generatedCode.codigo;\n } else {\n return \"Código não disponível\";\n }\n\n const codigoLimpo = codigo\n .split(\"\\n\")\n .filter((linha) => !linha.trim().startsWith(\"highlightBlock(\"))\n .join(\"\\n\")\n .trim();\n\n return codigoLimpo || codigo;\n }, [generatedCode]);\n\n return (\n
\n \n \n
\n \n \n \n {children}\n \n \n \n \n \n
\n \n \n \n
\n\n setModalFasesAberto(true)}\n onHelpClick={onHelpClick}\n />\n\n setModalFasesAberto(false)}\n faseAtual={currentPhase}\n gameConfig={gameConfig}\n onMudarFase={(fase) => {\n setCurrentPhase(fase);\n setModalFasesAberto(false);\n }}\n onResetProgresso={handleResetProgresso}\n />\n\n \n\n \n
\n );\n}\n\nexport default function GameBase({\n gameFactory,\n gameConfig,\n title,\n children,\n onHelpClick,\n customFailureHandler,\n}) {\n return (\n \n {children}\n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/GameEditor.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'Play' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":14,"suggestions":[{"messageId":"removeVar","data":{"varName":"Play"},"fix":{"range":[9,14],"text":""},"desc":"Remove unused variable 'Play'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Loader' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":16,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":22,"suggestions":[{"messageId":"removeVar","data":{"varName":"Loader"},"fix":{"range":[13,21],"text":""},"desc":"Remove unused variable 'Loader'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'RotateCcw' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":24,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":33,"suggestions":[{"messageId":"removeVar","data":{"varName":"RotateCcw"},"fix":{"range":[21,32],"text":""},"desc":"Remove unused variable 'RotateCcw'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'CircleAlert' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":35,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":46,"suggestions":[{"messageId":"removeVar","data":{"varName":"CircleAlert"},"fix":{"range":[32,45],"text":""},"desc":"Remove unused variable 'CircleAlert'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { Play, Loader, RotateCcw, CircleAlert } from \"lucide-react\";\nimport { useGameState, GAME_STATES } from \"../../contexts/GameStateContext\";\n\nexport default function GameEditor({\n children,\n textoExecutar = \"Executar\",\n textoReiniciar = \"Reiniciar\",\n}) {\n const {\n executionState,\n execute,\n restart,\n stop,\n currentBlockCount,\n editorType,\n } = useGameState();\n\n const isExecuting = executionState === GAME_STATES.EXECUTANDO;\n const needsRestart =\n executionState === GAME_STATES.SUCESSO ||\n executionState === GAME_STATES.FALHA;\n const noBlocks = currentBlockCount === 0;\n\n const handleClick = () => {\n if (noBlocks && !isExecuting && !needsRestart) {\n return; // Não faz nada se não há blocos\n }\n\n if (isExecuting) {\n stop();\n return;\n }\n\n if (needsRestart) {\n restart();\n } else {\n execute();\n }\n };\n\n const setStyle = () => {\n const style =\n \"game-controls-custom flex items-center space-x-2 px-6 py-3 rounded-full font-medium transition-all duration-200 shadow-md\";\n\n if (noBlocks) {\n return `${style} bg-gradient-to-r from-yellow-700 to-yellow-500 cursor-not-allowed text-white`;\n }\n\n if (isExecuting) {\n return `${style} bg-gradient-to-r from-blue-500 to-green-600 hover:from-blue-600 hover:to-green-700 text-white`;\n }\n\n if (needsRestart) {\n return `${style} bg-gradient-to-r from-orange-500 to-red-600 hover:from-orange-600 hover:to-red-700 text-white`;\n }\n\n return `${style} bg-gradient-to-r from-red-500 via-pink-500 to-purple-600 hover:from-red-600 hover:via-pink-600 hover:to-purple-700 text-white`;\n };\n\n const getEmptyStateText = () => {\n return editorType === \"code\"\n ? \"Adicione código para executar\"\n : \"Adicione blocos para executar\";\n };\n\n return (\n
\n
{children}
\n
\n \n {isExecuting ? (\n <>\n \n Executando, clique para interromper...\n \n ) : needsRestart ? (\n <>\n \n {textoReiniciar}\n \n ) : noBlocks ? (\n <>\n \n {getEmptyStateText()}\n \n ) : (\n <>\n \n {textoExecutar}\n \n )}\n \n
\n
\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/GameFaseInfo.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,18],"text":""},"desc":"Remove unused variable 'React'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from \"react\";\n\nfunction obterDificuldade(dadosFase) {\n // Usa a dificuldade da fase, se existir, senão calcula pelo número\n if (dadosFase?.dificuldade) {\n switch (dadosFase.dificuldade) {\n case \"Fácil\":\n return { nivel: \"Fácil\", cor: \"bg-green-500\", emoji: \"😊\" };\n case \"Médio\":\n return { nivel: \"Médio\", cor: \"bg-yellow-500\", emoji: \"🤔\" };\n case \"Difícil\":\n return { nivel: \"Difícil\", cor: \"bg-orange-500\", emoji: \"😤\" };\n case \"Extremo\":\n return { nivel: \"Extremo\", cor: \"bg-red-500\", emoji: \"🔥\" };\n default:\n return null;\n }\n }\n return null;\n}\n\nfunction GameFaseInfo({ dadosFase = {}, numeroFase }) {\n const dificuldade = obterDificuldade(dadosFase);\n\n return (\n
\n {dadosFase && dadosFase.nome ? (\n
\n {/* Número da fase */}\n
\n {numeroFase}\n
\n {/* Título/Subtítulo */}\n
\n

\n {dadosFase.nome}\n

\n {dadosFase.descricao && (\n

\n {dadosFase.descricao}\n

\n )}\n
\n {/* Dificuldade */}\n
\n {dificuldade && (\n \n {dificuldade.emoji}\n {dificuldade.nivel}\n
\n )}\n
\n
\n ) : (\n
\n
\n ?\n
\n
\n

\n Selecione uma fase para começar\n

\n
\n
\n
\n )}\n
\n );\n}\n\nexport default GameFaseInfo;\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/GameFooter.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,18],"text":""},"desc":"Remove unused variable 'React'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from \"react\";\n\nexport default function GameFooter({\n gameConfig,\n faseAtual,\n onAbrirSeletor,\n onHelpClick,\n}) {\n const totalFases = gameConfig.fases.length;\n\n const ajuda = () => {\n if (onHelpClick) {\n onHelpClick();\n } else {\n alert(\"Recurso de ajuda será implementado em breve!\");\n }\n };\n\n return (\n
\n
\n {/* Lado esquerdo - Botão de Ajuda */}\n
\n \n Ajuda\n \n
\n {/* Centro - Indicador de Fase Atual/Total */}\n
\n
\n \n {faseAtual}\n /\n {totalFases}\n \n
\n
\n {/* Lado direito - Botão do Seletor de Fases */}\n
\n \n Fases\n \n
\n
\n
\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/GameNavBar.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'Code' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":14,"suggestions":[{"messageId":"removeVar","data":{"varName":"Code"},"fix":{"range":[140,145],"text":""},"desc":"Remove unused variable 'Code'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Puzzle' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":16,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":22,"suggestions":[{"messageId":"removeVar","data":{"varName":"Puzzle"},"fix":{"range":[144,152],"text":""},"desc":"Remove unused variable 'Puzzle'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ArrowLeft' is defined but never used. Allowed unused vars must match /^_/u.","line":5,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":19,"suggestions":[{"messageId":"removeVar","data":{"varName":"ArrowLeft"},"fix":{"range":[176,217],"text":""},"desc":"Remove unused variable 'ArrowLeft'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { useState } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport logo from \"../../assets/logo_decoda.svg\";\nimport { Code, Puzzle } from \"lucide-react\";\nimport { ArrowLeft } from \"lucide-react\";\n\nexport default function GameNavBar({ title, type = \"blocks\" }) {\n const navigate = useNavigate();\n const [menuOpen, setMenuOpen] = useState(false);\n\n const renderIcon = (size = \"w-6 h-6 lg:w-8 lg:h-8\") => {\n if (type === \"code\") {\n return ;\n } else {\n return ;\n }\n };\n\n return (\n <>\n {/* Navbar normal - oculto em telas pequenas */}\n \n\n {/* Botão menu flutuante - só aparece em telas pequenas */}\n setMenuOpen(true)}\n >\n \n \n \n \n \n \n\n {/* Overlay do menu mobile */}\n {menuOpen && (\n
\n
\n
\n
\n setMenuOpen(false)}\n className=\"text-brand-500 text-3xl\"\n aria-label=\"Fechar menu\"\n >\n ×\n \n
\n
\n {type === \"code\" && }\n {type === \"blocks\" && (\n \n )}\n
{title}
\n
\n {\n setMenuOpen(false);\n navigate(\"/\");\n }}\n className=\"flex items-center gap-5 mt-10\"\n >\n \n Voltar\n \n
\n {\n setMenuOpen(false);\n navigate(\"/\");\n }}\n >\n {\n e.target.style.display = \"none\";\n e.target.nextSibling.style.display = \"inline\";\n }}\n />\n \n
\n
\n )}\n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/OptionsEditor.jsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/ResizeHandle.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'PanelResizeHandle' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":27,"suggestions":[{"messageId":"removeVar","data":{"varName":"PanelResizeHandle"},"fix":{"range":[0,59],"text":""},"desc":"Remove unused variable 'PanelResizeHandle'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { PanelResizeHandle } from \"react-resizable-panels\";\n\nexport default function ResizeHandle({\n direction = \"horizontal\",\n theme = \"light\",\n disabled = false,\n}) {\n const isHorizontal = direction === \"horizontal\";\n const isDark = theme === \"dark\";\n\n return (\n \n \n \n \n \n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/SeletorDeFases.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,13],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ConfirmacaoModal' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":24,"suggestions":[{"messageId":"removeVar","data":{"varName":"ConfirmacaoModal"},"fix":{"range":[59,81],"text":""},"desc":"Remove unused variable 'ConfirmacaoModal'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Lock' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":14,"suggestions":[{"messageId":"removeVar","data":{"varName":"Lock"},"fix":{"range":[112,117],"text":""},"desc":"Remove unused variable 'Lock'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'CheckCircle' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":16,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":27,"suggestions":[{"messageId":"removeVar","data":{"varName":"CheckCircle"},"fix":{"range":[116,129],"text":""},"desc":"Remove unused variable 'CheckCircle'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Star' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":29,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":33,"suggestions":[{"messageId":"removeVar","data":{"varName":"Star"},"fix":{"range":[129,135],"text":""},"desc":"Remove unused variable 'Star'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'X' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":35,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":36,"suggestions":[{"messageId":"removeVar","data":{"varName":"X"},"fix":{"range":[135,138],"text":""},"desc":"Remove unused variable 'X'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useEffect, useState } from \"react\";\nimport ConfirmacaoModal from \"./ConfirmacaoModal\";\nimport { Lock, CheckCircle, Star, X } from \"lucide-react\";\n\nexport default function SeletorDeFases({\n isVisible,\n onClose,\n gameConfig,\n faseAtual,\n onMudarFase,\n onResetProgresso,\n}) {\n const gameId = gameConfig.gameId;\n const totalFases = gameConfig.fases.length;\n const storageKey = `${gameId}-fases-concluidas`;\n const [fasesCompletadas, setFasesCompletadas] = useState([]);\n const [mostrarConfirmacaoReset, setMostrarConfirmacaoReset] = useState(false);\n\n useEffect(() => {\n if (!isVisible) return;\n const salvo = localStorage.getItem(storageKey);\n if (salvo) {\n try {\n const fases = JSON.parse(salvo);\n setFasesCompletadas(fases);\n } catch {\n setFasesCompletadas([]);\n }\n } else {\n setFasesCompletadas([]);\n }\n }, [isVisible, storageKey]);\n\n const fasesLiberadas = (() => {\n if (fasesCompletadas.length === 0) return [1];\n const maxCompleta = Math.max(...fasesCompletadas);\n return Array.from(\n { length: Math.min(maxCompleta + 1, totalFases) },\n (_, i) => i + 1,\n );\n })();\n\n const selecionarFase = (numero) => {\n if (!fasesLiberadas.includes(numero)) return;\n onMudarFase(numero);\n onClose();\n };\n\n if (!isVisible) return null;\n\n return (\n \n e.stopPropagation()}\n >\n
\n
\n
\n \n
\n

\n Selecionar Fase - {gameConfig.gameName || \"Jogo\"}\n

\n
\n \n \n \n
\n\n
\n
\n {Array.from({ length: totalFases }, (_, i) => {\n const numeroFase = i + 1;\n const estaLiberada = fasesLiberadas.includes(numeroFase);\n const foiCompletada = fasesCompletadas.includes(numeroFase);\n const ehAtual = faseAtual === numeroFase;\n const dadosFase = gameConfig.fases[i];\n\n return (\n estaLiberada && selecionarFase(numeroFase)}\n >\n
\n
\n \n {foiCompletada ? (\n \n ) : !estaLiberada ? (\n \n ) : (\n numeroFase\n )}\n
\n
\n {ehAtual && (\n \n Atual\n \n )}\n
\n\n
\n

\n Fase {numeroFase}\n

\n
\n {dadosFase.nome}\n
\n

\n {dadosFase.descricao}\n

\n \n {dadosFase.dificuldade}\n \n
\n
\n );\n })}\n \n \n\n
\n setMostrarConfirmacaoReset(true)}\n >\n Resetar TODO o progresso do jogo\n \n
\n\n setMostrarConfirmacaoReset(false)}\n onConfirm={() => {\n onResetProgresso();\n setMostrarConfirmacaoReset(false);\n onClose();\n }}\n titulo=\"Resetar progresso\"\n mensagem=\"Tem certeza que deseja apagar TODO o progresso e blocos salvos deste jogo? Esta ação não pode ser desfeita.\"\n />\n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/SucessoModal.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,18],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ChevronRight' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":22,"suggestions":[{"messageId":"removeVar","data":{"varName":"ChevronRight"},"fix":{"range":[63,107],"text":""},"desc":"Remove unused variable 'ChevronRight'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ModalBase' is defined but never used. Allowed unused vars must match /^_/u.","line":5,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":19,"suggestions":[{"messageId":"removeVar","data":{"varName":"ModalBase"},"fix":{"range":[109,155],"text":""},"desc":"Remove unused variable 'ModalBase'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'ModalHeader' is defined but never used. Allowed unused vars must match /^_/u.","line":6,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":6,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"ModalHeader"},"fix":{"range":[156,206],"text":""},"desc":"Remove unused variable 'ModalHeader'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'CodeArea' is defined but never used. Allowed unused vars must match /^_/u.","line":7,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":7,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"CodeArea"},"fix":{"range":[207,251],"text":""},"desc":"Remove unused variable 'CodeArea'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'FeedbackBox' is defined but never used. Allowed unused vars must match /^_/u.","line":8,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":8,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"FeedbackBox"},"fix":{"range":[252,302],"text":""},"desc":"Remove unused variable 'FeedbackBox'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from \"react\";\nimport PropTypes from \"prop-types\";\nimport { ChevronRight } from \"lucide-react\";\n\nimport { ModalBase } from \"./modal/ModalBase\";\nimport { ModalHeader } from \"./modal/ModalHeader\";\nimport { CodeArea } from \"./modal/CodeArea\";\nimport { FeedbackBox } from \"./modal/FeedbackBox\";\n\nconst SucessoModal = ({\n isOpen,\n onClose,\n onNextPhase,\n codigoGerado,\n canGoNext,\n}) => {\n const handleNextPhase = () => {\n onClose();\n if (onNextPhase) {\n onNextPhase();\n }\n };\n\n return (\n \n \n\n
\n
\n \n\n \n

\n Os blocos que você conectou foram convertidos em código JavaScript\n real. Este é o mesmo tipo de código que os programadores usam para\n criar aplicações!\n

\n
\n
\n
\n\n {/* 3. Rodapé (Botões de Ação) */}\n
\n \n Fechar\n \n\n {canGoNext && (\n \n Próxima Fase\n \n \n )}\n
\n
\n );\n};\n\nSucessoModal.propTypes = {\n isOpen: PropTypes.bool.isRequired,\n onClose: PropTypes.func.isRequired,\n onNextPhase: PropTypes.func,\n codigoGerado: PropTypes.any,\n canGoNext: PropTypes.bool.isRequired,\n};\n\nexport default SucessoModal;\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/editors/BlocklyEditor.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'Hammer' is defined but never used. Allowed unused vars must match /^_/u.","line":21,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":21,"endColumn":16,"suggestions":[{"messageId":"removeVar","data":{"varName":"Hammer"},"fix":{"range":[617,655],"text":""},"desc":"Remove unused variable 'Hammer'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'LoadingSpinner' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":25,"column":7,"nodeType":"Identifier","messageId":"unusedVar","endLine":25,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"LoadingSpinner"},"fix":{"range":[722,873],"text":""},"desc":"Remove unused variable 'LoadingSpinner'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'error' is defined but never used.","line":52,"column":16,"nodeType":"Identifier","messageId":"unusedVar","endLine":52,"endColumn":21},{"ruleId":"no-unused-vars","severity":1,"message":"'currentBlockCount' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":78,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":78,"endColumn":27,"suggestions":[{"messageId":"removeVar","data":{"varName":"currentBlockCount"},"fix":{"range":[2390,2407],"text":""},"desc":"Remove unused variable 'currentBlockCount'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, {\n useEffect,\n useRef,\n forwardRef,\n useImperativeHandle,\n useState,\n useCallback,\n useMemo,\n} from \"react\";\nimport * as Blockly from \"blockly/core\";\nimport Theme from \"@blockly/theme-modern\";\nimport { javascriptGenerator } from \"blockly/javascript\";\nimport { useGameState } from \"../../../contexts/GameStateContext\";\nimport { validateBlocklyWorkspace } from \"../../../utils/blocklyValidation\";\nimport { useEditor } from \"../../../contexts/EditorContext\";\nimport {\n loadWorkspace,\n createDebouncedSave,\n} from \"../../../services/blockstorage\";\nimport { getCategoryIcon } from \"./toolboxIcons\";\nimport { Hammer } from \"lucide-react\";\nimport \"./custom_category\";\nimport \"./BlocklyEditor.mobile.css\";\n\nconst LoadingSpinner = () => (\n
\n

Carregando Editor...

\n
\n);\n\nconst BlocklyEditor = forwardRef(function BlocklyEditor(\n { toolboxGenerator, debugSolutions = null, starterBlocks = null },\n ref,\n) {\n const { registerExecutionFunction, onWorkspaceChange } = useGameState();\n const { gameConfig, faseAtual, editorData, updateEditorData, gameNameKey } =\n useEditor();\n\n const hasSolution = debugSolutions && debugSolutions[faseAtual];\n\n const handleLoadSolution = () => {\n if (!workspaceRef.current) {\n alert(\"Editor não está pronto\");\n return;\n }\n\n if (window.confirm(\"Deseja carregar a solução desta fase?\")) {\n try {\n const solution = debugSolutions[faseAtual];\n workspaceRef.current.clear();\n Blockly.serialization.workspaces.load(solution, workspaceRef.current);\n } catch (error) {\n alert(\"Erro ao carregar a solução\");\n }\n }\n };\n\n useEffect(() => {\n if (!gameConfig || !toolboxGenerator) return;\n\n const currentPhase = gameConfig.fases[faseAtual - 1];\n const toolbox = toolboxGenerator(currentPhase.allowedBlocks);\n const max = currentPhase.maxBlocks;\n\n updateEditorData({\n toolboxJson: toolbox,\n maxBlocks: max,\n });\n }, [gameConfig, faseAtual, toolboxGenerator, updateEditorData]);\n\n const { toolboxJson, maxBlocks } = editorData;\n\n const blocklyDiv = useRef(null);\n const workspaceRef = useRef(null);\n const [initialJson, setInitialJson] = useState(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const isInitializedRef = useRef(false);\n const [currentBlockCount, setCurrentBlockCount] = useState(0);\n\n const debouncedSave = useMemo(() => createDebouncedSave(1000), []);\n const stableToolboxJson = useMemo(() => toolboxJson, [toolboxJson]);\n\n const updateCategoriesState = useCallback((limitReached) => {\n if (!workspaceRef.current) return;\n\n const toolbox = workspaceRef.current.getToolbox();\n if (!toolbox) return;\n\n const categories = toolbox.getToolboxItems();\n\n categories.forEach((category) => {\n category.setDisabled(limitReached);\n });\n }, []);\n\n const workspaceChange = useCallback(() => {\n if (!workspaceRef.current) return;\n const blockCount = workspaceRef.current.getAllBlocks().length;\n setCurrentBlockCount(blockCount);\n\n const limitReached =\n maxBlocks !== undefined &&\n maxBlocks !== Infinity &&\n maxBlocks <= blockCount;\n updateCategoriesState(limitReached);\n\n if (onWorkspaceChange) {\n onWorkspaceChange(blockCount);\n }\n }, [onWorkspaceChange, maxBlocks, updateCategoriesState]);\n\n useEffect(() => {\n updateCategoriesState();\n }, [updateCategoriesState]);\n\n useEffect(() => {\n const generateAndValidateCode = () => {\n if (!workspaceRef.current) {\n return { codigo: null, workspace: null };\n }\n const validation = validateBlocklyWorkspace(workspaceRef.current, {\n allowMultipleTopBlocks: false,\n preferredStartBlocks: [\"start\", \"when_run\", \"main\"],\n });\n if (!validation.isValid) {\n return { codigo: null, workspace: null };\n }\n const codigo = javascriptGenerator.workspaceToCode(workspaceRef.current);\n return { codigo, workspace: workspaceRef.current };\n };\n registerExecutionFunction(generateAndValidateCode);\n return () => {\n registerExecutionFunction(null);\n };\n }, [registerExecutionFunction]);\n\n useEffect(() => {\n setIsLoading(true);\n const loadedData = loadWorkspace(gameNameKey);\n setInitialJson(loadedData);\n setIsLoading(false);\n }, [gameNameKey]);\n\n useImperativeHandle(ref, () => workspaceRef.current, []);\n\n useEffect(() => {\n if (\n isLoading ||\n isInitializedRef.current ||\n !blocklyDiv.current ||\n !stableToolboxJson\n ) {\n return;\n }\n isInitializedRef.current = true;\n\n const toolboxWithIcons = {\n ...stableToolboxJson,\n contents: stableToolboxJson.contents.map((cat) => ({\n ...cat,\n \"css-icon\": getCategoryIcon(cat.name),\n })),\n };\n\n workspaceRef.current = Blockly.inject(blocklyDiv.current, {\n toolbox: toolboxWithIcons,\n trashcan: true,\n scrollbars: true,\n renderer: \"zelos\",\n theme: Theme,\n grid: { spacing: 25, length: 3, colour: \"#ccc\", snap: true },\n zoom: { controls: false, wheel: true, startScale: 0.7 },\n });\n\n // Criar variáveis pré-definidas para o jogo Cripto\n if (gameConfig?.gameId === \"cripto\") {\n [\"entrada\", \"saida\", \"pos\"].forEach((varName) => {\n const variableMap = workspaceRef.current.getVariableMap();\n if (!variableMap.getVariable(varName)) {\n workspaceRef.current.createVariable(varName);\n }\n });\n }\n\n // Carregar workspace: prioridade = localStorage > starterBlocks > vazio\n if (initialJson) {\n try {\n Blockly.serialization.workspaces.load(\n initialJson,\n workspaceRef.current,\n );\n } catch (error) {\n console.error(\n \"Falha ao carregar workspace do localStorage, limpando.\",\n error,\n );\n workspaceRef.current.clear();\n }\n } else if (starterBlocks && starterBlocks[faseAtual]) {\n // Se não há nada salvo, carregar blocos iniciais da fase\n try {\n console.log(`Carregando blocos iniciais para fase ${faseAtual}`);\n Blockly.serialization.workspaces.load(\n starterBlocks[faseAtual],\n workspaceRef.current,\n );\n } catch (error) {\n console.error(\"Falha ao carregar blocos iniciais.\", error);\n }\n }\n\n workspaceChange();\n\n const listener = (event) => {\n if (!workspaceRef.current || event.isUiEvent) {\n return;\n }\n\n if (event.type === Blockly.Events.BLOCK_CREATE) {\n const currentCount = workspaceRef.current.getAllBlocks().length;\n if (\n maxBlocks !== undefined &&\n maxBlocks !== Infinity &&\n currentCount > maxBlocks\n ) {\n const blockToRemove = workspaceRef.current.getBlockById(\n event.blockId,\n );\n if (blockToRemove) {\n console.warn(\n `Limite de blocos atingido (${maxBlocks}). Removendo bloco extra: ${event.blockId}`,\n );\n\n Blockly.Events.disable();\n blockToRemove.dispose(false);\n Blockly.Events.enable();\n return;\n }\n }\n }\n\n workspaceChange();\n const currentState = Blockly.serialization.workspaces.save(\n workspaceRef.current,\n );\n debouncedSave(gameNameKey, currentState);\n };\n\n workspaceRef.current.addChangeListener(listener);\n\n const observer = new ResizeObserver(() => {\n if (workspaceRef.current) {\n Blockly.svgResize(workspaceRef.current);\n }\n });\n observer.observe(blocklyDiv.current);\n\n setTimeout(() => {\n updateCategoriesState();\n const bg = document.querySelector(\".blocklyToolboxBackground\");\n if (bg) {\n bg.setAttribute(\"fill\", \"none\");\n bg.setAttribute(\"stroke\", \"none\");\n }\n }, 100);\n\n return () => {\n debouncedSave.cancel();\n if (workspaceRef.current) {\n workspaceRef.current.removeChangeListener(listener);\n try {\n workspaceRef.current.dispose();\n } catch (error) {\n console.warn(\"Erro ao fazer dispose do workspace:\", error);\n }\n workspaceRef.current = null;\n }\n observer.disconnect();\n isInitializedRef.current = false;\n };\n }, [\n isLoading,\n initialJson,\n gameNameKey,\n stableToolboxJson,\n debouncedSave,\n workspaceChange,\n maxBlocks,\n updateCategoriesState,\n ]);\n\n if (isLoading || !toolboxJson) {\n return ;\n }\n\n return (\n
\n {hasSolution && (\n \n \n \n )}\n
\n
\n );\n});\n\nexport default React.memo(BlocklyEditor);\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/editors/CodeEditor.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,13],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'CodeMirror' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"CodeMirror"},"fix":{"range":[68,84],"text":""},"desc":"Remove unused variable 'CodeMirror'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'insertTab' is defined but never used. Allowed unused vars must match /^_/u.","line":5,"column":25,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":34,"suggestions":[{"messageId":"removeVar","data":{"varName":"insertTab"},"fix":{"range":[248,259],"text":""},"desc":"Remove unused variable 'insertTab'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useState, useEffect, useMemo } from \"react\";\nimport CodeMirror from \"@uiw/react-codemirror\";\nimport { javascript } from \"@codemirror/lang-javascript\";\nimport { autocompletion } from \"@codemirror/autocomplete\";\nimport { indentWithTab, insertTab } from \"@codemirror/commands\";\nimport { keymap } from \"@codemirror/view\";\nimport { indentOnInput, indentUnit } from \"@codemirror/language\";\nimport { useGameState } from \"../../../contexts/GameStateContext\";\nimport { useEditor } from \"../../../contexts/EditorContext\";\nimport {\n loadCode,\n createDebouncedCodeSave,\n} from \"../../../services/codestorage\";\n\nconst createGameCompletion = (gameConfig) => {\n return autocompletion({\n override: [\n (context) => {\n const word = context.matchBefore(/\\w*/);\n if (!word || (word.from === word.to && !context.explicit)) return null;\n\n const allowedFunctions = gameConfig?.allowedFunctions || [];\n const functionDocs = gameConfig?.functionDocumentation || {};\n const allowedStructures = gameConfig?.allowedControlStructures || [];\n\n const functionOptions = allowedFunctions.map((funcName) => {\n const doc = functionDocs[funcName] || {};\n return {\n label: funcName,\n type: \"function\",\n info: doc.description || `Função ${funcName}`,\n detail: doc.syntax || `${funcName}()`,\n apply: doc.example || `${funcName}()`,\n };\n });\n\n const structureOptions = allowedStructures.map((structure) => {\n const templates = {\n if: \"if (${condition}) {\\n ${code}\\n}\",\n else: \"else {\\n ${code}\\n}\",\n while: \"while (${condition}) {\\n ${code}\\n}\",\n for: \"for (${init}; ${condition}; ${update}) {\\n ${code}\\n}\",\n var: \"var ${name} = ${value};\",\n function: \"function ${name}() {\\n ${code}\\n}\",\n };\n\n return {\n label: structure,\n type: \"keyword\",\n info: `Estrutura de controle ${structure}`,\n detail: templates[structure] || structure,\n apply: templates[structure] || structure,\n };\n });\n\n return {\n from: word.from,\n options: [...functionOptions, ...structureOptions],\n };\n },\n ],\n });\n};\n\nexport default function CodeEditor() {\n const {\n registerCodeEditorFunction,\n onCodeEditorChange,\n gameConfig,\n currentPhase,\n } = useGameState();\n const faseAtual = currentPhase;\n const { gameNameKey } = useEditor();\n\n const faseConfig = gameConfig?.fases?.find((fase) => fase.id === faseAtual);\n const initialCode = faseConfig?.initialCode || \"// Digite seu código aqui\";\n\n const [code, setCode] = useState(initialCode);\n const [isLoading, setIsLoading] = useState(true);\n\n const debouncedCodeSave = useMemo(() => createDebouncedCodeSave(1000), []);\n const codeStorageKey = `${gameNameKey}-code`;\n\n useEffect(() => {\n setIsLoading(true);\n\n const savedCode = loadCode(codeStorageKey);\n if (savedCode !== null) {\n setCode(savedCode);\n } else {\n setCode(initialCode);\n }\n\n setIsLoading(false);\n }, [codeStorageKey, initialCode]);\n\n useEffect(() => {\n const getCodeFromEditor = () => {\n return code;\n };\n\n registerCodeEditorFunction(getCodeFromEditor);\n\n return () => {\n registerCodeEditorFunction(null);\n };\n }, [code, registerCodeEditorFunction]);\n\n useEffect(() => {\n if (!isLoading) {\n onCodeEditorChange(code);\n }\n }, [code, onCodeEditorChange, isLoading]);\n\n const handleChange = (value) => {\n setCode(value);\n\n if (!isLoading) {\n debouncedCodeSave(codeStorageKey, value);\n }\n };\n\n useEffect(() => {\n return () => {\n debouncedCodeSave.cancel();\n };\n }, [debouncedCodeSave]);\n\n return (\n
\n {\n const { from } = state.selection.main;\n const line = state.doc.lineAt(from);\n const lineText = line.text;\n const indent = lineText.match(/^\\s*/)[0];\n\n let newIndent = indent;\n if (lineText.trim().endsWith(\"{\")) {\n newIndent += \" \";\n }\n\n dispatch(\n state.update({\n changes: {\n from,\n insert: \"\\n\" + newIndent,\n },\n selection: { anchor: from + newIndent.length + 1 },\n }),\n );\n\n return true;\n },\n },\n ]),\n ]}\n onChange={handleChange}\n basicSetup={{\n lineNumbers: true,\n highlightActiveLineGutter: true,\n highlightSpecialChars: true,\n history: true,\n foldGutter: true,\n drawSelection: true,\n dropCursor: true,\n allowMultipleSelections: true,\n indentOnInput: true,\n bracketMatching: true,\n closeBrackets: true,\n autocompletion: true,\n highlightSelectionMatches: false,\n }}\n className=\"h-full\"\n />\n
\n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/editors/OptionsEditor.jsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/editors/custom_category.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/editors/toolboxIcons.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/modal/CodeArea.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,18],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Code' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":14,"suggestions":[{"messageId":"removeVar","data":{"varName":"Code"},"fix":{"range":[27,63],"text":""},"desc":"Remove unused variable 'Code'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from \"react\";\nimport { Code } from \"lucide-react\";\n\nexport const CodeArea = ({\n code,\n title = \"Código Gerado\",\n variant = \"success\",\n}) => {\n const textColors = {\n success: \"text-green-400\",\n failure: \"text-red-300\",\n };\n\n return (\n
\n
\n \n

{title}

\n
\n\n
\n \n {code || \"Nenhum código disponível\"}\n \n
\n
\n );\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/modal/FeedbackBox.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,18],"text":""},"desc":"Remove unused variable 'React'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from \"react\";\n\nexport const FeedbackBox = ({ title, children, variant = \"success\" }) => {\n const styles = {\n success: \"bg-blue-50 border-blue-200 text-blue-800\",\n failure: \"bg-amber-50 border-amber-200 text-amber-800\",\n };\n\n const titleStyles = {\n success: \"text-blue-900\",\n failure: \"text-amber-900\",\n };\n\n return (\n
\n \n {variant === \"success\" ? \"💡\" : \"⚠️\"} {title}\n \n
{children}
\n
\n );\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/modal/ModalBase.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,18],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'X' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":11,"suggestions":[{"messageId":"removeVar","data":{"varName":"X"},"fix":{"range":[27,60],"text":""},"desc":"Remove unused variable 'X'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from \"react\";\nimport { X } from \"lucide-react\";\n\nexport const ModalBase = ({ isOpen, onClose, children }) => {\n if (!isOpen) return null;\n\n return (\n e.target === e.currentTarget && onClose()}\n >\n
\n {children}\n
\n
\n );\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/components/game/modal/ModalHeader.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,18],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'X' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":11,"suggestions":[{"messageId":"removeVar","data":{"varName":"X"},"fix":{"range":[36,38],"text":""},"desc":"Remove unused variable 'X'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'isSuccess' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":10,"column":9,"nodeType":"Identifier","messageId":"unusedVar","endLine":10,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"isSuccess"},"fix":{"range":[183,223],"text":""},"desc":"Remove unused variable 'isSuccess'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Icon' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":26,"column":31,"nodeType":"Identifier","messageId":"unusedVar","endLine":26,"endColumn":35,"suggestions":[{"messageId":"removeVar","data":{"varName":"Icon"},"fix":{"range":[540,546],"text":""},"desc":"Remove unused variable 'Icon'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from \"react\";\nimport { X, CheckCircle, AlertCircle } from \"lucide-react\";\n\nexport const ModalHeader = ({\n title,\n subTitle,\n variant = \"success\",\n onClose,\n}) => {\n const isSuccess = variant === \"success\";\n\n // Mapeamento de estilos por variante\n const config = {\n success: {\n bgColor: \"bg-green-100\",\n iconColor: \"text-green-600\",\n Icon: CheckCircle,\n },\n failure: {\n bgColor: \"bg-red-100\",\n iconColor: \"text-red-600\",\n Icon: AlertCircle,\n },\n };\n\n const { bgColor, iconColor, Icon } = config[variant];\n\n return (\n
\n
\n \n \n
\n
\n

{title}

\n

{subTitle}

\n
\n
\n \n \n \n \n );\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/config/blocklyConfig.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/config/categories.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/config/difficulty.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/config/gameRegistry.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/config/type.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/contexts/EditorContext.jsx","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/contexts/GameStateContext.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,13],"text":""},"desc":"Remove unused variable 'React'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n useCallback,\n useRef,\n} from \"react\";\n\nexport const GAME_STATES = {\n PARADO: \"parado\",\n EXECUTANDO: \"executando\",\n SUCESSO: \"sucesso\",\n FALHA: \"falha\",\n};\n\nconst GameStateContext = createContext();\n\nexport function GameStateProvider({ children, gameConfig }) {\n const [executionState, setExecutionState] = useState(GAME_STATES.PARADO);\n const [generatedCode, setGeneratedCode] = useState(\"\");\n const [currentBlockCount, setCurrentBlockCount] = useState(0);\n const [onWorkspaceChangeCallback, setOnWorkspaceChangeCallback] =\n useState(null);\n const [editorType, setEditorType] = useState(\"blockly\"); // 'blockly' ou 'code'\n const [codeEditorContent, setCodeEditorContent] = useState(\"\");\n const [failureMessage, setFailureMessage] = useState(\"\");\n const [isDebugMode, setIsDebugMode] = useState(false);\n \n const [currentPhase, setCurrentPhase] = useState(1);\n const [completedPhases, setCompletedPhases] = useState([]);\n\n const storageKey = `${gameConfig.gameId}-fases-concluidas`;\n const initialized = useRef(false);\n\n const getCodeFromWorkspace = useRef(null);\n const getCodeFromEditor = useRef(null);\n\n useEffect(() => {\n const urlParams = new URLSearchParams(window.location.search);\n const debugKey = Array.from(urlParams.keys()).find(\n (key) => key.toLowerCase() === \"debug\",\n );\n const isDebug = urlParams.get(debugKey)?.toLowerCase() === \"true\";\n\n if (isDebug) {\n setIsDebugMode(true);\n const todas = Array.from(\n { length: gameConfig.fases.length },\n (_, i) => i + 1,\n );\n setCompletedPhases(todas);\n localStorage.setItem(storageKey, JSON.stringify(todas));\n setCurrentPhase(gameConfig.fases.length);\n return;\n }\n\n if (initialized.current) return;\n\n const saved = localStorage.getItem(storageKey);\n\n if (saved) {\n const fasesSalvas = JSON.parse(saved);\n\n setCompletedPhases(fasesSalvas);\n\n if (fasesSalvas.length > 0) {\n const ultimaFaseConcluida = Math.max(...fasesSalvas);\n const proximaFase = ultimaFaseConcluida + 1;\n const faseParaSetar =\n proximaFase <= gameConfig.fases.length\n ? proximaFase\n : ultimaFaseConcluida;\n setCurrentPhase(faseParaSetar);\n }\n }\n initialized.current = true;\n }, [storageKey, gameConfig.fases.length]);\n\n useEffect(() => {\n if (!initialized.current) return;\n\n localStorage.setItem(storageKey, JSON.stringify(completedPhases));\n }, [completedPhases, storageKey]);\n\n const execute = () => {\n if (editorType === \"code\") {\n if (getCodeFromEditor.current) {\n const codigo = getCodeFromEditor.current();\n\n if (codigo && codigo.trim()) {\n setGeneratedCode(codigo);\n setExecutionState(GAME_STATES.EXECUTANDO);\n } else {\n console.error(\n \"CodeEditor ainda não registrou sua função de execução.\",\n );\n }\n }\n } else {\n if (getCodeFromWorkspace.current) {\n const { codigo, workspace } = getCodeFromWorkspace.current();\n if (codigo && workspace) {\n setGeneratedCode({ codigo, workspace });\n setExecutionState(GAME_STATES.EXECUTANDO);\n }\n } else {\n console.error(\n \"BlocklyEditor ainda não registrou sua função de execução.\",\n );\n }\n }\n };\n\n const finalizeWithSuccess = () => {\n setExecutionState(GAME_STATES.SUCESSO);\n\n if (!completedPhases.includes(currentPhase)) {\n setCompletedPhases([...completedPhases, currentPhase]);\n }\n };\n\n const finalizeWithFailure = () => {\n setExecutionState(GAME_STATES.FALHA);\n };\n\n const restart = () => {\n setExecutionState(GAME_STATES.PARADO);\n setGeneratedCode(\"\");\n };\n\n const resetProgress = () => {\n setCompletedPhases([]);\n setCurrentPhase(1);\n localStorage.removeItem(storageKey);\n };\n\n const changePhase = (numeroFase) => {\n setCurrentPhase(numeroFase);\n setExecutionState(GAME_STATES.PARADO);\n setGeneratedCode(\"\");\n setCurrentBlockCount(0);\n setCodeEditorContent(\"\");\n };\n\n const stop = () => {\n setExecutionState(GAME_STATES.PARADO);\n setGeneratedCode(\"\");\n };\n\n const registerExecutionFunction = useCallback((func) => {\n getCodeFromWorkspace.current = func;\n }, []);\n\n const registerCodeEditorFunction = useCallback((func) => {\n getCodeFromEditor.current = func;\n }, []);\n\n const onWorkspaceChange = useCallback(\n (blockCount) => {\n setCurrentBlockCount(blockCount);\n if (onWorkspaceChangeCallback) {\n onWorkspaceChangeCallback(blockCount);\n }\n },\n [onWorkspaceChangeCallback],\n );\n\n const onCodeEditorChange = useCallback((content) => {\n setCodeEditorContent(content);\n setCurrentBlockCount(content.trim() ? 1 : 0);\n }, []);\n\n useEffect(() => {\n if (editorType === \"code\" && getCodeFromEditor.current) {\n setCurrentBlockCount(\n codeEditorContent && codeEditorContent.trim() ? 1 : 0,\n );\n } else {\n setCodeEditorContent(0);\n }\n }, [editorType, codeEditorContent]);\n\n return (\n \n {children}\n \n );\n}\n\nexport function useGameState() {\n const context = useContext(GameStateContext);\n if (!context) {\n throw new Error(\"useGameState deve ser usado dentro de GameStateProvider\");\n }\n return context;\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/AutomatoGame.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,13],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameBase' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":16,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameBase"},"fix":{"range":[58,72],"text":""},"desc":"Remove unused variable 'GameBase'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameEditor"},"fix":{"range":[113,129],"text":""},"desc":"Remove unused variable 'GameEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'BlocklyEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"BlocklyEditor"},"fix":{"range":[172,191],"text":""},"desc":"Remove unused variable 'BlocklyEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameStateProvider' is defined but never used. Allowed unused vars must match /^_/u.","line":9,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameStateProvider"},"fix":{"range":[406,424],"text":""},"desc":"Remove unused variable 'GameStateProvider'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'AutomatoGameContent' is defined but never used. Allowed unused vars must match /^_/u.","line":17,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":17,"endColumn":29,"suggestions":[{"messageId":"removeVar","data":{"varName":"AutomatoGameContent"},"fix":{"range":[687,1432],"text":""},"desc":"Remove unused variable 'AutomatoGameContent'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useEffect, useMemo } from \"react\";\nimport GameBase from \"../../components/game/GameBase\";\nimport GameEditor from \"../../components/game/GameEditor\";\nimport BlocklyEditor from \"../../components/game/editors/BlocklyEditor\";\nimport { createGame } from \"./game\";\nimport { gameConfig } from \"./config/config\";\nimport { registerBlocks, generateDynamicToolbox } from \"./blocks/blocks\";\nimport {\n GameStateProvider,\n useGameState,\n} from \"../../contexts/GameStateContext\";\nimport { useAutomatoTour } from \"./hooks/useAutomatoTour\";\nimport { debugSolutions } from \"./config/debugSolutions\";\nimport \"shepherd.js/dist/css/shepherd.css\";\nimport \"../../styles/shepherd-theme.css\";\n\nfunction AutomatoGameContent() {\n const { isDebugMode, setFailureMessage } = useGameState();\n const { startTour } = useAutomatoTour();\n\n useEffect(() => {\n registerBlocks();\n }, []);\n\n const toolboxGenerator = useMemo(() => {\n return (allowedBlocks) => generateDynamicToolbox(allowedBlocks);\n }, []);\n\n const renderEditor = () => {\n return (\n \n );\n };\n\n return (\n \n {renderEditor()}\n \n );\n}\n\nexport default function AutomatoGame() {\n return (\n \n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/__tests__/integration.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/blocks/blocks.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/config/config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/config/debugSolutions.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/config/tourSteps.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/game.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/hooks/interpreterSetup.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/hooks/useAutomatoTour.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/automato/validation/validators.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/CriptoGame.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,13],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameBase' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":16,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameBase"},"fix":{"range":[58,72],"text":""},"desc":"Remove unused variable 'GameBase'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameEditor"},"fix":{"range":[113,129],"text":""},"desc":"Remove unused variable 'GameEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'BlocklyEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"BlocklyEditor"},"fix":{"range":[172,191],"text":""},"desc":"Remove unused variable 'BlocklyEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameStateProvider' is defined but never used. Allowed unused vars must match /^_/u.","line":9,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameStateProvider"},"fix":{"range":[406,424],"text":""},"desc":"Remove unused variable 'GameStateProvider'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'CriptoContent' is defined but never used. Allowed unused vars must match /^_/u.","line":18,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":18,"endColumn":23,"suggestions":[{"messageId":"removeVar","data":{"varName":"CriptoContent"},"fix":{"range":[739,1406],"text":""},"desc":"Remove unused variable 'CriptoContent'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useEffect, useMemo } from \"react\";\nimport GameBase from \"../../components/game/GameBase\";\nimport GameEditor from \"../../components/game/GameEditor\";\nimport BlocklyEditor from \"../../components/game/editors/BlocklyEditor\";\nimport { createGame } from \"./game\";\nimport { gameConfig } from \"./config/config\";\nimport { generateDynamicToolbox, registerBlocks } from \"./blocks/blocks\";\nimport {\n GameStateProvider,\n useGameState,\n} from \"../../contexts/GameStateContext\";\nimport { starterBlocks } from \"./config/starterBlocks\";\nimport { useCriptoTour } from \"./hooks/useCriptoTour\";\nimport { debugSolutions } from \"./config/debugSolutions\";\nimport \"shepherd.js/dist/css/shepherd.css\";\nimport \"../../styles/shepherd-theme.css\";\n\nfunction CriptoContent() {\n const { setFailureMessage, isDebugMode } = useGameState();\n useCriptoTour();\n\n useEffect(() => {\n registerBlocks();\n }, []);\n\n const toolboxGenerator = useMemo(() => {\n return (allowedBlocks) => generateDynamicToolbox(allowedBlocks);\n }, []);\n\n return (\n \n \n \n \n \n );\n}\n\nexport default function CriptoGame() {\n return (\n \n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/blocks/blocks.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":628,"column":61,"nodeType":"Identifier","messageId":"unusedVar","endLine":628,"endColumn":66,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[16272,16277],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":634,"column":59,"nodeType":"Identifier","messageId":"unusedVar","endLine":634,"endColumn":64,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[16466,16471],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":640,"column":62,"nodeType":"Identifier","messageId":"unusedVar","endLine":640,"endColumn":67,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[16664,16669],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":646,"column":56,"nodeType":"Identifier","messageId":"unusedVar","endLine":646,"endColumn":61,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[16853,16858],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":652,"column":64,"nodeType":"Identifier","messageId":"unusedVar","endLine":652,"endColumn":69,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[17064,17069],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":708,"column":59,"nodeType":"Identifier","messageId":"unusedVar","endLine":708,"endColumn":64,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[18825,18830],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":723,"column":61,"nodeType":"Identifier","messageId":"unusedVar","endLine":723,"endColumn":66,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[19249,19254],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":738,"column":66,"nodeType":"Identifier","messageId":"unusedVar","endLine":738,"endColumn":71,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[19695,19700],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":753,"column":64,"nodeType":"Identifier","messageId":"unusedVar","endLine":753,"endColumn":69,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[20139,20144],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":768,"column":59,"nodeType":"Identifier","messageId":"unusedVar","endLine":768,"endColumn":64,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[20560,20565],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":783,"column":67,"nodeType":"Identifier","messageId":"unusedVar","endLine":783,"endColumn":72,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[21009,21014],"text":""},"desc":"Remove unused variable 'block'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'block' is defined but never used. Allowed unused args must match /^_/u.","line":798,"column":58,"nodeType":"Identifier","messageId":"unusedVar","endLine":798,"endColumn":63,"suggestions":[{"messageId":"removeVar","data":{"varName":"block"},"fix":{"range":[21429,21434],"text":""},"desc":"Remove unused variable 'block'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":12,"fixableErrorCount":0,"fixableWarningCount":0,"source":"\"use strict\";\n\nimport * as Blockly from \"blockly/core\";\nimport \"blockly/blocks\";\nimport { javascriptGenerator } from \"blockly/javascript\";\n\nconst HUE_LOGICA = 210;\nconst HUE_MATEMATICA = 230;\nconst HUE_TEXTO = 160;\nconst HUE_REPETICAO = 120;\nconst HUE_VARIAVEIS = 330;\n\nexport const registerBlocks = () => {\n defineBlocks();\n defineGenerators();\n};\n\nexport const generateDynamicToolbox = (allowedBlocks = []) => {\n const blockDefinitions = {\n // Matemática\n math_number: {\n kind: \"block\",\n type: \"math_number\",\n },\n math_arithmetic: {\n kind: \"block\",\n type: \"math_arithmetic\",\n },\n math_modulo: {\n kind: \"block\",\n type: \"math_modulo\",\n },\n\n // Texto\n text: {\n kind: \"block\",\n type: \"text\",\n },\n text_indexOf: {\n kind: \"block\",\n type: \"text_indexOf\",\n },\n text_charAt: {\n kind: \"block\",\n type: \"text_charAt\",\n },\n text_join: {\n kind: \"block\",\n type: \"text_join\",\n },\n text_length: {\n kind: \"block\",\n type: \"text_length\",\n },\n alfabeto: {\n kind: \"block\",\n type: \"alfabeto\",\n },\n alfabeto_secreto: {\n kind: \"block\",\n type: \"alfabeto_secreto\",\n },\n\n // Lógica\n controls_if: {\n kind: \"block\",\n type: \"controls_if\",\n },\n logic_compare: {\n kind: \"block\",\n type: \"logic_compare\",\n },\n\n // Repetição\n controls_whileUntil: {\n kind: \"block\",\n type: \"controls_whileUntil\",\n },\n definir_contador: {\n kind: \"block\",\n type: \"definir_contador\",\n },\n obter_contador: {\n kind: \"block\",\n type: \"obter_contador\",\n },\n // Blocos Customizados de Entrada/Saída\n definir_entrada: {\n kind: \"block\",\n type: \"definir_entrada\",\n },\n definir_saida: {\n kind: \"block\",\n type: \"definir_saida\",\n },\n concatenar_saida: {\n kind: \"block\",\n type: \"concatenar_saida\",\n },\n obter_entrada: {\n kind: \"block\",\n type: \"obter_entrada\",\n },\n obter_saida: {\n kind: \"block\",\n type: \"obter_saida\",\n },\n\n // Variáveis Customizadas\n definir_letra: {\n kind: \"block\",\n type: \"definir_letra\",\n },\n obter_letra: {\n kind: \"block\",\n type: \"obter_letra\",\n },\n definir_posicao: {\n kind: \"block\",\n type: \"definir_posicao\",\n },\n obter_posicao: {\n kind: \"block\",\n type: \"obter_posicao\",\n },\n definir_nova_posicao: {\n kind: \"block\",\n type: \"definir_nova_posicao\",\n },\n obter_nova_posicao: {\n kind: \"block\",\n type: \"obter_nova_posicao\",\n },\n definir_nova_letra: {\n kind: \"block\",\n type: \"definir_nova_letra\",\n },\n obter_nova_letra: {\n kind: \"block\",\n type: \"obter_nova_letra\",\n },\n definir_chave: {\n kind: \"block\",\n type: \"definir_chave\",\n },\n obter_chave: {\n kind: \"block\",\n type: \"obter_chave\",\n },\n definir_letra_secreta: {\n kind: \"block\",\n type: \"definir_letra_secreta\",\n },\n obter_letra_secreta: {\n kind: \"block\",\n type: \"obter_letra_secreta\",\n },\n definir_soma: {\n kind: \"block\",\n type: \"definir_soma\",\n },\n obter_soma: {\n kind: \"block\",\n type: \"obter_soma\",\n },\n };\n\n const toolboxContents = {\n kind: \"categoryToolbox\",\n contents: [\n {\n kind: \"category\",\n name: \"Entrada/Saída\",\n colour: HUE_VARIAVEIS,\n contents: [],\n cssConfig: { container: \"variaveis\" },\n },\n {\n kind: \"category\",\n name: \"Lógica\",\n colour: HUE_LOGICA,\n contents: [],\n cssConfig: { container: \"logica\" },\n },\n {\n kind: \"category\",\n name: \"Repetição\",\n colour: HUE_REPETICAO,\n contents: [],\n cssConfig: { container: \"repeticao\" },\n },\n {\n kind: \"category\",\n name: \"Texto\",\n colour: HUE_TEXTO,\n contents: [],\n cssConfig: { container: \"texto\" },\n },\n {\n kind: \"category\",\n name: \"Matemática\",\n colour: HUE_MATEMATICA,\n contents: [],\n cssConfig: { container: \"matematica\" },\n },\n ],\n };\n\n allowedBlocks.forEach((blockId) => {\n const blockDef = blockDefinitions[blockId];\n\n if (!blockDef) {\n console.warn(`Bloco não encontrado: ${blockId}`);\n return;\n }\n\n const categoryMap = {\n obter_entrada: 0,\n obter_saida: 0,\n definir_entrada: 0,\n definir_saida: 0,\n concatenar_saida: 0,\n definir_letra: 0,\n obter_letra: 0,\n definir_posicao: 0,\n obter_posicao: 0,\n definir_nova_posicao: 0,\n obter_nova_posicao: 0,\n definir_nova_letra: 0,\n obter_nova_letra: 0,\n definir_chave: 0,\n obter_chave: 0,\n definir_letra_secreta: 0,\n obter_letra_secreta: 0,\n definir_soma: 0,\n obter_soma: 0,\n controls_if: 1,\n logic_compare: 1,\n controls_whileUntil: 2,\n definir_contador: 2,\n obter_contador: 2,\n text: 3,\n text_charAt: 3,\n text_join: 3,\n text_length: 3,\n text_indexOf: 3,\n alfabeto: 3,\n alfabeto_secreto: 3,\n math_number: 4,\n math_arithmetic: 4,\n math_modulo: 4,\n };\n\n const categoryIndex = categoryMap[blockId];\n\n if (\n categoryIndex !== undefined &&\n categoryIndex >= 0 &&\n toolboxContents.contents[categoryIndex]\n ) {\n if (!toolboxContents.contents[categoryIndex].contents) {\n toolboxContents.contents[categoryIndex].contents = [];\n }\n toolboxContents.contents[categoryIndex].contents.push(blockDef);\n }\n });\n\n return toolboxContents;\n};\n\nconst defineBlocks = () => {\n Blockly.Blocks[\"text_charAt\"] = {\n init: function () {\n this.setHelpUrl(Blockly.Msg[\"TEXT_CHARAT_HELPURL\"]);\n this.setColour(HUE_TEXTO);\n this.setOutput(true, \"String\");\n this.appendValueInput(\"VALUE\").setCheck(\"String\").appendField(\"no texto\");\n this.appendValueInput(\"AT\").setCheck(\"Number\").appendField(\"obter letra\");\n this.setInputsInline(true);\n this.setTooltip(Blockly.Msg[\"TEXT_CHARAT_TOOLTIP\"]);\n },\n };\n\n // Bloco: Definir Contador\n Blockly.Blocks[\"definir_contador\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir CONTADOR como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_REPETICAO);\n this.setTooltip(\"Define o valor do CONTADOR\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Definir Entrada\n Blockly.Blocks[\"definir_entrada\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir ENTRADA como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Define o valor da ENTRADA\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Definir Saída\n Blockly.Blocks[\"definir_saida\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir SAÍDA como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Define o valor da SAÍDA\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Concatenar Saída\n Blockly.Blocks[\"concatenar_saida\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"adicionar à SAÍDA\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Adiciona um valor ao final da saída\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter Entrada\n Blockly.Blocks[\"obter_entrada\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"ENTRADA\");\n this.setOutput(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Obtém o valor atual da entrada\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter Saída\n Blockly.Blocks[\"obter_saida\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"SAÍDA\");\n this.setOutput(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Obtém o valor atual da saída\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter Contador\n Blockly.Blocks[\"obter_contador\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"CONTADOR\");\n this.setOutput(true, null);\n this.setColour(HUE_REPETICAO);\n this.setTooltip(\"Obtém o valor atual do CONTADOR\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Alfabeto (constante)\n Blockly.Blocks[\"alfabeto\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"ALFABETO\");\n this.setOutput(true, \"String\");\n this.setColour(HUE_TEXTO);\n this.setTooltip(\n \"Retorna o alfabeto completo: ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\n );\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Alfabeto Secreto (constante)\n Blockly.Blocks[\"alfabeto_secreto\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"ALFABETO SECRETO\");\n this.setOutput(true, \"String\");\n this.setColour(HUE_TEXTO);\n this.setTooltip(\n \"Retorna o alfabeto embaralhado: QWERTYUIOPASDFGHJKLZXCVBNM\",\n );\n this.setHelpUrl(\"\");\n },\n };\n\n // ============ BLOCOS DE VARIÁVEIS CUSTOMIZADAS ============\n\n // Bloco: Definir letra\n Blockly.Blocks[\"definir_letra\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir LETRA como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Define o valor da variável LETRA\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter letra\n Blockly.Blocks[\"obter_letra\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"LETRA\");\n this.setOutput(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Obtém o valor da variável LETRA\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Definir posicao\n Blockly.Blocks[\"definir_posicao\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir POSIÇÃO como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Define o valor da variável POSIÇÃO\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter posicao\n Blockly.Blocks[\"obter_posicao\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"POSIÇÃO\");\n this.setOutput(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Obtém o valor da variável POSIÇÃO\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Definir nova_posicao\n Blockly.Blocks[\"definir_nova_posicao\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir nova_posicao como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Define o valor da variável nova_posicao\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter nova_posicao\n Blockly.Blocks[\"obter_nova_posicao\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"nova_posicao\");\n this.setOutput(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Obtém o valor da variável nova_posicao\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Definir nova_letra\n Blockly.Blocks[\"definir_nova_letra\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir nova_letra como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Define o valor da variável nova_letra\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter nova_letra\n Blockly.Blocks[\"obter_nova_letra\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"nova_letra\");\n this.setOutput(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Obtém o valor da variável nova_letra\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Definir chave\n Blockly.Blocks[\"definir_chave\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir chave como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\n \"Define o valor da variável chave (deslocamento da cifra)\",\n );\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter chave\n Blockly.Blocks[\"obter_chave\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"chave\");\n this.setOutput(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Obtém o valor da variável chave\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Definir letra_secreta\n Blockly.Blocks[\"definir_letra_secreta\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir LETRA_SECRETA como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Define o valor da variável LETRA_SECRETA\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter letra_secreta\n Blockly.Blocks[\"obter_letra_secreta\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"LETRA_SECRETA\");\n this.setOutput(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Obtém o valor da variável LETRA_SECRETA\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Definir soma\n Blockly.Blocks[\"definir_soma\"] = {\n init: function () {\n this.appendValueInput(\"VALUE\")\n .setCheck(null)\n .appendField(\"definir SOMA como\");\n this.setPreviousStatement(true, null);\n this.setNextStatement(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Define o valor da variável SOMA (acumulador)\");\n this.setHelpUrl(\"\");\n },\n };\n\n // Bloco: Obter soma\n Blockly.Blocks[\"obter_soma\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"SOMA\");\n this.setOutput(true, null);\n this.setColour(HUE_VARIAVEIS);\n this.setTooltip(\"Obtém o valor da variável SOMA\");\n this.setHelpUrl(\"\");\n },\n };\n};\n\nconst defineGenerators = () => {\n javascriptGenerator.STATEMENT_PREFIX = \"highlightBlock(%1);\\n\";\n javascriptGenerator.addReservedWords(\"highlightBlock\");\n\n // Gerador: Definir Entrada\n javascriptGenerator.forBlock[\"definir_entrada\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"''\";\n return \"definirEntrada(\" + value + \");\\n\";\n };\n\n // Gerador: Definir Saída\n javascriptGenerator.forBlock[\"definir_saida\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"''\";\n return \"definirSaida(\" + value + \");\\n\";\n };\n\n // Gerador: Definir Contador\n javascriptGenerator.forBlock[\"definir_contador\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"''\";\n return \"definirContador(\" + value + \");\\n\";\n };\n\n // Gerador: Concatenar Saída\n javascriptGenerator.forBlock[\"concatenar_saida\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"''\";\n return \"concatenarSaida(\" + value + \");\\n\";\n };\n\n // Gerador: Obter Entrada\n javascriptGenerator.forBlock[\"obter_entrada\"] = function (block) {\n const code = \"obterEntrada()\";\n return [code, javascriptGenerator.ORDER_FUNCTION_CALL];\n };\n\n // Gerador: Obter Saída\n javascriptGenerator.forBlock[\"obter_saida\"] = function (block) {\n const code = \"obterSaida()\";\n return [code, javascriptGenerator.ORDER_FUNCTION_CALL];\n };\n\n // Gerador: Obter Contador\n javascriptGenerator.forBlock[\"obter_contador\"] = function (block) {\n const code = \"obterContador()\";\n return [code, javascriptGenerator.ORDER_FUNCTION_CALL];\n };\n\n // Gerador: Alfabeto\n javascriptGenerator.forBlock[\"alfabeto\"] = function (block) {\n const code = '\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"';\n return [code, javascriptGenerator.ORDER_ATOMIC];\n };\n\n // Gerador: Alfabeto Secreto\n javascriptGenerator.forBlock[\"alfabeto_secreto\"] = function (block) {\n const code = '\"QWERTYUIOPASDFGHJKLZXCVBNM\"';\n return [code, javascriptGenerator.ORDER_ATOMIC];\n };\n\n // Gerador customizado: text_charAt (0-based, não subtrai 1)\n // Assume que todos os índices fornecidos já são 0-based (compatível com CONTADOR = 0)\n javascriptGenerator.forBlock[\"text_charAt\"] = function (block) {\n const text =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_MEMBER,\n ) || \"''\";\n const at =\n javascriptGenerator.valueToCode(\n block,\n \"AT\",\n javascriptGenerator.ORDER_NONE,\n ) || \"0\";\n const code = text + \".charAt(\" + at + \")\";\n return [code, javascriptGenerator.ORDER_MEMBER];\n };\n\n // Gerador customizado: text_indexOf (0-based, não adiciona 1)\n // Retorna o índice 0-based direto, compatível com charAt e arrays JavaScript\n javascriptGenerator.forBlock[\"text_indexOf\"] = function (block) {\n const text =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_MEMBER,\n ) || \"''\";\n const search =\n javascriptGenerator.valueToCode(\n block,\n \"FIND\",\n javascriptGenerator.ORDER_NONE,\n ) || \"''\";\n const code = text + \".indexOf(\" + search + \")\";\n return [code, javascriptGenerator.ORDER_MEMBER];\n };\n\n // ============ GERADORES PARA VARIÁVEIS CUSTOMIZADAS ============\n\n // Geradores: letra\n javascriptGenerator.forBlock[\"definir_letra\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"''\";\n return \"var letra = \" + value + \";\\n\";\n };\n\n javascriptGenerator.forBlock[\"obter_letra\"] = function (block) {\n return [\"letra\", javascriptGenerator.ORDER_ATOMIC];\n };\n\n // Geradores: posicao\n javascriptGenerator.forBlock[\"definir_posicao\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"0\";\n return \"var posicao = \" + value + \";\\n\";\n };\n\n javascriptGenerator.forBlock[\"obter_posicao\"] = function (block) {\n return [\"posicao\", javascriptGenerator.ORDER_ATOMIC];\n };\n\n // Geradores: nova_posicao\n javascriptGenerator.forBlock[\"definir_nova_posicao\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"0\";\n return \"var nova_posicao = \" + value + \";\\n\";\n };\n\n javascriptGenerator.forBlock[\"obter_nova_posicao\"] = function (block) {\n return [\"nova_posicao\", javascriptGenerator.ORDER_ATOMIC];\n };\n\n // Geradores: nova_letra\n javascriptGenerator.forBlock[\"definir_nova_letra\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"''\";\n return \"var nova_letra = \" + value + \";\\n\";\n };\n\n javascriptGenerator.forBlock[\"obter_nova_letra\"] = function (block) {\n return [\"nova_letra\", javascriptGenerator.ORDER_ATOMIC];\n };\n\n // Geradores: chave\n javascriptGenerator.forBlock[\"definir_chave\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"0\";\n return \"var chave = \" + value + \";\\n\";\n };\n\n javascriptGenerator.forBlock[\"obter_chave\"] = function (block) {\n return [\"chave\", javascriptGenerator.ORDER_ATOMIC];\n };\n\n // Geradores: letra_secreta\n javascriptGenerator.forBlock[\"definir_letra_secreta\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"''\";\n return \"var letra_secreta = \" + value + \";\\n\";\n };\n\n javascriptGenerator.forBlock[\"obter_letra_secreta\"] = function (block) {\n return [\"letra_secreta\", javascriptGenerator.ORDER_ATOMIC];\n };\n\n // Geradores: soma\n javascriptGenerator.forBlock[\"definir_soma\"] = function (block) {\n const value =\n javascriptGenerator.valueToCode(\n block,\n \"VALUE\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"0\";\n return \"var soma = \" + value + \";\\n\";\n };\n\n javascriptGenerator.forBlock[\"obter_soma\"] = function (block) {\n return [\"soma\", javascriptGenerator.ORDER_ATOMIC];\n };\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/config/codeValidations.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/config/config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/config/debugSolutions.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/config/starterBlocks.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/config/tourSteps.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/game.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/hooks/interpreterSetup.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/hooks/useCriptoTour.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/ui/CRTMonitor.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/ui/GridBackground.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/ui/MatrixEffect.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/ui/animations.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/ui/constants.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/ui/index.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/ui/layout.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/cripto/validation/validators.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/MoleMash.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,13],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameBase' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":16,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameBase"},"fix":{"range":[58,72],"text":""},"desc":"Remove unused variable 'GameBase'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameEditor"},"fix":{"range":[113,129],"text":""},"desc":"Remove unused variable 'GameEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'BlocklyEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"BlocklyEditor"},"fix":{"range":[172,191],"text":""},"desc":"Remove unused variable 'BlocklyEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameStateProvider' is defined but never used. Allowed unused vars must match /^_/u.","line":9,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameStateProvider"},"fix":{"range":[406,424],"text":""},"desc":"Remove unused variable 'GameStateProvider'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'MoleMashContent' is defined but never used. Allowed unused vars must match /^_/u.","line":17,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":17,"endColumn":25,"suggestions":[{"messageId":"removeVar","data":{"varName":"MoleMashContent"},"fix":{"range":[687,1370],"text":""},"desc":"Remove unused variable 'MoleMashContent'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useEffect, useMemo } from \"react\";\nimport GameBase from \"../../components/game/GameBase\";\nimport GameEditor from \"../../components/game/GameEditor\";\nimport BlocklyEditor from \"../../components/game/editors/BlocklyEditor\";\nimport { createGame } from \"./game\";\nimport { gameConfig } from \"./config/config\";\nimport { registerBlocks, generateDynamicToolbox } from \"./blocks/blocks\";\nimport {\n GameStateProvider,\n useGameState,\n} from \"../../contexts/GameStateContext\";\nimport { useMoleMashTour } from \"./hooks/useMoleMashTour\";\nimport { debugSolutions } from \"./config/debugSolutions\";\nimport \"shepherd.js/dist/css/shepherd.css\";\nimport \"../../styles/shepherd-theme.css\";\n\nfunction MoleMashContent() {\n const { startTour } = useMoleMashTour();\n const { setFailureMessage, isDebugMode } = useGameState();\n\n useEffect(() => {\n registerBlocks();\n }, []);\n\n const toolboxGenerator = useMemo(() => {\n return (allowedBlocks) => generateDynamicToolbox(allowedBlocks);\n }, []);\n\n return (\n \n \n \n \n \n );\n}\n\nexport default function MoleMashGame() {\n return (\n \n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/__tests__/integration.test.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'l' is defined but never used. Allowed unused args must match /^_/u.","line":227,"column":17,"nodeType":"Identifier","messageId":"unusedVar","endLine":227,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"l"},"fix":{"range":[5669,5671],"text":""},"desc":"Remove unused variable 'l'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'c' is defined but never used. Allowed unused args must match /^_/u.","line":227,"column":20,"nodeType":"Identifier","messageId":"unusedVar","endLine":227,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"c"},"fix":{"range":[5670,5673],"text":""},"desc":"Remove unused variable 'c'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'segundos' is defined but never used. Allowed unused args must match /^_/u.","line":238,"column":12,"nodeType":"Identifier","messageId":"unusedVar","endLine":238,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"segundos"},"fix":{"range":[5962,5970],"text":""},"desc":"Remove unused variable 'segundos'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { describe, it, expect, beforeEach, vi } from \"vitest\";\nimport { GameInterpreter } from \"../../../interpreters/GameInterpreter\";\nimport { setupMoleMashAPI } from \"../hooks/interpreterSetup\";\nimport { validateSolution } from \"../validation/validators\";\n\n// Mock de soluções para teste (movido de config/solutions.js)\nconst SOLUTIONS = {\n fase1: `\n moverToupeira(1, 1);\n moverToupeira(1, 2);\n moverToupeira(1, 3);\n `,\n fase1_fail: `\n moverToupeira(1, 1);\n moverToupeira(1, 3);\n `,\n fase2: `\n moverToupeira(1, 1);\n moverToupeira(1, 3);\n moverToupeira(3, 3);\n moverToupeira(3, 1);\n `,\n fase2_fail: `\n moverToupeira(1, 1);\n moverToupeira(2, 2);\n `,\n fase3: `\n for (var count = 0; count < 5; count++) {\n moverToupeira(2, 2);\n moverToupeira(1, 2);\n }\n `,\n fase3_fail: `\n for (var count = 0; count < 5; count++) {\n moverToupeira(2, 2);\n moverToupeira(2, 2); \n }\n `,\n fase4: `\n var linha, coluna;\n linha = 3;\n for (var count2 = 0; count2 < 3; count2++) {\n coluna = 3;\n for (var count = 0; count < 3; count++) {\n moverToupeira(linha, coluna);\n coluna = coluna - 1;\n }\n linha = (typeof linha === 'number' ? linha : 0) + -1;\n }\n `,\n fase4_fail: `\n for (var i = 0; i < 10; i++) {\n moverToupeira(1, 1);\n moverToupeira(1, 2);\n }\n `,\n fase5: `\n function mathRandomInt(a, b) {\n if (a > b) { var c = a; a = b; b = c; }\n return Math.floor(Math.random() * (b - a + 1) + a);\n }\n for (var count = 0; count < 10; count++) {\n moverToupeira(2, (mathRandomInt(1, 3)));\n }\n `,\n fase5_fail: `\n for (var count = 0; count < 5; count++) {\n moverToupeira(1, 2);\n }\n `,\n fase6: `\n function mathRandomInt(a, b) {\n if (a > b) { var c = a; a = b; b = c; }\n return Math.floor(Math.random() * (b - a + 1) + a);\n }\n for (var count = 0; count < 20; count++) {\n moverToupeira(mathRandomInt(1, 3), mathRandomInt(1, 3));\n }\n `,\n fase7: `\n var x, y;\n function mathRandomInt(a, b) {\n if (a > b) { var c = a; a = b; b = c; }\n return Math.floor(Math.random() * (b - a + 1) + a);\n }\n for (var count = 0; count < 20; count++) {\n x = mathRandomInt(1, 10);\n y = mathRandomInt(1, 3);\n if (x <= 5) {\n moverToupeira(1, y);\n } else {\n moverToupeira(3, y);\n }\n }\n `,\n fase8: `\n var linha_atual, coluna, ultima_linha;\n function mathRandomInt(a, b) {\n if (a > b) { var c = a; a = b; b = c; }\n return Math.floor(Math.random() * (b - a + 1) + a);\n }\n for (var count = 0; count < 10; count++) {\n linha_atual = mathRandomInt(1, 1);\n coluna = mathRandomInt(1, 3);\n if (linha_atual == ultima_linha) {\n moverToupeira(2, coluna);\n } else {\n moverToupeira(linha_atual, coluna);\n }\n ultima_linha = linha_atual;\n }\n `,\n fase8_fail: `\n moverToupeira(1, 1);\n moverToupeira(1, 2);\n `,\n fase9: `\n var linha, coluna, ultima_linha, ultima_coluna;\n function mathRandomInt(a, b) {\n if (a > b) { var c = a; a = b; b = c; }\n return Math.floor(Math.random() * (b - a + 1) + a);\n }\n for (var count = 0; count < 30; count++) {\n linha = mathRandomInt(1, 3);\n coluna = mathRandomInt(1, 3);\n while (linha == ultima_linha && coluna == ultima_coluna) {\n linha = mathRandomInt(1, 3);\n coluna = mathRandomInt(1, 3);\n }\n moverToupeira(linha, coluna);\n ultima_linha = linha;\n ultima_coluna = coluna;\n }\n `,\n fase10: `\n var l, c, ult_l, ult_c;\n function mathRandomInt(a, b) {\n if (a > b) { var c = a; a = b; b = c; }\n return Math.floor(Math.random() * (b - a + 1) + a);\n }\n for (var count = 0; count < 30; count++) {\n l = mathRandomInt(1, 3);\n c = mathRandomInt(1, 3);\n while (l == ult_l && c == ult_c) {\n l = mathRandomInt(1, 3);\n c = mathRandomInt(1, 3);\n }\n if (ult_l == 2) {\n if (mathRandomInt(1, 2) == 1) {\n l = 1;\n } else {\n l = 3;\n }\n }\n moverToupeira(l, c);\n ult_l = l;\n ult_c = c;\n aguardar(0.1);\n }\n `,\n fase10_fail: `\n moverToupeira(2, 1);\n moverToupeira(2, 3);\n `,\n};\n\n// MOCK DA CONFIGURAÇÃO (Para não depender do gameConfig externo)\n// Replicamos aqui apenas as regras que o validador consome.\nconst MOCK_GAME_CONFIG = {\n mensagens: {\n semMovimento: \"Sem mov\",\n foraTabuleiro: \"Fora!\",\n caminhoErrado: \"Caminho errado\",\n faltamSaltos: \"Falta salto\",\n saltoInsuficiente: \"Insuficiente\",\n saltoErrado: \"Padrão errado no salto {numero}: esperado {local}\",\n buracosFaltando: \"Não visitou tudo ({visitados} visitados)\",\n linhaErrada: \"Linha errada\",\n repeticaoLinha: \"Repetiu linha\",\n mesmoLugar: \"Mesmo lugar\",\n linhaCentral: \"Centro repetido\",\n },\n fases: [\n {\n id: 1,\n expectedSequence: [\n { l: 1, c: 1 },\n { l: 1, c: 2 },\n { l: 1, c: 3 },\n ],\n },\n {\n id: 2,\n expectedSequence: [\n { l: 1, c: 1 },\n { l: 1, c: 3 },\n { l: 3, c: 3 },\n { l: 3, c: 1 },\n ],\n },\n { id: 3 },\n { id: 4 },\n { id: 5 },\n { id: 6 },\n { id: 7 },\n { id: 8 },\n { id: 9 },\n { id: 10 },\n ],\n};\n\n// CENA HEADLESS (Simula o Phaser sem gráficos)\nclass HeadlessMoleMashScene {\n constructor() {\n this.historico = [];\n this.toupeira = {\n setPosition: vi.fn(),\n setVisible: vi.fn(),\n play: vi.fn(),\n scene: true,\n };\n // Mock do som\n this.sound = { play: vi.fn() };\n }\n\n // Utilitário usado pela API\n getGridPixels(l, c) {\n return { x: 0, y: 0 };\n }\n\n // Implementação da API Visual dentro da cena\n moverToupeira(linha, coluna) {\n this.historico.push({ l: linha, c: coluna, t: Date.now() });\n this.toupeira.setPosition(0, 0);\n }\n\n // Simula aguardar (resolve imediatamente no teste)\n aguardar(segundos) {\n return Promise.resolve();\n }\n}\n\ndescribe(\"Mole Mash - Integração de Lógica (Código -> Validação)\", () => {\n let scene;\n let interpreter;\n\n beforeEach(() => {\n scene = new HeadlessMoleMashScene();\n // StepDelay 0 para rodar instantâneo\n interpreter = new GameInterpreter({ stepDelay: 0, pauseExec: false });\n });\n\n const runFlow = async (code, phaseId) => {\n const api = setupMoleMashAPI(scene);\n\n // Executa o código (popula scene.historico)\n await interpreter.executeCode(code, api);\n\n const configFase = MOCK_GAME_CONFIG.fases.find((f) => f.id === phaseId);\n\n // Valida o histórico gerado\n return validateSolution(scene.historico, configFase, MOCK_GAME_CONFIG);\n };\n\n // --- TESTES DE FASES ---\n\n it(\"Fase 1: Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase1, 1);\n expect(result.success).toBe(true);\n });\n\n it(\"Fase 1: Deve reprovar solução errada\", async () => {\n const result = await runFlow(SOLUTIONS.fase1_fail, 1);\n expect(result.success).toBe(false);\n expect(result.reason).toBe(MOCK_GAME_CONFIG.mensagens.caminhoErrado);\n });\n\n it(\"Fase 2: Deve aprovar solução correta (Cantos)\", async () => {\n const result = await runFlow(SOLUTIONS.fase2, 2);\n expect(result.success).toBe(true);\n });\n\n it(\"Fase 2: Deve reprovar solução errada\", async () => {\n const result = await runFlow(SOLUTIONS.fase2_fail, 2);\n expect(result.success).toBe(false);\n });\n\n it(\"Fase 3: Deve aprovar loop correto\", async () => {\n const result = await runFlow(SOLUTIONS.fase3, 3);\n expect(result.success).toBe(true);\n expect(scene.historico.length).toBe(10);\n });\n\n it(\"Fase 3: Deve reprovar loop incorreto\", async () => {\n const result = await runFlow(SOLUTIONS.fase3_fail, 3);\n expect(result.success).toBe(false);\n expect(result.reason).toContain(\"Padrão errado\");\n });\n\n it(\"Fase 4: Deve aprovar varredura completa (Nested Loops)\", async () => {\n const result = await runFlow(SOLUTIONS.fase4, 4);\n expect(result.success).toBe(true);\n });\n\n it(\"Fase 4: Deve reprovar varredura incompleta\", async () => {\n const result = await runFlow(SOLUTIONS.fase4_fail, 4);\n expect(result.success).toBe(false);\n expect(result.reason).toContain(\"Não visitou tudo\");\n });\n\n it(\"Fase 5: Deve aprovar aleatório na linha 2\", async () => {\n const result = await runFlow(SOLUTIONS.fase5, 5);\n expect(result.success).toBe(true);\n });\n\n it(\"Fase 5: Deve reprovar linha errada\", async () => {\n const result = await runFlow(SOLUTIONS.fase5_fail, 5);\n expect(result.success).toBe(false);\n expect(result.reason).toBe(MOCK_GAME_CONFIG.mensagens.linhaErrada);\n });\n\n // Fase 6 e 7 e 9 não possuem validadores específicos complexos no momento,\n // validam apenas sanidade e limites. Testamos apenas o sucesso da execução.\n it(\"Fase 6: Deve executar com sucesso (Aleatório Total)\", async () => {\n const result = await runFlow(SOLUTIONS.fase6, 6);\n expect(result.success).toBe(true);\n });\n\n it(\"Fase 7: Deve executar com sucesso (Condicionais)\", async () => {\n const result = await runFlow(SOLUTIONS.fase7, 7);\n expect(result.success).toBe(true);\n });\n\n it(\"Fase 8: Deve aprovar lógica de não repetição de linha\", async () => {\n const result = await runFlow(SOLUTIONS.fase8, 8);\n expect(result.success).toBe(true);\n });\n\n it(\"Fase 8: Deve reprovar repetição explícita\", async () => {\n const result = await runFlow(SOLUTIONS.fase8_fail, 8);\n expect(result.success).toBe(false);\n expect(result.reason).toBe(MOCK_GAME_CONFIG.mensagens.repeticaoLinha);\n });\n\n it(\"Fase 9: Deve executar com sucesso (While loop)\", async () => {\n const result = await runFlow(SOLUTIONS.fase9, 9);\n expect(result.success).toBe(true);\n });\n\n it(\"Fase 10: Deve aprovar lógica complexa\", async () => {\n const result = await runFlow(SOLUTIONS.fase10, 10);\n expect(result.success).toBe(true);\n });\n\n it(\"Fase 10: Deve reprovar lógica errada (Centro Repetido)\", async () => {\n const result = await runFlow(SOLUTIONS.fase10_fail, 10);\n expect(result.success).toBe(false);\n expect(result.reason).toBe(MOCK_GAME_CONFIG.mensagens.linhaCentral);\n });\n}, 60000);\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/blocks/blocks.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'index' is defined but never used. Allowed unused args must match /^_/u.","line":261,"column":16,"nodeType":"Identifier","messageId":"unusedVar","endLine":261,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"index"},"fix":{"range":[6792,6799],"text":""},"desc":"Remove unused variable 'index'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import * as Blockly from \"blockly/core\";\nimport \"blockly/blocks\";\nimport { javascriptGenerator } from \"blockly/javascript\";\n\nconst HUE_CONDICIONAIS = \"#5B80A5\";\nconst HUE_MOVIMENTO = \"#8B4513\";\nconst HUE_LOGICA = \"#59C059\";\nconst HUE_MATEMATICA = \"#8BC34A\";\nconst HUE_VARIAVEIS = \"#9C27B0\";\nconst HUE_REPETICAO = \"#FF9800\";\nconst HUE_TEMPO = \"#FF5722\";\n\nexport const registerBlocks = () => {\n defineBlocks();\n defineGenerators();\n};\n\nconst defineBlocks = () => {\n Blockly.Blocks[\"mover_toupeira\"] = {\n init: function () {\n this.jsonInit({\n message0: \"mover para Linha %1 Coluna %2\",\n args0: [\n { type: \"input_value\", name: \"LINHA\", check: \"Number\" },\n { type: \"input_value\", name: \"COLUNA\", check: \"Number\" },\n ],\n inputsInline: true,\n previousStatement: null,\n nextStatement: null,\n colour: HUE_MOVIMENTO,\n tooltip:\n \"Move a toupeira para uma posição específica (1 a 3) na matriz.\",\n });\n },\n };\n\n Blockly.Blocks[\"aguardar\"] = {\n init: function () {\n this.jsonInit({\n message0: \"aguardar %1 segundos\",\n args0: [\n {\n type: \"field_number\",\n name: \"TEMPO\",\n value: 1,\n min: 0,\n max: 10,\n },\n ],\n previousStatement: null,\n nextStatement: null,\n colour: HUE_TEMPO,\n tooltip: \"Pausa a execução antes do próximo movimento.\",\n });\n },\n };\n\n Blockly.Blocks[\"repetir_sempre\"] = {\n init: function () {\n this.appendDummyInput().appendField(\"repetir para sempre\");\n this.appendStatementInput(\"STACK\").setCheck(null).appendField(\"faça\");\n this.setPreviousStatement(true, null);\n this.setColour(HUE_REPETICAO);\n this.setTooltip(\"Executa os blocos dentro dele em um ciclo infinito.\");\n },\n };\n};\n\nconst defineGenerators = () => {\n javascriptGenerator.STATEMENT_PREFIX = \"highlightBlock(%1);\\n\";\n javascriptGenerator.addReservedWords(\"highlightBlock\");\n\n javascriptGenerator.forBlock[\"mover_toupeira\"] = (block) => {\n const linha =\n javascriptGenerator.valueToCode(\n block,\n \"LINHA\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"1\";\n const coluna =\n javascriptGenerator.valueToCode(\n block,\n \"COLUNA\",\n javascriptGenerator.ORDER_ATOMIC,\n ) || \"1\";\n return `moverToupeira(${linha}, ${coluna});\\n`;\n };\n\n javascriptGenerator.forBlock[\"aguardar\"] = (block) => {\n const tempo = block.getFieldValue(\"TEMPO\");\n return `aguardar(${tempo * 1000});\\n`;\n };\n\n javascriptGenerator.forBlock[\"repetir_sempre\"] = (block) => {\n const branch = javascriptGenerator.statementToCode(block, \"STACK\");\n return `while (true) {\\n${branch} await esperar(10); // Segurança para não travar\\n}\\n`;\n };\n};\n\nexport const generateDynamicToolbox = (allowedBlocks = []) => {\n const blockDefinitions = {\n // Movimento\n mover_toupeira: {\n kind: \"block\",\n type: \"mover_toupeira\",\n },\n // Repetição\n repetir_sempre: {\n kind: \"block\",\n type: \"repetir_sempre\",\n },\n controls_repeat_ext: {\n kind: \"block\",\n type: \"controls_repeat_ext\",\n },\n controls_whileUntil: {\n kind: \"block\",\n type: \"controls_whileUntil\",\n },\n // Tempo\n aguardar: {\n kind: \"block\",\n type: \"aguardar\",\n },\n // Lógica\n logic_compare: {\n kind: \"block\",\n type: \"logic_compare\",\n },\n logic_operation: {\n kind: \"block\",\n type: \"logic_operation\",\n },\n logic_negate: {\n kind: \"block\",\n type: \"logic_negate\",\n },\n logic_boolean: {\n kind: \"block\",\n type: \"logic_boolean\",\n },\n controls_if: {\n kind: \"block\",\n type: \"controls_if\",\n },\n controls_ifelse: {\n kind: \"block\",\n type: \"controls_ifelse\",\n },\n // Matemática\n math_number: {\n kind: \"block\",\n type: \"math_number\",\n },\n math_arithmetic: {\n kind: \"block\",\n type: \"math_arithmetic\",\n },\n math_random_int: {\n kind: \"block\",\n type: \"math_random_int\",\n inputs: {\n FROM: { shadow: { type: \"math_number\", fields: { NUM: 1 } } },\n TO: { shadow: { type: \"math_number\", fields: { NUM: 3 } } },\n },\n },\n };\n\n const toolboxContents = {\n kind: \"categoryToolbox\",\n contents: [\n {\n kind: \"category\",\n name: \"Movimento\",\n colour: HUE_MOVIMENTO,\n contents: [],\n cssConfig: { container: \"movimento\" },\n },\n {\n kind: \"category\",\n name: \"Repetição\",\n colour: HUE_REPETICAO,\n contents: [],\n cssConfig: { container: \"repeticao\" },\n },\n {\n kind: \"category\",\n name: \"Lógica\",\n colour: HUE_LOGICA,\n contents: [],\n cssConfig: { container: \"logica\" },\n },\n {\n kind: \"category\",\n name: \"Condicionais\",\n colour: HUE_CONDICIONAIS,\n contents: [],\n cssConfig: { container: \"condicionais\" },\n },\n {\n kind: \"category\",\n name: \"Matemática\",\n colour: HUE_MATEMATICA,\n contents: [],\n cssConfig: { container: \"matematica\" },\n },\n {\n kind: \"category\",\n name: \"Tempo\",\n colour: HUE_TEMPO,\n contents: [],\n cssConfig: { container: \"tempo\" },\n },\n {\n kind: \"category\",\n name: \"Variáveis\",\n colour: HUE_VARIAVEIS,\n custom: \"VARIABLE\",\n cssConfig: { container: \"variaveis\" },\n },\n ],\n };\n\n allowedBlocks.forEach((blockId) => {\n const blockDef = blockDefinitions[blockId];\n\n if (blockId === \"mover_toupeira\") {\n toolboxContents.contents[0].contents.push(blockDef);\n } else if (\n [\"repetir_sempre\", \"controls_repeat_ext\", \"controls_whileUntil\"].includes(\n blockId,\n )\n ) {\n toolboxContents.contents[1].contents.push(blockDef);\n } else if (\n [\n \"logic_compare\",\n \"logic_operation\",\n \"logic_negate\",\n \"logic_boolean\",\n ].includes(blockId)\n ) {\n toolboxContents.contents[2].contents.push(blockDef);\n } else if ([\"controls_if\", \"controls_ifelse\"].includes(blockId)) {\n toolboxContents.contents[3].contents.push(blockDef);\n } else if (\n [\"math_number\", \"math_random_int\", \"math_arithmetic\"].includes(blockId)\n ) {\n toolboxContents.contents[4].contents.push(blockDef);\n } else if (blockId === \"aguardar\") {\n toolboxContents.contents[5].contents.push(blockDef);\n }\n });\n\n const hasVariables =\n allowedBlocks.includes(\"variables_set\") ||\n allowedBlocks.includes(\"variables_get\") ||\n allowedBlocks.includes(\"variables\");\n\n toolboxContents.contents = toolboxContents.contents.filter(\n (category, index) => {\n if (category.custom === \"VARIABLE\") {\n return hasVariables;\n }\n return category.contents && category.contents.length > 0;\n },\n );\n\n return toolboxContents;\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/config/config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/config/debugSolutions.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/config/tourSteps.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/game.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/hooks/interpreterSetup.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'options' is assigned a value but never used. Allowed unused args must match /^_/u.","line":3,"column":49,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":56,"suggestions":[{"messageId":"removeVar","data":{"varName":"options"},"fix":{"range":[113,127],"text":""},"desc":"Remove unused variable 'options'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ApiHelpers } from \"../../../interpreters/ApiHelpers.js\";\n\nexport const setupMoleMashAPI = (sceneInstance, options = {}) => {\n return (interpreter, globalObject) => {\n const highlightWrapper = function (id, callback) {\n sceneInstance.highlightBlock(id).then(callback);\n };\n\n const moverToupeiraWrapper = function (linha, coluna, callback) {\n sceneInstance.moverToupeira(linha, coluna);\n setTimeout(callback, 800);\n };\n\n const aguardarWrapper = function (ms, callback) {\n setTimeout(callback, ms);\n };\n\n ApiHelpers.registerMultipleFunctions(interpreter, globalObject, [\n { name: \"highlightBlock\", wrapper: highlightWrapper, isAsync: true },\n { name: \"moverToupeira\", wrapper: moverToupeiraWrapper, isAsync: true },\n { name: \"aguardar\", wrapper: aguardarWrapper, isAsync: true },\n ]);\n };\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/hooks/useMoleMashTour.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/mole-mash/validation/validators.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/SemaforoGame.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,13],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameBase' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":16,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameBase"},"fix":{"range":[58,72],"text":""},"desc":"Remove unused variable 'GameBase'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameEditor"},"fix":{"range":[113,129],"text":""},"desc":"Remove unused variable 'GameEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'BlocklyEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"BlocklyEditor"},"fix":{"range":[172,191],"text":""},"desc":"Remove unused variable 'BlocklyEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameStateProvider' is defined but never used. Allowed unused vars must match /^_/u.","line":9,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":9,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameStateProvider"},"fix":{"range":[406,424],"text":""},"desc":"Remove unused variable 'GameStateProvider'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'SemaforoContent' is defined but never used. Allowed unused vars must match /^_/u.","line":17,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":17,"endColumn":25,"suggestions":[{"messageId":"removeVar","data":{"varName":"SemaforoContent"},"fix":{"range":[687,1370],"text":""},"desc":"Remove unused variable 'SemaforoContent'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useEffect, useMemo } from \"react\";\nimport GameBase from \"../../components/game/GameBase\";\nimport GameEditor from \"../../components/game/GameEditor\";\nimport BlocklyEditor from \"../../components/game/editors/BlocklyEditor\";\nimport { createGame } from \"./game\";\nimport { gameConfig } from \"./config/config\";\nimport { generateDynamicToolbox, registerBlocks } from \"./blocks/blocks\";\nimport {\n GameStateProvider,\n useGameState,\n} from \"../../contexts/GameStateContext\";\nimport { useSemaforoTour } from \"./hooks/useSemaforoTour\";\nimport { debugSolutions } from \"./config/debugSolutions\";\nimport \"shepherd.js/dist/css/shepherd.css\";\nimport \"../../styles/shepherd-theme.css\";\n\nfunction SemaforoContent() {\n const { startTour } = useSemaforoTour();\n const { setFailureMessage, isDebugMode } = useGameState();\n\n useEffect(() => {\n registerBlocks();\n }, []);\n\n const toolboxGenerator = useMemo(() => {\n return (allowedBlocks) => generateDynamicToolbox(allowedBlocks);\n }, []);\n\n return (\n \n \n \n \n \n );\n}\n\nexport default function SemaforoGame() {\n return (\n \n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/__tests__/integration.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/blocks/blocks.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/config/config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/config/debugSolutions.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/config/tourSteps.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/game.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/hooks/interpreterSetup.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'config' is assigned a value but never used. Allowed unused args must match /^_/u.","line":3,"column":41,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":47,"suggestions":[{"messageId":"removeVar","data":{"varName":"config"},"fix":{"range":[105,118],"text":""},"desc":"Remove unused variable 'config'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ApiHelpers } from \"../../../interpreters/ApiHelpers.js\";\n\nexport const setupSemaforoAPI = (scene, config = {}) => {\n const getAnimationDelay = () => {\n if (scene.executionSpeed >= 75) return 1;\n if (scene.executionSpeed >= 50) return 2;\n if (scene.executionSpeed >= 25) return 5;\n return 10;\n };\n\n return (interpreter, globalScope) => {\n ApiHelpers.registerFunction(\n interpreter,\n globalScope,\n \"mudarSemaforo\",\n ApiHelpers.createActionWrapper(\n scene,\n \"mudarSemaforoCarros\",\n getAnimationDelay(),\n ),\n true,\n );\n\n ApiHelpers.registerFunction(\n interpreter,\n globalScope,\n \"mudarSemaforoPedestre\",\n ApiHelpers.createActionWrapper(\n scene,\n \"mudarSemaforoPedestre\",\n getAnimationDelay(),\n ),\n true,\n );\n\n ApiHelpers.registerFunction(\n interpreter,\n globalScope,\n \"aguardarSegundos\",\n ApiHelpers.createActionWrapper(scene, \"aguardarSegundos\"),\n true,\n );\n\n ApiHelpers.registerFunction(\n interpreter,\n globalScope,\n \"piscarLuzPedestre\",\n ApiHelpers.createActionWrapper(scene, \"piscarLuzPedestre\"),\n true,\n );\n\n ApiHelpers.registerFunction(\n interpreter,\n globalScope,\n \"tocarSom\",\n ApiHelpers.createActionWrapper(scene, \"tocarSom\"),\n true,\n );\n\n ApiHelpers.registerFunction(\n interpreter,\n globalScope,\n \"pararSom\",\n ApiHelpers.createActionWrapper(scene, \"pararSom\"),\n true,\n );\n\n ApiHelpers.registerFunction(\n interpreter,\n globalScope,\n \"highlightBlock\",\n ApiHelpers.createHighlightWrapper(scene),\n false,\n );\n };\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/hooks/useSemaforoTour.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/semaforo/validation/validators.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'sceneRef' is defined but never used. Allowed unused args must match /^_/u.","line":32,"column":46,"nodeType":"Identifier","messageId":"unusedVar","endLine":32,"endColumn":54,"suggestions":[{"messageId":"removeVar","data":{"varName":"sceneRef"},"fix":{"range":[1299,1309],"text":""},"desc":"Remove unused variable 'sceneRef'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { BaseGameValidator } from \"../../../shared/BaseGameValidator\";\n\n/**\n * Validador para o jogo Semáforo\n *\n * @class SemaforoValidator\n * @extends BaseGameValidator\n *\n * @description\n * Responsável por validar as ações do usuário em cada fase do jogo.\n * Utiliza validação baseada em histórico de comandos executados,\n * verificando sequências de cores, tempos de espera, sincronização\n * de semáforos, piscar de luzes e controle de sons.\n *\n * Validações por fase:\n * - Fase 1: Sequência básica de cores (verde → amarelo → vermelho)\n * - Fase 2: Sequência com pausas entre mudanças\n * - Fase 3: Sincronização de semáforos de carros e pedestres\n * - Fase 4: Adiciona piscar da luz de pedestre\n * - Fase 5: Adiciona controle de sons\n */\nexport class SemaforoValidator extends BaseGameValidator {\n /**\n * Método principal de validação - delega para métodos específicos por fase\n *\n * @param {Array} history - Histórico de comandos executados\n * @param {Object} config - Configuração da fase atual\n * @param {Object} gameConfig - Configuração geral do jogo (inclui mensagens)\n * @param {Object} sceneRef - Referência à cena do jogo (opcional)\n * @returns {Object} Resultado da validação {success: boolean, reason?: string}\n */\n validatePhase(history, config, gameConfig, sceneRef) {\n // Verificar se tem histórico\n if (!history || history.length === 0) {\n return this.failure(\n gameConfig.mensagens?.semComandos || \"Nenhum comando executado\",\n );\n }\n\n // Roteamento por fase\n const phaseMethod = this[`validateFase${config.id}`];\n if (phaseMethod) {\n return phaseMethod.call(this, history, config, gameConfig);\n }\n\n return this.success();\n }\n\n /**\n * Fase 1: Sequência básica de cores do semáforo\n * Valida: verde → amarelo → vermelho\n *\n * @param {Array} history - Histórico de comandos\n * @param {Object} config - Configuração da fase (contém expectedSequence)\n * @param {Object} gameConfig - Config do jogo (contém mensagens)\n * @returns {Object} Resultado da validação\n *\n * @note Fase 1 injeta automaticamente aguardarSegundos(2) entre cada mudança\n * para melhorar a visualização, então ignoramos comandos 'aguardar' na validação\n */\n validateFase1(history, config, gameConfig) {\n // Extrair apenas comandos de semáforo (ignorar aguardares automáticos)\n const cores = history\n .filter((h) => h.tipo === \"semaforo\")\n .map((h) => h.cor);\n\n const esperado = config.expectedSequence || [\n \"vermelho\",\n \"amarelo\",\n \"verde\",\n ];\n\n if (cores.length !== esperado.length) {\n return this.failure(\n gameConfig.mensagens?.sequenciaIncorreta || \"Sequência incompleta\",\n );\n }\n\n const match = cores.every((cor, i) => cor === esperado[i]);\n return match\n ? this.success()\n : this.failure(\n gameConfig.mensagens?.sequenciaIncorreta ||\n \"Sequência de cores incorreta\",\n );\n }\n\n /**\n * Fase 2: Sequência com aguardar\n * Valida: sequência + pausas entre mudanças\n */\n validateFase2(history, config, gameConfig) {\n const esperado = config.expectedCommands;\n\n if (history.length !== esperado.length) {\n return this.failure(\n gameConfig.mensagens?.faltaAguardar ||\n \"Comandos faltando ou em excesso\",\n );\n }\n\n for (let i = 0; i < esperado.length; i++) {\n if (history[i].tipo !== esperado[i].tipo) {\n return this.failure(\n gameConfig.mensagens?.sequenciaIncorreta ||\n \"Sequência de comandos incorreta\",\n );\n }\n\n if (\n esperado[i].tipo === \"semaforo\" &&\n history[i].cor !== esperado[i].cor\n ) {\n return this.failure(\n gameConfig.mensagens?.sequenciaIncorreta ||\n \"Cor do semáforo incorreta\",\n );\n }\n }\n\n return this.success();\n }\n\n /**\n * Fase 3: Carros + pedestres\n * Valida: sincronização entre semáforos de carros e pedestres\n */\n validateFase3(history, config, gameConfig) {\n const esperado = config.expectedCommands;\n\n if (history.length !== esperado.length) {\n return this.failure(\n gameConfig.mensagens?.pedestreErrado ||\n \"Comandos faltando ou em excesso\",\n );\n }\n\n for (let i = 0; i < esperado.length; i++) {\n if (history[i].tipo !== esperado[i].tipo) {\n return this.failure(\n gameConfig.mensagens?.sequenciaIncorreta ||\n \"Tipo de comando incorreto\",\n );\n }\n\n if (\n (history[i].tipo === \"semaforo\" || history[i].tipo === \"pedestre\") &&\n history[i].cor !== esperado[i].cor\n ) {\n return this.failure(\n gameConfig.mensagens?.pedestreErrado || \"Cor incorreta\",\n );\n }\n\n if (\n history[i].tipo === \"aguardar\" &&\n history[i].seg !== esperado[i].seg\n ) {\n return this.failure(\n gameConfig.mensagens?.faltaAguardar || \"Tempo de espera incorreto\",\n );\n }\n }\n\n return this.success();\n }\n\n /**\n * Fase 4: + piscar\n * Valida: inclui piscar da luz do pedestre\n */\n validateFase4(history, config, gameConfig) {\n const esperado = config.expectedCommands;\n\n if (history.length !== esperado.length) {\n return this.failure(\n gameConfig.mensagens?.semPiscar || \"Comandos faltando ou em excesso\",\n );\n }\n\n for (let i = 0; i < esperado.length; i++) {\n if (history[i].tipo !== esperado[i].tipo) {\n return this.failure(\n gameConfig.mensagens?.sequenciaIncorreta ||\n \"Tipo de comando incorreto\",\n );\n }\n\n if (\n (history[i].tipo === \"semaforo\" ||\n history[i].tipo === \"pedestre\" ||\n history[i].tipo === \"piscar\") &&\n history[i].cor !== esperado[i].cor\n ) {\n return this.failure(gameConfig.mensagens?.semPiscar || \"Cor incorreta\");\n }\n\n if (\n (history[i].tipo === \"aguardar\" || history[i].tipo === \"piscar\") &&\n history[i].seg !== esperado[i].seg\n ) {\n return this.failure(\n gameConfig.mensagens?.faltaAguardar || \"Tempo incorreto\",\n );\n }\n }\n\n return this.success();\n }\n\n /**\n * Fase 5: + sons\n * Valida: inclui controle de sons (tocar e parar)\n */\n validateFase5(history, config, gameConfig) {\n const esperado = config.expectedCommands;\n\n if (history.length !== esperado.length) {\n return this.failure(\n gameConfig.mensagens?.semSom || \"Comandos faltando ou em excesso\",\n );\n }\n\n for (let i = 0; i < esperado.length; i++) {\n if (history[i].tipo !== esperado[i].tipo) {\n return this.failure(\n gameConfig.mensagens?.sequenciaIncorreta ||\n \"Tipo de comando incorreto\",\n );\n }\n\n if (\n (history[i].tipo === \"semaforo\" ||\n history[i].tipo === \"pedestre\" ||\n history[i].tipo === \"piscar\") &&\n history[i].cor !== esperado[i].cor\n ) {\n return this.failure(\n gameConfig.mensagens?.sequenciaIncorreta || \"Cor incorreta\",\n );\n }\n\n if (\n (history[i].tipo === \"aguardar\" || history[i].tipo === \"piscar\") &&\n history[i].seg !== esperado[i].seg\n ) {\n return this.failure(\n gameConfig.mensagens?.faltaAguardar || \"Tempo incorreto\",\n );\n }\n\n if (\n (history[i].tipo === \"tocar\" || history[i].tipo === \"parar\") &&\n history[i].som !== esperado[i].som\n ) {\n return this.failure(gameConfig.mensagens?.semSom || \"Som incorreto\");\n }\n }\n\n return this.success();\n }\n}\n\n/**\n * Função de validação exportada para uso no gameController\n */\nexport function validateSolution(history, config, gameConfig, sceneRef) {\n const validator = new SemaforoValidator();\n return validator.validatePhase(history, config, gameConfig, sceneRef);\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/TurtleGame.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,13],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameBase' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":16,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameBase"},"fix":{"range":[58,72],"text":""},"desc":"Remove unused variable 'GameBase'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameEditor"},"fix":{"range":[113,129],"text":""},"desc":"Remove unused variable 'GameEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'BlocklyEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":21,"suggestions":[{"messageId":"removeVar","data":{"varName":"BlocklyEditor"},"fix":{"range":[172,191],"text":""},"desc":"Remove unused variable 'BlocklyEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'CodeEditor' is defined but never used. Allowed unused vars must match /^_/u.","line":5,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":5,"endColumn":18,"suggestions":[{"messageId":"removeVar","data":{"varName":"CodeEditor"},"fix":{"range":[245,261],"text":""},"desc":"Remove unused variable 'CodeEditor'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'GameStateProvider' is defined but never used. Allowed unused vars must match /^_/u.","line":14,"column":3,"nodeType":"Identifier","messageId":"unusedVar","endLine":14,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"GameStateProvider"},"fix":{"range":[495,513],"text":""},"desc":"Remove unused variable 'GameStateProvider'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'TurtleGameContent' is defined but never used. Allowed unused vars must match /^_/u.","line":22,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":22,"endColumn":27,"suggestions":[{"messageId":"removeVar","data":{"varName":"TurtleGameContent"},"fix":{"range":[772,2081],"text":""},"desc":"Remove unused variable 'TurtleGameContent'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React, { useEffect, useMemo } from \"react\";\nimport GameBase from \"../../components/game/GameBase\";\nimport GameEditor from \"../../components/game/GameEditor\";\nimport BlocklyEditor from \"../../components/game/editors/BlocklyEditor\";\nimport CodeEditor from \"../../components/game/editors/CodeEditor\";\nimport { createGame } from \"./game\";\nimport { gameConfig } from \"./config/config\";\nimport {\n registerBlocks,\n turtleToolbox,\n generateDynamicToolbox,\n} from \"./blocks/blocks\";\nimport {\n GameStateProvider,\n useGameState,\n} from \"../../contexts/GameStateContext\";\nimport { useTurtleTour } from \"./hooks/useTurtleTour\";\nimport { debugSolutions } from \"./config/debugSolutions\";\nimport \"shepherd.js/dist/css/shepherd.css\";\nimport \"../../styles/shepherd-theme.css\";\n\nfunction TurtleGameContent() {\n const { currentPhase, setEditorType, isDebugMode, setFailureMessage } =\n useGameState();\n const { startTour } = useTurtleTour();\n\n useEffect(() => {\n registerBlocks();\n }, []);\n\n useEffect(() => {\n if (currentPhase === 10) {\n setEditorType(\"code\");\n } else {\n setEditorType(\"blockly\");\n }\n }, [currentPhase, setEditorType]);\n\n const toolboxGenerator = useMemo(() => {\n const currentPhaseConfig = gameConfig.fases.find(\n (fase) => fase.id === currentPhase,\n );\n\n return () => {\n if (\n currentPhaseConfig?.allowedBlocks &&\n currentPhaseConfig.allowedBlocks.length > 0\n ) {\n return generateDynamicToolbox(currentPhaseConfig.allowedBlocks);\n }\n return turtleToolbox;\n };\n }, [currentPhase]);\n\n const renderEditor = () => {\n if (currentPhase === 10) {\n return ;\n }\n return (\n \n );\n };\n\n return (\n \n {renderEditor()}\n \n );\n}\n\nexport default function TurtleGame() {\n return (\n \n \n \n );\n}\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/__tests__/integration.test.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'id' is defined but never used. Allowed unused args must match /^_/u.","line":556,"column":18,"nodeType":"Identifier","messageId":"unusedVar","endLine":556,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"id"},"fix":{"range":[12264,12266],"text":""},"desc":"Remove unused variable 'id'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'freeDrawCode' is assigned a value but never used. Allowed unused vars must match /^_/u.","line":869,"column":13,"nodeType":"Identifier","messageId":"unusedVar","endLine":869,"endColumn":25,"suggestions":[{"messageId":"removeVar","data":{"varName":"freeDrawCode"},"fix":{"range":[22309,22424],"text":""},"desc":"Remove unused variable 'freeDrawCode'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { describe, it, expect, beforeEach, vi } from \"vitest\";\nimport { GameInterpreter } from \"../../../interpreters/GameInterpreter\";\nimport { setupTurtleAPI } from \"../hooks/interpreterSetup\";\nimport { validateSolution } from \"../validation/validators\";\n\n// Mock de soluções para teste (movido de config/solutions.js)\nconst SOLUTIONS = {\n fase1: `\n var count0 = 0;\n while (count0 < 4) {\n move(100);\n turn(90);\n count0 = count0 + 1;\n }\n `,\n fase1_fail: `\n var count0 = 0;\n while (count0 < 3) {\n move(100);\n turn(90);\n count0 = count0 + 1;\n }\n `,\n fase2: `\n var count1 = 0;\n while (count1 < 5) {\n move(100);\n turn(72);\n count1 = count1 + 1;\n }\n `,\n fase2_fail: `\n var count1 = 0;\n while (count1 < 5) {\n move(100);\n turn(90);\n count1 = count1 + 1;\n }\n `,\n fase3: `\n penColour('#ffff00');\n var count5 = 0;\n while (count5 < 5) {\n move(100);\n turn(144);\n count5 = count5 + 1;\n }\n `,\n fase3_fail: `\n penColour('#ff0000');\n var count5 = 0;\n while (count5 < 5) {\n move(100);\n turn(144);\n count5 = count5 + 1;\n }\n `,\n fase4: `\n penColour('#ffff00');\n var count7 = 0;\n while (count7 < 5) {\n move(50);\n turn(144);\n count7 = count7 + 1;\n }\n penDown(false);\n move(150);\n penDown(true);\n move(20);\n `,\n fase4_fail: `\n penColour('#ffff00');\n var count7 = 0;\n while (count7 < 5) {\n move(50);\n turn(144);\n count7 = count7 + 1;\n }\n move(20);\n `,\n fase5: `\n penColour('#ffff00');\n var count9 = 0;\n while (count9 < 4) {\n var count8 = 0;\n while (count8 < 5) {\n move(50);\n turn(144);\n count8 = count8 + 1;\n }\n penDown(false);\n move(150);\n turn(90);\n penDown(true);\n count9 = count9 + 1;\n }\n `,\n fase5_fail: `\n penColour('#ffff00');\n var count9 = 0;\n while (count9 < 3) {\n var count8 = 0;\n while (count8 < 5) {\n move(50);\n turn(144);\n count8 = count8 + 1;\n }\n penDown(false);\n move(150);\n turn(90);\n penDown(true);\n count9 = count9 + 1;\n }\n `,\n fase6: `\n penColour('#ffff00');\n var count20 = 0;\n while (count20 < 3) {\n var count19 = 0;\n while (count19 < 5) {\n move(50);\n turn(144);\n count19 = count19 + 1;\n }\n penDown(false);\n move(150);\n turn(120);\n penDown(true);\n count20 = count20 + 1;\n }\n penColour('#ffffff');\n penDown(false);\n var count21 = 0;\n while (count21 < 3) {\n turn(90);\n count21 = count21 + 1;\n }\n move(100);\n penDown(true);\n move(50);\n `,\n fase6_fail: `\n penColour('#ffff00');\n var count20 = 0;\n while (count20 < 3) {\n var count19 = 0;\n while (count19 < 5) {\n move(50);\n turn(144);\n count19 = count19 + 1;\n }\n penDown(false);\n move(150);\n turn(120);\n penDown(true);\n count20 = count20 + 1;\n }\n `,\n fase7: `\n penColour('#ffff00');\n var countStars = 0;\n while (countStars < 3) {\n var countPoints = 0;\n while (countPoints < 5) {\n move(50);\n turn(144);\n countPoints = countPoints + 1;\n }\n penDown(false);\n move(150);\n turn(120);\n penDown(true);\n countStars = countStars + 1;\n }\n penDown(false);\n var countTurn = 0;\n while (countTurn < 3) {\n turn(90);\n countTurn = countTurn + 1;\n }\n move(100);\n penDown(true);\n penColour('#ffffff');\n var countRays = 0;\n while (countRays < 4) {\n move(50);\n turn(90);\n turn(90);\n move(50);\n turn(90);\n turn(90);\n turn(45);\n countRays = countRays + 1;\n }\n `,\n fase7_fail: `\n penColour('#ffff00');\n var countStars = 0;\n while (countStars < 3) {\n var countPoints = 0;\n while (countPoints < 5) {\n move(50);\n turn(144);\n countPoints = countPoints + 1;\n }\n penDown(false);\n move(150);\n turn(120);\n penDown(true);\n countStars = countStars + 1;\n }\n `,\n fase8: `\n penColour('#ffff00');\n var countStars = 0;\n while (countStars < 3) {\n var countPoints = 0;\n while (countPoints < 5) {\n move(50);\n turn(144);\n countPoints = countPoints + 1;\n }\n penDown(false);\n move(150);\n turn(120);\n penDown(true);\n countStars = countStars + 1;\n }\n penDown(false);\n var countTurn = 0;\n while (countTurn < 3) {\n turn(90);\n countTurn = countTurn + 1;\n }\n move(100);\n penDown(true);\n penColour('#ffffff');\n var countCircle = 0;\n while (countCircle < 360) {\n move(50);\n turn(90);\n turn(90);\n move(50);\n turn(90);\n turn(90);\n turn(1);\n countCircle = countCircle + 1;\n }\n `,\n fase8_fail: `\n penColour('#ffff00');\n var countStars = 0;\n while (countStars < 3) {\n var countPoints = 0;\n while (countPoints < 5) {\n move(50);\n turn(144);\n countPoints = countPoints + 1;\n }\n penDown(false);\n move(150);\n turn(120);\n penDown(true);\n countStars = countStars + 1;\n }\n penDown(false);\n var countTurn = 0;\n while (countTurn < 3) {\n turn(90);\n countTurn = countTurn + 1;\n }\n move(100);\n penDown(true);\n penColour('#ffffff');\n var countCircle = 0;\n while (countCircle < 180) {\n move(50);\n turn(90);\n turn(90);\n move(50);\n turn(90);\n turn(90);\n turn(1);\n countCircle = countCircle + 1;\n }\n `,\n fase9: `\n penColour('#ffff00');\n var countStars = 0;\n while (countStars < 3) {\n var countPoints = 0;\n while (countPoints < 5) {\n move(50);\n turn(144);\n countPoints = countPoints + 1;\n }\n penDown(false);\n move(150);\n turn(120);\n penDown(true);\n countStars = countStars + 1;\n }\n penDown(false);\n var countTurn = 0;\n while (countTurn < 3) {\n turn(90);\n countTurn = countTurn + 1;\n }\n move(100);\n penDown(true);\n penColour('#ffffff');\n var countCircle1 = 0;\n while (countCircle1 < 360) {\n move(50);\n turn(90);\n turn(90);\n move(50);\n turn(90);\n turn(90);\n turn(1);\n countCircle1 = countCircle1 + 1;\n }\n turn(120);\n move(20);\n penColour('#000000');\n var countCircle2 = 0;\n while (countCircle2 < 360) {\n move(50);\n turn(90);\n turn(90);\n move(50);\n turn(90);\n turn(90);\n turn(1);\n countCircle2 = countCircle2 + 1;\n }\n `,\n fase9_fail: `\n penColour('#ffff00');\n var countStars = 0;\n while (countStars < 2) {\n var countPoints = 0;\n while (countPoints < 5) {\n move(50);\n turn(144);\n countPoints = countPoints + 1;\n }\n penDown(false);\n move(150);\n turn(120);\n penDown(true);\n countStars = countStars + 1;\n }\n penDown(false);\n var countTurn = 0;\n while (countTurn < 3) {\n turn(90);\n countTurn = countTurn + 1;\n }\n move(100);\n penDown(true);\n penColour('#ffffff');\n var countCircle1 = 0;\n while (countCircle1 < 360) {\n move(50);\n turn(90);\n turn(90);\n move(50);\n turn(90);\n turn(90);\n turn(1);\n countCircle1 = countCircle1 + 1;\n }\n `,\n fase10: null,\n fase10_fail: null,\n};\n\n// MOCK DA CONFIGURAÇÃO DO JOGO\n// Replicamos aqui apenas as regras que o validador consome\nconst MOCK_GAME_CONFIG = {\n mensagens: {\n semDesenho:\n \"Você não desenhou nada! Certifique-se de usar os comandos move() com a caneta abaixada.\",\n desenhoNaoConfere:\n \"O desenho não está correto. Verifique a forma, posição e cores.\",\n erroGeral: \"Erro técnico durante a validação.\",\n sucessoGenerico: \"Perfeito! Seu desenho está correto.\",\n timeoutExcedido: \"Tempo limite excedido!\",\n },\n fases: [\n { id: 1, nome: \"O Quadrado\", requiredDrawingMatch: true },\n { id: 2, nome: \"O Pentágono\", requiredDrawingMatch: true },\n { id: 3, nome: \"A Estrela\", requiredDrawingMatch: true },\n { id: 4, nome: \"Estrela Colorida\", requiredDrawingMatch: true },\n { id: 5, nome: \"Três Estrelas\", requiredDrawingMatch: true },\n { id: 6, nome: \"Composição\", requiredDrawingMatch: true },\n { id: 7, nome: \"Três Estrelas e Raios\", requiredDrawingMatch: true },\n { id: 8, nome: \"Três Estrelas e um Círculo\", requiredDrawingMatch: true },\n { id: 9, nome: \"Lua Crescente\", requiredDrawingMatch: true },\n { id: 10, nome: \"Desafio Livre\", requiredDrawingMatch: false },\n ],\n};\n\n/**\n * Mock do Graphics do Phaser\n * Simula o comportamento de desenho sem renderizar na tela\n */\nclass MockGraphics {\n constructor() {\n this.commandBuffer = [];\n this.lineStyle = vi.fn();\n this.fillStyle = vi.fn();\n this.beginPath = vi.fn();\n this.moveTo = vi.fn((x, y) => {\n this.commandBuffer.push({ type: \"moveTo\", x, y });\n });\n this.lineTo = vi.fn((x, y) => {\n this.commandBuffer.push({ type: \"lineTo\", x, y });\n });\n this.strokePath = vi.fn();\n this.fillRect = vi.fn();\n this.clear = vi.fn(() => {\n this.commandBuffer = [];\n });\n }\n\n // Simula extração de pontos para validação\n getPoints() {\n return this.commandBuffer\n .filter((cmd) => cmd.type === \"lineTo\" || cmd.type === \"moveTo\")\n .map((cmd) => ({ x: cmd.x, y: cmd.y }));\n }\n}\n\n/**\n * Cena Headless do Turtle Game (sem renderização gráfica)\n * Simula toda a lógica de desenho e estado necessária para os testes\n */\nclass HeadlessTurtleScene {\n constructor() {\n // Estado da tartaruga\n this.turtleX = 400;\n this.turtleY = 300;\n this.turtleAngle = -90; // Começa apontando para cima\n this.penIsDown = true;\n this.penColor = \"#FFFFFF\";\n\n // Graphics\n this.playerGraphics = new MockGraphics();\n this.validationGraphics = new MockGraphics();\n this.activeGraphics = this.playerGraphics;\n\n // Histórico de ações\n this.historico = [];\n\n // Velocidade de execução\n this.executionSpeed = 50;\n\n // Mock do som\n this.sound = { play: vi.fn() };\n }\n\n // ==================== API PÚBLICA ====================\n\n /**\n * Move a tartaruga para frente\n */\n move(distance) {\n this.historico.push({\n action: \"move\",\n distance,\n timestamp: Date.now(),\n });\n\n if (this.penIsDown) {\n // Calcula nova posição\n const radians = (this.turtleAngle * Math.PI) / 180;\n const startX = this.turtleX;\n const startY = this.turtleY;\n const endX = this.turtleX + Math.cos(radians) * distance;\n const endY = this.turtleY + Math.sin(radians) * distance;\n\n // Desenha linha\n this.activeGraphics.moveTo(startX, startY);\n this.activeGraphics.lineTo(endX, endY);\n\n // Atualiza posição\n this.turtleX = endX;\n this.turtleY = endY;\n } else {\n // Move sem desenhar\n const radians = (this.turtleAngle * Math.PI) / 180;\n this.turtleX += Math.cos(radians) * distance;\n this.turtleY += Math.sin(radians) * distance;\n }\n\n // Retorna promise resolvida imediatamente (sem delay, como no jogo real quando gera solução)\n return Promise.resolve();\n }\n\n /**\n * Gira a tartaruga\n */\n turn(angle) {\n this.historico.push({\n action: \"turn\",\n angle,\n timestamp: Date.now(),\n });\n\n this.turtleAngle = (this.turtleAngle + angle) % 360;\n return Promise.resolve();\n }\n\n /**\n * Controla se a caneta está abaixada (desenha) ou levantada (não desenha)\n */\n penDown(isDown) {\n this.historico.push({\n action: \"penDown\",\n isDown,\n timestamp: Date.now(),\n });\n\n this.penIsDown = isDown;\n }\n\n /**\n * Define a cor da caneta\n */\n penColour(color) {\n this.historico.push({\n action: \"penColour\",\n color,\n timestamp: Date.now(),\n });\n\n this.penColor = color;\n }\n\n /**\n * Pinta o fundo (não usado na validação)\n */\n pintarFundo(color) {\n this.historico.push({\n action: \"pintarFundo\",\n color,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Mock do highlightBlock (não faz nada nos testes)\n */\n highlightBlock(id) {\n // No-op nos testes\n }\n\n // ==================== VALIDAÇÃO ====================\n\n /**\n * Compara o desenho do jogador com o desenho de validação (solução)\n * Retorna true se os desenhos são suficientemente similares\n */\n compareDrawings() {\n const playerPoints = this.playerGraphics.getPoints();\n const validationPoints = this.validationGraphics.getPoints();\n\n // Se não há pontos no desenho do jogador, falha\n if (playerPoints.length === 0) {\n return false;\n }\n\n // Se não há desenho de validação, assume que não há comparação necessária\n if (validationPoints.length === 0) {\n return playerPoints.length > 0;\n }\n\n // Verifica se ambos têm aproximadamente o mesmo número de pontos\n // (tolerância de 20% para variações de implementação)\n const pointRatio = playerPoints.length / validationPoints.length;\n if (pointRatio < 0.8 || pointRatio > 1.2) {\n return false;\n }\n\n // Compara assinaturas topológicas simplificadas\n const playerSignature = this._getSimpleSignature(playerPoints);\n const validationSignature = this._getSimpleSignature(validationPoints);\n\n return this._compareSignatures(playerSignature, validationSignature);\n }\n\n /**\n * Gera uma assinatura simplificada do desenho\n * (bounding box + contagem de segmentos)\n */\n _getSimpleSignature(points) {\n if (points.length === 0)\n return { minX: 0, maxX: 0, minY: 0, maxY: 0, segments: 0 };\n\n const xs = points.map((p) => p.x);\n const ys = points.map((p) => p.y);\n\n return {\n minX: Math.min(...xs),\n maxX: Math.max(...xs),\n minY: Math.min(...ys),\n maxY: Math.max(...ys),\n segments: points.length - 1,\n };\n }\n\n /**\n * Compara duas assinaturas com tolerância\n */\n _compareSignatures(sig1, sig2) {\n const tolerance = 0.15; // 15% de tolerância\n\n // Compara dimensões\n const width1 = sig1.maxX - sig1.minX;\n const height1 = sig1.maxY - sig1.minY;\n const width2 = sig2.maxX - sig2.minX;\n const height2 = sig2.maxY - sig2.minY;\n\n const widthRatio = Math.abs(width1 - width2) / Math.max(width1, width2);\n const heightRatio =\n Math.abs(height1 - height2) / Math.max(height1, height2);\n\n if (widthRatio > tolerance || heightRatio > tolerance) {\n return false;\n }\n\n // Compara número de segmentos\n const segmentRatio =\n Math.abs(sig1.segments - sig2.segments) /\n Math.max(sig1.segments, sig2.segments);\n if (segmentRatio > tolerance) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Gera o desenho de validação executando o código da solução\n */\n async generateValidationDrawing(solutionCode) {\n if (!solutionCode) return;\n\n // Salva estado atual\n const savedGraphics = this.activeGraphics;\n const savedX = this.turtleX;\n const savedY = this.turtleY;\n const savedAngle = this.turtleAngle;\n const savedPenDown = this.penIsDown;\n\n // Reseta para desenho de validação\n this.activeGraphics = this.validationGraphics;\n this.validationGraphics.clear();\n this.turtleX = 400;\n this.turtleY = 300;\n this.turtleAngle = -90;\n this.penIsDown = true;\n\n // Executa o código da solução\n const api = setupTurtleAPI(this);\n const interpreter = new GameInterpreter({ stepDelay: 0, pauseExec: false });\n\n try {\n await interpreter.executeCode(solutionCode, api);\n } catch (error) {\n console.error(\"Erro ao gerar desenho de validação:\", error);\n }\n\n // Restaura estado\n this.activeGraphics = savedGraphics;\n this.turtleX = savedX;\n this.turtleY = savedY;\n this.turtleAngle = savedAngle;\n this.penIsDown = savedPenDown;\n }\n\n /**\n * Reseta o estado da tartaruga\n */\n resetTurtle() {\n this.turtleX = 400;\n this.turtleY = 300;\n this.turtleAngle = -90;\n this.penIsDown = true;\n this.penColor = \"#FFFFFF\";\n this.playerGraphics.clear();\n this.historico = [];\n }\n}\n\n// ==================== SUITE DE TESTES ====================\n\ndescribe(\"Turtle Game - Integração de Lógica (Código -> Desenho -> Validação)\", () => {\n let scene;\n let interpreter;\n\n beforeEach(() => {\n scene = new HeadlessTurtleScene();\n interpreter = new GameInterpreter({ stepDelay: 0, pauseExec: false });\n });\n\n /**\n * Fluxo completo de teste:\n * 1. Executa código do aluno (popula playerGraphics)\n * 2. Gera desenho de validação (solução)\n * 3. Valida comparando os desenhos\n */\n const runFlow = async (playerCode, solutionCode, phaseId) => {\n const api = setupTurtleAPI(scene);\n\n // 1. Executa código do aluno (desenha no playerGraphics)\n scene.activeGraphics = scene.playerGraphics;\n scene.resetTurtle(); // Garante estado limpo\n await interpreter.executeCode(playerCode, api);\n\n // 2. Gera desenho de validação\n await scene.generateValidationDrawing(solutionCode);\n\n // 3. Valida\n const configFase = MOCK_GAME_CONFIG.fases.find((f) => f.id === phaseId);\n return validateSolution(\n scene.historico,\n configFase,\n MOCK_GAME_CONFIG,\n scene,\n );\n };\n\n // ==================== TESTES DE FASES ====================\n\n describe(\"Fase 1: O Quadrado\", () => {\n it(\"Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase1, SOLUTIONS.fase1, 1);\n expect(result.success).toBe(true);\n });\n\n it(\"Deve reprovar solução incorreta (3 lados ao invés de 4)\", async () => {\n const result = await runFlow(SOLUTIONS.fase1_fail, SOLUTIONS.fase1, 1);\n expect(result.success).toBe(false);\n expect(result.reason).toContain(\"não está correto\");\n });\n\n it(\"Deve registrar ações no histórico\", async () => {\n const api = setupTurtleAPI(scene);\n await interpreter.executeCode(SOLUTIONS.fase1, api);\n\n expect(scene.historico.length).toBeGreaterThan(0);\n expect(scene.historico.some((h) => h.action === \"move\")).toBe(true);\n expect(scene.historico.some((h) => h.action === \"turn\")).toBe(true);\n });\n });\n\n describe(\"Fase 2: O Pentágono\", () => {\n it(\"Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase2, SOLUTIONS.fase2, 2);\n expect(result.success).toBe(true);\n });\n\n it(\"Deve reprovar solução incorreta (ângulos errados)\", async () => {\n const result = await runFlow(SOLUTIONS.fase2_fail, SOLUTIONS.fase2, 2);\n expect(result.success).toBe(false);\n expect(result.reason).toContain(\"não está correto\");\n });\n });\n\n describe(\"Fase 3: A Estrela\", () => {\n it(\"Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase3, SOLUTIONS.fase3, 3);\n expect(result.success).toBe(true);\n });\n\n it(\"Deve reprovar solução incorreta (4 pontas ao invés de 5)\", async () => {\n // Desenha uma estrela com 4 pontas ao invés de 5\n const wrongCode = `\n var count = 0;\n while (count < 4) {\n move(100);\n turn(144);\n count = count + 1;\n }\n `;\n const result = await runFlow(wrongCode, SOLUTIONS.fase3, 3);\n expect(result.success).toBe(false);\n });\n });\n\n describe(\"Fase 4: Estrela Colorida\", () => {\n it(\"Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase4, SOLUTIONS.fase4, 4);\n expect(result.success).toBe(true);\n });\n\n it(\"Deve reprovar solução incorreta\", async () => {\n const result = await runFlow(SOLUTIONS.fase4_fail, SOLUTIONS.fase4, 4);\n expect(result.success).toBe(false);\n });\n });\n\n describe(\"Fase 5: Três Estrelas\", () => {\n it(\"Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase5, SOLUTIONS.fase5, 5);\n expect(result.success).toBe(true);\n });\n\n it(\"Deve reprovar solução incorreta\", async () => {\n const result = await runFlow(SOLUTIONS.fase5_fail, SOLUTIONS.fase5, 5);\n expect(result.success).toBe(false);\n });\n }, 8000);\n describe(\"Fase 6: Composição\", () => {\n it(\"Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase6, SOLUTIONS.fase6, 6);\n expect(result.success).toBe(true);\n });\n\n it(\"Deve reprovar solução incorreta\", async () => {\n const result = await runFlow(SOLUTIONS.fase6_fail, SOLUTIONS.fase6, 6);\n expect(result.success).toBe(false);\n });\n });\n\n // Fases 7, 8, 9 agora têm soluções implementadas\n\n describe(\"Fase 7: Três Estrelas e Raios\", () => {\n it(\"Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase7, SOLUTIONS.fase7, 7);\n expect(result.success).toBe(true);\n }, 8000);\n\n it(\"Deve reprovar solução incorreta (sem raios brancos)\", async () => {\n const result = await runFlow(SOLUTIONS.fase7_fail, SOLUTIONS.fase7, 7);\n expect(result.success).toBe(false);\n }, 8000);\n });\n\n describe(\"Fase 8: Três Estrelas e um Círculo\", () => {\n it(\"Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase8, SOLUTIONS.fase8, 8);\n expect(result.success).toBe(true);\n }, 180000); // 3 minutos - círculo com 360 iterações\n\n it(\"Deve reprovar solução incorreta (meio círculo)\", async () => {\n const result = await runFlow(SOLUTIONS.fase8_fail, SOLUTIONS.fase8, 8);\n expect(result.success).toBe(false);\n }, 180000);\n });\n\n describe(\"Fase 9: Lua Crescente\", () => {\n it(\"Deve aprovar solução correta\", async () => {\n const result = await runFlow(SOLUTIONS.fase9, SOLUTIONS.fase9, 9);\n expect(result.success).toBe(true);\n }, 180000); // 3 minutos - dois círculos com 360 iterações cada\n\n it(\"Deve reprovar solução incorreta (2 estrelas ao invés de 3)\", async () => {\n const result = await runFlow(SOLUTIONS.fase9_fail, SOLUTIONS.fase9, 9);\n expect(result.success).toBe(false);\n }, 180000);\n });\n\n describe(\"Fase 10: Desafio Livre\", () => {\n it(\"Deve sempre aprovar qualquer código (sem validação)\", async () => {\n const freeDrawCode = `\n move(50);\n turn(45);\n move(50);\n `;\n\n const configFase = MOCK_GAME_CONFIG.fases.find((f) => f.id === 10);\n const result = validateSolution(\n scene.historico,\n configFase,\n MOCK_GAME_CONFIG,\n scene,\n );\n\n expect(result.success).toBe(true);\n });\n\n it(\"Deve aprovar mesmo sem desenho algum\", async () => {\n const configFase = MOCK_GAME_CONFIG.fases.find((f) => f.id === 10);\n const result = validateSolution([], configFase, MOCK_GAME_CONFIG, scene);\n\n expect(result.success).toBe(true);\n });\n });\n\n // ==================== TESTES DE COMPORTAMENTO ====================\n\n describe(\"Comportamento da API\", () => {\n it(\"Deve desenhar apenas quando caneta está abaixada\", async () => {\n const api = setupTurtleAPI(scene);\n\n // Caneta levantada\n scene.penDown(false);\n await interpreter.executeCode(\"move(100);\", api);\n const pointsWithPenUp = scene.playerGraphics.commandBuffer.length;\n\n // Limpa e testa com caneta abaixada\n scene.resetTurtle();\n scene.penDown(true);\n await interpreter.executeCode(\"move(100);\", api);\n const pointsWithPenDown = scene.playerGraphics.commandBuffer.length;\n\n expect(pointsWithPenUp).toBe(0);\n expect(pointsWithPenDown).toBeGreaterThan(0);\n });\n\n it(\"Deve atualizar posição da tartaruga corretamente\", async () => {\n const api = setupTurtleAPI(scene);\n const initialY = scene.turtleY;\n\n // Move para cima (ângulo -90 = norte), então Y deve diminuir\n await interpreter.executeCode(\"move(100);\", api);\n\n // X permanece o mesmo (movimento vertical), Y muda\n expect(scene.turtleY).not.toBe(initialY);\n expect(scene.turtleY).toBeLessThan(initialY); // Moveu para cima\n });\n\n it(\"Deve registrar todas as ações no histórico\", async () => {\n const api = setupTurtleAPI(scene);\n\n await interpreter.executeCode(\n `\n move(100);\n turn(90);\n penDown(false);\n penColour('red');\n `,\n api,\n );\n\n expect(scene.historico).toHaveLength(4);\n expect(scene.historico[0].action).toBe(\"move\");\n expect(scene.historico[1].action).toBe(\"turn\");\n expect(scene.historico[2].action).toBe(\"penDown\");\n expect(scene.historico[3].action).toBe(\"penColour\");\n });\n });\n\n describe(\"Validação Visual\", () => {\n it(\"Deve falhar quando não há desenho do jogador\", async () => {\n const configFase = MOCK_GAME_CONFIG.fases.find((f) => f.id === 1);\n\n // Não executa código, então não há desenho\n const result = validateSolution([], configFase, MOCK_GAME_CONFIG, scene);\n\n expect(result.success).toBe(false);\n expect(result.reason).toContain(\"não desenhou nada\");\n });\n\n it(\"Deve comparar desenhos usando geometria simplificada\", async () => {\n // Desenha dois quadrados idênticos em locais diferentes do código\n const code1 = `\n for (var i = 0; i < 4; i++) {\n move(100);\n turn(90);\n }\n `;\n\n const code2 = `\n var count = 0;\n while (count < 4) {\n move(100);\n turn(90);\n count++;\n }\n `;\n\n const result = await runFlow(code1, code2, 1);\n expect(result.success).toBe(true);\n });\n });\n\n describe(\"Casos Especiais\", () => {\n it(\"Deve tratar configuração de fase ausente\", () => {\n const result = validateSolution([], {}, MOCK_GAME_CONFIG, scene);\n\n expect(result.success).toBe(false);\n expect(result.reason).toContain(\"Erro técnico\");\n });\n\n it(\"Deve tratar ausência de referência à cena\", () => {\n const configFase = MOCK_GAME_CONFIG.fases.find((f) => f.id === 1);\n const result = validateSolution([], configFase, MOCK_GAME_CONFIG, null);\n\n expect(result.success).toBe(false);\n expect(result.reason).toContain(\"Erro técnico\");\n });\n });\n});\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/blocks/blocks.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/config/config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/config/debugSolutions.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/config/tourSteps.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/game.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'e' is defined but never used.","line":586,"column":14,"nodeType":"Identifier","messageId":"unusedVar","endLine":586,"endColumn":15},{"ruleId":"no-unused-vars","severity":1,"message":"'e' is defined but never used.","line":617,"column":14,"nodeType":"Identifier","messageId":"unusedVar","endLine":617,"endColumn":15}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import Phaser from \"phaser\";\nimport { BaseGameScene } from \"../../shared/BaseGameScene.js\";\nimport { GameInterpreter } from \"../../interpreters/GameInterpreter.js\";\nimport { setupTurtleAPI } from \"./hooks/interpreterSetup.js\";\nimport { validateSolution } from \"./validation/validators.js\";\nimport turtleImg1 from \"./assets/1.png\";\nimport turtleImg2 from \"./assets/2.png\";\nimport win from \"./assets/win.mp3\";\nimport fail from \"./assets/fail.mp3\";\n\nconst ASSETS = {\n IMG: { TURTLE1: \"turtle1\", TURTLE2: \"turtle2\" },\n AUDIO: { WIN: \"win\", FAIL: \"fail\" },\n};\n\nconst CONSTANTES = {\n LARGURA: 640,\n ALTURA: 480,\n};\n\nclass TurtleScene extends BaseGameScene {\n constructor() {\n super(\"TurtleScene\");\n\n this.turtleState = null;\n this.turtleSprite = null;\n this.solutionGraphics = null;\n this.playerGraphics = null;\n this.validationGraphics = null;\n this.activeGraphics = null;\n this.backgroundRect = null;\n this.playerColors = [];\n this.solutionColors = [];\n this.executionSpeed = 50;\n this.sliderWidth = 0;\n this.sliderFill = null;\n this.sliderHandle = null;\n this.speedText = null;\n this.playerRT = null;\n this.validationRT = null;\n this.resultadoJogada = \"em_andamento\";\n }\n\n preload() {\n this.preloadGlobalAssets();\n this.load.image(ASSETS.IMG.TURTLE1, turtleImg1);\n this.load.image(ASSETS.IMG.TURTLE2, turtleImg2);\n this.load.audio(ASSETS.AUDIO.WIN, win);\n this.load.audio(ASSETS.AUDIO.FAIL, fail);\n }\n\n init(data) {\n super.init(data);\n this.executionSpeed = 50;\n this.turtleState = {\n x: 0,\n y: 0,\n angle: 0,\n penDown: true,\n penColour: 0xffffff,\n };\n this.playerColors = [];\n this.solutionColors = [];\n this.resultadoJogada = \"em_andamento\";\n }\n\n setExecutionSpeed(speed) {\n this.executionSpeed = Math.max(1, Math.min(100, speed));\n\n if (typeof this.updateSpeedUI === \"function\") {\n this.updateSpeedUI();\n }\n }\n\n updateSpeedUI() {\n if (this.speedText) {\n this.speedText.setText(`Velocidade: ${this.executionSpeed}%`);\n }\n if (this.sliderFill) {\n this.sliderFill.setSize(\n (this.executionSpeed / 100) * this.sliderWidth,\n 12,\n );\n }\n if (this.sliderHandle) {\n this.sliderHandle.x =\n (this.executionSpeed / 100 - 0.5) * this.sliderWidth;\n }\n }\n\n createSpeedControl() {\n const gameWidth = this.game.config.width;\n const gameHeight = this.game.config.height;\n\n this.sliderWidth = Math.min(gameWidth - 40, 300);\n const controlHeight = 50;\n const centerX = gameWidth / 2;\n const bottomY = gameHeight - 35;\n\n const controlsContainer = this.add.container(centerX, bottomY);\n\n const bg = this.add.rectangle(\n 0,\n 0,\n this.sliderWidth + 80,\n controlHeight,\n 0x000000,\n 0.85,\n );\n bg.setOrigin(0.5, 0.5);\n controlsContainer.add(bg);\n\n const sliderBg = this.add.rectangle(0, 8, this.sliderWidth, 12, 0x444444);\n controlsContainer.add(sliderBg);\n\n this.sliderFill = this.add.rectangle(\n -this.sliderWidth / 2,\n 8,\n (this.executionSpeed / 100) * this.sliderWidth,\n 28,\n 0x00ff88,\n );\n this.sliderFill.setOrigin(0, 0.5);\n controlsContainer.add(this.sliderFill);\n\n this.sliderHandle = this.add.circle(\n (this.executionSpeed / 100 - 0.5) * this.sliderWidth,\n 8,\n 16,\n 0xffffff,\n );\n this.sliderHandle.setInteractive({ useHandCursor: true });\n this.sliderHandle.setStrokeStyle(2, 0x333333);\n controlsContainer.add(this.sliderHandle);\n\n this.speedText = this.add.text(\n 0,\n -12,\n `Velocidade: ${this.executionSpeed}%`,\n {\n fontSize: \"14px\",\n fill: \"#ffffff\",\n fontFamily: \"Arial\",\n },\n );\n this.speedText.setOrigin(0.5, 0.5);\n controlsContainer.add(this.speedText);\n\n let isDragging = false;\n\n this.sliderHandle.on(\"pointerdown\", () => {\n isDragging = true;\n });\n\n this.input.on(\"pointermove\", (pointer) => {\n if (isDragging) {\n const localX = pointer.x - centerX;\n const clampedX = Math.max(\n -this.sliderWidth / 2,\n Math.min(this.sliderWidth / 2, localX),\n );\n const newSpeed = Math.round(\n ((clampedX + this.sliderWidth / 2) / this.sliderWidth) * 100,\n );\n this.setExecutionSpeed(newSpeed);\n }\n });\n\n this.input.on(\"pointerup\", () => {\n isDragging = false;\n });\n\n sliderBg.setInteractive();\n sliderBg.on(\"pointerdown\", (pointer) => {\n const localX = pointer.x - centerX;\n const clampedX = Math.max(\n -this.sliderWidth / 2,\n Math.min(this.sliderWidth / 2, localX),\n );\n const newSpeed = Math.round(\n ((clampedX + this.sliderWidth / 2) / this.sliderWidth) * 100,\n );\n this.setExecutionSpeed(newSpeed);\n });\n\n controlsContainer.setDepth(9999);\n }\n\n calcDuration() {\n return 500 + ((1 - 500) / (100 - 1)) * (this.executionSpeed - 1);\n }\n\n resetTurtle() {\n this.turtleState.x = this.game.config.width / 2;\n this.turtleState.y = this.game.config.height / 2;\n this.turtleState.angle = 0;\n this.turtleState.penDown = true;\n this.turtleState.penColour = 0xffffff;\n\n if (this.turtleSprite) {\n this.turtleSprite.setPosition(this.turtleState.x, this.turtleState.y);\n this.turtleSprite.setAngle(0);\n this.turtleSprite.stop();\n this.turtleSprite.setTexture(ASSETS.IMG.TURTLE1);\n }\n }\n\n pintarFundo(color) {\n let colorValue;\n\n if (typeof color === \"string\") {\n if (color.startsWith(\"#\")) {\n colorValue = parseInt(color.substring(1), 16);\n } else {\n const colorMap = {\n vermelho: 0xff0000,\n azul: 0x0000ff,\n verde: 0x00ff00,\n amarelo: 0xffff00,\n branco: 0xffffff,\n preto: 0x000000,\n };\n colorValue = colorMap[color.toLowerCase()] || 0x000000;\n }\n } else {\n colorValue = color;\n }\n\n if (this.backgroundRect) {\n this.backgroundRect.destroy();\n }\n\n this.backgroundRect = this.add.rectangle(\n this.game.config.width / 2,\n this.game.config.height / 2,\n this.game.config.width,\n this.game.config.height,\n colorValue,\n );\n this.backgroundRect.setDepth(-1000);\n }\n\n addColorToActiveGraphics() {\n const colorArray =\n this.activeGraphics === this.playerGraphics\n ? this.playerColors\n : this.solutionColors;\n\n if (!colorArray.includes(this.turtleState.penColour)) {\n colorArray.push(this.turtleState.penColour);\n }\n }\n\n _moveInstant(distance) {\n const lastX = this.turtleState.x;\n const lastY = this.turtleState.y;\n const angleRad = Phaser.Math.DegToRad(this.turtleState.angle);\n\n this.turtleState.x += Math.cos(angleRad) * distance;\n this.turtleState.y -= Math.sin(angleRad) * distance;\n\n if (this.turtleState.penDown && this.activeGraphics) {\n this.activeGraphics.lineStyle(4, this.turtleState.penColour, 1);\n this.activeGraphics.lineBetween(\n lastX,\n lastY,\n this.turtleState.x,\n this.turtleState.y,\n );\n this.addColorToActiveGraphics();\n }\n }\n\n _turnInstant(angle) {\n this.turtleState.angle += angle;\n this.turtleState.angle = this.turtleState.angle % 360;\n if (this.turtleState.angle < 0) {\n this.turtleState.angle += 360;\n }\n }\n\n highlightBlock(id) {\n if (this.workspace) this.workspace.highlightBlock(id);\n this.highlightPause = true;\n }\n\n move(distance) {\n this.historico.push({ tipo: \"move\", distancia: distance });\n\n return new Promise((resolve) => {\n const duration = this.calcDuration();\n const startX = this.turtleState.x;\n const startY = this.turtleState.y;\n const angleRad = Phaser.Math.DegToRad(this.turtleState.angle);\n const targetX = this.turtleState.x + Math.cos(angleRad) * distance;\n const targetY = this.turtleState.y - Math.sin(angleRad) * distance;\n\n this.turtleState.x = targetX;\n this.turtleState.y = targetY;\n\n this.turtleSprite.play(\"turtle_walk\");\n\n this.tweens.add({\n targets: this.turtleSprite,\n x: targetX,\n y: targetY,\n duration: duration,\n ease: \"Linear\",\n onComplete: () => {\n this.turtleSprite.stop();\n this.turtleSprite.setTexture(ASSETS.IMG.TURTLE1);\n\n if (this.turtleState.penDown && this.activeGraphics) {\n this.activeGraphics.lineStyle(4, this.turtleState.penColour, 1);\n this.activeGraphics.lineBetween(\n startX,\n startY,\n this.turtleState.x,\n this.turtleState.y,\n );\n this.addColorToActiveGraphics();\n }\n\n resolve();\n },\n });\n });\n }\n\n turn(angle) {\n this.historico.push({ tipo: \"turn\", angulo: angle });\n\n return new Promise((resolve) => {\n const duration = this.calcDuration();\n this._turnInstant(angle);\n\n const currentSpriteAngle = this.turtleSprite.angle;\n const targetSpriteAngle = -this.turtleState.angle;\n\n let angleDiff = targetSpriteAngle - currentSpriteAngle;\n\n while (angleDiff > 180) angleDiff -= 360;\n while (angleDiff < -180) angleDiff += 360;\n\n const finalAngle = currentSpriteAngle + angleDiff;\n\n this.tweens.add({\n targets: this.turtleSprite,\n angle: finalAngle,\n duration: duration,\n ease: \"Linear\",\n onComplete: () => {\n resolve();\n },\n });\n });\n }\n\n penDown(isDown) {\n this.historico.push({ tipo: \"penDown\", valor: isDown });\n this.turtleState.penDown = isDown;\n }\n\n penColour(color) {\n this.historico.push({ tipo: \"penColour\", cor: color });\n\n if (typeof color === \"string\") {\n if (color.startsWith(\"#\")) {\n this.turtleState.penColour = parseInt(color.substring(1), 16);\n } else {\n const colorMap = {\n vermelho: 0xff0000,\n azul: 0x0000ff,\n verde: 0x00ff00,\n amarelo: 0xffff00,\n branco: 0xffffff,\n preto: 0x000000,\n };\n this.turtleState.penColour = colorMap[color.toLowerCase()] || 0xffffff;\n }\n } else {\n this.turtleState.penColour = color;\n }\n\n this.addColorToActiveGraphics();\n }\n\n extractPointsFromGraphics(graphics) {\n const points = [];\n let i = 0;\n\n while (i < graphics.commandBuffer.length) {\n const cmd = graphics.commandBuffer[i];\n if (\n cmd === 6 &&\n i + 11 < graphics.commandBuffer.length &&\n graphics.commandBuffer[i + 1] === 4 &&\n graphics.commandBuffer[i + 5] === 5 &&\n graphics.commandBuffer[i + 8] === 4 &&\n graphics.commandBuffer[i + 11] === 9\n ) {\n const x1 = graphics.commandBuffer[i + 6];\n const y1 = graphics.commandBuffer[i + 7];\n const x2 = graphics.commandBuffer[i + 9];\n const y2 = graphics.commandBuffer[i + 10];\n\n points.push({ x: x1, y: y1 });\n points.push({ x: x2, y: y2 });\n i += 12;\n } else {\n i++;\n }\n }\n\n return points;\n }\n\n getDrawingSignature(graphics) {\n if (!graphics.commandBuffer || graphics.commandBuffer.length === 0) {\n return null;\n }\n\n const points = this.extractPointsFromGraphics(graphics);\n if (points.length === 0) {\n return null;\n }\n\n let sumX = 0,\n sumY = 0;\n let minX = Infinity,\n minY = Infinity;\n let maxX = -Infinity,\n maxY = -Infinity;\n\n points.forEach((p) => {\n sumX += p.x;\n sumY += p.y;\n minX = Math.min(minX, p.x);\n minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x);\n maxY = Math.max(maxY, p.y);\n });\n\n const pointCount = points.length;\n const centroid = { x: sumX / pointCount, y: sumY / pointCount };\n const normalizedCentroid = {\n x: centroid.x - minX,\n y: centroid.y - minY,\n };\n\n return {\n bounds: { x: minX, y: minY, width: maxX - minX, height: maxY - minY },\n centroid: normalizedCentroid,\n };\n }\n\n compareColors(playerColors, solutionColors) {\n if (playerColors.length !== solutionColors.length) return false;\n\n const sortedPlayer = [...playerColors].sort();\n const sortedSolution = [...solutionColors].sort();\n\n return sortedSolution.every(\n (color, index) => sortedPlayer[index] === color,\n );\n }\n\n getTopologicalSignature(graphics) {\n if (!graphics.commandBuffer || graphics.commandBuffer.length === 0) {\n return null;\n }\n\n const points = this.extractPointsFromGraphics(graphics);\n\n if (points.length < 3) {\n return { curvatureSum: 0, pointCount: points.length };\n }\n\n let curvatureSum = 0;\n for (let j = 1; j < points.length - 1; j++) {\n const p0 = points[j - 1];\n const p1 = points[j];\n const p2 = points[j + 1];\n\n const v1 = { x: p1.x - p0.x, y: p1.y - p0.y };\n const v2 = { x: p2.x - p1.x, y: p2.y - p1.y };\n\n const crossProduct = v1.x * v2.y - v1.y * v2.x;\n curvatureSum += crossProduct;\n }\n\n return {\n curvatureSum: curvatureSum,\n pointCount: points.length,\n isClockwise: curvatureSum < 0,\n absoluteCurvature: Math.abs(curvatureSum),\n };\n }\n\n compareDrawings() {\n if (!this.compareColors(this.playerColors, this.solutionColors)) {\n return false;\n }\n\n const playerSig = this.getDrawingSignature(this.playerGraphics);\n const solutionSig = this.getDrawingSignature(this.validationGraphics);\n\n if (!playerSig || !solutionSig) {\n return false;\n }\n\n const pb = playerSig.bounds;\n const sb = solutionSig.bounds;\n\n const dimensionTolerance = Math.max(sb.width, sb.height, 1) * 0.05;\n if (\n Math.abs(pb.width - sb.width) > dimensionTolerance ||\n Math.abs(pb.height - sb.height) > dimensionTolerance\n ) {\n return false;\n }\n\n const posX_diff = Math.abs(pb.x - sb.x);\n const posY_diff = Math.abs(pb.y - sb.y);\n if (posX_diff > 1.5 || posY_diff > 1.5) {\n return false;\n }\n\n const centroidTolerance = 1.5;\n const centroidDeltaX = Math.abs(\n playerSig.centroid.x - solutionSig.centroid.x,\n );\n const centroidDeltaY = Math.abs(\n playerSig.centroid.y - solutionSig.centroid.y,\n );\n\n if (\n centroidDeltaX > centroidTolerance ||\n centroidDeltaY > centroidTolerance\n ) {\n return false;\n }\n\n const playerTopo = this.getTopologicalSignature(this.playerGraphics);\n const solutionTopo = this.getTopologicalSignature(this.validationGraphics);\n\n if (!playerTopo || !solutionTopo) {\n return false;\n }\n\n if (\n playerTopo.isClockwise !== solutionTopo.isClockwise &&\n Math.abs(playerTopo.absoluteCurvature) > 10\n ) {\n return false;\n }\n\n return true;\n }\n\n drawSolution() {\n const configFase = this.registry.get(\"configFase\");\n if (!configFase || !configFase.solutionCode) {\n return;\n }\n\n this.solutionColors = [];\n this.activeGraphics = this.solutionGraphics;\n this.resetTurtle();\n this.turtleState.penColour = 0xffffff;\n\n const move = this._moveInstant.bind(this);\n const turn = this._turnInstant.bind(this);\n const penDown = this.penDown.bind(this);\n const penColour = this.penColour.bind(this);\n\n try {\n const fn = new Function(\n \"move\",\n \"turn\",\n \"penDown\",\n \"penColour\",\n configFase.solutionCode,\n );\n fn(move, turn, penDown, penColour);\n } catch (e) {\n // Erro silencioso - desenho de solução não é crítico\n }\n }\n\n generateValidationDrawing() {\n const configFase = this.registry.get(\"configFase\");\n if (!configFase || !configFase.solutionCode) {\n return;\n }\n\n this.validationGraphics.clear();\n this.solutionColors = [];\n this.activeGraphics = this.validationGraphics;\n this.resetTurtle();\n this.turtleState.penColour = 0xffffff;\n\n const move = this._moveInstant.bind(this);\n const turn = this._turnInstant.bind(this);\n const penDown = this.penDown.bind(this);\n const penColour = this.penColour.bind(this);\n\n try {\n const fn = new Function(\n \"move\",\n \"turn\",\n \"penDown\",\n \"penColour\",\n configFase.solutionCode,\n );\n fn(move, turn, penDown, penColour);\n } catch (e) {\n // Erro silencioso - desenho de validação não é crítico\n }\n }\n\n onBeforeRun() {\n this.playerGraphics.clear();\n this.activeGraphics = this.playerGraphics;\n this.resetTurtle();\n this.playerColors = [];\n this.resultadoJogada = \"em_andamento\";\n this.solutionGraphics.clear();\n this.drawSolution();\n this.generateValidationDrawing();\n this.activeGraphics = this.playerGraphics;\n this.resetTurtle();\n }\n\n onReset() {\n this.playerGraphics.clear();\n this.solutionGraphics.clear();\n this.resetTurtle();\n this.activeGraphics = this.playerGraphics;\n this.drawSolution();\n this.playerColors = [];\n this.solutionColors = [];\n this.resultadoJogada = \"em_andamento\";\n }\n\n onSuccess() {\n const configFase = this.registry.get(\"configFase\");\n if (configFase && configFase.id === 10) return;\n this.playAudio(ASSETS.AUDIO.WIN);\n }\n\n onFailure() {\n this.playAudio(ASSETS.AUDIO.FAIL);\n }\n\n create() {\n this.createSpeedControl();\n\n this.anims.create({\n key: \"turtle_walk\",\n frames: [{ key: ASSETS.IMG.TURTLE1 }, { key: ASSETS.IMG.TURTLE2 }],\n frameRate: 8,\n repeat: -1,\n });\n\n this.solutionGraphics = this.add.graphics();\n this.playerGraphics = this.add.graphics();\n this.solutionGraphics.setAlpha(0.3);\n this.validationGraphics = this.add.graphics().setVisible(false);\n this.playerRT = this.add\n .renderTexture(0, 0, CONSTANTES.LARGURA, CONSTANTES.ALTURA)\n .setVisible(false);\n this.validationRT = this.add\n .renderTexture(0, 0, CONSTANTES.LARGURA, CONSTANTES.ALTURA)\n .setVisible(false);\n this.activeGraphics = this.playerGraphics;\n\n this.turtleSprite = this.add.sprite(\n CONSTANTES.LARGURA / 2,\n CONSTANTES.ALTURA / 2,\n ASSETS.IMG.TURTLE1,\n );\n this.turtleSprite.setOrigin(0.5, 0.5);\n this.turtleSprite.setAngle(0);\n this.turtleSprite.setDepth(1000);\n\n this.gameInterpreter = new GameInterpreter({ stepDelay: 500 });\n this.setExecutionSpeed(this.executionSpeed);\n this.drawSolution();\n\n this.setupStandardController(\n setupTurtleAPI,\n (history, config, gameConfig) =>\n validateSolution(history, config, gameConfig, this),\n );\n }\n}\n\nexport const createGame = (\n parentElement,\n configFaseAtual,\n customFailureHandler = null,\n idFaseAtual = null,\n gameConfig = null,\n) => {\n const config =\n idFaseAtual && gameConfig\n ? gameConfig.fases[idFaseAtual - 1]\n : configFaseAtual;\n\n return {\n type: Phaser.AUTO,\n width: CONSTANTES.LARGURA,\n height: CONSTANTES.ALTURA,\n backgroundColor: \"#171616\",\n antialias: true,\n roundPixels: true,\n pixelArt: false,\n parent: parentElement,\n scale: {\n mode: Phaser.Scale.FIT,\n autoCenter: Phaser.Scale.CENTER_BOTH,\n zoom: 5,\n },\n scene: [TurtleScene],\n callbacks: {\n preBoot: (game) => {\n game.registry.merge({\n configFase: config,\n gameConfig: gameConfig,\n customFailureHandler: customFailureHandler,\n stepDelay: 500,\n });\n },\n },\n };\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/hooks/interpreterSetup.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/hooks/useTurtleTour.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/games/turtle/validation/validators.js","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'error' is defined but never used.","line":83,"column":14,"nodeType":"Identifier","messageId":"unusedVar","endLine":83,"endColumn":19}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { BaseGameValidator } from \"../../../shared/BaseGameValidator\";\n\n/**\n * Validador específico do Turtle Game\n *\n * Diferente de outros jogos, o Turtle valida principalmente através de\n * comparação visual de desenhos, não apenas por sequência de ações.\n */\nclass TurtleValidator extends BaseGameValidator {\n /**\n * Valida a solução do aluno baseado no desenho produzido\n *\n * @param {Array} history - Histórico de ações (para debug/estatísticas)\n * @param {Object} config - Configuração da fase atual\n * @param {Object} gameConfig - Configuração global do jogo\n * @param {Object} sceneRef - Referência à cena Phaser (para acessar métodos de comparação)\n * @returns {Object} { success: boolean, reason?: string }\n */\n validatePhase(history, config, gameConfig, sceneRef) {\n // 1. Fail-Safe: Verificar se a configuração foi passada\n if (!config || Object.keys(config).length === 0) {\n return this.failure(\n gameConfig?.mensagens?.erroGeral ||\n \"Erro técnico: Fase não configurada.\",\n );\n }\n\n // 2. Fase 10 (Desafio Livre) - Sempre sucesso\n // Também aceita fases com requiredDrawingMatch = false\n if (config.id === 10 || config.requiredDrawingMatch === false) {\n return this.success();\n }\n\n // 3. Verificar se há referência à cena (necessária para comparação visual)\n if (!sceneRef) {\n return this.failure(\n gameConfig?.mensagens?.erroGeral || \"Erro técnico na validação.\",\n );\n }\n\n // 4. Fases 1-9: Validar desenho produzido\n return this._validateDrawing(sceneRef, config, gameConfig);\n }\n\n /**\n * Valida se o desenho do jogador corresponde à solução esperada\n * Método privado chamado apenas por validatePhase() para fases 1-9\n *\n * @param {Object} scene - Referência à cena Phaser\n * @param {Object} config - Configuração da fase\n * @param {Object} gameConfig - Configuração global\n * @returns {Object} { success: boolean, reason?: string }\n * @private\n */\n _validateDrawing(scene, config, gameConfig) {\n try {\n // 1. Verificar se o jogador desenhou algo\n const hasPlayerDrawing = this._hasPlayerDrawing(scene);\n\n if (!hasPlayerDrawing) {\n return this.failure(\n config?.mensagens?.semDesenho ||\n gameConfig?.mensagens?.semDesenho ||\n \"Você não desenhou nada! Certifique-se de usar os comandos move() com a caneta abaixada.\",\n );\n }\n\n // 2. Comparar desenhos usando método da scene (compareDrawings)\n // O método scene.compareDrawings() acessa validationGraphics e playerGraphics\n // que já foram preparados no onBeforeRun() através de generateValidationDrawing()\n const drawingsMatch = scene.compareDrawings();\n\n if (!drawingsMatch) {\n return this.failure(\n config?.mensagens?.desenhoNaoConfere ||\n gameConfig?.mensagens?.desenhoNaoConfere ||\n \"O desenho não está correto. Verifique a forma, posição e cores.\",\n );\n }\n\n // 3. Sucesso - desenho corresponde à solução!\n return this.success();\n } catch (error) {\n return this.failure(\n gameConfig?.mensagens?.erroGeral ||\n \"Erro inesperado durante a validação.\",\n );\n }\n }\n\n /**\n * Verifica se o jogador produziu algum desenho\n * Checa se o commandBuffer do playerGraphics possui comandos de desenho\n *\n * @param {Object} scene - Referência à cena Phaser\n * @returns {boolean} true se há desenho, false caso contrário\n * @private\n */\n _hasPlayerDrawing(scene) {\n return (\n scene.playerGraphics &&\n scene.playerGraphics.commandBuffer &&\n scene.playerGraphics.commandBuffer.length > 0\n );\n }\n\n // --- Métodos Herdados da Base ---\n // success() - retorna { success: true }\n // failure(reason) - retorna { success: false, reason }\n}\n\n// Singleton para reutilização\nconst validatorInstance = new TurtleValidator();\n\n/**\n * Função exportada para validação de soluções do Turtle Game\n *\n * @param {Array} history - Histórico de ações\n * @param {Object} config - Configuração da fase\n * @param {Object} gameConfig - Configuração global\n * @param {Object} sceneRef - Referência à cena (necessário para comparação visual)\n * @returns {Object} { success: boolean, reason?: string }\n */\nexport const validateSolution = (history, config, gameConfig, sceneRef) => {\n return validatorInstance.validatePhase(history, config, gameConfig, sceneRef);\n};\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/hooks/useGameTour.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/hooks/useIsMobile.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/hooks/useTour.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/interpreters/ApiHelpers.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/interpreters/GameInterpreter.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/main.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'React' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":13,"suggestions":[{"messageId":"removeVar","data":{"varName":"React"},"fix":{"range":[7,18],"text":""},"desc":"Remove unused variable 'React'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'App' is defined but never used. Allowed unused vars must match /^_/u.","line":4,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":4,"endColumn":11,"suggestions":[{"messageId":"removeVar","data":{"varName":"App"},"fix":{"range":[160,169],"text":""},"desc":"Remove unused variable 'App'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import React from \"react\";\nimport ReactDOM from \"react-dom/client\";\nimport \"./config/blocklyConfig.js\"; // Configuração global do Blockly (locale PT-BR)\nimport App from \"./App.jsx\";\n\nReactDOM.createRoot(document.getElementById(\"root\")).render();\n","usedDeprecatedRules":[]},{"filePath":"/home/rui/src/new/plataforma-edu/app/src/pages/About/About.jsx","messages":[{"ruleId":"no-unused-vars","severity":1,"message":"'ArrowRight' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":20,"suggestions":[{"messageId":"removeVar","data":{"varName":"ArrowRight"},"fix":{"range":[9,20],"text":""},"desc":"Remove unused variable 'ArrowRight'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Users' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":22,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":27,"suggestions":[{"messageId":"removeVar","data":{"varName":"Users"},"fix":{"range":[19,26],"text":""},"desc":"Remove unused variable 'Users'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Heart' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":29,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":34,"suggestions":[{"messageId":"removeVar","data":{"varName":"Heart"},"fix":{"range":[26,33],"text":""},"desc":"Remove unused variable 'Heart'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Lightbulb' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":36,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":45,"suggestions":[{"messageId":"removeVar","data":{"varName":"Lightbulb"},"fix":{"range":[33,44],"text":""},"desc":"Remove unused variable 'Lightbulb'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Globe' is defined but never used. Allowed unused vars must match /^_/u.","line":1,"column":47,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":52,"suggestions":[{"messageId":"removeVar","data":{"varName":"Globe"},"fix":{"range":[44,51],"text":""},"desc":"Remove unused variable 'Globe'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Navbar' is defined but never used. Allowed unused vars must match /^_/u.","line":2,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":2,"endColumn":14,"suggestions":[{"messageId":"removeVar","data":{"varName":"Navbar"},"fix":{"range":[82,94],"text":""},"desc":"Remove unused variable 'Navbar'."}]},{"ruleId":"no-unused-vars","severity":1,"message":"'Footer' is defined but never used. Allowed unused vars must match /^_/u.","line":3,"column":8,"nodeType":"Identifier","messageId":"unusedVar","endLine":3,"endColumn":14,"suggestions":[{"messageId":"removeVar","data":{"varName":"Footer"},"fix":{"range":[128,140],"text":""},"desc":"Remove unused variable 'Footer'."}]}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":7,"fixableErrorCount":0,"fixableWarningCount":0,"source":"import { ArrowRight, Users, Heart, Lightbulb, Globe } from \"lucide-react\";\nimport Navbar from \"../../components/Navbar\";\nimport Footer from \"../HomePage/Footer\";\n\nexport default function About() {\n return (\n <>\n {/* Navegação */}\n \n\n {/* Background Gradient */}\n \n\n
\n {/* Container principal */}\n
\n
\n {/* Conteúdo textual */}\n
\n

\n Somos Educadores do Núcleo de Tecnologia do MTST\n

\n\n

\n Somos parte do Núcleo de Tecnologia do MTST, e somos\n comprometidos com a democratização do ensino de programação e\n tecnologia. Acreditamos que a educação digital deve ser\n acessível, gratuita e transformadora para todas as pessoas.\n

\n\n

\n Nossa missão é empoderar estudantes e professores através de\n ferramentas pedagógicas abertas, baseadas em metodologias\n críticas e participativas. Trabalhamos para que a tecnologia\n seja um instrumento de inclusão social e desenvolvimento\n comunitário.\n

\n\n

\n O Decoda nasceu dessa visão: uma plataforma educacional que\n valoriza o pensamento computacional como ferramenta de\n transformação social, respeitando a diversidade de saberes e\n promovendo a autonomia pedagógica.\n

\n\n {/* Valores */}\n
\n
\n \n
\n

\n Educação Popular\n

\n

\n Valorizamos o diálogo, a participação coletiva e a\n construção colaborativa do conhecimento.\n

\n
\n
\n\n
\n \n
\n

\n Compromisso Social\n

\n

\n Lutamos por uma tecnologia inclusiva que reduza\n desigualdades e promova justiça social.\n

\n
\n
\n\n
\n \n
\n

\n Inovação Pedagógica\n

\n

\n Criamos métodos de ensino contextualizados, críticos e\n adaptados à realidade brasileira.\n

\n
\n
\n
\n\n {/* CTA */}\n
\n \n \n Conheça Nossa História\n \n \n \n
\n
\n\n {/* Grid de imagens representativas */}\n
\n {/* Card 1: Educação Popular */}\n
\n \n
\n
\n

\n Educação Popular\n

\n

\n Construção coletiva do saber\n

\n
\n
\n
\n\n {/* Card 2: Inclusão Digital */}\n
\n \n
\n
\n

\n Inclusão Digital\n

\n

\n Tecnologia para todos\n

\n
\n
\n
\n\n {/* Card 3: Pensamento Crítico */}\n
\n \n
\n
\n

\n Pensamento Crítico\n

\n

\n Autonomia e reflexão\n

\n
\n
\n
\n\n {/* Card 4: Programação Visual */}\n
\n \n
\n
\n

\n Programação Visual\n

\n

\n Aprender fazendo\n

\n
\n
\n
\n\n {/* Card 5: Transformação Social */}\n
\n \n
\n
\n

\n Transformação Social\n

\n

\n Tecnologia para mudar\n

\n
\n
\n
\n
\n
\n
\n
\n\n {/* Footer */}\n