[{"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