From 1d1c9692dc94f1084457fdd98616bae16c2e6aa1 Mon Sep 17 00:00:00 2001 From: Georgiy Komarov Date: Tue, 15 Oct 2024 04:30:28 +0000 Subject: [PATCH] Deploy site --- .nojekyll | 0 404.html | 21 + CNAME | 1 + assets/css/styles.57cb5423.css | 1 + ...oject-b8656fa4266c0c7923d6b67c7f5950e6.png | Bin 0 -> 11492 bytes assets/js/012e8e66.af4e648f.js | 1 + assets/js/01419b1f.55a4ac68.js | 1 + assets/js/06bf7bd2.93cfb521.js | 1 + assets/js/070671b7.a81bd6a1.js | 1 + assets/js/07f2fad9.76f75bf4.js | 1 + assets/js/0ac52da9.865948a5.js | 1 + assets/js/0b705376.0f6bdf25.js | 1 + assets/js/0c390d31.29054261.js | 1 + assets/js/0c3de8e2.454cb0da.js | 1 + assets/js/0c8d0168.c0afaf27.js | 1 + assets/js/0e4e7ef7.da1fd809.js | 1 + assets/js/0f37fc5e.4a23afc4.js | 1 + assets/js/0fb6ae9c.e2818ac1.js | 1 + assets/js/104c66c9.61be676d.js | 1 + assets/js/122f6b32.f6ee1737.js | 1 + assets/js/1295da86.6c981ca5.js | 1 + assets/js/138db073.578334fd.js | 1 + assets/js/1418388c.6eb86b98.js | 1 + assets/js/150b97d9.3c57e7f9.js | 1 + assets/js/1598dd73.06ff38aa.js | 1 + assets/js/15d13f14.3309e304.js | 1 + assets/js/17406c9d.759681c0.js | 1 + assets/js/17896441.dc05340c.js | 1 + assets/js/1869ccd1.5d76a4bd.js | 1 + assets/js/1a50d306.ff71f994.js | 1 + assets/js/1a8310a1.e63a2b77.js | 1 + assets/js/1b73222b.c47a22da.js | 1 + assets/js/1b960128.5b5b59d9.js | 1 + assets/js/1c26cb06.972f1ca6.js | 1 + assets/js/1df93b7f.4689c496.js | 1 + assets/js/1f391b9e.d1d4beb6.js | 1 + assets/js/2018b81b.63a7c757.js | 1 + assets/js/2237.92070aeb.js | 1 + assets/js/2257d06b.a740c88e.js | 1 + assets/js/23b0c962.e0d7957b.js | 1 + assets/js/2424092d.88efacf6.js | 1 + assets/js/24652b08.91ed48d5.js | 1 + assets/js/26592ea2.2dd4e9ca.js | 1 + assets/js/273168fb.26adb4b1.js | 1 + assets/js/299f32b1.3d9263b4.js | 1 + assets/js/2aa59687.16070803.js | 1 + assets/js/2ace25e9.6114563d.js | 1 + assets/js/2b6a80d0.3d7eb50f.js | 1 + assets/js/2b785902.b83e29b9.js | 1 + assets/js/2bdf0f82.11a0dcc1.js | 1 + assets/js/2cebbb1e.1c80f755.js | 1 + assets/js/2d07d137.1711bd45.js | 1 + assets/js/2f30e490.cf459bb9.js | 1 + assets/js/304edb56.1899324d.js | 1 + assets/js/3658.8fe69683.js | 1 + assets/js/36ebdf3e.c81514b8.js | 1 + assets/js/377c4f81.79a338ae.js | 1 + assets/js/393be207.fc96af0e.js | 1 + assets/js/3b3a1a75.976ba85c.js | 1 + assets/js/3bfe497f.a61d7e8b.js | 1 + assets/js/3db5102b.08380390.js | 1 + assets/js/40be7dfa.be7d2a62.js | 1 + assets/js/42510f93.7a5b306e.js | 1 + assets/js/432cb5a5.17016576.js | 1 + assets/js/43c93918.b3c5c4ff.js | 1 + assets/js/4518efa7.b9ef0cc5.js | 1 + assets/js/474ce197.29e1c442.js | 1 + assets/js/49256311.be5c404d.js | 1 + assets/js/4ab26116.4e3dc2f6.js | 1 + assets/js/4b89306f.efdf0920.js | 1 + assets/js/4d74b396.8aebea31.js | 1 + assets/js/4f2bb7ce.0a476d8d.js | 1 + assets/js/4fd06f05.45b0f688.js | 1 + assets/js/51fe41a6.f649c3d3.js | 1 + assets/js/55e1201d.f5805772.js | 1 + assets/js/563af34e.29a0e834.js | 1 + assets/js/566d8483.942257c5.js | 1 + assets/js/5815e0d3.36349d47.js | 1 + assets/js/59016342.fc899b97.js | 1 + assets/js/5a7ecd5b.08c83086.js | 1 + assets/js/5e95c892.0afa16e4.js | 1 + assets/js/5ec2195c.a723ab4e.js | 1 + assets/js/602c5d84.a9af00d9.js | 1 + assets/js/61c19607.94c232da.js | 1 + assets/js/6362ac9f.aa3d1fc1.js | 1 + assets/js/63a541b5.cf91b4ad.js | 1 + assets/js/63bb535a.ed747652.js | 1 + assets/js/6696f09b.9d59dc8d.js | 1 + assets/js/6934ebe4.7bcf9574.js | 1 + assets/js/693ffdbc.20a90ba4.js | 1 + assets/js/6f277b0e.89006761.js | 1 + assets/js/6f60ccd2.91c6f358.js | 1 + assets/js/719e5d48.0bc6e809.js | 1 + assets/js/72b7ad48.f6676fe3.js | 1 + assets/js/743bfbca.ba311b0c.js | 1 + assets/js/7499c02a.f1eb98f3.js | 1 + assets/js/754ccd45.2081d519.js | 1 + assets/js/76268162.332975fc.js | 1 + assets/js/773c7ee4.d71f2dd0.js | 1 + assets/js/775287ab.a34207ca.js | 1 + assets/js/776efca7.78ead050.js | 1 + assets/js/7b5b3cc2.90aa7fd2.js | 1 + assets/js/81087c81.7da41d03.js | 1 + assets/js/8272dc48.d9a84b38.js | 1 + assets/js/8306354c.2bbb254d.js | 1 + assets/js/844f22a2.2f80fdcf.js | 1 + assets/js/866ed13d.d4edfa4a.js | 1 + assets/js/86d22c3d.22d9a99e.js | 1 + assets/js/86d70222.91cb640f.js | 1 + assets/js/87ce9660.55512f80.js | 1 + assets/js/883df8cc.ec17e966.js | 1 + assets/js/8c01191f.93ad2656.js | 1 + assets/js/8c0243db.7de6da6a.js | 1 + assets/js/8c74c05e.09164805.js | 1 + assets/js/8c9dd45b.c7a96e3d.js | 1 + assets/js/8cf7c613.47582d2c.js | 1 + assets/js/8d6fa39c.f2faae22.js | 1 + assets/js/8d91c04d.ef1dbebb.js | 1 + assets/js/8df82fb6.5a9830a2.js | 1 + assets/js/8e426e62.bf0771c3.js | 1 + assets/js/8e8fe4d7.7a82fd74.js | 1 + assets/js/90b5d830.c162588e.js | 1 + assets/js/91acf703.c00ee771.js | 1 + assets/js/91ee281c.f53980f2.js | 1 + assets/js/94d07e36.7adad0e3.js | 1 + assets/js/96e77fcb.3fb77893.js | 1 + assets/js/972c9666.e5b493f7.js | 1 + assets/js/987a8a5d.bdfcfd74.js | 1 + assets/js/988b076a.3beed1a8.js | 1 + assets/js/9fedf60a.5a24888e.js | 1 + assets/js/a291c19d.f1ac0d98.js | 1 + assets/js/a3df6930.b9e3fcca.js | 1 + assets/js/a4516edb.19e6546c.js | 1 + assets/js/a5055d90.503ae7a2.js | 1 + assets/js/a66f2ff0.c39f76e5.js | 1 + assets/js/a7456010.c6eb9a57.js | 1 + assets/js/a7bd4aaa.1b32332e.js | 1 + assets/js/a7eb4927.90a54648.js | 1 + assets/js/a8c496ca.06cbb22b.js | 1 + assets/js/a8d7d639.ed43e771.js | 1 + assets/js/a94703ab.9f24e801.js | 1 + assets/js/aac87eb6.6b5bbfc3.js | 1 + assets/js/aba21aa0.d087865c.js | 1 + assets/js/acef80f0.ccd7a032.js | 1 + assets/js/aee0b8cc.c78b2bfe.js | 1 + assets/js/b05af762.c54dcfb2.js | 1 + assets/js/b12d76e5.d3ad221e.js | 1 + assets/js/b3799bec.86c01a35.js | 1 + assets/js/b64540ae.4fd9953e.js | 1 + assets/js/b64aaedd.88204f90.js | 1 + assets/js/b78952d0.efed39b1.js | 1 + assets/js/b80eaa74.91abd0f7.js | 1 + assets/js/b91dc83b.a57e29d3.js | 1 + assets/js/bce595e9.46a0cb1c.js | 1 + assets/js/bd72ef9b.45e20252.js | 1 + assets/js/be8ab43b.f4a8e3dd.js | 1 + assets/js/c00ee666.951c69ba.js | 1 + assets/js/c05c6791.1dfb4d97.js | 1 + assets/js/c252c345.a3cf3637.js | 1 + assets/js/c377a04b.8c30a29b.js | 1 + assets/js/c49af6bd.85a90098.js | 1 + assets/js/c55f1521.cb9c8e4f.js | 1 + assets/js/c5c1850c.d97c4482.js | 1 + assets/js/c5d65102.924539a3.js | 1 + assets/js/c7ee6afe.0b86ae18.js | 1 + assets/js/c82192ae.b860298b.js | 1 + assets/js/c926d0d4.30e3ae68.js | 1 + assets/js/c96954fa.f94afa3f.js | 1 + assets/js/ca178ca4.7d6ff74e.js | 1 + assets/js/cb77e040.4c34ff27.js | 1 + assets/js/cc6d1ce2.2f552c48.js | 1 + assets/js/cd411a47.dbdd6a6b.js | 1 + assets/js/ce7f72c2.19df7abf.js | 1 + assets/js/cf2c24d9.167088de.js | 1 + assets/js/cf5f971a.651efe6f.js | 1 + assets/js/d147047e.c3db349f.js | 1 + assets/js/d15cc687.df08049f.js | 1 + assets/js/d1781038.35abe5aa.js | 1 + assets/js/d2aaf676.0ddaefea.js | 1 + assets/js/d2d53d04.404d4960.js | 1 + assets/js/d2f295f4.6d5ee62f.js | 1 + assets/js/d3996cd7.0ca74802.js | 1 + assets/js/d46ee8ed.7ed1c3f4.js | 1 + assets/js/d6f3e79e.d1be0df5.js | 1 + assets/js/d7c99f30.b0b05326.js | 1 + assets/js/d7d99e1d.67e2d007.js | 1 + assets/js/d9542fcf.bbcb88d0.js | 1 + assets/js/dc55925b.1af0a38f.js | 1 + assets/js/dd8730c9.aeb151c7.js | 1 + assets/js/e1c88a01.26b5c812.js | 1 + assets/js/e2ad9c7a.573d9426.js | 1 + assets/js/e3b47995.2fccb84f.js | 1 + assets/js/e3c4fe0a.bf2b73e2.js | 1 + assets/js/e4a43c7d.d2da82aa.js | 1 + assets/js/e5aa38d8.17e7d0ef.js | 1 + assets/js/e63578c3.6cc338fe.js | 1 + assets/js/e6ef21e7.de959db6.js | 1 + assets/js/e9524270.4f13728a.js | 1 + assets/js/ea064c97.7b1162bd.js | 1 + assets/js/ea8d0df0.a9834690.js | 1 + assets/js/ebcc9167.b433e15d.js | 1 + assets/js/ed017323.30666872.js | 1 + assets/js/ed2e6971.1441e217.js | 1 + assets/js/edf1e52e.7e8e467f.js | 1 + assets/js/effcc73a.68126485.js | 1 + assets/js/f18c7db7.502a736a.js | 1 + assets/js/f2bdb0f5.256a666a.js | 1 + assets/js/f3297ff5.b24f1896.js | 1 + assets/js/f3466e67.b2bd9e44.js | 1 + assets/js/f34cb5e0.b26c4fc7.js | 1 + assets/js/f4d075b1.8ca57b63.js | 1 + assets/js/f503d00c.e7655ff6.js | 1 + assets/js/f553073e.8eca43d2.js | 1 + assets/js/f5772bf1.e894af92.js | 1 + assets/js/f58fcc43.833fdf0f.js | 1 + assets/js/f5bf49b8.3b9a5601.js | 1 + assets/js/f6f2b22b.1f2e8cc1.js | 1 + assets/js/f752d1db.9ec62e05.js | 1 + assets/js/f7ab1f3a.096a7a59.js | 1 + assets/js/f97c3fca.6a842194.js | 1 + assets/js/faae61e5.d4f77930.js | 1 + assets/js/fafa7ec8.f8fc7c04.js | 1 + assets/js/fbbe250b.022d69c3.js | 1 + assets/js/fcd86191.e1395157.js | 1 + assets/js/fe7c01fc.f82580ba.js | 1 + assets/js/ff0db780.e64f7648.js | 1 + assets/js/main.0656ce4d.js | 2 + assets/js/main.0656ce4d.js.LICENSE.txt | 81 ++ assets/js/runtime~main.5d851323.js | 1 + img/blueprint-select-project.png | Bin 0 -> 11492 bytes img/cfg-example.svg | 90 ++ img/favicon.png | Bin 0 -> 1486 bytes img/misti.png | Bin 0 -> 489531 bytes index.html | 13 + lib/souffle-js/api/.nojekyll | 1 + lib/souffle-js/api/assets/custom.css | 1 + lib/souffle-js/api/assets/highlight.css | 1 + lib/souffle-js/api/assets/icons.js | 1 + lib/souffle-js/api/assets/icons.svg | 1 + lib/souffle-js/api/assets/main.js | 2 + lib/souffle-js/api/assets/main.js.LICENSE.txt | 54 ++ lib/souffle-js/api/assets/navigation.js | 1 + lib/souffle-js/api/assets/search.js | 1 + lib/souffle-js/api/assets/style.css | 1 + .../api/classes/context.SouffleContext.html | 40 + .../api/classes/emitter.SouffleEmitter.html | 9 + .../api/classes/errors.SouffleError.html | 3 + .../classes/errors.SouffleExecutionError.html | 3 + .../classes/errors.SouffleInternalError.html | 3 + .../api/classes/errors.SouffleUsageError.html | 3 + ...xecutor_executor.SouffleAsyncExecutor.html | 12 + .../executor_executor.SouffleExecutor.html | 10 + ...executor_executor.SouffleSyncExecutor.html | 12 + ...cutor_results.SouffleOutputStructured.html | 7 + ...executor_results.SpaceSeparatedParser.html | 820 ++++++++++++++++++ .../api/classes/logger.DefaultLogger.html | 6 + .../prettyPrinter.SoufflePrettyPrinter.html | 4 + .../api/classes/syntaxConstructors.Type.html | 6 + .../classes/syntaxConstructors.TypeDef.html | 3 + .../executor_results.parseResults.html | 4 + .../executor_results.parseResultsSync.html | 4 + ...tor_results.parseSpaceSeparatedValues.html | 2 + .../functions/syntaxConstructors.atom.html | 1 + .../syntaxConstructors.binaryConstraint.html | 1 + .../functions/syntaxConstructors.body.html | 1 + .../syntaxConstructors.booleanConstraint.html | 1 + .../functions/syntaxConstructors.comment.html | 1 + ...syntaxConstructors.containsConstraint.html | 1 + .../functions/syntaxConstructors.fact.html | 1 + .../syntaxConstructors.matchConstraint.html | 1 + .../functions/syntaxConstructors.program.html | 1 + .../syntaxConstructors.relation.html | 1 + .../functions/syntaxConstructors.rule.html | 1 + .../functions/syntaxUtils.eqFactValues.html | 1 + lib/souffle-js/api/hierarchy.html | 1 + lib/souffle-js/api/index.html | 14 + ...ecutor_executor.SouffleExecutorParams.html | 9 + .../api/interfaces/logger.ILogger.html | 5 + .../api/media/simpleTypedVarPointsTo.ts | 125 +++ lib/souffle-js/api/modules/context.html | 2 + lib/souffle-js/api/modules/emitter.html | 2 + lib/souffle-js/api/modules/errors.html | 5 + lib/souffle-js/api/modules/executor.html | 8 + .../api/modules/executor_executor.html | 6 + .../api/modules/executor_results.html | 7 + lib/souffle-js/api/modules/index.html | 48 + lib/souffle-js/api/modules/logger.html | 3 + lib/souffle-js/api/modules/prettyPrinter.html | 2 + lib/souffle-js/api/modules/syntax.html | 23 + .../api/modules/syntaxConstructors.html | 15 + lib/souffle-js/api/modules/syntaxUtils.html | 2 + lib/souffle-js/api/modules/version.html | 2 + ...cutor_executor.SouffleExecutionResult.html | 6 + .../executor_results.SouffleOutputRaw.html | 3 + .../api/types/syntax.SouffleAtom.html | 3 + .../api/types/syntax.SouffleComment.html | 3 + .../api/types/syntax.SouffleConstraint.html | 3 + .../types/syntax.SouffleConstraintArg.html | 1 + .../api/types/syntax.SouffleConstraintOp.html | 1 + .../api/types/syntax.SouffleCustomType.html | 1 + ...ntax.SouffleEquivalenceTypeDefinition.html | 1 + .../api/types/syntax.SouffleFact.html | 5 + .../api/types/syntax.SouffleFactValue.html | 1 + .../api/types/syntax.SouffleNode.html | 1 + .../types/syntax.SoufflePrimitiveType.html | 1 + .../syntax.SoufflePrimitiveTypeValue.html | 1 + .../api/types/syntax.SouffleProgram.html | 3 + .../api/types/syntax.SouffleProgramEntry.html | 1 + .../api/types/syntax.SouffleRelation.html | 3 + .../api/types/syntax.SouffleRelationArg.html | 1 + .../api/types/syntax.SouffleRelationIO.html | 1 + .../api/types/syntax.SouffleRule.html | 3 + .../api/types/syntax.SouffleRuleBody.html | 3 + .../syntax.SouffleSubtypeTypeDefinition.html | 1 + .../api/types/syntax.SouffleType.html | 2 + .../types/syntax.SouffleTypeDefinition.html | 3 + .../syntaxConstructors.CommentValue.html | 1 + .../variables/version.SOUFFLE_VERSION.html | 2 + markdown-page/index.html | 22 + sitemap.xml | 1 + tools/misti/api/.nojekyll | 1 + tools/misti/api/assets/custom.css | 1 + tools/misti/api/assets/highlight.css | 1 + tools/misti/api/assets/icons.js | 1 + tools/misti/api/assets/icons.svg | 1 + tools/misti/api/assets/main.js | 2 + tools/misti/api/assets/main.js.LICENSE.txt | 54 ++ tools/misti/api/assets/navigation.js | 1 + tools/misti/api/assets/search.js | 1 + tools/misti/api/assets/style.css | 1 + .../misti/api/classes/cli_driver.Driver.html | 24 + ...Contract.SingleContractProjectManager.html | 11 + ...iltin_argCopyMutation.ArgCopyMutation.html | 61 ++ ...detectors_builtin_asmIsUsed.AsmIsUsed.html | 43 + ...iltin_branchDuplicate.BranchDuplicate.html | 57 ++ ...ors_builtin_cellOverflow.CellOverflow.html | 69 ++ ...iltin_constantAddress.ConstantAddress.html | 60 ++ ...deBeforeMultiply.DivideBeforeMultiply.html | 66 ++ ...tectors_builtin_dumpIsUsed.DumpIsUsed.html | 56 ++ ...plicatedCondition.DuplicatedCondition.html | 57 ++ ...s_builtin_ensurePrgSeed.EnsurePrgSeed.html | 58 ++ ...builtin_falseCondition.FalseCondition.html | 53 ++ ...iltin_fieldDoubleInit.FieldDoubleInit.html | 54 ++ ...dStateMutation.InheritedStateMutation.html | 71 ++ ...essedVariables.NeverAccessedVariables.html | 67 ++ ...timalMathFunction.OptimalMathFunction.html | 44 + ...AugmentedAssign.PreferAugmentedAssign.html | 47 + ...preferredStdlibApi.PreferredStdlibApi.html | 59 ++ ...n_readOnlyVariables.ReadOnlyVariables.html | 70 ++ ...ceiversOverlap.StringReceiversOverlap.html | 53 ++ ...ors_builtin_unboundLoops.UnboundLoops.html | 65 ++ ...builtin_unusedOptional.UnusedOptional.html | 54 ++ ...ctors_builtin_zeroAddress.ZeroAddress.html | 65 ++ .../detectors_detector.ASTDetector.html | 36 + .../detectors_detector.DataflowDetector.html | 36 + .../classes/detectors_detector.Detector.html | 36 + .../detectors_detector.SouffleDetector.html | 44 + .../classes/internals_config.MistiConfig.html | 12 + .../internals_context.MistiContext.html | 10 + ...ternals_exceptions.ExecutionException.html | 4 + ...nternals_exceptions.InternalException.html | 3 + .../internals_exceptions.TactException.html | 7 + .../internals_ir_astStore.TactASTStore.html | 116 +++ ..._builders_tactIRBuilder.TactIRBuilder.html | 15 + .../classes/internals_ir_cfg.BasicBlock.html | 16 + .../api/classes/internals_ir_cfg.CFG.html | 53 ++ .../api/classes/internals_ir_cfg.Edge.html | 9 + .../internals_ir_ir.CompilationUnit.html | 40 + .../api/classes/internals_ir_ir.Contract.html | 17 + .../internals_lattice.SetJoinSemilattice.html | 17 + .../internals_lattice.SetMeetSemilattice.html | 17 + .../classes/internals_logger.DebugLogger.html | 11 + .../api/classes/internals_logger.Logger.html | 13 + .../classes/internals_logger.QuietLogger.html | 11 + .../classes/internals_logger.TraceLogger.html | 11 + ...nternals_solver_results.SolverResults.html | 7 + ...nternals_solver_souffle.SouffleSolver.html | 8 + ...ernals_solver_worklist.WorklistSolver.html | 11 + .../internals_tact_util.SrcInfoSet.html | 8 + .../internals_warnings.MistiTactWarning.html | 22 + .../api/classes/tools_dumpAst.DumpAst.html | 20 + .../api/classes/tools_dumpCfg.DumpCfg.html | 20 + .../classes/tools_dumpConfig.DumpConfig.html | 20 + tools/misti/api/classes/tools_tool.Tool.html | 20 + tools/misti/api/enums/cli_types.ExitCode.html | 8 + .../api/enums/internals_logger.LogLevel.html | 5 + .../enums/internals_warnings.Severity.html | 7 + .../functions/cli_cli.createMistiCommand.html | 3 + .../api/functions/cli_cli.executeMisti.html | 4 + .../functions/cli_cli.handleMistiResult.html | 2 + .../functions/cli_cli.runMistiCommand.html | 4 + .../cli_result.resultToExitCode.html | 1 + .../functions/cli_result.resultToString.html | 2 + .../cli_result.saveResultToFiles.html | 10 + .../createDetector.createDetector.html | 5 + ...etectors_detector.findBuiltInDetector.html | 7 + .../detectors_detector.getAllDetectors.html | 3 + ...etectors_detector.getEnabledDetectors.html | 3 + ...detectors_detector.hasBuiltInDetector.html | 2 + .../internals_exceptions.throwZodError.html | 3 + .../internals_exceptions.tryMsg.html | 2 + ...ls_ir_builders_tactIRBuilder.createIR.html | 3 + ...lders_tactIRBuilder.setTactStdlibPath.html | 3 + .../internals_ir_cfg.getPredecessors.html | 2 + .../internals_ir_cfg.getSuccessors.html | 2 + ...rnals_ir_indices.IdxGenerator.__reset.html | 2 + ...nternals_ir_indices.IdxGenerator.next.html | 1 + .../internals_tact_constEval.evalExpr.html | 4 + .../internals_tact_constEval.evalToType.html | 6 + ...rnals_tact_constEval.evalsToPredicate.html | 6 + ...internals_tact_constEval.evalsToValue.html | 8 + .../internals_tact_iterators.extractPath.html | 1 + ...nals_tact_iterators.findInExpressions.html | 5 + ...ernals_tact_iterators.foldExpressions.html | 6 + ...ternals_tact_iterators.foldStatements.html | 8 + ...nals_tact_iterators.forEachExpression.html | 6 + ...rnals_tact_iterators.forEachStatement.html | 4 + ...rnals_tact_iterators.hasInExpressions.html | 5 + ...internals_tact_util.collectConditions.html | 2 + .../internals_tact_util.collectFields.html | 2 + .../internals_tact_util.collectMutations.html | 6 + .../internals_tact_util.formatPosition.html | 2 + .../internals_tact_util.funName.html | 2 + ...nternals_tact_util.isPrimitiveLiteral.html | 2 + .../functions/internals_tact_util.isSelf.html | 2 + .../internals_tact_util.isSelfAccess.html | 2 + ...nals_tact_util.isStdlibMutationMethod.html | 2 + .../internals_tact_util.mutationNames.html | 8 + .../internals_tact_util.nodesAreEqual.html | 2 + .../internals_tact_util.removeSelf.html | 9 + ...nternals_tact_util.statementsAreEqual.html | 2 + .../internals_util.intersection.html | 2 + .../internals_util.isListSubsetOf.html | 1 + .../internals_util.isMapSubsetOf.html | 1 + .../functions/internals_util.isSubsetOf.html | 1 + .../functions/internals_util.mergeLists.html | 1 + .../functions/internals_util.mergeMaps.html | 1 + .../functions/internals_util.mergeSets.html | 1 + .../functions/internals_util.unreachable.html | 2 + .../internals_warnings.makeDocURL.html | 2 + .../internals_warnings.parseSeverity.html | 2 + .../internals_warnings.severityToString.html | 3 + .../functions/tools_tool.findBuiltInTool.html | 8 + .../tools_tool.generateToolsHelpMessage.html | 3 + .../api/functions/tools_tool.getAllTools.html | 3 + .../functions/tools_tool.hasBuiltInTool.html | 2 + tools/misti/api/hierarchy.html | 1 + tools/misti/api/index.html | 36 + .../interfaces/cli_options.CLIOptions.html | 18 + .../interfaces/cli_types.DetectorConfig.html | 7 + .../api/interfaces/cli_types.ToolConfig.html | 6 + .../internals_lattice.JoinSemilattice.html | 16 + .../interfaces/internals_lattice.Lattice.html | 11 + .../internals_lattice.MeetSemilattice.html | 16 + .../internals_solver_solver.Solver.html | 3 + ...nternals_solver_souffle.SouffleMapper.html | 25 + .../internals_transfer.Transfer.html | 11 + tools/misti/api/media/misti.png | Bin 0 -> 331022 bytes tools/misti/api/modules/cli.html | 25 + tools/misti/api/modules/cli_cli.html | 5 + tools/misti/api/modules/cli_driver.html | 2 + tools/misti/api/modules/cli_options.html | 5 + tools/misti/api/modules/cli_result.html | 12 + .../misti/api/modules/cli_singleContract.html | 2 + tools/misti/api/modules/cli_types.html | 5 + tools/misti/api/modules/createDetector.html | 3 + .../detectors_builtin_argCopyMutation.html | 2 + .../modules/detectors_builtin_asmIsUsed.html | 2 + .../detectors_builtin_branchDuplicate.html | 2 + .../detectors_builtin_cellOverflow.html | 2 + .../detectors_builtin_constantAddress.html | 2 + ...etectors_builtin_divideBeforeMultiply.html | 2 + .../modules/detectors_builtin_dumpIsUsed.html | 2 + ...detectors_builtin_duplicatedCondition.html | 2 + .../detectors_builtin_ensurePrgSeed.html | 2 + .../detectors_builtin_falseCondition.html | 2 + .../detectors_builtin_fieldDoubleInit.html | 2 + ...ectors_builtin_inheritedStateMutation.html | 2 + ...ectors_builtin_neverAccessedVariables.html | 2 + ...detectors_builtin_optimalMathFunction.html | 2 + ...tectors_builtin_preferAugmentedAssign.html | 2 + .../detectors_builtin_preferredStdlibApi.html | 2 + .../detectors_builtin_readOnlyVariables.html | 2 + ...ectors_builtin_stringReceiversOverlap.html | 2 + .../detectors_builtin_unboundLoops.html | 2 + .../detectors_builtin_unusedOptional.html | 2 + .../detectors_builtin_zeroAddress.html | 2 + .../misti/api/modules/detectors_detector.html | 20 + tools/misti/api/modules/index.html | 79 ++ tools/misti/api/modules/internals_config.html | 3 + .../misti/api/modules/internals_context.html | 2 + .../api/modules/internals_exceptions.html | 6 + tools/misti/api/modules/internals_ir.html | 25 + .../api/modules/internals_ir_astStore.html | 2 + .../internals_ir_builders_tactIRBuilder.html | 7 + tools/misti/api/modules/internals_ir_cfg.html | 11 + .../internals_ir_indices.IdxGenerator.html | 5 + .../api/modules/internals_ir_indices.html | 2 + tools/misti/api/modules/internals_ir_ir.html | 4 + .../misti/api/modules/internals_ir_types.html | 8 + .../misti/api/modules/internals_lattice.html | 6 + tools/misti/api/modules/internals_logger.html | 7 + tools/misti/api/modules/internals_solver.html | 7 + .../api/modules/internals_solver_results.html | 2 + .../api/modules/internals_solver_solver.html | 2 + .../api/modules/internals_solver_souffle.html | 3 + .../modules/internals_solver_worklist.html | 3 + tools/misti/api/modules/internals_tact.html | 27 + .../api/modules/internals_tact_constEval.html | 5 + .../api/modules/internals_tact_iterators.html | 8 + .../api/modules/internals_tact_util.html | 16 + .../misti/api/modules/internals_transfer.html | 2 + tools/misti/api/modules/internals_util.html | 10 + .../misti/api/modules/internals_warnings.html | 7 + tools/misti/api/modules/main.html | 1 + tools/misti/api/modules/tools.html | 10 + tools/misti/api/modules/tools_dumpAst.html | 2 + tools/misti/api/modules/tools_dumpCfg.html | 2 + tools/misti/api/modules/tools_dumpConfig.html | 2 + tools/misti/api/modules/tools_tool.html | 7 + tools/misti/api/modules/version.html | 3 + tools/misti/api/modules/version_info.html | 3 + .../api/types/cli_result.MistiResult.html | 1 + .../types/cli_result.MistiResultError.html | 3 + .../api/types/cli_result.MistiResultOK.html | 2 + .../api/types/cli_result.MistiResultTool.html | 2 + .../types/cli_result.MistiResultWarnings.html | 2 + .../api/types/cli_result.ResultReport.html | 1 + .../api/types/cli_result.ToolOutput.html | 3 + .../api/types/cli_result.WarningOutput.html | 3 + .../api/types/cli_types.OutputFormat.html | 1 + .../detectors_detector.DetectorKind.html | 1 + .../detectors_detector.DetectorName.html | 1 + .../detectors_detector.WarningsBehavior.html | 1 + .../internals_config.WarningSuppression.html | 1 + ...r_builders_tactIRBuilder.FunctionsMap.html | 2 + ..._ir_builders_tactIRBuilder.MethodsMap.html | 2 + .../internals_ir_cfg.BasicBlockKind.html | 8 + .../types/internals_ir_cfg.EntryOrigin.html | 1 + .../types/internals_ir_cfg.FunctionKind.html | 2 + .../internals_ir_types.BasicBlockIdx.html | 1 + .../api/types/internals_ir_types.CFGIdx.html | 1 + .../types/internals_ir_types.ContractIdx.html | 1 + .../internals_ir_types.ContractName.html | 1 + .../api/types/internals_ir_types.EdgeIdx.html | 1 + .../internals_ir_types.FunctionName.html | 1 + .../types/internals_ir_types.ProjectName.html | 1 + .../types/internals_logger.LogFunction.html | 1 + ...nternals_solver_worklist.AnalysisKind.html | 9 + .../internals_tact_util.MutatedElement.html | 1 + .../misti/api/types/tools_tool.ToolName.html | 1 + .../variables/cli_options.STDOUT_PATH.html | 1 + .../cli_options.cliOptionDefaults.html | 1 + .../variables/cli_options.cliOptions-1.html | 1 + .../detectors_detector.BuiltInDetectors.html | 2 + ...RBuilder.DEFAULT_STDLIB_PATH_ELEMENTS.html | 2 + .../internals_warnings.BASE_DOC_URL.html | 2 + .../variables/version_info.MISTI_VERSION.html | 1 + .../variables/version_info.TACT_VERSION.html | 1 + .../detectors/DivideBeforeMultiply/index.html | 34 + .../NeverAccessedVariables/index.html | 30 + .../detectors/ReadOnlyVariables/index.html | 29 + .../0.1.2/detectors/UnboundLoops/index.html | 33 + .../0.1.2/detectors/ZeroAddress/index.html | 31 + .../docs/0.1.2/hacking/CHANGELOG/index.html | 43 + .../0.1.2/hacking/contributing/index.html | 66 ++ .../0.1.2/hacking/custom-detector/index.html | 32 + .../docs/0.1.2/hacking/design/index.html | 34 + .../docs/0.1.2/hacking/souffle/index.html | 38 + .../misti/docs/0.1.2/hacking/tools/index.html | 51 ++ tools/misti/docs/0.1.2/index.html | 37 + .../0.1.2/tutorial/configuration/index.html | 54 ++ .../0.1.2/tutorial/getting-started/index.html | 39 + .../detectors/BranchDuplicate/index.html | 33 + .../detectors/ConstantAddress/index.html | 31 + .../detectors/DivideBeforeMultiply/index.html | 34 + .../0.2.0/detectors/DumpIsUsed/index.html | 28 + .../detectors/FieldDoubleInit/index.html | 28 + .../NeverAccessedVariables/index.html | 30 + .../PreferAugmentedAssign/index.html | 28 + .../detectors/ReadOnlyVariables/index.html | 29 + .../0.2.0/detectors/UnboundLoops/index.html | 33 + .../0.2.0/detectors/ZeroAddress/index.html | 31 + tools/misti/docs/0.2.0/detectors/index.html | 35 + .../0.2.0/hacking/contributing/index.html | 66 ++ .../0.2.0/hacking/custom-detector/index.html | 32 + .../docs/0.2.0/hacking/design/index.html | 34 + .../docs/0.2.0/hacking/souffle/index.html | 38 + .../misti/docs/0.2.0/hacking/tools/index.html | 51 ++ tools/misti/docs/0.2.0/index.html | 37 + .../docs/0.2.0/tutorial/ci-cd/index.html | 33 + .../0.2.0/tutorial/configuration/index.html | 60 ++ .../0.2.0/tutorial/getting-started/index.html | 49 ++ .../detectors/BranchDuplicate/index.html | 33 + .../detectors/ConstantAddress/index.html | 31 + .../detectors/DivideBeforeMultiply/index.html | 34 + .../0.2.1/detectors/DumpIsUsed/index.html | 28 + .../detectors/FieldDoubleInit/index.html | 28 + .../NeverAccessedVariables/index.html | 30 + .../PreferAugmentedAssign/index.html | 28 + .../detectors/ReadOnlyVariables/index.html | 29 + .../0.2.1/detectors/UnboundLoops/index.html | 33 + .../0.2.1/detectors/ZeroAddress/index.html | 31 + tools/misti/docs/0.2.1/detectors/index.html | 35 + .../0.2.1/hacking/contributing/index.html | 66 ++ .../0.2.1/hacking/custom-detector/index.html | 32 + .../docs/0.2.1/hacking/design/index.html | 34 + .../docs/0.2.1/hacking/souffle/index.html | 38 + .../misti/docs/0.2.1/hacking/tools/index.html | 51 ++ tools/misti/docs/0.2.1/index.html | 37 + .../docs/0.2.1/tutorial/ci-cd/index.html | 33 + .../0.2.1/tutorial/configuration/index.html | 60 ++ .../0.2.1/tutorial/getting-started/index.html | 49 ++ .../detectors/BranchDuplicate/index.html | 33 + .../detectors/ConstantAddress/index.html | 31 + .../detectors/DivideBeforeMultiply/index.html | 34 + .../0.2.2/detectors/DumpIsUsed/index.html | 28 + .../detectors/FieldDoubleInit/index.html | 28 + .../NeverAccessedVariables/index.html | 30 + .../PreferAugmentedAssign/index.html | 28 + .../detectors/ReadOnlyVariables/index.html | 29 + .../0.2.2/detectors/UnboundLoops/index.html | 33 + .../0.2.2/detectors/ZeroAddress/index.html | 31 + tools/misti/docs/0.2.2/detectors/index.html | 35 + .../0.2.2/hacking/contributing/index.html | 66 ++ .../0.2.2/hacking/custom-detector/index.html | 32 + .../docs/0.2.2/hacking/design/index.html | 34 + .../docs/0.2.2/hacking/souffle/index.html | 38 + .../misti/docs/0.2.2/hacking/tools/index.html | 51 ++ tools/misti/docs/0.2.2/index.html | 37 + .../docs/0.2.2/tutorial/blueprint/index.html | 32 + .../docs/0.2.2/tutorial/ci-cd/index.html | 33 + .../0.2.2/tutorial/configuration/index.html | 60 ++ .../0.2.2/tutorial/getting-started/index.html | 49 ++ .../detectors/ArgCopyMutation/index.html | 34 + .../docs/0.3.0/detectors/AsmIsUsed/index.html | 28 + .../detectors/BranchDuplicate/index.html | 33 + .../detectors/ConstantAddress/index.html | 31 + .../detectors/DivideBeforeMultiply/index.html | 34 + .../0.3.0/detectors/DumpIsUsed/index.html | 31 + .../detectors/FieldDoubleInit/index.html | 32 + .../InheritedStateMutation/index.html | 33 + .../NeverAccessedVariables/index.html | 30 + .../PreferAugmentedAssign/index.html | 31 + .../detectors/PreferredStdlibApi/index.html | 34 + .../detectors/ReadOnlyVariables/index.html | 29 + .../StringReceiversOverlap/index.html | 29 + .../0.3.0/detectors/UnboundLoops/index.html | 33 + .../0.3.0/detectors/ZeroAddress/index.html | 31 + tools/misti/docs/0.3.0/detectors/index.html | 26 + .../0.3.0/hacking/contributing/index.html | 66 ++ .../0.3.0/hacking/custom-detector/index.html | 38 + .../docs/0.3.0/hacking/design/index.html | 34 + .../docs/0.3.0/hacking/souffle/index.html | 38 + .../misti/docs/0.3.0/hacking/tools/index.html | 51 ++ tools/misti/docs/0.3.0/index.html | 39 + .../docs/0.3.0/tutorial/blueprint/index.html | 32 + .../docs/0.3.0/tutorial/ci-cd/index.html | 33 + .../misti/docs/0.3.0/tutorial/cli/index.html | 102 +++ .../0.3.0/tutorial/configuration/index.html | 63 ++ .../0.3.0/tutorial/getting-started/index.html | 62 ++ .../detectors/ArgCopyMutation/index.html | 34 + .../docs/0.3.1/detectors/AsmIsUsed/index.html | 28 + .../detectors/BranchDuplicate/index.html | 33 + .../detectors/ConstantAddress/index.html | 31 + .../detectors/DivideBeforeMultiply/index.html | 34 + .../0.3.1/detectors/DumpIsUsed/index.html | 31 + .../detectors/FieldDoubleInit/index.html | 32 + .../InheritedStateMutation/index.html | 33 + .../NeverAccessedVariables/index.html | 30 + .../PreferAugmentedAssign/index.html | 31 + .../detectors/PreferredStdlibApi/index.html | 34 + .../detectors/ReadOnlyVariables/index.html | 29 + .../StringReceiversOverlap/index.html | 29 + .../0.3.1/detectors/UnboundLoops/index.html | 33 + .../0.3.1/detectors/ZeroAddress/index.html | 31 + tools/misti/docs/0.3.1/detectors/index.html | 26 + .../0.3.1/hacking/contributing/index.html | 66 ++ .../0.3.1/hacking/custom-detector/index.html | 38 + .../docs/0.3.1/hacking/design/index.html | 34 + .../docs/0.3.1/hacking/souffle/index.html | 38 + .../misti/docs/0.3.1/hacking/tools/index.html | 51 ++ tools/misti/docs/0.3.1/index.html | 39 + .../docs/0.3.1/tutorial/blueprint/index.html | 32 + .../docs/0.3.1/tutorial/ci-cd/index.html | 33 + .../misti/docs/0.3.1/tutorial/cli/index.html | 102 +++ .../0.3.1/tutorial/configuration/index.html | 63 ++ .../0.3.1/tutorial/getting-started/index.html | 62 ++ .../docs/detectors/ArgCopyMutation/index.html | 34 + .../misti/docs/detectors/AsmIsUsed/index.html | 28 + .../docs/detectors/BranchDuplicate/index.html | 33 + .../docs/detectors/ConstantAddress/index.html | 31 + .../detectors/DivideBeforeMultiply/index.html | 34 + .../docs/detectors/DumpIsUsed/index.html | 31 + .../detectors/DuplicatedCondition/index.html | 29 + .../docs/detectors/EnsurePrgSeed/index.html | 32 + .../docs/detectors/FalseCondition/index.html | 31 + .../docs/detectors/FieldDoubleInit/index.html | 32 + .../InheritedStateMutation/index.html | 33 + .../NeverAccessedVariables/index.html | 30 + .../detectors/OptimalMathFunction/index.html | 28 + .../PreferAugmentedAssign/index.html | 31 + .../detectors/PreferredStdlibApi/index.html | 34 + .../detectors/ReadOnlyVariables/index.html | 29 + .../StringReceiversOverlap/index.html | 29 + .../docs/detectors/UnboundLoops/index.html | 33 + .../docs/detectors/UnusedOptional/index.html | 31 + .../docs/detectors/ZeroAddress/index.html | 31 + tools/misti/docs/detectors/index.html | 26 + .../docs/hacking/contributing/index.html | 66 ++ .../docs/hacking/custom-detector/index.html | 38 + tools/misti/docs/hacking/design/index.html | 34 + .../docs/hacking/developing-misti/index.html | 44 + tools/misti/docs/hacking/souffle/index.html | 38 + tools/misti/docs/index.html | 44 + .../next/detectors/ArgCopyMutation/index.html | 34 + .../docs/next/detectors/AsmIsUsed/index.html | 28 + .../next/detectors/BranchDuplicate/index.html | 33 + .../next/detectors/ConstantAddress/index.html | 31 + .../detectors/DivideBeforeMultiply/index.html | 34 + .../docs/next/detectors/DumpIsUsed/index.html | 31 + .../detectors/DuplicatedCondition/index.html | 29 + .../next/detectors/EnsurePrgSeed/index.html | 32 + .../next/detectors/FalseCondition/index.html | 31 + .../next/detectors/FieldDoubleInit/index.html | 32 + .../InheritedStateMutation/index.html | 33 + .../NeverAccessedVariables/index.html | 30 + .../detectors/OptimalMathFunction/index.html | 28 + .../PreferAugmentedAssign/index.html | 31 + .../detectors/PreferredStdlibApi/index.html | 34 + .../detectors/ReadOnlyVariables/index.html | 29 + .../StringReceiversOverlap/index.html | 29 + .../next/detectors/UnboundLoops/index.html | 33 + .../next/detectors/UnusedOptional/index.html | 31 + .../next/detectors/ZeroAddress/index.html | 31 + tools/misti/docs/next/detectors/index.html | 61 ++ .../docs/next/hacking/contributing/index.html | 66 ++ .../next/hacking/custom-detector/index.html | 38 + .../misti/docs/next/hacking/design/index.html | 34 + .../next/hacking/developing-misti/index.html | 44 + .../docs/next/hacking/souffle/index.html | 38 + tools/misti/docs/next/index.html | 44 + .../misti/docs/next/tools/DumpAst/index.html | 30 + .../misti/docs/next/tools/DumpCfg/index.html | 62 ++ .../docs/next/tools/DumpConfig/index.html | 27 + tools/misti/docs/next/tools/index.html | 36 + .../docs/next/tutorial/blueprint/index.html | 48 + .../misti/docs/next/tutorial/ci-cd/index.html | 42 + tools/misti/docs/next/tutorial/cli/index.html | 105 +++ .../next/tutorial/configuration/index.html | 77 ++ .../next/tutorial/getting-started/index.html | 62 ++ tools/misti/docs/tools/DumpAst/index.html | 30 + tools/misti/docs/tools/DumpCfg/index.html | 62 ++ tools/misti/docs/tools/DumpConfig/index.html | 27 + tools/misti/docs/tools/index.html | 36 + .../misti/docs/tutorial/blueprint/index.html | 48 + tools/misti/docs/tutorial/ci-cd/index.html | 42 + tools/misti/docs/tutorial/cli/index.html | 105 +++ .../docs/tutorial/configuration/index.html | 77 ++ .../docs/tutorial/getting-started/index.html | 62 ++ tools/misti/index.html | 21 + 761 files changed, 12438 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 CNAME create mode 100644 assets/css/styles.57cb5423.css create mode 100644 assets/images/blueprint-select-project-b8656fa4266c0c7923d6b67c7f5950e6.png create mode 100644 assets/js/012e8e66.af4e648f.js create mode 100644 assets/js/01419b1f.55a4ac68.js create mode 100644 assets/js/06bf7bd2.93cfb521.js create mode 100644 assets/js/070671b7.a81bd6a1.js create mode 100644 assets/js/07f2fad9.76f75bf4.js create mode 100644 assets/js/0ac52da9.865948a5.js create mode 100644 assets/js/0b705376.0f6bdf25.js create mode 100644 assets/js/0c390d31.29054261.js create mode 100644 assets/js/0c3de8e2.454cb0da.js create mode 100644 assets/js/0c8d0168.c0afaf27.js create mode 100644 assets/js/0e4e7ef7.da1fd809.js create mode 100644 assets/js/0f37fc5e.4a23afc4.js create mode 100644 assets/js/0fb6ae9c.e2818ac1.js create mode 100644 assets/js/104c66c9.61be676d.js create mode 100644 assets/js/122f6b32.f6ee1737.js create mode 100644 assets/js/1295da86.6c981ca5.js create mode 100644 assets/js/138db073.578334fd.js create mode 100644 assets/js/1418388c.6eb86b98.js create mode 100644 assets/js/150b97d9.3c57e7f9.js create mode 100644 assets/js/1598dd73.06ff38aa.js create mode 100644 assets/js/15d13f14.3309e304.js create mode 100644 assets/js/17406c9d.759681c0.js create mode 100644 assets/js/17896441.dc05340c.js create mode 100644 assets/js/1869ccd1.5d76a4bd.js create mode 100644 assets/js/1a50d306.ff71f994.js create mode 100644 assets/js/1a8310a1.e63a2b77.js create mode 100644 assets/js/1b73222b.c47a22da.js create mode 100644 assets/js/1b960128.5b5b59d9.js create mode 100644 assets/js/1c26cb06.972f1ca6.js create mode 100644 assets/js/1df93b7f.4689c496.js create mode 100644 assets/js/1f391b9e.d1d4beb6.js create mode 100644 assets/js/2018b81b.63a7c757.js create mode 100644 assets/js/2237.92070aeb.js create mode 100644 assets/js/2257d06b.a740c88e.js create mode 100644 assets/js/23b0c962.e0d7957b.js create mode 100644 assets/js/2424092d.88efacf6.js create mode 100644 assets/js/24652b08.91ed48d5.js create mode 100644 assets/js/26592ea2.2dd4e9ca.js create mode 100644 assets/js/273168fb.26adb4b1.js create mode 100644 assets/js/299f32b1.3d9263b4.js create mode 100644 assets/js/2aa59687.16070803.js create mode 100644 assets/js/2ace25e9.6114563d.js create mode 100644 assets/js/2b6a80d0.3d7eb50f.js create mode 100644 assets/js/2b785902.b83e29b9.js create mode 100644 assets/js/2bdf0f82.11a0dcc1.js create mode 100644 assets/js/2cebbb1e.1c80f755.js create mode 100644 assets/js/2d07d137.1711bd45.js create mode 100644 assets/js/2f30e490.cf459bb9.js create mode 100644 assets/js/304edb56.1899324d.js create mode 100644 assets/js/3658.8fe69683.js create mode 100644 assets/js/36ebdf3e.c81514b8.js create mode 100644 assets/js/377c4f81.79a338ae.js create mode 100644 assets/js/393be207.fc96af0e.js create mode 100644 assets/js/3b3a1a75.976ba85c.js create mode 100644 assets/js/3bfe497f.a61d7e8b.js create mode 100644 assets/js/3db5102b.08380390.js create mode 100644 assets/js/40be7dfa.be7d2a62.js create mode 100644 assets/js/42510f93.7a5b306e.js create mode 100644 assets/js/432cb5a5.17016576.js create mode 100644 assets/js/43c93918.b3c5c4ff.js create mode 100644 assets/js/4518efa7.b9ef0cc5.js create mode 100644 assets/js/474ce197.29e1c442.js create mode 100644 assets/js/49256311.be5c404d.js create mode 100644 assets/js/4ab26116.4e3dc2f6.js create mode 100644 assets/js/4b89306f.efdf0920.js create mode 100644 assets/js/4d74b396.8aebea31.js create mode 100644 assets/js/4f2bb7ce.0a476d8d.js create mode 100644 assets/js/4fd06f05.45b0f688.js create mode 100644 assets/js/51fe41a6.f649c3d3.js create mode 100644 assets/js/55e1201d.f5805772.js create mode 100644 assets/js/563af34e.29a0e834.js create mode 100644 assets/js/566d8483.942257c5.js create mode 100644 assets/js/5815e0d3.36349d47.js create mode 100644 assets/js/59016342.fc899b97.js create mode 100644 assets/js/5a7ecd5b.08c83086.js create mode 100644 assets/js/5e95c892.0afa16e4.js create mode 100644 assets/js/5ec2195c.a723ab4e.js create mode 100644 assets/js/602c5d84.a9af00d9.js create mode 100644 assets/js/61c19607.94c232da.js create mode 100644 assets/js/6362ac9f.aa3d1fc1.js create mode 100644 assets/js/63a541b5.cf91b4ad.js create mode 100644 assets/js/63bb535a.ed747652.js create mode 100644 assets/js/6696f09b.9d59dc8d.js create mode 100644 assets/js/6934ebe4.7bcf9574.js create mode 100644 assets/js/693ffdbc.20a90ba4.js create mode 100644 assets/js/6f277b0e.89006761.js create mode 100644 assets/js/6f60ccd2.91c6f358.js create mode 100644 assets/js/719e5d48.0bc6e809.js create mode 100644 assets/js/72b7ad48.f6676fe3.js create mode 100644 assets/js/743bfbca.ba311b0c.js create mode 100644 assets/js/7499c02a.f1eb98f3.js create mode 100644 assets/js/754ccd45.2081d519.js create mode 100644 assets/js/76268162.332975fc.js create mode 100644 assets/js/773c7ee4.d71f2dd0.js create mode 100644 assets/js/775287ab.a34207ca.js create mode 100644 assets/js/776efca7.78ead050.js create mode 100644 assets/js/7b5b3cc2.90aa7fd2.js create mode 100644 assets/js/81087c81.7da41d03.js create mode 100644 assets/js/8272dc48.d9a84b38.js create mode 100644 assets/js/8306354c.2bbb254d.js create mode 100644 assets/js/844f22a2.2f80fdcf.js create mode 100644 assets/js/866ed13d.d4edfa4a.js create mode 100644 assets/js/86d22c3d.22d9a99e.js create mode 100644 assets/js/86d70222.91cb640f.js create mode 100644 assets/js/87ce9660.55512f80.js create mode 100644 assets/js/883df8cc.ec17e966.js create mode 100644 assets/js/8c01191f.93ad2656.js create mode 100644 assets/js/8c0243db.7de6da6a.js create mode 100644 assets/js/8c74c05e.09164805.js create mode 100644 assets/js/8c9dd45b.c7a96e3d.js create mode 100644 assets/js/8cf7c613.47582d2c.js create mode 100644 assets/js/8d6fa39c.f2faae22.js create mode 100644 assets/js/8d91c04d.ef1dbebb.js create mode 100644 assets/js/8df82fb6.5a9830a2.js create mode 100644 assets/js/8e426e62.bf0771c3.js create mode 100644 assets/js/8e8fe4d7.7a82fd74.js create mode 100644 assets/js/90b5d830.c162588e.js create mode 100644 assets/js/91acf703.c00ee771.js create mode 100644 assets/js/91ee281c.f53980f2.js create mode 100644 assets/js/94d07e36.7adad0e3.js create mode 100644 assets/js/96e77fcb.3fb77893.js create mode 100644 assets/js/972c9666.e5b493f7.js create mode 100644 assets/js/987a8a5d.bdfcfd74.js create mode 100644 assets/js/988b076a.3beed1a8.js create mode 100644 assets/js/9fedf60a.5a24888e.js create mode 100644 assets/js/a291c19d.f1ac0d98.js create mode 100644 assets/js/a3df6930.b9e3fcca.js create mode 100644 assets/js/a4516edb.19e6546c.js create mode 100644 assets/js/a5055d90.503ae7a2.js create mode 100644 assets/js/a66f2ff0.c39f76e5.js create mode 100644 assets/js/a7456010.c6eb9a57.js create mode 100644 assets/js/a7bd4aaa.1b32332e.js create mode 100644 assets/js/a7eb4927.90a54648.js create mode 100644 assets/js/a8c496ca.06cbb22b.js create mode 100644 assets/js/a8d7d639.ed43e771.js create mode 100644 assets/js/a94703ab.9f24e801.js create mode 100644 assets/js/aac87eb6.6b5bbfc3.js create mode 100644 assets/js/aba21aa0.d087865c.js create mode 100644 assets/js/acef80f0.ccd7a032.js create mode 100644 assets/js/aee0b8cc.c78b2bfe.js create mode 100644 assets/js/b05af762.c54dcfb2.js create mode 100644 assets/js/b12d76e5.d3ad221e.js create mode 100644 assets/js/b3799bec.86c01a35.js create mode 100644 assets/js/b64540ae.4fd9953e.js create mode 100644 assets/js/b64aaedd.88204f90.js create mode 100644 assets/js/b78952d0.efed39b1.js create mode 100644 assets/js/b80eaa74.91abd0f7.js create mode 100644 assets/js/b91dc83b.a57e29d3.js create mode 100644 assets/js/bce595e9.46a0cb1c.js create mode 100644 assets/js/bd72ef9b.45e20252.js create mode 100644 assets/js/be8ab43b.f4a8e3dd.js create mode 100644 assets/js/c00ee666.951c69ba.js create mode 100644 assets/js/c05c6791.1dfb4d97.js create mode 100644 assets/js/c252c345.a3cf3637.js create mode 100644 assets/js/c377a04b.8c30a29b.js create mode 100644 assets/js/c49af6bd.85a90098.js create mode 100644 assets/js/c55f1521.cb9c8e4f.js create mode 100644 assets/js/c5c1850c.d97c4482.js create mode 100644 assets/js/c5d65102.924539a3.js create mode 100644 assets/js/c7ee6afe.0b86ae18.js create mode 100644 assets/js/c82192ae.b860298b.js create mode 100644 assets/js/c926d0d4.30e3ae68.js create mode 100644 assets/js/c96954fa.f94afa3f.js create mode 100644 assets/js/ca178ca4.7d6ff74e.js create mode 100644 assets/js/cb77e040.4c34ff27.js create mode 100644 assets/js/cc6d1ce2.2f552c48.js create mode 100644 assets/js/cd411a47.dbdd6a6b.js create mode 100644 assets/js/ce7f72c2.19df7abf.js create mode 100644 assets/js/cf2c24d9.167088de.js create mode 100644 assets/js/cf5f971a.651efe6f.js create mode 100644 assets/js/d147047e.c3db349f.js create mode 100644 assets/js/d15cc687.df08049f.js create mode 100644 assets/js/d1781038.35abe5aa.js create mode 100644 assets/js/d2aaf676.0ddaefea.js create mode 100644 assets/js/d2d53d04.404d4960.js create mode 100644 assets/js/d2f295f4.6d5ee62f.js create mode 100644 assets/js/d3996cd7.0ca74802.js create mode 100644 assets/js/d46ee8ed.7ed1c3f4.js create mode 100644 assets/js/d6f3e79e.d1be0df5.js create mode 100644 assets/js/d7c99f30.b0b05326.js create mode 100644 assets/js/d7d99e1d.67e2d007.js create mode 100644 assets/js/d9542fcf.bbcb88d0.js create mode 100644 assets/js/dc55925b.1af0a38f.js create mode 100644 assets/js/dd8730c9.aeb151c7.js create mode 100644 assets/js/e1c88a01.26b5c812.js create mode 100644 assets/js/e2ad9c7a.573d9426.js create mode 100644 assets/js/e3b47995.2fccb84f.js create mode 100644 assets/js/e3c4fe0a.bf2b73e2.js create mode 100644 assets/js/e4a43c7d.d2da82aa.js create mode 100644 assets/js/e5aa38d8.17e7d0ef.js create mode 100644 assets/js/e63578c3.6cc338fe.js create mode 100644 assets/js/e6ef21e7.de959db6.js create mode 100644 assets/js/e9524270.4f13728a.js create mode 100644 assets/js/ea064c97.7b1162bd.js create mode 100644 assets/js/ea8d0df0.a9834690.js create mode 100644 assets/js/ebcc9167.b433e15d.js create mode 100644 assets/js/ed017323.30666872.js create mode 100644 assets/js/ed2e6971.1441e217.js create mode 100644 assets/js/edf1e52e.7e8e467f.js create mode 100644 assets/js/effcc73a.68126485.js create mode 100644 assets/js/f18c7db7.502a736a.js create mode 100644 assets/js/f2bdb0f5.256a666a.js create mode 100644 assets/js/f3297ff5.b24f1896.js create mode 100644 assets/js/f3466e67.b2bd9e44.js create mode 100644 assets/js/f34cb5e0.b26c4fc7.js create mode 100644 assets/js/f4d075b1.8ca57b63.js create mode 100644 assets/js/f503d00c.e7655ff6.js create mode 100644 assets/js/f553073e.8eca43d2.js create mode 100644 assets/js/f5772bf1.e894af92.js create mode 100644 assets/js/f58fcc43.833fdf0f.js create mode 100644 assets/js/f5bf49b8.3b9a5601.js create mode 100644 assets/js/f6f2b22b.1f2e8cc1.js create mode 100644 assets/js/f752d1db.9ec62e05.js create mode 100644 assets/js/f7ab1f3a.096a7a59.js create mode 100644 assets/js/f97c3fca.6a842194.js create mode 100644 assets/js/faae61e5.d4f77930.js create mode 100644 assets/js/fafa7ec8.f8fc7c04.js create mode 100644 assets/js/fbbe250b.022d69c3.js create mode 100644 assets/js/fcd86191.e1395157.js create mode 100644 assets/js/fe7c01fc.f82580ba.js create mode 100644 assets/js/ff0db780.e64f7648.js create mode 100644 assets/js/main.0656ce4d.js create mode 100644 assets/js/main.0656ce4d.js.LICENSE.txt create mode 100644 assets/js/runtime~main.5d851323.js create mode 100644 img/blueprint-select-project.png create mode 100644 img/cfg-example.svg create mode 100644 img/favicon.png create mode 100644 img/misti.png create mode 100644 index.html create mode 100644 lib/souffle-js/api/.nojekyll create mode 100644 lib/souffle-js/api/assets/custom.css create mode 100644 lib/souffle-js/api/assets/highlight.css create mode 100644 lib/souffle-js/api/assets/icons.js create mode 100644 lib/souffle-js/api/assets/icons.svg create mode 100644 lib/souffle-js/api/assets/main.js create mode 100644 lib/souffle-js/api/assets/main.js.LICENSE.txt create mode 100644 lib/souffle-js/api/assets/navigation.js create mode 100644 lib/souffle-js/api/assets/search.js create mode 100644 lib/souffle-js/api/assets/style.css create mode 100644 lib/souffle-js/api/classes/context.SouffleContext.html create mode 100644 lib/souffle-js/api/classes/emitter.SouffleEmitter.html create mode 100644 lib/souffle-js/api/classes/errors.SouffleError.html create mode 100644 lib/souffle-js/api/classes/errors.SouffleExecutionError.html create mode 100644 lib/souffle-js/api/classes/errors.SouffleInternalError.html create mode 100644 lib/souffle-js/api/classes/errors.SouffleUsageError.html create mode 100644 lib/souffle-js/api/classes/executor_executor.SouffleAsyncExecutor.html create mode 100644 lib/souffle-js/api/classes/executor_executor.SouffleExecutor.html create mode 100644 lib/souffle-js/api/classes/executor_executor.SouffleSyncExecutor.html create mode 100644 lib/souffle-js/api/classes/executor_results.SouffleOutputStructured.html create mode 100644 lib/souffle-js/api/classes/executor_results.SpaceSeparatedParser.html create mode 100644 lib/souffle-js/api/classes/logger.DefaultLogger.html create mode 100644 lib/souffle-js/api/classes/prettyPrinter.SoufflePrettyPrinter.html create mode 100644 lib/souffle-js/api/classes/syntaxConstructors.Type.html create mode 100644 lib/souffle-js/api/classes/syntaxConstructors.TypeDef.html create mode 100644 lib/souffle-js/api/functions/executor_results.parseResults.html create mode 100644 lib/souffle-js/api/functions/executor_results.parseResultsSync.html create mode 100644 lib/souffle-js/api/functions/executor_results.parseSpaceSeparatedValues.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.atom.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.binaryConstraint.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.body.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.booleanConstraint.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.comment.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.containsConstraint.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.fact.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.matchConstraint.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.program.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.relation.html create mode 100644 lib/souffle-js/api/functions/syntaxConstructors.rule.html create mode 100644 lib/souffle-js/api/functions/syntaxUtils.eqFactValues.html create mode 100644 lib/souffle-js/api/hierarchy.html create mode 100644 lib/souffle-js/api/index.html create mode 100644 lib/souffle-js/api/interfaces/executor_executor.SouffleExecutorParams.html create mode 100644 lib/souffle-js/api/interfaces/logger.ILogger.html create mode 100644 lib/souffle-js/api/media/simpleTypedVarPointsTo.ts create mode 100644 lib/souffle-js/api/modules/context.html create mode 100644 lib/souffle-js/api/modules/emitter.html create mode 100644 lib/souffle-js/api/modules/errors.html create mode 100644 lib/souffle-js/api/modules/executor.html create mode 100644 lib/souffle-js/api/modules/executor_executor.html create mode 100644 lib/souffle-js/api/modules/executor_results.html create mode 100644 lib/souffle-js/api/modules/index.html create mode 100644 lib/souffle-js/api/modules/logger.html create mode 100644 lib/souffle-js/api/modules/prettyPrinter.html create mode 100644 lib/souffle-js/api/modules/syntax.html create mode 100644 lib/souffle-js/api/modules/syntaxConstructors.html create mode 100644 lib/souffle-js/api/modules/syntaxUtils.html create mode 100644 lib/souffle-js/api/modules/version.html create mode 100644 lib/souffle-js/api/types/executor_executor.SouffleExecutionResult.html create mode 100644 lib/souffle-js/api/types/executor_results.SouffleOutputRaw.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleAtom.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleComment.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleConstraint.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleConstraintArg.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleConstraintOp.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleCustomType.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleEquivalenceTypeDefinition.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleFact.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleFactValue.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleNode.html create mode 100644 lib/souffle-js/api/types/syntax.SoufflePrimitiveType.html create mode 100644 lib/souffle-js/api/types/syntax.SoufflePrimitiveTypeValue.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleProgram.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleProgramEntry.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleRelation.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleRelationArg.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleRelationIO.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleRule.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleRuleBody.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleSubtypeTypeDefinition.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleType.html create mode 100644 lib/souffle-js/api/types/syntax.SouffleTypeDefinition.html create mode 100644 lib/souffle-js/api/types/syntaxConstructors.CommentValue.html create mode 100644 lib/souffle-js/api/variables/version.SOUFFLE_VERSION.html create mode 100644 markdown-page/index.html create mode 100644 sitemap.xml create mode 100644 tools/misti/api/.nojekyll create mode 100644 tools/misti/api/assets/custom.css create mode 100644 tools/misti/api/assets/highlight.css create mode 100644 tools/misti/api/assets/icons.js create mode 100644 tools/misti/api/assets/icons.svg create mode 100644 tools/misti/api/assets/main.js create mode 100644 tools/misti/api/assets/main.js.LICENSE.txt create mode 100644 tools/misti/api/assets/navigation.js create mode 100644 tools/misti/api/assets/search.js create mode 100644 tools/misti/api/assets/style.css create mode 100644 tools/misti/api/classes/cli_driver.Driver.html create mode 100644 tools/misti/api/classes/cli_singleContract.SingleContractProjectManager.html create mode 100644 tools/misti/api/classes/detectors_builtin_argCopyMutation.ArgCopyMutation.html create mode 100644 tools/misti/api/classes/detectors_builtin_asmIsUsed.AsmIsUsed.html create mode 100644 tools/misti/api/classes/detectors_builtin_branchDuplicate.BranchDuplicate.html create mode 100644 tools/misti/api/classes/detectors_builtin_cellOverflow.CellOverflow.html create mode 100644 tools/misti/api/classes/detectors_builtin_constantAddress.ConstantAddress.html create mode 100644 tools/misti/api/classes/detectors_builtin_divideBeforeMultiply.DivideBeforeMultiply.html create mode 100644 tools/misti/api/classes/detectors_builtin_dumpIsUsed.DumpIsUsed.html create mode 100644 tools/misti/api/classes/detectors_builtin_duplicatedCondition.DuplicatedCondition.html create mode 100644 tools/misti/api/classes/detectors_builtin_ensurePrgSeed.EnsurePrgSeed.html create mode 100644 tools/misti/api/classes/detectors_builtin_falseCondition.FalseCondition.html create mode 100644 tools/misti/api/classes/detectors_builtin_fieldDoubleInit.FieldDoubleInit.html create mode 100644 tools/misti/api/classes/detectors_builtin_inheritedStateMutation.InheritedStateMutation.html create mode 100644 tools/misti/api/classes/detectors_builtin_neverAccessedVariables.NeverAccessedVariables.html create mode 100644 tools/misti/api/classes/detectors_builtin_optimalMathFunction.OptimalMathFunction.html create mode 100644 tools/misti/api/classes/detectors_builtin_preferAugmentedAssign.PreferAugmentedAssign.html create mode 100644 tools/misti/api/classes/detectors_builtin_preferredStdlibApi.PreferredStdlibApi.html create mode 100644 tools/misti/api/classes/detectors_builtin_readOnlyVariables.ReadOnlyVariables.html create mode 100644 tools/misti/api/classes/detectors_builtin_stringReceiversOverlap.StringReceiversOverlap.html create mode 100644 tools/misti/api/classes/detectors_builtin_unboundLoops.UnboundLoops.html create mode 100644 tools/misti/api/classes/detectors_builtin_unusedOptional.UnusedOptional.html create mode 100644 tools/misti/api/classes/detectors_builtin_zeroAddress.ZeroAddress.html create mode 100644 tools/misti/api/classes/detectors_detector.ASTDetector.html create mode 100644 tools/misti/api/classes/detectors_detector.DataflowDetector.html create mode 100644 tools/misti/api/classes/detectors_detector.Detector.html create mode 100644 tools/misti/api/classes/detectors_detector.SouffleDetector.html create mode 100644 tools/misti/api/classes/internals_config.MistiConfig.html create mode 100644 tools/misti/api/classes/internals_context.MistiContext.html create mode 100644 tools/misti/api/classes/internals_exceptions.ExecutionException.html create mode 100644 tools/misti/api/classes/internals_exceptions.InternalException.html create mode 100644 tools/misti/api/classes/internals_exceptions.TactException.html create mode 100644 tools/misti/api/classes/internals_ir_astStore.TactASTStore.html create mode 100644 tools/misti/api/classes/internals_ir_builders_tactIRBuilder.TactIRBuilder.html create mode 100644 tools/misti/api/classes/internals_ir_cfg.BasicBlock.html create mode 100644 tools/misti/api/classes/internals_ir_cfg.CFG.html create mode 100644 tools/misti/api/classes/internals_ir_cfg.Edge.html create mode 100644 tools/misti/api/classes/internals_ir_ir.CompilationUnit.html create mode 100644 tools/misti/api/classes/internals_ir_ir.Contract.html create mode 100644 tools/misti/api/classes/internals_lattice.SetJoinSemilattice.html create mode 100644 tools/misti/api/classes/internals_lattice.SetMeetSemilattice.html create mode 100644 tools/misti/api/classes/internals_logger.DebugLogger.html create mode 100644 tools/misti/api/classes/internals_logger.Logger.html create mode 100644 tools/misti/api/classes/internals_logger.QuietLogger.html create mode 100644 tools/misti/api/classes/internals_logger.TraceLogger.html create mode 100644 tools/misti/api/classes/internals_solver_results.SolverResults.html create mode 100644 tools/misti/api/classes/internals_solver_souffle.SouffleSolver.html create mode 100644 tools/misti/api/classes/internals_solver_worklist.WorklistSolver.html create mode 100644 tools/misti/api/classes/internals_tact_util.SrcInfoSet.html create mode 100644 tools/misti/api/classes/internals_warnings.MistiTactWarning.html create mode 100644 tools/misti/api/classes/tools_dumpAst.DumpAst.html create mode 100644 tools/misti/api/classes/tools_dumpCfg.DumpCfg.html create mode 100644 tools/misti/api/classes/tools_dumpConfig.DumpConfig.html create mode 100644 tools/misti/api/classes/tools_tool.Tool.html create mode 100644 tools/misti/api/enums/cli_types.ExitCode.html create mode 100644 tools/misti/api/enums/internals_logger.LogLevel.html create mode 100644 tools/misti/api/enums/internals_warnings.Severity.html create mode 100644 tools/misti/api/functions/cli_cli.createMistiCommand.html create mode 100644 tools/misti/api/functions/cli_cli.executeMisti.html create mode 100644 tools/misti/api/functions/cli_cli.handleMistiResult.html create mode 100644 tools/misti/api/functions/cli_cli.runMistiCommand.html create mode 100644 tools/misti/api/functions/cli_result.resultToExitCode.html create mode 100644 tools/misti/api/functions/cli_result.resultToString.html create mode 100644 tools/misti/api/functions/cli_result.saveResultToFiles.html create mode 100644 tools/misti/api/functions/createDetector.createDetector.html create mode 100644 tools/misti/api/functions/detectors_detector.findBuiltInDetector.html create mode 100644 tools/misti/api/functions/detectors_detector.getAllDetectors.html create mode 100644 tools/misti/api/functions/detectors_detector.getEnabledDetectors.html create mode 100644 tools/misti/api/functions/detectors_detector.hasBuiltInDetector.html create mode 100644 tools/misti/api/functions/internals_exceptions.throwZodError.html create mode 100644 tools/misti/api/functions/internals_exceptions.tryMsg.html create mode 100644 tools/misti/api/functions/internals_ir_builders_tactIRBuilder.createIR.html create mode 100644 tools/misti/api/functions/internals_ir_builders_tactIRBuilder.setTactStdlibPath.html create mode 100644 tools/misti/api/functions/internals_ir_cfg.getPredecessors.html create mode 100644 tools/misti/api/functions/internals_ir_cfg.getSuccessors.html create mode 100644 tools/misti/api/functions/internals_ir_indices.IdxGenerator.__reset.html create mode 100644 tools/misti/api/functions/internals_ir_indices.IdxGenerator.next.html create mode 100644 tools/misti/api/functions/internals_tact_constEval.evalExpr.html create mode 100644 tools/misti/api/functions/internals_tact_constEval.evalToType.html create mode 100644 tools/misti/api/functions/internals_tact_constEval.evalsToPredicate.html create mode 100644 tools/misti/api/functions/internals_tact_constEval.evalsToValue.html create mode 100644 tools/misti/api/functions/internals_tact_iterators.extractPath.html create mode 100644 tools/misti/api/functions/internals_tact_iterators.findInExpressions.html create mode 100644 tools/misti/api/functions/internals_tact_iterators.foldExpressions.html create mode 100644 tools/misti/api/functions/internals_tact_iterators.foldStatements.html create mode 100644 tools/misti/api/functions/internals_tact_iterators.forEachExpression.html create mode 100644 tools/misti/api/functions/internals_tact_iterators.forEachStatement.html create mode 100644 tools/misti/api/functions/internals_tact_iterators.hasInExpressions.html create mode 100644 tools/misti/api/functions/internals_tact_util.collectConditions.html create mode 100644 tools/misti/api/functions/internals_tact_util.collectFields.html create mode 100644 tools/misti/api/functions/internals_tact_util.collectMutations.html create mode 100644 tools/misti/api/functions/internals_tact_util.formatPosition.html create mode 100644 tools/misti/api/functions/internals_tact_util.funName.html create mode 100644 tools/misti/api/functions/internals_tact_util.isPrimitiveLiteral.html create mode 100644 tools/misti/api/functions/internals_tact_util.isSelf.html create mode 100644 tools/misti/api/functions/internals_tact_util.isSelfAccess.html create mode 100644 tools/misti/api/functions/internals_tact_util.isStdlibMutationMethod.html create mode 100644 tools/misti/api/functions/internals_tact_util.mutationNames.html create mode 100644 tools/misti/api/functions/internals_tact_util.nodesAreEqual.html create mode 100644 tools/misti/api/functions/internals_tact_util.removeSelf.html create mode 100644 tools/misti/api/functions/internals_tact_util.statementsAreEqual.html create mode 100644 tools/misti/api/functions/internals_util.intersection.html create mode 100644 tools/misti/api/functions/internals_util.isListSubsetOf.html create mode 100644 tools/misti/api/functions/internals_util.isMapSubsetOf.html create mode 100644 tools/misti/api/functions/internals_util.isSubsetOf.html create mode 100644 tools/misti/api/functions/internals_util.mergeLists.html create mode 100644 tools/misti/api/functions/internals_util.mergeMaps.html create mode 100644 tools/misti/api/functions/internals_util.mergeSets.html create mode 100644 tools/misti/api/functions/internals_util.unreachable.html create mode 100644 tools/misti/api/functions/internals_warnings.makeDocURL.html create mode 100644 tools/misti/api/functions/internals_warnings.parseSeverity.html create mode 100644 tools/misti/api/functions/internals_warnings.severityToString.html create mode 100644 tools/misti/api/functions/tools_tool.findBuiltInTool.html create mode 100644 tools/misti/api/functions/tools_tool.generateToolsHelpMessage.html create mode 100644 tools/misti/api/functions/tools_tool.getAllTools.html create mode 100644 tools/misti/api/functions/tools_tool.hasBuiltInTool.html create mode 100644 tools/misti/api/hierarchy.html create mode 100644 tools/misti/api/index.html create mode 100644 tools/misti/api/interfaces/cli_options.CLIOptions.html create mode 100644 tools/misti/api/interfaces/cli_types.DetectorConfig.html create mode 100644 tools/misti/api/interfaces/cli_types.ToolConfig.html create mode 100644 tools/misti/api/interfaces/internals_lattice.JoinSemilattice.html create mode 100644 tools/misti/api/interfaces/internals_lattice.Lattice.html create mode 100644 tools/misti/api/interfaces/internals_lattice.MeetSemilattice.html create mode 100644 tools/misti/api/interfaces/internals_solver_solver.Solver.html create mode 100644 tools/misti/api/interfaces/internals_solver_souffle.SouffleMapper.html create mode 100644 tools/misti/api/interfaces/internals_transfer.Transfer.html create mode 100644 tools/misti/api/media/misti.png create mode 100644 tools/misti/api/modules/cli.html create mode 100644 tools/misti/api/modules/cli_cli.html create mode 100644 tools/misti/api/modules/cli_driver.html create mode 100644 tools/misti/api/modules/cli_options.html create mode 100644 tools/misti/api/modules/cli_result.html create mode 100644 tools/misti/api/modules/cli_singleContract.html create mode 100644 tools/misti/api/modules/cli_types.html create mode 100644 tools/misti/api/modules/createDetector.html create mode 100644 tools/misti/api/modules/detectors_builtin_argCopyMutation.html create mode 100644 tools/misti/api/modules/detectors_builtin_asmIsUsed.html create mode 100644 tools/misti/api/modules/detectors_builtin_branchDuplicate.html create mode 100644 tools/misti/api/modules/detectors_builtin_cellOverflow.html create mode 100644 tools/misti/api/modules/detectors_builtin_constantAddress.html create mode 100644 tools/misti/api/modules/detectors_builtin_divideBeforeMultiply.html create mode 100644 tools/misti/api/modules/detectors_builtin_dumpIsUsed.html create mode 100644 tools/misti/api/modules/detectors_builtin_duplicatedCondition.html create mode 100644 tools/misti/api/modules/detectors_builtin_ensurePrgSeed.html create mode 100644 tools/misti/api/modules/detectors_builtin_falseCondition.html create mode 100644 tools/misti/api/modules/detectors_builtin_fieldDoubleInit.html create mode 100644 tools/misti/api/modules/detectors_builtin_inheritedStateMutation.html create mode 100644 tools/misti/api/modules/detectors_builtin_neverAccessedVariables.html create mode 100644 tools/misti/api/modules/detectors_builtin_optimalMathFunction.html create mode 100644 tools/misti/api/modules/detectors_builtin_preferAugmentedAssign.html create mode 100644 tools/misti/api/modules/detectors_builtin_preferredStdlibApi.html create mode 100644 tools/misti/api/modules/detectors_builtin_readOnlyVariables.html create mode 100644 tools/misti/api/modules/detectors_builtin_stringReceiversOverlap.html create mode 100644 tools/misti/api/modules/detectors_builtin_unboundLoops.html create mode 100644 tools/misti/api/modules/detectors_builtin_unusedOptional.html create mode 100644 tools/misti/api/modules/detectors_builtin_zeroAddress.html create mode 100644 tools/misti/api/modules/detectors_detector.html create mode 100644 tools/misti/api/modules/index.html create mode 100644 tools/misti/api/modules/internals_config.html create mode 100644 tools/misti/api/modules/internals_context.html create mode 100644 tools/misti/api/modules/internals_exceptions.html create mode 100644 tools/misti/api/modules/internals_ir.html create mode 100644 tools/misti/api/modules/internals_ir_astStore.html create mode 100644 tools/misti/api/modules/internals_ir_builders_tactIRBuilder.html create mode 100644 tools/misti/api/modules/internals_ir_cfg.html create mode 100644 tools/misti/api/modules/internals_ir_indices.IdxGenerator.html create mode 100644 tools/misti/api/modules/internals_ir_indices.html create mode 100644 tools/misti/api/modules/internals_ir_ir.html create mode 100644 tools/misti/api/modules/internals_ir_types.html create mode 100644 tools/misti/api/modules/internals_lattice.html create mode 100644 tools/misti/api/modules/internals_logger.html create mode 100644 tools/misti/api/modules/internals_solver.html create mode 100644 tools/misti/api/modules/internals_solver_results.html create mode 100644 tools/misti/api/modules/internals_solver_solver.html create mode 100644 tools/misti/api/modules/internals_solver_souffle.html create mode 100644 tools/misti/api/modules/internals_solver_worklist.html create mode 100644 tools/misti/api/modules/internals_tact.html create mode 100644 tools/misti/api/modules/internals_tact_constEval.html create mode 100644 tools/misti/api/modules/internals_tact_iterators.html create mode 100644 tools/misti/api/modules/internals_tact_util.html create mode 100644 tools/misti/api/modules/internals_transfer.html create mode 100644 tools/misti/api/modules/internals_util.html create mode 100644 tools/misti/api/modules/internals_warnings.html create mode 100644 tools/misti/api/modules/main.html create mode 100644 tools/misti/api/modules/tools.html create mode 100644 tools/misti/api/modules/tools_dumpAst.html create mode 100644 tools/misti/api/modules/tools_dumpCfg.html create mode 100644 tools/misti/api/modules/tools_dumpConfig.html create mode 100644 tools/misti/api/modules/tools_tool.html create mode 100644 tools/misti/api/modules/version.html create mode 100644 tools/misti/api/modules/version_info.html create mode 100644 tools/misti/api/types/cli_result.MistiResult.html create mode 100644 tools/misti/api/types/cli_result.MistiResultError.html create mode 100644 tools/misti/api/types/cli_result.MistiResultOK.html create mode 100644 tools/misti/api/types/cli_result.MistiResultTool.html create mode 100644 tools/misti/api/types/cli_result.MistiResultWarnings.html create mode 100644 tools/misti/api/types/cli_result.ResultReport.html create mode 100644 tools/misti/api/types/cli_result.ToolOutput.html create mode 100644 tools/misti/api/types/cli_result.WarningOutput.html create mode 100644 tools/misti/api/types/cli_types.OutputFormat.html create mode 100644 tools/misti/api/types/detectors_detector.DetectorKind.html create mode 100644 tools/misti/api/types/detectors_detector.DetectorName.html create mode 100644 tools/misti/api/types/detectors_detector.WarningsBehavior.html create mode 100644 tools/misti/api/types/internals_config.WarningSuppression.html create mode 100644 tools/misti/api/types/internals_ir_builders_tactIRBuilder.FunctionsMap.html create mode 100644 tools/misti/api/types/internals_ir_builders_tactIRBuilder.MethodsMap.html create mode 100644 tools/misti/api/types/internals_ir_cfg.BasicBlockKind.html create mode 100644 tools/misti/api/types/internals_ir_cfg.EntryOrigin.html create mode 100644 tools/misti/api/types/internals_ir_cfg.FunctionKind.html create mode 100644 tools/misti/api/types/internals_ir_types.BasicBlockIdx.html create mode 100644 tools/misti/api/types/internals_ir_types.CFGIdx.html create mode 100644 tools/misti/api/types/internals_ir_types.ContractIdx.html create mode 100644 tools/misti/api/types/internals_ir_types.ContractName.html create mode 100644 tools/misti/api/types/internals_ir_types.EdgeIdx.html create mode 100644 tools/misti/api/types/internals_ir_types.FunctionName.html create mode 100644 tools/misti/api/types/internals_ir_types.ProjectName.html create mode 100644 tools/misti/api/types/internals_logger.LogFunction.html create mode 100644 tools/misti/api/types/internals_solver_worklist.AnalysisKind.html create mode 100644 tools/misti/api/types/internals_tact_util.MutatedElement.html create mode 100644 tools/misti/api/types/tools_tool.ToolName.html create mode 100644 tools/misti/api/variables/cli_options.STDOUT_PATH.html create mode 100644 tools/misti/api/variables/cli_options.cliOptionDefaults.html create mode 100644 tools/misti/api/variables/cli_options.cliOptions-1.html create mode 100644 tools/misti/api/variables/detectors_detector.BuiltInDetectors.html create mode 100644 tools/misti/api/variables/internals_ir_builders_tactIRBuilder.DEFAULT_STDLIB_PATH_ELEMENTS.html create mode 100644 tools/misti/api/variables/internals_warnings.BASE_DOC_URL.html create mode 100644 tools/misti/api/variables/version_info.MISTI_VERSION.html create mode 100644 tools/misti/api/variables/version_info.TACT_VERSION.html create mode 100644 tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply/index.html create mode 100644 tools/misti/docs/0.1.2/detectors/NeverAccessedVariables/index.html create mode 100644 tools/misti/docs/0.1.2/detectors/ReadOnlyVariables/index.html create mode 100644 tools/misti/docs/0.1.2/detectors/UnboundLoops/index.html create mode 100644 tools/misti/docs/0.1.2/detectors/ZeroAddress/index.html create mode 100644 tools/misti/docs/0.1.2/hacking/CHANGELOG/index.html create mode 100644 tools/misti/docs/0.1.2/hacking/contributing/index.html create mode 100644 tools/misti/docs/0.1.2/hacking/custom-detector/index.html create mode 100644 tools/misti/docs/0.1.2/hacking/design/index.html create mode 100644 tools/misti/docs/0.1.2/hacking/souffle/index.html create mode 100644 tools/misti/docs/0.1.2/hacking/tools/index.html create mode 100644 tools/misti/docs/0.1.2/index.html create mode 100644 tools/misti/docs/0.1.2/tutorial/configuration/index.html create mode 100644 tools/misti/docs/0.1.2/tutorial/getting-started/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/BranchDuplicate/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/ConstantAddress/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/DumpIsUsed/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/FieldDoubleInit/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/NeverAccessedVariables/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/ReadOnlyVariables/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/UnboundLoops/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/ZeroAddress/index.html create mode 100644 tools/misti/docs/0.2.0/detectors/index.html create mode 100644 tools/misti/docs/0.2.0/hacking/contributing/index.html create mode 100644 tools/misti/docs/0.2.0/hacking/custom-detector/index.html create mode 100644 tools/misti/docs/0.2.0/hacking/design/index.html create mode 100644 tools/misti/docs/0.2.0/hacking/souffle/index.html create mode 100644 tools/misti/docs/0.2.0/hacking/tools/index.html create mode 100644 tools/misti/docs/0.2.0/index.html create mode 100644 tools/misti/docs/0.2.0/tutorial/ci-cd/index.html create mode 100644 tools/misti/docs/0.2.0/tutorial/configuration/index.html create mode 100644 tools/misti/docs/0.2.0/tutorial/getting-started/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/BranchDuplicate/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/ConstantAddress/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/DumpIsUsed/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/FieldDoubleInit/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/NeverAccessedVariables/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/ReadOnlyVariables/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/UnboundLoops/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/ZeroAddress/index.html create mode 100644 tools/misti/docs/0.2.1/detectors/index.html create mode 100644 tools/misti/docs/0.2.1/hacking/contributing/index.html create mode 100644 tools/misti/docs/0.2.1/hacking/custom-detector/index.html create mode 100644 tools/misti/docs/0.2.1/hacking/design/index.html create mode 100644 tools/misti/docs/0.2.1/hacking/souffle/index.html create mode 100644 tools/misti/docs/0.2.1/hacking/tools/index.html create mode 100644 tools/misti/docs/0.2.1/index.html create mode 100644 tools/misti/docs/0.2.1/tutorial/ci-cd/index.html create mode 100644 tools/misti/docs/0.2.1/tutorial/configuration/index.html create mode 100644 tools/misti/docs/0.2.1/tutorial/getting-started/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/BranchDuplicate/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/ConstantAddress/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/DumpIsUsed/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/FieldDoubleInit/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/NeverAccessedVariables/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/ReadOnlyVariables/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/UnboundLoops/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/ZeroAddress/index.html create mode 100644 tools/misti/docs/0.2.2/detectors/index.html create mode 100644 tools/misti/docs/0.2.2/hacking/contributing/index.html create mode 100644 tools/misti/docs/0.2.2/hacking/custom-detector/index.html create mode 100644 tools/misti/docs/0.2.2/hacking/design/index.html create mode 100644 tools/misti/docs/0.2.2/hacking/souffle/index.html create mode 100644 tools/misti/docs/0.2.2/hacking/tools/index.html create mode 100644 tools/misti/docs/0.2.2/index.html create mode 100644 tools/misti/docs/0.2.2/tutorial/blueprint/index.html create mode 100644 tools/misti/docs/0.2.2/tutorial/ci-cd/index.html create mode 100644 tools/misti/docs/0.2.2/tutorial/configuration/index.html create mode 100644 tools/misti/docs/0.2.2/tutorial/getting-started/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/ArgCopyMutation/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/AsmIsUsed/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/BranchDuplicate/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/ConstantAddress/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/DumpIsUsed/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/FieldDoubleInit/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/InheritedStateMutation/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/NeverAccessedVariables/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/PreferredStdlibApi/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/ReadOnlyVariables/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/StringReceiversOverlap/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/UnboundLoops/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/ZeroAddress/index.html create mode 100644 tools/misti/docs/0.3.0/detectors/index.html create mode 100644 tools/misti/docs/0.3.0/hacking/contributing/index.html create mode 100644 tools/misti/docs/0.3.0/hacking/custom-detector/index.html create mode 100644 tools/misti/docs/0.3.0/hacking/design/index.html create mode 100644 tools/misti/docs/0.3.0/hacking/souffle/index.html create mode 100644 tools/misti/docs/0.3.0/hacking/tools/index.html create mode 100644 tools/misti/docs/0.3.0/index.html create mode 100644 tools/misti/docs/0.3.0/tutorial/blueprint/index.html create mode 100644 tools/misti/docs/0.3.0/tutorial/ci-cd/index.html create mode 100644 tools/misti/docs/0.3.0/tutorial/cli/index.html create mode 100644 tools/misti/docs/0.3.0/tutorial/configuration/index.html create mode 100644 tools/misti/docs/0.3.0/tutorial/getting-started/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/ArgCopyMutation/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/AsmIsUsed/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/BranchDuplicate/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/ConstantAddress/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/DumpIsUsed/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/FieldDoubleInit/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/InheritedStateMutation/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/NeverAccessedVariables/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/PreferredStdlibApi/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/ReadOnlyVariables/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/StringReceiversOverlap/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/UnboundLoops/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/ZeroAddress/index.html create mode 100644 tools/misti/docs/0.3.1/detectors/index.html create mode 100644 tools/misti/docs/0.3.1/hacking/contributing/index.html create mode 100644 tools/misti/docs/0.3.1/hacking/custom-detector/index.html create mode 100644 tools/misti/docs/0.3.1/hacking/design/index.html create mode 100644 tools/misti/docs/0.3.1/hacking/souffle/index.html create mode 100644 tools/misti/docs/0.3.1/hacking/tools/index.html create mode 100644 tools/misti/docs/0.3.1/index.html create mode 100644 tools/misti/docs/0.3.1/tutorial/blueprint/index.html create mode 100644 tools/misti/docs/0.3.1/tutorial/ci-cd/index.html create mode 100644 tools/misti/docs/0.3.1/tutorial/cli/index.html create mode 100644 tools/misti/docs/0.3.1/tutorial/configuration/index.html create mode 100644 tools/misti/docs/0.3.1/tutorial/getting-started/index.html create mode 100644 tools/misti/docs/detectors/ArgCopyMutation/index.html create mode 100644 tools/misti/docs/detectors/AsmIsUsed/index.html create mode 100644 tools/misti/docs/detectors/BranchDuplicate/index.html create mode 100644 tools/misti/docs/detectors/ConstantAddress/index.html create mode 100644 tools/misti/docs/detectors/DivideBeforeMultiply/index.html create mode 100644 tools/misti/docs/detectors/DumpIsUsed/index.html create mode 100644 tools/misti/docs/detectors/DuplicatedCondition/index.html create mode 100644 tools/misti/docs/detectors/EnsurePrgSeed/index.html create mode 100644 tools/misti/docs/detectors/FalseCondition/index.html create mode 100644 tools/misti/docs/detectors/FieldDoubleInit/index.html create mode 100644 tools/misti/docs/detectors/InheritedStateMutation/index.html create mode 100644 tools/misti/docs/detectors/NeverAccessedVariables/index.html create mode 100644 tools/misti/docs/detectors/OptimalMathFunction/index.html create mode 100644 tools/misti/docs/detectors/PreferAugmentedAssign/index.html create mode 100644 tools/misti/docs/detectors/PreferredStdlibApi/index.html create mode 100644 tools/misti/docs/detectors/ReadOnlyVariables/index.html create mode 100644 tools/misti/docs/detectors/StringReceiversOverlap/index.html create mode 100644 tools/misti/docs/detectors/UnboundLoops/index.html create mode 100644 tools/misti/docs/detectors/UnusedOptional/index.html create mode 100644 tools/misti/docs/detectors/ZeroAddress/index.html create mode 100644 tools/misti/docs/detectors/index.html create mode 100644 tools/misti/docs/hacking/contributing/index.html create mode 100644 tools/misti/docs/hacking/custom-detector/index.html create mode 100644 tools/misti/docs/hacking/design/index.html create mode 100644 tools/misti/docs/hacking/developing-misti/index.html create mode 100644 tools/misti/docs/hacking/souffle/index.html create mode 100644 tools/misti/docs/index.html create mode 100644 tools/misti/docs/next/detectors/ArgCopyMutation/index.html create mode 100644 tools/misti/docs/next/detectors/AsmIsUsed/index.html create mode 100644 tools/misti/docs/next/detectors/BranchDuplicate/index.html create mode 100644 tools/misti/docs/next/detectors/ConstantAddress/index.html create mode 100644 tools/misti/docs/next/detectors/DivideBeforeMultiply/index.html create mode 100644 tools/misti/docs/next/detectors/DumpIsUsed/index.html create mode 100644 tools/misti/docs/next/detectors/DuplicatedCondition/index.html create mode 100644 tools/misti/docs/next/detectors/EnsurePrgSeed/index.html create mode 100644 tools/misti/docs/next/detectors/FalseCondition/index.html create mode 100644 tools/misti/docs/next/detectors/FieldDoubleInit/index.html create mode 100644 tools/misti/docs/next/detectors/InheritedStateMutation/index.html create mode 100644 tools/misti/docs/next/detectors/NeverAccessedVariables/index.html create mode 100644 tools/misti/docs/next/detectors/OptimalMathFunction/index.html create mode 100644 tools/misti/docs/next/detectors/PreferAugmentedAssign/index.html create mode 100644 tools/misti/docs/next/detectors/PreferredStdlibApi/index.html create mode 100644 tools/misti/docs/next/detectors/ReadOnlyVariables/index.html create mode 100644 tools/misti/docs/next/detectors/StringReceiversOverlap/index.html create mode 100644 tools/misti/docs/next/detectors/UnboundLoops/index.html create mode 100644 tools/misti/docs/next/detectors/UnusedOptional/index.html create mode 100644 tools/misti/docs/next/detectors/ZeroAddress/index.html create mode 100644 tools/misti/docs/next/detectors/index.html create mode 100644 tools/misti/docs/next/hacking/contributing/index.html create mode 100644 tools/misti/docs/next/hacking/custom-detector/index.html create mode 100644 tools/misti/docs/next/hacking/design/index.html create mode 100644 tools/misti/docs/next/hacking/developing-misti/index.html create mode 100644 tools/misti/docs/next/hacking/souffle/index.html create mode 100644 tools/misti/docs/next/index.html create mode 100644 tools/misti/docs/next/tools/DumpAst/index.html create mode 100644 tools/misti/docs/next/tools/DumpCfg/index.html create mode 100644 tools/misti/docs/next/tools/DumpConfig/index.html create mode 100644 tools/misti/docs/next/tools/index.html create mode 100644 tools/misti/docs/next/tutorial/blueprint/index.html create mode 100644 tools/misti/docs/next/tutorial/ci-cd/index.html create mode 100644 tools/misti/docs/next/tutorial/cli/index.html create mode 100644 tools/misti/docs/next/tutorial/configuration/index.html create mode 100644 tools/misti/docs/next/tutorial/getting-started/index.html create mode 100644 tools/misti/docs/tools/DumpAst/index.html create mode 100644 tools/misti/docs/tools/DumpCfg/index.html create mode 100644 tools/misti/docs/tools/DumpConfig/index.html create mode 100644 tools/misti/docs/tools/index.html create mode 100644 tools/misti/docs/tutorial/blueprint/index.html create mode 100644 tools/misti/docs/tutorial/ci-cd/index.html create mode 100644 tools/misti/docs/tutorial/cli/index.html create mode 100644 tools/misti/docs/tutorial/configuration/index.html create mode 100644 tools/misti/docs/tutorial/getting-started/index.html create mode 100644 tools/misti/index.html diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/404.html b/404.html new file mode 100644 index 000000000..ade25fe44 --- /dev/null +++ b/404.html @@ -0,0 +1,21 @@ + + + + + +Page Not Found | Misti + + + + +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

+ + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 000000000..9c30bb3f2 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +nowarp.io diff --git a/assets/css/styles.57cb5423.css b/assets/css/styles.57cb5423.css new file mode 100644 index 000000000..60857f162 --- /dev/null +++ b/assets/css/styles.57cb5423.css @@ -0,0 +1 @@ +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#0a3d62;--ifm-color-secondary:#34b3f1;--ifm-color-accent:#00e6e6;--ifm-color-light:#d3d3d3;--ifm-color-white:#fff;--ifm-color-primary-dark:#093457;--ifm-color-primary-darker:#082b4c;--ifm-color-primary-darkest:#072341;--ifm-color-primary-light:#145488;--ifm-color-primary-lighter:#1661a3;--ifm-color-primary-lightest:#1873c2;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0a3d621a;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_Gvgb,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_BuS1>:last-child,.collapsibleContent_i85q p:last-child,.details_lb9f>summary>p:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;top:0;left:0;visibility:hidden}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;content:"";filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.footer__copyright a:active,.footer__copyright a:hover,.footer__link-item:active,.footer__link-item:hover{color:#1873c2}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]{--ifm-color-primary:#4b87b3;--ifm-color-secondary:#66c5f8;--ifm-color-accent:#6ff;--ifm-color-light:#e6e6e6;--ifm-color-white:#fff;--ifm-color-primary-dark:#4f97c9;--ifm-color-primary-darker:#549bda;--ifm-color-primary-darkest:#5ab0f0;--ifm-color-primary-light:#4b8ccc;--ifm-color-primary-lighter:#66a7db;--ifm-color-primary-lightest:#81c3ed;--docusaurus-highlighted-code-line-bg:#4b87b34d}.footer__links{display:grid;gap:2rem;grid-template-columns:auto auto;justify-content:start;padding:1rem}.footer__copyright a,.footer__link-item{color:#34b3f1}.menu__link--active{background-color:#e6f7ff!important;color:var(--ifm-color-primary);font-weight:700}a.table-of-contents__link--active{font-weight:700}.sidebars-separator{border:none!important;border-top:.5px solid #ccc!important;box-sizing:initial!important;height:0!important;margin:5px 0!important}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}#__docusaurus-base-url-issue-banner-container,.docSidebarContainer_YfHR,.navbarSearchContainer_Bca1:empty,.sidebarLogo_isFc,.themedComponent_mlkZ,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_xIcU,[data-theme=light] .themedComponent--light_NVdE,html:not([data-theme]) .themedComponent--light_NVdE{display:initial}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.iconExternalLink_nPIU{margin-left:.3rem}.docMainContainer_TBSr,.docRoot_UBD9{display:flex;width:100%}.docsWrapper_hBAB{display:flex;flex:1 0 auto}.dropdownNavbarItemMobile_S0Fm{cursor:pointer}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.errorBoundaryFallback_VBag{color:red;padding:.55rem}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.heroBanner_hAhw{overflow:hidden;padding:4rem 0;position:relative;text-align:center}.buttons_YgGx{align-items:center;display:flex;justify-content:center}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{left:0;position:absolute;top:0;fill:currentColor;height:inherit;opacity:inherit;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.lastUpdated_JAkA{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.img_ev3q{height:auto}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.admonition_xJq3{margin-bottom:1em}.admonitionHeading_Gvgb{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family)}.admonitionHeading_Gvgb:not(:last-child){margin-bottom:.3rem}.admonitionHeading_Gvgb code{text-transform:none}.admonitionIcon_Rf37{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_Rf37 svg{display:inline-block;height:1.6em;width:1.6em;fill:var(--ifm-alert-foreground-color)}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.mdxPageWrapper_j9I6{justify-content:center}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_TmdG{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_i1dp,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_TmdG:focus,.expandButton_TmdG:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_TmdG{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_i1dp{transform:rotate(180deg)}.docSidebarContainer_YfHR{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_DPk8{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_aRkj{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_TBSr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_lQrH{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_JWYK{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.navbarSearchContainer_Bca1{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_JAkA{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.navbarSearchContainer_Bca1{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media screen and (max-width:996px){.heroBanner_hAhw{padding:2rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/images/blueprint-select-project-b8656fa4266c0c7923d6b67c7f5950e6.png b/assets/images/blueprint-select-project-b8656fa4266c0c7923d6b67c7f5950e6.png new file mode 100644 index 0000000000000000000000000000000000000000..fbc35d186ac0f1719a101413ee5f8dee76e4d84e GIT binary patch literal 11492 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 yqi($cn|MLg{a{n.r(e),n.d(e,{assets:()=>a,contentTitle:()=>r,default:()=>l,frontMatter:()=>s,metadata:()=>u,toc:()=>c});var o=n(4848),i=n(8453);const s={},r="DumpConfig",u={id:"tools/DumpConfig",title:"DumpConfig",description:"The DumpConfig tool in Misti allows you to print the current configuration file used by the analyzer. This is useful for obtaining the default configuration to use as a starting point for your custom setup or to inspect and understand the existing configuration in use.",source:"@site/docs/tools/DumpConfig.md",sourceDirName:"tools",slug:"/tools/DumpConfig",permalink:"/tools/misti/docs/next/tools/DumpConfig",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tools/DumpConfig.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpCfg",permalink:"/tools/misti/docs/next/tools/DumpCfg"},next:{title:"Design Overview",permalink:"/tools/misti/docs/next/hacking/design"}},a={},c=[{value:"Usage",id:"usage",level:2},{value:"Understanding the Output",id:"understanding-the-output",level:2}];function d(t){const e={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...t.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(e.h1,{id:"dumpconfig",children:"DumpConfig"}),"\n",(0,o.jsxs)(e.p,{children:["The ",(0,o.jsx)(e.code,{children:"DumpConfig"})," tool in Misti allows you to print the current configuration file used by the analyzer. This is useful for obtaining the default configuration to use as a starting point for your custom setup or to inspect and understand the existing configuration in use."]}),"\n",(0,o.jsx)(e.h2,{id:"usage",children:"Usage"}),"\n",(0,o.jsx)(e.p,{children:"To dump the configuration file, use the following command:"}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpConfig" \n'})}),"\n",(0,o.jsx)(e.h2,{id:"understanding-the-output",children:"Understanding the Output"}),"\n",(0,o.jsx)(e.p,{children:"The output provides an overview of all the configurations and settings applied to your project. This can help you quickly identify the default settings, make adjustments to fit your specific needs, and ensure that your custom detectors are running under the correct configurations."})]})}function l(t={}){const{wrapper:e}={...(0,i.R)(),...t.components};return e?(0,o.jsx)(e,{...t,children:(0,o.jsx)(d,{...t})}):d(t)}},8453:(t,e,n)=>{n.d(e,{R:()=>r,x:()=>u});var o=n(6540);const i={},s=o.createContext(i);function r(t){const e=o.useContext(s);return o.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function u(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(i):t.components||i:r(t.components),o.createElement(s.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/01419b1f.55a4ac68.js b/assets/js/01419b1f.55a4ac68.js new file mode 100644 index 000000000..b60070563 --- /dev/null +++ b/assets/js/01419b1f.55a4ac68.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4371],{4622:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>l,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var i=n(4848),s=n(8453);const r={},l="Getting started",o={id:"tutorial/getting-started",title:"Getting started",description:"This guide will walk you through the steps to install and set up the Misti static analyzer.",source:"@site/versioned_docs/version-0.2.0/tutorial/getting-started.md",sourceDirName:"tutorial",slug:"/tutorial/getting-started",permalink:"/tools/misti/docs/0.2.0/tutorial/getting-started",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/tutorial/getting-started.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Introduction",permalink:"/tools/misti/docs/0.2.0/"},next:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.2.0/tutorial/ci-cd"}},a={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Using Development Version",id:"using-development-version",level:3},{value:"Running the analysis",id:"running-the-analysis",level:2},{value:"Troubleshooting",id:"troubleshooting",level:2}];function c(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,i.jsx)(t.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsx)(t.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Git"}),"\n",(0,i.jsx)(t.li,{children:"Yarn"}),"\n",(0,i.jsx)(t.li,{children:"Node.js"}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"installation",children:"Installation"}),"\n",(0,i.jsxs)(t.p,{children:["Misti is distributed via npm and should be added to your Tact project ",(0,i.jsx)(t.a,{href:"https://github.com/tact-lang/tact?tab=readme-ov-file#installation",children:"in the same way"})," as Tact itself:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"yarn add @nowarp/misti\n"})}),"\n",(0,i.jsx)(t.h3,{id:"using-development-version",children:"Using Development Version"}),"\n",(0,i.jsx)(t.p,{children:"The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis."}),"\n",(0,i.jsx)(t.p,{children:"To install the latest development version you should:"}),"\n",(0,i.jsxs)(t.ol,{children:["\n",(0,i.jsxs)(t.li,{children:["Clone Misti: ",(0,i.jsx)(t.code,{children:"git clone https://github.com/nowarp/misti"})]}),"\n",(0,i.jsxs)(t.li,{children:["Build it: ",(0,i.jsx)(t.code,{children:"cd misti && yarn install && yarn build"})]}),"\n",(0,i.jsxs)(t.li,{children:["Use it in your Tact project: ",(0,i.jsx)(t.code,{children:"cd /path/to/tact/project && yarn add file:/path/to/misti"})]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,i.jsx)(t.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{children:"npx misti test/projects/simple/tactConfig.json\n"})}),"\n",(0,i.jsx)(t.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,i.jsxs)(t.p,{children:["You can also add a script to your ",(0,i.jsx)(t.code,{children:"package.json"})," to simplify running the linting process:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-json",children:'{\n "scripts": {\n "lint": "npx misti test/projects/simple/tactConfig.json"\n }\n}\n'})}),"\n",(0,i.jsx)(t.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsxs)(t.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,i.jsx)(t.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>l,x:()=>o});var i=n(6540);const s={},r=i.createContext(s);function l(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/06bf7bd2.93cfb521.js b/assets/js/06bf7bd2.93cfb521.js new file mode 100644 index 000000000..fc3c4245f --- /dev/null +++ b/assets/js/06bf7bd2.93cfb521.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[804],{6538:(i,e,t)=>{t.r(e),t.d(e,{assets:()=>o,contentTitle:()=>I,default:()=>c,frontMatter:()=>l,metadata:()=>d,toc:()=>g});var n=t(4848),s=t(8453);const l={},I="Tools Guide",d={id:"hacking/tools",title:"Tools Guide",description:"This page describes the internal analyzer tools available in Misti to aid in development and debugging.",source:"@site/versioned_docs/version-0.2.2/hacking/tools.md",sourceDirName:"hacking",slug:"/hacking/tools",permalink:"/tools/misti/docs/0.2.2/hacking/tools",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/hacking/tools.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.2.2/hacking/souffle"},next:{title:"Custom Detectors",permalink:"/tools/misti/docs/0.2.2/hacking/custom-detector"}},o={},g=[{value:"CFG Dump",id:"cfg-dump",level:2},{value:"Usage",id:"usage",level:3},{value:"Converting DOT to SVG",id:"converting-dot-to-svg",level:3},{value:"Viewing the SVG",id:"viewing-the-svg",level:3},{value:"VS Code Plugin",id:"vs-code-plugin",level:3},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function a(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"tools-guide",children:"Tools Guide"}),"\n",(0,n.jsx)(e.p,{children:"This page describes the internal analyzer tools available in Misti to aid in development and debugging."}),"\n",(0,n.jsx)(e.h2,{id:"cfg-dump",children:"CFG Dump"}),"\n",(0,n.jsx)(e.p,{children:"Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts."}),"\n",(0,n.jsx)(e.h3,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in JSON format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="json" \n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in DOT format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" \n'})}),"\n",(0,n.jsx)(e.h3,{id:"converting-dot-to-svg",children:"Converting DOT to SVG"}),"\n",(0,n.jsxs)(e.p,{children:["To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use ",(0,n.jsx)(e.a,{href:"https://graphviz.org",children:"Graphviz"})," with the following command:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" > output.dot\ndot -Tsvg output.dot -o output.svg\n'})}),"\n",(0,n.jsx)(e.h3,{id:"viewing-the-svg",children:"Viewing the SVG"}),"\n",(0,n.jsx)(e.p,{children:"To view the SVG file in Firefox, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"firefox output.svg\n"})}),"\n",(0,n.jsx)(e.p,{children:"For example, for the following contract:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:"fun test(): Int {\n let sum: Int = 0;\n let i: Int = 0;\n repeat (10) {\n i = i + 1;\n sum = sum + i;\n }\n return sum;\n}\n"})}),"\n",(0,n.jsx)(e.p,{children:"The following CFG will be generated:"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"CFG Example",src:t(685).A+"",width:"337",height:"516"})}),"\n",(0,n.jsx)(e.h3,{id:"vs-code-plugin",children:"VS Code Plugin"}),"\n",(0,n.jsxs)(e.p,{children:["For real-time visualization of DOT files, you can use ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/search?term=tag%3Agraphviz&target=VSCode&category=All%20categories&sortBy=Relevance",children:"one of the available"})," Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development."]}),"\n",(0,n.jsx)(e.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"JSON Dumps"}),": These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"DOT Dumps"}),": These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(e.p,{children:"By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors."})]})}function c(i={}){const{wrapper:e}={...(0,s.R)(),...i.components};return e?(0,n.jsx)(e,{...i,children:(0,n.jsx)(a,{...i})}):a(i)}},685:(i,e,t)=>{t.d(e,{A:()=>n});const n="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDIuNCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBsb29wcyYjNDU7MyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjUzcHQiIGhlaWdodD0iMzg3cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjUzLjAwIDM4Ny4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzODMpIj4KPHRpdGxlPmxvb3BzJiM0NTszPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzgzIDI0OSwtMzgzIDI0OSw0IC00LDQiLz4KPGcgaWQ9ImNsdXN0MSIgY2xhc3M9ImNsdXN0ZXIiPgo8dGl0bGU+Y2x1c3Rlcl90ZXN0PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI4LC04IDgsLTM3MSAyMzcsLTM3MSAyMzcsLTggOCwtOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIuNSIgeT0iLTM1NS44IiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnRlc3Q8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0MSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT50ZXN0XzE0MTwvdGl0bGU+Cjxwb2x5Z29uIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjI0LjUsLTM0MCA5NS41LC0zNDAgOTUuNSwtMzA0IDIyNC41LC0zMDQgMjI0LjUsLTM0MCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNjAiIHk9Ii0zMTguMyIgZm9udC1mYW1pbHk9IlRpbWVzLHNlcmlmIiBmb250LXNpemU9IjE0LjAwIj5sZXQgc3VtOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDI8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMiwtMjY4IDEwOCwtMjY4IDEwOCwtMjMyIDIxMiwtMjMyIDIxMiwtMjY4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTI0Ni4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPmxldCBpOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDEmIzQ1OyZndDt0ZXN0XzE0MiAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MSYjNDU7Jmd0O3Rlc3RfMTQyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMzAzLjdDMTYwLC0yOTUuOTggMTYwLC0yODYuNzEgMTYwLC0yNzguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTI3OC4xIDE2MCwtMjY4LjEgMTU2LjUsLTI3OC4xIDE2My41LC0yNzguMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDQ8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOCwtMTk2IDExMiwtMTk2IDExMiwtMTYwIDIwOCwtMTYwIDIwOCwtMTk2Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTE3NC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnJlcGVhdCAoMTApPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDImIzQ1OyZndDt0ZXN0XzE0NCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MiYjNDU7Jmd0O3Rlc3RfMTQ0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMjMxLjdDMTYwLC0yMjMuOTggMTYwLC0yMTQuNzEgMTYwLC0yMDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTIwNi4xIDE2MCwtMTk2LjEgMTU2LjUsLTIwNi4xIDE2My41LC0yMDYuMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDYgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDY8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjkzLjUsLTEyNCAxNi41LC0xMjQgMTYuNSwtODggOTMuNSwtODggOTMuNSwtMTI0Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjU1IiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+aSA9IGkgKyAxPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE0NiAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0NCYjNDU7Jmd0O3Rlc3RfMTQ2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEzNC4zMSwtMTU5Ljg4QzEyMC43MSwtMTUwLjgxIDEwMy44MywtMTM5LjU1IDg5LjE0LC0xMjkuNzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iOTEuMDUsLTEyNi44MiA4MC43OCwtMTI0LjE5IDg3LjE2LC0xMzIuNjUgOTEuMDUsLTEyNi44MiIvPgo8L2c+CjwhLS0gdGVzdF8xNTEgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNTE8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjNjZhN2RiIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOC41LC0xMjQgMTExLjUsLTEyNCAxMTEuNSwtODggMjA4LjUsLTg4IDIwOC41LC0xMjQiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTYwIiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+cmV0dXJuIHN1bTwvdGV4dD4KPC9nPgo8IS0tIHRlc3RfMTQ0JiM0NTsmZ3Q7dGVzdF8xNTEgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE1MTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNjAsLTE1OS43QzE2MCwtMTUxLjk4IDE2MCwtMTQyLjcxIDE2MCwtMTM0LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2My41LC0xMzQuMSAxNjAsLTEyNC4xIDE1Ni41LC0xMzQuMSAxNjMuNSwtMTM0LjEiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPnRlc3RfMTQ4PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxODMuNSwtNTIgNjAuNSwtNTIgNjAuNSwtMTYgMTgzLjUsLTE2IDE4My41LC01MiIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIiIHk9Ii0zMC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnN1bSA9IHN1bSArIGk8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0NiYjNDU7Jmd0O3Rlc3RfMTQ4IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPnRlc3RfMTQ2JiM0NTsmZ3Q7dGVzdF8xNDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuNTYsLTg3LjdDNzkuNjgsLTc5LjIyIDg5LjU5LC02OC44NiA5OC40NywtNTkuNTgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAxLjI0LC02MS43NSAxMDUuNjMsLTUyLjEgOTYuMTksLTU2LjkxIDEwMS4yNCwtNjEuNzUiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4JiM0NTsmZ3Q7dGVzdF8xNDQgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDgmIzQ1OyZndDt0ZXN0XzE0NDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzUuMjIsLTUyLjA0QzE5MS44OSwtNjAuMTYgMjA4LjQyLC03MS43NyAyMTgsLTg4IDIyNi4xMywtMTAxLjc4IDIyNC40NSwtMTA5LjM2IDIxOCwtMTI0IDIxMy4wMSwtMTM1LjMxIDIwNC4yOSwtMTQ1LjI2IDE5NS4xLC0xNTMuMzgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTkyLjgzLC0xNTAuNzIgMTg3LjM0LC0xNTkuNzcgMTk3LjI4LC0xNTYuMTIgMTkyLjgzLC0xNTAuNzIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8453:(i,e,t)=>{t.d(e,{R:()=>I,x:()=>d});var n=t(6540);const s={},l=n.createContext(s);function I(i){const e=n.useContext(l);return n.useMemo((function(){return"function"==typeof i?i(e):{...e,...i}}),[e,i])}function d(i){let e;return e=i.disableParentContext?"function"==typeof i.components?i.components(s):i.components||s:I(i.components),n.createElement(l.Provider,{value:e},i.children)}}}]); \ No newline at end of file diff --git a/assets/js/070671b7.a81bd6a1.js b/assets/js/070671b7.a81bd6a1.js new file mode 100644 index 000000000..0a2599cee --- /dev/null +++ b/assets/js/070671b7.a81bd6a1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8607],{3620:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>a,toc:()=>d});var s=n(4848),r=n(8453);const i={},o="PreferAugmentedAssign",a={id:"detectors/PreferAugmentedAssign",title:"PreferAugmentedAssign",description:"Detects non-idiomatic statements that can be written using augmented assignment",source:"@site/docs/detectors/PreferAugmentedAssign.md",sourceDirName:"detectors",slug:"/detectors/PreferAugmentedAssign",permalink:"/tools/misti/docs/next/detectors/PreferAugmentedAssign",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/PreferAugmentedAssign.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"OptimalMathFunction",permalink:"/tools/misti/docs/next/detectors/OptimalMathFunction"},next:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/next/detectors/PreferredStdlibApi"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"preferaugmentedassign",children:"PreferAugmentedAssign"}),"\n",(0,s.jsxs)(t.p,{children:["Detects non-idiomatic statements that can be written using augmented assignment\noperators like ",(0,s.jsx)(t.code,{children:"+="}),", ",(0,s.jsx)(t.code,{children:"-="}),", etc."]}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Using augmented assignment operations improves the readability of the source code\nand reduces the risk of mistakes, such as those that occur during copy-pasting\nand refactoring code."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue = (msgValue - ctx.readForwardFee());\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue -= ctx.readForwardFee());\n"})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(6540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/07f2fad9.76f75bf4.js b/assets/js/07f2fad9.76f75bf4.js new file mode 100644 index 000000000..9ef5c2ea6 --- /dev/null +++ b/assets/js/07f2fad9.76f75bf4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3462],{8092:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var i=n(4848),s=n(8453);const o={id:"intro",title:"Introduction",slug:"/",sidebar_position:1},r=void 0,a={id:"intro",title:"Introduction",description:"Misti is a static analysis tool designed for smart contracts on the TON blockchain.",source:"@site/versioned_docs/version-0.3.0/index.md",sourceDirName:".",slug:"/",permalink:"/tools/misti/docs/0.3.0/",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/index.md",tags:[],version:"0.3.0",sidebarPosition:1,frontMatter:{id:"intro",title:"Introduction",slug:"/",sidebar_position:1},sidebar:"sidebar",next:{title:"Getting Started",permalink:"/tools/misti/docs/0.3.0/tutorial/getting-started"}},c={},d=[{value:"Use Cases",id:"use-cases",level:2},{value:"Name Origin",id:"name-origin",level:2},{value:"Funding",id:"funding",level:2}];function l(e){const t={a:"a",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Misti is a static analysis tool designed for smart contracts on the ",(0,i.jsx)(t.a,{href:"https://ton.org/",children:"TON blockchain"}),"."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Language Support:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://tact-lang.org/",children:"Tact"})," 1.5 is supported."]}),"\n",(0,i.jsxs)(t.li,{children:["Support for ",(0,i.jsx)(t.a,{href:"https://docs.ton.org/develop/func/overview",children:"FunC"})," ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/56",children:"is planned"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,i.jsx)(t.p,{children:"Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Detect Vulnerabilities:"})," Identify and fix potential security flaws early in the development cycle."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Improve Code Quality:"})," Maintain high standards by catching bugs and enforcing best practices automatically."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Streamline Development:"})," Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Custom Detectors:"})," Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow."}),"\n",(0,i.jsx)(t.h2,{id:"name-origin",children:"Name Origin"}),"\n",(0,i.jsx)(t.p,{children:'The name "Misti" comes from the Misti volcano in Peru. It was chosen because it\'s catchy and easy to remember.'}),"\n",(0,i.jsx)(t.h2,{id:"funding",children:"Funding"}),"\n",(0,i.jsxs)(t.p,{children:["Misti has been ",(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/436",children:"funded"})," by ",(0,i.jsx)(t.a,{href:"https://ton.foundation",children:"TON Foundation"}),". This support has enabled us to develop and maintain the tool."]})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/0ac52da9.865948a5.js b/assets/js/0ac52da9.865948a5.js new file mode 100644 index 000000000..3c9b6e000 --- /dev/null +++ b/assets/js/0ac52da9.865948a5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7702],{8288:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var t=n(4848),s=n(8453);const o={},r="Configuration",l={id:"tutorial/configuration",title:"Configuration",description:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.",source:"@site/versioned_docs/version-0.3.1/tutorial/configuration.md",sourceDirName:"tutorial",slug:"/tutorial/configuration",permalink:"/tools/misti/docs/0.3.1/tutorial/configuration",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/tutorial/configuration.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Command-Line Interface",permalink:"/tools/misti/docs/0.3.1/tutorial/cli"},next:{title:"Using with Blueprint",permalink:"/tools/misti/docs/0.3.1/tutorial/blueprint"}},a={},c=[{value:"Configuration Options",id:"configuration-options",level:3},{value:"Running Misti with Configuration",id:"running-misti-with-configuration",level:2},{value:"Default Configuration File",id:"default-configuration-file",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const i={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(i.h1,{id:"configuration",children:"Configuration"}),"\n",(0,t.jsx)(i.p,{children:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set."}),"\n",(0,t.jsx)(i.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"detectors"}),": List of detectors to run. Each detector can be specified with a ",(0,t.jsx)(i.code,{children:"className"})," and optionally a ",(0,t.jsx)(i.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"modulePath"})," (string, optional): The file path of the detector module."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"ignoredProjects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"soufflePath"})," (string, optional): Directory to save generated Souffl\xe9 files which is helpful for debugging purposes. If not set, a temporary directory will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"souffleVerbose"})," (boolean, optional): If set, generates more readable Souffl\xe9 files instead of making the result source code smaller."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"tactStdlibPath"})," (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"unusedPrefix"}),' (string, default: "_"): Identifiers starting with this prefix won\'t be reported as unused by built-in detectors.']}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"verbosity"})," (string, optional): Verbosity level of the logs. Possible values are ",(0,t.jsx)(i.code,{children:"quiet"}),", ",(0,t.jsx)(i.code,{children:"debug"}),", and ",(0,t.jsx)(i.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(i.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,t.jsx)(i.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsx)(i.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,t.jsx)(i.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,t.jsx)(i.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-json",children:'{\n "detectors": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n { "className": "BranchDuplicate" },\n { "className": "FieldDoubleInit" },\n { "className": "PreferAugmentedAssign" },\n { "className": "StringReceiversOverlap" },\n { "className": "ArgCopyMutation" }\n ],\n "ignoredProjects": [],\n "soufflePath": "/tmp/misti/souffle",\n "souffleVerbose": false,\n "unusedPrefix": "_",\n "verbosity": "default"\n}\n'})}),"\n",(0,t.jsxs)(i.p,{children:["All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,t.jsxs)(i.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,t.jsx)(i.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --dump-config test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsxs)(i.p,{children:["If there is no Misti config in the ",(0,t.jsx)(i.code,{children:"simple"})," directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors."]}),"\n",(0,t.jsx)(i.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,t.jsxs)(i.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,t.jsx)(i.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function u(e={}){const{wrapper:i}={...(0,s.R)(),...e.components};return i?(0,t.jsx)(i,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>r,x:()=>l});var t=n(6540);const s={},o=t.createContext(s);function r(e){const i=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/0b705376.0f6bdf25.js b/assets/js/0b705376.0f6bdf25.js new file mode 100644 index 000000000..8b3e891dd --- /dev/null +++ b/assets/js/0b705376.0f6bdf25.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2903],{9153:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>c});var n=s(4848),i=s(8453);const o={},r="AsmIsUsed",a={id:"detectors/AsmIsUsed",title:"AsmIsUsed",description:"An optional detector that highlights all the asm functions.",source:"@site/versioned_docs/version-0.3.1/detectors/AsmIsUsed.md",sourceDirName:"detectors",slug:"/detectors/AsmIsUsed",permalink:"/tools/misti/docs/0.3.1/detectors/AsmIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/AsmIsUsed.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"ArgCopyMutation",permalink:"/tools/misti/docs/0.3.1/detectors/ArgCopyMutation"},next:{title:"BranchDuplicate",permalink:"/tools/misti/docs/0.3.1/detectors/BranchDuplicate"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"asmisused",children:"AsmIsUsed"}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"asm"})," functions."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Using TVM Assembly is a potentially dangerous operation that requires additional\nattention from an auditor. This optional detector will highlight all its uses to\nassist in contract security audits."}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"// Highlighted: the asm function use should be audited\nasm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE }\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>r,x:()=>a});var n=s(6540);const i={},o=n.createContext(i);function r(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/0c390d31.29054261.js b/assets/js/0c390d31.29054261.js new file mode 100644 index 000000000..fca1d211b --- /dev/null +++ b/assets/js/0c390d31.29054261.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1200],{934:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>d});var s=i(4848),l=i(8453);const t={},o="Command-Line Interface",r={id:"tutorial/cli",title:"Command-Line Interface",description:"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.",source:"@site/versioned_docs/version-0.4.0/tutorial/cli.md",sourceDirName:"tutorial",slug:"/tutorial/cli",permalink:"/tools/misti/docs/tutorial/cli",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/tutorial/cli.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"CI/CD Integration",permalink:"/tools/misti/docs/tutorial/ci-cd"},next:{title:"Configuration",permalink:"/tools/misti/docs/tutorial/configuration"}},c={},d=[{value:"-t, --tools <className[:key=value...]>",id:"-t---tools-classnamekeyvalue",level:3},{value:"--output-path <PATH>",id:"--output-path-path",level:3},{value:"--list-tools",id:"--list-tools",level:3},{value:"-o, --output-format <json|plain>",id:"-o---output-format-jsonplain",level:3},{value:"-C, --no-colors",id:"-c---no-colors",level:3},{value:"--souffle-binary <PATH>",id:"--souffle-binary-path",level:3},{value:"--souffle-path <PATH>",id:"--souffle-path-path",level:3},{value:"--souffle-verbose",id:"--souffle-verbose",level:3},{value:"--tact-stdlib-path <PATH>",id:"--tact-stdlib-path-path",level:3},{value:"-v, --verbose",id:"-v---verbose",level:3},{value:"-q, --quiet",id:"-q---quiet",level:3},{value:"-m, --min-severity <info|low|medium|high|critical>",id:"-m---min-severity-infolowmediumhighcritical",level:3},{value:"-de, --enabled-detectors <name|path:name>",id:"-de---enabled-detectors-namepathname",level:3},{value:"-dd, --disabled-detectors <names>",id:"-dd---disabled-detectors-names",level:3},{value:"-A, --all-detectors",id:"-a---all-detectors",level:3},{value:"-c, --config <PATH>",id:"-c---config-path",level:3},{value:"--new-detector <PATH>",id:"--new-detector-path",level:3}];function a(e){const n={code:"code",h1:"h1",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"command-line-interface",children:"Command-Line Interface"}),"\n",(0,s.jsx)(n.p,{children:"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each."}),"\n",(0,s.jsx)(n.h3,{id:"-t---tools-classnamekeyvalue",children:(0,s.jsx)(n.code,{children:"-t, --tools "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Specifies a tool to enable with optional configuration. This option can be used multiple times."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Example"}),": ",(0,s.jsx)(n.code,{children:'-t "DumpCfg:format=dot"'})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"--output-path-path",children:(0,s.jsx)(n.code,{children:"--output-path "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Specifies the directory to save warnings or output generated by tools. If ",(0,s.jsx)(n.code,{children:""})," is ",(0,s.jsx)(n.code,{children:"-"}),", then the output is sent to stdout."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"-"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"--list-tools",children:(0,s.jsx)(n.code,{children:"--list-tools"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Lists available tools and their configuration options."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"-o---output-format-jsonplain",children:(0,s.jsx)(n.code,{children:"-o, --output-format "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Sets the output format for all tools and warnings (either JSON or plain text)."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"plain"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"-c---no-colors",children:(0,s.jsx)(n.code,{children:"-C, --no-colors"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Disables ANSI colors in the output."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"--souffle-binary-path",children:(0,s.jsx)(n.code,{children:"--souffle-binary "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Specifies the path to the Souffl\xe9 binary."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:'"souffle"'})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"--souffle-path-path",children:(0,s.jsx)(n.code,{children:"--souffle-path "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Specifies the directory to save generated Souffl\xe9 files."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:'"/tmp/misti/souffle"'})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"--souffle-verbose",children:(0,s.jsx)(n.code,{children:"--souffle-verbose"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Generates human-readable, more verbose Souffl\xe9 files."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"--tact-stdlib-path-path",children:(0,s.jsx)(n.code,{children:"--tact-stdlib-path "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Specifies the path to the Tact standard library."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"-v---verbose",children:(0,s.jsx)(n.code,{children:"-v, --verbose"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Enables verbose output."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"-q---quiet",children:(0,s.jsx)(n.code,{children:"-q, --quiet"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Suppresses all output."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"-m---min-severity-infolowmediumhighcritical",children:(0,s.jsx)(n.code,{children:"-m, --min-severity "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Sets the minimum level of severity to report."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"info"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"-de---enabled-detectors-namepathname",children:(0,s.jsx)(n.code,{children:"-de, --enabled-detectors "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": A comma-separated list of detectors to enable."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Argument Validation"}),": Requires a non-empty list of detector names."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"-dd---disabled-detectors-names",children:(0,s.jsx)(n.code,{children:"-dd, --disabled-detectors "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": A comma-separated list of detector names to disable."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Argument Validation"}),": Requires a non-empty list of detector names."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"-a---all-detectors",children:(0,s.jsx)(n.code,{children:"-A, --all-detectors"})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Enables all available built-in detectors."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"-c---config-path",children:(0,s.jsx)(n.code,{children:"-c, --config "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Specifies the path to the Misti configuration file."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"--new-detector-path",children:(0,s.jsx)(n.code,{children:"--new-detector "})}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Description"}),": Creates a new custom detector at the specified path."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"undefined"})]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>o,x:()=>r});var s=i(6540);const l={},t=s.createContext(l);function o(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(l):e.components||l:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/0c3de8e2.454cb0da.js b/assets/js/0c3de8e2.454cb0da.js new file mode 100644 index 000000000..9ced26e68 --- /dev/null +++ b/assets/js/0c3de8e2.454cb0da.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4875],{9689:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var i=n(4848),a=n(8453);const r={},s="InheritedStateMutation",o={id:"detectors/InheritedStateMutation",title:"InheritedStateMutation",description:"An optional detector that highlights all instances where inherited trait variables",source:"@site/docs/detectors/InheritedStateMutation.md",sourceDirName:"detectors",slug:"/detectors/InheritedStateMutation",permalink:"/tools/misti/docs/next/detectors/InheritedStateMutation",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/InheritedStateMutation.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"FieldDoubleInit",permalink:"/tools/misti/docs/next/detectors/FieldDoubleInit"},next:{title:"NeverAccessedVariables",permalink:"/tools/misti/docs/next/detectors/NeverAccessedVariables"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"inheritedstatemutation",children:"InheritedStateMutation"}),"\n",(0,i.jsx)(t.p,{children:"An optional detector that highlights all instances where inherited trait variables\nare directly modified."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsxs)(t.p,{children:["Traits should provide setter methods to ensure that invariants related to their\nstate are preserved. Directly modifying trait variables (e.g., ",(0,i.jsx)(t.code,{children:"self.traitVar = 42"}),")\ncan violate these invariants, leading to potential bugs or security vulnerabilities.\nThis detector warns when such direct modifications occur, prompting further review\nby auditors."]}),"\n",(0,i.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"trait T {\n balance: Int;\n}\n\ncontract C with T {\n balance: Int = 42;\n fun updateBalance() {\n self.balance = 100; // Suspicious: Highlighted by the detector\n }\n}\n"})}),"\n",(0,i.jsx)(t.p,{children:"Use instead:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:'trait T {\n balance: Int;\n fun setBalance(newBalance: Int) {\n require(newBalance > 0, "balance cannot be negative"); // Invariant check\n self.balance = newBalance;\n }\n}\n\ncontract C with T {\n balance: Int = 42;\n fun updateBalance() {\n self.setBalance(100); // OK: Invariant preserved\n }\n}\n'})})]})}function h(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(6540);const a={},r=i.createContext(a);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/0c8d0168.c0afaf27.js b/assets/js/0c8d0168.c0afaf27.js new file mode 100644 index 000000000..3f162b5d7 --- /dev/null +++ b/assets/js/0c8d0168.c0afaf27.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[607],{5843:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>a,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var i=n(4848),s=n(8453);const r={},o="Using Misti with Blueprint",l={id:"tutorial/blueprint",title:"Using Misti with Blueprint",description:"Blueprint is a platform to compile, test, and deploy contracts on the TON blockchain. It is quite similar to Hardhat and Truffle for Ethereum.",source:"@site/docs/tutorial/blueprint.md",sourceDirName:"tutorial",slug:"/tutorial/blueprint",permalink:"/tools/misti/docs/next/tutorial/blueprint",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tutorial/blueprint.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/tools/misti/docs/next/tutorial/configuration"},next:{title:"Overview",permalink:"/tools/misti/docs/next/detectors"}},a={},c=[{value:"Getting Started",id:"getting-started",level:2},{value:"Usage",id:"usage",level:2}];function d(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",...(0,s.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"using-misti-with-blueprint",children:"Using Misti with Blueprint"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:"https://github.com/ton-org/blueprint/",children:"Blueprint"})," is a platform to compile, test, and deploy contracts on the TON blockchain. It is quite similar to Hardhat and Truffle for Ethereum."]}),"\n",(0,i.jsxs)(e.p,{children:["There is a ",(0,i.jsx)(e.a,{href:"https://github.com/nowarp/blueprint-misti",children:"blueprint-misti"})," plugin that can be added to a Blueprint configuration. It adds the ",(0,i.jsx)(e.code,{children:"blueprint misti"})," command, which runs the static analyzer over the selected Blueprint project."]}),"\n",(0,i.jsx)(e.p,{children:"This page describes how to use it."}),"\n",(0,i.jsx)(e.h2,{id:"getting-started",children:"Getting Started"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsxs)(e.li,{children:["\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:"https://souffle-lang.github.io/install",children:"Install Souffl\xe9"})," to use all detectors provided by Misti."]}),"\n"]}),"\n",(0,i.jsxs)(e.li,{children:["\n",(0,i.jsx)(e.p,{children:"Add this plugin as a dependency of your Blueprint project:"}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn add @nowarp/blueprint-misti\n"})}),"\n",(0,i.jsxs)(e.ol,{start:"3",children:["\n",(0,i.jsxs)(e.li,{children:["Add this configuration to ",(0,i.jsx)(e.code,{children:"blueprint.config.ts"}),":"]}),"\n"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",children:"import { MistiPlugin } from '@nowarp/blueprint-misti';\nexport const config = {\n plugins: [\n new MistiPlugin(),\n ],\n};\n"})}),"\n",(0,i.jsx)(e.h2,{id:"usage",children:"Usage"}),"\n",(0,i.jsx)(e.p,{children:"Run the following command:"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn blueprint misti\n"})}),"\n",(0,i.jsx)(e.p,{children:"It will run the analysis of the available project, if there is one, or show an interactive window to select a project:"}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.img,{alt:"img",src:n(1547).A+"",width:"493",height:"96"})}),"\n",(0,i.jsxs)(e.p,{children:["You could also pass the ",(0,i.jsx)(e.a,{href:"/tools/misti/docs/next/tutorial/cli",children:"supported CLI options"})," for Misti, for example:"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn blueprint misti --all-detectors\n"})}),"\n",(0,i.jsx)(e.p,{children:"Or you can even pass the path to the contract directly:"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn blueprint misti path/to/my/contract.tact\n"})}),"\n",(0,i.jsxs)(e.p,{children:["If you have any problems, feel free to reach out to us in the ",(0,i.jsx)(e.a,{href:"https://t.me/misti_dev",children:"Misti discussion group"}),"."]})]})}function h(t={}){const{wrapper:e}={...(0,s.R)(),...t.components};return e?(0,i.jsx)(e,{...t,children:(0,i.jsx)(d,{...t})}):d(t)}},1547:(t,e,n)=>{n.d(e,{A:()=>i});const i=n.p+"assets/images/blueprint-select-project-b8656fa4266c0c7923d6b67c7f5950e6.png"},8453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>l});var i=n(6540);const s={},r=i.createContext(s);function o(t){const e=i.useContext(r);return i.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function l(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(s):t.components||s:o(t.components),i.createElement(r.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/0e4e7ef7.da1fd809.js b/assets/js/0e4e7ef7.da1fd809.js new file mode 100644 index 000000000..1faf33616 --- /dev/null +++ b/assets/js/0e4e7ef7.da1fd809.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1070],{2210:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var t=i(4848),s=i(8453);const o={},r="Configuration",l={id:"tutorial/configuration",title:"Configuration",description:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.",source:"@site/versioned_docs/version-0.4.0/tutorial/configuration.md",sourceDirName:"tutorial",slug:"/tutorial/configuration",permalink:"/tools/misti/docs/tutorial/configuration",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/tutorial/configuration.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Command-Line Interface",permalink:"/tools/misti/docs/tutorial/cli"},next:{title:"Using with Blueprint",permalink:"/tools/misti/docs/tutorial/blueprint"}},a={},c=[{value:"Configuration Options",id:"configuration-options",level:3},{value:"Running Misti with Configuration",id:"running-misti-with-configuration",level:2},{value:"Default Configuration File",id:"default-configuration-file",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"configuration",children:"Configuration"}),"\n",(0,t.jsx)(n.p,{children:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set."}),"\n",(0,t.jsx)(n.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"detectors"})," (array of objects, optional): List of detectors to run. Each detector can be specified with a ",(0,t.jsx)(n.code,{children:"className"})," and optionally a ",(0,t.jsx)(n.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"modulePath"})," (string, optional): The file path of the detector module if it's a custom implementation."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"tools"})," (array of objects, optional): List of tools to enable, each with its own configuration."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"className"})," (string, required): The class name of the tool."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"options"})," (object, optional): Key-value configuration options for the tool."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"suppressions"})," (array of objects, optional): A list of suppressions for warnings."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"detector"})," (string, required): The detector to suppress warnings for."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"position"})," (string, required): The position in the code where the warning should be suppressed."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"ignoredProjects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"soufflePath"})," (string, optional): Directory to save generated Souffl\xe9 files, useful for debugging purposes. If not set, a temporary directory will be used."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"souffleVerbose"})," (boolean, optional): If set, generates more readable Souffl\xe9 files instead of optimizing the output for size."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"tactStdlibPath"})," (string, optional): Path to the Tact standard library. If not set, the default standard library from the active Tact setup will be used."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"unusedPrefix"}),' (string, default: "_"): Identifiers starting with this prefix won\'t be reported as unused by the built-in detectors.']}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"verbosity"}),' (string, optional, default: "default"): Verbosity level of the logs. Possible values are ',(0,t.jsx)(n.code,{children:"quiet"}),", ",(0,t.jsx)(n.code,{children:"debug"}),", and ",(0,t.jsx)(n.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,t.jsx)(n.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,t.jsx)(n.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,t.jsx)(n.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "detectors": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n { "className": "BranchDuplicate" },\n { "className": "FieldDoubleInit" },\n { "className": "PreferAugmentedAssign" },\n { "className": "StringReceiversOverlap" },\n { "className": "ArgCopyMutation" }\n ],\n "ignoredProjects": [],\n "soufflePath": "/tmp/misti/souffle",\n "souffleVerbose": false,\n "unusedPrefix": "_",\n "verbosity": "default"\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,t.jsx)(n.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --dump-config path/to/your/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"If there is no Misti config in the directory, Misti dumps the default config. This can be used to adjust it, such as adding or suppressing some detectors."}),"\n",(0,t.jsx)(n.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,t.jsxs)(n.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,t.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>l});var t=i(6540);const s={},o=t.createContext(s);function r(e){const n=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/0f37fc5e.4a23afc4.js b/assets/js/0f37fc5e.4a23afc4.js new file mode 100644 index 000000000..be67018b1 --- /dev/null +++ b/assets/js/0f37fc5e.4a23afc4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9692],{7141:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>p,frontMatter:()=>i,metadata:()=>o,toc:()=>d});var n=r(4848),s=r(8453);const i={},c="StringReceiversOverlap",o={id:"detectors/StringReceiversOverlap",title:"StringReceiversOverlap",description:"A detector that finds overlapping messages between general string receivers and string receivers.",source:"@site/docs/detectors/StringReceiversOverlap.md",sourceDirName:"detectors",slug:"/detectors/StringReceiversOverlap",permalink:"/tools/misti/docs/next/detectors/StringReceiversOverlap",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/StringReceiversOverlap.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/next/detectors/ReadOnlyVariables"},next:{title:"UnboundLoops",permalink:"/tools/misti/docs/next/detectors/UnboundLoops"}},a={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"stringreceiversoverlap",children:"StringReceiversOverlap"}),"\n",(0,n.jsx)(t.p,{children:"A detector that finds overlapping messages between general string receivers and string receivers."}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Constant string receivers and general string receivers can have overlapping messages\nin which case the constant string receiver always takes precedence."}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:'contract Test {\n receive("foobar") { throw(1042) }\n receive(msg: String) {\n if (msg == "foobar") { throw(1043) } // Bad: Dead code\n }\n}\n'})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:'contract Test {\n receive("foobar") { throw(1042) }\n receive(msg: String) {}\n}\n'})})]})}function p(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,r)=>{r.d(t,{R:()=>c,x:()=>o});var n=r(6540);const s={},i=n.createContext(s);function c(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:c(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/0fb6ae9c.e2818ac1.js b/assets/js/0fb6ae9c.e2818ac1.js new file mode 100644 index 000000000..eb6b5bfc7 --- /dev/null +++ b/assets/js/0fb6ae9c.e2818ac1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5983],{5091:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>f});var t=i(4848),r=i(8453);const s={},a="Souffl\xe9 Integration Guide",o={id:"hacking/souffle",title:"Souffl\xe9 Integration Guide",description:"What is Souffl\xe9?",source:"@site/docs/hacking/souffle.md",sourceDirName:"hacking",slug:"/hacking/souffle",permalink:"/tools/misti/docs/next/hacking/souffle",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/hacking/souffle.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Design Overview",permalink:"/tools/misti/docs/next/hacking/design"},next:{title:"Contributing",permalink:"/tools/misti/docs/next/hacking/contributing"}},l={},f=[{value:"What is Souffl\xe9?",id:"what-is-souffl\xe9",level:2},{value:"Benefits of Using Souffl\xe9 for Static Analysis",id:"benefits-of-using-souffl\xe9-for-static-analysis",level:2},{value:"Souffl\xe9 Integration in Misti",id:"souffl\xe9-integration-in-misti",level:2},{value:"Creating Souffl\xe9 Programs",id:"creating-souffl\xe9-programs",level:3},{value:"Generating Facts and Executing Souffl\xe9",id:"generating-facts-and-executing-souffl\xe9",level:3},{value:"Learning from Existing Code",id:"learning-from-existing-code",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"souffl\xe9-integration-guide",children:"Souffl\xe9 Integration Guide"}),"\n",(0,t.jsx)(n.h2,{id:"what-is-souffl\xe9",children:"What is Souffl\xe9?"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io",children:"Souffl\xe9"})," is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Souffl\xe9, Misti can perform deep and scalable analyses of smart contracts."]}),"\n",(0,t.jsx)(n.h2,{id:"benefits-of-using-souffl\xe9-for-static-analysis",children:"Benefits of Using Souffl\xe9 for Static Analysis"}),"\n",(0,t.jsx)(n.p,{children:"Souffl\xe9 allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Souffl\xe9 program might be more straightforward then implementing a complex transfer function in for a classic monotone framework."}),"\n",(0,t.jsx)(n.h2,{id:"souffl\xe9-integration-in-misti",children:"Souffl\xe9 Integration in Misti"}),"\n",(0,t.jsxs)(n.p,{children:["The API for interacting with Souffl\xe9 in Misti is implemented in the ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/souffle.js",children:"Souffle.js library"}),". See the ",(0,t.jsx)(n.a,{href:"https://nowarp.io/lib/souffle-js/api/",children:"Souffle.js API reference"})," for more detailed information."]}),"\n",(0,t.jsx)(n.h3,{id:"creating-souffl\xe9-programs",children:"Creating Souffl\xe9 Programs"}),"\n",(0,t.jsx)(n.p,{children:'To create a Souffl\xe9 program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:'}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addDecls(ctx: Context) {\n ctx.add(\n Relation.from(\n "varDecl",\n [\n ["var", FactType.Symbol],\n ["func", FactType.Symbol],\n ],\n undefined,\n ),\n );\n // other declarations\n}\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addRules(ctx: Context) {\n // readOnly(var, func) :-\n // varDecl(var, func),\n // !varAssign(var, func),\n // !varUse(var, func).\n ctx.add(\n Rule.from(\n [makeAtom("readOnly", ["var", "func"])],\n makeRuleBody(makeAtom("varDecl", ["var", "func"])),\n makeRuleBody(makeAtom("varAssign", ["var", "func"]), {\n negated: true,\n }),\n makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),\n ),\n );\n }\n'})}),"\n",(0,t.jsx)(n.h3,{id:"generating-facts-and-executing-souffl\xe9",children:"Generating Facts and Executing Souffl\xe9"}),"\n",(0,t.jsx)(n.p,{children:"After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Souffl\xe9 executor to run the analysis:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"const executor = ctx.config.soufflePath\n ? new Executor({\n inputDir: ctx.config.soufflePath,\n outputDir: ctx.config.soufflePath,\n })\n : new Executor();\n\nconst result = executor.executeSync(program);\n\nif (!result.success) {\n throw new Error(\n `Error executing Souffl\xe9 for ${this.id}:\\n${result.stderr}`,\n );\n}\n\nconst warnings = Array.from(result.results.entries.values()).map((fact) => {\n // raise warnings\n});\n"})}),"\n",(0,t.jsx)(n.h3,{id:"learning-from-existing-code",children:"Learning from Existing Code"}),"\n",(0,t.jsx)(n.p,{children:"We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Souffl\xe9 with Misti. This will help you understand the intricacies of generating IR and executing Souffl\xe9 programs effectively."}),"\n",(0,t.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,t.jsxs)(n.p,{children:["For a deeper understanding of static analysis using Souffl\xe9, refer to the textbook ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.a,{href:"https://arxiv.org/pdf/2012.10086",children:"Program Analysis: An Appetizer"})})," by Flemming Nielson and Hanne Riis Nielson. It discusses Souffl\xe9-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field."]})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>a,x:()=>o});var t=i(6540);const r={},s=t.createContext(r);function a(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/104c66c9.61be676d.js b/assets/js/104c66c9.61be676d.js new file mode 100644 index 000000000..b63cc35d7 --- /dev/null +++ b/assets/js/104c66c9.61be676d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6695],{1806:(e,s,t)=>{t.r(s),t.d(s,{assets:()=>a,contentTitle:()=>d,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>c});var n=t(4848),o=t(8453);const r={},d="Zero Address",i={id:"detectors/ZeroAddress",title:"Zero Address",description:"A detector that identifies uses of the zero address.",source:"@site/versioned_docs/version-0.2.1/detectors/ZeroAddress.md",sourceDirName:"detectors",slug:"/detectors/ZeroAddress",permalink:"/tools/misti/docs/0.2.1/detectors/ZeroAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/ZeroAddress.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Unbound Loops",permalink:"/tools/misti/docs/0.2.1/detectors/UnboundLoops"},next:{title:"Constant Address",permalink:"/tools/misti/docs/0.2.1/detectors/ConstantAddress"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const s={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{id:"zero-address",children:"Zero Address"}),"\n",(0,n.jsx)(s.p,{children:"A detector that identifies uses of the zero address."}),"\n",(0,n.jsx)(s.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(s.p,{children:"Using the zero address in smart contracts is typically problematic because it can be\nexploited as a default or uninitialized address, leading to unintended transfers and\nsecurity vulnerabilities. Additionally, operations involving the zero address can\nresult in loss of funds or tokens, as there is no private key to access this address."}),"\n",(0,n.jsx)(s.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init() {\n // Warning: Insecure usage of zero address as default value\n self.to = newAddress(0, 0);\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})}),"\n",(0,n.jsx)(s.p,{children:"Use instead:"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init(to: Address) {\n // Fixed: Using the input value on initializaiton.\n self.to = to;\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})})]})}function u(e={}){const{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,s,t)=>{t.d(s,{R:()=>d,x:()=>i});var n=t(6540);const o={},r=n.createContext(o);function d(e){const s=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function i(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),n.createElement(r.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/122f6b32.f6ee1737.js b/assets/js/122f6b32.f6ee1737.js new file mode 100644 index 000000000..484986163 --- /dev/null +++ b/assets/js/122f6b32.f6ee1737.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[25],{9648:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var n=i(4848),o=i(8453);const r={},s="DivideBeforeMultiply",l={id:"detectors/DivideBeforeMultiply",title:"DivideBeforeMultiply",description:"A detector that identifies and corrects instances of division before multiplication to",source:"@site/versioned_docs/version-0.3.0/detectors/DivideBeforeMultiply.md",sourceDirName:"detectors",slug:"/detectors/DivideBeforeMultiply",permalink:"/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/DivideBeforeMultiply.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"ConstantAddress",permalink:"/tools/misti/docs/0.3.0/detectors/ConstantAddress"},next:{title:"DumpIsUsed",permalink:"/tools/misti/docs/0.3.0/detectors/DumpIsUsed"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function a(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"dividebeforemultiply",children:"DivideBeforeMultiply"}),"\n",(0,n.jsx)(t.p,{children:"A detector that identifies and corrects instances of division before multiplication to\nensure accurate mathematical operations."}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers."}),"\n",(0,n.jsx)(t.li,{children:"Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations."}),"\n",(0,n.jsx)(t.li,{children:"Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Bad: Division before multiplication\nlet result: Int = a / b * c;\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Correct: Multiplication before division\nlet result: Int = a * c / b;\n"})})]})}function u(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(a,{...e})}):a(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>l});var n=i(6540);const o={},r=n.createContext(o);function s(e){const t=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),n.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1295da86.6c981ca5.js b/assets/js/1295da86.6c981ca5.js new file mode 100644 index 000000000..f6d0213ec --- /dev/null +++ b/assets/js/1295da86.6c981ca5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[559],{7413:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>o,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>a});var i=n(4848),r=n(8453);const s={},o="Using Misti with Blueprint",c={id:"tutorial/blueprint",title:"Using Misti with Blueprint",description:"Blueprint is a development environment for writing, testing, and deploying TON smart contracts.",source:"@site/versioned_docs/version-0.3.1/tutorial/blueprint.md",sourceDirName:"tutorial",slug:"/tutorial/blueprint",permalink:"/tools/misti/docs/0.3.1/tutorial/blueprint",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/tutorial/blueprint.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/tools/misti/docs/0.3.1/tutorial/configuration"},next:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.3.1/detectors"}},l={},a=[{value:"Getting started",id:"getting-started",level:2},{value:"Resources",id:"resources",level:2}];function u(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"using-misti-with-blueprint",children:"Using Misti with Blueprint"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:"https://github.com/ton-org/blueprint",children:"Blueprint"})," is a development environment for writing, testing, and deploying TON smart contracts."]}),"\n",(0,i.jsxs)(e.p,{children:["Misti can be used in Blueprint projects by leveraging the ",(0,i.jsx)(e.a,{href:"https://github.com/nowarp/blueprint-misti",children:(0,i.jsx)(e.code,{children:"blueprint-misti"})})," plugin."]}),"\n",(0,i.jsx)(e.h2,{id:"getting-started",children:"Getting started"}),"\n",(0,i.jsxs)(e.p,{children:["Add the plugin and the recent version of Tact to the ",(0,i.jsx)(e.code,{children:"package.json"})," of your Blueprint project by running:"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn add @tact-lang/compiler\nyarn add @nowarp/blueprint-misti\n"})}),"\n",(0,i.jsxs)(e.p,{children:["Then, add this configuration to ",(0,i.jsx)(e.code,{children:"blueprint.config.ts"}),":"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",children:"import { MistiPlugin } from '@nowarp/blueprint-misti';\nexport const config = {\n plugins: [\n new MistiPlugin(),\n ],\n};\n"})}),"\n",(0,i.jsx)(e.p,{children:"Now, try to run Misti:"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn blueprint misti ./path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(e.h2,{id:"resources",children:"Resources"}),"\n",(0,i.jsxs)(e.p,{children:["For more information, please refer to the README of the ",(0,i.jsx)(e.a,{href:"https://github.com/nowarp/blueprint-misti",children:(0,i.jsx)(e.code,{children:"blueprint-misti"})})," project. If you have any problems, feel free to reach out to us in the ",(0,i.jsx)(e.a,{href:"https://t.me/misti_dev",children:"Misti discussion group"}),"."]})]})}function d(t={}){const{wrapper:e}={...(0,r.R)(),...t.components};return e?(0,i.jsx)(e,{...t,children:(0,i.jsx)(u,{...t})}):u(t)}},8453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>c});var i=n(6540);const r={},s=i.createContext(r);function o(t){const e=i.useContext(s);return i.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function c(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),i.createElement(s.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/138db073.578334fd.js b/assets/js/138db073.578334fd.js new file mode 100644 index 000000000..e3163c7d5 --- /dev/null +++ b/assets/js/138db073.578334fd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1519],{3331:(t,e,s)=>{s.r(e),s.d(e,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var n=s(4848),i=s(8453);const o={},r="AsmIsUsed",a={id:"detectors/AsmIsUsed",title:"AsmIsUsed",description:"An optional detector that highlights all the asm functions.",source:"@site/docs/detectors/AsmIsUsed.md",sourceDirName:"detectors",slug:"/detectors/AsmIsUsed",permalink:"/tools/misti/docs/next/detectors/AsmIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/AsmIsUsed.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"ArgCopyMutation",permalink:"/tools/misti/docs/next/detectors/ArgCopyMutation"},next:{title:"BranchDuplicate",permalink:"/tools/misti/docs/next/detectors/BranchDuplicate"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(t){const e={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...t.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"asmisused",children:"AsmIsUsed"}),"\n",(0,n.jsxs)(e.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(e.code,{children:"asm"})," functions."]}),"\n",(0,n.jsx)(e.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(e.p,{children:"Using TVM Assembly is a potentially dangerous operation that requires additional\nattention from an auditor. This optional detector will highlight all its uses to\nassist in contract security audits."}),"\n",(0,n.jsx)(e.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-tact",children:"// Highlighted: the asm function use should be audited\nasm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE }\n"})})]})}function h(t={}){const{wrapper:e}={...(0,i.R)(),...t.components};return e?(0,n.jsx)(e,{...t,children:(0,n.jsx)(l,{...t})}):l(t)}},8453:(t,e,s)=>{s.d(e,{R:()=>r,x:()=>a});var n=s(6540);const i={},o=n.createContext(i);function r(t){const e=n.useContext(o);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function a(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(i):t.components||i:r(t.components),n.createElement(o.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/1418388c.6eb86b98.js b/assets/js/1418388c.6eb86b98.js new file mode 100644 index 000000000..20512be26 --- /dev/null +++ b/assets/js/1418388c.6eb86b98.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8917],{0:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>d});var o=n(4848),r=n(8453);const i={},s="Custom Detector Guide",c={id:"hacking/custom-detector",title:"Custom Detector Guide",description:"Introduction",source:"@site/versioned_docs/version-0.2.1/hacking/custom-detector.md",sourceDirName:"hacking",slug:"/hacking/custom-detector",permalink:"/tools/misti/docs/0.2.1/hacking/custom-detector",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/hacking/custom-detector.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Tools",permalink:"/tools/misti/docs/0.2.1/hacking/tools"}},a={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Writing a Detector",id:"writing-a-detector",level:2},{value:"Example Detectors",id:"example-detectors",level:2}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h1,{id:"custom-detector-guide",children:"Custom Detector Guide"}),"\n",(0,o.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,o.jsxs)(t.p,{children:["Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: ",(0,o.jsx)(t.a,{href:"https://nowarp.github.io/tools/misti/api/",children:"Misti API Reference"}),"."]}),"\n",(0,o.jsxs)(t.p,{children:["Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the ",(0,o.jsx)(t.a,{href:"https://nowarp.github.io/tools/misti/api/classes/detectors_detector.Detector.html",children:(0,o.jsx)(t.code,{children:"Detector"})})," interface."]}),"\n",(0,o.jsx)(t.h2,{id:"writing-a-detector",children:"Writing a Detector"}),"\n",(0,o.jsx)(t.p,{children:"To write a custom detector, create a TypeScript file using the Misti API. Here's an example of how to implement a custom detector:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-typescript",children:'import { Detector } from "../../src/detectors/detector";\nimport { MistiContext } from "../../src/internals/context";\nimport { CompilationUnit } from "../../src/internals/ir";\nimport {\n createError,\n MistiTactError,\n Severity,\n} from "../../src/internals/errors";\n\n/**\n * An example of a custom detector that showcases the usage of the detector API.\n *\n * It reports all the contracts that don\'t have an explicit implementation of the init function.\n */\nexport class ImplicitInit extends Detector {\n check(ctx: MistiContext, cu: CompilationUnit): MistiTactError[] {\n return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {\n if (!cu.findMethodCFGByName(contract.name, "init")) {\n const err = createError(\n ctx,\n `contract ${contract.name} doesn\'t define an init function`,\n Severity.INFO,\n contract.ref,\n );\n foundErrors.push(err);\n }\n return foundErrors;\n }, [] as MistiTactError[]);\n }\n}\n'})}),"\n",(0,o.jsx)(t.p,{children:"After creating a detector, you need to specify it in your configuration. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{children:'{\n "detectors": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n\n { "className": "ImplicitInit", "modulePath": "/path/to/implicitInit.ts" }\n ],\n "ignored_projects": [],\n "verbosity": "default"\n}\n\n'})}),"\n",(0,o.jsxs)(t.p,{children:["After this, you could run the created detector specifying a path to it: ",(0,o.jsx)(t.code,{children:"--config path/to/mistiConfig.json test/projects/simple/tactConfig.json"}),"."]}),"\n",(0,o.jsx)(t.h2,{id:"example-detectors",children:"Example Detectors"}),"\n",(0,o.jsxs)(t.p,{children:["The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the ",(0,o.jsx)(t.a,{href:"https://github.com/nowarp/misti/tree/master/examples",children:"examples directory"})," in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors."]})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>c});var o=n(6540);const r={},i=o.createContext(r);function s(e){const t=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),o.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/150b97d9.3c57e7f9.js b/assets/js/150b97d9.3c57e7f9.js new file mode 100644 index 000000000..e4aa817e7 --- /dev/null +++ b/assets/js/150b97d9.3c57e7f9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1258],{7254:(e,s,t)=>{t.r(s),t.d(s,{assets:()=>d,contentTitle:()=>l,default:()=>h,frontMatter:()=>n,metadata:()=>r,toc:()=>a});var o=t(4848),i=t(8453);const n={id:"tools",title:"Tools Overview",sidebar_label:"Tools Overview"},l="Tools Overview",r={id:"tools",title:"Tools Overview",description:"Misti Tools are additional modules designed to work alongside detectors, enabling various tasks beyond code analysis.",source:"@site/versioned_docs/version-0.4.0/tools.md",sourceDirName:".",slug:"/tools",permalink:"/tools/misti/docs/tools",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/tools.md",tags:[],version:"0.4.0",frontMatter:{id:"tools",title:"Tools Overview",sidebar_label:"Tools Overview"},sidebar:"sidebar",previous:{title:"ZeroAddress",permalink:"/tools/misti/docs/detectors/ZeroAddress"},next:{title:"DumpAst",permalink:"/tools/misti/docs/tools/DumpAst"}},d={},a=[{value:"Usage",id:"usage",level:2},{value:"Usage Examples",id:"usage-examples",level:2},{value:"Available Tools",id:"available-tools",level:2}];function c(e){const s={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(s.h1,{id:"tools-overview",children:"Tools Overview"}),"\n",(0,o.jsx)(s.p,{children:"Misti Tools are additional modules designed to work alongside detectors, enabling various tasks beyond code analysis."}),"\n",(0,o.jsx)(s.p,{children:"These tools are particularly useful for auditors, providing additional functionalities to assist in manual code reviews."}),"\n",(0,o.jsx)(s.h2,{id:"usage",children:"Usage"}),"\n",(0,o.jsx)(s.p,{children:"List available tools and their options:"}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{className:"language-bash",children:"npx misti --list-tools\n"})}),"\n",(0,o.jsx)(s.p,{children:"To invoke a specific tool, use the following command format:"}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{className:"language-bash",children:'npx misti -t "ToolName:option=value,option=value" /path/to/tact.config.json\n'})}),"\n",(0,o.jsx)(s.h2,{id:"usage-examples",children:"Usage Examples"}),"\n",(0,o.jsx)(s.p,{children:"Dump the AST of the project:"}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{children:'npx misti -t "DumpAst" my-example.tact\n'})}),"\n",(0,o.jsxs)(s.p,{children:["Dump the CFGs of the project in ",(0,o.jsx)(s.a,{href:"https://mermaid.live",children:"Mermaid"})," format to the file ",(0,o.jsx)(s.code,{children:"/tmp/my-example.DumpCfg.out"}),":"]}),"\n",(0,o.jsx)(s.pre,{children:(0,o.jsx)(s.code,{children:'npx misti --output-path "/tmp" -t "DumpCfg:format=mermaid" my-example.tact\n'})}),"\n",(0,o.jsx)(s.h2,{id:"available-tools",children:"Available Tools"}),"\n",(0,o.jsx)(s.p,{children:"Below is the complete list of built-in tools. Click on any of them to learn more."}),"\n",(0,o.jsxs)(s.table,{children:[(0,o.jsx)(s.thead,{children:(0,o.jsxs)(s.tr,{children:[(0,o.jsx)(s.th,{children:"#"}),(0,o.jsx)(s.th,{children:"Tool"}),(0,o.jsx)(s.th,{children:"Description"})]})}),(0,o.jsxs)(s.tbody,{children:[(0,o.jsxs)(s.tr,{children:[(0,o.jsx)(s.td,{children:"1"}),(0,o.jsx)(s.td,{children:(0,o.jsx)(s.a,{href:"/tools/misti/docs/tools/DumpAst",children:"DumpAst"})}),(0,o.jsx)(s.td,{children:"Dumps the AST of project modules"})]}),(0,o.jsxs)(s.tr,{children:[(0,o.jsx)(s.td,{children:"2"}),(0,o.jsx)(s.td,{children:(0,o.jsx)(s.a,{href:"/tools/misti/docs/tools/DumpCfg",children:"DumpCfg"})}),(0,o.jsx)(s.td,{children:"Dumps the CFG of project modules"})]}),(0,o.jsxs)(s.tr,{children:[(0,o.jsx)(s.td,{children:"3"}),(0,o.jsx)(s.td,{children:(0,o.jsx)(s.a,{href:"/tools/misti/docs/tools/DumpConfig",children:"DumpConfig"})}),(0,o.jsx)(s.td,{children:"Dumps the Misti configuration file in use"})]})]})]})]})}function h(e={}){const{wrapper:s}={...(0,i.R)(),...e.components};return s?(0,o.jsx)(s,{...e,children:(0,o.jsx)(c,{...e})}):c(e)}},8453:(e,s,t)=>{t.d(s,{R:()=>l,x:()=>r});var o=t(6540);const i={},n=o.createContext(i);function l(e){const s=o.useContext(n);return o.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function r(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),o.createElement(n.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1598dd73.06ff38aa.js b/assets/js/1598dd73.06ff38aa.js new file mode 100644 index 000000000..1928e6fb1 --- /dev/null +++ b/assets/js/1598dd73.06ff38aa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8708],{4661:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>s,metadata:()=>l,toc:()=>c});var t=n(4848),o=n(8453);const s={},r="Configuration",l={id:"tutorial/configuration",title:"Configuration",description:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.",source:"@site/versioned_docs/version-0.1.2/tutorial/configuration.md",sourceDirName:"tutorial",slug:"/tutorial/configuration",permalink:"/tools/misti/docs/0.1.2/tutorial/configuration",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/tutorial/configuration.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Getting Started",permalink:"/tools/misti/docs/0.1.2/tutorial/getting-started"},next:{title:"Divide before Multiply",permalink:"/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply"}},a={},c=[{value:"Configuration Options",id:"configuration-options",level:3},{value:"Running Misti with Configuration",id:"running-misti-with-configuration",level:2},{value:"Default Configuration File",id:"default-configuration-file",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const i={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(i.h1,{id:"configuration",children:"Configuration"}),"\n",(0,t.jsx)(i.p,{children:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set."}),"\n",(0,t.jsx)(i.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"detectors"}),": List of detectors to run. Each detector can be specified with a ",(0,t.jsx)(i.code,{children:"className"})," and optionally a ",(0,t.jsx)(i.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"modulePath"})," (string, optional): The file path of the detector module."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"ignored_projects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"soufflePath"})," (string, optional): Directory to save generated Souffl\xe9 files which is helpful for debugging purposes. If not set, a temporary directory will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"verbosity"})," (string, optional): Verbosity level of the logs. Possible values are ",(0,t.jsx)(i.code,{children:"quiet"}),", ",(0,t.jsx)(i.code,{children:"debug"}),", and ",(0,t.jsx)(i.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(i.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,t.jsx)(i.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsx)(i.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,t.jsx)(i.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,t.jsx)(i.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-json",children:'{\n "detectors": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" }\n ],\n "ignored_projects": [],\n "verbosity": "default"\n}\n'})}),"\n",(0,t.jsxs)(i.p,{children:["All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,t.jsxs)(i.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,t.jsx)(i.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --dump-config test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsxs)(i.p,{children:["If there is no Misti config in the ",(0,t.jsx)(i.code,{children:"simple"})," directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors."]}),"\n",(0,t.jsx)(i.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,t.jsxs)(i.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,t.jsx)(i.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function u(e={}){const{wrapper:i}={...(0,o.R)(),...e.components};return i?(0,t.jsx)(i,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>r,x:()=>l});var t=n(6540);const o={},s=t.createContext(o);function r(e){const i=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),t.createElement(s.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/15d13f14.3309e304.js b/assets/js/15d13f14.3309e304.js new file mode 100644 index 000000000..f306a2442 --- /dev/null +++ b/assets/js/15d13f14.3309e304.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3884],{6662:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var t=i(4848),s=i(8453);const r={},o="Contributing Guide",a={id:"hacking/contributing",title:"Contributing Guide",description:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.",source:"@site/versioned_docs/version-0.2.1/hacking/contributing.md",sourceDirName:"hacking",slug:"/hacking/contributing",permalink:"/tools/misti/docs/0.2.1/hacking/contributing",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/hacking/contributing.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Prefer Augmented Assignment",permalink:"/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign"},next:{title:"Design Overview",permalink:"/tools/misti/docs/0.2.1/hacking/design"}},c={},d=[{value:"Issues reporting",id:"issues-reporting",level:2},{value:"Documentation contribution",id:"documentation-contribution",level:2},{value:"Code contribution",id:"code-contribution",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"contributing-guide",children:"Contributing Guide"}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better."}),"\n",(0,t.jsx)(n.h2,{id:"issues-reporting",children:"Issues reporting"}),"\n",(0,t.jsx)(n.p,{children:"When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.\nPlease help us by publishing it and the input sources at:\nhttps://github.com/nowarp/misti/issues/new.\n"})}),"\n",(0,t.jsx)(n.p,{children:"We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users."}),"\n",(0,t.jsx)(n.h2,{id:"documentation-contribution",children:"Documentation contribution"}),"\n",(0,t.jsxs)(n.p,{children:["We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/nowarp.github.io/issues",children:"nowarp.github.io Issues"}),". Additionally, many documentation pages have an ",(0,t.jsx)(n.code,{children:"Edit"})," button that allows you to make direct contributions easily."]}),"\n",(0,t.jsx)(n.h2,{id:"code-contribution",children:"Code contribution"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Navigate Issues and Find Tasks"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Browse the issues ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"here"}),". Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues."]}),"\n",(0,t.jsx)(n.li,{children:"Choose an issue suitable for you and mention in the issue that you're working on it."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Implement Your Changes"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Implement your changes. Feel free to ask questions in the issue if needed."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Ensure Tests Pass"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Before creating a PR, make sure all tests and CI checks are passing by running:","\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn test-all\n"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Create a PR"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Submit your pull request ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/pulls",children:"here"})]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Add a CHANGELOG entry"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Describe your changes in the ",(0,t.jsx)(n.code,{children:"CHANGELOG.md"})," file according to the existing structure."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/HACKING.md",children:"HACKING.md"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your contributions!"})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>o,x:()=>a});var t=i(6540);const s={},r=t.createContext(s);function o(e){const n=t.useContext(r);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),t.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/17406c9d.759681c0.js b/assets/js/17406c9d.759681c0.js new file mode 100644 index 000000000..3ea76fa6a --- /dev/null +++ b/assets/js/17406c9d.759681c0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8513],{1027:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>s,default:()=>p,frontMatter:()=>a,metadata:()=>l,toc:()=>d});var r=n(4848),i=n(8453);const a={},s="ReadOnlyVariables",l={id:"detectors/ReadOnlyVariables",title:"ReadOnlyVariables",description:"A detector that identifies read-only variables and fields.",source:"@site/versioned_docs/version-0.3.0/detectors/ReadOnlyVariables.md",sourceDirName:"detectors",slug:"/detectors/ReadOnlyVariables",permalink:"/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/ReadOnlyVariables.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi"},next:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap"}},o={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"readonlyvariables",children:"ReadOnlyVariables"}),"\n",(0,r.jsx)(t.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"These variables could typically be replaced with constants to optimize performance.\nAlternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally."}),"\n",(0,r.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"fun calculateFinalPrice(price: Int): Int {\n // Warning: the developer uses a read-only variable that could be a constant\n let DISCOUNT_AMOUNT: Int = 10;\n return price - DISCOUNT_AMOUNT;\n}\n"})}),"\n",(0,r.jsx)(t.p,{children:"Use instead:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"const DISCOUNT_AMOUNT: Int = 10;\n\nfun calculateFinalPrice(price: Int): Int {\n // OK: Fixed after the analyzer highlighted this warning\n return price - DISCOUNT_AMOUNT;\n}\n"})})]})}function p(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>l});var r=n(6540);const i={},a=r.createContext(i);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/17896441.dc05340c.js b/assets/js/17896441.dc05340c.js new file mode 100644 index 000000000..ebbf1e5b1 --- /dev/null +++ b/assets/js/17896441.dc05340c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8401],{6365:(e,t,n)=>{n.r(t),n.d(t,{default:()=>le});var s=n(6540),a=n(1003),i=n(9532),o=n(4848);const l=s.createContext(null);function r(e){let{children:t,content:n}=e;const a=function(e){return(0,s.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(n);return(0,o.jsx)(l.Provider,{value:a,children:t})}function c(){const e=(0,s.useContext)(l);if(null===e)throw new i.dV("DocProvider");return e}function d(){const{metadata:e,frontMatter:t,assets:n}=c();return(0,o.jsx)(a.be,{title:e.title,description:e.description,keywords:t.keywords,image:n.image??t.image})}var u=n(4164),m=n(4581),h=n(1312),b=n(8774);function x(e){const{permalink:t,title:n,subLabel:s,isNext:a}=e;return(0,o.jsxs)(b.A,{className:(0,u.A)("pagination-nav__link",a?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t,children:[s&&(0,o.jsx)("div",{className:"pagination-nav__sublabel",children:s}),(0,o.jsx)("div",{className:"pagination-nav__label",children:n})]})}function p(e){const{previous:t,next:n}=e;return(0,o.jsxs)("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,h.T)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"}),children:[t&&(0,o.jsx)(x,{...t,subLabel:(0,o.jsx)(h.A,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc",children:"Previous"})}),n&&(0,o.jsx)(x,{...n,subLabel:(0,o.jsx)(h.A,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc",children:"Next"}),isNext:!0})]})}function v(){const{metadata:e}=c();return(0,o.jsx)(p,{previous:e.previous,next:e.next})}var g=n(4586),j=n(4070),f=n(7559),_=n(5597),A=n(2252);const N={unreleased:function(e){let{siteTitle:t,versionMetadata:n}=e;return(0,o.jsx)(h.A,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:(0,o.jsx)("b",{children:n.label})},children:"This is unreleased documentation for {siteTitle} {versionLabel} version."})},unmaintained:function(e){let{siteTitle:t,versionMetadata:n}=e;return(0,o.jsx)(h.A,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:(0,o.jsx)("b",{children:n.label})},children:"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained."})}};function C(e){const t=N[e.versionMetadata.banner];return(0,o.jsx)(t,{...e})}function L(e){let{versionLabel:t,to:n,onClick:s}=e;return(0,o.jsx)(h.A,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:(0,o.jsx)("b",{children:(0,o.jsx)(b.A,{to:n,onClick:s,children:(0,o.jsx)(h.A,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label",children:"latest version"})})})},children:"For up-to-date documentation, see the {latestVersionLink} ({versionLabel})."})}function T(e){let{className:t,versionMetadata:n}=e;const{siteConfig:{title:s}}=(0,g.A)(),{pluginId:a}=(0,j.vT)({failfast:!0}),{savePreferredVersionName:i}=(0,_.g1)(a),{latestDocSuggestion:l,latestVersionSuggestion:r}=(0,j.HW)(a),c=l??(d=r).docs.find((e=>e.id===d.mainDocId));var d;return(0,o.jsxs)("div",{className:(0,u.A)(t,f.G.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert",children:[(0,o.jsx)("div",{children:(0,o.jsx)(C,{siteTitle:s,versionMetadata:n})}),(0,o.jsx)("div",{className:"margin-top--md",children:(0,o.jsx)(L,{versionLabel:r.label,to:c.path,onClick:()=>i(r.name)})})]})}function k(e){let{className:t}=e;const n=(0,A.r)();return n.banner?(0,o.jsx)(T,{className:t,versionMetadata:n}):null}function M(e){let{className:t}=e;const n=(0,A.r)();return n.badge?(0,o.jsx)("span",{className:(0,u.A)(t,f.G.docs.docVersionBadge,"badge badge--secondary"),children:(0,o.jsx)(h.A,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label},children:"Version: {versionLabel}"})}):null}const w={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function B(e){let{permalink:t,label:n,count:s,description:a}=e;return(0,o.jsxs)(b.A,{href:t,title:a,className:(0,u.A)(w.tag,s?w.tagWithCount:w.tagRegular),children:[n,s&&(0,o.jsx)("span",{children:s})]})}const I={tags:"tags_jXut",tag:"tag_QGVx"};function V(e){let{tags:t}=e;return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)("b",{children:(0,o.jsx)(h.A,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list",children:"Tags:"})}),(0,o.jsx)("ul",{className:(0,u.A)(I.tags,"padding--none","margin-left--sm"),children:t.map((e=>(0,o.jsx)("li",{className:I.tag,children:(0,o.jsx)(B,{...e})},e.permalink)))})]})}var H=n(2153);function y(){const{metadata:e}=c(),{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:s,tags:a}=e,i=a.length>0,l=!!(t||n||s);return i||l?(0,o.jsxs)("footer",{className:(0,u.A)(f.G.docs.docFooter,"docusaurus-mt-lg"),children:[i&&(0,o.jsx)("div",{className:(0,u.A)("row margin-top--sm",f.G.docs.docFooterTagsRow),children:(0,o.jsx)("div",{className:"col",children:(0,o.jsx)(V,{tags:a})})}),l&&(0,o.jsx)(H.A,{className:(0,u.A)("margin-top--sm",f.G.docs.docFooterEditMetaRow),editUrl:t,lastUpdatedAt:n,lastUpdatedBy:s})]}):null}var E=n(1422),G=n(5195);const P={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function F(e){let{collapsed:t,...n}=e;return(0,o.jsx)("button",{type:"button",...n,className:(0,u.A)("clean-btn",P.tocCollapsibleButton,!t&&P.tocCollapsibleButtonExpanded,n.className),children:(0,o.jsx)(h.A,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component",children:"On this page"})})}const R={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function D(e){let{toc:t,className:n,minHeadingLevel:s,maxHeadingLevel:a}=e;const{collapsed:i,toggleCollapsed:l}=(0,E.u)({initialState:!0});return(0,o.jsxs)("div",{className:(0,u.A)(R.tocCollapsible,!i&&R.tocCollapsibleExpanded,n),children:[(0,o.jsx)(F,{collapsed:i,onClick:l}),(0,o.jsx)(E.N,{lazy:!0,className:R.tocCollapsibleContent,collapsed:i,children:(0,o.jsx)(G.A,{toc:t,minHeadingLevel:s,maxHeadingLevel:a})})]})}const S={tocMobile:"tocMobile_ITEo"};function U(){const{toc:e,frontMatter:t}=c();return(0,o.jsx)(D,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,u.A)(f.G.docs.docTocMobile,S.tocMobile)})}var O=n(7763);function W(){const{toc:e,frontMatter:t}=c();return(0,o.jsx)(O.A,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:f.G.docs.docTocDesktop})}var z=n(1107),Q=n(5533);function X(e){let{children:t}=e;const n=function(){const{metadata:e,frontMatter:t,contentTitle:n}=c();return t.hide_title||void 0!==n?null:e.title}();return(0,o.jsxs)("div",{className:(0,u.A)(f.G.docs.docMarkdown,"markdown"),children:[n&&(0,o.jsx)("header",{children:(0,o.jsx)(z.A,{as:"h1",children:n})}),(0,o.jsx)(Q.A,{children:t})]})}var Y=n(1754),Z=n(9169),$=n(6025);function q(e){return(0,o.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,o.jsx)("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"})})}const J={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function K(){const e=(0,$.Ay)("/");return(0,o.jsx)("li",{className:"breadcrumbs__item",children:(0,o.jsx)(b.A,{"aria-label":(0,h.T)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e,children:(0,o.jsx)(q,{className:J.breadcrumbHomeIcon})})})}const ee={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function te(e){let{children:t,href:n,isLast:s}=e;const a="breadcrumbs__link";return s?(0,o.jsx)("span",{className:a,itemProp:"name",children:t}):n?(0,o.jsx)(b.A,{className:a,href:n,itemProp:"item",children:(0,o.jsx)("span",{itemProp:"name",children:t})}):(0,o.jsx)("span",{className:a,children:t})}function ne(e){let{children:t,active:n,index:s,addMicrodata:a}=e;return(0,o.jsxs)("li",{...a&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},className:(0,u.A)("breadcrumbs__item",{"breadcrumbs__item--active":n}),children:[t,(0,o.jsx)("meta",{itemProp:"position",content:String(s+1)})]})}function se(){const e=(0,Y.OF)(),t=(0,Z.Dt)();return e?(0,o.jsx)("nav",{className:(0,u.A)(f.G.docs.docBreadcrumbs,ee.breadcrumbsContainer),"aria-label":(0,h.T)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"}),children:(0,o.jsxs)("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList",children:[t&&(0,o.jsx)(K,{}),e.map(((t,n)=>{const s=n===e.length-1,a="category"===t.type&&t.linkUnlisted?void 0:t.href;return(0,o.jsx)(ne,{active:s,index:n,addMicrodata:!!a,children:(0,o.jsx)(te,{href:a,isLast:s,children:t.label})},n)}))]})}):null}var ae=n(996);const ie={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function oe(e){let{children:t}=e;const n=function(){const{frontMatter:e,toc:t}=c(),n=(0,m.l)(),s=e.hide_table_of_contents,a=!s&&t.length>0;return{hidden:s,mobile:a?(0,o.jsx)(U,{}):void 0,desktop:!a||"desktop"!==n&&"ssr"!==n?void 0:(0,o.jsx)(W,{})}}(),{metadata:{unlisted:s}}=c();return(0,o.jsxs)("div",{className:"row",children:[(0,o.jsxs)("div",{className:(0,u.A)("col",!n.hidden&&ie.docItemCol),children:[s&&(0,o.jsx)(ae.A,{}),(0,o.jsx)(k,{}),(0,o.jsxs)("div",{className:ie.docItemContainer,children:[(0,o.jsxs)("article",{children:[(0,o.jsx)(se,{}),(0,o.jsx)(M,{}),n.mobile,(0,o.jsx)(X,{children:t}),(0,o.jsx)(y,{})]}),(0,o.jsx)(v,{})]})]}),n.desktop&&(0,o.jsx)("div",{className:"col col--3",children:n.desktop})]})}function le(e){const t=`docs-doc-id-${e.content.metadata.id}`,n=e.content;return(0,o.jsx)(r,{content:e.content,children:(0,o.jsxs)(a.e3,{className:t,children:[(0,o.jsx)(d,{}),(0,o.jsx)(oe,{children:(0,o.jsx)(n,{})})]})})}}}]); \ No newline at end of file diff --git a/assets/js/1869ccd1.5d76a4bd.js b/assets/js/1869ccd1.5d76a4bd.js new file mode 100644 index 000000000..2451bd210 --- /dev/null +++ b/assets/js/1869ccd1.5d76a4bd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9108],{9400:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var s=n(4848),i=n(8453);const r={},o="Prefer Augmented Assignment",a={id:"detectors/PreferAugmentedAssign",title:"Prefer Augmented Assignment",description:"Detects non-idiomatic statements that can be written using augmented assignment operators like +=, -=, etc.",source:"@site/versioned_docs/version-0.2.2/detectors/PreferAugmentedAssign.md",sourceDirName:"detectors",slug:"/detectors/PreferAugmentedAssign",permalink:"/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/PreferAugmentedAssign.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Field Initialized Twice",permalink:"/tools/misti/docs/0.2.2/detectors/FieldDoubleInit"},next:{title:"Contributing",permalink:"/tools/misti/docs/0.2.2/hacking/contributing"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"prefer-augmented-assignment",children:"Prefer Augmented Assignment"}),"\n",(0,s.jsxs)(t.p,{children:["Detects non-idiomatic statements that can be written using augmented assignment operators like ",(0,s.jsx)(t.code,{children:"+="}),", ",(0,s.jsx)(t.code,{children:"-="}),", etc."]}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Using augmented assignment operations improves the readability of the source code and reduces the risk of mistakes, such as those that occur during copy-pasting and refactoring code."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue = (msgValue - ctx.readForwardFee());\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue -= ctx.readForwardFee());\n"})})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(6540);const i={},r=s.createContext(i);function o(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1a50d306.ff71f994.js b/assets/js/1a50d306.ff71f994.js new file mode 100644 index 000000000..3a3cefe8e --- /dev/null +++ b/assets/js/1a50d306.ff71f994.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6999],{5669:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>o,toc:()=>d});var s=n(4848),r=n(8453);const a={},i="NeverAccessedVariables",o={id:"detectors/NeverAccessedVariables",title:"NeverAccessedVariables",description:"A detector that identifies write-only or unused variables, fields and constants.",source:"@site/versioned_docs/version-0.3.1/detectors/NeverAccessedVariables.md",sourceDirName:"detectors",slug:"/detectors/NeverAccessedVariables",permalink:"/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/NeverAccessedVariables.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"InheritedStateMutation",permalink:"/tools/misti/docs/0.3.1/detectors/InheritedStateMutation"},next:{title:"PreferAugmentedAssign",permalink:"/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"neveraccessedvariables",children:"NeverAccessedVariables"}),"\n",(0,s.jsx)(t.p,{children:"A detector that identifies write-only or unused variables, fields and constants."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"These variables are either assigned but never used in any meaningful computation,\nor they are declared and never used at all, which may indicate redundant code\nor an incomplete implementation of the intended logic."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"// Error: the developer forgot to use the constant\nconst MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'const MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n // OK: Fixed after the analyzer highlighted this warning\n require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(6540);const r={},a=s.createContext(r);function i(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1a8310a1.e63a2b77.js b/assets/js/1a8310a1.e63a2b77.js new file mode 100644 index 000000000..d14aa3f82 --- /dev/null +++ b/assets/js/1a8310a1.e63a2b77.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7743],{9881:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var t=i(4848),s=i(8453);const o={},r="Contributing Guide",c={id:"hacking/contributing",title:"Contributing Guide",description:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.",source:"@site/versioned_docs/version-0.4.0/hacking/contributing.md",sourceDirName:"hacking",slug:"/hacking/contributing",permalink:"/tools/misti/docs/hacking/contributing",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/hacking/contributing.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpConfig",permalink:"/tools/misti/docs/tools/DumpConfig"},next:{title:"Developing Misti",permalink:"/tools/misti/docs/hacking/developing-misti"}},a={},l=[{value:"Issues reporting",id:"issues-reporting",level:2},{value:"Documentation contribution",id:"documentation-contribution",level:2},{value:"Code contribution",id:"code-contribution",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"contributing-guide",children:"Contributing Guide"}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better."}),"\n",(0,t.jsx)(n.h2,{id:"issues-reporting",children:"Issues reporting"}),"\n",(0,t.jsx)(n.p,{children:"When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.\nPlease help us by publishing it and the input sources at:\nhttps://github.com/nowarp/misti/issues/new.\n"})}),"\n",(0,t.jsx)(n.p,{children:"We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users."}),"\n",(0,t.jsx)(n.h2,{id:"documentation-contribution",children:"Documentation contribution"}),"\n",(0,t.jsxs)(n.p,{children:["We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/nowarp.github.io/issues",children:"nowarp.github.io Issues"}),". Additionally, many documentation pages have an ",(0,t.jsx)(n.code,{children:"Edit"})," button that allows you to make direct contributions easily."]}),"\n",(0,t.jsx)(n.h2,{id:"code-contribution",children:"Code contribution"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Navigate Issues and Find Tasks"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Browse the issues ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"here"}),". Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues."]}),"\n",(0,t.jsx)(n.li,{children:"Choose an issue suitable for you and mention in the issue that you're working on it."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Implement Your Changes"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Implement your changes. Feel free to ask questions in the issue if needed."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Ensure Tests Pass"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Before creating a PR, make sure all tests and CI checks are passing by running:","\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn test-all\n"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Create a PR"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Submit your pull request ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/pulls",children:"here"})]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Add a CHANGELOG entry"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Describe your changes in the ",(0,t.jsx)(n.code,{children:"CHANGELOG.md"})," file according to the existing structure."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["See ",(0,t.jsx)(n.a,{href:"/tools/misti/docs/hacking/developing-misti",children:"Developing Misti"})," for information about initializing the environment and additional hacking tips."]}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your contributions!"})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>c});var t=i(6540);const s={},o=t.createContext(s);function r(e){const n=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1b73222b.c47a22da.js b/assets/js/1b73222b.c47a22da.js new file mode 100644 index 000000000..bf5a87621 --- /dev/null +++ b/assets/js/1b73222b.c47a22da.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3420],{5274:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.3.0","label":"0.3.0","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.3.0","isLast":false,"docsSidebars":{"sidebar":[{"type":"link","label":"Introduction","href":"/tools/misti/docs/0.3.0/","docId":"intro","unlisted":false},{"type":"category","label":"Tutorial","items":[{"type":"link","label":"Getting Started","href":"/tools/misti/docs/0.3.0/tutorial/getting-started","docId":"tutorial/getting-started","unlisted":false},{"type":"link","label":"CI/CD Integration","href":"/tools/misti/docs/0.3.0/tutorial/ci-cd","docId":"tutorial/ci-cd","unlisted":false},{"type":"link","label":"Command-Line Interface","href":"/tools/misti/docs/0.3.0/tutorial/cli","docId":"tutorial/cli","unlisted":false},{"type":"link","label":"Configuration","href":"/tools/misti/docs/0.3.0/tutorial/configuration","docId":"tutorial/configuration","unlisted":false},{"type":"link","label":"Using with Blueprint","href":"/tools/misti/docs/0.3.0/tutorial/blueprint","docId":"tutorial/blueprint","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Detectors Overview","href":"/tools/misti/docs/0.3.0/detectors","docId":"detectors","unlisted":false},{"type":"category","label":"Detectors","items":[{"type":"link","label":"ArgCopyMutation","href":"/tools/misti/docs/0.3.0/detectors/ArgCopyMutation","docId":"detectors/ArgCopyMutation","unlisted":false},{"type":"link","label":"AsmIsUsed","href":"/tools/misti/docs/0.3.0/detectors/AsmIsUsed","docId":"detectors/AsmIsUsed","unlisted":false},{"type":"link","label":"BranchDuplicate","href":"/tools/misti/docs/0.3.0/detectors/BranchDuplicate","docId":"detectors/BranchDuplicate","unlisted":false},{"type":"link","label":"ConstantAddress","href":"/tools/misti/docs/0.3.0/detectors/ConstantAddress","docId":"detectors/ConstantAddress","unlisted":false},{"type":"link","label":"DivideBeforeMultiply","href":"/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply","docId":"detectors/DivideBeforeMultiply","unlisted":false},{"type":"link","label":"DumpIsUsed","href":"/tools/misti/docs/0.3.0/detectors/DumpIsUsed","docId":"detectors/DumpIsUsed","unlisted":false},{"type":"link","label":"FieldDoubleInit","href":"/tools/misti/docs/0.3.0/detectors/FieldDoubleInit","docId":"detectors/FieldDoubleInit","unlisted":false},{"type":"link","label":"InheritedStateMutation","href":"/tools/misti/docs/0.3.0/detectors/InheritedStateMutation","docId":"detectors/InheritedStateMutation","unlisted":false},{"type":"link","label":"NeverAccessedVariables","href":"/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables","docId":"detectors/NeverAccessedVariables","unlisted":false},{"type":"link","label":"PreferAugmentedAssign","href":"/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign","docId":"detectors/PreferAugmentedAssign","unlisted":false},{"type":"link","label":"PreferredStdlibApi","href":"/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi","docId":"detectors/PreferredStdlibApi","unlisted":false},{"type":"link","label":"ReadOnlyVariables","href":"/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables","docId":"detectors/ReadOnlyVariables","unlisted":false},{"type":"link","label":"StringReceiversOverlap","href":"/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap","docId":"detectors/StringReceiversOverlap","unlisted":false},{"type":"link","label":"UnboundLoops","href":"/tools/misti/docs/0.3.0/detectors/UnboundLoops","docId":"detectors/UnboundLoops","unlisted":false},{"type":"link","label":"ZeroAddress","href":"/tools/misti/docs/0.3.0/detectors/ZeroAddress","docId":"detectors/ZeroAddress","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacking","items":[{"type":"link","label":"Contributing","href":"/tools/misti/docs/0.3.0/hacking/contributing","docId":"hacking/contributing","unlisted":false},{"type":"link","label":"Design Overview","href":"/tools/misti/docs/0.3.0/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/0.3.0/hacking/souffle","docId":"hacking/souffle","unlisted":false},{"type":"link","label":"Tools","href":"/tools/misti/docs/0.3.0/hacking/tools","docId":"hacking/tools","unlisted":false},{"type":"link","label":"Custom Detectors","href":"/tools/misti/docs/0.3.0/hacking/custom-detector","docId":"hacking/custom-detector","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"detectors":{"id":"detectors","title":"Detectors Overview","description":"Misti currently supports 15 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:","sidebar":"sidebar"},"detectors/ArgCopyMutation":{"id":"detectors/ArgCopyMutation","title":"ArgCopyMutation","description":"A detector that highlights cases where function argument mutations are ineffective","sidebar":"sidebar"},"detectors/AsmIsUsed":{"id":"detectors/AsmIsUsed","title":"AsmIsUsed","description":"An optional detector that highlights all the asm functions.","sidebar":"sidebar"},"detectors/BranchDuplicate":{"id":"detectors/BranchDuplicate","title":"BranchDuplicate","description":"Detector that reports duplicated code in conditional branches.","sidebar":"sidebar"},"detectors/ConstantAddress":{"id":"detectors/ConstantAddress","title":"ConstantAddress","description":"An optional detector that highlights all the constant addresses appearing in the source code.","sidebar":"sidebar"},"detectors/DivideBeforeMultiply":{"id":"detectors/DivideBeforeMultiply","title":"DivideBeforeMultiply","description":"A detector that identifies and corrects instances of division before multiplication to","sidebar":"sidebar"},"detectors/DumpIsUsed":{"id":"detectors/DumpIsUsed","title":"DumpIsUsed","description":"An optional detector that highlights all the dump function calls.","sidebar":"sidebar"},"detectors/FieldDoubleInit":{"id":"detectors/FieldDoubleInit","title":"FieldDoubleInit","description":"A detector that highlights cases where a field is initialized both in the","sidebar":"sidebar"},"detectors/InheritedStateMutation":{"id":"detectors/InheritedStateMutation","title":"InheritedStateMutation","description":"An optional detector that highlights all instances where inherited trait variables","sidebar":"sidebar"},"detectors/NeverAccessedVariables":{"id":"detectors/NeverAccessedVariables","title":"NeverAccessedVariables","description":"A detector that identifies write-only or unused variables, fields and constants.","sidebar":"sidebar"},"detectors/PreferAugmentedAssign":{"id":"detectors/PreferAugmentedAssign","title":"PreferAugmentedAssign","description":"Detects non-idiomatic statements that can be written using augmented assignment","sidebar":"sidebar"},"detectors/PreferredStdlibApi":{"id":"detectors/PreferredStdlibApi","title":"PreferredStdlibApi","description":"An optional detector that flags the use of advanced functions from the standard library.","sidebar":"sidebar"},"detectors/ReadOnlyVariables":{"id":"detectors/ReadOnlyVariables","title":"ReadOnlyVariables","description":"A detector that identifies read-only variables and fields.","sidebar":"sidebar"},"detectors/StringReceiversOverlap":{"id":"detectors/StringReceiversOverlap","title":"StringReceiversOverlap","description":"A detector that finds overlapping messages between general string receivers and string receivers.","sidebar":"sidebar"},"detectors/UnboundLoops":{"id":"detectors/UnboundLoops","title":"UnboundLoops","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/ZeroAddress":{"id":"detectors/ZeroAddress","title":"ZeroAddress","description":"A detector that identifies uses of the zero address.","sidebar":"sidebar"},"hacking/contributing":{"id":"hacking/contributing","title":"Contributing Guide","description":"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.","sidebar":"sidebar"},"hacking/custom-detector":{"id":"hacking/custom-detector","title":"Custom Detector Guide","description":"Introduction","sidebar":"sidebar"},"hacking/design":{"id":"hacking/design","title":"Design Overview","description":"Static Analysis","sidebar":"sidebar"},"hacking/souffle":{"id":"hacking/souffle","title":"Souffl\xe9 Integration Guide","description":"What is Souffl\xe9?","sidebar":"sidebar"},"hacking/tools":{"id":"hacking/tools","title":"Tools Guide","description":"This page describes the internal analyzer tools available in Misti to aid in development and debugging.","sidebar":"sidebar"},"intro":{"id":"intro","title":"Introduction","description":"Misti is a static analysis tool designed for smart contracts on the TON blockchain.","sidebar":"sidebar"},"tutorial/blueprint":{"id":"tutorial/blueprint","title":"Using Misti with Blueprint","description":"Blueprint is a development environment for writing, testing, and deploying TON smart contracts.","sidebar":"sidebar"},"tutorial/ci-cd":{"id":"tutorial/ci-cd","title":"Integrating Misti into CI/CD","description":"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.","sidebar":"sidebar"},"tutorial/cli":{"id":"tutorial/cli","title":"Command-Line Interface","description":"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.","sidebar":"sidebar"},"tutorial/configuration":{"id":"tutorial/configuration","title":"Configuration","description":"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.","sidebar":"sidebar"},"tutorial/getting-started":{"id":"tutorial/getting-started","title":"Getting started","description":"This guide will walk you through the steps to install and set up the Misti static analyzer.","sidebar":"sidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/1b960128.5b5b59d9.js b/assets/js/1b960128.5b5b59d9.js new file mode 100644 index 000000000..1b87f840d --- /dev/null +++ b/assets/js/1b960128.5b5b59d9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8920],{3265:(t,n,e)=>{e.r(n),e.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>l,frontMatter:()=>s,metadata:()=>u,toc:()=>c});var o=e(4848),i=e(8453);const s={},r="DumpConfig",u={id:"tools/DumpConfig",title:"DumpConfig",description:"The DumpConfig tool in Misti allows you to print the current configuration file used by the analyzer. This is useful for obtaining the default configuration to use as a starting point for your custom setup or to inspect and understand the existing configuration in use.",source:"@site/versioned_docs/version-0.4.0/tools/DumpConfig.md",sourceDirName:"tools",slug:"/tools/DumpConfig",permalink:"/tools/misti/docs/tools/DumpConfig",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/tools/DumpConfig.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpCfg",permalink:"/tools/misti/docs/tools/DumpCfg"},next:{title:"Contributing",permalink:"/tools/misti/docs/hacking/contributing"}},a={},c=[{value:"Usage",id:"usage",level:2},{value:"Understanding the Output",id:"understanding-the-output",level:2}];function d(t){const n={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...t.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"dumpconfig",children:"DumpConfig"}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"DumpConfig"})," tool in Misti allows you to print the current configuration file used by the analyzer. This is useful for obtaining the default configuration to use as a starting point for your custom setup or to inspect and understand the existing configuration in use."]}),"\n",(0,o.jsx)(n.h2,{id:"usage",children:"Usage"}),"\n",(0,o.jsx)(n.p,{children:"To dump the configuration file, use the following command:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:'npx misti -t "DumpConfig" \n'})}),"\n",(0,o.jsx)(n.h2,{id:"understanding-the-output",children:"Understanding the Output"}),"\n",(0,o.jsx)(n.p,{children:"The output provides an overview of all the configurations and settings applied to your project. This can help you quickly identify the default settings, make adjustments to fit your specific needs, and ensure that your custom detectors are running under the correct configurations."})]})}function l(t={}){const{wrapper:n}={...(0,i.R)(),...t.components};return n?(0,o.jsx)(n,{...t,children:(0,o.jsx)(d,{...t})}):d(t)}},8453:(t,n,e)=>{e.d(n,{R:()=>r,x:()=>u});var o=e(6540);const i={},s=o.createContext(i);function r(t){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof t?t(n):{...n,...t}}),[n,t])}function u(t){let n;return n=t.disableParentContext?"function"==typeof t.components?t.components(i):t.components||i:r(t.components),o.createElement(s.Provider,{value:n},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/1c26cb06.972f1ca6.js b/assets/js/1c26cb06.972f1ca6.js new file mode 100644 index 000000000..bb1a78e57 --- /dev/null +++ b/assets/js/1c26cb06.972f1ca6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5602],{8164:(t,n,e)=>{e.r(n),e.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>u});var i=e(4848),o=e(8453);const s={},r="Integrating Misti into CI/CD",c={id:"tutorial/ci-cd",title:"Integrating Misti into CI/CD",description:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.",source:"@site/versioned_docs/version-0.2.2/tutorial/ci-cd.md",sourceDirName:"tutorial",slug:"/tutorial/ci-cd",permalink:"/tools/misti/docs/0.2.2/tutorial/ci-cd",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/tutorial/ci-cd.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Getting Started",permalink:"/tools/misti/docs/0.2.2/tutorial/getting-started"},next:{title:"Configuration",permalink:"/tools/misti/docs/0.2.2/tutorial/configuration"}},a={},u=[{value:"GitHub Actions",id:"github-actions",level:2}];function l(t){const n={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,o.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"integrating-misti-into-cicd",children:"Integrating Misti into CI/CD"}),"\n",(0,i.jsx)(n.p,{children:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle."}),"\n",(0,i.jsx)(n.h2,{id:"github-actions",children:"GitHub Actions"}),"\n",(0,i.jsx)(n.p,{children:"To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"1. Open your GitHub repository"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"2. Create or edit the GitHub Actions workflow YAML file"})}),"\n",(0,i.jsxs)(n.p,{children:["It could be located at e.g., ",(0,i.jsx)(n.code,{children:".github/workflows/main.yml"}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"3. Add the step to run Misti to your YAML file"})}),"\n",(0,i.jsx)(n.p,{children:"For example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"name: Run Misti\non: [push, pull_request]\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v2\n\n - name: Install dependencies\n run: npm install\n\n - name: Run Misti\n run: npx misti /path/to/your/tact.config.json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"npx misti /path/to/your/tact.config.json"})," command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"4. Adjusting the Misti Configuration"})}),"\n",(0,i.jsxs)(n.p,{children:["If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the ",(0,i.jsx)(n.a,{href:"./configuration",children:"Configuration"})," section for more details on how to customize your settings."]})]})}function d(t={}){const{wrapper:n}={...(0,o.R)(),...t.components};return n?(0,i.jsx)(n,{...t,children:(0,i.jsx)(l,{...t})}):l(t)}},8453:(t,n,e)=>{e.d(n,{R:()=>r,x:()=>c});var i=e(6540);const o={},s=i.createContext(o);function r(t){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof t?t(n):{...n,...t}}),[n,t])}function c(t){let n;return n=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:r(t.components),i.createElement(s.Provider,{value:n},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/1df93b7f.4689c496.js b/assets/js/1df93b7f.4689c496.js new file mode 100644 index 000000000..ac8f2d14f --- /dev/null +++ b/assets/js/1df93b7f.4689c496.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4583],{6866:(s,t,u)=>{u.r(t),u.d(t,{default:()=>o});var e=u(6540),n=u(6347);const o=()=>{const s=(0,n.W6)();return(0,e.useEffect)((()=>{s.push("/tools/misti")}),[s]),null}}}]); \ No newline at end of file diff --git a/assets/js/1f391b9e.d1d4beb6.js b/assets/js/1f391b9e.d1d4beb6.js new file mode 100644 index 000000000..e1cb96929 --- /dev/null +++ b/assets/js/1f391b9e.d1d4beb6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6061],{7973:(e,a,s)=>{s.r(a),s.d(a,{default:()=>g});s(6540);var t=s(4164),i=s(1003),l=s(7559),r=s(781),d=s(5533),n=s(7763),c=s(996),o=s(2153);const p={mdxPageWrapper:"mdxPageWrapper_j9I6"};var m=s(4848);function g(e){const{content:a}=e,{metadata:{title:s,editUrl:g,description:x,frontMatter:h,unlisted:j,lastUpdatedBy:_,lastUpdatedAt:u},assets:A}=a,{keywords:v,wrapperClassName:w,hide_table_of_contents:f}=h,N=A.image??h.image,b=!!(g||u||_);return(0,m.jsx)(i.e3,{className:(0,t.A)(w??l.G.wrapper.mdxPages,l.G.page.mdxPage),children:(0,m.jsxs)(r.A,{children:[(0,m.jsx)(i.be,{title:s,description:x,keywords:v,image:N}),(0,m.jsx)("main",{className:"container container--fluid margin-vert--lg",children:(0,m.jsxs)("div",{className:(0,t.A)("row",p.mdxPageWrapper),children:[(0,m.jsxs)("div",{className:(0,t.A)("col",!f&&"col--8"),children:[j&&(0,m.jsx)(c.A,{}),(0,m.jsx)("article",{children:(0,m.jsx)(d.A,{children:(0,m.jsx)(a,{})})}),b&&(0,m.jsx)(o.A,{className:(0,t.A)("margin-top--sm",l.G.pages.pageFooterEditMetaRow),editUrl:g,lastUpdatedAt:u,lastUpdatedBy:_})]}),!f&&a.toc.length>0&&(0,m.jsx)("div",{className:"col col--2",children:(0,m.jsx)(n.A,{toc:a.toc,minHeadingLevel:h.toc_min_heading_level,maxHeadingLevel:h.toc_max_heading_level})})]})})]})})}}}]); \ No newline at end of file diff --git a/assets/js/2018b81b.63a7c757.js b/assets/js/2018b81b.63a7c757.js new file mode 100644 index 000000000..85fff4ca6 --- /dev/null +++ b/assets/js/2018b81b.63a7c757.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7677],{6964:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>o,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>a});var i=n(4848),r=n(8453);const s={},o="Using Misti with Blueprint",c={id:"tutorial/blueprint",title:"Using Misti with Blueprint",description:"Blueprint is a development environment for writing, testing, and deploying TON smart contracts.",source:"@site/versioned_docs/version-0.3.0/tutorial/blueprint.md",sourceDirName:"tutorial",slug:"/tutorial/blueprint",permalink:"/tools/misti/docs/0.3.0/tutorial/blueprint",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/tutorial/blueprint.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/tools/misti/docs/0.3.0/tutorial/configuration"},next:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.3.0/detectors"}},l={},a=[{value:"Getting started",id:"getting-started",level:2},{value:"Resources",id:"resources",level:2}];function u(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"using-misti-with-blueprint",children:"Using Misti with Blueprint"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:"https://github.com/ton-org/blueprint",children:"Blueprint"})," is a development environment for writing, testing, and deploying TON smart contracts."]}),"\n",(0,i.jsxs)(e.p,{children:["Misti can be used in Blueprint projects by leveraging the ",(0,i.jsx)(e.a,{href:"https://github.com/nowarp/blueprint-misti",children:(0,i.jsx)(e.code,{children:"blueprint-misti"})})," plugin."]}),"\n",(0,i.jsx)(e.h2,{id:"getting-started",children:"Getting started"}),"\n",(0,i.jsxs)(e.p,{children:["Add the plugin and the recent version of Tact to the ",(0,i.jsx)(e.code,{children:"package.json"})," of your Blueprint project by running:"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn add @tact-lang/compiler\nyarn add @nowarp/blueprint-misti\n"})}),"\n",(0,i.jsxs)(e.p,{children:["Then, add this configuration to ",(0,i.jsx)(e.code,{children:"blueprint.config.ts"}),":"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",children:"import { MistiPlugin } from '@nowarp/blueprint-misti';\nexport const config = {\n plugins: [\n new MistiPlugin(),\n ],\n};\n"})}),"\n",(0,i.jsx)(e.p,{children:"Now, try to run Misti:"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn blueprint misti ./path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(e.h2,{id:"resources",children:"Resources"}),"\n",(0,i.jsxs)(e.p,{children:["For more information, please refer to the README of the ",(0,i.jsx)(e.a,{href:"https://github.com/nowarp/blueprint-misti",children:(0,i.jsx)(e.code,{children:"blueprint-misti"})})," project. If you have any problems, feel free to reach out to us in the ",(0,i.jsx)(e.a,{href:"https://t.me/misti_dev",children:"Misti discussion group"}),"."]})]})}function d(t={}){const{wrapper:e}={...(0,r.R)(),...t.components};return e?(0,i.jsx)(e,{...t,children:(0,i.jsx)(u,{...t})}):u(t)}},8453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>c});var i=n(6540);const r={},s=i.createContext(r);function o(t){const e=i.useContext(s);return i.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function c(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),i.createElement(s.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/2237.92070aeb.js b/assets/js/2237.92070aeb.js new file mode 100644 index 000000000..6bd597aab --- /dev/null +++ b/assets/js/2237.92070aeb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2237],{3363:(e,t,i)=>{i.d(t,{A:()=>a});i(6540);var n=i(4164),o=i(1312),s=i(1107),r=i(4848);function a(e){let{className:t}=e;return(0,r.jsx)("main",{className:(0,n.A)("container margin-vert--xl",t),children:(0,r.jsx)("div",{className:"row",children:(0,r.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,r.jsx)(s.A,{as:"h1",className:"hero__title",children:(0,r.jsx)(o.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,r.jsx)("p",{children:(0,r.jsx)(o.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,r.jsx)("p",{children:(0,r.jsx)(o.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}},2237:(e,t,i)=>{i.r(t),i.d(t,{default:()=>h});i(6540);var n=i(1312),o=i(1003),s=i(781),r=i(3363),a=i(4848);function h(){const e=(0,n.T)({id:"theme.NotFound.title",message:"Page Not Found"});return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(o.be,{title:e}),(0,a.jsx)(s.A,{children:(0,a.jsx)(r.A,{})})]})}}}]); \ No newline at end of file diff --git a/assets/js/2257d06b.a740c88e.js b/assets/js/2257d06b.a740c88e.js new file mode 100644 index 000000000..9bca7c522 --- /dev/null +++ b/assets/js/2257d06b.a740c88e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1687],{111:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>n,metadata:()=>c,toc:()=>l});var s=r(4848),i=r(8453);const n={id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},o="Detectors Overview",c={id:"detectors",title:"Detectors Overview",description:"Here's a list of all the detectors:",source:"@site/versioned_docs/version-0.2.1/detectors.md",sourceDirName:".",slug:"/detectors",permalink:"/tools/misti/docs/0.2.1/detectors",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors.md",tags:[],version:"0.2.1",frontMatter:{id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/tools/misti/docs/0.2.1/tutorial/configuration"},next:{title:"Divide before Multiply",permalink:"/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply"}},d={},l=[];function a(e){const t={a:"a",code:"code",h1:"h1",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"detectors-overview",children:"Detectors Overview"}),"\n",(0,s.jsx)(t.p,{children:"Here's a list of all the detectors:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/DivideBeforeMultiply",children:"Divide before Multiply"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/NeverAccessedVariables",children:"Never-accessed Variables"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/ReadOnlyVariables",children:"Read-only Variables"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/UnboundLoops",children:"Unbound Loops"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/ZeroAddress",children:"Zero Address"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/ConstantAddress",children:"Constant Address"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/BranchDuplicate",children:"Branch Duplicate"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsxs)(t.a,{href:"./detectors/DumpIsUsed",children:[(0,s.jsx)(t.code,{children:"dump"})," Is Used"]})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/FieldDoubleInit",children:"Field Initialized Twice"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/PreferAugmentedAssign",children:"Prefer Augmented Assignment"})}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"Each detector is designed to catch specific issues in your code. Click on any of them to learn more."})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},8453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>c});var s=r(6540);const i={},n=s.createContext(i);function o(e){const t=s.useContext(n);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(n.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/23b0c962.e0d7957b.js b/assets/js/23b0c962.e0d7957b.js new file mode 100644 index 000000000..ff5315913 --- /dev/null +++ b/assets/js/23b0c962.e0d7957b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6784],{7838:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>l,metadata:()=>r,toc:()=>d});var t=i(4848),s=i(8453);const l={},o="Command-Line Interface",r={id:"tutorial/cli",title:"Command-Line Interface",description:"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.",source:"@site/docs/tutorial/cli.md",sourceDirName:"tutorial",slug:"/tutorial/cli",permalink:"/tools/misti/docs/next/tutorial/cli",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tutorial/cli.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"CI/CD Integration",permalink:"/tools/misti/docs/next/tutorial/ci-cd"},next:{title:"Configuration",permalink:"/tools/misti/docs/next/tutorial/configuration"}},c={},d=[{value:"-t, --tools <className[:key=value...]>",id:"-t---tools-classnamekeyvalue",level:3},{value:"--output-path <PATH>",id:"--output-path-path",level:3},{value:"--list-tools",id:"--list-tools",level:3},{value:"-o, --output-format <json|plain>",id:"-o---output-format-jsonplain",level:3},{value:"-C, --no-colors",id:"-c---no-colors",level:3},{value:"--souffle-binary <PATH>",id:"--souffle-binary-path",level:3},{value:"--souffle-path <PATH>",id:"--souffle-path-path",level:3},{value:"--souffle-verbose",id:"--souffle-verbose",level:3},{value:"--tact-stdlib-path <PATH>",id:"--tact-stdlib-path-path",level:3},{value:"-v, --verbose",id:"-v---verbose",level:3},{value:"-q, --quiet",id:"-q---quiet",level:3},{value:"-m, --min-severity <info|low|medium|high|critical>",id:"-m---min-severity-infolowmediumhighcritical",level:3},{value:"-de, --enabled-detectors <name|path:name>",id:"-de---enabled-detectors-namepathname",level:3},{value:"-dd, --disabled-detectors <names>",id:"-dd---disabled-detectors-names",level:3},{value:"-A, --all-detectors",id:"-a---all-detectors",level:3},{value:"-c, --config <PATH>",id:"-c---config-path",level:3},{value:"--new-detector <PATH>",id:"--new-detector-path",level:3}];function a(e){const n={code:"code",h1:"h1",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"command-line-interface",children:"Command-Line Interface"}),"\n",(0,t.jsx)(n.p,{children:"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each."}),"\n",(0,t.jsx)(n.h3,{id:"-t---tools-classnamekeyvalue",children:(0,t.jsx)(n.code,{children:"-t, --tools "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Specifies a tool to enable with optional configuration. This option can be used multiple times."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Example"}),": ",(0,t.jsx)(n.code,{children:'-t "DumpCfg:format=dot"'})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"--output-path-path",children:(0,t.jsx)(n.code,{children:"--output-path "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Specifies the directory to save warnings or output generated by tools. If ",(0,t.jsx)(n.code,{children:""})," is ",(0,t.jsx)(n.code,{children:"-"}),", then the output is sent to stdout."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"-"})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"--list-tools",children:(0,t.jsx)(n.code,{children:"--list-tools"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Lists available tools and their configuration options."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"-o---output-format-jsonplain",children:(0,t.jsx)(n.code,{children:"-o, --output-format "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Sets the output format for all tools and warnings (either JSON or plain text)."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"plain"})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"-c---no-colors",children:(0,t.jsx)(n.code,{children:"-C, --no-colors"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Disables ANSI colors in the output."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"--souffle-binary-path",children:(0,t.jsx)(n.code,{children:"--souffle-binary "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Specifies the path to the Souffl\xe9 binary."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:'"souffle"'})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"--souffle-path-path",children:(0,t.jsx)(n.code,{children:"--souffle-path "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Specifies the directory to save generated Souffl\xe9 files."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:'"/tmp/misti/souffle"'})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"--souffle-verbose",children:(0,t.jsx)(n.code,{children:"--souffle-verbose"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Generates human-readable, more verbose Souffl\xe9 files."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"--tact-stdlib-path-path",children:(0,t.jsx)(n.code,{children:"--tact-stdlib-path "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Specifies the path to the Tact standard library."]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"-v---verbose",children:(0,t.jsx)(n.code,{children:"-v, --verbose"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Enables verbose output."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"-q---quiet",children:(0,t.jsx)(n.code,{children:"-q, --quiet"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Suppresses all output."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"-m---min-severity-infolowmediumhighcritical",children:(0,t.jsx)(n.code,{children:"-m, --min-severity "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Sets the minimum level of severity to report."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"info"})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"-de---enabled-detectors-namepathname",children:(0,t.jsx)(n.code,{children:"-de, --enabled-detectors "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": A comma-separated list of detectors to enable."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Argument Validation"}),": Requires a non-empty list of detector names."]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"-dd---disabled-detectors-names",children:(0,t.jsx)(n.code,{children:"-dd, --disabled-detectors "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": A comma-separated list of detector names to disable."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Argument Validation"}),": Requires a non-empty list of detector names."]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"-a---all-detectors",children:(0,t.jsx)(n.code,{children:"-A, --all-detectors"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Enables all available built-in detectors."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"-c---config-path",children:(0,t.jsx)(n.code,{children:"-c, --config "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Specifies the path to the Misti configuration file."]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"--new-detector-path",children:(0,t.jsx)(n.code,{children:"--new-detector "})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Description"}),": Creates a new custom detector at the specified path."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Default"}),": ",(0,t.jsx)(n.code,{children:"undefined"})]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(a,{...e})}):a(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>o,x:()=>r});var t=i(6540);const s={},l=t.createContext(s);function o(e){const n=t.useContext(l);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),t.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2424092d.88efacf6.js b/assets/js/2424092d.88efacf6.js new file mode 100644 index 000000000..e876b937e --- /dev/null +++ b/assets/js/2424092d.88efacf6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[420],{512:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var a=t(4848),i=t(8453);const r={},s="Read-only Variables",o={id:"detectors/ReadOnlyVariables",title:"Read-only Variables",description:"A detector that identifies read-only variables and fields.",source:"@site/versioned_docs/version-0.2.0/detectors/ReadOnlyVariables.md",sourceDirName:"detectors",slug:"/detectors/ReadOnlyVariables",permalink:"/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/ReadOnlyVariables.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Never-accessed Variables",permalink:"/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables"},next:{title:"Unbound Loops",permalink:"/tools/misti/docs/0.2.0/detectors/UnboundLoops"}},l={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.h1,{id:"read-only-variables",children:"Read-only Variables"}),"\n",(0,a.jsx)(n.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,a.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,a.jsx)(n.p,{children:"These variables could typically be replaced with constants to optimize performance.\nAlternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally."}),"\n",(0,a.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-tact",children:"fun calculateFinalPrice(price: Int): Int {\n // Warning: the developer uses a read-only variable that could be a constant\n let DISCOUNT_AMOUNT: Int = 10;\n return price - DISCOUNT_AMOUNT;\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:"Use instead:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-tact",children:"const DISCOUNT_AMOUNT: Int = 10;\n\nfun calculateFinalPrice(price: Int): Int {\n // OK: Fixed after the linter highlighted this warning\n return price - DISCOUNT_AMOUNT;\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>o});var a=t(6540);const i={},r=a.createContext(i);function s(e){const n=a.useContext(r);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),a.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/24652b08.91ed48d5.js b/assets/js/24652b08.91ed48d5.js new file mode 100644 index 000000000..868031702 --- /dev/null +++ b/assets/js/24652b08.91ed48d5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7406],{2208:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>a});var n=s(4848),i=s(8453);const o={},d="dump Is Used",r={id:"detectors/DumpIsUsed",title:"dump Is Used",description:"An optional detector that highlights all the dump function calls.",source:"@site/versioned_docs/version-0.2.0/detectors/DumpIsUsed.md",sourceDirName:"detectors",slug:"/detectors/DumpIsUsed",permalink:"/tools/misti/docs/0.2.0/detectors/DumpIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/DumpIsUsed.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Branch Duplicate",permalink:"/tools/misti/docs/0.2.0/detectors/BranchDuplicate"},next:{title:"Field Initialized Twice",permalink:"/tools/misti/docs/0.2.0/detectors/FieldDoubleInit"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(t.h1,{id:"dump-is-used",children:[(0,n.jsx)(t.code,{children:"dump"})," Is Used"]}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"dump"})," function calls."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"dump"})," function is a debug print that shouldn't be in the final code. Even though the compiler removes it in production, its presence suggests the developer was debugging something. This can flag areas where issues might exist, so auditors should take a closer look at these parts of the code."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = (RANDOM_SEED >> half_shift) &\n (MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;\n dump(combined); // Suspicious: Highlighted by the detector\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = this.seed ^ shift_mask\n // OK: The code was reviewed and simplified; `dump` was removed\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>d,x:()=>r});var n=s(6540);const i={},o=n.createContext(i);function d(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/26592ea2.2dd4e9ca.js b/assets/js/26592ea2.2dd4e9ca.js new file mode 100644 index 000000000..cb464b26a --- /dev/null +++ b/assets/js/26592ea2.2dd4e9ca.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3543],{3178:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>r,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>l,toc:()=>d});var n=i(4848),o=i(8453);const s={},a="FieldDoubleInit",l={id:"detectors/FieldDoubleInit",title:"FieldDoubleInit",description:"A detector that highlights cases where a field is initialized both in the",source:"@site/docs/detectors/FieldDoubleInit.md",sourceDirName:"detectors",slug:"/detectors/FieldDoubleInit",permalink:"/tools/misti/docs/next/detectors/FieldDoubleInit",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/FieldDoubleInit.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"FalseCondition",permalink:"/tools/misti/docs/next/detectors/FalseCondition"},next:{title:"InheritedStateMutation",permalink:"/tools/misti/docs/next/detectors/InheritedStateMutation"}},r={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"fielddoubleinit",children:"FieldDoubleInit"}),"\n",(0,n.jsxs)(t.p,{children:["A detector that highlights cases where a field is initialized both in the\n",(0,n.jsx)(t.code,{children:"init"})," function and at the point of definition."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["Double initialization of fields can either be a programmer's mistake or simply\na waste of gas. It is always preferred to initialize values in the field declaration\nif they have a compile-time evaluatable default value, or in the ",(0,n.jsx)(t.code,{children:"init"})," function if\nthey must be initialized dynamically."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int = 0; // Bad\n init(x: Int) { self.a = x }\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int; // Fixed\n init(x: Int) { self.a = x }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>a,x:()=>l});var n=i(6540);const o={},s=n.createContext(o);function a(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/273168fb.26adb4b1.js b/assets/js/273168fb.26adb4b1.js new file mode 100644 index 000000000..046a2f156 --- /dev/null +++ b/assets/js/273168fb.26adb4b1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1492],{7079:(t,e,i)=>{i.r(e),i.d(e,{assets:()=>l,contentTitle:()=>o,default:()=>c,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var n=i(4848),s=i(8453);const r={},o="Getting started",a={id:"tutorial/getting-started",title:"Getting started",description:"This guide will walk you through the steps to install and set up the Misti static analyzer.",source:"@site/versioned_docs/version-0.1.2/tutorial/getting-started.md",sourceDirName:"tutorial",slug:"/tutorial/getting-started",permalink:"/tools/misti/docs/0.1.2/tutorial/getting-started",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/tutorial/getting-started.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Introduction",permalink:"/tools/misti/docs/0.1.2/"},next:{title:"Configuration",permalink:"/tools/misti/docs/0.1.2/tutorial/configuration"}},l={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Running the analysis",id:"running-the-analysis",level:2},{value:"Troubleshooting",id:"troubleshooting",level:2}];function u(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...t.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,n.jsx)(e.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,n.jsx)(e.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,n.jsx)(e.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsx)(e.li,{children:"Git"}),"\n",(0,n.jsx)(e.li,{children:"Yarn"}),"\n",(0,n.jsx)(e.li,{children:"Node.js"}),"\n",(0,n.jsx)(e.li,{children:(0,n.jsx)(e.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,n.jsx)(e.h2,{id:"installation",children:"Installation"}),"\n",(0,n.jsxs)(e.p,{children:["Misti is distributed via npm and should be added to your Tact project ",(0,n.jsx)(e.a,{href:"https://github.com/tact-lang/tact?tab=readme-ov-file#installation",children:"in the same way"})," as Tact itself:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"yarn add @nowarp/misti\n"})}),"\n",(0,n.jsx)(e.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,n.jsx)(e.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:"npx misti test/projects/simple/tactConfig.json\n"})}),"\n",(0,n.jsx)(e.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,n.jsx)(e.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,n.jsxs)(e.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,n.jsx)(e.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,n.jsx)(e.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function c(t={}){const{wrapper:e}={...(0,s.R)(),...t.components};return e?(0,n.jsx)(e,{...t,children:(0,n.jsx)(u,{...t})}):u(t)}},8453:(t,e,i)=>{i.d(e,{R:()=>o,x:()=>a});var n=i(6540);const s={},r=n.createContext(s);function o(t){const e=n.useContext(r);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function a(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(s):t.components||s:o(t.components),n.createElement(r.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/299f32b1.3d9263b4.js b/assets/js/299f32b1.3d9263b4.js new file mode 100644 index 000000000..1dc9a530e --- /dev/null +++ b/assets/js/299f32b1.3d9263b4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[853],{1665:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>d});var o=t(4848),s=t(8453);const i={},r="UnboundLoops",a={id:"detectors/UnboundLoops",title:"UnboundLoops",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/docs/detectors/UnboundLoops.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoops",permalink:"/tools/misti/docs/next/detectors/UnboundLoops",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/UnboundLoops.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/next/detectors/StringReceiversOverlap"},next:{title:"UnusedOptional",permalink:"/tools/misti/docs/next/detectors/UnusedOptional"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"unboundloops",children:"UnboundLoops"}),"\n",(0,o.jsx)(n.p,{children:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria."}),"\n",(0,o.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsx)(n.p,{children:"An unbounded loop can be problematic for several reasons:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Unexpected Behavior:"})," Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Out-of-gas Attacks:"})," Continuous looping without termination can lead to out-of-gas attacks."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"DoS Attacks:"})," Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability."]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n // Bad: x is not changed due looping\n send(SendParameters{ to: sender(), ... });\n}\n"})}),"\n",(0,o.jsx)(n.p,{children:"Use instead:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n send(SendParameters{ to: sender(), ... });\n x = x - 1;\n}\n"})})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var o=t(6540);const s={},i=o.createContext(s);function r(e){const n=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2aa59687.16070803.js b/assets/js/2aa59687.16070803.js new file mode 100644 index 000000000..a18b73e9c --- /dev/null +++ b/assets/js/2aa59687.16070803.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3196],{542:(t,n,e)=>{e.r(n),e.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>u});var i=e(4848),o=e(8453);const s={},r="Integrating Misti into CI/CD",c={id:"tutorial/ci-cd",title:"Integrating Misti into CI/CD",description:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.",source:"@site/versioned_docs/version-0.3.1/tutorial/ci-cd.md",sourceDirName:"tutorial",slug:"/tutorial/ci-cd",permalink:"/tools/misti/docs/0.3.1/tutorial/ci-cd",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/tutorial/ci-cd.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Getting Started",permalink:"/tools/misti/docs/0.3.1/tutorial/getting-started"},next:{title:"Command-Line Interface",permalink:"/tools/misti/docs/0.3.1/tutorial/cli"}},a={},u=[{value:"GitHub Actions",id:"github-actions",level:2}];function l(t){const n={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,o.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"integrating-misti-into-cicd",children:"Integrating Misti into CI/CD"}),"\n",(0,i.jsx)(n.p,{children:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle."}),"\n",(0,i.jsx)(n.h2,{id:"github-actions",children:"GitHub Actions"}),"\n",(0,i.jsx)(n.p,{children:"To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"1. Open your GitHub repository"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"2. Create or edit the GitHub Actions workflow YAML file"})}),"\n",(0,i.jsxs)(n.p,{children:["It could be located at e.g., ",(0,i.jsx)(n.code,{children:".github/workflows/main.yml"}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"3. Add the step to run Misti to your YAML file"})}),"\n",(0,i.jsx)(n.p,{children:"For example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"name: Run Misti\non: [push, pull_request]\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v2\n\n - name: Install dependencies\n run: npm install\n\n - name: Run Misti\n run: npx misti /path/to/your/tact.config.json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"npx misti /path/to/your/tact.config.json"})," command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"4. Adjusting the Misti Configuration"})}),"\n",(0,i.jsxs)(n.p,{children:["If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the ",(0,i.jsx)(n.a,{href:"./configuration",children:"Configuration"})," section for more details on how to customize your settings."]})]})}function d(t={}){const{wrapper:n}={...(0,o.R)(),...t.components};return n?(0,i.jsx)(n,{...t,children:(0,i.jsx)(l,{...t})}):l(t)}},8453:(t,n,e)=>{e.d(n,{R:()=>r,x:()=>c});var i=e(6540);const o={},s=i.createContext(o);function r(t){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof t?t(n):{...n,...t}}),[n,t])}function c(t){let n;return n=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:r(t.components),i.createElement(s.Provider,{value:n},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/2ace25e9.6114563d.js b/assets/js/2ace25e9.6114563d.js new file mode 100644 index 000000000..ea94eb586 --- /dev/null +++ b/assets/js/2ace25e9.6114563d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4013],{5111:(i,e,t)=>{t.r(e),t.d(e,{assets:()=>o,contentTitle:()=>I,default:()=>c,frontMatter:()=>l,metadata:()=>d,toc:()=>g});var n=t(4848),s=t(8453);const l={},I="Tools Guide",d={id:"hacking/tools",title:"Tools Guide",description:"This page describes the internal analyzer tools available in Misti to aid in development and debugging.",source:"@site/versioned_docs/version-0.2.1/hacking/tools.md",sourceDirName:"hacking",slug:"/hacking/tools",permalink:"/tools/misti/docs/0.2.1/hacking/tools",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/hacking/tools.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.2.1/hacking/souffle"},next:{title:"Custom Detectors",permalink:"/tools/misti/docs/0.2.1/hacking/custom-detector"}},o={},g=[{value:"CFG Dump",id:"cfg-dump",level:2},{value:"Usage",id:"usage",level:3},{value:"Converting DOT to SVG",id:"converting-dot-to-svg",level:3},{value:"Viewing the SVG",id:"viewing-the-svg",level:3},{value:"VS Code Plugin",id:"vs-code-plugin",level:3},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function a(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"tools-guide",children:"Tools Guide"}),"\n",(0,n.jsx)(e.p,{children:"This page describes the internal analyzer tools available in Misti to aid in development and debugging."}),"\n",(0,n.jsx)(e.h2,{id:"cfg-dump",children:"CFG Dump"}),"\n",(0,n.jsx)(e.p,{children:"Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts."}),"\n",(0,n.jsx)(e.h3,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in JSON format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="json" \n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in DOT format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" \n'})}),"\n",(0,n.jsx)(e.h3,{id:"converting-dot-to-svg",children:"Converting DOT to SVG"}),"\n",(0,n.jsxs)(e.p,{children:["To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use ",(0,n.jsx)(e.a,{href:"https://graphviz.org",children:"Graphviz"})," with the following command:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" > output.dot\ndot -Tsvg output.dot -o output.svg\n'})}),"\n",(0,n.jsx)(e.h3,{id:"viewing-the-svg",children:"Viewing the SVG"}),"\n",(0,n.jsx)(e.p,{children:"To view the SVG file in Firefox, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"firefox output.svg\n"})}),"\n",(0,n.jsx)(e.p,{children:"For example, for the following contract:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:"fun test(): Int {\n let sum: Int = 0;\n let i: Int = 0;\n repeat (10) {\n i = i + 1;\n sum = sum + i;\n }\n return sum;\n}\n"})}),"\n",(0,n.jsx)(e.p,{children:"The following CFG will be generated:"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"CFG Example",src:t(685).A+"",width:"337",height:"516"})}),"\n",(0,n.jsx)(e.h3,{id:"vs-code-plugin",children:"VS Code Plugin"}),"\n",(0,n.jsxs)(e.p,{children:["For real-time visualization of DOT files, you can use ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/search?term=tag%3Agraphviz&target=VSCode&category=All%20categories&sortBy=Relevance",children:"one of the available"})," Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development."]}),"\n",(0,n.jsx)(e.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"JSON Dumps"}),": These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"DOT Dumps"}),": These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(e.p,{children:"By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors."})]})}function c(i={}){const{wrapper:e}={...(0,s.R)(),...i.components};return e?(0,n.jsx)(e,{...i,children:(0,n.jsx)(a,{...i})}):a(i)}},685:(i,e,t)=>{t.d(e,{A:()=>n});const n="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDIuNCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBsb29wcyYjNDU7MyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjUzcHQiIGhlaWdodD0iMzg3cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjUzLjAwIDM4Ny4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzODMpIj4KPHRpdGxlPmxvb3BzJiM0NTszPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzgzIDI0OSwtMzgzIDI0OSw0IC00LDQiLz4KPGcgaWQ9ImNsdXN0MSIgY2xhc3M9ImNsdXN0ZXIiPgo8dGl0bGU+Y2x1c3Rlcl90ZXN0PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI4LC04IDgsLTM3MSAyMzcsLTM3MSAyMzcsLTggOCwtOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIuNSIgeT0iLTM1NS44IiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnRlc3Q8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0MSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT50ZXN0XzE0MTwvdGl0bGU+Cjxwb2x5Z29uIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjI0LjUsLTM0MCA5NS41LC0zNDAgOTUuNSwtMzA0IDIyNC41LC0zMDQgMjI0LjUsLTM0MCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNjAiIHk9Ii0zMTguMyIgZm9udC1mYW1pbHk9IlRpbWVzLHNlcmlmIiBmb250LXNpemU9IjE0LjAwIj5sZXQgc3VtOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDI8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMiwtMjY4IDEwOCwtMjY4IDEwOCwtMjMyIDIxMiwtMjMyIDIxMiwtMjY4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTI0Ni4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPmxldCBpOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDEmIzQ1OyZndDt0ZXN0XzE0MiAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MSYjNDU7Jmd0O3Rlc3RfMTQyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMzAzLjdDMTYwLC0yOTUuOTggMTYwLC0yODYuNzEgMTYwLC0yNzguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTI3OC4xIDE2MCwtMjY4LjEgMTU2LjUsLTI3OC4xIDE2My41LC0yNzguMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDQ8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOCwtMTk2IDExMiwtMTk2IDExMiwtMTYwIDIwOCwtMTYwIDIwOCwtMTk2Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTE3NC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnJlcGVhdCAoMTApPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDImIzQ1OyZndDt0ZXN0XzE0NCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MiYjNDU7Jmd0O3Rlc3RfMTQ0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMjMxLjdDMTYwLC0yMjMuOTggMTYwLC0yMTQuNzEgMTYwLC0yMDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTIwNi4xIDE2MCwtMTk2LjEgMTU2LjUsLTIwNi4xIDE2My41LC0yMDYuMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDYgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDY8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjkzLjUsLTEyNCAxNi41LC0xMjQgMTYuNSwtODggOTMuNSwtODggOTMuNSwtMTI0Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjU1IiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+aSA9IGkgKyAxPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE0NiAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0NCYjNDU7Jmd0O3Rlc3RfMTQ2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEzNC4zMSwtMTU5Ljg4QzEyMC43MSwtMTUwLjgxIDEwMy44MywtMTM5LjU1IDg5LjE0LC0xMjkuNzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iOTEuMDUsLTEyNi44MiA4MC43OCwtMTI0LjE5IDg3LjE2LC0xMzIuNjUgOTEuMDUsLTEyNi44MiIvPgo8L2c+CjwhLS0gdGVzdF8xNTEgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNTE8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjNjZhN2RiIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOC41LC0xMjQgMTExLjUsLTEyNCAxMTEuNSwtODggMjA4LjUsLTg4IDIwOC41LC0xMjQiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTYwIiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+cmV0dXJuIHN1bTwvdGV4dD4KPC9nPgo8IS0tIHRlc3RfMTQ0JiM0NTsmZ3Q7dGVzdF8xNTEgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE1MTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNjAsLTE1OS43QzE2MCwtMTUxLjk4IDE2MCwtMTQyLjcxIDE2MCwtMTM0LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2My41LC0xMzQuMSAxNjAsLTEyNC4xIDE1Ni41LC0xMzQuMSAxNjMuNSwtMTM0LjEiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPnRlc3RfMTQ4PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxODMuNSwtNTIgNjAuNSwtNTIgNjAuNSwtMTYgMTgzLjUsLTE2IDE4My41LC01MiIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIiIHk9Ii0zMC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnN1bSA9IHN1bSArIGk8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0NiYjNDU7Jmd0O3Rlc3RfMTQ4IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPnRlc3RfMTQ2JiM0NTsmZ3Q7dGVzdF8xNDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuNTYsLTg3LjdDNzkuNjgsLTc5LjIyIDg5LjU5LC02OC44NiA5OC40NywtNTkuNTgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAxLjI0LC02MS43NSAxMDUuNjMsLTUyLjEgOTYuMTksLTU2LjkxIDEwMS4yNCwtNjEuNzUiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4JiM0NTsmZ3Q7dGVzdF8xNDQgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDgmIzQ1OyZndDt0ZXN0XzE0NDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzUuMjIsLTUyLjA0QzE5MS44OSwtNjAuMTYgMjA4LjQyLC03MS43NyAyMTgsLTg4IDIyNi4xMywtMTAxLjc4IDIyNC40NSwtMTA5LjM2IDIxOCwtMTI0IDIxMy4wMSwtMTM1LjMxIDIwNC4yOSwtMTQ1LjI2IDE5NS4xLC0xNTMuMzgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTkyLjgzLC0xNTAuNzIgMTg3LjM0LC0xNTkuNzcgMTk3LjI4LC0xNTYuMTIgMTkyLjgzLC0xNTAuNzIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8453:(i,e,t)=>{t.d(e,{R:()=>I,x:()=>d});var n=t(6540);const s={},l=n.createContext(s);function I(i){const e=n.useContext(l);return n.useMemo((function(){return"function"==typeof i?i(e):{...e,...i}}),[e,i])}function d(i){let e;return e=i.disableParentContext?"function"==typeof i.components?i.components(s):i.components||s:I(i.components),n.createElement(l.Provider,{value:e},i.children)}}}]); \ No newline at end of file diff --git a/assets/js/2b6a80d0.3d7eb50f.js b/assets/js/2b6a80d0.3d7eb50f.js new file mode 100644 index 000000000..9fad723ec --- /dev/null +++ b/assets/js/2b6a80d0.3d7eb50f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1084],{3646:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>d,default:()=>u,frontMatter:()=>o,metadata:()=>r,toc:()=>a});var n=s(4848),i=s(8453);const o={},d="DumpIsUsed",r={id:"detectors/DumpIsUsed",title:"DumpIsUsed",description:"An optional detector that highlights all the dump debug prints.",source:"@site/docs/detectors/DumpIsUsed.md",sourceDirName:"detectors",slug:"/detectors/DumpIsUsed",permalink:"/tools/misti/docs/next/detectors/DumpIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/DumpIsUsed.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"DivideBeforeMultiply",permalink:"/tools/misti/docs/next/detectors/DivideBeforeMultiply"},next:{title:"DuplicatedCondition",permalink:"/tools/misti/docs/next/detectors/DuplicatedCondition"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"dumpisused",children:"DumpIsUsed"}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"dump"})," debug prints."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"dump"})," function is a debug print that shouldn't be in the final code.\nEven though the compiler removes it in production, its presence suggests the\ndeveloper was debugging something. This can flag areas where issues might exist,\nso auditors should take a closer look at these parts of the code."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = (RANDOM_SEED >> half_shift) &\n (MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;\n dump(combined); // Suspicious: Highlighted by the detector\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = this.seed ^ shift_mask\n // OK: The code was reviewed and simplified; `dump` was removed\n}\n"})})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>d,x:()=>r});var n=s(6540);const i={},o=n.createContext(i);function d(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2b785902.b83e29b9.js b/assets/js/2b785902.b83e29b9.js new file mode 100644 index 000000000..a4a8c416d --- /dev/null +++ b/assets/js/2b785902.b83e29b9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4806],{2814:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>h,frontMatter:()=>n,metadata:()=>r,toc:()=>a});var o=s(4848),i=s(8453);const n={id:"tools",title:"Tools Overview"},l="Tools Overview",r={id:"tools",title:"Tools Overview",description:"Misti Tools are additional modules designed to work alongside detectors, enabling various tasks beyond code analysis.",source:"@site/docs/tools.md",sourceDirName:".",slug:"/tools",permalink:"/tools/misti/docs/next/tools",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tools.md",tags:[],version:"current",frontMatter:{id:"tools",title:"Tools Overview"},sidebar:"sidebar",previous:{title:"ZeroAddress",permalink:"/tools/misti/docs/next/detectors/ZeroAddress"},next:{title:"DumpAst",permalink:"/tools/misti/docs/next/tools/DumpAst"}},d={},a=[{value:"Usage",id:"usage",level:2},{value:"Usage Examples",id:"usage-examples",level:2},{value:"Available Tools",id:"available-tools",level:2}];function c(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h1,{id:"tools-overview",children:"Tools Overview"}),"\n",(0,o.jsx)(t.p,{children:"Misti Tools are additional modules designed to work alongside detectors, enabling various tasks beyond code analysis."}),"\n",(0,o.jsx)(t.p,{children:"These tools are particularly useful for auditors, providing additional functionalities to assist in manual code reviews."}),"\n",(0,o.jsx)(t.h2,{id:"usage",children:"Usage"}),"\n",(0,o.jsx)(t.p,{children:"List available tools and their options:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-bash",children:"npx misti --list-tools\n"})}),"\n",(0,o.jsx)(t.p,{children:"To invoke a specific tool, use the following command format:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-bash",children:'npx misti -t "ToolName:option=value,option=value" /path/to/tact.config.json\n'})}),"\n",(0,o.jsx)(t.h2,{id:"usage-examples",children:"Usage Examples"}),"\n",(0,o.jsx)(t.p,{children:"Dump the AST of the project:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{children:'npx misti -t "DumpAst" my-example.tact\n'})}),"\n",(0,o.jsxs)(t.p,{children:["Dump the CFGs of the project in ",(0,o.jsx)(t.a,{href:"https://mermaid.live",children:"Mermaid"})," format to the file ",(0,o.jsx)(t.code,{children:"/tmp/my-example.DumpCfg.out"}),":"]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{children:'npx misti --output-path "/tmp" -t "DumpCfg:format=mermaid" my-example.tact\n'})}),"\n",(0,o.jsx)(t.h2,{id:"available-tools",children:"Available Tools"}),"\n",(0,o.jsx)(t.p,{children:"Below is the complete list of built-in tools. Click on any of them to learn more."}),"\n",(0,o.jsxs)(t.table,{children:[(0,o.jsx)(t.thead,{children:(0,o.jsxs)(t.tr,{children:[(0,o.jsx)(t.th,{children:"#"}),(0,o.jsx)(t.th,{children:"Tool"}),(0,o.jsx)(t.th,{children:"Description"})]})}),(0,o.jsxs)(t.tbody,{children:[(0,o.jsxs)(t.tr,{children:[(0,o.jsx)(t.td,{children:"1"}),(0,o.jsx)(t.td,{children:(0,o.jsx)(t.a,{href:"/tools/misti/docs/next/tools/DumpAst",children:"DumpAst"})}),(0,o.jsx)(t.td,{children:"Dumps the AST of project modules"})]}),(0,o.jsxs)(t.tr,{children:[(0,o.jsx)(t.td,{children:"2"}),(0,o.jsx)(t.td,{children:(0,o.jsx)(t.a,{href:"/tools/misti/docs/next/tools/DumpCfg",children:"DumpCfg"})}),(0,o.jsx)(t.td,{children:"Dumps the CFG of project modules"})]}),(0,o.jsxs)(t.tr,{children:[(0,o.jsx)(t.td,{children:"3"}),(0,o.jsx)(t.td,{children:(0,o.jsx)(t.a,{href:"/tools/misti/docs/next/tools/DumpConfig",children:"DumpConfig"})}),(0,o.jsx)(t.td,{children:"Dumps the Misti configuration file in use"})]})]})]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(c,{...e})}):c(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>l,x:()=>r});var o=s(6540);const i={},n=o.createContext(i);function l(e){const t=o.useContext(n);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),o.createElement(n.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2bdf0f82.11a0dcc1.js b/assets/js/2bdf0f82.11a0dcc1.js new file mode 100644 index 000000000..21a90eeb5 --- /dev/null +++ b/assets/js/2bdf0f82.11a0dcc1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[321],{3842:(e,n,d)=>{d.r(n),d.d(n,{assets:()=>r,contentTitle:()=>s,default:()=>h,frontMatter:()=>l,metadata:()=>a,toc:()=>o});var i=d(4848),t=d(8453);const l={},s="Changelog",a={id:"hacking/CHANGELOG",title:"Changelog",description:"All notable changes to this project are documented in this file.",source:"@site/versioned_docs/version-0.1.2/hacking/CHANGELOG.md",sourceDirName:"hacking",slug:"/hacking/CHANGELOG",permalink:"/tools/misti/docs/0.1.2/hacking/CHANGELOG",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/hacking/CHANGELOG.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Custom Detectors",permalink:"/tools/misti/docs/0.1.2/hacking/custom-detector"}},r={},o=[{value:"[0.1.2] - 2024-08-06",id:"012---2024-08-06",level:2},{value:"Added",id:"added",level:3},{value:"Changed",id:"changed",level:3},{value:"Fixed",id:"fixed",level:3},{value:"[0.1.1] - 2024-08-06",id:"011---2024-08-06",level:2},{value:"Added",id:"added-1",level:3},{value:"Changed",id:"changed-1",level:3},{value:"Fixed",id:"fixed-1",level:3},{value:"[0.1.0] - 2024-08-06",id:"010---2024-08-06",level:2},{value:"Added",id:"added-2",level:3}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",ul:"ul",...(0,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"changelog",children:"Changelog"}),"\n",(0,i.jsx)(n.p,{children:"All notable changes to this project are documented in this file."}),"\n",(0,i.jsxs)(n.p,{children:["The format is based on ",(0,i.jsx)(n.a,{href:"https://keepachangelog.com/en/1.0.0/",children:"Keep a Changelog"}),",\nand this project adheres to ",(0,i.jsx)(n.a,{href:"https://semver.org/spec/v2.0.0.html",children:"Semantic Versioning"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"012---2024-08-06",children:"[0.1.2] - 2024-08-06"}),"\n",(0,i.jsx)(n.h3,{id:"added",children:"Added"}),"\n",(0,i.jsx)(n.h3,{id:"changed",children:"Changed"}),"\n",(0,i.jsx)(n.h3,{id:"fixed",children:"Fixed"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Set the actual documentation URL in warnings."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"011---2024-08-06",children:"[0.1.1] - 2024-08-06"}),"\n",(0,i.jsx)(n.h3,{id:"added-1",children:"Added"}),"\n",(0,i.jsx)(n.h3,{id:"changed-1",children:"Changed"}),"\n",(0,i.jsx)(n.h3,{id:"fixed-1",children:"Fixed"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["The npm postinstall script tries to build a contract project after running ",(0,i.jsx)(n.code,{children:"yarn add @nowarp/misti"}),"."]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"010---2024-08-06",children:"[0.1.0] - 2024-08-06"}),"\n",(0,i.jsx)(n.h3,{id:"added-2",children:"Added"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Initial release"}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},8453:(e,n,d)=>{d.d(n,{R:()=>s,x:()=>a});var i=d(6540);const t={},l=i.createContext(t);function s(e){const n=i.useContext(l);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),i.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2cebbb1e.1c80f755.js b/assets/js/2cebbb1e.1c80f755.js new file mode 100644 index 000000000..dadaa645c --- /dev/null +++ b/assets/js/2cebbb1e.1c80f755.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5345],{730:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>d,toc:()=>c});var s=n(4848),r=n(8453);const i={},o="PreferAugmentedAssign",d={id:"detectors/PreferAugmentedAssign",title:"PreferAugmentedAssign",description:"Detects non-idiomatic statements that can be written using augmented assignment",source:"@site/versioned_docs/version-0.3.1/detectors/PreferAugmentedAssign.md",sourceDirName:"detectors",slug:"/detectors/PreferAugmentedAssign",permalink:"/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/PreferAugmentedAssign.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"NeverAccessedVariables",permalink:"/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables"},next:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"preferaugmentedassign",children:"PreferAugmentedAssign"}),"\n",(0,s.jsxs)(t.p,{children:["Detects non-idiomatic statements that can be written using augmented assignment\noperators like ",(0,s.jsx)(t.code,{children:"+="}),", ",(0,s.jsx)(t.code,{children:"-="}),", etc."]}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Using augmented assignment operations improves the readability of the source code\nand reduces the risk of mistakes, such as those that occur during copy-pasting\nand refactoring code."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue = (msgValue - ctx.readForwardFee());\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue -= ctx.readForwardFee());\n"})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>d});var s=n(6540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2d07d137.1711bd45.js b/assets/js/2d07d137.1711bd45.js new file mode 100644 index 000000000..f81b9398e --- /dev/null +++ b/assets/js/2d07d137.1711bd45.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5097],{6097:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>a});var n=i(4848),r=i(8453);const o={},s="Divide before Multiply",l={id:"detectors/DivideBeforeMultiply",title:"Divide before Multiply",description:"A detector that identifies and corrects instances of division before multiplication to",source:"@site/versioned_docs/version-0.2.0/detectors/DivideBeforeMultiply.md",sourceDirName:"detectors",slug:"/detectors/DivideBeforeMultiply",permalink:"/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/DivideBeforeMultiply.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.2.0/detectors"},next:{title:"Never-accessed Variables",permalink:"/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function d(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"divide-before-multiply",children:"Divide before Multiply"}),"\n",(0,n.jsx)(t.p,{children:"A detector that identifies and corrects instances of division before multiplication to\nensure accurate mathematical operations."}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers."}),"\n",(0,n.jsx)(t.li,{children:"Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations."}),"\n",(0,n.jsx)(t.li,{children:"Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Bad: Division before multiplication\nlet result: Int = a / b * c;\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Correct: Multiplication before division\nlet result: Int = a * c / b;\n"})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>l});var n=i(6540);const r={},o=n.createContext(r);function s(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2f30e490.cf459bb9.js b/assets/js/2f30e490.cf459bb9.js new file mode 100644 index 000000000..76df4f62a --- /dev/null +++ b/assets/js/2f30e490.cf459bb9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1638],{2380:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>a});var n=i(4848),r=i(8453);const o={},s="Divide before Multiply",l={id:"detectors/DivideBeforeMultiply",title:"Divide before Multiply",description:"A detector that identifies and corrects instances of division before multiplication to",source:"@site/versioned_docs/version-0.2.1/detectors/DivideBeforeMultiply.md",sourceDirName:"detectors",slug:"/detectors/DivideBeforeMultiply",permalink:"/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/DivideBeforeMultiply.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.2.1/detectors"},next:{title:"Never-accessed Variables",permalink:"/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function d(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"divide-before-multiply",children:"Divide before Multiply"}),"\n",(0,n.jsx)(t.p,{children:"A detector that identifies and corrects instances of division before multiplication to\nensure accurate mathematical operations."}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers."}),"\n",(0,n.jsx)(t.li,{children:"Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations."}),"\n",(0,n.jsx)(t.li,{children:"Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Bad: Division before multiplication\nlet result: Int = a / b * c;\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Correct: Multiplication before division\nlet result: Int = a * c / b;\n"})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>l});var n=i(6540);const r={},o=n.createContext(r);function s(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/304edb56.1899324d.js b/assets/js/304edb56.1899324d.js new file mode 100644 index 000000000..6b6027147 --- /dev/null +++ b/assets/js/304edb56.1899324d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4088],{8271:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var a=n(4848),s=n(8453);const i={},o="ArgCopyMutation",r={id:"detectors/ArgCopyMutation",title:"ArgCopyMutation",description:"A detector that highlights cases where function argument mutations are ineffective",source:"@site/docs/detectors/ArgCopyMutation.md",sourceDirName:"detectors",slug:"/detectors/ArgCopyMutation",permalink:"/tools/misti/docs/next/detectors/ArgCopyMutation",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/ArgCopyMutation.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Overview",permalink:"/tools/misti/docs/next/detectors"},next:{title:"AsmIsUsed",permalink:"/tools/misti/docs/next/detectors/AsmIsUsed"}},c={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function u(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h1,{id:"argcopymutation",children:"ArgCopyMutation"}),"\n",(0,a.jsxs)(t.p,{children:["A detector that highlights cases where function argument mutations are ineffective\ndue to ",(0,a.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value",children:"call-by-value semantics"})," in Tact."]}),"\n",(0,a.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,a.jsx)(t.p,{children:"In Tact, function arguments are passed by value, meaning that any mutations applied\nto these arguments will only affect the local copy of the variable within the function.\nSuch mutations are unobservable outside the function, except for potentially\nincreasing gas consumption or causing exceptions."}),"\n",(0,a.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-tact",children:"fun addEntry(m: map) {\n m.set(1, 10); // Bad: Mutating the copy\n}\n"})}),"\n",(0,a.jsx)(t.p,{children:"Use instead:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-tact",children:"fun addEntry() {\n self.m.set(1, 10); // OK: Changing contract's state\n}\n"})}),"\n",(0,a.jsx)(t.p,{children:"Alternatively, you could redesign the method:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.jsx)(t.code,{className:"language-tact",children:"fun generateNewValue(): Int {\n // ... produce new value for the map\n return self.nextValue + 1;\n}\n\nm.set(self.nextKey, self.generateNewValue()); // OK\n"})})]})}function d(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(u,{...e})}):u(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>r});var a=n(6540);const s={},i=a.createContext(s);function o(e){const t=a.useContext(i);return a.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),a.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/3658.8fe69683.js b/assets/js/3658.8fe69683.js new file mode 100644 index 000000000..8de0a4c2e --- /dev/null +++ b/assets/js/3658.8fe69683.js @@ -0,0 +1 @@ +(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3658],{7293:(e,t,n)=>{"use strict";n.d(t,{A:()=>E});var s=n(6540),o=n(4848);function a(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=s.Children.toArray(e),n=t.find((e=>s.isValidElement(e)&&"mdxAdmonitionTitle"===e.type)),a=t.filter((e=>e!==n)),c=n?.props.children;return{mdxAdmonitionTitle:c,rest:a.length>0?(0,o.jsx)(o.Fragment,{children:a}):null}}(e.children),a=e.title??t;return{...e,...a&&{title:a},children:n}}var c=n(4164),i=n(1312),r=n(7559);const l={admonition:"admonition_xJq3",admonitionHeading:"admonitionHeading_Gvgb",admonitionIcon:"admonitionIcon_Rf37",admonitionContent:"admonitionContent_BuS1"};function d(e){let{type:t,className:n,children:s}=e;return(0,o.jsx)("div",{className:(0,c.A)(r.G.common.admonition,r.G.common.admonitionType(t),l.admonition,n),children:s})}function u(e){let{icon:t,title:n}=e;return(0,o.jsxs)("div",{className:l.admonitionHeading,children:[(0,o.jsx)("span",{className:l.admonitionIcon,children:t}),n]})}function m(e){let{children:t}=e;return t?(0,o.jsx)("div",{className:l.admonitionContent,children:t}):null}function h(e){const{type:t,icon:n,title:s,children:a,className:c}=e;return(0,o.jsxs)(d,{type:t,className:c,children:[s||n?(0,o.jsx)(u,{title:s,icon:n}):null,(0,o.jsx)(m,{children:a})]})}function f(e){return(0,o.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})})}const p={icon:(0,o.jsx)(f,{}),title:(0,o.jsx)(i.A,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)",children:"note"})};function x(e){return(0,o.jsx)(h,{...p,...e,className:(0,c.A)("alert alert--secondary",e.className),children:e.children})}function g(e){return(0,o.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"})})}const b={icon:(0,o.jsx)(g,{}),title:(0,o.jsx)(i.A,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)",children:"tip"})};function v(e){return(0,o.jsx)(h,{...b,...e,className:(0,c.A)("alert alert--success",e.className),children:e.children})}function j(e){return(0,o.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})})}const N={icon:(0,o.jsx)(j,{}),title:(0,o.jsx)(i.A,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)",children:"info"})};function y(e){return(0,o.jsx)(h,{...N,...e,className:(0,c.A)("alert alert--info",e.className),children:e.children})}function A(e){return(0,o.jsx)("svg",{viewBox:"0 0 16 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})})}const C={icon:(0,o.jsx)(A,{}),title:(0,o.jsx)(i.A,{id:"theme.admonition.warning",description:"The default label used for the Warning admonition (:::warning)",children:"warning"})};function k(e){return(0,o.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,o.jsx)("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"})})}const B={icon:(0,o.jsx)(k,{}),title:(0,o.jsx)(i.A,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)",children:"danger"})};const w={icon:(0,o.jsx)(A,{}),title:(0,o.jsx)(i.A,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)",children:"caution"})};const L={...{note:x,tip:v,info:y,warning:function(e){return(0,o.jsx)(h,{...C,...e,className:(0,c.A)("alert alert--warning",e.className),children:e.children})},danger:function(e){return(0,o.jsx)(h,{...B,...e,className:(0,c.A)("alert alert--danger",e.className),children:e.children})}},...{secondary:e=>(0,o.jsx)(x,{title:"secondary",...e}),important:e=>(0,o.jsx)(y,{title:"important",...e}),success:e=>(0,o.jsx)(v,{title:"success",...e}),caution:function(e){return(0,o.jsx)(h,{...w,...e,className:(0,c.A)("alert alert--warning",e.className),children:e.children})}}};function E(e){const t=a(e),n=(s=t.type,L[s]||(console.warn(`No admonition component found for admonition type "${s}". Using Info as fallback.`),L.info));var s;return(0,o.jsx)(n,{...t})}},2153:(e,t,n)=>{"use strict";n.d(t,{A:()=>g});n(6540);var s=n(4164),o=n(1312),a=n(7559),c=n(8774);const i={iconEdit:"iconEdit_Z9Sw"};var r=n(4848);function l(e){let{className:t,...n}=e;return(0,r.jsx)("svg",{fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,s.A)(i.iconEdit,t),"aria-hidden":"true",...n,children:(0,r.jsx)("g",{children:(0,r.jsx)("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})})})}function d(e){let{editUrl:t}=e;return(0,r.jsxs)(c.A,{to:t,className:a.G.common.editThisPage,children:[(0,r.jsx)(l,{}),(0,r.jsx)(o.A,{id:"theme.common.editThisPage",description:"The link label to edit the current page",children:"Edit this page"})]})}var u=n(4586);function m(e){void 0===e&&(e={});const{i18n:{currentLocale:t}}=(0,u.A)(),n=function(){const{i18n:{currentLocale:e,localeConfigs:t}}=(0,u.A)();return t[e].calendar}();return new Intl.DateTimeFormat(t,{calendar:n,...e})}function h(e){let{lastUpdatedAt:t}=e;const n=new Date(t),s=m({day:"numeric",month:"short",year:"numeric",timeZone:"UTC"}).format(n);return(0,r.jsx)(o.A,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:(0,r.jsx)("b",{children:(0,r.jsx)("time",{dateTime:n.toISOString(),itemProp:"dateModified",children:s})})},children:" on {date}"})}function f(e){let{lastUpdatedBy:t}=e;return(0,r.jsx)(o.A,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:(0,r.jsx)("b",{children:t})},children:" by {user}"})}function p(e){let{lastUpdatedAt:t,lastUpdatedBy:n}=e;return(0,r.jsxs)("span",{className:a.G.common.lastUpdated,children:[(0,r.jsx)(o.A,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t?(0,r.jsx)(h,{lastUpdatedAt:t}):"",byUser:n?(0,r.jsx)(f,{lastUpdatedBy:n}):""},children:"Last updated{atDate}{byUser}"}),!1]})}const x={lastUpdated:"lastUpdated_JAkA"};function g(e){let{className:t,editUrl:n,lastUpdatedAt:o,lastUpdatedBy:a}=e;return(0,r.jsxs)("div",{className:(0,s.A)("row",t),children:[(0,r.jsx)("div",{className:"col",children:n&&(0,r.jsx)(d,{editUrl:n})}),(0,r.jsx)("div",{className:(0,s.A)("col",x.lastUpdated),children:(o||a)&&(0,r.jsx)(p,{lastUpdatedAt:o,lastUpdatedBy:a})})]})}},5533:(e,t,n)=>{"use strict";n.d(t,{A:()=>re});var s=n(6540),o=n(8453),a=n(5260),c=n(2303),i=n(4164),r=n(5293),l=n(6342);function d(){const{prism:e}=(0,l.p)(),{colorMode:t}=(0,r.G)(),n=e.theme,s=e.darkTheme||n;return"dark"===t?s:n}var u=n(7559),m=n(8426),h=n.n(m);const f=/title=(?["'])(?.*?)\1/,p=/\{(?<range>[\d,-]+)\}/,x={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}},g={...x,lua:{start:"--",end:""},wasm:{start:"\\;\\;",end:""},tex:{start:"%",end:""},vb:{start:"['\u2018\u2019]",end:""},vbnet:{start:"(?:_\\s*)?['\u2018\u2019]",end:""},rem:{start:"[Rr][Ee][Mm]\\b",end:""},f90:{start:"!",end:""},ml:{start:"\\(\\*",end:"\\*\\)"},cobol:{start:"\\*>",end:""}},b=Object.keys(x);function v(e,t){const n=e.map((e=>{const{start:n,end:s}=g[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${s})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function j(e,t){let n=e.replace(/\n$/,"");const{language:s,magicComments:o,metastring:a}=t;if(a&&p.test(a)){const e=a.match(p).groups.range;if(0===o.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${a}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=o[0].className,s=h()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(s),code:n}}if(void 0===s)return{lineClassNames:{},code:n};const c=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return v(["js","jsBlock"],t);case"jsx":case"tsx":return v(["js","jsBlock","jsx"],t);case"html":return v(["js","jsBlock","html"],t);case"python":case"py":case"bash":return v(["bash"],t);case"markdown":case"md":return v(["html","jsx","bash"],t);case"tex":case"latex":case"matlab":return v(["tex"],t);case"lua":case"haskell":case"sql":return v(["lua"],t);case"wasm":return v(["wasm"],t);case"vb":case"vba":case"visual-basic":return v(["vb","rem"],t);case"vbnet":return v(["vbnet","rem"],t);case"batch":return v(["rem"],t);case"basic":return v(["rem","f90"],t);case"fsharp":return v(["js","ml"],t);case"ocaml":case"sml":return v(["ml"],t);case"fortran":return v(["f90"],t);case"cobol":return v(["cobol"],t);default:return v(b,t)}}(s,o),i=n.split("\n"),r=Object.fromEntries(o.map((e=>[e.className,{start:0,range:""}]))),l=Object.fromEntries(o.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),d=Object.fromEntries(o.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),u=Object.fromEntries(o.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let h=0;h<i.length;){const e=i[h].match(c);if(!e){h+=1;continue}const t=e.slice(1).find((e=>void 0!==e));l[t]?r[l[t]].range+=`${h},`:d[t]?r[d[t]].start=h:u[t]&&(r[u[t]].range+=`${r[u[t]].start}-${h-1},`),i.splice(h,1)}n=i.join("\n");const m={};return Object.entries(r).forEach((e=>{let[t,{range:n}]=e;h()(n).forEach((e=>{m[e]??=[],m[e].push(t)}))})),{lineClassNames:m,code:n}}const N={codeBlockContainer:"codeBlockContainer_Ckt0"};var y=n(4848);function A(e){let{as:t,...n}=e;const s=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[s,o]=e;const a=t[s];a&&"string"==typeof o&&(n[a]=o)})),n}(d());return(0,y.jsx)(t,{...n,style:s,className:(0,i.A)(n.className,N.codeBlockContainer,u.G.common.codeBlock)})}const C={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function k(e){let{children:t,className:n}=e;return(0,y.jsx)(A,{as:"pre",tabIndex:0,className:(0,i.A)(C.codeBlockStandalone,"thin-scrollbar",n),children:(0,y.jsx)("code",{className:C.codeBlockLines,children:t})})}var B=n(9532);const w={attributes:!0,characterData:!0,childList:!0,subtree:!0};function L(e,t){const[n,o]=(0,s.useState)(),a=(0,s.useCallback)((()=>{o(e.current?.closest("[role=tabpanel][hidden]"))}),[e,o]);(0,s.useEffect)((()=>{a()}),[a]),function(e,t,n){void 0===n&&(n=w);const o=(0,B._q)(t),a=(0,B.Be)(n);(0,s.useEffect)((()=>{const t=new MutationObserver(o);return e&&t.observe(e,a),()=>t.disconnect()}),[e,o,a])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),a())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}var E=n(1765);const T={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function _(e){let{line:t,classNames:n,showLineNumbers:s,getLineProps:o,getTokenProps:a}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const c=o({line:t,className:(0,i.A)(n,s&&T.codeLine)}),r=t.map(((e,t)=>(0,y.jsx)("span",{...a({token:e})},t)));return(0,y.jsxs)("span",{...c,children:[s?(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)("span",{className:T.codeLineNumber}),(0,y.jsx)("span",{className:T.codeLineContent,children:r})]}):r,(0,y.jsx)("br",{})]})}var H=n(1312);function S(e){return(0,y.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,y.jsx)("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})})}function I(e){return(0,y.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,y.jsx)("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"})})}const M={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function U(e){let{code:t,className:n}=e;const[o,a]=(0,s.useState)(!1),c=(0,s.useRef)(void 0),r=(0,s.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const s=document.createElement("textarea"),o=document.activeElement;s.value=e,s.setAttribute("readonly",""),s.style.contain="strict",s.style.position="absolute",s.style.left="-9999px",s.style.fontSize="12pt";const a=document.getSelection(),c=a.rangeCount>0&&a.getRangeAt(0);n.append(s),s.select(),s.selectionStart=0,s.selectionEnd=e.length;let i=!1;try{i=document.execCommand("copy")}catch{}s.remove(),c&&(a.removeAllRanges(),a.addRange(c)),o&&o.focus()}(t),a(!0),c.current=window.setTimeout((()=>{a(!1)}),1e3)}),[t]);return(0,s.useEffect)((()=>()=>window.clearTimeout(c.current)),[]),(0,y.jsx)("button",{type:"button","aria-label":o?(0,H.T)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,H.T)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,H.T)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,i.A)("clean-btn",n,M.copyButton,o&&M.copyButtonCopied),onClick:r,children:(0,y.jsxs)("span",{className:M.copyButtonIcons,"aria-hidden":"true",children:[(0,y.jsx)(S,{className:M.copyButtonIcon}),(0,y.jsx)(I,{className:M.copyButtonSuccessIcon})]})})}function z(e){return(0,y.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,y.jsx)("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})})}const R={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function O(e){let{className:t,onClick:n,isEnabled:s}=e;const o=(0,H.T)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return(0,y.jsx)("button",{type:"button",onClick:n,className:(0,i.A)("clean-btn",t,s&&R.wordWrapButtonEnabled),"aria-label":o,title:o,children:(0,y.jsx)(z,{className:R.wordWrapButtonIcon,"aria-hidden":"true"})})}function $(e){let{children:t,className:n="",metastring:o,title:a,showLineNumbers:c,language:r}=e;const{prism:{defaultLanguage:u,magicComments:m}}=(0,l.p)(),h=function(e){return e?.toLowerCase()}(r??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??u),p=d(),x=function(){const[e,t]=(0,s.useState)(!1),[n,o]=(0,s.useState)(!1),a=(0,s.useRef)(null),c=(0,s.useCallback)((()=>{const n=a.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[a,e]),i=(0,s.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=a.current,n=e>t||a.current.querySelector("code").hasAttribute("style");o(n)}),[a]);return L(a,i),(0,s.useEffect)((()=>{i()}),[e,i]),(0,s.useEffect)((()=>(window.addEventListener("resize",i,{passive:!0}),()=>{window.removeEventListener("resize",i)})),[i]),{codeBlockRef:a,isEnabled:e,isCodeScrollable:n,toggle:c}}(),g=function(e){return e?.match(f)?.groups.title??""}(o)||a,{lineClassNames:b,code:v}=j(t,{metastring:o,language:h,magicComments:m}),N=c??function(e){return Boolean(e?.includes("showLineNumbers"))}(o);return(0,y.jsxs)(A,{as:"div",className:(0,i.A)(n,h&&!n.includes(`language-${h}`)&&`language-${h}`),children:[g&&(0,y.jsx)("div",{className:C.codeBlockTitle,children:g}),(0,y.jsxs)("div",{className:C.codeBlockContent,children:[(0,y.jsx)(E.f4,{theme:p,code:v,language:h??"text",children:e=>{let{className:t,style:n,tokens:s,getLineProps:o,getTokenProps:a}=e;return(0,y.jsx)("pre",{tabIndex:0,ref:x.codeBlockRef,className:(0,i.A)(t,C.codeBlock,"thin-scrollbar"),style:n,children:(0,y.jsx)("code",{className:(0,i.A)(C.codeBlockLines,N&&C.codeBlockLinesWithNumbering),children:s.map(((e,t)=>(0,y.jsx)(_,{line:e,getLineProps:o,getTokenProps:a,classNames:b[t],showLineNumbers:N},t)))})})}}),(0,y.jsxs)("div",{className:C.buttonGroup,children:[(x.isEnabled||x.isCodeScrollable)&&(0,y.jsx)(O,{className:C.codeButton,onClick:()=>x.toggle(),isEnabled:x.isEnabled}),(0,y.jsx)(U,{className:C.codeButton,code:v})]})]})]})}function V(e){let{children:t,...n}=e;const o=(0,c.A)(),a=function(e){return s.Children.toArray(e).some((e=>(0,s.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),i="string"==typeof a?$:k;return(0,y.jsx)(i,{...n,children:a},String(o))}function P(e){return(0,y.jsx)("code",{...e})}var W=n(8774);var D=n(3427),q=n(1422);const G={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function F(e){return!!e&&("SUMMARY"===e.tagName||F(e.parentElement))}function Z(e,t){return!!e&&(e===t||Z(e.parentElement,t))}function J(e){let{summary:t,children:n,...o}=e;(0,D.A)().collectAnchor(o.id);const a=(0,c.A)(),r=(0,s.useRef)(null),{collapsed:l,setCollapsed:d}=(0,q.u)({initialState:!o.open}),[u,m]=(0,s.useState)(o.open),h=s.isValidElement(t)?t:(0,y.jsx)("summary",{children:t??"Details"});return(0,y.jsxs)("details",{...o,ref:r,open:u,"data-collapsed":l,className:(0,i.A)(G.details,a&&G.isBrowser,o.className),onMouseDown:e=>{F(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;F(t)&&Z(t,r.current)&&(e.preventDefault(),l?(d(!1),m(!0)):d(!0))},children:[h,(0,y.jsx)(q.N,{lazy:!1,collapsed:l,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{d(e),m(!e)},children:(0,y.jsx)("div",{className:G.collapsibleContent,children:n})})]})}const Y={details:"details_b_Ee"},K="alert alert--info";function Q(e){let{...t}=e;return(0,y.jsx)(J,{...t,className:(0,i.A)(K,Y.details,t.className)})}function X(e){const t=s.Children.toArray(e.children),n=t.find((e=>s.isValidElement(e)&&"summary"===e.type)),o=(0,y.jsx)(y.Fragment,{children:t.filter((e=>e!==n))});return(0,y.jsx)(Q,{...e,summary:n,children:o})}var ee=n(1107);function te(e){return(0,y.jsx)(ee.A,{...e})}const ne={containsTaskList:"containsTaskList_mC6p"};function se(e){if(void 0!==e)return(0,i.A)(e,e?.includes("contains-task-list")&&ne.containsTaskList)}const oe={img:"img_ev3q"};var ae=n(7293),ce=n(418);const ie={Head:a.A,details:X,Details:X,code:function(e){return function(e){return void 0!==e.children&&s.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")))}(e)?(0,y.jsx)(P,{...e}):(0,y.jsx)(V,{...e})},a:function(e){return(0,y.jsx)(W.A,{...e})},pre:function(e){return(0,y.jsx)(y.Fragment,{children:e.children})},ul:function(e){return(0,y.jsx)("ul",{...e,className:se(e.className)})},li:function(e){return(0,D.A)().collectAnchor(e.id),(0,y.jsx)("li",{...e})},img:function(e){return(0,y.jsx)("img",{decoding:"async",loading:"lazy",...e,className:(t=e.className,(0,i.A)(t,oe.img))});var t},h1:e=>(0,y.jsx)(te,{as:"h1",...e}),h2:e=>(0,y.jsx)(te,{as:"h2",...e}),h3:e=>(0,y.jsx)(te,{as:"h3",...e}),h4:e=>(0,y.jsx)(te,{as:"h4",...e}),h5:e=>(0,y.jsx)(te,{as:"h5",...e}),h6:e=>(0,y.jsx)(te,{as:"h6",...e}),admonition:ae.A,mermaid:ce.A};function re(e){let{children:t}=e;return(0,y.jsx)(o.x,{components:ie,children:t})}},7763:(e,t,n)=>{"use strict";n.d(t,{A:()=>l});n(6540);var s=n(4164),o=n(5195);const a={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"};var c=n(4848);const i="table-of-contents__link toc-highlight",r="table-of-contents__link--active";function l(e){let{className:t,...n}=e;return(0,c.jsx)("div",{className:(0,s.A)(a.tableOfContents,"thin-scrollbar",t),children:(0,c.jsx)(o.A,{...n,linkClassName:i,linkActiveClassName:r})})}},5195:(e,t,n)=>{"use strict";n.d(t,{A:()=>p});var s=n(6540),o=n(6342);function a(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const s=n.slice(2,e.level);e.parentIndex=Math.max(...s),n[e.level]=t}));const s=[];return t.forEach((e=>{const{parentIndex:n,...o}=e;n>=0?t[n].children.push(o):s.push(o)})),s}function c(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:s}=e;return t.flatMap((e=>{const t=c({toc:e.children,minHeadingLevel:n,maxHeadingLevel:s});return function(e){return e.level>=n&&e.level<=s}(e)?[{...e,children:t}]:t}))}function i(e){const t=e.getBoundingClientRect();return t.top===t.bottom?i(e.parentNode):t}function r(e,t){let{anchorTopOffset:n}=t;const s=e.find((e=>i(e).top>=n));if(s){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}(i(s))?s:e[e.indexOf(s)-1]??null}return e[e.length-1]??null}function l(){const e=(0,s.useRef)(0),{navbar:{hideOnScroll:t}}=(0,o.p)();return(0,s.useEffect)((()=>{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function d(e){const t=(0,s.useRef)(void 0),n=l();(0,s.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:s,linkActiveClassName:o,minHeadingLevel:a,maxHeadingLevel:c}=e;function i(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(s),i=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const s=[];for(let o=t;o<=n;o+=1)s.push(`h${o}.anchor`);return Array.from(document.querySelectorAll(s.join()))}({minHeadingLevel:a,maxHeadingLevel:c}),l=r(i,{anchorTopOffset:n.current}),d=e.find((e=>l&&l.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(o),e.classList.add(o),t.current=e):e.classList.remove(o)}(e,e===d)}))}return document.addEventListener("scroll",i),document.addEventListener("resize",i),i(),()=>{document.removeEventListener("scroll",i),document.removeEventListener("resize",i)}}),[e,n])}var u=n(8774),m=n(4848);function h(e){let{toc:t,className:n,linkClassName:s,isChild:o}=e;return t.length?(0,m.jsx)("ul",{className:o?void 0:n,children:t.map((e=>(0,m.jsxs)("li",{children:[(0,m.jsx)(u.A,{to:`#${e.id}`,className:s??void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,m.jsx)(h,{isChild:!0,toc:e.children,className:n,linkClassName:s})]},e.id)))}):null}const f=s.memo(h);function p(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:i="table-of-contents__link",linkActiveClassName:r,minHeadingLevel:l,maxHeadingLevel:u,...h}=e;const p=(0,o.p)(),x=l??p.tableOfContents.minHeadingLevel,g=u??p.tableOfContents.maxHeadingLevel,b=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:o}=e;return(0,s.useMemo)((()=>c({toc:a(t),minHeadingLevel:n,maxHeadingLevel:o})),[t,n,o])}({toc:t,minHeadingLevel:x,maxHeadingLevel:g});return d((0,s.useMemo)((()=>{if(i&&r)return{linkClassName:i,linkActiveClassName:r,minHeadingLevel:x,maxHeadingLevel:g}}),[i,r,x,g])),(0,m.jsx)(f,{toc:b,className:n,linkClassName:i,...h})}},996:(e,t,n)=>{"use strict";n.d(t,{A:()=>h});n(6540);var s=n(4164),o=n(1312),a=n(5260),c=n(4848);function i(){return(0,c.jsx)(o.A,{id:"theme.unlistedContent.title",description:"The unlisted content banner title",children:"Unlisted page"})}function r(){return(0,c.jsx)(o.A,{id:"theme.unlistedContent.message",description:"The unlisted content banner message",children:"This page is unlisted. Search engines will not index it, and only users having a direct link can access it."})}function l(){return(0,c.jsx)(a.A,{children:(0,c.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})}var d=n(7559),u=n(7293);function m(e){let{className:t}=e;return(0,c.jsx)(u.A,{type:"caution",title:(0,c.jsx)(i,{}),className:(0,s.A)(t,d.G.common.unlistedBanner),children:(0,c.jsx)(r,{})})}function h(e){return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(l,{}),(0,c.jsx)(m,{...e})]})}},8426:(e,t)=>{function n(e){let t,n=[];for(let s of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(s))n.push(parseInt(s,10));else if(t=s.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,s,o,a]=t;if(s&&a){s=parseInt(s),a=parseInt(a);const e=s<a?1:-1;"-"!==o&&".."!==o&&"\u2025"!==o||(a+=e);for(let t=s;t!==a;t+=e)n.push(t)}}return n}t.default=n,e.exports=n},8453:(e,t,n)=>{"use strict";n.d(t,{R:()=>c,x:()=>i});var s=n(6540);const o={},a=s.createContext(o);function c(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:c(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/36ebdf3e.c81514b8.js b/assets/js/36ebdf3e.c81514b8.js new file mode 100644 index 000000000..db15bf8c7 --- /dev/null +++ b/assets/js/36ebdf3e.c81514b8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7787],{7162:(e,s,t)=>{t.r(s),t.d(s,{assets:()=>a,contentTitle:()=>d,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>c});var n=t(4848),o=t(8453);const r={},d="Zero Address",i={id:"detectors/ZeroAddress",title:"Zero Address",description:"A detector that identifies uses of the zero address.",source:"@site/versioned_docs/version-0.1.2/detectors/ZeroAddress.md",sourceDirName:"detectors",slug:"/detectors/ZeroAddress",permalink:"/tools/misti/docs/0.1.2/detectors/ZeroAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/detectors/ZeroAddress.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Unbound Loops",permalink:"/tools/misti/docs/0.1.2/detectors/UnboundLoops"},next:{title:"Contributing",permalink:"/tools/misti/docs/0.1.2/hacking/contributing"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const s={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{id:"zero-address",children:"Zero Address"}),"\n",(0,n.jsx)(s.p,{children:"A detector that identifies uses of the zero address."}),"\n",(0,n.jsx)(s.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(s.p,{children:"Using the zero address in smart contracts is typically problematic because it can be\nexploited as a default or uninitialized address, leading to unintended transfers and\nsecurity vulnerabilities. Additionally, operations involving the zero address can\nresult in loss of funds or tokens, as there is no private key to access this address."}),"\n",(0,n.jsx)(s.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init() {\n // Warning: Insecure usage of zero address as default value\n self.to = newAddress(0, 0);\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})}),"\n",(0,n.jsx)(s.p,{children:"Use instead:"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init(to: Address) {\n // Fixed: Using the input value on initializaiton.\n self.to = to;\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})})]})}function u(e={}){const{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,s,t)=>{t.d(s,{R:()=>d,x:()=>i});var n=t(6540);const o={},r=n.createContext(o);function d(e){const s=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function i(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),n.createElement(r.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/377c4f81.79a338ae.js b/assets/js/377c4f81.79a338ae.js new file mode 100644 index 000000000..00298847f --- /dev/null +++ b/assets/js/377c4f81.79a338ae.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3448],{235:(i,e,t)=>{t.r(e),t.d(e,{assets:()=>o,contentTitle:()=>I,default:()=>c,frontMatter:()=>l,metadata:()=>d,toc:()=>g});var n=t(4848),s=t(8453);const l={},I="Tools Guide",d={id:"hacking/tools",title:"Tools Guide",description:"This page describes the internal analyzer tools available in Misti to aid in development and debugging.",source:"@site/versioned_docs/version-0.3.0/hacking/tools.md",sourceDirName:"hacking",slug:"/hacking/tools",permalink:"/tools/misti/docs/0.3.0/hacking/tools",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/hacking/tools.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.3.0/hacking/souffle"},next:{title:"Custom Detectors",permalink:"/tools/misti/docs/0.3.0/hacking/custom-detector"}},o={},g=[{value:"CFG Dump",id:"cfg-dump",level:2},{value:"Usage",id:"usage",level:3},{value:"Converting DOT to SVG",id:"converting-dot-to-svg",level:3},{value:"Viewing the SVG",id:"viewing-the-svg",level:3},{value:"VS Code Plugin",id:"vs-code-plugin",level:3},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function a(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"tools-guide",children:"Tools Guide"}),"\n",(0,n.jsx)(e.p,{children:"This page describes the internal analyzer tools available in Misti to aid in development and debugging."}),"\n",(0,n.jsx)(e.h2,{id:"cfg-dump",children:"CFG Dump"}),"\n",(0,n.jsx)(e.p,{children:"Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts."}),"\n",(0,n.jsx)(e.h3,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in JSON format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in DOT format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.h3,{id:"converting-dot-to-svg",children:"Converting DOT to SVG"}),"\n",(0,n.jsxs)(e.p,{children:["To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use ",(0,n.jsx)(e.a,{href:"https://graphviz.org",children:"Graphviz"})," with the following command:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot\ndot -Tsvg output.dot -o output.svg\n'})}),"\n",(0,n.jsx)(e.h3,{id:"viewing-the-svg",children:"Viewing the SVG"}),"\n",(0,n.jsx)(e.p,{children:"To view the SVG file in Firefox, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"firefox output.svg\n"})}),"\n",(0,n.jsx)(e.p,{children:"For example, for the following contract:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:"fun test(): Int {\n let sum: Int = 0;\n let i: Int = 0;\n repeat (10) {\n i = i + 1;\n sum = sum + i;\n }\n return sum;\n}\n"})}),"\n",(0,n.jsx)(e.p,{children:"The following CFG will be generated:"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"CFG Example",src:t(685).A+"",width:"337",height:"516"})}),"\n",(0,n.jsx)(e.h3,{id:"vs-code-plugin",children:"VS Code Plugin"}),"\n",(0,n.jsxs)(e.p,{children:["For real-time visualization of DOT files, you can use ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/search?term=tag%3Agraphviz&target=VSCode&category=All%20categories&sortBy=Relevance",children:"one of the available"})," Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development."]}),"\n",(0,n.jsx)(e.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"JSON Dumps"}),": These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"DOT Dumps"}),": These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(e.p,{children:"By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors."})]})}function c(i={}){const{wrapper:e}={...(0,s.R)(),...i.components};return e?(0,n.jsx)(e,{...i,children:(0,n.jsx)(a,{...i})}):a(i)}},685:(i,e,t)=>{t.d(e,{A:()=>n});const n="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDIuNCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBsb29wcyYjNDU7MyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjUzcHQiIGhlaWdodD0iMzg3cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjUzLjAwIDM4Ny4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzODMpIj4KPHRpdGxlPmxvb3BzJiM0NTszPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzgzIDI0OSwtMzgzIDI0OSw0IC00LDQiLz4KPGcgaWQ9ImNsdXN0MSIgY2xhc3M9ImNsdXN0ZXIiPgo8dGl0bGU+Y2x1c3Rlcl90ZXN0PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI4LC04IDgsLTM3MSAyMzcsLTM3MSAyMzcsLTggOCwtOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIuNSIgeT0iLTM1NS44IiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnRlc3Q8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0MSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT50ZXN0XzE0MTwvdGl0bGU+Cjxwb2x5Z29uIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjI0LjUsLTM0MCA5NS41LC0zNDAgOTUuNSwtMzA0IDIyNC41LC0zMDQgMjI0LjUsLTM0MCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNjAiIHk9Ii0zMTguMyIgZm9udC1mYW1pbHk9IlRpbWVzLHNlcmlmIiBmb250LXNpemU9IjE0LjAwIj5sZXQgc3VtOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDI8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMiwtMjY4IDEwOCwtMjY4IDEwOCwtMjMyIDIxMiwtMjMyIDIxMiwtMjY4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTI0Ni4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPmxldCBpOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDEmIzQ1OyZndDt0ZXN0XzE0MiAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MSYjNDU7Jmd0O3Rlc3RfMTQyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMzAzLjdDMTYwLC0yOTUuOTggMTYwLC0yODYuNzEgMTYwLC0yNzguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTI3OC4xIDE2MCwtMjY4LjEgMTU2LjUsLTI3OC4xIDE2My41LC0yNzguMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDQ8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOCwtMTk2IDExMiwtMTk2IDExMiwtMTYwIDIwOCwtMTYwIDIwOCwtMTk2Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTE3NC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnJlcGVhdCAoMTApPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDImIzQ1OyZndDt0ZXN0XzE0NCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MiYjNDU7Jmd0O3Rlc3RfMTQ0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMjMxLjdDMTYwLC0yMjMuOTggMTYwLC0yMTQuNzEgMTYwLC0yMDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTIwNi4xIDE2MCwtMTk2LjEgMTU2LjUsLTIwNi4xIDE2My41LC0yMDYuMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDYgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDY8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjkzLjUsLTEyNCAxNi41LC0xMjQgMTYuNSwtODggOTMuNSwtODggOTMuNSwtMTI0Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjU1IiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+aSA9IGkgKyAxPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE0NiAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0NCYjNDU7Jmd0O3Rlc3RfMTQ2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEzNC4zMSwtMTU5Ljg4QzEyMC43MSwtMTUwLjgxIDEwMy44MywtMTM5LjU1IDg5LjE0LC0xMjkuNzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iOTEuMDUsLTEyNi44MiA4MC43OCwtMTI0LjE5IDg3LjE2LC0xMzIuNjUgOTEuMDUsLTEyNi44MiIvPgo8L2c+CjwhLS0gdGVzdF8xNTEgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNTE8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjNjZhN2RiIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOC41LC0xMjQgMTExLjUsLTEyNCAxMTEuNSwtODggMjA4LjUsLTg4IDIwOC41LC0xMjQiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTYwIiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+cmV0dXJuIHN1bTwvdGV4dD4KPC9nPgo8IS0tIHRlc3RfMTQ0JiM0NTsmZ3Q7dGVzdF8xNTEgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE1MTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNjAsLTE1OS43QzE2MCwtMTUxLjk4IDE2MCwtMTQyLjcxIDE2MCwtMTM0LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2My41LC0xMzQuMSAxNjAsLTEyNC4xIDE1Ni41LC0xMzQuMSAxNjMuNSwtMTM0LjEiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPnRlc3RfMTQ4PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxODMuNSwtNTIgNjAuNSwtNTIgNjAuNSwtMTYgMTgzLjUsLTE2IDE4My41LC01MiIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIiIHk9Ii0zMC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnN1bSA9IHN1bSArIGk8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0NiYjNDU7Jmd0O3Rlc3RfMTQ4IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPnRlc3RfMTQ2JiM0NTsmZ3Q7dGVzdF8xNDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuNTYsLTg3LjdDNzkuNjgsLTc5LjIyIDg5LjU5LC02OC44NiA5OC40NywtNTkuNTgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAxLjI0LC02MS43NSAxMDUuNjMsLTUyLjEgOTYuMTksLTU2LjkxIDEwMS4yNCwtNjEuNzUiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4JiM0NTsmZ3Q7dGVzdF8xNDQgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDgmIzQ1OyZndDt0ZXN0XzE0NDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzUuMjIsLTUyLjA0QzE5MS44OSwtNjAuMTYgMjA4LjQyLC03MS43NyAyMTgsLTg4IDIyNi4xMywtMTAxLjc4IDIyNC40NSwtMTA5LjM2IDIxOCwtMTI0IDIxMy4wMSwtMTM1LjMxIDIwNC4yOSwtMTQ1LjI2IDE5NS4xLC0xNTMuMzgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTkyLjgzLC0xNTAuNzIgMTg3LjM0LC0xNTkuNzcgMTk3LjI4LC0xNTYuMTIgMTkyLjgzLC0xNTAuNzIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8453:(i,e,t)=>{t.d(e,{R:()=>I,x:()=>d});var n=t(6540);const s={},l=n.createContext(s);function I(i){const e=n.useContext(l);return n.useMemo((function(){return"function"==typeof i?i(e):{...e,...i}}),[e,i])}function d(i){let e;return e=i.disableParentContext?"function"==typeof i.components?i.components(s):i.components||s:I(i.components),n.createElement(l.Provider,{value:e},i.children)}}}]); \ No newline at end of file diff --git a/assets/js/393be207.fc96af0e.js b/assets/js/393be207.fc96af0e.js new file mode 100644 index 000000000..d58aab05e --- /dev/null +++ b/assets/js/393be207.fc96af0e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4134],{633:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>p,default:()=>l,frontMatter:()=>r,metadata:()=>s,toc:()=>i});var o=t(4848),a=t(8453);const r={title:"Markdown page example"},p="Markdown page example",s={type:"mdx",permalink:"/markdown-page",source:"@site/src/pages/markdown-page.md",title:"Markdown page example",description:"You don't need React to write simple standalone pages.",frontMatter:{title:"Markdown page example"},unlisted:!1},c={},i=[];function d(e){const n={h1:"h1",p:"p",...(0,a.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"markdown-page-example",children:"Markdown page example"}),"\n",(0,o.jsx)(n.p,{children:"You don't need React to write simple standalone pages."})]})}function l(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>p,x:()=>s});var o=t(6540);const a={},r=o.createContext(a);function p(e){const n=o.useContext(r);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:p(e.components),o.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/3b3a1a75.976ba85c.js b/assets/js/3b3a1a75.976ba85c.js new file mode 100644 index 000000000..f208b02f4 --- /dev/null +++ b/assets/js/3b3a1a75.976ba85c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2478],{4727:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>r,toc:()=>l});var s=n(4848),o=n(8453);const a={},i="ArgCopyMutation",r={id:"detectors/ArgCopyMutation",title:"ArgCopyMutation",description:"A detector that highlights cases where function argument mutations are ineffective",source:"@site/versioned_docs/version-0.4.0/detectors/ArgCopyMutation.md",sourceDirName:"detectors",slug:"/detectors/ArgCopyMutation",permalink:"/tools/misti/docs/detectors/ArgCopyMutation",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/ArgCopyMutation.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Detectors Overview",permalink:"/tools/misti/docs/detectors"},next:{title:"AsmIsUsed",permalink:"/tools/misti/docs/detectors/AsmIsUsed"}},c={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function d(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"argcopymutation",children:"ArgCopyMutation"}),"\n",(0,s.jsxs)(t.p,{children:["A detector that highlights cases where function argument mutations are ineffective\ndue to ",(0,s.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value",children:"call-by-value semantics"})," in Tact."]}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"In Tact, function arguments are passed by value, meaning that any mutations applied\nto these arguments will only affect the local copy of the variable within the function.\nSuch mutations are unobservable outside the function, except for potentially\nincreasing gas consumption or causing exceptions."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"fun addEntry(m: map<Int,Int>) {\n m.set(1, 10); // Bad: Mutating the copy\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"fun addEntry() {\n self.m.set(1, 10); // OK: Changing contract's state\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Alternatively, you could redesign the method:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"fun generateNewValue(): Int {\n // ... produce new value for the map\n return self.nextValue + 1;\n}\n\nm.set(self.nextKey, self.generateNewValue()); // OK\n"})})]})}function u(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>r});var s=n(6540);const o={},a=s.createContext(o);function i(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:i(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/3bfe497f.a61d7e8b.js b/assets/js/3bfe497f.a61d7e8b.js new file mode 100644 index 000000000..dcfd8a961 --- /dev/null +++ b/assets/js/3bfe497f.a61d7e8b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5381],{4512:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var n=i(4848),s=i(8453);const r={},o="DivideBeforeMultiply",l={id:"detectors/DivideBeforeMultiply",title:"DivideBeforeMultiply",description:"A detector that identifies and corrects instances of division before multiplication to",source:"@site/versioned_docs/version-0.4.0/detectors/DivideBeforeMultiply.md",sourceDirName:"detectors",slug:"/detectors/DivideBeforeMultiply",permalink:"/tools/misti/docs/detectors/DivideBeforeMultiply",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/DivideBeforeMultiply.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"ConstantAddress",permalink:"/tools/misti/docs/detectors/ConstantAddress"},next:{title:"DumpIsUsed",permalink:"/tools/misti/docs/detectors/DumpIsUsed"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function a(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"dividebeforemultiply",children:"DivideBeforeMultiply"}),"\n",(0,n.jsx)(t.p,{children:"A detector that identifies and corrects instances of division before multiplication to\nensure accurate mathematical operations."}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Precision Loss:"})," Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers."]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Rounding Errors:"})," Early division might cause rounding errors that propagate through subsequent calculations."]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.strong,{children:"Unexpected Behavior:"})," Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging."]}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Bad: Division before multiplication\nlet result: Int = a / b * c;\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Correct: Multiplication before division\nlet result: Int = a * c / b;\n"})})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(a,{...e})}):a(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>o,x:()=>l});var n=i(6540);const s={},r=n.createContext(s);function o(e){const t=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/3db5102b.08380390.js b/assets/js/3db5102b.08380390.js new file mode 100644 index 000000000..706c5a887 --- /dev/null +++ b/assets/js/3db5102b.08380390.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6774],{6931:(t,n,e)=>{e.r(n),e.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>u});var i=e(4848),o=e(8453);const s={},r="Integrating Misti into CI/CD",c={id:"tutorial/ci-cd",title:"Integrating Misti into CI/CD",description:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.",source:"@site/versioned_docs/version-0.2.1/tutorial/ci-cd.md",sourceDirName:"tutorial",slug:"/tutorial/ci-cd",permalink:"/tools/misti/docs/0.2.1/tutorial/ci-cd",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/tutorial/ci-cd.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Getting Started",permalink:"/tools/misti/docs/0.2.1/tutorial/getting-started"},next:{title:"Configuration",permalink:"/tools/misti/docs/0.2.1/tutorial/configuration"}},a={},u=[{value:"GitHub Actions",id:"github-actions",level:2}];function l(t){const n={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,o.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"integrating-misti-into-cicd",children:"Integrating Misti into CI/CD"}),"\n",(0,i.jsx)(n.p,{children:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle."}),"\n",(0,i.jsx)(n.h2,{id:"github-actions",children:"GitHub Actions"}),"\n",(0,i.jsx)(n.p,{children:"To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"1. Open your GitHub repository"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"2. Create or edit the GitHub Actions workflow YAML file"})}),"\n",(0,i.jsxs)(n.p,{children:["It could be located at e.g., ",(0,i.jsx)(n.code,{children:".github/workflows/main.yml"}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"3. Add the step to run Misti to your YAML file"})}),"\n",(0,i.jsx)(n.p,{children:"For example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"name: Run Misti\non: [push, pull_request]\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v2\n\n - name: Install dependencies\n run: npm install\n\n - name: Run Misti\n run: npx misti /path/to/your/tact.config.json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"npx misti /path/to/your/tact.config.json"})," command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"4. Adjusting the Misti Configuration"})}),"\n",(0,i.jsxs)(n.p,{children:["If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the ",(0,i.jsx)(n.a,{href:"./configuration",children:"Configuration"})," section for more details on how to customize your settings."]})]})}function d(t={}){const{wrapper:n}={...(0,o.R)(),...t.components};return n?(0,i.jsx)(n,{...t,children:(0,i.jsx)(l,{...t})}):l(t)}},8453:(t,n,e)=>{e.d(n,{R:()=>r,x:()=>c});var i=e(6540);const o={},s=i.createContext(o);function r(t){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof t?t(n):{...n,...t}}),[n,t])}function c(t){let n;return n=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:r(t.components),i.createElement(s.Provider,{value:n},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/40be7dfa.be7d2a62.js b/assets/js/40be7dfa.be7d2a62.js new file mode 100644 index 000000000..f7bd65463 --- /dev/null +++ b/assets/js/40be7dfa.be7d2a62.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6602],{7991:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var i=n(4848),s=n(8453);const o={id:"intro",title:"Introduction",slug:"/",sidebar_position:1},r=void 0,a={id:"intro",title:"Introduction",description:"Misti is a static analysis tool designed for smart contracts on the TON blockchain.",source:"@site/versioned_docs/version-0.2.0/index.md",sourceDirName:".",slug:"/",permalink:"/tools/misti/docs/0.2.0/",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/index.md",tags:[],version:"0.2.0",sidebarPosition:1,frontMatter:{id:"intro",title:"Introduction",slug:"/",sidebar_position:1},sidebar:"sidebar",next:{title:"Getting Started",permalink:"/tools/misti/docs/0.2.0/tutorial/getting-started"}},c={},d=[{value:"Use Cases",id:"use-cases",level:2},{value:"Funding",id:"funding",level:2}];function l(e){const t={a:"a",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Misti is a static analysis tool designed for smart contracts on the ",(0,i.jsx)(t.a,{href:"https://ton.org/",children:"TON blockchain"}),"."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Language Support:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://tact-lang.org/",children:"Tact"})," 1.4.4 is supported."]}),"\n",(0,i.jsxs)(t.li,{children:["Support for ",(0,i.jsx)(t.a,{href:"https://docs.ton.org/develop/func/overview",children:"FunC"})," ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/56",children:"is planned"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,i.jsx)(t.p,{children:"Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Detect Vulnerabilities:"})," Identify and fix potential security flaws early in the development cycle."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Improve Code Quality:"})," Maintain high standards by catching bugs and enforcing best practices automatically."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Streamline Development:"})," Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Custom Detectors:"})," Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow."}),"\n",(0,i.jsx)(t.h2,{id:"funding",children:"Funding"}),"\n",(0,i.jsxs)(t.p,{children:["Misti has been ",(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/436",children:"funded"})," by ",(0,i.jsx)(t.a,{href:"https://ton.foundation",children:"TON Foundation"}),". This support has enabled us to develop and maintain the tool."]})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/42510f93.7a5b306e.js b/assets/js/42510f93.7a5b306e.js new file mode 100644 index 000000000..d120a5e5f --- /dev/null +++ b/assets/js/42510f93.7a5b306e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2913],{5875:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var i=n(4848),s=n(8453);const r={},o="Developing Misti",a={id:"hacking/developing-misti",title:"Developing Misti",description:"Prerequisites",source:"@site/versioned_docs/version-0.4.0/hacking/developing-misti.md",sourceDirName:"hacking",slug:"/hacking/developing-misti",permalink:"/tools/misti/docs/hacking/developing-misti",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/hacking/developing-misti.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Contributing",permalink:"/tools/misti/docs/hacking/contributing"},next:{title:"Design Overview",permalink:"/tools/misti/docs/hacking/design"}},c={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Cloning the Repository",id:"cloning-the-repository",level:2},{value:"Building the Project",id:"building-the-project",level:2},{value:"Running the Analyzer",id:"running-the-analyzer",level:2},{value:"Adding Backtraces to the Logger",id:"adding-backtraces-to-the-logger",level:2},{value:"Updating Expected Outputs of Tests",id:"updating-expected-outputs-of-tests",level:2}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"developing-misti",children:"Developing Misti"}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(t.p,{children:["Before you begin, please refer to the ",(0,i.jsx)(t.a,{href:"https://nowarp.io/tools/misti/docs/next/tutorial/getting-started",children:"Getting Started documentation"})," for the required system dependencies."]}),"\n",(0,i.jsx)(t.h2,{id:"cloning-the-repository",children:"Cloning the Repository"}),"\n",(0,i.jsx)(t.p,{children:"Clone the Misti repository:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"git clone 'https://github.com/nowarp/misti'\n"})}),"\n",(0,i.jsx)(t.h2,{id:"building-the-project",children:"Building the Project"}),"\n",(0,i.jsx)(t.p,{children:"Navigate to the project directory, install dependencies, generate necessary files, and build the project:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"cd misti && yarn install && yarn gen && yarn build\n"})}),"\n",(0,i.jsx)(t.h2,{id:"running-the-analyzer",children:"Running the Analyzer"}),"\n",(0,i.jsx)(t.p,{children:"During development, you can run the analyzer using:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"yarn misti\n"})}),"\n",(0,i.jsx)(t.p,{children:"For example, to run it for tests:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"yarn misti test/good/never-accessed.tact\n"})}),"\n",(0,i.jsx)(t.h2,{id:"adding-backtraces-to-the-logger",children:"Adding Backtraces to the Logger"}),"\n",(0,i.jsxs)(t.p,{children:["To add debug traces to all log messages, set the ",(0,i.jsx)(t.code,{children:"MISTI_TRACE"})," environment variable to ",(0,i.jsx)(t.code,{children:"1"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"export MISTI_TRACE=1\n"})}),"\n",(0,i.jsx)(t.h2,{id:"updating-expected-outputs-of-tests",children:"Updating Expected Outputs of Tests"}),"\n",(0,i.jsxs)(t.p,{children:["To update the expected outputs of tests, set the ",(0,i.jsx)(t.code,{children:"BLESS"})," environment variable and run the tests:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test\n"})}),"\n",(0,i.jsx)(t.p,{children:"You can also run a single test or update its expected output when working with a specific test file:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test test/tactIR.spec.ts tests/good/never-accessed.tact\n"})}),"\n",(0,i.jsx)(t.p,{children:"And for another specific test:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test test/builtinDetectors.spec.ts test/good/branch-duplicate.tact\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var i=n(6540);const s={},r=i.createContext(s);function o(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/432cb5a5.17016576.js b/assets/js/432cb5a5.17016576.js new file mode 100644 index 000000000..ef1203a82 --- /dev/null +++ b/assets/js/432cb5a5.17016576.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3840],{4303:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>l,toc:()=>c});var s=n(4848),a=n(8453);const t={},o="Design Overview",l={id:"hacking/design",title:"Design Overview",description:"Static Analysis",source:"@site/versioned_docs/version-0.4.0/hacking/design.md",sourceDirName:"hacking",slug:"/hacking/design",permalink:"/tools/misti/docs/hacking/design",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/hacking/design.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Developing Misti",permalink:"/tools/misti/docs/hacking/developing-misti"},next:{title:"Souffl\xe9",permalink:"/tools/misti/docs/hacking/souffle"}},r={},c=[{value:"Static Analysis",id:"static-analysis",level:2},{value:"Souffle Datalog Solver",id:"souffle-datalog-solver",level:2},{value:"Dataflow Analysis in Misti",id:"dataflow-analysis-in-misti",level:2},{value:"References",id:"references",level:2}];function d(e){const i={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"design-overview",children:"Design Overview"}),"\n",(0,s.jsx)(i.h2,{id:"static-analysis",children:"Static Analysis"}),"\n",(0,s.jsx)(i.p,{children:"Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues."}),"\n",(0,s.jsx)(i.h2,{id:"souffle-datalog-solver",children:"Souffle Datalog Solver"}),"\n",(0,s.jsxs)(i.p,{children:["Misti leverages the ",(0,s.jsx)(i.a,{href:"https://souffle-lang.github.io",children:"Souffle Datalog solver"}),", an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases."]}),"\n",(0,s.jsx)(i.h2,{id:"dataflow-analysis-in-misti",children:"Dataflow Analysis in Misti"}),"\n",(0,s.jsx)(i.p,{children:"Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code."}),"\n",(0,s.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,s.jsx)(i.p,{children:"For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.a,{href:"https://cs.au.dk/~amoeller/spa/spa.pdf",children:"Anders M\xf8ller and Michael I. Schwartzbach \u2013 Static Program Analysis"})}),"\n",(0,s.jsx)(i.li,{children:"Uday Khedker et al. \u2013 Data Flow Analysis: Theory and Practice"}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"These resources provide a solid foundation in the theory and practice of static and dataflow analysis."})]})}function h(e={}){const{wrapper:i}={...(0,a.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>o,x:()=>l});var s=n(6540);const a={},t=s.createContext(a);function o(e){const i=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:o(e.components),s.createElement(t.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/43c93918.b3c5c4ff.js b/assets/js/43c93918.b3c5c4ff.js new file mode 100644 index 000000000..e97ab7b8b --- /dev/null +++ b/assets/js/43c93918.b3c5c4ff.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1299],{955:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var i=n(4848),s=n(8453);const o={id:"intro",title:"Introduction",slug:"/",sidebar_position:1},r=void 0,a={id:"intro",title:"Introduction",description:"Misti is a static analysis tool designed for smart contracts on the TON blockchain.",source:"@site/versioned_docs/version-0.3.1/index.md",sourceDirName:".",slug:"/",permalink:"/tools/misti/docs/0.3.1/",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/index.md",tags:[],version:"0.3.1",sidebarPosition:1,frontMatter:{id:"intro",title:"Introduction",slug:"/",sidebar_position:1},sidebar:"sidebar",next:{title:"Getting Started",permalink:"/tools/misti/docs/0.3.1/tutorial/getting-started"}},c={},d=[{value:"Use Cases",id:"use-cases",level:2},{value:"Name Origin",id:"name-origin",level:2},{value:"Funding",id:"funding",level:2}];function l(e){const t={a:"a",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Misti is a static analysis tool designed for smart contracts on the ",(0,i.jsx)(t.a,{href:"https://ton.org/",children:"TON blockchain"}),"."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Language Support:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://tact-lang.org/",children:"Tact"})," 1.5 is supported."]}),"\n",(0,i.jsxs)(t.li,{children:["Support for ",(0,i.jsx)(t.a,{href:"https://docs.ton.org/develop/func/overview",children:"FunC"})," ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/56",children:"is planned"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,i.jsx)(t.p,{children:"Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Detect Vulnerabilities:"})," Identify and fix potential security flaws early in the development cycle."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Improve Code Quality:"})," Maintain high standards by catching bugs and enforcing best practices automatically."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Streamline Development:"})," Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Custom Detectors:"})," Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow."}),"\n",(0,i.jsx)(t.h2,{id:"name-origin",children:"Name Origin"}),"\n",(0,i.jsx)(t.p,{children:'The name "Misti" comes from the Misti volcano in Peru. It was chosen because it\'s catchy and easy to remember.'}),"\n",(0,i.jsx)(t.h2,{id:"funding",children:"Funding"}),"\n",(0,i.jsxs)(t.p,{children:["Misti has been ",(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/436",children:"funded"})," by ",(0,i.jsx)(t.a,{href:"https://ton.foundation",children:"TON Foundation"}),". This support has enabled us to develop and maintain the tool."]})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4518efa7.b9ef0cc5.js b/assets/js/4518efa7.b9ef0cc5.js new file mode 100644 index 000000000..c70bbf268 --- /dev/null +++ b/assets/js/4518efa7.b9ef0cc5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6544],{2308:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>p,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),i=n(8453);const r={},c="Branch Duplicate",o={id:"detectors/BranchDuplicate",title:"Branch Duplicate",description:"Detector that reports duplicated code in conditional branches.",source:"@site/versioned_docs/version-0.2.2/detectors/BranchDuplicate.md",sourceDirName:"detectors",slug:"/detectors/BranchDuplicate",permalink:"/tools/misti/docs/0.2.2/detectors/BranchDuplicate",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/BranchDuplicate.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Constant Address",permalink:"/tools/misti/docs/0.2.2/detectors/ConstantAddress"},next:{title:"`dump` Is Used",permalink:"/tools/misti/docs/0.2.2/detectors/DumpIsUsed"}},a={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"branch-duplicate",children:"Branch Duplicate"}),"\n",(0,s.jsx)(t.p,{children:"Detector that reports duplicated code in conditional branches."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Duplicated code in branches is bad because it:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Reduces Readability"}),": Repetition makes the code harder to understand."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Increases Maintenance"}),": Changes must be made in multiple places, risking errors."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Signals Poor Design"}),": It suggests missed opportunities for cleaner, more abstract code."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = 43; // bad: duplicated code\n} else {\n a = 43;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = inc(b); // ok\n} else {\n a = 43;\n}\n"})})]})}function p(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>o});var s=n(6540);const i={},r=s.createContext(i);function c(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:c(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/474ce197.29e1c442.js b/assets/js/474ce197.29e1c442.js new file mode 100644 index 000000000..615c99e26 --- /dev/null +++ b/assets/js/474ce197.29e1c442.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4069],{7715:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.2.1","label":"0.2.1","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.2.1","isLast":false,"docsSidebars":{"sidebar":[{"type":"link","label":"Introduction","href":"/tools/misti/docs/0.2.1/","docId":"intro","unlisted":false},{"type":"category","label":"Tutorial","items":[{"type":"link","label":"Getting Started","href":"/tools/misti/docs/0.2.1/tutorial/getting-started","docId":"tutorial/getting-started","unlisted":false},{"type":"link","label":"CI/CD Integration","href":"/tools/misti/docs/0.2.1/tutorial/ci-cd","docId":"tutorial/ci-cd","unlisted":false},{"type":"link","label":"Configuration","href":"/tools/misti/docs/0.2.1/tutorial/configuration","docId":"tutorial/configuration","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Detectors Overview","href":"/tools/misti/docs/0.2.1/detectors","docId":"detectors","unlisted":false},{"type":"category","label":"Detectors","items":[{"type":"link","label":"Divide before Multiply","href":"/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply","docId":"detectors/DivideBeforeMultiply","unlisted":false},{"type":"link","label":"Never-accessed Variables","href":"/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables","docId":"detectors/NeverAccessedVariables","unlisted":false},{"type":"link","label":"Read-only Variables","href":"/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables","docId":"detectors/ReadOnlyVariables","unlisted":false},{"type":"link","label":"Unbound Loops","href":"/tools/misti/docs/0.2.1/detectors/UnboundLoops","docId":"detectors/UnboundLoops","unlisted":false},{"type":"link","label":"Zero Address","href":"/tools/misti/docs/0.2.1/detectors/ZeroAddress","docId":"detectors/ZeroAddress","unlisted":false},{"type":"link","label":"Constant Address","href":"/tools/misti/docs/0.2.1/detectors/ConstantAddress","docId":"detectors/ConstantAddress","unlisted":false},{"type":"link","label":"Branch Duplicate","href":"/tools/misti/docs/0.2.1/detectors/BranchDuplicate","docId":"detectors/BranchDuplicate","unlisted":false},{"type":"link","label":"`dump` Is Used","href":"/tools/misti/docs/0.2.1/detectors/DumpIsUsed","docId":"detectors/DumpIsUsed","unlisted":false},{"type":"link","label":"Field Initialized Twice","href":"/tools/misti/docs/0.2.1/detectors/FieldDoubleInit","docId":"detectors/FieldDoubleInit","unlisted":false},{"type":"link","label":"Prefer Augmented Assignment","href":"/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign","docId":"detectors/PreferAugmentedAssign","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacking","items":[{"type":"link","label":"Contributing","href":"/tools/misti/docs/0.2.1/hacking/contributing","docId":"hacking/contributing","unlisted":false},{"type":"link","label":"Design Overview","href":"/tools/misti/docs/0.2.1/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/0.2.1/hacking/souffle","docId":"hacking/souffle","unlisted":false},{"type":"link","label":"Tools","href":"/tools/misti/docs/0.2.1/hacking/tools","docId":"hacking/tools","unlisted":false},{"type":"link","label":"Custom Detectors","href":"/tools/misti/docs/0.2.1/hacking/custom-detector","docId":"hacking/custom-detector","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"detectors":{"id":"detectors","title":"Detectors Overview","description":"Here\'s a list of all the detectors:","sidebar":"sidebar"},"detectors/BranchDuplicate":{"id":"detectors/BranchDuplicate","title":"Branch Duplicate","description":"Detector that reports duplicated code in conditional branches.","sidebar":"sidebar"},"detectors/ConstantAddress":{"id":"detectors/ConstantAddress","title":"Constant Address","description":"An optional detector that highlights all the constant addresses appearing in the source code.","sidebar":"sidebar"},"detectors/DivideBeforeMultiply":{"id":"detectors/DivideBeforeMultiply","title":"Divide before Multiply","description":"A detector that identifies and corrects instances of division before multiplication to","sidebar":"sidebar"},"detectors/DumpIsUsed":{"id":"detectors/DumpIsUsed","title":"dump Is Used","description":"An optional detector that highlights all the dump function calls.","sidebar":"sidebar"},"detectors/FieldDoubleInit":{"id":"detectors/FieldDoubleInit","title":"Field Initialized Twice","description":"A detector that highlights cases where a field is initialized both in the init function and at the point of definition.","sidebar":"sidebar"},"detectors/NeverAccessedVariables":{"id":"detectors/NeverAccessedVariables","title":"Never-accessed Variables","description":"A detector that identifies write-only or unused variables, fields and constants.","sidebar":"sidebar"},"detectors/PreferAugmentedAssign":{"id":"detectors/PreferAugmentedAssign","title":"Prefer Augmented Assignment","description":"Detects non-idiomatic statements that can be written using augmented assignment operators like +=, -=, etc.","sidebar":"sidebar"},"detectors/ReadOnlyVariables":{"id":"detectors/ReadOnlyVariables","title":"Read-only Variables","description":"A detector that identifies read-only variables and fields.","sidebar":"sidebar"},"detectors/UnboundLoops":{"id":"detectors/UnboundLoops","title":"Unbound Loops","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/ZeroAddress":{"id":"detectors/ZeroAddress","title":"Zero Address","description":"A detector that identifies uses of the zero address.","sidebar":"sidebar"},"hacking/contributing":{"id":"hacking/contributing","title":"Contributing Guide","description":"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.","sidebar":"sidebar"},"hacking/custom-detector":{"id":"hacking/custom-detector","title":"Custom Detector Guide","description":"Introduction","sidebar":"sidebar"},"hacking/design":{"id":"hacking/design","title":"Design Overview","description":"Static Analysis","sidebar":"sidebar"},"hacking/souffle":{"id":"hacking/souffle","title":"Souffl\xe9 Integration Guide","description":"What is Souffl\xe9?","sidebar":"sidebar"},"hacking/tools":{"id":"hacking/tools","title":"Tools Guide","description":"This page describes the internal analyzer tools available in Misti to aid in development and debugging.","sidebar":"sidebar"},"intro":{"id":"intro","title":"Introduction","description":"Misti is a static analysis tool designed for smart contracts on the TON blockchain.","sidebar":"sidebar"},"tutorial/ci-cd":{"id":"tutorial/ci-cd","title":"Integrating Misti into CI/CD","description":"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.","sidebar":"sidebar"},"tutorial/configuration":{"id":"tutorial/configuration","title":"Configuration","description":"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.","sidebar":"sidebar"},"tutorial/getting-started":{"id":"tutorial/getting-started","title":"Getting started","description":"This guide will walk you through the steps to install and set up the Misti static analyzer.","sidebar":"sidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/49256311.be5c404d.js b/assets/js/49256311.be5c404d.js new file mode 100644 index 000000000..bd5aea274 --- /dev/null +++ b/assets/js/49256311.be5c404d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2734],{9475:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var s=n(4848),o=n(8453);const r={},d="ConstantAddress",a={id:"detectors/ConstantAddress",title:"ConstantAddress",description:"An optional detector that highlights all the constant addresses appearing in the source code.",source:"@site/versioned_docs/version-0.3.1/detectors/ConstantAddress.md",sourceDirName:"detectors",slug:"/detectors/ConstantAddress",permalink:"/tools/misti/docs/0.3.1/detectors/ConstantAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/ConstantAddress.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"BranchDuplicate",permalink:"/tools/misti/docs/0.3.1/detectors/BranchDuplicate"},next:{title:"DivideBeforeMultiply",permalink:"/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply"}},i={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"constantaddress",children:"ConstantAddress"}),"\n",(0,s.jsx)(t.p,{children:"An optional detector that highlights all the constant addresses appearing in the source code."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsxs)(t.p,{children:["Using hardcoded addresses can sometimes indicate poor contract design.\nSome constant addresses may need to be set dynamically, e.g., using\n",(0,s.jsx)(t.code,{children:"contractAddress"}),", or at least have a way to change them at runtime, for\nexample, when upgrading a contract."]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'contract Main {\n proxy: Address;\n init() {\n // Bad: Constant address highlighted by the analyzer.\n self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");\n }\n}\n'})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"contract Main {\n proxy: Address;\n init() {\n let proxy: Proxy = initOf Proxy(myAddress());\n // OK: Address depends on how the proxy contact has been deployed\n self.proxy = contractAddress(proxy);\n }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>a});var s=n(6540);const o={},r=s.createContext(o);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4ab26116.4e3dc2f6.js b/assets/js/4ab26116.4e3dc2f6.js new file mode 100644 index 000000000..d9a3e7c8f --- /dev/null +++ b/assets/js/4ab26116.4e3dc2f6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9276],{1857:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var s=n(4848),o=n(8453);const r={},d="ConstantAddress",a={id:"detectors/ConstantAddress",title:"ConstantAddress",description:"An optional detector that highlights all the constant addresses appearing in the source code.",source:"@site/versioned_docs/version-0.4.0/detectors/ConstantAddress.md",sourceDirName:"detectors",slug:"/detectors/ConstantAddress",permalink:"/tools/misti/docs/detectors/ConstantAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/ConstantAddress.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"BranchDuplicate",permalink:"/tools/misti/docs/detectors/BranchDuplicate"},next:{title:"DivideBeforeMultiply",permalink:"/tools/misti/docs/detectors/DivideBeforeMultiply"}},i={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"constantaddress",children:"ConstantAddress"}),"\n",(0,s.jsx)(t.p,{children:"An optional detector that highlights all the constant addresses appearing in the source code."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsxs)(t.p,{children:["Using hardcoded addresses can sometimes indicate poor contract design.\nSome constant addresses may need to be set dynamically, e.g., using\n",(0,s.jsx)(t.code,{children:"contractAddress"}),", or at least have a way to change them at runtime, for\nexample, when upgrading a contract."]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'contract Main {\n proxy: Address;\n init() {\n // Bad: Constant address highlighted by the analyzer.\n self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");\n }\n}\n'})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"contract Main {\n proxy: Address;\n init() {\n let proxy: Proxy = initOf Proxy(myAddress());\n // OK: Address depends on how the proxy contact has been deployed\n self.proxy = contractAddress(proxy);\n }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>a});var s=n(6540);const o={},r=s.createContext(o);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4b89306f.efdf0920.js b/assets/js/4b89306f.efdf0920.js new file mode 100644 index 000000000..44f92da7b --- /dev/null +++ b/assets/js/4b89306f.efdf0920.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6769],{1821:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>f});var t=i(4848),r=i(8453);const s={},a="Souffl\xe9 Integration Guide",o={id:"hacking/souffle",title:"Souffl\xe9 Integration Guide",description:"What is Souffl\xe9?",source:"@site/versioned_docs/version-0.3.1/hacking/souffle.md",sourceDirName:"hacking",slug:"/hacking/souffle",permalink:"/tools/misti/docs/0.3.1/hacking/souffle",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/hacking/souffle.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Design Overview",permalink:"/tools/misti/docs/0.3.1/hacking/design"},next:{title:"Tools",permalink:"/tools/misti/docs/0.3.1/hacking/tools"}},l={},f=[{value:"What is Souffl\xe9?",id:"what-is-souffl\xe9",level:2},{value:"Benefits of Using Souffl\xe9 for Static Analysis",id:"benefits-of-using-souffl\xe9-for-static-analysis",level:2},{value:"Souffl\xe9 Integration in Misti",id:"souffl\xe9-integration-in-misti",level:2},{value:"Creating Souffl\xe9 Programs",id:"creating-souffl\xe9-programs",level:3},{value:"Generating Facts and Executing Souffl\xe9",id:"generating-facts-and-executing-souffl\xe9",level:3},{value:"Learning from Existing Code",id:"learning-from-existing-code",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"souffl\xe9-integration-guide",children:"Souffl\xe9 Integration Guide"}),"\n",(0,t.jsx)(n.h2,{id:"what-is-souffl\xe9",children:"What is Souffl\xe9?"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io",children:"Souffl\xe9"})," is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Souffl\xe9, Misti can perform deep and scalable analyses of smart contracts."]}),"\n",(0,t.jsx)(n.h2,{id:"benefits-of-using-souffl\xe9-for-static-analysis",children:"Benefits of Using Souffl\xe9 for Static Analysis"}),"\n",(0,t.jsx)(n.p,{children:"Souffl\xe9 allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Souffl\xe9 program might be more straightforward then implementing a complex transfer function in for a classic monotone framework."}),"\n",(0,t.jsx)(n.h2,{id:"souffl\xe9-integration-in-misti",children:"Souffl\xe9 Integration in Misti"}),"\n",(0,t.jsxs)(n.p,{children:["The API for interacting with Souffl\xe9 in Misti is implemented in the ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/souffle.js",children:"Souffle.js library"}),". See the ",(0,t.jsx)(n.a,{href:"https://nowarp.io/lib/souffle-js/api/",children:"Souffle.js API reference"})," for more detailed information."]}),"\n",(0,t.jsx)(n.h3,{id:"creating-souffl\xe9-programs",children:"Creating Souffl\xe9 Programs"}),"\n",(0,t.jsx)(n.p,{children:'To create a Souffl\xe9 program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:'}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addDecls(ctx: Context<SrcInfo>) {\n ctx.add(\n Relation.from(\n "varDecl",\n [\n ["var", FactType.Symbol],\n ["func", FactType.Symbol],\n ],\n undefined,\n ),\n );\n // other declarations\n}\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addRules(ctx: Context<SrcInfo>) {\n // readOnly(var, func) :-\n // varDecl(var, func),\n // !varAssign(var, func),\n // !varUse(var, func).\n ctx.add(\n Rule.from(\n [makeAtom("readOnly", ["var", "func"])],\n makeRuleBody(makeAtom("varDecl", ["var", "func"])),\n makeRuleBody(makeAtom("varAssign", ["var", "func"]), {\n negated: true,\n }),\n makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),\n ),\n );\n }\n'})}),"\n",(0,t.jsx)(n.h3,{id:"generating-facts-and-executing-souffl\xe9",children:"Generating Facts and Executing Souffl\xe9"}),"\n",(0,t.jsx)(n.p,{children:"After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Souffl\xe9 executor to run the analysis:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"const executor = ctx.config.soufflePath\n ? new Executor<SrcInfo>({\n inputDir: ctx.config.soufflePath,\n outputDir: ctx.config.soufflePath,\n })\n : new Executor<SrcInfo>();\n\nconst result = executor.executeSync(program);\n\nif (!result.success) {\n throw new Error(\n `Error executing Souffl\xe9 for ${this.id}:\\n${result.stderr}`,\n );\n}\n\nconst warnings = Array.from(result.results.entries.values()).map((fact) => {\n // raise warnings\n});\n"})}),"\n",(0,t.jsx)(n.h3,{id:"learning-from-existing-code",children:"Learning from Existing Code"}),"\n",(0,t.jsx)(n.p,{children:"We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Souffl\xe9 with Misti. This will help you understand the intricacies of generating IR and executing Souffl\xe9 programs effectively."}),"\n",(0,t.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,t.jsxs)(n.p,{children:["For a deeper understanding of static analysis using Souffl\xe9, refer to the textbook ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.a,{href:"https://arxiv.org/pdf/2012.10086",children:"Program Analysis: An Appetizer"})})," by Flemming Nielson and Hanne Riis Nielson. It discusses Souffl\xe9-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field."]})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>a,x:()=>o});var t=i(6540);const r={},s=t.createContext(r);function a(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4d74b396.8aebea31.js b/assets/js/4d74b396.8aebea31.js new file mode 100644 index 000000000..34cece6f8 --- /dev/null +++ b/assets/js/4d74b396.8aebea31.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9802],{1167:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var a=t(4848),i=t(8453);const r={},s="Read-only Variables",o={id:"detectors/ReadOnlyVariables",title:"Read-only Variables",description:"A detector that identifies read-only variables and fields.",source:"@site/versioned_docs/version-0.2.1/detectors/ReadOnlyVariables.md",sourceDirName:"detectors",slug:"/detectors/ReadOnlyVariables",permalink:"/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/ReadOnlyVariables.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Never-accessed Variables",permalink:"/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables"},next:{title:"Unbound Loops",permalink:"/tools/misti/docs/0.2.1/detectors/UnboundLoops"}},l={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.h1,{id:"read-only-variables",children:"Read-only Variables"}),"\n",(0,a.jsx)(n.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,a.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,a.jsx)(n.p,{children:"These variables could typically be replaced with constants to optimize performance.\nAlternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally."}),"\n",(0,a.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-tact",children:"fun calculateFinalPrice(price: Int): Int {\n // Warning: the developer uses a read-only variable that could be a constant\n let DISCOUNT_AMOUNT: Int = 10;\n return price - DISCOUNT_AMOUNT;\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:"Use instead:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-tact",children:"const DISCOUNT_AMOUNT: Int = 10;\n\nfun calculateFinalPrice(price: Int): Int {\n // OK: Fixed after the linter highlighted this warning\n return price - DISCOUNT_AMOUNT;\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>o});var a=t(6540);const i={},r=a.createContext(i);function s(e){const n=a.useContext(r);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),a.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4f2bb7ce.0a476d8d.js b/assets/js/4f2bb7ce.0a476d8d.js new file mode 100644 index 000000000..d8a5608d9 --- /dev/null +++ b/assets/js/4f2bb7ce.0a476d8d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6156],{8867:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>l,frontMatter:()=>r,metadata:()=>c,toc:()=>d});var i=n(4848),o=n(8453);const r={},s="Custom Detector Guide",c={id:"hacking/custom-detector",title:"Custom Detector Guide",description:"Introduction",source:"@site/versioned_docs/version-0.3.1/hacking/custom-detector.md",sourceDirName:"hacking",slug:"/hacking/custom-detector",permalink:"/tools/misti/docs/0.3.1/hacking/custom-detector",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/hacking/custom-detector.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Tools",permalink:"/tools/misti/docs/0.3.1/hacking/tools"}},a={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Creating a Detector",id:"creating-a-detector",level:2},{value:"Testing the detector",id:"testing-the-detector",level:3},{value:"Saving the configuration",id:"saving-the-configuration",level:3},{value:"Example Detectors",id:"example-detectors",level:2}];function h(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"custom-detector-guide",children:"Custom Detector Guide"}),"\n",(0,i.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsxs)(t.p,{children:["Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: ",(0,i.jsx)(t.a,{href:"https://nowarp.io/tools/misti/api/",children:"Misti API Reference"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the ",(0,i.jsx)(t.a,{href:"https://nowarp.io/tools/misti/api/classes/detectors_detector.Detector.html",children:(0,i.jsx)(t.code,{children:"Detector"})})," interface."]}),"\n",(0,i.jsx)(t.h2,{id:"creating-a-detector",children:"Creating a Detector"}),"\n",(0,i.jsxs)(t.p,{children:["You can create a new custom detector by executing Misti with the ",(0,i.jsx)(t.code,{children:"--new-detector"})," option: ",(0,i.jsx)(t.code,{children:"npx misti --new-detector implicitInit"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["This will create the ",(0,i.jsx)(t.code,{children:"implicitInit.ts"})," file, which contains the template code for writing your own custom detector logic leveraging the Misti API."]}),"\n",(0,i.jsx)(t.p,{children:"Here's an example of how to implement a custom detector using Misti API:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-typescript",children:'import { Detector } from "@nowarp/misti/dist/detectors/detector";\nimport { CompilationUnit } from "@nowarp/misti/dist/internals/ir";\nimport {\n MistiTactWarning,\n Severity,\n} from "@nowarp/misti/dist/internals/errors";\n\n/**\n * An example of a custom detector that showcases the usage of the detector API.\n *\n * It reports all the contracts that doesn\'t have an explicit implementation of the init function.\n */\nexport class ImplicitInit extends Detector {\n async check(cu: CompilationUnit): Promise<MistiTactWarning[]> {\n return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {\n if (!cu.findMethodCFGByName(contract.name, "init")) {\n const err = this.makeError(\n `Contract ${contract.name} doesn\'t define an init function`,\n Severity.INFO,\n contract.ref,\n );\n foundErrors.push(err);\n }\n return foundErrors;\n }, [] as MistiTactWarning[]);\n }\n}\n'})}),"\n",(0,i.jsx)(t.h3,{id:"testing-the-detector",children:"Testing the detector"}),"\n",(0,i.jsxs)(t.p,{children:["To run Misti with only your new detector, use the ",(0,i.jsx)(t.code,{children:"--detectors"})," option, specifying the path to the detector and the Detector class name: ",(0,i.jsx)(t.code,{children:"npx misti path/to/your/tact.config.json --detectors path/to/implicitInit.ts:ImplicitInit"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["That's a good way to test the detector on the first run. You could also use the ",(0,i.jsx)(t.code,{children:"--verbose"})," CLI option and set the environment variable ",(0,i.jsx)(t.code,{children:"MISTI_TRACE=1"})," to facilitate debugging."]}),"\n",(0,i.jsx)(t.h3,{id:"saving-the-configuration",children:"Saving the configuration"}),"\n",(0,i.jsx)(t.p,{children:"After testing the detector, you can specify it in your configuration to enable it in future runs. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{children:'{\n "detectors": [\n // Other detectors...\n { "className": "ImplicitInit", "modulePath": "ImplicitInit.ts" }\n ],\n}\n'})}),"\n",(0,i.jsxs)(t.p,{children:["After this, you could run Misti specifying a path to a custom configuration ",(0,i.jsx)(t.code,{children:"npx misti --config path/to/misti.config.json path/to/your/tact.config.json"}),"."]}),"\n",(0,i.jsx)(t.h2,{id:"example-detectors",children:"Example Detectors"}),"\n",(0,i.jsxs)(t.p,{children:["The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/tree/master/examples",children:"examples directory"})," in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors."]})]})}function l(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>c});var i=n(6540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/4fd06f05.45b0f688.js b/assets/js/4fd06f05.45b0f688.js new file mode 100644 index 000000000..95cb00a08 --- /dev/null +++ b/assets/js/4fd06f05.45b0f688.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6948],{7402:(t,n,e)=>{e.r(n),e.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>u});var i=e(4848),o=e(8453);const s={},r="Integrating Misti into CI/CD",c={id:"tutorial/ci-cd",title:"Integrating Misti into CI/CD",description:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.",source:"@site/versioned_docs/version-0.2.0/tutorial/ci-cd.md",sourceDirName:"tutorial",slug:"/tutorial/ci-cd",permalink:"/tools/misti/docs/0.2.0/tutorial/ci-cd",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/tutorial/ci-cd.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Getting Started",permalink:"/tools/misti/docs/0.2.0/tutorial/getting-started"},next:{title:"Configuration",permalink:"/tools/misti/docs/0.2.0/tutorial/configuration"}},a={},u=[{value:"GitHub Actions",id:"github-actions",level:2}];function l(t){const n={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,o.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"integrating-misti-into-cicd",children:"Integrating Misti into CI/CD"}),"\n",(0,i.jsx)(n.p,{children:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle."}),"\n",(0,i.jsx)(n.h2,{id:"github-actions",children:"GitHub Actions"}),"\n",(0,i.jsx)(n.p,{children:"To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"1. Open your GitHub repository"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"2. Create or edit the GitHub Actions workflow YAML file"})}),"\n",(0,i.jsxs)(n.p,{children:["It could be located at e.g., ",(0,i.jsx)(n.code,{children:".github/workflows/main.yml"}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"3. Add the step to run Misti to your YAML file"})}),"\n",(0,i.jsx)(n.p,{children:"For example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"name: Run Misti\non: [push, pull_request]\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v2\n\n - name: Install dependencies\n run: npm install\n\n - name: Run Misti\n run: npx misti /path/to/your/tact.config.json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"npx misti /path/to/your/tact.config.json"})," command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"4. Adjusting the Misti Configuration"})}),"\n",(0,i.jsxs)(n.p,{children:["If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the ",(0,i.jsx)(n.a,{href:"./configuration",children:"Configuration"})," section for more details on how to customize your settings."]})]})}function d(t={}){const{wrapper:n}={...(0,o.R)(),...t.components};return n?(0,i.jsx)(n,{...t,children:(0,i.jsx)(l,{...t})}):l(t)}},8453:(t,n,e)=>{e.d(n,{R:()=>r,x:()=>c});var i=e(6540);const o={},s=i.createContext(o);function r(t){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof t?t(n):{...n,...t}}),[n,t])}function c(t){let n;return n=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:r(t.components),i.createElement(s.Provider,{value:n},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/51fe41a6.f649c3d3.js b/assets/js/51fe41a6.f649c3d3.js new file mode 100644 index 000000000..fc221fda3 --- /dev/null +++ b/assets/js/51fe41a6.f649c3d3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8290],{723:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),a=n(8453);const r={},i="NeverAccessedVariables",o={id:"detectors/NeverAccessedVariables",title:"NeverAccessedVariables",description:"A detector that identifies write-only or unused variables, fields and constants.",source:"@site/versioned_docs/version-0.4.0/detectors/NeverAccessedVariables.md",sourceDirName:"detectors",slug:"/detectors/NeverAccessedVariables",permalink:"/tools/misti/docs/detectors/NeverAccessedVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/NeverAccessedVariables.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"InheritedStateMutation",permalink:"/tools/misti/docs/detectors/InheritedStateMutation"},next:{title:"OptimalMathFunction",permalink:"/tools/misti/docs/detectors/OptimalMathFunction"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"neveraccessedvariables",children:"NeverAccessedVariables"}),"\n",(0,s.jsx)(t.p,{children:"A detector that identifies write-only or unused variables, fields and constants."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"These variables are either assigned but never used in any meaningful computation,\nor they are declared and never used at all, which may indicate redundant code\nor an incomplete implementation of the intended logic."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"// Error: the developer forgot to use the constant\nconst MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'const MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n // OK: Fixed after the analyzer highlighted this warning\n require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(6540);const a={},r=s.createContext(a);function i(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/55e1201d.f5805772.js b/assets/js/55e1201d.f5805772.js new file mode 100644 index 000000000..45d35104f --- /dev/null +++ b/assets/js/55e1201d.f5805772.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8422],{2165:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>r,toc:()=>l});var i=n(4848),s=n(8453);const a={},o="OptimalMathFunction",r={id:"detectors/OptimalMathFunction",title:"OptimalMathFunction",description:"A detector that highlights standard library math function calls that have more gas-efficient alternatives.",source:"@site/docs/detectors/OptimalMathFunction.md",sourceDirName:"detectors",slug:"/detectors/OptimalMathFunction",permalink:"/tools/misti/docs/next/detectors/OptimalMathFunction",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/OptimalMathFunction.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"NeverAccessedVariables",permalink:"/tools/misti/docs/next/detectors/NeverAccessedVariables"},next:{title:"PreferAugmentedAssign",permalink:"/tools/misti/docs/next/detectors/PreferAugmentedAssign"}},c={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function d(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"optimalmathfunction",children:"OptimalMathFunction"}),"\n",(0,i.jsx)(t.p,{children:"A detector that highlights standard library math function calls that have more gas-efficient alternatives."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsxs)(t.p,{children:["Tact supports ",(0,i.jsx)(t.code,{children:"log2"}),"/",(0,i.jsx)(t.code,{children:"pow2"})," functions, which are more gas-efficient than ",(0,i.jsx)(t.code,{children:"log(x, 2)"}),"/",(0,i.jsx)(t.code,{children:"pow(x, 2)"}),"."]}),"\n",(0,i.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"log(x, 2);\n"})}),"\n",(0,i.jsx)(t.p,{children:"Use instead:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"log2(x)\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>r});var i=n(6540);const s={},a=i.createContext(s);function o(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/563af34e.29a0e834.js b/assets/js/563af34e.29a0e834.js new file mode 100644 index 000000000..93a903964 --- /dev/null +++ b/assets/js/563af34e.29a0e834.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3890],{1410:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>d});var n=t(4848),s=t(8453);const i={},o="StringReceiversOverlap",a={id:"detectors/StringReceiversOverlap",title:"StringReceiversOverlap",description:"A detector that finds overlapping messages between general string receivers and string receivers.",source:"@site/versioned_docs/version-0.3.0/detectors/StringReceiversOverlap.md",sourceDirName:"detectors",slug:"/detectors/StringReceiversOverlap",permalink:"/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/StringReceiversOverlap.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables"},next:{title:"UnboundLoops",permalink:"/tools/misti/docs/0.3.0/detectors/UnboundLoops"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const r={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.h1,{id:"stringreceiversoverlap",children:"StringReceiversOverlap"}),"\n",(0,n.jsx)(r.p,{children:"A detector that finds overlapping messages between general string receivers and string receivers."}),"\n",(0,n.jsx)(r.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(r.p,{children:"Constant string receivers and general string receivers can have overlapping messages\nin which case the constant string receiver always takes precedence."}),"\n",(0,n.jsx)(r.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-tact",children:'contract Test {\n receive("foobar") { throw(1042) }\n receive(msg: String) {\n if (msg == "foobar") { throw(1043) } // Bad: Dead code\n }\n}\n'})}),"\n",(0,n.jsx)(r.p,{children:"Use instead:"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-tact",children:'contract Test {\n receive("foobar") { throw(1042) }\n receive(msg: String) {}\n}\n'})})]})}function p(e={}){const{wrapper:r}={...(0,s.R)(),...e.components};return r?(0,n.jsx)(r,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,r,t)=>{t.d(r,{R:()=>o,x:()=>a});var n=t(6540);const s={},i=n.createContext(s);function o(e){const r=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function a(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/566d8483.942257c5.js b/assets/js/566d8483.942257c5.js new file mode 100644 index 000000000..87fc358f6 --- /dev/null +++ b/assets/js/566d8483.942257c5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6551],{5437:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var i=n(4848),s=n(8453);const o={id:"intro",title:"Introduction",slug:"/",sidebar_position:1},r=void 0,a={id:"intro",title:"Introduction",description:"Misti is a static analysis tool designed for smart contracts on the TON blockchain.",source:"@site/versioned_docs/version-0.2.2/index.md",sourceDirName:".",slug:"/",permalink:"/tools/misti/docs/0.2.2/",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/index.md",tags:[],version:"0.2.2",sidebarPosition:1,frontMatter:{id:"intro",title:"Introduction",slug:"/",sidebar_position:1},sidebar:"sidebar",next:{title:"Getting Started",permalink:"/tools/misti/docs/0.2.2/tutorial/getting-started"}},c={},d=[{value:"Use Cases",id:"use-cases",level:2},{value:"Funding",id:"funding",level:2}];function l(e){const t={a:"a",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Misti is a static analysis tool designed for smart contracts on the ",(0,i.jsx)(t.a,{href:"https://ton.org/",children:"TON blockchain"}),"."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Language Support:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://tact-lang.org/",children:"Tact"})," 1.4.4 is supported."]}),"\n",(0,i.jsxs)(t.li,{children:["Support for ",(0,i.jsx)(t.a,{href:"https://docs.ton.org/develop/func/overview",children:"FunC"})," ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/56",children:"is planned"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,i.jsx)(t.p,{children:"Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Detect Vulnerabilities:"})," Identify and fix potential security flaws early in the development cycle."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Improve Code Quality:"})," Maintain high standards by catching bugs and enforcing best practices automatically."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Streamline Development:"})," Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Custom Detectors:"})," Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow."}),"\n",(0,i.jsx)(t.h2,{id:"funding",children:"Funding"}),"\n",(0,i.jsxs)(t.p,{children:["Misti has been ",(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/436",children:"funded"})," by ",(0,i.jsx)(t.a,{href:"https://ton.foundation",children:"TON Foundation"}),". This support has enabled us to develop and maintain the tool."]})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5815e0d3.36349d47.js b/assets/js/5815e0d3.36349d47.js new file mode 100644 index 000000000..822600a38 --- /dev/null +++ b/assets/js/5815e0d3.36349d47.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[186],{9644:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var t=n(4848),s=n(8453);const o={},r="Configuration",l={id:"tutorial/configuration",title:"Configuration",description:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.",source:"@site/versioned_docs/version-0.2.0/tutorial/configuration.md",sourceDirName:"tutorial",slug:"/tutorial/configuration",permalink:"/tools/misti/docs/0.2.0/tutorial/configuration",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/tutorial/configuration.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.2.0/tutorial/ci-cd"},next:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.2.0/detectors"}},a={},c=[{value:"Configuration Options",id:"configuration-options",level:3},{value:"Running Misti with Configuration",id:"running-misti-with-configuration",level:2},{value:"Default Configuration File",id:"default-configuration-file",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const i={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(i.h1,{id:"configuration",children:"Configuration"}),"\n",(0,t.jsx)(i.p,{children:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set."}),"\n",(0,t.jsx)(i.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"detectors"}),": List of detectors to run. Each detector can be specified with a ",(0,t.jsx)(i.code,{children:"className"})," and optionally a ",(0,t.jsx)(i.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"modulePath"})," (string, optional): The file path of the detector module."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"ignored_projects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"soufflePath"})," (string, optional): Directory to save generated Souffl\xe9 files which is helpful for debugging purposes. If not set, a temporary directory will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"tactStdlibPath"})," (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"unusedPrefix"}),' (string, default: "_"): Identifiers starting with this prefix won\'t be reported as unused by built-in detectors.']}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"verbosity"})," (string, optional): Verbosity level of the logs. Possible values are ",(0,t.jsx)(i.code,{children:"quiet"}),", ",(0,t.jsx)(i.code,{children:"debug"}),", and ",(0,t.jsx)(i.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(i.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,t.jsx)(i.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsx)(i.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,t.jsx)(i.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,t.jsx)(i.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-json",children:'{\n "detectorsEnabled": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n { "className": "BranchDuplicate" },\n { "className": "FieldDoubleInit" },\n { "className": "PreferAugmentedAssign" }\n ],\n "ignoredProjects": [],\n "unusedPrefix": "_",\n "verbosity": "default"\n}\n'})}),"\n",(0,t.jsxs)(i.p,{children:["All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,t.jsxs)(i.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,t.jsx)(i.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --dump-config test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsxs)(i.p,{children:["If there is no Misti config in the ",(0,t.jsx)(i.code,{children:"simple"})," directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors."]}),"\n",(0,t.jsx)(i.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,t.jsxs)(i.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,t.jsx)(i.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function u(e={}){const{wrapper:i}={...(0,s.R)(),...e.components};return i?(0,t.jsx)(i,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>r,x:()=>l});var t=n(6540);const s={},o=t.createContext(s);function r(e){const i=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/59016342.fc899b97.js b/assets/js/59016342.fc899b97.js new file mode 100644 index 000000000..71186ee0e --- /dev/null +++ b/assets/js/59016342.fc899b97.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6751],{9027:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=t(4848),o=t(8453);const i={},a="UnusedOptional",r={id:"detectors/UnusedOptional",title:"UnusedOptional",description:"A detector variables and fields with unused optional modifier.",source:"@site/versioned_docs/version-0.4.0/detectors/UnusedOptional.md",sourceDirName:"detectors",slug:"/detectors/UnusedOptional",permalink:"/tools/misti/docs/detectors/UnusedOptional",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/UnusedOptional.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"UnboundLoops",permalink:"/tools/misti/docs/detectors/UnboundLoops"},next:{title:"ZeroAddress",permalink:"/tools/misti/docs/detectors/ZeroAddress"}},d={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"unusedoptional",children:"UnusedOptional"}),"\n",(0,s.jsx)(n.p,{children:"A detector variables and fields with unused optional modifier."}),"\n",(0,s.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"Optional"})," is a nullable value that has a special ",(0,s.jsx)(n.code,{children:"null"})," value indicating the absence\nof a value. If a developer creates an optional variable or field, he should leverage\nits functionality by accessing the ",(0,s.jsx)(n.code,{children:"null"})," value somewhere in his code. Otherwise,\nthe optional type should be removed to simplify and optimize the code."]}),"\n",(0,s.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-tact",children:"contract Test {\n a: Int?; // Bad: null value is never accessed\n init() { self.a = 42; }\n get fun getA(): Int { return self.a!!; }\n}\n"})}),"\n",(0,s.jsx)(n.p,{children:"Use instead:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-tact",children:"contract Test {\n a: Int = 42; // OK: Removed optional\n get fun getA(): Int { return self.a; }\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>r});var s=t(6540);const o={},i=s.createContext(o);function a(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5a7ecd5b.08c83086.js b/assets/js/5a7ecd5b.08c83086.js new file mode 100644 index 000000000..cb04054d9 --- /dev/null +++ b/assets/js/5a7ecd5b.08c83086.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1417],{26:(e,s,t)=>{t.r(s),t.d(s,{assets:()=>a,contentTitle:()=>d,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>c});var n=t(4848),o=t(8453);const r={},d="ZeroAddress",i={id:"detectors/ZeroAddress",title:"ZeroAddress",description:"A detector that identifies uses of the zero address.",source:"@site/versioned_docs/version-0.3.0/detectors/ZeroAddress.md",sourceDirName:"detectors",slug:"/detectors/ZeroAddress",permalink:"/tools/misti/docs/0.3.0/detectors/ZeroAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/ZeroAddress.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"UnboundLoops",permalink:"/tools/misti/docs/0.3.0/detectors/UnboundLoops"},next:{title:"Contributing",permalink:"/tools/misti/docs/0.3.0/hacking/contributing"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const s={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{id:"zeroaddress",children:"ZeroAddress"}),"\n",(0,n.jsx)(s.p,{children:"A detector that identifies uses of the zero address."}),"\n",(0,n.jsx)(s.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(s.p,{children:"Using the zero address in smart contracts is typically problematic because it can be\nexploited as a default or uninitialized address, leading to unintended transfers and\nsecurity vulnerabilities. Additionally, operations involving the zero address can\nresult in loss of funds or tokens, as there is no private key to access this address."}),"\n",(0,n.jsx)(s.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init() {\n // Warning: Insecure usage of zero address as default value\n self.to = newAddress(0, 0);\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})}),"\n",(0,n.jsx)(s.p,{children:"Use instead:"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init(to: Address) {\n // Fixed: Using the input value on initialization.\n self.to = to;\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})})]})}function u(e={}){const{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,s,t)=>{t.d(s,{R:()=>d,x:()=>i});var n=t(6540);const o={},r=n.createContext(o);function d(e){const s=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function i(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),n.createElement(r.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5e95c892.0afa16e4.js b/assets/js/5e95c892.0afa16e4.js new file mode 100644 index 000000000..50422e8a1 --- /dev/null +++ b/assets/js/5e95c892.0afa16e4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9647],{7121:(e,r,s)=>{s.r(r),s.d(r,{default:()=>o});s(6540);var u=s(4164),a=s(1003),n=s(7559),t=s(2831),c=s(781),i=s(4848);function o(e){return(0,i.jsx)(a.e3,{className:(0,u.A)(n.G.wrapper.docsPages),children:(0,i.jsx)(c.A,{children:(0,t.v)(e.route.routes)})})}}}]); \ No newline at end of file diff --git a/assets/js/5ec2195c.a723ab4e.js b/assets/js/5ec2195c.a723ab4e.js new file mode 100644 index 000000000..779980d03 --- /dev/null +++ b/assets/js/5ec2195c.a723ab4e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9708],{1484:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var s=n(4848),o=n(8453);const r={},d="Constant Address",a={id:"detectors/ConstantAddress",title:"Constant Address",description:"An optional detector that highlights all the constant addresses appearing in the source code.",source:"@site/versioned_docs/version-0.2.1/detectors/ConstantAddress.md",sourceDirName:"detectors",slug:"/detectors/ConstantAddress",permalink:"/tools/misti/docs/0.2.1/detectors/ConstantAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/ConstantAddress.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Zero Address",permalink:"/tools/misti/docs/0.2.1/detectors/ZeroAddress"},next:{title:"Branch Duplicate",permalink:"/tools/misti/docs/0.2.1/detectors/BranchDuplicate"}},i={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"constant-address",children:"Constant Address"}),"\n",(0,s.jsx)(t.p,{children:"An optional detector that highlights all the constant addresses appearing in the source code."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsxs)(t.p,{children:["Using hardcoded addresses can sometimes indicate poor contract design.\nSome constant addresses may need to be set dynamically, e.g., using\n",(0,s.jsx)(t.code,{children:"contractAddress"}),", or at least have a way to change them at runtime, for\nexample, when upgrading a contract."]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'contract Main {\n proxy: Address;\n init() {\n // Bad: Constant address highlighted by the analyzer.\n self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");\n }\n}\n'})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"contract Main {\n proxy: Address;\n init() {\n let proxy: Proxy = initOf Proxy(myAddress());\n // OK: Address depends on how the proxy contact has been deployed\n self.proxy = contractAddress(proxy);\n }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>a});var s=n(6540);const o={},r=s.createContext(o);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/602c5d84.a9af00d9.js b/assets/js/602c5d84.a9af00d9.js new file mode 100644 index 000000000..ca250a7f9 --- /dev/null +++ b/assets/js/602c5d84.a9af00d9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4719],{8930:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>r,contentTitle:()=>a,default:()=>h,frontMatter:()=>s,metadata:()=>l,toc:()=>d});var n=i(4848),o=i(8453);const s={},a="FieldDoubleInit",l={id:"detectors/FieldDoubleInit",title:"FieldDoubleInit",description:"A detector that highlights cases where a field is initialized both in the",source:"@site/versioned_docs/version-0.4.0/detectors/FieldDoubleInit.md",sourceDirName:"detectors",slug:"/detectors/FieldDoubleInit",permalink:"/tools/misti/docs/detectors/FieldDoubleInit",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/FieldDoubleInit.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"FalseCondition",permalink:"/tools/misti/docs/detectors/FalseCondition"},next:{title:"InheritedStateMutation",permalink:"/tools/misti/docs/detectors/InheritedStateMutation"}},r={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"fielddoubleinit",children:"FieldDoubleInit"}),"\n",(0,n.jsxs)(t.p,{children:["A detector that highlights cases where a field is initialized both in the\n",(0,n.jsx)(t.code,{children:"init"})," function and at the point of definition."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["Double initialization of fields can either be a programmer's mistake or simply\na waste of gas. It is always preferred to initialize values in the field declaration\nif they have a compile-time evaluatable default value, or in the ",(0,n.jsx)(t.code,{children:"init"})," function if\nthey must be initialized dynamically."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int = 0; // Bad\n init(x: Int) { self.a = x }\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int; // Fixed\n init(x: Int) { self.a = x }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>a,x:()=>l});var n=i(6540);const o={},s=n.createContext(o);function a(e){const t=n.useContext(s);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),n.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/61c19607.94c232da.js b/assets/js/61c19607.94c232da.js new file mode 100644 index 000000000..5fee2f5e6 --- /dev/null +++ b/assets/js/61c19607.94c232da.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5794],{8628:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>l,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var i=n(4848),s=n(8453);const r={},l="Getting started",o={id:"tutorial/getting-started",title:"Getting started",description:"This guide will walk you through the steps to install and set up the Misti static analyzer.",source:"@site/versioned_docs/version-0.2.2/tutorial/getting-started.md",sourceDirName:"tutorial",slug:"/tutorial/getting-started",permalink:"/tools/misti/docs/0.2.2/tutorial/getting-started",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/tutorial/getting-started.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Introduction",permalink:"/tools/misti/docs/0.2.2/"},next:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.2.2/tutorial/ci-cd"}},a={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Using Development Version",id:"using-development-version",level:3},{value:"Running the analysis",id:"running-the-analysis",level:2},{value:"Troubleshooting",id:"troubleshooting",level:2}];function c(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,i.jsx)(t.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsx)(t.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Git"}),"\n",(0,i.jsx)(t.li,{children:"Yarn"}),"\n",(0,i.jsx)(t.li,{children:"Node.js"}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"installation",children:"Installation"}),"\n",(0,i.jsxs)(t.p,{children:["Misti is distributed via npm and should be added to your Tact project ",(0,i.jsx)(t.a,{href:"https://github.com/tact-lang/tact?tab=readme-ov-file#installation",children:"in the same way"})," as Tact itself:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"yarn add @nowarp/misti\n"})}),"\n",(0,i.jsx)(t.h3,{id:"using-development-version",children:"Using Development Version"}),"\n",(0,i.jsx)(t.p,{children:"The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis."}),"\n",(0,i.jsx)(t.p,{children:"To install the latest development version you should:"}),"\n",(0,i.jsxs)(t.ol,{children:["\n",(0,i.jsxs)(t.li,{children:["Clone Misti: ",(0,i.jsx)(t.code,{children:"git clone https://github.com/nowarp/misti"})]}),"\n",(0,i.jsxs)(t.li,{children:["Build it: ",(0,i.jsx)(t.code,{children:"cd misti && yarn install && yarn build"})]}),"\n",(0,i.jsxs)(t.li,{children:["Use it in your Tact project: ",(0,i.jsx)(t.code,{children:"cd /path/to/tact/project && yarn add file:/path/to/misti"})]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,i.jsx)(t.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{children:"npx misti test/projects/simple/tactConfig.json\n"})}),"\n",(0,i.jsx)(t.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,i.jsxs)(t.p,{children:["You can also add a script to your ",(0,i.jsx)(t.code,{children:"package.json"})," to simplify running the linting process:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-json",children:'{\n "scripts": {\n "lint": "npx misti test/projects/simple/tactConfig.json"\n }\n}\n'})}),"\n",(0,i.jsx)(t.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsxs)(t.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,i.jsx)(t.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>l,x:()=>o});var i=n(6540);const s={},r=i.createContext(s);function l(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6362ac9f.aa3d1fc1.js b/assets/js/6362ac9f.aa3d1fc1.js new file mode 100644 index 000000000..881b1e3b7 --- /dev/null +++ b/assets/js/6362ac9f.aa3d1fc1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9431],{2219:(t,e,i)=>{i.r(e),i.d(e,{assets:()=>a,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var n=i(4848),s=i(8453);const r={},o="Using Misti with Blueprint",l={id:"tutorial/blueprint",title:"Using Misti with Blueprint",description:"Blueprint is a platform to compile, test, and deploy contracts on the TON blockchain. It is quite similar to Hardhat and Truffle for Ethereum.",source:"@site/versioned_docs/version-0.4.0/tutorial/blueprint.md",sourceDirName:"tutorial",slug:"/tutorial/blueprint",permalink:"/tools/misti/docs/tutorial/blueprint",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/tutorial/blueprint.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/tools/misti/docs/tutorial/configuration"},next:{title:"Detectors Overview",permalink:"/tools/misti/docs/detectors"}},a={},c=[{value:"Getting Started",id:"getting-started",level:2},{value:"Usage",id:"usage",level:2}];function d(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",...(0,s.R)(),...t.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"using-misti-with-blueprint",children:"Using Misti with Blueprint"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:"https://github.com/ton-org/blueprint/",children:"Blueprint"})," is a platform to compile, test, and deploy contracts on the TON blockchain. It is quite similar to Hardhat and Truffle for Ethereum."]}),"\n",(0,n.jsxs)(e.p,{children:["There is a ",(0,n.jsx)(e.a,{href:"https://github.com/nowarp/blueprint-misti",children:"blueprint-misti"})," plugin that can be added to a Blueprint configuration. It adds the ",(0,n.jsx)(e.code,{children:"blueprint misti"})," command, which runs the static analyzer over the selected Blueprint project."]}),"\n",(0,n.jsx)(e.p,{children:"This page describes how to use it."}),"\n",(0,n.jsx)(e.h2,{id:"getting-started",children:"Getting Started"}),"\n",(0,n.jsxs)(e.ol,{children:["\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:"https://souffle-lang.github.io/install",children:"Install Souffl\xe9"})," to use all detectors provided by Misti."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsx)(e.p,{children:"Add this plugin as a dependency of your Blueprint project:"}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"yarn add @tact-lang/compiler\nyarn add @nowarp/blueprint-misti\n"})}),"\n",(0,n.jsxs)(e.ol,{start:"3",children:["\n",(0,n.jsxs)(e.li,{children:["Add this configuration to ",(0,n.jsx)(e.code,{children:"blueprint.config.ts"}),":"]}),"\n"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-ts",children:"import { MistiPlugin } from '@nowarp/blueprint-misti';\nexport const config = {\n plugins: [\n new MistiPlugin(),\n ],\n};\n"})}),"\n",(0,n.jsx)(e.h2,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(e.p,{children:"Run the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"yarn blueprint misti\n"})}),"\n",(0,n.jsx)(e.p,{children:"It will run the analysis of the available project, if there is one, or show an interactive window to select a project:"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"img",src:i(1547).A+"",width:"493",height:"96"})}),"\n",(0,n.jsxs)(e.p,{children:["You could also pass the ",(0,n.jsx)(e.a,{href:"/tools/misti/docs/tutorial/cli",children:"supported CLI options"})," for Misti, for example:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"yarn blueprint misti --all-detectors\n"})}),"\n",(0,n.jsx)(e.p,{children:"Or you can even pass the path to the contract directly:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"yarn blueprint misti path/to/my/contract.tact\n"})}),"\n",(0,n.jsxs)(e.p,{children:["If you have any problems, feel free to reach out to us in the ",(0,n.jsx)(e.a,{href:"https://t.me/misti_dev",children:"Misti discussion group"}),"."]})]})}function h(t={}){const{wrapper:e}={...(0,s.R)(),...t.components};return e?(0,n.jsx)(e,{...t,children:(0,n.jsx)(d,{...t})}):d(t)}},1547:(t,e,i)=>{i.d(e,{A:()=>n});const n=i.p+"assets/images/blueprint-select-project-b8656fa4266c0c7923d6b67c7f5950e6.png"},8453:(t,e,i)=>{i.d(e,{R:()=>o,x:()=>l});var n=i(6540);const s={},r=n.createContext(s);function o(t){const e=n.useContext(r);return n.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function l(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(s):t.components||s:o(t.components),n.createElement(r.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/63a541b5.cf91b4ad.js b/assets/js/63a541b5.cf91b4ad.js new file mode 100644 index 000000000..5d00abc01 --- /dev/null +++ b/assets/js/63a541b5.cf91b4ad.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5122],{1105:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=n(4848),o=n(8453);const i={},a="ArgCopyMutation",r={id:"detectors/ArgCopyMutation",title:"ArgCopyMutation",description:"A detector that highlights cases where function argument mutations are ineffective",source:"@site/versioned_docs/version-0.3.1/detectors/ArgCopyMutation.md",sourceDirName:"detectors",slug:"/detectors/ArgCopyMutation",permalink:"/tools/misti/docs/0.3.1/detectors/ArgCopyMutation",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/ArgCopyMutation.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.3.1/detectors"},next:{title:"AsmIsUsed",permalink:"/tools/misti/docs/0.3.1/detectors/AsmIsUsed"}},c={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function d(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"argcopymutation",children:"ArgCopyMutation"}),"\n",(0,s.jsx)(t.p,{children:"A detector that highlights cases where function argument mutations are ineffective\ndue to call-by-value semantics in Tact."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"In Tact, function arguments are passed by value, meaning that any mutations applied\nto these arguments will only affect the local copy of the variable within the function.\nSuch mutations are unobservable outside the function, except for potentially\nincreasing gas consumption or causing exceptions."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"fun addEntry(m: map<Int,Int>) {\n m.set(1, 10); // Bad: Mutating the copy\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"fun addEntry() {\n self.m.set(1, 10); // OK: Changing contract's state\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Alternatively, you could redesign the method:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"fun generateNewValue(): Int {\n // ... produce new value for the map\n return self.nextValue + 1;\n}\n\nm.set(self.nextKey, self.generateNewValue()); // OK\n"})})]})}function u(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var s=n(6540);const o={},i=s.createContext(o);function a(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/63bb535a.ed747652.js b/assets/js/63bb535a.ed747652.js new file mode 100644 index 000000000..989ae93ab --- /dev/null +++ b/assets/js/63bb535a.ed747652.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3684],{3494:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>p,frontMatter:()=>d,metadata:()=>o,toc:()=>l});var r=n(4848),s=n(8453);const d={},i="PreferredStdlibApi",o={id:"detectors/PreferredStdlibApi",title:"PreferredStdlibApi",description:"An optional detector that flags the use of advanced functions from the standard library.",source:"@site/versioned_docs/version-0.4.0/detectors/PreferredStdlibApi.md",sourceDirName:"detectors",slug:"/detectors/PreferredStdlibApi",permalink:"/tools/misti/docs/detectors/PreferredStdlibApi",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/PreferredStdlibApi.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"PreferAugmentedAssign",permalink:"/tools/misti/docs/detectors/PreferAugmentedAssign"},next:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/detectors/ReadOnlyVariables"}},a={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"preferredstdlibapi",children:"PreferredStdlibApi"}),"\n",(0,r.jsx)(t.p,{children:"An optional detector that flags the use of advanced functions from the standard library."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"Auditors should pay extra attention to these functions, as incorrect usage can\nlead to subtle bugs. Safer stdlib alternatives should be preferred in the code."}),"\n",(0,r.jsx)(t.p,{children:"Supported functions:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Use ",(0,r.jsx)(t.code,{children:"send"})," instead of ",(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-advanced#nativesendmessage",children:(0,r.jsx)(t.code,{children:"nativeSendMessage"})})]}),"\n",(0,r.jsxs)(t.li,{children:["Prefer ",(0,r.jsx)(t.code,{children:"randomInt"})," instead of ",(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-advanced#nativerandom",children:(0,r.jsx)(t.code,{children:"nativeRandom"})})]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"let pkg: Slice = msg.transfer;\nlet _seqno: Int = pkg.loadInt(32);\nlet mode: Int = pkg.loadInt(8);\nlet body: Cell = pkg.loadRef();\n// Bad: prefer `send` to avoid low-level manipulation of Slice\nnativeSendMessage(body, mode);\n"})}),"\n",(0,r.jsx)(t.p,{children:"Use instead:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"// Safer: More explicit definition of the send operation\nsend(SendParameters{ value: amount,\n to: self.owner,\n mode: mode,\n body: beginCell().endCell() });\n"})})]})}function p(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var r=n(6540);const s={},d=r.createContext(s);function i(e){const t=r.useContext(d);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(d.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6696f09b.9d59dc8d.js b/assets/js/6696f09b.9d59dc8d.js new file mode 100644 index 000000000..2a7065bb8 --- /dev/null +++ b/assets/js/6696f09b.9d59dc8d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9417],{1469:(i,e,t)=>{t.r(e),t.d(e,{assets:()=>o,contentTitle:()=>d,default:()=>g,frontMatter:()=>l,metadata:()=>a,toc:()=>r});var n=t(4848),s=t(8453);const l={},d="DumpCfg",a={id:"tools/DumpCfg",title:"DumpCfg",description:"Misti provides a feature to dump the Control Flow Graph (CFG) in JSON, DOT, and Mermaid formats. This is essential for understanding the Internal Representation (IR) of the code and analyzing the control flow within contracts.",source:"@site/versioned_docs/version-0.4.0/tools/DumpCfg.md",sourceDirName:"tools",slug:"/tools/DumpCfg",permalink:"/tools/misti/docs/tools/DumpCfg",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/tools/DumpCfg.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpAst",permalink:"/tools/misti/docs/tools/DumpAst"},next:{title:"DumpConfig",permalink:"/tools/misti/docs/tools/DumpConfig"}},o={},r=[{value:"Usage",id:"usage",level:2},{value:"Working with Mermaid",id:"working-with-mermaid",level:2},{value:"Working with Graphviz",id:"working-with-graphviz",level:2},{value:"Converting DOT to SVG",id:"converting-dot-to-svg",level:3},{value:"Viewing the SVG",id:"viewing-the-svg",level:3},{value:"VS Code Plugin",id:"vs-code-plugin",level:3},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function I(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"dumpcfg",children:"DumpCfg"}),"\n",(0,n.jsxs)(e.p,{children:["Misti provides a feature to dump the ",(0,n.jsx)(e.a,{href:"https://en.wikipedia.org/wiki/Control-flow_graph",children:"Control Flow Graph (CFG)"})," in JSON, DOT, and Mermaid formats. This is essential for understanding the Internal Representation (IR) of the code and analyzing the control flow within contracts."]}),"\n",(0,n.jsx)(e.h2,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in Mermaid format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=mmd" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in Graphviz DOT format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in JSON format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=json" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsxs)(e.p,{children:["You could also include Tact standard library functions to the dump adding ",(0,n.jsx)(e.code,{children:"dumpStdlib=true"})," to the ",(0,n.jsx)(e.code,{children:"DumpCfg"})," options."]}),"\n",(0,n.jsx)(e.h2,{id:"working-with-mermaid",children:"Working with Mermaid"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:"https://mermaid.js.org",children:"Mermaid"})," is a JavaScript-based diagramming and charting tool that allows you to create dynamic visualizations, such as flowcharts and sequence diagrams, using a simple syntax. It is integrated into various platforms, including Visual Studio Code."]}),"\n",(0,n.jsxs)(e.p,{children:["To view Mermaid diagrams in Visual Studio Code, you can use the ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/items?itemName=bierner.markdown-mermaid",children:"Markdown Preview Mermaid Support"})," extension. You can also use the ",(0,n.jsx)(e.a,{href:"https://mermaid.live",children:"Mermaid Live Editor"})," to preview your diagrams online."]}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in Mermaid format using Misti, run the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=mermaid" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"The output can be viewed directly in the VS Code plugin or the online editor."}),"\n",(0,n.jsx)(e.h2,{id:"working-with-graphviz",children:"Working with Graphviz"}),"\n",(0,n.jsx)(e.h3,{id:"converting-dot-to-svg",children:"Converting DOT to SVG"}),"\n",(0,n.jsxs)(e.p,{children:["To convert the resulting DOT file to an SVG for visualization, save the generated DOT dump to a file and use ",(0,n.jsx)(e.a,{href:"https://graphviz.org",children:"Graphviz"})," with the following command:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot\ndot -Tsvg output.dot -o output.svg\n'})}),"\n",(0,n.jsx)(e.h3,{id:"viewing-the-svg",children:"Viewing the SVG"}),"\n",(0,n.jsx)(e.p,{children:"To view the SVG file in Firefox, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"firefox output.svg\n"})}),"\n",(0,n.jsx)(e.p,{children:"For example, for the following contract:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-tact",children:"fun test(): Int {\n let sum: Int = 0;\n let i: Int = 0;\n repeat (10) {\n i = i + 1;\n sum = sum + i;\n }\n return sum;\n}\n"})}),"\n",(0,n.jsx)(e.p,{children:"The following CFG will be generated:"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"CFG Example",src:t(685).A+"",width:"337",height:"516"})}),"\n",(0,n.jsx)(e.h3,{id:"vs-code-plugin",children:"VS Code Plugin"}),"\n",(0,n.jsxs)(e.p,{children:["For real-time visualization of DOT files, you can use ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/search?term=tag%3Agraphviz&target=VSCode&category=All%20categories&sortBy=Relevance",children:"one of the available"})," Graphviz plugins for Visual Studio Code. These plugins allow you to view DOT diagrams directly within the editor, facilitating easier debugging and development."]}),"\n",(0,n.jsx)(e.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"JSON Dumps"}),": These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"DOT Dumps"}),": These provide a visual representation of the contract's control flow. They are particularly useful for understanding the control flow within contracts, making it easier to identify issues and optimize the code."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"Mermaid Dumps"}),": The Mermaid format allows you to generate flowcharts that are easy to read and share. They offer a convenient way to visualize the CFG without requiring additional tools, as they can be directly embedded in markdown files or viewed in the Mermaid Live Editor."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(e.p,{children:"By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors."})]})}function g(i={}){const{wrapper:e}={...(0,s.R)(),...i.components};return e?(0,n.jsx)(e,{...i,children:(0,n.jsx)(I,{...i})}):I(i)}},685:(i,e,t)=>{t.d(e,{A:()=>n});const n="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDIuNCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBsb29wcyYjNDU7MyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjUzcHQiIGhlaWdodD0iMzg3cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjUzLjAwIDM4Ny4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzODMpIj4KPHRpdGxlPmxvb3BzJiM0NTszPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzgzIDI0OSwtMzgzIDI0OSw0IC00LDQiLz4KPGcgaWQ9ImNsdXN0MSIgY2xhc3M9ImNsdXN0ZXIiPgo8dGl0bGU+Y2x1c3Rlcl90ZXN0PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI4LC04IDgsLTM3MSAyMzcsLTM3MSAyMzcsLTggOCwtOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIuNSIgeT0iLTM1NS44IiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnRlc3Q8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0MSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT50ZXN0XzE0MTwvdGl0bGU+Cjxwb2x5Z29uIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjI0LjUsLTM0MCA5NS41LC0zNDAgOTUuNSwtMzA0IDIyNC41LC0zMDQgMjI0LjUsLTM0MCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNjAiIHk9Ii0zMTguMyIgZm9udC1mYW1pbHk9IlRpbWVzLHNlcmlmIiBmb250LXNpemU9IjE0LjAwIj5sZXQgc3VtOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDI8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMiwtMjY4IDEwOCwtMjY4IDEwOCwtMjMyIDIxMiwtMjMyIDIxMiwtMjY4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTI0Ni4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPmxldCBpOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDEmIzQ1OyZndDt0ZXN0XzE0MiAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MSYjNDU7Jmd0O3Rlc3RfMTQyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMzAzLjdDMTYwLC0yOTUuOTggMTYwLC0yODYuNzEgMTYwLC0yNzguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTI3OC4xIDE2MCwtMjY4LjEgMTU2LjUsLTI3OC4xIDE2My41LC0yNzguMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDQ8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOCwtMTk2IDExMiwtMTk2IDExMiwtMTYwIDIwOCwtMTYwIDIwOCwtMTk2Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTE3NC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnJlcGVhdCAoMTApPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDImIzQ1OyZndDt0ZXN0XzE0NCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MiYjNDU7Jmd0O3Rlc3RfMTQ0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMjMxLjdDMTYwLC0yMjMuOTggMTYwLC0yMTQuNzEgMTYwLC0yMDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTIwNi4xIDE2MCwtMTk2LjEgMTU2LjUsLTIwNi4xIDE2My41LC0yMDYuMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDYgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDY8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjkzLjUsLTEyNCAxNi41LC0xMjQgMTYuNSwtODggOTMuNSwtODggOTMuNSwtMTI0Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjU1IiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+aSA9IGkgKyAxPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE0NiAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0NCYjNDU7Jmd0O3Rlc3RfMTQ2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEzNC4zMSwtMTU5Ljg4QzEyMC43MSwtMTUwLjgxIDEwMy44MywtMTM5LjU1IDg5LjE0LC0xMjkuNzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iOTEuMDUsLTEyNi44MiA4MC43OCwtMTI0LjE5IDg3LjE2LC0xMzIuNjUgOTEuMDUsLTEyNi44MiIvPgo8L2c+CjwhLS0gdGVzdF8xNTEgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNTE8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjNjZhN2RiIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOC41LC0xMjQgMTExLjUsLTEyNCAxMTEuNSwtODggMjA4LjUsLTg4IDIwOC41LC0xMjQiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTYwIiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+cmV0dXJuIHN1bTwvdGV4dD4KPC9nPgo8IS0tIHRlc3RfMTQ0JiM0NTsmZ3Q7dGVzdF8xNTEgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE1MTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNjAsLTE1OS43QzE2MCwtMTUxLjk4IDE2MCwtMTQyLjcxIDE2MCwtMTM0LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2My41LC0xMzQuMSAxNjAsLTEyNC4xIDE1Ni41LC0xMzQuMSAxNjMuNSwtMTM0LjEiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPnRlc3RfMTQ4PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxODMuNSwtNTIgNjAuNSwtNTIgNjAuNSwtMTYgMTgzLjUsLTE2IDE4My41LC01MiIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIiIHk9Ii0zMC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnN1bSA9IHN1bSArIGk8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0NiYjNDU7Jmd0O3Rlc3RfMTQ4IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPnRlc3RfMTQ2JiM0NTsmZ3Q7dGVzdF8xNDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuNTYsLTg3LjdDNzkuNjgsLTc5LjIyIDg5LjU5LC02OC44NiA5OC40NywtNTkuNTgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAxLjI0LC02MS43NSAxMDUuNjMsLTUyLjEgOTYuMTksLTU2LjkxIDEwMS4yNCwtNjEuNzUiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4JiM0NTsmZ3Q7dGVzdF8xNDQgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDgmIzQ1OyZndDt0ZXN0XzE0NDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzUuMjIsLTUyLjA0QzE5MS44OSwtNjAuMTYgMjA4LjQyLC03MS43NyAyMTgsLTg4IDIyNi4xMywtMTAxLjc4IDIyNC40NSwtMTA5LjM2IDIxOCwtMTI0IDIxMy4wMSwtMTM1LjMxIDIwNC4yOSwtMTQ1LjI2IDE5NS4xLC0xNTMuMzgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTkyLjgzLC0xNTAuNzIgMTg3LjM0LC0xNTkuNzcgMTk3LjI4LC0xNTYuMTIgMTkyLjgzLC0xNTAuNzIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8453:(i,e,t)=>{t.d(e,{R:()=>d,x:()=>a});var n=t(6540);const s={},l=n.createContext(s);function d(i){const e=n.useContext(l);return n.useMemo((function(){return"function"==typeof i?i(e):{...e,...i}}),[e,i])}function a(i){let e;return e=i.disableParentContext?"function"==typeof i.components?i.components(s):i.components||s:d(i.components),n.createElement(l.Provider,{value:e},i.children)}}}]); \ No newline at end of file diff --git a/assets/js/6934ebe4.7bcf9574.js b/assets/js/6934ebe4.7bcf9574.js new file mode 100644 index 000000000..e85bbde5d --- /dev/null +++ b/assets/js/6934ebe4.7bcf9574.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3175],{4919:(t,n,e)=>{e.r(n),e.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>u});var i=e(4848),o=e(8453);const s={},r="Integrating Misti into CI/CD",c={id:"tutorial/ci-cd",title:"Integrating Misti into CI/CD",description:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.",source:"@site/versioned_docs/version-0.3.0/tutorial/ci-cd.md",sourceDirName:"tutorial",slug:"/tutorial/ci-cd",permalink:"/tools/misti/docs/0.3.0/tutorial/ci-cd",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/tutorial/ci-cd.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Getting Started",permalink:"/tools/misti/docs/0.3.0/tutorial/getting-started"},next:{title:"Command-Line Interface",permalink:"/tools/misti/docs/0.3.0/tutorial/cli"}},a={},u=[{value:"GitHub Actions",id:"github-actions",level:2}];function l(t){const n={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",strong:"strong",...(0,o.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"integrating-misti-into-cicd",children:"Integrating Misti into CI/CD"}),"\n",(0,i.jsx)(n.p,{children:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle."}),"\n",(0,i.jsx)(n.h2,{id:"github-actions",children:"GitHub Actions"}),"\n",(0,i.jsx)(n.p,{children:"To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"1. Open your GitHub repository"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"2. Create or edit the GitHub Actions workflow YAML file"})}),"\n",(0,i.jsxs)(n.p,{children:["It could be located at e.g., ",(0,i.jsx)(n.code,{children:".github/workflows/main.yml"}),"."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"3. Add the step to run Misti to your YAML file"})}),"\n",(0,i.jsx)(n.p,{children:"For example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-yaml",children:"name: Run Misti\non: [push, pull_request]\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - name: Checkout code\n uses: actions/checkout@v2\n\n - name: Install dependencies\n run: npm install\n\n - name: Run Misti\n run: npx misti /path/to/your/tact.config.json\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"npx misti /path/to/your/tact.config.json"})," command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.strong,{children:"4. Adjusting the Misti Configuration"})}),"\n",(0,i.jsxs)(n.p,{children:["If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the ",(0,i.jsx)(n.a,{href:"./configuration",children:"Configuration"})," section for more details on how to customize your settings."]})]})}function d(t={}){const{wrapper:n}={...(0,o.R)(),...t.components};return n?(0,i.jsx)(n,{...t,children:(0,i.jsx)(l,{...t})}):l(t)}},8453:(t,n,e)=>{e.d(n,{R:()=>r,x:()=>c});var i=e(6540);const o={},s=i.createContext(o);function r(t){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof t?t(n):{...n,...t}}),[n,t])}function c(t){let n;return n=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:r(t.components),i.createElement(s.Provider,{value:n},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/693ffdbc.20a90ba4.js b/assets/js/693ffdbc.20a90ba4.js new file mode 100644 index 000000000..d6d50b426 --- /dev/null +++ b/assets/js/693ffdbc.20a90ba4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1204],{7567:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>f});var t=i(4848),r=i(8453);const s={},a="Souffl\xe9 Integration Guide",o={id:"hacking/souffle",title:"Souffl\xe9 Integration Guide",description:"What is Souffl\xe9?",source:"@site/versioned_docs/version-0.2.2/hacking/souffle.md",sourceDirName:"hacking",slug:"/hacking/souffle",permalink:"/tools/misti/docs/0.2.2/hacking/souffle",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/hacking/souffle.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Design Overview",permalink:"/tools/misti/docs/0.2.2/hacking/design"},next:{title:"Tools",permalink:"/tools/misti/docs/0.2.2/hacking/tools"}},l={},f=[{value:"What is Souffl\xe9?",id:"what-is-souffl\xe9",level:2},{value:"Benefits of Using Souffl\xe9 for Static Analysis",id:"benefits-of-using-souffl\xe9-for-static-analysis",level:2},{value:"Souffl\xe9 Integration in Misti",id:"souffl\xe9-integration-in-misti",level:2},{value:"Creating Souffl\xe9 Programs",id:"creating-souffl\xe9-programs",level:3},{value:"Generating Facts and Executing Souffl\xe9",id:"generating-facts-and-executing-souffl\xe9",level:3},{value:"Learning from Existing Code",id:"learning-from-existing-code",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"souffl\xe9-integration-guide",children:"Souffl\xe9 Integration Guide"}),"\n",(0,t.jsx)(n.h2,{id:"what-is-souffl\xe9",children:"What is Souffl\xe9?"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io",children:"Souffl\xe9"})," is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Souffl\xe9, Misti can perform deep and scalable analyses of smart contracts."]}),"\n",(0,t.jsx)(n.h2,{id:"benefits-of-using-souffl\xe9-for-static-analysis",children:"Benefits of Using Souffl\xe9 for Static Analysis"}),"\n",(0,t.jsx)(n.p,{children:"Souffl\xe9 allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Souffl\xe9 program might be more straightforward then implementing a complex transfer function in for a classic monotone framework."}),"\n",(0,t.jsx)(n.h2,{id:"souffl\xe9-integration-in-misti",children:"Souffl\xe9 Integration in Misti"}),"\n",(0,t.jsxs)(n.p,{children:["The API for interacting with Souffl\xe9 in Misti is detailed ",(0,t.jsx)(n.a,{href:"https://nowarp.github.io/docs/misti/api/modules/internals_souffle.html",children:"here"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"creating-souffl\xe9-programs",children:"Creating Souffl\xe9 Programs"}),"\n",(0,t.jsx)(n.p,{children:'To create a Souffl\xe9 program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:'}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addDecls(ctx: Context<SrcInfo>) {\n ctx.add(\n Relation.from(\n "varDecl",\n [\n ["var", FactType.Symbol],\n ["func", FactType.Symbol],\n ],\n undefined,\n ),\n );\n // other declarations\n}\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addRules(ctx: Context<SrcInfo>) {\n // readOnly(var, func) :-\n // varDecl(var, func),\n // !varAssign(var, func),\n // !varUse(var, func).\n ctx.add(\n Rule.from(\n [makeAtom("readOnly", ["var", "func"])],\n makeRuleBody(makeAtom("varDecl", ["var", "func"])),\n makeRuleBody(makeAtom("varAssign", ["var", "func"]), {\n negated: true,\n }),\n makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),\n ),\n );\n }\n'})}),"\n",(0,t.jsx)(n.h3,{id:"generating-facts-and-executing-souffl\xe9",children:"Generating Facts and Executing Souffl\xe9"}),"\n",(0,t.jsx)(n.p,{children:"After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Souffl\xe9 executor to run the analysis:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"const executor = ctx.config.soufflePath\n ? new Executor<SrcInfo>({\n inputDir: ctx.config.soufflePath,\n outputDir: ctx.config.soufflePath,\n })\n : new Executor<SrcInfo>();\n\nconst result = executor.executeSync(program);\n\nif (!result.success) {\n throw new Error(\n `Error executing Souffl\xe9 for ${this.id}:\\n${result.stderr}`,\n );\n}\n\nconst warnings = Array.from(result.results.entries.values()).map((fact) => {\n // raise warnings\n});\n"})}),"\n",(0,t.jsx)(n.h3,{id:"learning-from-existing-code",children:"Learning from Existing Code"}),"\n",(0,t.jsx)(n.p,{children:"We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Souffl\xe9 with Misti. This will help you understand the intricacies of generating IR and executing Souffl\xe9 programs effectively."}),"\n",(0,t.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,t.jsxs)(n.p,{children:["For a deeper understanding of static analysis using Souffl\xe9, refer to the textbook ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.a,{href:"https://arxiv.org/pdf/2012.10086",children:"Program Analysis: An Appetizer"})})," by Flemming Nielson and Hanne Riis Nielson. It discusses Souffl\xe9-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field."]})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>a,x:()=>o});var t=i(6540);const r={},s=t.createContext(r);function a(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6f277b0e.89006761.js b/assets/js/6f277b0e.89006761.js new file mode 100644 index 000000000..37aa85745 --- /dev/null +++ b/assets/js/6f277b0e.89006761.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6340],{701:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var t=o(4848),s=o(8453);const i={},r="Unbound Loops",a={id:"detectors/UnboundLoops",title:"Unbound Loops",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/versioned_docs/version-0.2.2/detectors/UnboundLoops.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoops",permalink:"/tools/misti/docs/0.2.2/detectors/UnboundLoops",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/UnboundLoops.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Read-only Variables",permalink:"/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables"},next:{title:"Zero Address",permalink:"/tools/misti/docs/0.2.2/detectors/ZeroAddress"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"unbound-loops",children:"Unbound Loops"}),"\n",(0,t.jsx)(n.p,{children:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria."}),"\n",(0,t.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,t.jsx)(n.p,{children:"An unbounded loop can be problematic for several reasons:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult."}),"\n",(0,t.jsx)(n.li,{children:"Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks."}),"\n",(0,t.jsx)(n.li,{children:"DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability."}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n // Bad: x is not changed due looping\n send(SendParameters{ to: sender(), ... });\n}\n"})}),"\n",(0,t.jsx)(n.p,{children:"Use instead:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n send(SendParameters{ to: sender(), ... });\n x = x - 1;\n}\n"})})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,o)=>{o.d(n,{R:()=>r,x:()=>a});var t=o(6540);const s={},i=t.createContext(s);function r(e){const n=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/6f60ccd2.91c6f358.js b/assets/js/6f60ccd2.91c6f358.js new file mode 100644 index 000000000..ec4a38093 --- /dev/null +++ b/assets/js/6f60ccd2.91c6f358.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4861],{3316:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>s,default:()=>p,frontMatter:()=>a,metadata:()=>l,toc:()=>d});var r=n(4848),i=n(8453);const a={},s="ReadOnlyVariables",l={id:"detectors/ReadOnlyVariables",title:"ReadOnlyVariables",description:"A detector that identifies read-only variables and fields.",source:"@site/versioned_docs/version-0.3.1/detectors/ReadOnlyVariables.md",sourceDirName:"detectors",slug:"/detectors/ReadOnlyVariables",permalink:"/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/ReadOnlyVariables.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi"},next:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap"}},o={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"readonlyvariables",children:"ReadOnlyVariables"}),"\n",(0,r.jsx)(t.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"These variables could typically be replaced with constants to optimize performance.\nAlternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally."}),"\n",(0,r.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"fun calculateFinalPrice(price: Int): Int {\n // Warning: the developer uses a read-only variable that could be a constant\n let DISCOUNT_AMOUNT: Int = 10;\n return price - DISCOUNT_AMOUNT;\n}\n"})}),"\n",(0,r.jsx)(t.p,{children:"Use instead:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"const DISCOUNT_AMOUNT: Int = 10;\n\nfun calculateFinalPrice(price: Int): Int {\n // OK: Fixed after the analyzer highlighted this warning\n return price - DISCOUNT_AMOUNT;\n}\n"})})]})}function p(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>l});var r=n(6540);const i={},a=r.createContext(i);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/719e5d48.0bc6e809.js b/assets/js/719e5d48.0bc6e809.js new file mode 100644 index 000000000..55e4fa951 --- /dev/null +++ b/assets/js/719e5d48.0bc6e809.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[106],{4878:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>s,default:()=>p,frontMatter:()=>a,metadata:()=>l,toc:()=>d});var r=n(4848),i=n(8453);const a={},s="ReadOnlyVariables",l={id:"detectors/ReadOnlyVariables",title:"ReadOnlyVariables",description:"A detector that identifies read-only variables and fields.",source:"@site/versioned_docs/version-0.4.0/detectors/ReadOnlyVariables.md",sourceDirName:"detectors",slug:"/detectors/ReadOnlyVariables",permalink:"/tools/misti/docs/detectors/ReadOnlyVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/ReadOnlyVariables.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/detectors/PreferredStdlibApi"},next:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/detectors/StringReceiversOverlap"}},o={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"readonlyvariables",children:"ReadOnlyVariables"}),"\n",(0,r.jsx)(t.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"These variables could typically be replaced with constants to optimize performance.\nAlternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally."}),"\n",(0,r.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"fun calculateFinalPrice(price: Int): Int {\n // Warning: the developer uses a read-only variable that could be a constant\n let DISCOUNT_AMOUNT: Int = 10;\n return price - DISCOUNT_AMOUNT;\n}\n"})}),"\n",(0,r.jsx)(t.p,{children:"Use instead:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"const DISCOUNT_AMOUNT: Int = 10;\n\nfun calculateFinalPrice(price: Int): Int {\n // OK: Fixed after the analyzer highlighted this warning\n return price - DISCOUNT_AMOUNT;\n}\n"})})]})}function p(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>l});var r=n(6540);const i={},a=r.createContext(i);function s(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/72b7ad48.f6676fe3.js b/assets/js/72b7ad48.f6676fe3.js new file mode 100644 index 000000000..5361aff47 --- /dev/null +++ b/assets/js/72b7ad48.f6676fe3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2378],{6878:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var t=o(4848),s=o(8453);const i={},r="Unbound Loops",a={id:"detectors/UnboundLoops",title:"Unbound Loops",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/versioned_docs/version-0.2.1/detectors/UnboundLoops.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoops",permalink:"/tools/misti/docs/0.2.1/detectors/UnboundLoops",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/UnboundLoops.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Read-only Variables",permalink:"/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables"},next:{title:"Zero Address",permalink:"/tools/misti/docs/0.2.1/detectors/ZeroAddress"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"unbound-loops",children:"Unbound Loops"}),"\n",(0,t.jsx)(n.p,{children:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria."}),"\n",(0,t.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,t.jsx)(n.p,{children:"An unbounded loop can be problematic for several reasons:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult."}),"\n",(0,t.jsx)(n.li,{children:"Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks."}),"\n",(0,t.jsx)(n.li,{children:"DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability."}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n // Bad: x is not changed due looping\n send(SendParameters{ to: sender(), ... });\n}\n"})}),"\n",(0,t.jsx)(n.p,{children:"Use instead:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n send(SendParameters{ to: sender(), ... });\n x = x - 1;\n}\n"})})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,o)=>{o.d(n,{R:()=>r,x:()=>a});var t=o(6540);const s={},i=t.createContext(s);function r(e){const n=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/743bfbca.ba311b0c.js b/assets/js/743bfbca.ba311b0c.js new file mode 100644 index 000000000..e05e411c9 --- /dev/null +++ b/assets/js/743bfbca.ba311b0c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[121],{3372:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>d});var o=n(4848),r=n(8453);const i={},s="Custom Detector Guide",c={id:"hacking/custom-detector",title:"Custom Detector Guide",description:"Introduction",source:"@site/versioned_docs/version-0.1.2/hacking/custom-detector.md",sourceDirName:"hacking",slug:"/hacking/custom-detector",permalink:"/tools/misti/docs/0.1.2/hacking/custom-detector",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/hacking/custom-detector.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Tools",permalink:"/tools/misti/docs/0.1.2/hacking/tools"},next:{title:"CHANGELOG",permalink:"/tools/misti/docs/0.1.2/hacking/CHANGELOG"}},a={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Writing a Detector",id:"writing-a-detector",level:2},{value:"Example Detectors",id:"example-detectors",level:2}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h1,{id:"custom-detector-guide",children:"Custom Detector Guide"}),"\n",(0,o.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,o.jsxs)(t.p,{children:["Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: ",(0,o.jsx)(t.a,{href:"./api/",children:"Misti API Reference"}),"."]}),"\n",(0,o.jsxs)(t.p,{children:["Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the ",(0,o.jsx)(t.a,{href:"./api/classes/detectors_detector.Detector.html",children:(0,o.jsx)(t.code,{children:"Detector"})})," interface."]}),"\n",(0,o.jsx)(t.h2,{id:"writing-a-detector",children:"Writing a Detector"}),"\n",(0,o.jsx)(t.p,{children:"To write a custom detector, create a TypeScript file using the Misti API. Here's an example of how to implement a custom detector:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-typescript",children:'import { Detector } from "../../src/detectors/detector";\nimport { MistiContext } from "../../src/internals/context";\nimport { CompilationUnit } from "../../src/internals/ir";\nimport {\n createError,\n MistiTactError,\n Severity,\n} from "../../src/internals/errors";\n\n/**\n * An example of a custom detector that showcases the usage of the detector API.\n *\n * It reports all the contracts that don\'t have an explicit implementation of the init function.\n */\nexport class ImplicitInit extends Detector {\n check(ctx: MistiContext, cu: CompilationUnit): MistiTactError[] {\n return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {\n if (!cu.findMethodCFGByName(contract.name, "init")) {\n const err = createError(\n ctx,\n `contract ${contract.name} doesn\'t define an init function`,\n Severity.INFO,\n contract.ref,\n );\n foundErrors.push(err);\n }\n return foundErrors;\n }, [] as MistiTactError[]);\n }\n}\n'})}),"\n",(0,o.jsx)(t.p,{children:"After creating a detector, you need to specify it in your configuration. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{children:'{\n "detectors": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n\n { "className": "ImplicitInit", "modulePath": "/path/to/implicitInit.ts" }\n ],\n "ignored_projects": [],\n "verbosity": "default"\n}\n\n'})}),"\n",(0,o.jsxs)(t.p,{children:["After this, you could run the created detector specifying a path to it: ",(0,o.jsx)(t.code,{children:"--config path/to/mistiConfig.json test/projects/simple/tactConfig.json"}),"."]}),"\n",(0,o.jsx)(t.h2,{id:"example-detectors",children:"Example Detectors"}),"\n",(0,o.jsxs)(t.p,{children:["The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the ",(0,o.jsx)(t.a,{href:"https://github.com/nowarp/misti/tree/master/examples",children:"examples directory"})," in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors."]})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>c});var o=n(6540);const r={},i=o.createContext(r);function s(e){const t=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),o.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/7499c02a.f1eb98f3.js b/assets/js/7499c02a.f1eb98f3.js new file mode 100644 index 000000000..31f85341d --- /dev/null +++ b/assets/js/7499c02a.f1eb98f3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3150],{6400:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),i=n(8453);const r={},c="BranchDuplicate",o={id:"detectors/BranchDuplicate",title:"BranchDuplicate",description:"Detector that reports duplicated code in conditional branches.",source:"@site/versioned_docs/version-0.4.0/detectors/BranchDuplicate.md",sourceDirName:"detectors",slug:"/detectors/BranchDuplicate",permalink:"/tools/misti/docs/detectors/BranchDuplicate",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/BranchDuplicate.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"AsmIsUsed",permalink:"/tools/misti/docs/detectors/AsmIsUsed"},next:{title:"ConstantAddress",permalink:"/tools/misti/docs/detectors/ConstantAddress"}},a={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"branchduplicate",children:"BranchDuplicate"}),"\n",(0,s.jsx)(t.p,{children:"Detector that reports duplicated code in conditional branches."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Duplicated code in branches is bad because it:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Reduces Readability"}),": Repetition makes the code harder to understand."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Increases Maintenance"}),": Changes must be made in multiple places, risking errors."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Signals Poor Design"}),": It suggests missed opportunities for cleaner, more abstract code."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = 43; // bad: duplicated code\n} else {\n a = 43;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = inc(b); // ok\n} else {\n a = 43;\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>o});var s=n(6540);const i={},r=s.createContext(i);function c(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:c(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/754ccd45.2081d519.js b/assets/js/754ccd45.2081d519.js new file mode 100644 index 000000000..7037e3bf3 --- /dev/null +++ b/assets/js/754ccd45.2081d519.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3304],{1643:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var i=n(4848),s=n(8453);const r={},o="Developing Misti",a={id:"hacking/developing-misti",title:"Developing Misti",description:"Prerequisites",source:"@site/docs/hacking/developing-misti.md",sourceDirName:"hacking",slug:"/hacking/developing-misti",permalink:"/tools/misti/docs/next/hacking/developing-misti",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/hacking/developing-misti.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Contributing",permalink:"/tools/misti/docs/next/hacking/contributing"},next:{title:"Writing Custom Detectors",permalink:"/tools/misti/docs/next/hacking/custom-detector"}},c={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Cloning the Repository",id:"cloning-the-repository",level:2},{value:"Building the Project",id:"building-the-project",level:2},{value:"Running the Analyzer",id:"running-the-analyzer",level:2},{value:"Adding Backtraces to the Logger",id:"adding-backtraces-to-the-logger",level:2},{value:"Updating Expected Outputs of Tests",id:"updating-expected-outputs-of-tests",level:2}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"developing-misti",children:"Developing Misti"}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(t.p,{children:["Before you begin, please refer to the ",(0,i.jsx)(t.a,{href:"https://nowarp.io/tools/misti/docs/next/tutorial/getting-started",children:"Getting Started documentation"})," for the required system dependencies."]}),"\n",(0,i.jsx)(t.h2,{id:"cloning-the-repository",children:"Cloning the Repository"}),"\n",(0,i.jsx)(t.p,{children:"Clone the Misti repository:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"git clone 'https://github.com/nowarp/misti'\n"})}),"\n",(0,i.jsx)(t.h2,{id:"building-the-project",children:"Building the Project"}),"\n",(0,i.jsx)(t.p,{children:"Navigate to the project directory, install dependencies, generate necessary files, and build the project:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"cd misti && yarn install && yarn gen && yarn build\n"})}),"\n",(0,i.jsx)(t.h2,{id:"running-the-analyzer",children:"Running the Analyzer"}),"\n",(0,i.jsx)(t.p,{children:"During development, you can run the analyzer using:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"yarn misti\n"})}),"\n",(0,i.jsx)(t.p,{children:"For example, to run it for tests:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"yarn misti test/good/never-accessed.tact\n"})}),"\n",(0,i.jsx)(t.h2,{id:"adding-backtraces-to-the-logger",children:"Adding Backtraces to the Logger"}),"\n",(0,i.jsxs)(t.p,{children:["To add debug traces to all log messages, set the ",(0,i.jsx)(t.code,{children:"MISTI_TRACE"})," environment variable to ",(0,i.jsx)(t.code,{children:"1"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"export MISTI_TRACE=1\n"})}),"\n",(0,i.jsx)(t.h2,{id:"updating-expected-outputs-of-tests",children:"Updating Expected Outputs of Tests"}),"\n",(0,i.jsxs)(t.p,{children:["To update the expected outputs of tests, set the ",(0,i.jsx)(t.code,{children:"BLESS"})," environment variable and run the tests:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test\n"})}),"\n",(0,i.jsx)(t.p,{children:"You can also run a single test or update its expected output when working with a specific test file:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test test/tactIR.spec.ts tests/good/never-accessed.tact\n"})}),"\n",(0,i.jsx)(t.p,{children:"And for another specific test:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test test/builtinDetectors.spec.ts test/good/branch-duplicate.tact\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var i=n(6540);const s={},r=i.createContext(s);function o(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/76268162.332975fc.js b/assets/js/76268162.332975fc.js new file mode 100644 index 000000000..f4f39d806 --- /dev/null +++ b/assets/js/76268162.332975fc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7005],{1943:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var t=o(4848),s=o(8453);const i={},r="Unbound Loops",a={id:"detectors/UnboundLoops",title:"Unbound Loops",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/versioned_docs/version-0.2.0/detectors/UnboundLoops.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoops",permalink:"/tools/misti/docs/0.2.0/detectors/UnboundLoops",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/UnboundLoops.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Read-only Variables",permalink:"/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables"},next:{title:"Zero Address",permalink:"/tools/misti/docs/0.2.0/detectors/ZeroAddress"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"unbound-loops",children:"Unbound Loops"}),"\n",(0,t.jsx)(n.p,{children:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria."}),"\n",(0,t.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,t.jsx)(n.p,{children:"An unbounded loop can be problematic for several reasons:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult."}),"\n",(0,t.jsx)(n.li,{children:"Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks."}),"\n",(0,t.jsx)(n.li,{children:"DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability."}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n // Bad: x is not changed due looping\n send(SendParameters{ to: sender(), ... });\n}\n"})}),"\n",(0,t.jsx)(n.p,{children:"Use instead:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n send(SendParameters{ to: sender(), ... });\n x = x - 1;\n}\n"})})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,o)=>{o.d(n,{R:()=>r,x:()=>a});var t=o(6540);const s={},i=t.createContext(s);function r(e){const n=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/773c7ee4.d71f2dd0.js b/assets/js/773c7ee4.d71f2dd0.js new file mode 100644 index 000000000..bce954227 --- /dev/null +++ b/assets/js/773c7ee4.d71f2dd0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1564],{9113:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>f});var t=i(4848),r=i(8453);const s={},a="Souffl\xe9 Integration Guide",o={id:"hacking/souffle",title:"Souffl\xe9 Integration Guide",description:"What is Souffl\xe9?",source:"@site/versioned_docs/version-0.2.0/hacking/souffle.md",sourceDirName:"hacking",slug:"/hacking/souffle",permalink:"/tools/misti/docs/0.2.0/hacking/souffle",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/hacking/souffle.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Design Overview",permalink:"/tools/misti/docs/0.2.0/hacking/design"},next:{title:"Tools",permalink:"/tools/misti/docs/0.2.0/hacking/tools"}},l={},f=[{value:"What is Souffl\xe9?",id:"what-is-souffl\xe9",level:2},{value:"Benefits of Using Souffl\xe9 for Static Analysis",id:"benefits-of-using-souffl\xe9-for-static-analysis",level:2},{value:"Souffl\xe9 Integration in Misti",id:"souffl\xe9-integration-in-misti",level:2},{value:"Creating Souffl\xe9 Programs",id:"creating-souffl\xe9-programs",level:3},{value:"Generating Facts and Executing Souffl\xe9",id:"generating-facts-and-executing-souffl\xe9",level:3},{value:"Learning from Existing Code",id:"learning-from-existing-code",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"souffl\xe9-integration-guide",children:"Souffl\xe9 Integration Guide"}),"\n",(0,t.jsx)(n.h2,{id:"what-is-souffl\xe9",children:"What is Souffl\xe9?"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io",children:"Souffl\xe9"})," is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Souffl\xe9, Misti can perform deep and scalable analyses of smart contracts."]}),"\n",(0,t.jsx)(n.h2,{id:"benefits-of-using-souffl\xe9-for-static-analysis",children:"Benefits of Using Souffl\xe9 for Static Analysis"}),"\n",(0,t.jsx)(n.p,{children:"Souffl\xe9 allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Souffl\xe9 program might be more straightforward then implementing a complex transfer function in for a classic monotone framework."}),"\n",(0,t.jsx)(n.h2,{id:"souffl\xe9-integration-in-misti",children:"Souffl\xe9 Integration in Misti"}),"\n",(0,t.jsxs)(n.p,{children:["The API for interacting with Souffl\xe9 in Misti is detailed ",(0,t.jsx)(n.a,{href:"https://nowarp.github.io/docs/misti/api/modules/internals_souffle.html",children:"here"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"creating-souffl\xe9-programs",children:"Creating Souffl\xe9 Programs"}),"\n",(0,t.jsx)(n.p,{children:'To create a Souffl\xe9 program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:'}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addDecls(ctx: Context<SrcInfo>) {\n ctx.add(\n Relation.from(\n "varDecl",\n [\n ["var", FactType.Symbol],\n ["func", FactType.Symbol],\n ],\n undefined,\n ),\n );\n // other declarations\n}\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addRules(ctx: Context<SrcInfo>) {\n // readOnly(var, func) :-\n // varDecl(var, func),\n // !varAssign(var, func),\n // !varUse(var, func).\n ctx.add(\n Rule.from(\n [makeAtom("readOnly", ["var", "func"])],\n makeRuleBody(makeAtom("varDecl", ["var", "func"])),\n makeRuleBody(makeAtom("varAssign", ["var", "func"]), {\n negated: true,\n }),\n makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),\n ),\n );\n }\n'})}),"\n",(0,t.jsx)(n.h3,{id:"generating-facts-and-executing-souffl\xe9",children:"Generating Facts and Executing Souffl\xe9"}),"\n",(0,t.jsx)(n.p,{children:"After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Souffl\xe9 executor to run the analysis:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"const executor = ctx.config.soufflePath\n ? new Executor<SrcInfo>({\n inputDir: ctx.config.soufflePath,\n outputDir: ctx.config.soufflePath,\n })\n : new Executor<SrcInfo>();\n\nconst result = executor.executeSync(program);\n\nif (!result.success) {\n throw new Error(\n `Error executing Souffl\xe9 for ${this.id}:\\n${result.stderr}`,\n );\n}\n\nconst warnings = Array.from(result.results.entries.values()).map((fact) => {\n // raise warnings\n});\n"})}),"\n",(0,t.jsx)(n.h3,{id:"learning-from-existing-code",children:"Learning from Existing Code"}),"\n",(0,t.jsx)(n.p,{children:"We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Souffl\xe9 with Misti. This will help you understand the intricacies of generating IR and executing Souffl\xe9 programs effectively."}),"\n",(0,t.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,t.jsxs)(n.p,{children:["For a deeper understanding of static analysis using Souffl\xe9, refer to the textbook ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.a,{href:"https://arxiv.org/pdf/2012.10086",children:"Program Analysis: An Appetizer"})})," by Flemming Nielson and Hanne Riis Nielson. It discusses Souffl\xe9-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field."]})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>a,x:()=>o});var t=i(6540);const r={},s=t.createContext(r);function a(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/775287ab.a34207ca.js b/assets/js/775287ab.a34207ca.js new file mode 100644 index 000000000..0e1b07912 --- /dev/null +++ b/assets/js/775287ab.a34207ca.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8342],{1402:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var t=i(4848),s=i(8453);const o={},r="Contributing Guide",a={id:"hacking/contributing",title:"Contributing Guide",description:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.",source:"@site/versioned_docs/version-0.1.2/hacking/contributing.md",sourceDirName:"hacking",slug:"/hacking/contributing",permalink:"/tools/misti/docs/0.1.2/hacking/contributing",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/hacking/contributing.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Zero Address",permalink:"/tools/misti/docs/0.1.2/detectors/ZeroAddress"},next:{title:"Design Overview",permalink:"/tools/misti/docs/0.1.2/hacking/design"}},c={},d=[{value:"Issues reporting",id:"issues-reporting",level:2},{value:"Documentation contribution",id:"documentation-contribution",level:2},{value:"Code contribution",id:"code-contribution",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"contributing-guide",children:"Contributing Guide"}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better."}),"\n",(0,t.jsx)(n.h2,{id:"issues-reporting",children:"Issues reporting"}),"\n",(0,t.jsx)(n.p,{children:"When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.\nPlease help us by publishing it and the input sources at:\nhttps://github.com/nowarp/misti/issues/new.\n"})}),"\n",(0,t.jsx)(n.p,{children:"We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users."}),"\n",(0,t.jsx)(n.h2,{id:"documentation-contribution",children:"Documentation contribution"}),"\n",(0,t.jsxs)(n.p,{children:["We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/nowarp.github.io/issues",children:"nowarp.github.io Issues"}),". Additionally, many documentation pages have an ",(0,t.jsx)(n.code,{children:"Edit"})," button that allows you to make direct contributions easily."]}),"\n",(0,t.jsx)(n.h2,{id:"code-contribution",children:"Code contribution"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Navigate Issues and Find Tasks"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Browse the issues ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"here"}),". Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues."]}),"\n",(0,t.jsx)(n.li,{children:"Choose an issue suitable for you and mention in the issue that you're working on it."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Implement Your Changes"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Implement your changes. Feel free to ask questions in the issue if needed."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Ensure Tests Pass"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Before creating a PR, make sure all tests and CI checks are passing by running:","\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn test-all\n"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Create a PR"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Submit your pull request ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/pulls",children:"here"})]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Add a CHANGELOG entry"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Describe your changes in the ",(0,t.jsx)(n.code,{children:"CHANGELOG.md"})," file according to the existing structure."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/HACKING.md",children:"HACKING.md"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your contributions!"})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>a});var t=i(6540);const s={},o=t.createContext(s);function r(e){const n=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/776efca7.78ead050.js b/assets/js/776efca7.78ead050.js new file mode 100644 index 000000000..6ddb6e691 --- /dev/null +++ b/assets/js/776efca7.78ead050.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7151],{1883:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>d});var n=t(4848),s=t(8453);const i={},o="StringReceiversOverlap",a={id:"detectors/StringReceiversOverlap",title:"StringReceiversOverlap",description:"A detector that finds overlapping messages between general string receivers and string receivers.",source:"@site/versioned_docs/version-0.3.1/detectors/StringReceiversOverlap.md",sourceDirName:"detectors",slug:"/detectors/StringReceiversOverlap",permalink:"/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/StringReceiversOverlap.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables"},next:{title:"UnboundLoops",permalink:"/tools/misti/docs/0.3.1/detectors/UnboundLoops"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const r={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.h1,{id:"stringreceiversoverlap",children:"StringReceiversOverlap"}),"\n",(0,n.jsx)(r.p,{children:"A detector that finds overlapping messages between general string receivers and string receivers."}),"\n",(0,n.jsx)(r.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(r.p,{children:"Constant string receivers and general string receivers can have overlapping messages\nin which case the constant string receiver always takes precedence."}),"\n",(0,n.jsx)(r.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-tact",children:'contract Test {\n receive("foobar") { throw(1042) }\n receive(msg: String) {\n if (msg == "foobar") { throw(1043) } // Bad: Dead code\n }\n}\n'})}),"\n",(0,n.jsx)(r.p,{children:"Use instead:"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-tact",children:'contract Test {\n receive("foobar") { throw(1042) }\n receive(msg: String) {}\n}\n'})})]})}function p(e={}){const{wrapper:r}={...(0,s.R)(),...e.components};return r?(0,n.jsx)(r,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,r,t)=>{t.d(r,{R:()=>o,x:()=>a});var n=t(6540);const s={},i=n.createContext(s);function o(e){const r=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function a(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/7b5b3cc2.90aa7fd2.js b/assets/js/7b5b3cc2.90aa7fd2.js new file mode 100644 index 000000000..b3a4a5f06 --- /dev/null +++ b/assets/js/7b5b3cc2.90aa7fd2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6612],{8962:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var i=n(4848),a=n(8453);const r={},s="InheritedStateMutation",o={id:"detectors/InheritedStateMutation",title:"InheritedStateMutation",description:"An optional detector that highlights all instances where inherited trait variables",source:"@site/versioned_docs/version-0.3.0/detectors/InheritedStateMutation.md",sourceDirName:"detectors",slug:"/detectors/InheritedStateMutation",permalink:"/tools/misti/docs/0.3.0/detectors/InheritedStateMutation",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/InheritedStateMutation.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"FieldDoubleInit",permalink:"/tools/misti/docs/0.3.0/detectors/FieldDoubleInit"},next:{title:"NeverAccessedVariables",permalink:"/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"inheritedstatemutation",children:"InheritedStateMutation"}),"\n",(0,i.jsx)(t.p,{children:"An optional detector that highlights all instances where inherited trait variables\nare directly modified."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsxs)(t.p,{children:["Traits should provide setter methods to ensure that invariants related to their\nstate are preserved. Directly modifying trait variables (e.g., ",(0,i.jsx)(t.code,{children:"self.traitVar = 42"}),")\ncan violate these invariants, leading to potential bugs or security vulnerabilities.\nThis detector warns when such direct modifications occur, prompting further review\nby auditors."]}),"\n",(0,i.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"trait T {\n balance: Int;\n}\n\ncontract C with T {\n balance: Int = 42;\n fun updateBalance() {\n self.balance = 100; // Suspicious: Highlighted by the detector\n }\n}\n"})}),"\n",(0,i.jsx)(t.p,{children:"Use instead:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:'trait T {\n balance: Int;\n fun setBalance(newBalance: Int) {\n require(newBalance > 0, "balance cannot be negative"); // Invariant check\n self.balance = newBalance;\n }\n}\n\ncontract C with T {\n balance: Int = 42;\n fun updateBalance() {\n self.setBalance(100); // OK: Invariant preserved\n }\n}\n'})})]})}function h(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(6540);const a={},r=i.createContext(a);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/81087c81.7da41d03.js b/assets/js/81087c81.7da41d03.js new file mode 100644 index 000000000..f769ead53 --- /dev/null +++ b/assets/js/81087c81.7da41d03.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6869],{2140:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>l,frontMatter:()=>r,metadata:()=>c,toc:()=>d});var i=n(4848),o=n(8453);const r={},s="Custom Detector Guide",c={id:"hacking/custom-detector",title:"Custom Detector Guide",description:"Introduction",source:"@site/versioned_docs/version-0.3.0/hacking/custom-detector.md",sourceDirName:"hacking",slug:"/hacking/custom-detector",permalink:"/tools/misti/docs/0.3.0/hacking/custom-detector",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/hacking/custom-detector.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Tools",permalink:"/tools/misti/docs/0.3.0/hacking/tools"}},a={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Creating a Detector",id:"creating-a-detector",level:2},{value:"Testing the detector",id:"testing-the-detector",level:3},{value:"Saving the configuration",id:"saving-the-configuration",level:3},{value:"Example Detectors",id:"example-detectors",level:2}];function h(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"custom-detector-guide",children:"Custom Detector Guide"}),"\n",(0,i.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsxs)(t.p,{children:["Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: ",(0,i.jsx)(t.a,{href:"https://nowarp.io/tools/misti/api/",children:"Misti API Reference"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the ",(0,i.jsx)(t.a,{href:"https://nowarp.io/tools/misti/api/classes/detectors_detector.Detector.html",children:(0,i.jsx)(t.code,{children:"Detector"})})," interface."]}),"\n",(0,i.jsx)(t.h2,{id:"creating-a-detector",children:"Creating a Detector"}),"\n",(0,i.jsxs)(t.p,{children:["You can create a new custom detector by executing Misti with the ",(0,i.jsx)(t.code,{children:"--new-detector"})," option: ",(0,i.jsx)(t.code,{children:"npx misti --new-detector implicitInit"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["This will create the ",(0,i.jsx)(t.code,{children:"implicitInit.ts"})," file, which contains the template code for writing your own custom detector logic leveraging the Misti API."]}),"\n",(0,i.jsx)(t.p,{children:"Here's an example of how to implement a custom detector using Misti API:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-typescript",children:'import { Detector } from "@nowarp/misti/dist/detectors/detector";\nimport { CompilationUnit } from "@nowarp/misti/dist/internals/ir";\nimport {\n MistiTactWarning,\n Severity,\n} from "@nowarp/misti/dist/internals/errors";\n\n/**\n * An example of a custom detector that showcases the usage of the detector API.\n *\n * It reports all the contracts that doesn\'t have an explicit implementation of the init function.\n */\nexport class ImplicitInit extends Detector {\n async check(cu: CompilationUnit): Promise<MistiTactWarning[]> {\n return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {\n if (!cu.findMethodCFGByName(contract.name, "init")) {\n const err = this.makeError(\n `Contract ${contract.name} doesn\'t define an init function`,\n Severity.INFO,\n contract.ref,\n );\n foundErrors.push(err);\n }\n return foundErrors;\n }, [] as MistiTactWarning[]);\n }\n}\n'})}),"\n",(0,i.jsx)(t.h3,{id:"testing-the-detector",children:"Testing the detector"}),"\n",(0,i.jsxs)(t.p,{children:["To run Misti with only your new detector, use the ",(0,i.jsx)(t.code,{children:"--detectors"})," option, specifying the path to the detector and the Detector class name: ",(0,i.jsx)(t.code,{children:"npx misti path/to/your/tact.config.json --detectors path/to/implicitInit.ts:ImplicitInit"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["That's a good way to test the detector on the first run. You could also use the ",(0,i.jsx)(t.code,{children:"--verbose"})," CLI option and set the environment variable ",(0,i.jsx)(t.code,{children:"MISTI_TRACE=1"})," to facilitate debugging."]}),"\n",(0,i.jsx)(t.h3,{id:"saving-the-configuration",children:"Saving the configuration"}),"\n",(0,i.jsx)(t.p,{children:"After testing the detector, you can specify it in your configuration to enable it in future runs. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{children:'{\n "detectors": [\n // Other detectors...\n { "className": "ImplicitInit", "modulePath": "ImplicitInit.ts" }\n ],\n}\n'})}),"\n",(0,i.jsxs)(t.p,{children:["After this, you could run Misti specifying a path to a custom configuration ",(0,i.jsx)(t.code,{children:"npx misti --config path/to/misti.config.json path/to/your/tact.config.json"}),"."]}),"\n",(0,i.jsx)(t.h2,{id:"example-detectors",children:"Example Detectors"}),"\n",(0,i.jsxs)(t.p,{children:["The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/tree/master/examples",children:"examples directory"})," in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors."]})]})}function l(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>c});var i=n(6540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8272dc48.d9a84b38.js b/assets/js/8272dc48.d9a84b38.js new file mode 100644 index 000000000..ed5f14c5e --- /dev/null +++ b/assets/js/8272dc48.d9a84b38.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1529],{2184:(i,e,t)=>{t.r(e),t.d(e,{assets:()=>o,contentTitle:()=>I,default:()=>c,frontMatter:()=>l,metadata:()=>d,toc:()=>g});var n=t(4848),s=t(8453);const l={},I="Tools Guide",d={id:"hacking/tools",title:"Tools Guide",description:"This page describes the internal analyzer tools available in Misti to aid in development and debugging.",source:"@site/versioned_docs/version-0.2.0/hacking/tools.md",sourceDirName:"hacking",slug:"/hacking/tools",permalink:"/tools/misti/docs/0.2.0/hacking/tools",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/hacking/tools.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.2.0/hacking/souffle"},next:{title:"Custom Detectors",permalink:"/tools/misti/docs/0.2.0/hacking/custom-detector"}},o={},g=[{value:"CFG Dump",id:"cfg-dump",level:2},{value:"Usage",id:"usage",level:3},{value:"Converting DOT to SVG",id:"converting-dot-to-svg",level:3},{value:"Viewing the SVG",id:"viewing-the-svg",level:3},{value:"VS Code Plugin",id:"vs-code-plugin",level:3},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function a(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"tools-guide",children:"Tools Guide"}),"\n",(0,n.jsx)(e.p,{children:"This page describes the internal analyzer tools available in Misti to aid in development and debugging."}),"\n",(0,n.jsx)(e.h2,{id:"cfg-dump",children:"CFG Dump"}),"\n",(0,n.jsx)(e.p,{children:"Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts."}),"\n",(0,n.jsx)(e.h3,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in JSON format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in DOT format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.h3,{id:"converting-dot-to-svg",children:"Converting DOT to SVG"}),"\n",(0,n.jsxs)(e.p,{children:["To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use ",(0,n.jsx)(e.a,{href:"https://graphviz.org",children:"Graphviz"})," with the following command:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot\ndot -Tsvg output.dot -o output.svg\n'})}),"\n",(0,n.jsx)(e.h3,{id:"viewing-the-svg",children:"Viewing the SVG"}),"\n",(0,n.jsx)(e.p,{children:"To view the SVG file in Firefox, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"firefox output.svg\n"})}),"\n",(0,n.jsx)(e.p,{children:"For example, for the following contract:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:"fun test(): Int {\n let sum: Int = 0;\n let i: Int = 0;\n repeat (10) {\n i = i + 1;\n sum = sum + i;\n }\n return sum;\n}\n"})}),"\n",(0,n.jsx)(e.p,{children:"The following CFG will be generated:"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"CFG Example",src:t(685).A+"",width:"337",height:"516"})}),"\n",(0,n.jsx)(e.h3,{id:"vs-code-plugin",children:"VS Code Plugin"}),"\n",(0,n.jsxs)(e.p,{children:["For real-time visualization of DOT files, you can use ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/search?term=tag%3Agraphviz&target=VSCode&category=All%20categories&sortBy=Relevance",children:"one of the available"})," Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development."]}),"\n",(0,n.jsx)(e.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"JSON Dumps"}),": These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"DOT Dumps"}),": These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(e.p,{children:"By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors."})]})}function c(i={}){const{wrapper:e}={...(0,s.R)(),...i.components};return e?(0,n.jsx)(e,{...i,children:(0,n.jsx)(a,{...i})}):a(i)}},685:(i,e,t)=>{t.d(e,{A:()=>n});const n="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDIuNCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBsb29wcyYjNDU7MyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjUzcHQiIGhlaWdodD0iMzg3cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjUzLjAwIDM4Ny4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzODMpIj4KPHRpdGxlPmxvb3BzJiM0NTszPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzgzIDI0OSwtMzgzIDI0OSw0IC00LDQiLz4KPGcgaWQ9ImNsdXN0MSIgY2xhc3M9ImNsdXN0ZXIiPgo8dGl0bGU+Y2x1c3Rlcl90ZXN0PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI4LC04IDgsLTM3MSAyMzcsLTM3MSAyMzcsLTggOCwtOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIuNSIgeT0iLTM1NS44IiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnRlc3Q8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0MSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT50ZXN0XzE0MTwvdGl0bGU+Cjxwb2x5Z29uIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjI0LjUsLTM0MCA5NS41LC0zNDAgOTUuNSwtMzA0IDIyNC41LC0zMDQgMjI0LjUsLTM0MCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNjAiIHk9Ii0zMTguMyIgZm9udC1mYW1pbHk9IlRpbWVzLHNlcmlmIiBmb250LXNpemU9IjE0LjAwIj5sZXQgc3VtOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDI8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMiwtMjY4IDEwOCwtMjY4IDEwOCwtMjMyIDIxMiwtMjMyIDIxMiwtMjY4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTI0Ni4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPmxldCBpOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDEmIzQ1OyZndDt0ZXN0XzE0MiAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MSYjNDU7Jmd0O3Rlc3RfMTQyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMzAzLjdDMTYwLC0yOTUuOTggMTYwLC0yODYuNzEgMTYwLC0yNzguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTI3OC4xIDE2MCwtMjY4LjEgMTU2LjUsLTI3OC4xIDE2My41LC0yNzguMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDQ8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOCwtMTk2IDExMiwtMTk2IDExMiwtMTYwIDIwOCwtMTYwIDIwOCwtMTk2Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTE3NC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnJlcGVhdCAoMTApPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDImIzQ1OyZndDt0ZXN0XzE0NCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MiYjNDU7Jmd0O3Rlc3RfMTQ0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMjMxLjdDMTYwLC0yMjMuOTggMTYwLC0yMTQuNzEgMTYwLC0yMDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTIwNi4xIDE2MCwtMTk2LjEgMTU2LjUsLTIwNi4xIDE2My41LC0yMDYuMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDYgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDY8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjkzLjUsLTEyNCAxNi41LC0xMjQgMTYuNSwtODggOTMuNSwtODggOTMuNSwtMTI0Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjU1IiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+aSA9IGkgKyAxPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE0NiAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0NCYjNDU7Jmd0O3Rlc3RfMTQ2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEzNC4zMSwtMTU5Ljg4QzEyMC43MSwtMTUwLjgxIDEwMy44MywtMTM5LjU1IDg5LjE0LC0xMjkuNzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iOTEuMDUsLTEyNi44MiA4MC43OCwtMTI0LjE5IDg3LjE2LC0xMzIuNjUgOTEuMDUsLTEyNi44MiIvPgo8L2c+CjwhLS0gdGVzdF8xNTEgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNTE8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjNjZhN2RiIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOC41LC0xMjQgMTExLjUsLTEyNCAxMTEuNSwtODggMjA4LjUsLTg4IDIwOC41LC0xMjQiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTYwIiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+cmV0dXJuIHN1bTwvdGV4dD4KPC9nPgo8IS0tIHRlc3RfMTQ0JiM0NTsmZ3Q7dGVzdF8xNTEgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE1MTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNjAsLTE1OS43QzE2MCwtMTUxLjk4IDE2MCwtMTQyLjcxIDE2MCwtMTM0LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2My41LC0xMzQuMSAxNjAsLTEyNC4xIDE1Ni41LC0xMzQuMSAxNjMuNSwtMTM0LjEiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPnRlc3RfMTQ4PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxODMuNSwtNTIgNjAuNSwtNTIgNjAuNSwtMTYgMTgzLjUsLTE2IDE4My41LC01MiIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIiIHk9Ii0zMC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnN1bSA9IHN1bSArIGk8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0NiYjNDU7Jmd0O3Rlc3RfMTQ4IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPnRlc3RfMTQ2JiM0NTsmZ3Q7dGVzdF8xNDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuNTYsLTg3LjdDNzkuNjgsLTc5LjIyIDg5LjU5LC02OC44NiA5OC40NywtNTkuNTgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAxLjI0LC02MS43NSAxMDUuNjMsLTUyLjEgOTYuMTksLTU2LjkxIDEwMS4yNCwtNjEuNzUiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4JiM0NTsmZ3Q7dGVzdF8xNDQgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDgmIzQ1OyZndDt0ZXN0XzE0NDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzUuMjIsLTUyLjA0QzE5MS44OSwtNjAuMTYgMjA4LjQyLC03MS43NyAyMTgsLTg4IDIyNi4xMywtMTAxLjc4IDIyNC40NSwtMTA5LjM2IDIxOCwtMTI0IDIxMy4wMSwtMTM1LjMxIDIwNC4yOSwtMTQ1LjI2IDE5NS4xLC0xNTMuMzgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTkyLjgzLC0xNTAuNzIgMTg3LjM0LC0xNTkuNzcgMTk3LjI4LC0xNTYuMTIgMTkyLjgzLC0xNTAuNzIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8453:(i,e,t)=>{t.d(e,{R:()=>I,x:()=>d});var n=t(6540);const s={},l=n.createContext(s);function I(i){const e=n.useContext(l);return n.useMemo((function(){return"function"==typeof i?i(e):{...e,...i}}),[e,i])}function d(i){let e;return e=i.disableParentContext?"function"==typeof i.components?i.components(s):i.components||s:I(i.components),n.createElement(l.Provider,{value:e},i.children)}}}]); \ No newline at end of file diff --git a/assets/js/8306354c.2bbb254d.js b/assets/js/8306354c.2bbb254d.js new file mode 100644 index 000000000..27fb5d878 --- /dev/null +++ b/assets/js/8306354c.2bbb254d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7877],{9164:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var s=n(4848),r=n(8453);const i={},o="PreferAugmentedAssign",a={id:"detectors/PreferAugmentedAssign",title:"PreferAugmentedAssign",description:"Detects non-idiomatic statements that can be written using augmented assignment",source:"@site/versioned_docs/version-0.4.0/detectors/PreferAugmentedAssign.md",sourceDirName:"detectors",slug:"/detectors/PreferAugmentedAssign",permalink:"/tools/misti/docs/detectors/PreferAugmentedAssign",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/PreferAugmentedAssign.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"OptimalMathFunction",permalink:"/tools/misti/docs/detectors/OptimalMathFunction"},next:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/detectors/PreferredStdlibApi"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"preferaugmentedassign",children:"PreferAugmentedAssign"}),"\n",(0,s.jsxs)(t.p,{children:["Detects non-idiomatic statements that can be written using augmented assignment\noperators like ",(0,s.jsx)(t.code,{children:"+="}),", ",(0,s.jsx)(t.code,{children:"-="}),", etc."]}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Using augmented assignment operations improves the readability of the source code\nand reduces the risk of mistakes, such as those that occur during copy-pasting\nand refactoring code."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue = (msgValue - ctx.readForwardFee());\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue -= ctx.readForwardFee());\n"})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(6540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/844f22a2.2f80fdcf.js b/assets/js/844f22a2.2f80fdcf.js new file mode 100644 index 000000000..b4d82e564 --- /dev/null +++ b/assets/js/844f22a2.2f80fdcf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5316],{9095:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var t=i(4848),s=i(8453);const l={},r="Getting started",o={id:"tutorial/getting-started",title:"Getting started",description:"This guide will walk you through the steps to install and set up the Misti static analyzer.",source:"@site/versioned_docs/version-0.3.0/tutorial/getting-started.md",sourceDirName:"tutorial",slug:"/tutorial/getting-started",permalink:"/tools/misti/docs/0.3.0/tutorial/getting-started",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/tutorial/getting-started.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Introduction",permalink:"/tools/misti/docs/0.3.0/"},next:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.3.0/tutorial/ci-cd"}},a={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Using Development Version",id:"using-development-version",level:3},{value:"Running the analysis",id:"running-the-analysis",level:2},{value:"More usage examples",id:"more-usage-examples",level:2},{value:"Suppressing Specific Detectors",id:"suppressing-specific-detectors",level:3},{value:"Enabling All Detectors",id:"enabling-all-detectors",level:3},{value:"Running in Quiet Mode",id:"running-in-quiet-mode",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,t.jsx)(n.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsx)(n.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Git"}),"\n",(0,t.jsx)(n.li,{children:"Yarn"}),"\n",(0,t.jsx)(n.li,{children:"Node.js version 22 or higher"}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,t.jsxs)(n.p,{children:["Misti is distributed via npm and should be added to your Tact project ",(0,t.jsx)(n.a,{href:"https://github.com/tact-lang/tact?tab=readme-ov-file#installation",children:"in the same way"})," as Tact itself:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn add @nowarp/misti\n"})}),"\n",(0,t.jsx)(n.h3,{id:"using-development-version",children:"Using Development Version"}),"\n",(0,t.jsx)(n.p,{children:"The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis."}),"\n",(0,t.jsx)(n.p,{children:"To install the latest development version you should:"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["Clone Misti: ",(0,t.jsx)(n.code,{children:"git clone https://github.com/nowarp/misti"})]}),"\n",(0,t.jsxs)(n.li,{children:["Build it: ",(0,t.jsx)(n.code,{children:"cd misti && yarn install && yarn build"})]}),"\n",(0,t.jsxs)(n.li,{children:["Use it in your Tact project: ",(0,t.jsx)(n.code,{children:"cd /path/to/tact/project && yarn add file:/path/to/misti"})]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,t.jsx)(n.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"npx misti path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,t.jsxs)(n.p,{children:["You can also add a script to your ",(0,t.jsx)(n.code,{children:"package.json"})," to simplify running the linting process:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "scripts": {\n "lint": "npx misti path/to/tact.config.json"\n }\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"more-usage-examples",children:"More usage examples"}),"\n",(0,t.jsxs)(n.p,{children:["Below are a few usage examples for common scenarios when using ",(0,t.jsxs)(n.a,{href:"/tools/misti/docs/0.3.0/tutorial/cli",children:["the ",(0,t.jsx)(n.code,{children:"misti"})," CLI"]}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"suppressing-specific-detectors",children:"Suppressing Specific Detectors"}),"\n",(0,t.jsxs)(n.p,{children:["To run ",(0,t.jsx)(n.code,{children:"misti"})," while suppressing specific detectors, such as ",(0,t.jsx)(n.code,{children:"ReadOnlyVariables"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --suppress ReadOnlyVariables path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.h3,{id:"enabling-all-detectors",children:"Enabling All Detectors"}),"\n",(0,t.jsxs)(n.p,{children:["Running ",(0,t.jsx)(n.code,{children:"misti"})," with all available built-in detectors enabled:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --all-detectors path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"It is recommended to do that when auditing the project."}),"\n",(0,t.jsx)(n.h3,{id:"running-in-quiet-mode",children:"Running in Quiet Mode"}),"\n",(0,t.jsxs)(n.p,{children:["To suppress all output while running ",(0,t.jsx)(n.code,{children:"misti"})," getting just a return code:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --quiet path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This might be useful in scripts and CI/CD."}),"\n",(0,t.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,t.jsxs)(n.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,t.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>o});var t=i(6540);const s={},l=t.createContext(s);function r(e){const n=t.useContext(l);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/866ed13d.d4edfa4a.js b/assets/js/866ed13d.d4edfa4a.js new file mode 100644 index 000000000..3eed53997 --- /dev/null +++ b/assets/js/866ed13d.d4edfa4a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6974],{9515:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>a,contentTitle:()=>d,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var n=s(4848),r=s(8453);const o={},d="ZeroAddress",i={id:"detectors/ZeroAddress",title:"ZeroAddress",description:"A detector that identifies uses of the zero address.",source:"@site/docs/detectors/ZeroAddress.md",sourceDirName:"detectors",slug:"/detectors/ZeroAddress",permalink:"/tools/misti/docs/next/detectors/ZeroAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/ZeroAddress.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"UnusedOptional",permalink:"/tools/misti/docs/next/detectors/UnusedOptional"},next:{title:"Overview",permalink:"/tools/misti/docs/next/tools"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"zeroaddress",children:"ZeroAddress"}),"\n",(0,n.jsx)(t.p,{children:"A detector that identifies uses of the zero address."}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Using the zero address in smart contracts is typically problematic because it can be\nexploited as a default or uninitialized address, leading to unintended transfers and\nsecurity vulnerabilities. Additionally, operations involving the zero address can\nresult in loss of funds or tokens, as there is no private key to access this address."}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init() {\n // Warning: Insecure usage of zero address as default value\n self.to = newAddress(0, 0);\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init(to: Address) {\n // Fixed: Using the input value on initialization.\n self.to = to;\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>d,x:()=>i});var n=s(6540);const r={},o=n.createContext(r);function d(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:d(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/86d22c3d.22d9a99e.js b/assets/js/86d22c3d.22d9a99e.js new file mode 100644 index 000000000..e65a93912 --- /dev/null +++ b/assets/js/86d22c3d.22d9a99e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1407],{5012:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.4.0","label":"0.4.0","banner":null,"badge":true,"noIndex":false,"className":"docs-version-0.4.0","isLast":true,"docsSidebars":{"sidebar":[{"type":"link","label":"Introduction","href":"/tools/misti/docs/","docId":"intro","unlisted":false},{"type":"category","label":"Tutorial","items":[{"type":"link","label":"Getting Started","href":"/tools/misti/docs/tutorial/getting-started","docId":"tutorial/getting-started","unlisted":false},{"type":"link","label":"CI/CD Integration","href":"/tools/misti/docs/tutorial/ci-cd","docId":"tutorial/ci-cd","unlisted":false},{"type":"link","label":"Command-Line Interface","href":"/tools/misti/docs/tutorial/cli","docId":"tutorial/cli","unlisted":false},{"type":"link","label":"Configuration","href":"/tools/misti/docs/tutorial/configuration","docId":"tutorial/configuration","unlisted":false},{"type":"link","label":"Using with Blueprint","href":"/tools/misti/docs/tutorial/blueprint","docId":"tutorial/blueprint","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Detectors Overview","href":"/tools/misti/docs/detectors","docId":"detectors","unlisted":false},{"type":"category","label":"Detectors","items":[{"type":"link","label":"ArgCopyMutation","href":"/tools/misti/docs/detectors/ArgCopyMutation","docId":"detectors/ArgCopyMutation","unlisted":false},{"type":"link","label":"AsmIsUsed","href":"/tools/misti/docs/detectors/AsmIsUsed","docId":"detectors/AsmIsUsed","unlisted":false},{"type":"link","label":"BranchDuplicate","href":"/tools/misti/docs/detectors/BranchDuplicate","docId":"detectors/BranchDuplicate","unlisted":false},{"type":"link","label":"ConstantAddress","href":"/tools/misti/docs/detectors/ConstantAddress","docId":"detectors/ConstantAddress","unlisted":false},{"type":"link","label":"DivideBeforeMultiply","href":"/tools/misti/docs/detectors/DivideBeforeMultiply","docId":"detectors/DivideBeforeMultiply","unlisted":false},{"type":"link","label":"DumpIsUsed","href":"/tools/misti/docs/detectors/DumpIsUsed","docId":"detectors/DumpIsUsed","unlisted":false},{"type":"link","label":"DuplicatedCondition","href":"/tools/misti/docs/detectors/DuplicatedCondition","docId":"detectors/DuplicatedCondition","unlisted":false},{"type":"link","label":"EnsurePrgSeed","href":"/tools/misti/docs/detectors/EnsurePrgSeed","docId":"detectors/EnsurePrgSeed","unlisted":false},{"type":"link","label":"FalseCondition","href":"/tools/misti/docs/detectors/FalseCondition","docId":"detectors/FalseCondition","unlisted":false},{"type":"link","label":"FieldDoubleInit","href":"/tools/misti/docs/detectors/FieldDoubleInit","docId":"detectors/FieldDoubleInit","unlisted":false},{"type":"link","label":"InheritedStateMutation","href":"/tools/misti/docs/detectors/InheritedStateMutation","docId":"detectors/InheritedStateMutation","unlisted":false},{"type":"link","label":"NeverAccessedVariables","href":"/tools/misti/docs/detectors/NeverAccessedVariables","docId":"detectors/NeverAccessedVariables","unlisted":false},{"type":"link","label":"OptimalMathFunction","href":"/tools/misti/docs/detectors/OptimalMathFunction","docId":"detectors/OptimalMathFunction","unlisted":false},{"type":"link","label":"PreferAugmentedAssign","href":"/tools/misti/docs/detectors/PreferAugmentedAssign","docId":"detectors/PreferAugmentedAssign","unlisted":false},{"type":"link","label":"PreferredStdlibApi","href":"/tools/misti/docs/detectors/PreferredStdlibApi","docId":"detectors/PreferredStdlibApi","unlisted":false},{"type":"link","label":"ReadOnlyVariables","href":"/tools/misti/docs/detectors/ReadOnlyVariables","docId":"detectors/ReadOnlyVariables","unlisted":false},{"type":"link","label":"StringReceiversOverlap","href":"/tools/misti/docs/detectors/StringReceiversOverlap","docId":"detectors/StringReceiversOverlap","unlisted":false},{"type":"link","label":"UnboundLoops","href":"/tools/misti/docs/detectors/UnboundLoops","docId":"detectors/UnboundLoops","unlisted":false},{"type":"link","label":"UnusedOptional","href":"/tools/misti/docs/detectors/UnusedOptional","docId":"detectors/UnusedOptional","unlisted":false},{"type":"link","label":"ZeroAddress","href":"/tools/misti/docs/detectors/ZeroAddress","docId":"detectors/ZeroAddress","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Tools Overview","href":"/tools/misti/docs/tools","docId":"tools","unlisted":false},{"type":"category","label":"Tools","items":[{"type":"link","label":"DumpAst","href":"/tools/misti/docs/tools/DumpAst","docId":"tools/DumpAst","unlisted":false},{"type":"link","label":"DumpCfg","href":"/tools/misti/docs/tools/DumpCfg","docId":"tools/DumpCfg","unlisted":false},{"type":"link","label":"DumpConfig","href":"/tools/misti/docs/tools/DumpConfig","docId":"tools/DumpConfig","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacking","items":[{"type":"link","label":"Contributing","href":"/tools/misti/docs/hacking/contributing","docId":"hacking/contributing","unlisted":false},{"type":"link","label":"Developing Misti","href":"/tools/misti/docs/hacking/developing-misti","docId":"hacking/developing-misti","unlisted":false},{"type":"link","label":"Design Overview","href":"/tools/misti/docs/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/hacking/souffle","docId":"hacking/souffle","unlisted":false},{"type":"link","label":"Custom Detectors","href":"/tools/misti/docs/hacking/custom-detector","docId":"hacking/custom-detector","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"detectors":{"id":"detectors","title":"Detectors Overview","description":"Misti currently supports 20 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:","sidebar":"sidebar"},"detectors/ArgCopyMutation":{"id":"detectors/ArgCopyMutation","title":"ArgCopyMutation","description":"A detector that highlights cases where function argument mutations are ineffective","sidebar":"sidebar"},"detectors/AsmIsUsed":{"id":"detectors/AsmIsUsed","title":"AsmIsUsed","description":"An optional detector that highlights all the asm functions.","sidebar":"sidebar"},"detectors/BranchDuplicate":{"id":"detectors/BranchDuplicate","title":"BranchDuplicate","description":"Detector that reports duplicated code in conditional branches.","sidebar":"sidebar"},"detectors/ConstantAddress":{"id":"detectors/ConstantAddress","title":"ConstantAddress","description":"An optional detector that highlights all the constant addresses appearing in the source code.","sidebar":"sidebar"},"detectors/DivideBeforeMultiply":{"id":"detectors/DivideBeforeMultiply","title":"DivideBeforeMultiply","description":"A detector that identifies and corrects instances of division before multiplication to","sidebar":"sidebar"},"detectors/DumpIsUsed":{"id":"detectors/DumpIsUsed","title":"DumpIsUsed","description":"An optional detector that highlights all the dump debug prints.","sidebar":"sidebar"},"detectors/DuplicatedCondition":{"id":"detectors/DuplicatedCondition","title":"DuplicatedCondition","description":"A detector that finds duplicated conditions appearing in conditional expressions.","sidebar":"sidebar"},"detectors/EnsurePrgSeed":{"id":"detectors/EnsurePrgSeed","title":"EnsurePrgSeed","description":"A detector that identifies all calls to nativeRandom and nativeRandomInterval","sidebar":"sidebar"},"detectors/FalseCondition":{"id":"detectors/FalseCondition","title":"FalseCondition","description":"A detector that highlights conditions that evaluate to a constant true or false","sidebar":"sidebar"},"detectors/FieldDoubleInit":{"id":"detectors/FieldDoubleInit","title":"FieldDoubleInit","description":"A detector that highlights cases where a field is initialized both in the","sidebar":"sidebar"},"detectors/InheritedStateMutation":{"id":"detectors/InheritedStateMutation","title":"InheritedStateMutation","description":"An optional detector that highlights all instances where inherited trait variables","sidebar":"sidebar"},"detectors/NeverAccessedVariables":{"id":"detectors/NeverAccessedVariables","title":"NeverAccessedVariables","description":"A detector that identifies write-only or unused variables, fields and constants.","sidebar":"sidebar"},"detectors/OptimalMathFunction":{"id":"detectors/OptimalMathFunction","title":"OptimalMathFunction","description":"A detector that highlights standard library math function calls that have more gas-efficient alternatives.","sidebar":"sidebar"},"detectors/PreferAugmentedAssign":{"id":"detectors/PreferAugmentedAssign","title":"PreferAugmentedAssign","description":"Detects non-idiomatic statements that can be written using augmented assignment","sidebar":"sidebar"},"detectors/PreferredStdlibApi":{"id":"detectors/PreferredStdlibApi","title":"PreferredStdlibApi","description":"An optional detector that flags the use of advanced functions from the standard library.","sidebar":"sidebar"},"detectors/ReadOnlyVariables":{"id":"detectors/ReadOnlyVariables","title":"ReadOnlyVariables","description":"A detector that identifies read-only variables and fields.","sidebar":"sidebar"},"detectors/StringReceiversOverlap":{"id":"detectors/StringReceiversOverlap","title":"StringReceiversOverlap","description":"A detector that finds overlapping messages between general string receivers and string receivers.","sidebar":"sidebar"},"detectors/UnboundLoops":{"id":"detectors/UnboundLoops","title":"UnboundLoops","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/UnusedOptional":{"id":"detectors/UnusedOptional","title":"UnusedOptional","description":"A detector variables and fields with unused optional modifier.","sidebar":"sidebar"},"detectors/ZeroAddress":{"id":"detectors/ZeroAddress","title":"ZeroAddress","description":"A detector that identifies uses of the zero address.","sidebar":"sidebar"},"hacking/contributing":{"id":"hacking/contributing","title":"Contributing Guide","description":"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.","sidebar":"sidebar"},"hacking/custom-detector":{"id":"hacking/custom-detector","title":"Custom Detector Guide","description":"Introduction","sidebar":"sidebar"},"hacking/design":{"id":"hacking/design","title":"Design Overview","description":"Static Analysis","sidebar":"sidebar"},"hacking/developing-misti":{"id":"hacking/developing-misti","title":"Developing Misti","description":"Prerequisites","sidebar":"sidebar"},"hacking/souffle":{"id":"hacking/souffle","title":"Souffl\xe9 Integration Guide","description":"What is Souffl\xe9?","sidebar":"sidebar"},"intro":{"id":"intro","title":"Introduction","description":"Misti is a static analysis tool designed for smart contracts on the TON blockchain.","sidebar":"sidebar"},"tools":{"id":"tools","title":"Tools Overview","description":"Misti Tools are additional modules designed to work alongside detectors, enabling various tasks beyond code analysis.","sidebar":"sidebar"},"tools/DumpAst":{"id":"tools/DumpAst","title":"DumpAst","description":"The DumpAst tool in Misti enables users to output the Abstract Syntax Tree (AST) of project modules in JSON format. This is particularly useful when writing custom detectors, as it helps understand the structure and components of the code.","sidebar":"sidebar"},"tools/DumpCfg":{"id":"tools/DumpCfg","title":"DumpCfg","description":"Misti provides a feature to dump the Control Flow Graph (CFG) in JSON, DOT, and Mermaid formats. This is essential for understanding the Internal Representation (IR) of the code and analyzing the control flow within contracts.","sidebar":"sidebar"},"tools/DumpConfig":{"id":"tools/DumpConfig","title":"DumpConfig","description":"The DumpConfig tool in Misti allows you to print the current configuration file used by the analyzer. This is useful for obtaining the default configuration to use as a starting point for your custom setup or to inspect and understand the existing configuration in use.","sidebar":"sidebar"},"tutorial/blueprint":{"id":"tutorial/blueprint","title":"Using Misti with Blueprint","description":"Blueprint is a platform to compile, test, and deploy contracts on the TON blockchain. It is quite similar to Hardhat and Truffle for Ethereum.","sidebar":"sidebar"},"tutorial/ci-cd":{"id":"tutorial/ci-cd","title":"Integrating Misti into CI/CD","description":"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.","sidebar":"sidebar"},"tutorial/cli":{"id":"tutorial/cli","title":"Command-Line Interface","description":"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.","sidebar":"sidebar"},"tutorial/configuration":{"id":"tutorial/configuration","title":"Configuration","description":"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.","sidebar":"sidebar"},"tutorial/getting-started":{"id":"tutorial/getting-started","title":"Getting started","description":"This guide will walk you through the steps to install and set up the Misti static analyzer.","sidebar":"sidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/86d70222.91cb640f.js b/assets/js/86d70222.91cb640f.js new file mode 100644 index 000000000..8674ae3c3 --- /dev/null +++ b/assets/js/86d70222.91cb640f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3812],{2759:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>d});var o=n(4848),r=n(8453);const i={},s="Custom Detector Guide",c={id:"hacking/custom-detector",title:"Custom Detector Guide",description:"Introduction",source:"@site/versioned_docs/version-0.2.0/hacking/custom-detector.md",sourceDirName:"hacking",slug:"/hacking/custom-detector",permalink:"/tools/misti/docs/0.2.0/hacking/custom-detector",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/hacking/custom-detector.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Tools",permalink:"/tools/misti/docs/0.2.0/hacking/tools"}},a={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Writing a Detector",id:"writing-a-detector",level:2},{value:"Example Detectors",id:"example-detectors",level:2}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h1,{id:"custom-detector-guide",children:"Custom Detector Guide"}),"\n",(0,o.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,o.jsxs)(t.p,{children:["Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: ",(0,o.jsx)(t.a,{href:"https://nowarp.github.io/tools/misti/api/",children:"Misti API Reference"}),"."]}),"\n",(0,o.jsxs)(t.p,{children:["Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the ",(0,o.jsx)(t.a,{href:"https://nowarp.github.io/tools/misti/api/classes/detectors_detector.Detector.html",children:(0,o.jsx)(t.code,{children:"Detector"})})," interface."]}),"\n",(0,o.jsx)(t.h2,{id:"writing-a-detector",children:"Writing a Detector"}),"\n",(0,o.jsx)(t.p,{children:"To write a custom detector, create a TypeScript file using the Misti API. Here's an example of how to implement a custom detector:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-typescript",children:'import { Detector } from "../../src/detectors/detector";\nimport { MistiContext } from "../../src/internals/context";\nimport { CompilationUnit } from "../../src/internals/ir";\nimport {\n createError,\n MistiTactError,\n Severity,\n} from "../../src/internals/errors";\n\n/**\n * An example of a custom detector that showcases the usage of the detector API.\n *\n * It reports all the contracts that don\'t have an explicit implementation of the init function.\n */\nexport class ImplicitInit extends Detector {\n check(ctx: MistiContext, cu: CompilationUnit): MistiTactError[] {\n return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {\n if (!cu.findMethodCFGByName(contract.name, "init")) {\n const err = createError(\n ctx,\n `contract ${contract.name} doesn\'t define an init function`,\n Severity.INFO,\n contract.ref,\n );\n foundErrors.push(err);\n }\n return foundErrors;\n }, [] as MistiTactError[]);\n }\n}\n'})}),"\n",(0,o.jsx)(t.p,{children:"After creating a detector, you need to specify it in your configuration. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{children:'{\n "detectors": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n\n { "className": "ImplicitInit", "modulePath": "/path/to/implicitInit.ts" }\n ],\n "ignored_projects": [],\n "verbosity": "default"\n}\n\n'})}),"\n",(0,o.jsxs)(t.p,{children:["After this, you could run the created detector specifying a path to it: ",(0,o.jsx)(t.code,{children:"--config path/to/mistiConfig.json test/projects/simple/tactConfig.json"}),"."]}),"\n",(0,o.jsx)(t.h2,{id:"example-detectors",children:"Example Detectors"}),"\n",(0,o.jsxs)(t.p,{children:["The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the ",(0,o.jsx)(t.a,{href:"https://github.com/nowarp/misti/tree/master/examples",children:"examples directory"})," in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors."]})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>c});var o=n(6540);const r={},i=o.createContext(r);function s(e){const t=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),o.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/87ce9660.55512f80.js b/assets/js/87ce9660.55512f80.js new file mode 100644 index 000000000..aad3f6d5b --- /dev/null +++ b/assets/js/87ce9660.55512f80.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7495],{7049:(e,s,t)=>{t.r(s),t.d(s,{assets:()=>a,contentTitle:()=>d,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>c});var n=t(4848),o=t(8453);const r={},d="Zero Address",i={id:"detectors/ZeroAddress",title:"Zero Address",description:"A detector that identifies uses of the zero address.",source:"@site/versioned_docs/version-0.2.0/detectors/ZeroAddress.md",sourceDirName:"detectors",slug:"/detectors/ZeroAddress",permalink:"/tools/misti/docs/0.2.0/detectors/ZeroAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/ZeroAddress.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Unbound Loops",permalink:"/tools/misti/docs/0.2.0/detectors/UnboundLoops"},next:{title:"Constant Address",permalink:"/tools/misti/docs/0.2.0/detectors/ConstantAddress"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const s={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{id:"zero-address",children:"Zero Address"}),"\n",(0,n.jsx)(s.p,{children:"A detector that identifies uses of the zero address."}),"\n",(0,n.jsx)(s.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(s.p,{children:"Using the zero address in smart contracts is typically problematic because it can be\nexploited as a default or uninitialized address, leading to unintended transfers and\nsecurity vulnerabilities. Additionally, operations involving the zero address can\nresult in loss of funds or tokens, as there is no private key to access this address."}),"\n",(0,n.jsx)(s.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init() {\n // Warning: Insecure usage of zero address as default value\n self.to = newAddress(0, 0);\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})}),"\n",(0,n.jsx)(s.p,{children:"Use instead:"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init(to: Address) {\n // Fixed: Using the input value on initializaiton.\n self.to = to;\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})})]})}function u(e={}){const{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,s,t)=>{t.d(s,{R:()=>d,x:()=>i});var n=t(6540);const o={},r=n.createContext(o);function d(e){const s=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function i(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),n.createElement(r.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/883df8cc.ec17e966.js b/assets/js/883df8cc.ec17e966.js new file mode 100644 index 000000000..fca20bab1 --- /dev/null +++ b/assets/js/883df8cc.ec17e966.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7238],{6395:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var i=n(4848),s=n(8453);const r={},o="DivideBeforeMultiply",l={id:"detectors/DivideBeforeMultiply",title:"DivideBeforeMultiply",description:"A detector that identifies and corrects instances of division before multiplication to",source:"@site/docs/detectors/DivideBeforeMultiply.md",sourceDirName:"detectors",slug:"/detectors/DivideBeforeMultiply",permalink:"/tools/misti/docs/next/detectors/DivideBeforeMultiply",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/DivideBeforeMultiply.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"ConstantAddress",permalink:"/tools/misti/docs/next/detectors/ConstantAddress"},next:{title:"DumpIsUsed",permalink:"/tools/misti/docs/next/detectors/DumpIsUsed"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function a(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"dividebeforemultiply",children:"DivideBeforeMultiply"}),"\n",(0,i.jsx)(t.p,{children:"A detector that identifies and corrects instances of division before multiplication to\nensure accurate mathematical operations."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsx)(t.p,{children:"Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Precision Loss:"})," Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Rounding Errors:"})," Early division might cause rounding errors that propagate through subsequent calculations."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Unexpected Behavior:"})," Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Bad: Division before multiplication\nlet result: Int = a / b * c;\n"})}),"\n",(0,i.jsx)(t.p,{children:"Use instead:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Correct: Multiplication before division\nlet result: Int = a * c / b;\n"})})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(a,{...e})}):a(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>l});var i=n(6540);const s={},r=i.createContext(s);function o(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8c01191f.93ad2656.js b/assets/js/8c01191f.93ad2656.js new file mode 100644 index 000000000..5de748bc2 --- /dev/null +++ b/assets/js/8c01191f.93ad2656.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[494],{1017:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),a=n(8453);const r={},i="Never-accessed Variables",o={id:"detectors/NeverAccessedVariables",title:"Never-accessed Variables",description:"A detector that identifies write-only or unused variables, fields and constants.",source:"@site/versioned_docs/version-0.2.0/detectors/NeverAccessedVariables.md",sourceDirName:"detectors",slug:"/detectors/NeverAccessedVariables",permalink:"/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/NeverAccessedVariables.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Divide before Multiply",permalink:"/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply"},next:{title:"Read-only Variables",permalink:"/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"never-accessed-variables",children:"Never-accessed Variables"}),"\n",(0,s.jsx)(t.p,{children:"A detector that identifies write-only or unused variables, fields and constants."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"These variables are either assigned but never used in any meaningful computation,\nor they are declared and never used at all, which may indicate redundant code\nor an incomplete implementation of the intended logic."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"// Error: the developer forgot to use the constant\nconst MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'const MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n // OK: Fixed after the linter highlighted this warning\n require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(6540);const a={},r=s.createContext(a);function i(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8c0243db.7de6da6a.js b/assets/js/8c0243db.7de6da6a.js new file mode 100644 index 000000000..303ed81d8 --- /dev/null +++ b/assets/js/8c0243db.7de6da6a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7839],{9520:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>a});var n=t(4848),o=t(8453);const r={},s="Divide before Multiply",l={id:"detectors/DivideBeforeMultiply",title:"Divide before Multiply",description:"A detector that identifies and corrects instances of division before multiplication to",source:"@site/versioned_docs/version-0.1.2/detectors/DivideBeforeMultiply.md",sourceDirName:"detectors",slug:"/detectors/DivideBeforeMultiply",permalink:"/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/detectors/DivideBeforeMultiply.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/tools/misti/docs/0.1.2/tutorial/configuration"},next:{title:"Never-accessed Variables",permalink:"/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function d(e){const i={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"divide-before-multiply",children:"Divide before Multiply"}),"\n",(0,n.jsx)(i.p,{children:"A detector that identifies and corrects instances of division before multiplication to\nensure accurate mathematical operations."}),"\n",(0,n.jsx)(i.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(i.p,{children:"Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:"Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers."}),"\n",(0,n.jsx)(i.li,{children:"Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations."}),"\n",(0,n.jsx)(i.li,{children:"Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging."}),"\n"]}),"\n",(0,n.jsx)(i.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Bad: Division before multiplication\nlet result: Int = a / b * c;\n"})}),"\n",(0,n.jsx)(i.p,{children:"Use instead:"}),"\n",(0,n.jsx)(i.pre,{children:(0,n.jsx)(i.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Correct: Multiplication before division\nlet result: Int = a * c / b;\n"})})]})}function u(e={}){const{wrapper:i}={...(0,o.R)(),...e.components};return i?(0,n.jsx)(i,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},8453:(e,i,t)=>{t.d(i,{R:()=>s,x:()=>l});var n=t(6540);const o={},r=n.createContext(o);function s(e){const i=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),n.createElement(r.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8c74c05e.09164805.js b/assets/js/8c74c05e.09164805.js new file mode 100644 index 000000000..2ca455e14 --- /dev/null +++ b/assets/js/8c74c05e.09164805.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9198],{8981:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var s=n(4848),t=n(8453);const a={},o="Design Overview",l={id:"hacking/design",title:"Design Overview",description:"Static Analysis",source:"@site/versioned_docs/version-0.2.0/hacking/design.md",sourceDirName:"hacking",slug:"/hacking/design",permalink:"/tools/misti/docs/0.2.0/hacking/design",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/hacking/design.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Contributing",permalink:"/tools/misti/docs/0.2.0/hacking/contributing"},next:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.2.0/hacking/souffle"}},r={},c=[{value:"Static Analysis",id:"static-analysis",level:2},{value:"Souffle Datalog Solver",id:"souffle-datalog-solver",level:2},{value:"Dataflow Analysis in Misti",id:"dataflow-analysis-in-misti",level:2},{value:"References",id:"references",level:2}];function d(e){const i={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"design-overview",children:"Design Overview"}),"\n",(0,s.jsx)(i.h2,{id:"static-analysis",children:"Static Analysis"}),"\n",(0,s.jsx)(i.p,{children:"Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues."}),"\n",(0,s.jsx)(i.h2,{id:"souffle-datalog-solver",children:"Souffle Datalog Solver"}),"\n",(0,s.jsxs)(i.p,{children:["Misti leverages the ",(0,s.jsx)(i.a,{href:"https://souffle-lang.github.io",children:"Souffle Datalog solver"}),", an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases."]}),"\n",(0,s.jsx)(i.h2,{id:"dataflow-analysis-in-misti",children:"Dataflow Analysis in Misti"}),"\n",(0,s.jsx)(i.p,{children:"Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code."}),"\n",(0,s.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,s.jsx)(i.p,{children:"For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.a,{href:"https://cs.au.dk/~amoeller/spa/spa.pdf",children:"Anders M\xf8ller and Michael I. Schwartzbach \u2013 Static Program Analysis"})}),"\n",(0,s.jsx)(i.li,{children:"Uday Khedker et al. \u2013 Data Flow Analysis: Theory and Practice"}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"These resources provide a solid foundation in the theory and practice of static and dataflow analysis."})]})}function h(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>o,x:()=>l});var s=n(6540);const t={},a=s.createContext(t);function o(e){const i=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8c9dd45b.c7a96e3d.js b/assets/js/8c9dd45b.c7a96e3d.js new file mode 100644 index 000000000..6e8ca768e --- /dev/null +++ b/assets/js/8c9dd45b.c7a96e3d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6286],{7579:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var s=n(4848),t=n(8453);const a={},o="Design Overview",l={id:"hacking/design",title:"Design Overview",description:"Static Analysis",source:"@site/versioned_docs/version-0.2.2/hacking/design.md",sourceDirName:"hacking",slug:"/hacking/design",permalink:"/tools/misti/docs/0.2.2/hacking/design",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/hacking/design.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Contributing",permalink:"/tools/misti/docs/0.2.2/hacking/contributing"},next:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.2.2/hacking/souffle"}},r={},c=[{value:"Static Analysis",id:"static-analysis",level:2},{value:"Souffle Datalog Solver",id:"souffle-datalog-solver",level:2},{value:"Dataflow Analysis in Misti",id:"dataflow-analysis-in-misti",level:2},{value:"References",id:"references",level:2}];function d(e){const i={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"design-overview",children:"Design Overview"}),"\n",(0,s.jsx)(i.h2,{id:"static-analysis",children:"Static Analysis"}),"\n",(0,s.jsx)(i.p,{children:"Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues."}),"\n",(0,s.jsx)(i.h2,{id:"souffle-datalog-solver",children:"Souffle Datalog Solver"}),"\n",(0,s.jsxs)(i.p,{children:["Misti leverages the ",(0,s.jsx)(i.a,{href:"https://souffle-lang.github.io",children:"Souffle Datalog solver"}),", an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases."]}),"\n",(0,s.jsx)(i.h2,{id:"dataflow-analysis-in-misti",children:"Dataflow Analysis in Misti"}),"\n",(0,s.jsx)(i.p,{children:"Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code."}),"\n",(0,s.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,s.jsx)(i.p,{children:"For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.a,{href:"https://cs.au.dk/~amoeller/spa/spa.pdf",children:"Anders M\xf8ller and Michael I. Schwartzbach \u2013 Static Program Analysis"})}),"\n",(0,s.jsx)(i.li,{children:"Uday Khedker et al. \u2013 Data Flow Analysis: Theory and Practice"}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"These resources provide a solid foundation in the theory and practice of static and dataflow analysis."})]})}function h(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>o,x:()=>l});var s=n(6540);const t={},a=s.createContext(t);function o(e){const i=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8cf7c613.47582d2c.js b/assets/js/8cf7c613.47582d2c.js new file mode 100644 index 000000000..7ab97fd1e --- /dev/null +++ b/assets/js/8cf7c613.47582d2c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6274],{2234:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var t=i(4848),s=i(8453);const l={},r="Getting started",o={id:"tutorial/getting-started",title:"Getting started",description:"This guide will walk you through the steps to install and set up the Misti static analyzer.",source:"@site/versioned_docs/version-0.3.1/tutorial/getting-started.md",sourceDirName:"tutorial",slug:"/tutorial/getting-started",permalink:"/tools/misti/docs/0.3.1/tutorial/getting-started",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/tutorial/getting-started.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Introduction",permalink:"/tools/misti/docs/0.3.1/"},next:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.3.1/tutorial/ci-cd"}},a={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Using Development Version",id:"using-development-version",level:3},{value:"Running the analysis",id:"running-the-analysis",level:2},{value:"More usage examples",id:"more-usage-examples",level:2},{value:"Suppressing Specific Detectors",id:"suppressing-specific-detectors",level:3},{value:"Enabling All Detectors",id:"enabling-all-detectors",level:3},{value:"Running in Quiet Mode",id:"running-in-quiet-mode",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,t.jsx)(n.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsx)(n.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Git"}),"\n",(0,t.jsx)(n.li,{children:"Yarn"}),"\n",(0,t.jsx)(n.li,{children:"Node.js version 22 or higher"}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,t.jsxs)(n.p,{children:["Misti is distributed via npm and should be added to your Tact project ",(0,t.jsx)(n.a,{href:"https://github.com/tact-lang/tact?tab=readme-ov-file#installation",children:"in the same way"})," as Tact itself:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn add @nowarp/misti\n"})}),"\n",(0,t.jsx)(n.h3,{id:"using-development-version",children:"Using Development Version"}),"\n",(0,t.jsx)(n.p,{children:"The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis."}),"\n",(0,t.jsx)(n.p,{children:"To install the latest development version you should:"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["Clone Misti: ",(0,t.jsx)(n.code,{children:"git clone https://github.com/nowarp/misti"})]}),"\n",(0,t.jsxs)(n.li,{children:["Build it: ",(0,t.jsx)(n.code,{children:"cd misti && yarn install && yarn build"})]}),"\n",(0,t.jsxs)(n.li,{children:["Use it in your Tact project: ",(0,t.jsx)(n.code,{children:"cd /path/to/tact/project && yarn add file:/path/to/misti"})]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,t.jsx)(n.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"npx misti path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,t.jsxs)(n.p,{children:["You can also add a script to your ",(0,t.jsx)(n.code,{children:"package.json"})," to simplify running the linting process:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "scripts": {\n "lint": "npx misti path/to/tact.config.json"\n }\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"more-usage-examples",children:"More usage examples"}),"\n",(0,t.jsxs)(n.p,{children:["Below are a few usage examples for common scenarios when using ",(0,t.jsxs)(n.a,{href:"/tools/misti/docs/0.3.1/tutorial/cli",children:["the ",(0,t.jsx)(n.code,{children:"misti"})," CLI"]}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"suppressing-specific-detectors",children:"Suppressing Specific Detectors"}),"\n",(0,t.jsxs)(n.p,{children:["To run ",(0,t.jsx)(n.code,{children:"misti"})," while suppressing specific detectors, such as ",(0,t.jsx)(n.code,{children:"ReadOnlyVariables"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --suppress ReadOnlyVariables path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.h3,{id:"enabling-all-detectors",children:"Enabling All Detectors"}),"\n",(0,t.jsxs)(n.p,{children:["Running ",(0,t.jsx)(n.code,{children:"misti"})," with all available built-in detectors enabled:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --all-detectors path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"It is recommended to do that when auditing the project."}),"\n",(0,t.jsx)(n.h3,{id:"running-in-quiet-mode",children:"Running in Quiet Mode"}),"\n",(0,t.jsxs)(n.p,{children:["To suppress all output while running ",(0,t.jsx)(n.code,{children:"misti"})," getting just a return code:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --quiet path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This might be useful in scripts and CI/CD."}),"\n",(0,t.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,t.jsxs)(n.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,t.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>o});var t=i(6540);const s={},l=t.createContext(s);function r(e){const n=t.useContext(l);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8d6fa39c.f2faae22.js b/assets/js/8d6fa39c.f2faae22.js new file mode 100644 index 000000000..ccc634ae7 --- /dev/null +++ b/assets/js/8d6fa39c.f2faae22.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2187],{453:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var s=n(4848),o=n(8453);const r={},d="Constant Address",a={id:"detectors/ConstantAddress",title:"Constant Address",description:"An optional detector that highlights all the constant addresses appearing in the source code.",source:"@site/versioned_docs/version-0.2.2/detectors/ConstantAddress.md",sourceDirName:"detectors",slug:"/detectors/ConstantAddress",permalink:"/tools/misti/docs/0.2.2/detectors/ConstantAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/ConstantAddress.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Zero Address",permalink:"/tools/misti/docs/0.2.2/detectors/ZeroAddress"},next:{title:"Branch Duplicate",permalink:"/tools/misti/docs/0.2.2/detectors/BranchDuplicate"}},i={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"constant-address",children:"Constant Address"}),"\n",(0,s.jsx)(t.p,{children:"An optional detector that highlights all the constant addresses appearing in the source code."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsxs)(t.p,{children:["Using hardcoded addresses can sometimes indicate poor contract design.\nSome constant addresses may need to be set dynamically, e.g., using\n",(0,s.jsx)(t.code,{children:"contractAddress"}),", or at least have a way to change them at runtime, for\nexample, when upgrading a contract."]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'contract Main {\n proxy: Address;\n init() {\n // Bad: Constant address highlighted by the analyzer.\n self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");\n }\n}\n'})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"contract Main {\n proxy: Address;\n init() {\n let proxy: Proxy = initOf Proxy(myAddress());\n // OK: Address depends on how the proxy contact has been deployed\n self.proxy = contractAddress(proxy);\n }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>a});var s=n(6540);const o={},r=s.createContext(o);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8d91c04d.ef1dbebb.js b/assets/js/8d91c04d.ef1dbebb.js new file mode 100644 index 000000000..0da6ba324 --- /dev/null +++ b/assets/js/8d91c04d.ef1dbebb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4024],{2850:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var o=t(4848),s=t(8453);const i={},r="UnboundLoops",a={id:"detectors/UnboundLoops",title:"UnboundLoops",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/versioned_docs/version-0.3.0/detectors/UnboundLoops.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoops",permalink:"/tools/misti/docs/0.3.0/detectors/UnboundLoops",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/UnboundLoops.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap"},next:{title:"ZeroAddress",permalink:"/tools/misti/docs/0.3.0/detectors/ZeroAddress"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"unboundloops",children:"UnboundLoops"}),"\n",(0,o.jsx)(n.p,{children:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria."}),"\n",(0,o.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsx)(n.p,{children:"An unbounded loop can be problematic for several reasons:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult."}),"\n",(0,o.jsx)(n.li,{children:"Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks."}),"\n",(0,o.jsx)(n.li,{children:"DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability."}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n // Bad: x is not changed due looping\n send(SendParameters{ to: sender(), ... });\n}\n"})}),"\n",(0,o.jsx)(n.p,{children:"Use instead:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n send(SendParameters{ to: sender(), ... });\n x = x - 1;\n}\n"})})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var o=t(6540);const s={},i=o.createContext(s);function r(e){const n=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8df82fb6.5a9830a2.js b/assets/js/8df82fb6.5a9830a2.js new file mode 100644 index 000000000..f58baff0e --- /dev/null +++ b/assets/js/8df82fb6.5a9830a2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[301],{2964:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),a=n(8453);const r={},i="Never-accessed Variables",o={id:"detectors/NeverAccessedVariables",title:"Never-accessed Variables",description:"A detector that identifies write-only or unused variables, fields and constants.",source:"@site/versioned_docs/version-0.2.1/detectors/NeverAccessedVariables.md",sourceDirName:"detectors",slug:"/detectors/NeverAccessedVariables",permalink:"/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/NeverAccessedVariables.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Divide before Multiply",permalink:"/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply"},next:{title:"Read-only Variables",permalink:"/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"never-accessed-variables",children:"Never-accessed Variables"}),"\n",(0,s.jsx)(t.p,{children:"A detector that identifies write-only or unused variables, fields and constants."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"These variables are either assigned but never used in any meaningful computation,\nor they are declared and never used at all, which may indicate redundant code\nor an incomplete implementation of the intended logic."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"// Error: the developer forgot to use the constant\nconst MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'const MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n // OK: Fixed after the linter highlighted this warning\n require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(6540);const a={},r=s.createContext(a);function i(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8e426e62.bf0771c3.js b/assets/js/8e426e62.bf0771c3.js new file mode 100644 index 000000000..98278d2a4 --- /dev/null +++ b/assets/js/8e426e62.bf0771c3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2991],{8966:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>a});var n=s(4848),i=s(8453);const o={},d="DumpIsUsed",r={id:"detectors/DumpIsUsed",title:"DumpIsUsed",description:"An optional detector that highlights all the dump debug prints.",source:"@site/versioned_docs/version-0.4.0/detectors/DumpIsUsed.md",sourceDirName:"detectors",slug:"/detectors/DumpIsUsed",permalink:"/tools/misti/docs/detectors/DumpIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/DumpIsUsed.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"DivideBeforeMultiply",permalink:"/tools/misti/docs/detectors/DivideBeforeMultiply"},next:{title:"DuplicatedCondition",permalink:"/tools/misti/docs/detectors/DuplicatedCondition"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"dumpisused",children:"DumpIsUsed"}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"dump"})," debug prints."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"dump"})," function is a debug print that shouldn't be in the final code.\nEven though the compiler removes it in production, its presence suggests the\ndeveloper was debugging something. This can flag areas where issues might exist,\nso auditors should take a closer look at these parts of the code."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = (RANDOM_SEED >> half_shift) &\n (MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;\n dump(combined); // Suspicious: Highlighted by the detector\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = this.seed ^ shift_mask\n // OK: The code was reviewed and simplified; `dump` was removed\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>d,x:()=>r});var n=s(6540);const i={},o=n.createContext(i);function d(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8e8fe4d7.7a82fd74.js b/assets/js/8e8fe4d7.7a82fd74.js new file mode 100644 index 000000000..8f99ce6e8 --- /dev/null +++ b/assets/js/8e8fe4d7.7a82fd74.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9924],{2917:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var n=i(4848),o=i(8453);const r={},s="DivideBeforeMultiply",l={id:"detectors/DivideBeforeMultiply",title:"DivideBeforeMultiply",description:"A detector that identifies and corrects instances of division before multiplication to",source:"@site/versioned_docs/version-0.3.1/detectors/DivideBeforeMultiply.md",sourceDirName:"detectors",slug:"/detectors/DivideBeforeMultiply",permalink:"/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/DivideBeforeMultiply.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"ConstantAddress",permalink:"/tools/misti/docs/0.3.1/detectors/ConstantAddress"},next:{title:"DumpIsUsed",permalink:"/tools/misti/docs/0.3.1/detectors/DumpIsUsed"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function a(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"dividebeforemultiply",children:"DivideBeforeMultiply"}),"\n",(0,n.jsx)(t.p,{children:"A detector that identifies and corrects instances of division before multiplication to\nensure accurate mathematical operations."}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers."}),"\n",(0,n.jsx)(t.li,{children:"Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations."}),"\n",(0,n.jsx)(t.li,{children:"Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Bad: Division before multiplication\nlet result: Int = a / b * c;\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Correct: Multiplication before division\nlet result: Int = a * c / b;\n"})})]})}function u(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(a,{...e})}):a(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>l});var n=i(6540);const o={},r=n.createContext(o);function s(e){const t=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),n.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/90b5d830.c162588e.js b/assets/js/90b5d830.c162588e.js new file mode 100644 index 000000000..279f1db66 --- /dev/null +++ b/assets/js/90b5d830.c162588e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4318],{7230:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>n,metadata:()=>c,toc:()=>l});var s=r(4848),i=r(8453);const n={id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},o="Detectors Overview",c={id:"detectors",title:"Detectors Overview",description:"Here's a list of all the detectors:",source:"@site/versioned_docs/version-0.2.2/detectors.md",sourceDirName:".",slug:"/detectors",permalink:"/tools/misti/docs/0.2.2/detectors",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors.md",tags:[],version:"0.2.2",frontMatter:{id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},sidebar:"sidebar",previous:{title:"Using with Blueprint",permalink:"/tools/misti/docs/0.2.2/tutorial/blueprint"},next:{title:"Divide before Multiply",permalink:"/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply"}},d={},l=[];function a(e){const t={a:"a",code:"code",h1:"h1",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"detectors-overview",children:"Detectors Overview"}),"\n",(0,s.jsx)(t.p,{children:"Here's a list of all the detectors:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/DivideBeforeMultiply",children:"Divide before Multiply"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/NeverAccessedVariables",children:"Never-accessed Variables"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/ReadOnlyVariables",children:"Read-only Variables"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/UnboundLoops",children:"Unbound Loops"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/ZeroAddress",children:"Zero Address"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/ConstantAddress",children:"Constant Address"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/BranchDuplicate",children:"Branch Duplicate"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsxs)(t.a,{href:"./detectors/DumpIsUsed",children:[(0,s.jsx)(t.code,{children:"dump"})," Is Used"]})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/FieldDoubleInit",children:"Field Initialized Twice"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/PreferAugmentedAssign",children:"Prefer Augmented Assignment"})}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"Each detector is designed to catch specific issues in your code. Click on any of them to learn more."})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},8453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>c});var s=r(6540);const i={},n=s.createContext(i);function o(e){const t=s.useContext(n);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(n.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/91acf703.c00ee771.js b/assets/js/91acf703.c00ee771.js new file mode 100644 index 000000000..b0f8def8f --- /dev/null +++ b/assets/js/91acf703.c00ee771.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3291],{7619:(e,s,t)=>{t.r(s),t.d(s,{assets:()=>a,contentTitle:()=>d,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var n=t(4848),r=t(8453);const o={},d="ZeroAddress",i={id:"detectors/ZeroAddress",title:"ZeroAddress",description:"A detector that identifies uses of the zero address.",source:"@site/versioned_docs/version-0.4.0/detectors/ZeroAddress.md",sourceDirName:"detectors",slug:"/detectors/ZeroAddress",permalink:"/tools/misti/docs/detectors/ZeroAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/ZeroAddress.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"UnusedOptional",permalink:"/tools/misti/docs/detectors/UnusedOptional"},next:{title:"Tools Overview",permalink:"/tools/misti/docs/tools"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const s={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{id:"zeroaddress",children:"ZeroAddress"}),"\n",(0,n.jsx)(s.p,{children:"A detector that identifies uses of the zero address."}),"\n",(0,n.jsx)(s.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(s.p,{children:"Using the zero address in smart contracts is typically problematic because it can be\nexploited as a default or uninitialized address, leading to unintended transfers and\nsecurity vulnerabilities. Additionally, operations involving the zero address can\nresult in loss of funds or tokens, as there is no private key to access this address."}),"\n",(0,n.jsx)(s.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init() {\n // Warning: Insecure usage of zero address as default value\n self.to = newAddress(0, 0);\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})}),"\n",(0,n.jsx)(s.p,{children:"Use instead:"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init(to: Address) {\n // Fixed: Using the input value on initialization.\n self.to = to;\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})})]})}function u(e={}){const{wrapper:s}={...(0,r.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,s,t)=>{t.d(s,{R:()=>d,x:()=>i});var n=t(6540);const r={},o=n.createContext(r);function d(e){const s=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function i(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:d(e.components),n.createElement(o.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/91ee281c.f53980f2.js b/assets/js/91ee281c.f53980f2.js new file mode 100644 index 000000000..b2914edbe --- /dev/null +++ b/assets/js/91ee281c.f53980f2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2397],{3505:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>o});var i=s(4848),l=s(8453);const t={},d="Command-Line Interface",r={id:"tutorial/cli",title:"Command-Line Interface",description:"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.",source:"@site/versioned_docs/version-0.3.0/tutorial/cli.md",sourceDirName:"tutorial",slug:"/tutorial/cli",permalink:"/tools/misti/docs/0.3.0/tutorial/cli",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/tutorial/cli.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.3.0/tutorial/ci-cd"},next:{title:"Configuration",permalink:"/tools/misti/docs/0.3.0/tutorial/configuration"}},c={},o=[{value:"<code>--dump-cfg <json|dot></code>",id:"--dump-cfg-jsondot",level:3},{value:"<code>--dump-ast</code>",id:"--dump-ast",level:3},{value:"<code>--dump-output <PATH></code>",id:"--dump-output-path",level:3},{value:"<code>--dump-include-stdlib</code>",id:"--dump-include-stdlib",level:3},{value:"<code>--dump-config</code>",id:"--dump-config",level:3},{value:"<code>--souffle-binary <PATH></code>",id:"--souffle-binary-path",level:3},{value:"<code>--souffle-path <PATH></code>",id:"--souffle-path-path",level:3},{value:"<code>--souffle-verbose</code>",id:"--souffle-verbose",level:3},{value:"<code>--tact-stdlib-path <PATH></code>",id:"--tact-stdlib-path-path",level:3},{value:"<code>--verbose</code>",id:"--verbose",level:3},{value:"<code>--quiet</code>",id:"--quiet",level:3},{value:"<code>--detectors <name|path:name></code>",id:"--detectors-namepathname",level:3},{value:"<code>--suppress <names></code>",id:"--suppress-names",level:3},{value:"<code>--all-detectors</code>",id:"--all-detectors",level:3},{value:"<code>--config <PATH></code>",id:"--config-path",level:3},{value:"<code>--new-detector <PATH></code>",id:"--new-detector-path",level:3}];function a(e){const n={code:"code",h1:"h1",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"command-line-interface",children:"Command-Line Interface"}),"\n",(0,i.jsx)(n.p,{children:"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each."}),"\n",(0,i.jsx)(n.h3,{id:"--dump-cfg-jsondot",children:(0,i.jsx)(n.code,{children:"--dump-cfg <json|dot>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Dumps the Control Flow Graph (CFG) in the requested format: JSON or Graphviz Dot."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"undefined"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--dump-ast",children:(0,i.jsx)(n.code,{children:"--dump-ast"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Dumps the Abstract Syntax Tree (AST) in JSON format."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--dump-output-path",children:(0,i.jsx)(n.code,{children:"--dump-output <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Specifies the directory to save the AST/CFG dump. If ",(0,i.jsx)(n.code,{children:"<PATH>"})," is ",(0,i.jsx)(n.code,{children:"-"}),", then the output is sent to stdout."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": Value of ",(0,i.jsx)(n.code,{children:"DUMP_STDOUT_PATH"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--dump-include-stdlib",children:(0,i.jsx)(n.code,{children:"--dump-include-stdlib"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Includes standard library components in the AST/CFG dump."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--dump-config",children:(0,i.jsx)(n.code,{children:"--dump-config"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Dumps the Misti JSON configuration file in use."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--souffle-binary-path",children:(0,i.jsx)(n.code,{children:"--souffle-binary <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Path to the Souffl\xe9 binary."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:'"souffle"'})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--souffle-path-path",children:(0,i.jsx)(n.code,{children:"--souffle-path <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Directory to save the generated Souffl\xe9 files."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:'"/tmp/misti/souffle"'})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--souffle-verbose",children:(0,i.jsx)(n.code,{children:"--souffle-verbose"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Generates human-readable, but more verbose, Souffl\xe9 files."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--tact-stdlib-path-path",children:(0,i.jsx)(n.code,{children:"--tact-stdlib-path <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Path to the Tact standard library."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--verbose",children:(0,i.jsx)(n.code,{children:"--verbose"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Enables verbose output."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--quiet",children:(0,i.jsx)(n.code,{children:"--quiet"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Suppresses all output."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--detectors-namepathname",children:(0,i.jsx)(n.code,{children:"--detectors <name|path:name>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": A comma-separated list of detectors to enable."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Argument Validation"}),": Requires a non-empty list of detector names."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"undefined"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--suppress-names",children:(0,i.jsx)(n.code,{children:"--suppress <names>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": A comma-separated list of detector names to suppress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Argument Validation"}),": Requires a non-empty list of detector names."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"undefined"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--all-detectors",children:(0,i.jsx)(n.code,{children:"--all-detectors"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Enables all the available built-in detectors."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--config-path",children:(0,i.jsx)(n.code,{children:"--config <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Path to the Misti configuration file."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--new-detector-path",children:(0,i.jsx)(n.code,{children:"--new-detector <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Creates a new custom detector at the specified path."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"undefined"})]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(a,{...e})}):a(e)}},8453:(e,n,s)=>{s.d(n,{R:()=>d,x:()=>r});var i=s(6540);const l={},t=i.createContext(l);function d(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(l):e.components||l:d(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/94d07e36.7adad0e3.js b/assets/js/94d07e36.7adad0e3.js new file mode 100644 index 000000000..d312b5db8 --- /dev/null +++ b/assets/js/94d07e36.7adad0e3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8235],{2345:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var i=t(4848),r=t(8453);const o={},a="EnsurePrgSeed",s={id:"detectors/EnsurePrgSeed",title:"EnsurePrgSeed",description:"A detector that identifies all calls to nativeRandom and nativeRandomInterval",source:"@site/versioned_docs/version-0.4.0/detectors/EnsurePrgSeed.md",sourceDirName:"detectors",slug:"/detectors/EnsurePrgSeed",permalink:"/tools/misti/docs/detectors/EnsurePrgSeed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/EnsurePrgSeed.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"DuplicatedCondition",permalink:"/tools/misti/docs/detectors/DuplicatedCondition"},next:{title:"FalseCondition",permalink:"/tools/misti/docs/detectors/FalseCondition"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"ensureprgseed",children:"EnsurePrgSeed"}),"\n",(0,i.jsxs)(n.p,{children:["A detector that identifies all calls to ",(0,i.jsx)(n.code,{children:"nativeRandom"})," and ",(0,i.jsx)(n.code,{children:"nativeRandomInterval"}),"\nwithout a preceding PRG seed initialization."]}),"\n",(0,i.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsxs)(n.p,{children:["Using ",(0,i.jsx)(n.code,{children:"nativeRandom"})," or ",(0,i.jsx)(n.code,{children:"nativeRandomInterval"})," without first initializing the PRG seed via\n",(0,i.jsx)(n.code,{children:"nativePrepareRandom"}),", ",(0,i.jsx)(n.code,{children:"nativeRandomize"}),", or ",(0,i.jsx)(n.code,{children:"nativeRandomizeLt"})," may lead to unintended behavior\nor weak random number generation. This detector ensures that PRG seed initialization\nis always performed before any use of random functions, enhancing contract security."]}),"\n",(0,i.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"// Bad: `nativeRandom` is used without prior PRG seed initialization\nfun generateRandomValue(): Int {\n return nativeRandom()\n}\n"})}),"\n",(0,i.jsx)(n.p,{children:"Use instead:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"fun test(): Int {\n nativePrepareRandom();\n}\n\n// OK: PRG has been initialized somewhere in the contract\nfun generateRandomValue(): Int {\n return nativeRandom()\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>s});var i=t(6540);const r={},o=i.createContext(r);function a(e){const n=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/96e77fcb.3fb77893.js b/assets/js/96e77fcb.3fb77893.js new file mode 100644 index 000000000..27ed8fc6d --- /dev/null +++ b/assets/js/96e77fcb.3fb77893.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5922],{7021:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>d,toc:()=>c});var s=n(4848),r=n(8453);const i={},o="PreferAugmentedAssign",d={id:"detectors/PreferAugmentedAssign",title:"PreferAugmentedAssign",description:"Detects non-idiomatic statements that can be written using augmented assignment",source:"@site/versioned_docs/version-0.3.0/detectors/PreferAugmentedAssign.md",sourceDirName:"detectors",slug:"/detectors/PreferAugmentedAssign",permalink:"/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/PreferAugmentedAssign.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"NeverAccessedVariables",permalink:"/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables"},next:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"preferaugmentedassign",children:"PreferAugmentedAssign"}),"\n",(0,s.jsxs)(t.p,{children:["Detects non-idiomatic statements that can be written using augmented assignment\noperators like ",(0,s.jsx)(t.code,{children:"+="}),", ",(0,s.jsx)(t.code,{children:"-="}),", etc."]}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Using augmented assignment operations improves the readability of the source code\nand reduces the risk of mistakes, such as those that occur during copy-pasting\nand refactoring code."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue = (msgValue - ctx.readForwardFee());\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue -= ctx.readForwardFee());\n"})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>d});var s=n(6540);const r={},i=s.createContext(r);function o(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/972c9666.e5b493f7.js b/assets/js/972c9666.e5b493f7.js new file mode 100644 index 000000000..dd93657bc --- /dev/null +++ b/assets/js/972c9666.e5b493f7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1179],{590:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var s=n(4848),i=n(8453);const r={},o="Prefer Augmented Assignment",a={id:"detectors/PreferAugmentedAssign",title:"Prefer Augmented Assignment",description:"Detects non-idiomatic statements that can be written using augmented assignment operators like +=, -=, etc.",source:"@site/versioned_docs/version-0.2.0/detectors/PreferAugmentedAssign.md",sourceDirName:"detectors",slug:"/detectors/PreferAugmentedAssign",permalink:"/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/PreferAugmentedAssign.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Field Initialized Twice",permalink:"/tools/misti/docs/0.2.0/detectors/FieldDoubleInit"},next:{title:"Contributing",permalink:"/tools/misti/docs/0.2.0/hacking/contributing"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"prefer-augmented-assignment",children:"Prefer Augmented Assignment"}),"\n",(0,s.jsxs)(t.p,{children:["Detects non-idiomatic statements that can be written using augmented assignment operators like ",(0,s.jsx)(t.code,{children:"+="}),", ",(0,s.jsx)(t.code,{children:"-="}),", etc."]}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Using augmented assignment operations improves the readability of the source code and reduces the risk of mistakes, such as those that occur during copy-pasting and refactoring code."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue = (msgValue - ctx.readForwardFee());\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue -= ctx.readForwardFee());\n"})})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(6540);const i={},r=s.createContext(i);function o(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/987a8a5d.bdfcfd74.js b/assets/js/987a8a5d.bdfcfd74.js new file mode 100644 index 000000000..0edfc6836 --- /dev/null +++ b/assets/js/987a8a5d.bdfcfd74.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1318],{9490:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var t=o(4848),s=o(8453);const i={},r="Unbound Loops",a={id:"detectors/UnboundLoops",title:"Unbound Loops",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/versioned_docs/version-0.1.2/detectors/UnboundLoops.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoops",permalink:"/tools/misti/docs/0.1.2/detectors/UnboundLoops",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/detectors/UnboundLoops.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Read-only Variables",permalink:"/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables"},next:{title:"Zero Address",permalink:"/tools/misti/docs/0.1.2/detectors/ZeroAddress"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"unbound-loops",children:"Unbound Loops"}),"\n",(0,t.jsx)(n.p,{children:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria."}),"\n",(0,t.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,t.jsx)(n.p,{children:"An unbounded loop can be problematic for several reasons:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult."}),"\n",(0,t.jsx)(n.li,{children:"Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks."}),"\n",(0,t.jsx)(n.li,{children:"DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability."}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n // Bad: x is not changed due looping\n send(SendParameters{ to: sender(), ... });\n}\n"})}),"\n",(0,t.jsx)(n.p,{children:"Use instead:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n send(SendParameters{ to: sender(), ... });\n x = x - 1;\n}\n"})})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,o)=>{o.d(n,{R:()=>r,x:()=>a});var t=o(6540);const s={},i=t.createContext(s);function r(e){const n=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/988b076a.3beed1a8.js b/assets/js/988b076a.3beed1a8.js new file mode 100644 index 000000000..79670be66 --- /dev/null +++ b/assets/js/988b076a.3beed1a8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9758],{2426:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var t=i(4848),s=i(8453);const o={},r="Contributing Guide",a={id:"hacking/contributing",title:"Contributing Guide",description:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.",source:"@site/versioned_docs/version-0.3.0/hacking/contributing.md",sourceDirName:"hacking",slug:"/hacking/contributing",permalink:"/tools/misti/docs/0.3.0/hacking/contributing",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/hacking/contributing.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"ZeroAddress",permalink:"/tools/misti/docs/0.3.0/detectors/ZeroAddress"},next:{title:"Design Overview",permalink:"/tools/misti/docs/0.3.0/hacking/design"}},c={},d=[{value:"Issues reporting",id:"issues-reporting",level:2},{value:"Documentation contribution",id:"documentation-contribution",level:2},{value:"Code contribution",id:"code-contribution",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"contributing-guide",children:"Contributing Guide"}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better."}),"\n",(0,t.jsx)(n.h2,{id:"issues-reporting",children:"Issues reporting"}),"\n",(0,t.jsx)(n.p,{children:"When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.\nPlease help us by publishing it and the input sources at:\nhttps://github.com/nowarp/misti/issues/new.\n"})}),"\n",(0,t.jsx)(n.p,{children:"We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users."}),"\n",(0,t.jsx)(n.h2,{id:"documentation-contribution",children:"Documentation contribution"}),"\n",(0,t.jsxs)(n.p,{children:["We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/nowarp.github.io/issues",children:"nowarp.github.io Issues"}),". Additionally, many documentation pages have an ",(0,t.jsx)(n.code,{children:"Edit"})," button that allows you to make direct contributions easily."]}),"\n",(0,t.jsx)(n.h2,{id:"code-contribution",children:"Code contribution"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Navigate Issues and Find Tasks"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Browse the issues ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"here"}),". Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues."]}),"\n",(0,t.jsx)(n.li,{children:"Choose an issue suitable for you and mention in the issue that you're working on it."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Implement Your Changes"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Implement your changes. Feel free to ask questions in the issue if needed."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Ensure Tests Pass"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Before creating a PR, make sure all tests and CI checks are passing by running:","\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn test-all\n"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Create a PR"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Submit your pull request ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/pulls",children:"here"})]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Add a CHANGELOG entry"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Describe your changes in the ",(0,t.jsx)(n.code,{children:"CHANGELOG.md"})," file according to the existing structure."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/HACKING.md",children:"HACKING.md"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your contributions!"})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>a});var t=i(6540);const s={},o=t.createContext(s);function r(e){const n=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9fedf60a.5a24888e.js b/assets/js/9fedf60a.5a24888e.js new file mode 100644 index 000000000..5d29c0eff --- /dev/null +++ b/assets/js/9fedf60a.5a24888e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3388],{9957:(e,s,t)=>{t.r(s),t.d(s,{assets:()=>a,contentTitle:()=>d,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>c});var n=t(4848),o=t(8453);const r={},d="ZeroAddress",i={id:"detectors/ZeroAddress",title:"ZeroAddress",description:"A detector that identifies uses of the zero address.",source:"@site/versioned_docs/version-0.3.1/detectors/ZeroAddress.md",sourceDirName:"detectors",slug:"/detectors/ZeroAddress",permalink:"/tools/misti/docs/0.3.1/detectors/ZeroAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/ZeroAddress.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"UnboundLoops",permalink:"/tools/misti/docs/0.3.1/detectors/UnboundLoops"},next:{title:"Contributing",permalink:"/tools/misti/docs/0.3.1/hacking/contributing"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const s={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{id:"zeroaddress",children:"ZeroAddress"}),"\n",(0,n.jsx)(s.p,{children:"A detector that identifies uses of the zero address."}),"\n",(0,n.jsx)(s.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(s.p,{children:"Using the zero address in smart contracts is typically problematic because it can be\nexploited as a default or uninitialized address, leading to unintended transfers and\nsecurity vulnerabilities. Additionally, operations involving the zero address can\nresult in loss of funds or tokens, as there is no private key to access this address."}),"\n",(0,n.jsx)(s.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init() {\n // Warning: Insecure usage of zero address as default value\n self.to = newAddress(0, 0);\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})}),"\n",(0,n.jsx)(s.p,{children:"Use instead:"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init(to: Address) {\n // Fixed: Using the input value on initialization.\n self.to = to;\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})})]})}function u(e={}){const{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,s,t)=>{t.d(s,{R:()=>d,x:()=>i});var n=t(6540);const o={},r=n.createContext(o);function d(e){const s=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function i(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),n.createElement(r.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a291c19d.f1ac0d98.js b/assets/js/a291c19d.f1ac0d98.js new file mode 100644 index 000000000..1b708d552 --- /dev/null +++ b/assets/js/a291c19d.f1ac0d98.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4903],{7937:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var i=n(4848),a=n(8453);const r={},s="InheritedStateMutation",o={id:"detectors/InheritedStateMutation",title:"InheritedStateMutation",description:"An optional detector that highlights all instances where inherited trait variables",source:"@site/versioned_docs/version-0.4.0/detectors/InheritedStateMutation.md",sourceDirName:"detectors",slug:"/detectors/InheritedStateMutation",permalink:"/tools/misti/docs/detectors/InheritedStateMutation",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/InheritedStateMutation.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"FieldDoubleInit",permalink:"/tools/misti/docs/detectors/FieldDoubleInit"},next:{title:"NeverAccessedVariables",permalink:"/tools/misti/docs/detectors/NeverAccessedVariables"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"inheritedstatemutation",children:"InheritedStateMutation"}),"\n",(0,i.jsx)(t.p,{children:"An optional detector that highlights all instances where inherited trait variables\nare directly modified."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsxs)(t.p,{children:["Traits should provide setter methods to ensure that invariants related to their\nstate are preserved. Directly modifying trait variables (e.g., ",(0,i.jsx)(t.code,{children:"self.traitVar = 42"}),")\ncan violate these invariants, leading to potential bugs or security vulnerabilities.\nThis detector warns when such direct modifications occur, prompting further review\nby auditors."]}),"\n",(0,i.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"trait T {\n balance: Int;\n}\n\ncontract C with T {\n balance: Int = 42;\n fun updateBalance() {\n self.balance = 100; // Suspicious: Highlighted by the detector\n }\n}\n"})}),"\n",(0,i.jsx)(t.p,{children:"Use instead:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:'trait T {\n balance: Int;\n fun setBalance(newBalance: Int) {\n require(newBalance > 0, "balance cannot be negative"); // Invariant check\n self.balance = newBalance;\n }\n}\n\ncontract C with T {\n balance: Int = 42;\n fun updateBalance() {\n self.setBalance(100); // OK: Invariant preserved\n }\n}\n'})})]})}function h(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(6540);const a={},r=i.createContext(a);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a3df6930.b9e3fcca.js b/assets/js/a3df6930.b9e3fcca.js new file mode 100644 index 000000000..4480f0a38 --- /dev/null +++ b/assets/js/a3df6930.b9e3fcca.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[767],{4152:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var t=i(4848),s=i(8453);const l={},r="Getting started",o={id:"tutorial/getting-started",title:"Getting started",description:"This guide will walk you through the steps to install and set up the Misti static analyzer.",source:"@site/versioned_docs/version-0.4.0/tutorial/getting-started.md",sourceDirName:"tutorial",slug:"/tutorial/getting-started",permalink:"/tools/misti/docs/tutorial/getting-started",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/tutorial/getting-started.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Introduction",permalink:"/tools/misti/docs/"},next:{title:"CI/CD Integration",permalink:"/tools/misti/docs/tutorial/ci-cd"}},a={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Using Development Version",id:"using-development-version",level:3},{value:"Running the analysis",id:"running-the-analysis",level:2},{value:"More usage examples",id:"more-usage-examples",level:2},{value:"Suppressing Specific Detectors",id:"suppressing-specific-detectors",level:3},{value:"Enabling All Detectors",id:"enabling-all-detectors",level:3},{value:"Running in Quiet Mode",id:"running-in-quiet-mode",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,t.jsx)(n.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsx)(n.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Git"}),"\n",(0,t.jsx)(n.li,{children:"Yarn"}),"\n",(0,t.jsx)(n.li,{children:"Node.js version 22 or higher"}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,t.jsxs)(n.p,{children:["Misti is distributed via npm and should be added to your Tact project ",(0,t.jsx)(n.a,{href:"https://github.com/tact-lang/tact?tab=readme-ov-file#installation",children:"in the same way"})," as Tact itself:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn add @nowarp/misti\n"})}),"\n",(0,t.jsx)(n.h3,{id:"using-development-version",children:"Using Development Version"}),"\n",(0,t.jsx)(n.p,{children:"The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis."}),"\n",(0,t.jsx)(n.p,{children:"To install the latest development version you should:"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["Clone Misti: ",(0,t.jsx)(n.code,{children:"git clone https://github.com/nowarp/misti"})]}),"\n",(0,t.jsxs)(n.li,{children:["Build it: ",(0,t.jsx)(n.code,{children:"cd misti && yarn install && yarn build"})]}),"\n",(0,t.jsxs)(n.li,{children:["Use it in your Tact project: ",(0,t.jsx)(n.code,{children:"cd /path/to/tact/project && yarn add file:/path/to/misti"})]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,t.jsx)(n.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"npx misti path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,t.jsxs)(n.p,{children:["You can also add a script to your ",(0,t.jsx)(n.code,{children:"package.json"})," to simplify running the linting process:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "scripts": {\n "lint": "npx misti path/to/tact.config.json"\n }\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"more-usage-examples",children:"More usage examples"}),"\n",(0,t.jsxs)(n.p,{children:["Below are a few usage examples for common scenarios when using ",(0,t.jsxs)(n.a,{href:"/tools/misti/docs/tutorial/cli",children:["the ",(0,t.jsx)(n.code,{children:"misti"})," CLI"]}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"suppressing-specific-detectors",children:"Suppressing Specific Detectors"}),"\n",(0,t.jsxs)(n.p,{children:["To run ",(0,t.jsx)(n.code,{children:"misti"})," while suppressing specific detectors, such as ",(0,t.jsx)(n.code,{children:"ReadOnlyVariables"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --suppress ReadOnlyVariables path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.h3,{id:"enabling-all-detectors",children:"Enabling All Detectors"}),"\n",(0,t.jsxs)(n.p,{children:["Running ",(0,t.jsx)(n.code,{children:"misti"})," with all available built-in detectors enabled:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --all-detectors path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"It is recommended to do that when auditing the project."}),"\n",(0,t.jsx)(n.h3,{id:"running-in-quiet-mode",children:"Running in Quiet Mode"}),"\n",(0,t.jsxs)(n.p,{children:["To suppress all output while running ",(0,t.jsx)(n.code,{children:"misti"})," getting just a return code:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --quiet path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This might be useful in scripts and CI/CD."}),"\n",(0,t.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,t.jsxs)(n.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,t.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>o});var t=i(6540);const s={},l=t.createContext(s);function r(e){const n=t.useContext(l);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a4516edb.19e6546c.js b/assets/js/a4516edb.19e6546c.js new file mode 100644 index 000000000..9c10ed9e9 --- /dev/null +++ b/assets/js/a4516edb.19e6546c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9415],{1664:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.1.2","label":"0.1.2","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.1.2","isLast":false,"docsSidebars":{"sidebar":[{"type":"link","label":"Introduction","href":"/tools/misti/docs/0.1.2/","docId":"intro","unlisted":false},{"type":"category","label":"Tutorial","items":[{"type":"link","label":"Getting Started","href":"/tools/misti/docs/0.1.2/tutorial/getting-started","docId":"tutorial/getting-started","unlisted":false},{"type":"link","label":"Configuration","href":"/tools/misti/docs/0.1.2/tutorial/configuration","docId":"tutorial/configuration","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Detectors","items":[{"type":"link","label":"Divide before Multiply","href":"/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply","docId":"detectors/DivideBeforeMultiply","unlisted":false},{"type":"link","label":"Never-accessed Variables","href":"/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables","docId":"detectors/NeverAccessedVariables","unlisted":false},{"type":"link","label":"Read-only Variables","href":"/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables","docId":"detectors/ReadOnlyVariables","unlisted":false},{"type":"link","label":"Unbound Loops","href":"/tools/misti/docs/0.1.2/detectors/UnboundLoops","docId":"detectors/UnboundLoops","unlisted":false},{"type":"link","label":"Zero Address","href":"/tools/misti/docs/0.1.2/detectors/ZeroAddress","docId":"detectors/ZeroAddress","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacking","items":[{"type":"link","label":"Contributing","href":"/tools/misti/docs/0.1.2/hacking/contributing","docId":"hacking/contributing","unlisted":false},{"type":"link","label":"Design Overview","href":"/tools/misti/docs/0.1.2/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/0.1.2/hacking/souffle","docId":"hacking/souffle","unlisted":false},{"type":"link","label":"Tools","href":"/tools/misti/docs/0.1.2/hacking/tools","docId":"hacking/tools","unlisted":false},{"type":"link","label":"Custom Detectors","href":"/tools/misti/docs/0.1.2/hacking/custom-detector","docId":"hacking/custom-detector","unlisted":false},{"type":"link","label":"CHANGELOG","href":"/tools/misti/docs/0.1.2/hacking/CHANGELOG","docId":"hacking/CHANGELOG","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"detectors/DivideBeforeMultiply":{"id":"detectors/DivideBeforeMultiply","title":"Divide before Multiply","description":"A detector that identifies and corrects instances of division before multiplication to","sidebar":"sidebar"},"detectors/NeverAccessedVariables":{"id":"detectors/NeverAccessedVariables","title":"Never-accessed Variables","description":"A detector that identifies write-only or unused variables, fields and constants.","sidebar":"sidebar"},"detectors/ReadOnlyVariables":{"id":"detectors/ReadOnlyVariables","title":"Read-only Variables","description":"A detector that identifies read-only variables and fields.","sidebar":"sidebar"},"detectors/UnboundLoops":{"id":"detectors/UnboundLoops","title":"Unbound Loops","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/ZeroAddress":{"id":"detectors/ZeroAddress","title":"Zero Address","description":"A detector that identifies uses of the zero address.","sidebar":"sidebar"},"hacking/CHANGELOG":{"id":"hacking/CHANGELOG","title":"Changelog","description":"All notable changes to this project are documented in this file.","sidebar":"sidebar"},"hacking/contributing":{"id":"hacking/contributing","title":"Contributing Guide","description":"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.","sidebar":"sidebar"},"hacking/custom-detector":{"id":"hacking/custom-detector","title":"Custom Detector Guide","description":"Introduction","sidebar":"sidebar"},"hacking/design":{"id":"hacking/design","title":"Design Overview","description":"Static Analysis","sidebar":"sidebar"},"hacking/souffle":{"id":"hacking/souffle","title":"Souffl\xe9 Integration Guide","description":"What is Souffl\xe9?","sidebar":"sidebar"},"hacking/tools":{"id":"hacking/tools","title":"Tools Guide","description":"This page describes the internal analyzer tools available in Misti to aid in development and debugging.","sidebar":"sidebar"},"intro":{"id":"intro","title":"Introduction","description":"Misti is a static analysis tool designed for smart contracts on the TON blockchain.","sidebar":"sidebar"},"tutorial/configuration":{"id":"tutorial/configuration","title":"Configuration","description":"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.","sidebar":"sidebar"},"tutorial/getting-started":{"id":"tutorial/getting-started","title":"Getting started","description":"This guide will walk you through the steps to install and set up the Misti static analyzer.","sidebar":"sidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/a5055d90.503ae7a2.js b/assets/js/a5055d90.503ae7a2.js new file mode 100644 index 000000000..3d8db7a79 --- /dev/null +++ b/assets/js/a5055d90.503ae7a2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5484],{535:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>r,contentTitle:()=>l,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>c});var s=n(4848),t=n(8453);const a={},l="Design Overview",o={id:"hacking/design",title:"Design Overview",description:"Static Analysis",source:"@site/docs/hacking/design.md",sourceDirName:"hacking",slug:"/hacking/design",permalink:"/tools/misti/docs/next/hacking/design",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/hacking/design.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpConfig",permalink:"/tools/misti/docs/next/tools/DumpConfig"},next:{title:"Souffl\xe9",permalink:"/tools/misti/docs/next/hacking/souffle"}},r={},c=[{value:"Static Analysis",id:"static-analysis",level:2},{value:"Souffle Datalog Solver",id:"souffle-datalog-solver",level:2},{value:"Dataflow Analysis in Misti",id:"dataflow-analysis-in-misti",level:2},{value:"References",id:"references",level:2}];function d(e){const i={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"design-overview",children:"Design Overview"}),"\n",(0,s.jsx)(i.h2,{id:"static-analysis",children:"Static Analysis"}),"\n",(0,s.jsx)(i.p,{children:"Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues."}),"\n",(0,s.jsx)(i.h2,{id:"souffle-datalog-solver",children:"Souffle Datalog Solver"}),"\n",(0,s.jsxs)(i.p,{children:["Misti leverages the ",(0,s.jsx)(i.a,{href:"https://souffle-lang.github.io",children:"Souffle Datalog solver"}),", an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases."]}),"\n",(0,s.jsx)(i.h2,{id:"dataflow-analysis-in-misti",children:"Dataflow Analysis in Misti"}),"\n",(0,s.jsx)(i.p,{children:"Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code."}),"\n",(0,s.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,s.jsx)(i.p,{children:"For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.a,{href:"https://cs.au.dk/~amoeller/spa/spa.pdf",children:"Anders M\xf8ller and Michael I. Schwartzbach \u2013 Static Program Analysis"})}),"\n",(0,s.jsx)(i.li,{children:"Uday Khedker et al. \u2013 Data Flow Analysis: Theory and Practice"}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"These resources provide a solid foundation in the theory and practice of static and dataflow analysis."})]})}function h(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>l,x:()=>o});var s=n(6540);const t={},a=s.createContext(t);function l(e){const i=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function o(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:l(e.components),s.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a66f2ff0.c39f76e5.js b/assets/js/a66f2ff0.c39f76e5.js new file mode 100644 index 000000000..e915c4230 --- /dev/null +++ b/assets/js/a66f2ff0.c39f76e5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1332],{5467:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var o=t(4848),s=t(8453);const i={},r="UnboundLoops",a={id:"detectors/UnboundLoops",title:"UnboundLoops",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/versioned_docs/version-0.3.1/detectors/UnboundLoops.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoops",permalink:"/tools/misti/docs/0.3.1/detectors/UnboundLoops",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/UnboundLoops.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap"},next:{title:"ZeroAddress",permalink:"/tools/misti/docs/0.3.1/detectors/ZeroAddress"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"unboundloops",children:"UnboundLoops"}),"\n",(0,o.jsx)(n.p,{children:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria."}),"\n",(0,o.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsx)(n.p,{children:"An unbounded loop can be problematic for several reasons:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult."}),"\n",(0,o.jsx)(n.li,{children:"Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks."}),"\n",(0,o.jsx)(n.li,{children:"DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability."}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n // Bad: x is not changed due looping\n send(SendParameters{ to: sender(), ... });\n}\n"})}),"\n",(0,o.jsx)(n.p,{children:"Use instead:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n send(SendParameters{ to: sender(), ... });\n x = x - 1;\n}\n"})})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var o=t(6540);const s={},i=o.createContext(s);function r(e){const n=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a7456010.c6eb9a57.js b/assets/js/a7456010.c6eb9a57.js new file mode 100644 index 000000000..34e25e855 --- /dev/null +++ b/assets/js/a7456010.c6eb9a57.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1235],{8552:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-pages","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/a7bd4aaa.1b32332e.js b/assets/js/a7bd4aaa.1b32332e.js new file mode 100644 index 000000000..48f57569c --- /dev/null +++ b/assets/js/a7bd4aaa.1b32332e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7098],{4532:(n,e,s)=>{s.r(e),s.d(e,{default:()=>x});s(6540);var r=s(1003),o=s(2967),t=s(2252),i=s(2831),c=s(1463),u=s(4848);function a(n){const{version:e}=n;return(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(c.A,{version:e.version,tag:(0,o.tU)(e.pluginId,e.version)}),(0,u.jsx)(r.be,{children:e.noIndex&&(0,u.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})]})}function l(n){const{version:e,route:s}=n;return(0,u.jsx)(r.e3,{className:e.className,children:(0,u.jsx)(t.n,{version:e,children:(0,i.v)(s.routes)})})}function x(n){return(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(a,{...n}),(0,u.jsx)(l,{...n})]})}}}]); \ No newline at end of file diff --git a/assets/js/a7eb4927.90a54648.js b/assets/js/a7eb4927.90a54648.js new file mode 100644 index 000000000..5e726a0e1 --- /dev/null +++ b/assets/js/a7eb4927.90a54648.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8262],{936:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var s=n(4848),t=n(8453);const a={},o="Design Overview",l={id:"hacking/design",title:"Design Overview",description:"Static Analysis",source:"@site/versioned_docs/version-0.3.0/hacking/design.md",sourceDirName:"hacking",slug:"/hacking/design",permalink:"/tools/misti/docs/0.3.0/hacking/design",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/hacking/design.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Contributing",permalink:"/tools/misti/docs/0.3.0/hacking/contributing"},next:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.3.0/hacking/souffle"}},r={},c=[{value:"Static Analysis",id:"static-analysis",level:2},{value:"Souffle Datalog Solver",id:"souffle-datalog-solver",level:2},{value:"Dataflow Analysis in Misti",id:"dataflow-analysis-in-misti",level:2},{value:"References",id:"references",level:2}];function d(e){const i={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"design-overview",children:"Design Overview"}),"\n",(0,s.jsx)(i.h2,{id:"static-analysis",children:"Static Analysis"}),"\n",(0,s.jsx)(i.p,{children:"Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues."}),"\n",(0,s.jsx)(i.h2,{id:"souffle-datalog-solver",children:"Souffle Datalog Solver"}),"\n",(0,s.jsxs)(i.p,{children:["Misti leverages the ",(0,s.jsx)(i.a,{href:"https://souffle-lang.github.io",children:"Souffle Datalog solver"}),", an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases."]}),"\n",(0,s.jsx)(i.h2,{id:"dataflow-analysis-in-misti",children:"Dataflow Analysis in Misti"}),"\n",(0,s.jsx)(i.p,{children:"Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code."}),"\n",(0,s.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,s.jsx)(i.p,{children:"For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.a,{href:"https://cs.au.dk/~amoeller/spa/spa.pdf",children:"Anders M\xf8ller and Michael I. Schwartzbach \u2013 Static Program Analysis"})}),"\n",(0,s.jsx)(i.li,{children:"Uday Khedker et al. \u2013 Data Flow Analysis: Theory and Practice"}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"These resources provide a solid foundation in the theory and practice of static and dataflow analysis."})]})}function h(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>o,x:()=>l});var s=n(6540);const t={},a=s.createContext(t);function o(e){const i=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a8c496ca.06cbb22b.js b/assets/js/a8c496ca.06cbb22b.js new file mode 100644 index 000000000..01170d4bf --- /dev/null +++ b/assets/js/a8c496ca.06cbb22b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9304],{8812:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=s(4848),i=s(8453);const o={},d="DumpIsUsed",r={id:"detectors/DumpIsUsed",title:"DumpIsUsed",description:"An optional detector that highlights all the dump function calls.",source:"@site/versioned_docs/version-0.3.1/detectors/DumpIsUsed.md",sourceDirName:"detectors",slug:"/detectors/DumpIsUsed",permalink:"/tools/misti/docs/0.3.1/detectors/DumpIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/DumpIsUsed.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"DivideBeforeMultiply",permalink:"/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply"},next:{title:"FieldDoubleInit",permalink:"/tools/misti/docs/0.3.1/detectors/FieldDoubleInit"}},c={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function a(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"dumpisused",children:"DumpIsUsed"}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"dump"})," function calls."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"dump"})," function is a debug print that shouldn't be in the final code.\nEven though the compiler removes it in production, its presence suggests the\ndeveloper was debugging something. This can flag areas where issues might exist,\nso auditors should take a closer look at these parts of the code."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = (RANDOM_SEED >> half_shift) &\n (MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;\n dump(combined); // Suspicious: Highlighted by the detector\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = this.seed ^ shift_mask\n // OK: The code was reviewed and simplified; `dump` was removed\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(a,{...e})}):a(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>d,x:()=>r});var n=s(6540);const i={},o=n.createContext(i);function d(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a8d7d639.ed43e771.js b/assets/js/a8d7d639.ed43e771.js new file mode 100644 index 000000000..137ba89f6 --- /dev/null +++ b/assets/js/a8d7d639.ed43e771.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6701],{1831:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.2.0","label":"0.2.0","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.2.0","isLast":false,"docsSidebars":{"sidebar":[{"type":"link","label":"Introduction","href":"/tools/misti/docs/0.2.0/","docId":"intro","unlisted":false},{"type":"category","label":"Tutorial","items":[{"type":"link","label":"Getting Started","href":"/tools/misti/docs/0.2.0/tutorial/getting-started","docId":"tutorial/getting-started","unlisted":false},{"type":"link","label":"CI/CD Integration","href":"/tools/misti/docs/0.2.0/tutorial/ci-cd","docId":"tutorial/ci-cd","unlisted":false},{"type":"link","label":"Configuration","href":"/tools/misti/docs/0.2.0/tutorial/configuration","docId":"tutorial/configuration","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Detectors Overview","href":"/tools/misti/docs/0.2.0/detectors","docId":"detectors","unlisted":false},{"type":"category","label":"Detectors","items":[{"type":"link","label":"Divide before Multiply","href":"/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply","docId":"detectors/DivideBeforeMultiply","unlisted":false},{"type":"link","label":"Never-accessed Variables","href":"/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables","docId":"detectors/NeverAccessedVariables","unlisted":false},{"type":"link","label":"Read-only Variables","href":"/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables","docId":"detectors/ReadOnlyVariables","unlisted":false},{"type":"link","label":"Unbound Loops","href":"/tools/misti/docs/0.2.0/detectors/UnboundLoops","docId":"detectors/UnboundLoops","unlisted":false},{"type":"link","label":"Zero Address","href":"/tools/misti/docs/0.2.0/detectors/ZeroAddress","docId":"detectors/ZeroAddress","unlisted":false},{"type":"link","label":"Constant Address","href":"/tools/misti/docs/0.2.0/detectors/ConstantAddress","docId":"detectors/ConstantAddress","unlisted":false},{"type":"link","label":"Branch Duplicate","href":"/tools/misti/docs/0.2.0/detectors/BranchDuplicate","docId":"detectors/BranchDuplicate","unlisted":false},{"type":"link","label":"`dump` Is Used","href":"/tools/misti/docs/0.2.0/detectors/DumpIsUsed","docId":"detectors/DumpIsUsed","unlisted":false},{"type":"link","label":"Field Initialized Twice","href":"/tools/misti/docs/0.2.0/detectors/FieldDoubleInit","docId":"detectors/FieldDoubleInit","unlisted":false},{"type":"link","label":"Prefer Augmented Assignment","href":"/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign","docId":"detectors/PreferAugmentedAssign","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacking","items":[{"type":"link","label":"Contributing","href":"/tools/misti/docs/0.2.0/hacking/contributing","docId":"hacking/contributing","unlisted":false},{"type":"link","label":"Design Overview","href":"/tools/misti/docs/0.2.0/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/0.2.0/hacking/souffle","docId":"hacking/souffle","unlisted":false},{"type":"link","label":"Tools","href":"/tools/misti/docs/0.2.0/hacking/tools","docId":"hacking/tools","unlisted":false},{"type":"link","label":"Custom Detectors","href":"/tools/misti/docs/0.2.0/hacking/custom-detector","docId":"hacking/custom-detector","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"detectors":{"id":"detectors","title":"Detectors Overview","description":"Here\'s a list of all the detectors:","sidebar":"sidebar"},"detectors/BranchDuplicate":{"id":"detectors/BranchDuplicate","title":"Branch Duplicate","description":"Detector that reports duplicated code in conditional branches.","sidebar":"sidebar"},"detectors/ConstantAddress":{"id":"detectors/ConstantAddress","title":"Constant Address","description":"An optional detector that highlights all the constant addresses appearing in the source code.","sidebar":"sidebar"},"detectors/DivideBeforeMultiply":{"id":"detectors/DivideBeforeMultiply","title":"Divide before Multiply","description":"A detector that identifies and corrects instances of division before multiplication to","sidebar":"sidebar"},"detectors/DumpIsUsed":{"id":"detectors/DumpIsUsed","title":"dump Is Used","description":"An optional detector that highlights all the dump function calls.","sidebar":"sidebar"},"detectors/FieldDoubleInit":{"id":"detectors/FieldDoubleInit","title":"Field Initialized Twice","description":"A detector that highlights cases where a field is initialized both in the init function and at the point of definition.","sidebar":"sidebar"},"detectors/NeverAccessedVariables":{"id":"detectors/NeverAccessedVariables","title":"Never-accessed Variables","description":"A detector that identifies write-only or unused variables, fields and constants.","sidebar":"sidebar"},"detectors/PreferAugmentedAssign":{"id":"detectors/PreferAugmentedAssign","title":"Prefer Augmented Assignment","description":"Detects non-idiomatic statements that can be written using augmented assignment operators like +=, -=, etc.","sidebar":"sidebar"},"detectors/ReadOnlyVariables":{"id":"detectors/ReadOnlyVariables","title":"Read-only Variables","description":"A detector that identifies read-only variables and fields.","sidebar":"sidebar"},"detectors/UnboundLoops":{"id":"detectors/UnboundLoops","title":"Unbound Loops","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/ZeroAddress":{"id":"detectors/ZeroAddress","title":"Zero Address","description":"A detector that identifies uses of the zero address.","sidebar":"sidebar"},"hacking/contributing":{"id":"hacking/contributing","title":"Contributing Guide","description":"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.","sidebar":"sidebar"},"hacking/custom-detector":{"id":"hacking/custom-detector","title":"Custom Detector Guide","description":"Introduction","sidebar":"sidebar"},"hacking/design":{"id":"hacking/design","title":"Design Overview","description":"Static Analysis","sidebar":"sidebar"},"hacking/souffle":{"id":"hacking/souffle","title":"Souffl\xe9 Integration Guide","description":"What is Souffl\xe9?","sidebar":"sidebar"},"hacking/tools":{"id":"hacking/tools","title":"Tools Guide","description":"This page describes the internal analyzer tools available in Misti to aid in development and debugging.","sidebar":"sidebar"},"intro":{"id":"intro","title":"Introduction","description":"Misti is a static analysis tool designed for smart contracts on the TON blockchain.","sidebar":"sidebar"},"tutorial/ci-cd":{"id":"tutorial/ci-cd","title":"Integrating Misti into CI/CD","description":"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.","sidebar":"sidebar"},"tutorial/configuration":{"id":"tutorial/configuration","title":"Configuration","description":"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.","sidebar":"sidebar"},"tutorial/getting-started":{"id":"tutorial/getting-started","title":"Getting started","description":"This guide will walk you through the steps to install and set up the Misti static analyzer.","sidebar":"sidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/a94703ab.9f24e801.js b/assets/js/a94703ab.9f24e801.js new file mode 100644 index 000000000..d81e92f43 --- /dev/null +++ b/assets/js/a94703ab.9f24e801.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9048],{2559:(e,t,n)=>{n.r(t),n.d(t,{default:()=>be});var a=n(6540),o=n(4164),i=n(1003),s=n(7559),l=n(1754),r=n(6588),c=n(1312),d=n(3104),u=n(5062);const m={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};var b=n(4848);function h(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,o]=(0,a.useState)(!1),i=(0,a.useRef)(!1),{startScroll:s,cancelScroll:l}=(0,d.gk)();return(0,d.Mq)(((e,n)=>{let{scrollY:a}=e;const s=n?.scrollY;s&&(i.current?i.current=!1:a>=s?(l(),o(!1)):a<t?o(!1):a+window.innerHeight<document.documentElement.scrollHeight&&o(!0))})),(0,u.$)((e=>{e.location.hash&&(i.current=!0,o(!1))})),{shown:n,scrollToTop:()=>s(0)}}({threshold:300});return(0,b.jsx)("button",{"aria-label":(0,c.T)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,o.A)("clean-btn",s.G.common.backToTopButton,m.backToTopButton,e&&m.backToTopButtonShow),type:"button",onClick:t})}var p=n(3109),x=n(6347),f=n(4581),j=n(6342),_=n(3465);function v(e){return(0,b.jsx)("svg",{width:"20",height:"20","aria-hidden":"true",...e,children:(0,b.jsxs)("g",{fill:"#7a7a7a",children:[(0,b.jsx)("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),(0,b.jsx)("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})]})})}const g={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function A(e){let{onClick:t}=e;return(0,b.jsx)("button",{type:"button",title:(0,c.T)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,o.A)("button button--secondary button--outline",g.collapseSidebarButton),onClick:t,children:(0,b.jsx)(v,{className:g.collapseSidebarButtonIcon})})}var k=n(5041),C=n(9532);const S=Symbol("EmptyContext"),T=a.createContext(S);function N(e){let{children:t}=e;const[n,o]=(0,a.useState)(null),i=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:o})),[n]);return(0,b.jsx)(T.Provider,{value:i,children:t})}var I=n(1422),B=n(9169),y=n(8774),w=n(2303);function L(e){let{collapsed:t,categoryLabel:n,onClick:a}=e;return(0,b.jsx)("button",{"aria-label":t?(0,c.T)({id:"theme.DocSidebarItem.expandCategoryAriaLabel",message:"Expand sidebar category '{label}'",description:"The ARIA label to expand the sidebar category"},{label:n}):(0,c.T)({id:"theme.DocSidebarItem.collapseCategoryAriaLabel",message:"Collapse sidebar category '{label}'",description:"The ARIA label to collapse the sidebar category"},{label:n}),"aria-expanded":!t,type:"button",className:"clean-btn menu__caret",onClick:a})}function E(e){let{item:t,onItemClick:n,activePath:i,level:r,index:c,...d}=e;const{items:u,label:m,collapsible:h,className:p,href:x}=t,{docs:{sidebar:{autoCollapseCategories:f}}}=(0,j.p)(),_=function(e){const t=(0,w.A)();return(0,a.useMemo)((()=>e.href&&!e.linkUnlisted?e.href:!t&&e.collapsible?(0,l.Nr)(e):void 0),[e,t])}(t),v=(0,l.w8)(t,i),g=(0,B.ys)(x,i),{collapsed:A,setCollapsed:k}=(0,I.u)({initialState:()=>!!h&&(!v&&t.collapsed)}),{expandedItem:N,setExpandedItem:E}=function(){const e=(0,a.useContext)(T);if(e===S)throw new C.dV("DocSidebarItemsExpandedStateProvider");return e}(),M=function(e){void 0===e&&(e=!A),E(e?null:c),k(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:o}=e;const i=(0,C.ZC)(t);(0,a.useEffect)((()=>{t&&!i&&n&&o(!1)}),[t,i,n,o])}({isActive:v,collapsed:A,updateCollapsed:M}),(0,a.useEffect)((()=>{h&&null!=N&&N!==c&&f&&k(!0)}),[h,N,c,k,f]),(0,b.jsxs)("li",{className:(0,o.A)(s.G.docs.docSidebarItemCategory,s.G.docs.docSidebarItemCategoryLevel(r),"menu__list-item",{"menu__list-item--collapsed":A},p),children:[(0,b.jsxs)("div",{className:(0,o.A)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":g}),children:[(0,b.jsx)(y.A,{className:(0,o.A)("menu__link",{"menu__link--sublist":h,"menu__link--sublist-caret":!x&&h,"menu__link--active":v}),onClick:h?e=>{n?.(t),x?M(!1):(e.preventDefault(),M())}:()=>{n?.(t)},"aria-current":g?"page":void 0,role:h&&!x?"button":void 0,"aria-expanded":h&&!x?!A:void 0,href:h?_??"#":_,...d,children:m}),x&&h&&(0,b.jsx)(L,{collapsed:A,categoryLabel:m,onClick:e=>{e.preventDefault(),M()}})]}),(0,b.jsx)(I.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:A,children:(0,b.jsx)(U,{items:u,tabIndex:A?-1:0,onItemClick:n,activePath:i,level:r+1})})]})}var M=n(6654),H=n(3186);const G={menuExternalLink:"menuExternalLink_NmtK"};function W(e){let{item:t,onItemClick:n,activePath:a,level:i,index:r,...c}=e;const{href:d,label:u,className:m,autoAddBaseUrl:h}=t,p=(0,l.w8)(t,a),x=(0,M.A)(d);return(0,b.jsx)("li",{className:(0,o.A)(s.G.docs.docSidebarItemLink,s.G.docs.docSidebarItemLinkLevel(i),"menu__list-item",m),children:(0,b.jsxs)(y.A,{className:(0,o.A)("menu__link",!x&&G.menuExternalLink,{"menu__link--active":p}),autoAddBaseUrl:h,"aria-current":p?"page":void 0,to:d,...x&&{onClick:n?()=>n(t):void 0},...c,children:[u,!x&&(0,b.jsx)(H.A,{})]})},u)}const P={menuHtmlItem:"menuHtmlItem_M9Kj"};function R(e){let{item:t,level:n,index:a}=e;const{value:i,defaultStyle:l,className:r}=t;return(0,b.jsx)("li",{className:(0,o.A)(s.G.docs.docSidebarItemLink,s.G.docs.docSidebarItemLinkLevel(n),l&&[P.menuHtmlItem,"menu__list-item"],r),dangerouslySetInnerHTML:{__html:i}},a)}function D(e){let{item:t,...n}=e;switch(t.type){case"category":return(0,b.jsx)(E,{item:t,...n});case"html":return(0,b.jsx)(R,{item:t,...n});default:return(0,b.jsx)(W,{item:t,...n})}}function F(e){let{items:t,...n}=e;const a=(0,l.Y)(t,n.activePath);return(0,b.jsx)(N,{children:a.map(((e,t)=>(0,b.jsx)(D,{item:e,index:t,...n},t)))})}const U=(0,a.memo)(F),V={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function Y(e){let{path:t,sidebar:n,className:i}=e;const l=function(){const{isActive:e}=(0,k.M)(),[t,n]=(0,a.useState)(e);return(0,d.Mq)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return(0,b.jsx)("nav",{"aria-label":(0,c.T)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,o.A)("menu thin-scrollbar",V.menu,l&&V.menuWithAnnouncementBar,i),children:(0,b.jsx)("ul",{className:(0,o.A)(s.G.docs.docSidebarMenu,"menu__list"),children:(0,b.jsx)(U,{items:n,activePath:t,level:1})})})}const K="sidebar_njMd",z="sidebarWithHideableNavbar_wUlq",q="sidebarHidden_VK0M",O="sidebarLogo_isFc";function J(e){let{path:t,sidebar:n,onCollapse:a,isHidden:i}=e;const{navbar:{hideOnScroll:s},docs:{sidebar:{hideable:l}}}=(0,j.p)();return(0,b.jsxs)("div",{className:(0,o.A)(K,s&&z,i&&q),children:[s&&(0,b.jsx)(_.A,{tabIndex:-1,className:O}),(0,b.jsx)(Y,{path:t,sidebar:n}),l&&(0,b.jsx)(A,{onClick:a})]})}const Q=a.memo(J);var X=n(5600),Z=n(9876);const $=e=>{let{sidebar:t,path:n}=e;const a=(0,Z.M)();return(0,b.jsx)("ul",{className:(0,o.A)(s.G.docs.docSidebarMenu,"menu__list"),children:(0,b.jsx)(U,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&a.toggle(),"link"===e.type&&a.toggle()},level:1})})};function ee(e){return(0,b.jsx)(X.GX,{component:$,props:e})}const te=a.memo(ee);function ne(e){const t=(0,f.l)(),n="desktop"===t||"ssr"===t,a="mobile"===t;return(0,b.jsxs)(b.Fragment,{children:[n&&(0,b.jsx)(Q,{...e}),a&&(0,b.jsx)(te,{...e})]})}const ae={expandButton:"expandButton_TmdG",expandButtonIcon:"expandButtonIcon_i1dp"};function oe(e){let{toggleSidebar:t}=e;return(0,b.jsx)("div",{className:ae.expandButton,title:(0,c.T)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t,children:(0,b.jsx)(v,{className:ae.expandButtonIcon})})}const ie={docSidebarContainer:"docSidebarContainer_YfHR",docSidebarContainerHidden:"docSidebarContainerHidden_DPk8",sidebarViewport:"sidebarViewport_aRkj"};function se(e){let{children:t}=e;const n=(0,r.t)();return(0,b.jsx)(a.Fragment,{children:t},n?.name??"noSidebar")}function le(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:i}=e;const{pathname:l}=(0,x.zy)(),[r,c]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{r&&c(!1),!r&&(0,p.O)()&&c(!0),i((e=>!e))}),[i,r]);return(0,b.jsx)("aside",{className:(0,o.A)(s.G.docs.docSidebarContainer,ie.docSidebarContainer,n&&ie.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(ie.docSidebarContainer)&&n&&c(!0)},children:(0,b.jsx)(se,{children:(0,b.jsxs)("div",{className:(0,o.A)(ie.sidebarViewport,r&&ie.sidebarViewportHidden),children:[(0,b.jsx)(ne,{sidebar:t,path:l,onCollapse:d,isHidden:r}),r&&(0,b.jsx)(oe,{toggleSidebar:d})]})})})}const re={docMainContainer:"docMainContainer_TBSr",docMainContainerEnhanced:"docMainContainerEnhanced_lQrH",docItemWrapperEnhanced:"docItemWrapperEnhanced_JWYK"};function ce(e){let{hiddenSidebarContainer:t,children:n}=e;const a=(0,r.t)();return(0,b.jsx)("main",{className:(0,o.A)(re.docMainContainer,(t||!a)&&re.docMainContainerEnhanced),children:(0,b.jsx)("div",{className:(0,o.A)("container padding-top--md padding-bottom--lg",re.docItemWrapper,t&&re.docItemWrapperEnhanced),children:n})})}const de={docRoot:"docRoot_UBD9",docsWrapper:"docsWrapper_hBAB"};function ue(e){let{children:t}=e;const n=(0,r.t)(),[o,i]=(0,a.useState)(!1);return(0,b.jsxs)("div",{className:de.docsWrapper,children:[(0,b.jsx)(h,{}),(0,b.jsxs)("div",{className:de.docRoot,children:[n&&(0,b.jsx)(le,{sidebar:n.items,hiddenSidebarContainer:o,setHiddenSidebarContainer:i}),(0,b.jsx)(ce,{hiddenSidebarContainer:o,children:t})]})]})}var me=n(3363);function be(e){const t=(0,l.B5)(e);if(!t)return(0,b.jsx)(me.A,{});const{docElement:n,sidebarName:a,sidebarItems:c}=t;return(0,b.jsx)(i.e3,{className:(0,o.A)(s.G.page.docsDocPage),children:(0,b.jsx)(r.V,{name:a,items:c,children:(0,b.jsx)(ue,{children:n})})})}},3363:(e,t,n)=>{n.d(t,{A:()=>l});n(6540);var a=n(4164),o=n(1312),i=n(1107),s=n(4848);function l(e){let{className:t}=e;return(0,s.jsx)("main",{className:(0,a.A)("container margin-vert--xl",t),children:(0,s.jsx)("div",{className:"row",children:(0,s.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,s.jsx)(i.A,{as:"h1",className:"hero__title",children:(0,s.jsx)(o.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}}}]); \ No newline at end of file diff --git a/assets/js/aac87eb6.6b5bbfc3.js b/assets/js/aac87eb6.6b5bbfc3.js new file mode 100644 index 000000000..793856084 --- /dev/null +++ b/assets/js/aac87eb6.6b5bbfc3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[684],{4646:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),i=n(8453);const r={},c="BranchDuplicate",o={id:"detectors/BranchDuplicate",title:"BranchDuplicate",description:"Detector that reports duplicated code in conditional branches.",source:"@site/versioned_docs/version-0.3.1/detectors/BranchDuplicate.md",sourceDirName:"detectors",slug:"/detectors/BranchDuplicate",permalink:"/tools/misti/docs/0.3.1/detectors/BranchDuplicate",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/BranchDuplicate.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"AsmIsUsed",permalink:"/tools/misti/docs/0.3.1/detectors/AsmIsUsed"},next:{title:"ConstantAddress",permalink:"/tools/misti/docs/0.3.1/detectors/ConstantAddress"}},a={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"branchduplicate",children:"BranchDuplicate"}),"\n",(0,s.jsx)(t.p,{children:"Detector that reports duplicated code in conditional branches."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Duplicated code in branches is bad because it:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Reduces Readability"}),": Repetition makes the code harder to understand."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Increases Maintenance"}),": Changes must be made in multiple places, risking errors."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Signals Poor Design"}),": It suggests missed opportunities for cleaner, more abstract code."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = 43; // bad: duplicated code\n} else {\n a = 43;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = inc(b); // ok\n} else {\n a = 43;\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>o});var s=n(6540);const i={},r=s.createContext(i);function c(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:c(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/aba21aa0.d087865c.js b/assets/js/aba21aa0.d087865c.js new file mode 100644 index 000000000..549d21e19 --- /dev/null +++ b/assets/js/aba21aa0.d087865c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5742],{7093:u=>{u.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/acef80f0.ccd7a032.js b/assets/js/acef80f0.ccd7a032.js new file mode 100644 index 000000000..faa9e946d --- /dev/null +++ b/assets/js/acef80f0.ccd7a032.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1468],{2492:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var s=n(4848),t=n(8453);const a={},o="Design Overview",l={id:"hacking/design",title:"Design Overview",description:"Static Analysis",source:"@site/versioned_docs/version-0.2.1/hacking/design.md",sourceDirName:"hacking",slug:"/hacking/design",permalink:"/tools/misti/docs/0.2.1/hacking/design",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/hacking/design.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Contributing",permalink:"/tools/misti/docs/0.2.1/hacking/contributing"},next:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.2.1/hacking/souffle"}},r={},c=[{value:"Static Analysis",id:"static-analysis",level:2},{value:"Souffle Datalog Solver",id:"souffle-datalog-solver",level:2},{value:"Dataflow Analysis in Misti",id:"dataflow-analysis-in-misti",level:2},{value:"References",id:"references",level:2}];function d(e){const i={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"design-overview",children:"Design Overview"}),"\n",(0,s.jsx)(i.h2,{id:"static-analysis",children:"Static Analysis"}),"\n",(0,s.jsx)(i.p,{children:"Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues."}),"\n",(0,s.jsx)(i.h2,{id:"souffle-datalog-solver",children:"Souffle Datalog Solver"}),"\n",(0,s.jsxs)(i.p,{children:["Misti leverages the ",(0,s.jsx)(i.a,{href:"https://souffle-lang.github.io",children:"Souffle Datalog solver"}),", an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases."]}),"\n",(0,s.jsx)(i.h2,{id:"dataflow-analysis-in-misti",children:"Dataflow Analysis in Misti"}),"\n",(0,s.jsx)(i.p,{children:"Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code."}),"\n",(0,s.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,s.jsx)(i.p,{children:"For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.a,{href:"https://cs.au.dk/~amoeller/spa/spa.pdf",children:"Anders M\xf8ller and Michael I. Schwartzbach \u2013 Static Program Analysis"})}),"\n",(0,s.jsx)(i.li,{children:"Uday Khedker et al. \u2013 Data Flow Analysis: Theory and Practice"}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"These resources provide a solid foundation in the theory and practice of static and dataflow analysis."})]})}function h(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>o,x:()=>l});var s=n(6540);const t={},a=s.createContext(t);function o(e){const i=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/aee0b8cc.c78b2bfe.js b/assets/js/aee0b8cc.c78b2bfe.js new file mode 100644 index 000000000..6627f1086 --- /dev/null +++ b/assets/js/aee0b8cc.c78b2bfe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5622],{3023:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>a,contentTitle:()=>r,default:()=>l,frontMatter:()=>i,metadata:()=>d,toc:()=>c});var n=s(4848),o=s(8453);const i={},r="DumpAst",d={id:"tools/DumpAst",title:"DumpAst",description:"The DumpAst tool in Misti enables users to output the Abstract Syntax Tree (AST) of project modules in JSON format. This is particularly useful when writing custom detectors, as it helps understand the structure and components of the code.",source:"@site/versioned_docs/version-0.4.0/tools/DumpAst.md",sourceDirName:"tools",slug:"/tools/DumpAst",permalink:"/tools/misti/docs/tools/DumpAst",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/tools/DumpAst.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Tools Overview",permalink:"/tools/misti/docs/tools"},next:{title:"DumpCfg",permalink:"/tools/misti/docs/tools/DumpCfg"}},a={},c=[{value:"Usage",id:"usage",level:2},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function u(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"dumpast",children:"DumpAst"}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"DumpAst"})," tool in Misti enables users to output the ",(0,n.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Abstract_syntax_tree",children:"Abstract Syntax Tree (AST)"})," of project modules in JSON format. This is particularly useful when writing custom detectors, as it helps understand the structure and components of the code."]}),"\n",(0,n.jsx)(t.h2,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(t.p,{children:"To dump the AST in JSON format, use the following command:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:'npx misti -t "DumpAst" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsxs)(t.p,{children:["If you wish to include the standard library in the dump, set ",(0,n.jsx)(t.code,{children:"dumpStdlib"})," to ",(0,n.jsx)(t.code,{children:"true"}),":"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:'npx misti -t "DumpAst:dumpStdlib=true" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(t.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(t.p,{children:["The AST provides a detailed breakdown of code components, offering insights into its structure. This is essential when creating or debugging ",(0,n.jsx)(t.a,{href:"/tools/misti/docs/hacking/custom-detector",children:"custom detectors"}),", as it allows a deeper understanding of how code is represented internally by the analyzer."]}),"\n",(0,n.jsxs)(t.p,{children:["By leveraging the ",(0,n.jsx)(t.code,{children:"DumpAst"})," tool, developers can more effectively navigate and interpret the project's syntax, supporting the development of accurate and efficient detectors."]})]})}function l(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(u,{...e})}):u(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>r,x:()=>d});var n=s(6540);const o={},i=n.createContext(o);function r(e){const t=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),n.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b05af762.c54dcfb2.js b/assets/js/b05af762.c54dcfb2.js new file mode 100644 index 000000000..cab741cf9 --- /dev/null +++ b/assets/js/b05af762.c54dcfb2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6670],{6683:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>a,frontMatter:()=>i,metadata:()=>n,toc:()=>l});var r=s(4848),d=s(8453);const i={id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},o="Detectors Overview",n={id:"detectors",title:"Detectors Overview",description:"Misti currently supports 15 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:",source:"@site/versioned_docs/version-0.3.0/detectors.md",sourceDirName:".",slug:"/detectors",permalink:"/tools/misti/docs/0.3.0/detectors",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors.md",tags:[],version:"0.3.0",frontMatter:{id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},sidebar:"sidebar",previous:{title:"Using with Blueprint",permalink:"/tools/misti/docs/0.3.0/tutorial/blueprint"},next:{title:"ArgCopyMutation",permalink:"/tools/misti/docs/0.3.0/detectors/ArgCopyMutation"}},c={},l=[];function h(e){const t={a:"a",code:"code",h1:"h1",p:"p",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,d.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"detectors-overview",children:"Detectors Overview"}),"\n",(0,r.jsx)(t.p,{children:"Misti currently supports 15 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"#"}),(0,r.jsx)(t.th,{children:"Detector"}),(0,r.jsx)(t.th,{children:"Requires Souffl\xe9"}),(0,r.jsx)(t.th,{children:"Enabled by default"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"1"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/ArgCopyMutation",children:"ArgCopyMutation"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"2"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/AsmIsUsed",children:"AsmIsUsed"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"3"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/BranchDuplicate",children:"BranchDuplicate"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"4"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/ConstantAddress",children:"ConstantAddress"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"5"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply",children:"DivideBeforeMultiply"})}),(0,r.jsx)(t.td,{children:"\u2714"}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"6"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/DumpIsUsed",children:"DumpIsUsed"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"7"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/FieldDoubleInit",children:"FieldDoubleInit"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"8"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/InheritedStateMutation",children:"InheritedStateMutation"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"9"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables",children:"NeverAccessedVariables"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"10"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign",children:"PreferAugmentedAssign"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"11"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi",children:"PreferredStdlibApi"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"12"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables",children:"ReadOnlyVariables"})}),(0,r.jsx)(t.td,{children:"\u2714"}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"13"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap",children:"StringReceiversOverlap"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"14"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/UnboundLoops",children:"UnboundLoops"})}),(0,r.jsx)(t.td,{children:"\u2714"}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"15"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/detectors/ZeroAddress",children:"ZeroAddress"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]})]})]}),"\n",(0,r.jsxs)(t.p,{children:["Some of the detectors require ",(0,r.jsx)(t.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})," to be installed. If no Souffl\xe9 installation is found, these detectors won't be executed."]}),"\n",(0,r.jsxs)(t.p,{children:["A few detectors are optional and aimed at auditors to help uncover subtle issues in the source code. To enable all detectors, use the ",(0,r.jsx)(t.code,{children:"--all-detectors"})," option. You can find a full list of configuration options on the ",(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.0/tutorial/configuration",children:"configuration page"}),"."]}),"\n",(0,r.jsx)(t.p,{children:"Each detector targets a specific type of problem in your code. Click on the detector name to learn more."})]})}function a(e={}){const{wrapper:t}={...(0,d.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>o,x:()=>n});var r=s(6540);const d={},i=r.createContext(d);function o(e){const t=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function n(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:o(e.components),r.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b12d76e5.d3ad221e.js b/assets/js/b12d76e5.d3ad221e.js new file mode 100644 index 000000000..252b9c857 --- /dev/null +++ b/assets/js/b12d76e5.d3ad221e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9359],{9813:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>d,toc:()=>a});var i=n(4848),o=n(8453);const s={},r="DuplicatedCondition",d={id:"detectors/DuplicatedCondition",title:"DuplicatedCondition",description:"A detector that finds duplicated conditions appearing in conditional expressions.",source:"@site/docs/detectors/DuplicatedCondition.md",sourceDirName:"detectors",slug:"/detectors/DuplicatedCondition",permalink:"/tools/misti/docs/next/detectors/DuplicatedCondition",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/DuplicatedCondition.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpIsUsed",permalink:"/tools/misti/docs/next/detectors/DumpIsUsed"},next:{title:"EnsurePrgSeed",permalink:"/tools/misti/docs/next/detectors/EnsurePrgSeed"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"duplicatedcondition",children:"DuplicatedCondition"}),"\n",(0,i.jsx)(t.p,{children:"A detector that finds duplicated conditions appearing in conditional expressions."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsx)(t.p,{children:"Typically, these cases are developer errors caused by copy-pasting code, leading\nto unreachable code."}),"\n",(0,i.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"fun test(a: Int): Int {\n if (a < 1) { return 1; }\n else if (a > 4) { return 2; }\n // Bad: A developer copy-pasted the condition\n else if (a > 4) { return 3; }\n return 4;\n}\n"})}),"\n",(0,i.jsx)(t.p,{children:"Use instead:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"fun test(a: Int): Int {\n if (a < 1) { return 1; }\n else if (a > 4) { return 2; }\n // OK: Fixed\n else if (a < x) { return 3; }\n return 4;\n}\n"})})]})}function p(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>d});var i=n(6540);const o={},s=i.createContext(o);function r(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b3799bec.86c01a35.js b/assets/js/b3799bec.86c01a35.js new file mode 100644 index 000000000..6bee2bf96 --- /dev/null +++ b/assets/js/b3799bec.86c01a35.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8031],{4207:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var s=n(4848),o=n(8453);const r={},d="Constant Address",a={id:"detectors/ConstantAddress",title:"Constant Address",description:"An optional detector that highlights all the constant addresses appearing in the source code.",source:"@site/versioned_docs/version-0.2.0/detectors/ConstantAddress.md",sourceDirName:"detectors",slug:"/detectors/ConstantAddress",permalink:"/tools/misti/docs/0.2.0/detectors/ConstantAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/ConstantAddress.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Zero Address",permalink:"/tools/misti/docs/0.2.0/detectors/ZeroAddress"},next:{title:"Branch Duplicate",permalink:"/tools/misti/docs/0.2.0/detectors/BranchDuplicate"}},i={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"constant-address",children:"Constant Address"}),"\n",(0,s.jsx)(t.p,{children:"An optional detector that highlights all the constant addresses appearing in the source code."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsxs)(t.p,{children:["Using hardcoded addresses can sometimes indicate poor contract design.\nSome constant addresses may need to be set dynamically, e.g., using\n",(0,s.jsx)(t.code,{children:"contractAddress"}),", or at least have a way to change them at runtime, for\nexample, when upgrading a contract."]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'contract Main {\n proxy: Address;\n init() {\n // Bad: Constant address highlighted by the analyzer.\n self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");\n }\n}\n'})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"contract Main {\n proxy: Address;\n init() {\n let proxy: Proxy = initOf Proxy(myAddress());\n // OK: Address depends on how the proxy contact has been deployed\n self.proxy = contractAddress(proxy);\n }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>a});var s=n(6540);const o={},r=s.createContext(o);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b64540ae.4fd9953e.js b/assets/js/b64540ae.4fd9953e.js new file mode 100644 index 000000000..684266dac --- /dev/null +++ b/assets/js/b64540ae.4fd9953e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6412],{8560:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var t=i(4848),s=i(8453);const l={},r="Getting started",o={id:"tutorial/getting-started",title:"Getting started",description:"This guide will walk you through the steps to install and set up the Misti static analyzer.",source:"@site/docs/tutorial/getting-started.md",sourceDirName:"tutorial",slug:"/tutorial/getting-started",permalink:"/tools/misti/docs/next/tutorial/getting-started",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tutorial/getting-started.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Introduction",permalink:"/tools/misti/docs/next/"},next:{title:"CI/CD Integration",permalink:"/tools/misti/docs/next/tutorial/ci-cd"}},a={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Using Development Version",id:"using-development-version",level:3},{value:"Running the analysis",id:"running-the-analysis",level:2},{value:"More usage examples",id:"more-usage-examples",level:2},{value:"Suppressing Specific Detectors",id:"suppressing-specific-detectors",level:3},{value:"Enabling All Detectors",id:"enabling-all-detectors",level:3},{value:"Running in Quiet Mode",id:"running-in-quiet-mode",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,t.jsx)(n.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsx)(n.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Git"}),"\n",(0,t.jsx)(n.li,{children:"Yarn"}),"\n",(0,t.jsx)(n.li,{children:"Node.js version 22 or higher"}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,t.jsxs)(n.p,{children:["Misti is distributed via npm and should be added to your Tact project ",(0,t.jsx)(n.a,{href:"https://github.com/tact-lang/tact?tab=readme-ov-file#installation",children:"in the same way"})," as Tact itself:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn add @nowarp/misti\n"})}),"\n",(0,t.jsx)(n.h3,{id:"using-development-version",children:"Using Development Version"}),"\n",(0,t.jsx)(n.p,{children:"The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis."}),"\n",(0,t.jsx)(n.p,{children:"To install the latest development version you should:"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["Clone Misti: ",(0,t.jsx)(n.code,{children:"git clone https://github.com/nowarp/misti"})]}),"\n",(0,t.jsxs)(n.li,{children:["Build it: ",(0,t.jsx)(n.code,{children:"cd misti && yarn install && yarn build"})]}),"\n",(0,t.jsxs)(n.li,{children:["Use it in your Tact project: ",(0,t.jsx)(n.code,{children:"cd /path/to/tact/project && yarn add file:/path/to/misti"})]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,t.jsx)(n.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"npx misti path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,t.jsxs)(n.p,{children:["You can also add a script to your ",(0,t.jsx)(n.code,{children:"package.json"})," to simplify running the linting process:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "scripts": {\n "lint": "npx misti path/to/tact.config.json"\n }\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"more-usage-examples",children:"More usage examples"}),"\n",(0,t.jsxs)(n.p,{children:["Below are a few usage examples for common scenarios when using ",(0,t.jsxs)(n.a,{href:"/tools/misti/docs/next/tutorial/cli",children:["the ",(0,t.jsx)(n.code,{children:"misti"})," CLI"]}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"suppressing-specific-detectors",children:"Suppressing Specific Detectors"}),"\n",(0,t.jsxs)(n.p,{children:["To run ",(0,t.jsx)(n.code,{children:"misti"})," while suppressing specific detectors, such as ",(0,t.jsx)(n.code,{children:"ReadOnlyVariables"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --suppress ReadOnlyVariables path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.h3,{id:"enabling-all-detectors",children:"Enabling All Detectors"}),"\n",(0,t.jsxs)(n.p,{children:["Running ",(0,t.jsx)(n.code,{children:"misti"})," with all available built-in detectors enabled:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --all-detectors path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"It is recommended to do that when auditing the project."}),"\n",(0,t.jsx)(n.h3,{id:"running-in-quiet-mode",children:"Running in Quiet Mode"}),"\n",(0,t.jsxs)(n.p,{children:["To suppress all output while running ",(0,t.jsx)(n.code,{children:"misti"})," getting just a return code:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --quiet path/to/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This might be useful in scripts and CI/CD."}),"\n",(0,t.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,t.jsxs)(n.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,t.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>o});var t=i(6540);const s={},l=t.createContext(s);function r(e){const n=t.useContext(l);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b64aaedd.88204f90.js b/assets/js/b64aaedd.88204f90.js new file mode 100644 index 000000000..79472ec1e --- /dev/null +++ b/assets/js/b64aaedd.88204f90.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5588],{4913:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>a,toc:()=>c});var o=n(4848),i=n(8453);const s={},r="FalseCondition",a={id:"detectors/FalseCondition",title:"FalseCondition",description:"A detector that highlights conditions that evaluate to a constant true or false",source:"@site/versioned_docs/version-0.4.0/detectors/FalseCondition.md",sourceDirName:"detectors",slug:"/detectors/FalseCondition",permalink:"/tools/misti/docs/detectors/FalseCondition",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/FalseCondition.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"EnsurePrgSeed",permalink:"/tools/misti/docs/detectors/EnsurePrgSeed"},next:{title:"FieldDoubleInit",permalink:"/tools/misti/docs/detectors/FieldDoubleInit"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h1,{id:"falsecondition",children:"FalseCondition"}),"\n",(0,o.jsxs)(t.p,{children:["A detector that highlights conditions that evaluate to a constant ",(0,o.jsx)(t.code,{children:"true"})," or ",(0,o.jsx)(t.code,{children:"false"}),"\nin ",(0,o.jsx)(t.code,{children:"if"}),", ",(0,o.jsx)(t.code,{children:"while"}),", or ",(0,o.jsx)(t.code,{children:"until"})," statements, and zero iterations in ",(0,o.jsx)(t.code,{children:"repeat"})," statements."]}),"\n",(0,o.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsxs)(t.p,{children:["Conditions that always evaluate to a constant ",(0,o.jsx)(t.code,{children:"true"})," or ",(0,o.jsx)(t.code,{children:"false"})," are likely the result of a typo\nor logic error. Such conditions can lead to unintended behavior, dead code, or incorrect control flow.\nThis detector helps identify these cases so they can be corrected, improving the code's reliability."]}),"\n",(0,o.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-tact",children:"const FALSE: Bool = false;\n// Bad: Always false because of operator precedence\nif ((param | value) & FALSE) {\n // ... never executed\n}\n"})}),"\n",(0,o.jsx)(t.p,{children:"Use instead:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-tact",children:"const FALSE: Bool = false;\n// OK: Fixed after the analyzer highlighted this\nif (param) {}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var o=n(6540);const i={},s=o.createContext(i);function r(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b78952d0.efed39b1.js b/assets/js/b78952d0.efed39b1.js new file mode 100644 index 000000000..031affaeb --- /dev/null +++ b/assets/js/b78952d0.efed39b1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7682],{4428:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(4848),s=i(8453);const o={},a="FieldDoubleInit",r={id:"detectors/FieldDoubleInit",title:"FieldDoubleInit",description:"A detector that highlights cases where a field is initialized both in the",source:"@site/versioned_docs/version-0.3.1/detectors/FieldDoubleInit.md",sourceDirName:"detectors",slug:"/detectors/FieldDoubleInit",permalink:"/tools/misti/docs/0.3.1/detectors/FieldDoubleInit",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/FieldDoubleInit.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpIsUsed",permalink:"/tools/misti/docs/0.3.1/detectors/DumpIsUsed"},next:{title:"InheritedStateMutation",permalink:"/tools/misti/docs/0.3.1/detectors/InheritedStateMutation"}},d={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"fielddoubleinit",children:"FieldDoubleInit"}),"\n",(0,n.jsxs)(t.p,{children:["A detector that highlights cases where a field is initialized both in the\n",(0,n.jsx)(t.code,{children:"init"})," function and at the point of definition."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["Double initialization of fields can either be a programmer's mistake or simply\na waste of gas. It is always preferred to initialize values in the field declaration\nif they have a compile-time evaluatable default value, or in the ",(0,n.jsx)(t.code,{children:"init"})," function if\nthey must be initialized dynamically."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int = 0; // Bad\n init(x: Int) { self.a = x }\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int; // Fixed\n init(x: Int) { self.a = x }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>a,x:()=>r});var n=i(6540);const s={},o=n.createContext(s);function a(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b80eaa74.91abd0f7.js b/assets/js/b80eaa74.91abd0f7.js new file mode 100644 index 000000000..002af74f0 --- /dev/null +++ b/assets/js/b80eaa74.91abd0f7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4111],{8050:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>f});var t=i(4848),r=i(8453);const s={},a="Souffl\xe9 Integration Guide",o={id:"hacking/souffle",title:"Souffl\xe9 Integration Guide",description:"What is Souffl\xe9?",source:"@site/versioned_docs/version-0.3.0/hacking/souffle.md",sourceDirName:"hacking",slug:"/hacking/souffle",permalink:"/tools/misti/docs/0.3.0/hacking/souffle",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/hacking/souffle.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Design Overview",permalink:"/tools/misti/docs/0.3.0/hacking/design"},next:{title:"Tools",permalink:"/tools/misti/docs/0.3.0/hacking/tools"}},l={},f=[{value:"What is Souffl\xe9?",id:"what-is-souffl\xe9",level:2},{value:"Benefits of Using Souffl\xe9 for Static Analysis",id:"benefits-of-using-souffl\xe9-for-static-analysis",level:2},{value:"Souffl\xe9 Integration in Misti",id:"souffl\xe9-integration-in-misti",level:2},{value:"Creating Souffl\xe9 Programs",id:"creating-souffl\xe9-programs",level:3},{value:"Generating Facts and Executing Souffl\xe9",id:"generating-facts-and-executing-souffl\xe9",level:3},{value:"Learning from Existing Code",id:"learning-from-existing-code",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"souffl\xe9-integration-guide",children:"Souffl\xe9 Integration Guide"}),"\n",(0,t.jsx)(n.h2,{id:"what-is-souffl\xe9",children:"What is Souffl\xe9?"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io",children:"Souffl\xe9"})," is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Souffl\xe9, Misti can perform deep and scalable analyses of smart contracts."]}),"\n",(0,t.jsx)(n.h2,{id:"benefits-of-using-souffl\xe9-for-static-analysis",children:"Benefits of Using Souffl\xe9 for Static Analysis"}),"\n",(0,t.jsx)(n.p,{children:"Souffl\xe9 allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Souffl\xe9 program might be more straightforward then implementing a complex transfer function in for a classic monotone framework."}),"\n",(0,t.jsx)(n.h2,{id:"souffl\xe9-integration-in-misti",children:"Souffl\xe9 Integration in Misti"}),"\n",(0,t.jsxs)(n.p,{children:["The API for interacting with Souffl\xe9 in Misti is implemented in the ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/souffle.js",children:"Souffle.js library"}),". See the ",(0,t.jsx)(n.a,{href:"https://nowarp.io/lib/souffle-js/api/",children:"Souffle.js API reference"})," for more detailed information."]}),"\n",(0,t.jsx)(n.h3,{id:"creating-souffl\xe9-programs",children:"Creating Souffl\xe9 Programs"}),"\n",(0,t.jsx)(n.p,{children:'To create a Souffl\xe9 program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:'}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addDecls(ctx: Context<SrcInfo>) {\n ctx.add(\n Relation.from(\n "varDecl",\n [\n ["var", FactType.Symbol],\n ["func", FactType.Symbol],\n ],\n undefined,\n ),\n );\n // other declarations\n}\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addRules(ctx: Context<SrcInfo>) {\n // readOnly(var, func) :-\n // varDecl(var, func),\n // !varAssign(var, func),\n // !varUse(var, func).\n ctx.add(\n Rule.from(\n [makeAtom("readOnly", ["var", "func"])],\n makeRuleBody(makeAtom("varDecl", ["var", "func"])),\n makeRuleBody(makeAtom("varAssign", ["var", "func"]), {\n negated: true,\n }),\n makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),\n ),\n );\n }\n'})}),"\n",(0,t.jsx)(n.h3,{id:"generating-facts-and-executing-souffl\xe9",children:"Generating Facts and Executing Souffl\xe9"}),"\n",(0,t.jsx)(n.p,{children:"After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Souffl\xe9 executor to run the analysis:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"const executor = ctx.config.soufflePath\n ? new Executor<SrcInfo>({\n inputDir: ctx.config.soufflePath,\n outputDir: ctx.config.soufflePath,\n })\n : new Executor<SrcInfo>();\n\nconst result = executor.executeSync(program);\n\nif (!result.success) {\n throw new Error(\n `Error executing Souffl\xe9 for ${this.id}:\\n${result.stderr}`,\n );\n}\n\nconst warnings = Array.from(result.results.entries.values()).map((fact) => {\n // raise warnings\n});\n"})}),"\n",(0,t.jsx)(n.h3,{id:"learning-from-existing-code",children:"Learning from Existing Code"}),"\n",(0,t.jsx)(n.p,{children:"We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Souffl\xe9 with Misti. This will help you understand the intricacies of generating IR and executing Souffl\xe9 programs effectively."}),"\n",(0,t.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,t.jsxs)(n.p,{children:["For a deeper understanding of static analysis using Souffl\xe9, refer to the textbook ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.a,{href:"https://arxiv.org/pdf/2012.10086",children:"Program Analysis: An Appetizer"})})," by Flemming Nielson and Hanne Riis Nielson. It discusses Souffl\xe9-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field."]})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>a,x:()=>o});var t=i(6540);const r={},s=t.createContext(r);function a(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b91dc83b.a57e29d3.js b/assets/js/b91dc83b.a57e29d3.js new file mode 100644 index 000000000..ccf1311be --- /dev/null +++ b/assets/js/b91dc83b.a57e29d3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9601],{3137:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var t=n(4848),s=n(8453);const o={},r="Configuration",l={id:"tutorial/configuration",title:"Configuration",description:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.",source:"@site/versioned_docs/version-0.2.1/tutorial/configuration.md",sourceDirName:"tutorial",slug:"/tutorial/configuration",permalink:"/tools/misti/docs/0.2.1/tutorial/configuration",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/tutorial/configuration.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.2.1/tutorial/ci-cd"},next:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.2.1/detectors"}},a={},c=[{value:"Configuration Options",id:"configuration-options",level:3},{value:"Running Misti with Configuration",id:"running-misti-with-configuration",level:2},{value:"Default Configuration File",id:"default-configuration-file",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const i={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(i.h1,{id:"configuration",children:"Configuration"}),"\n",(0,t.jsx)(i.p,{children:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set."}),"\n",(0,t.jsx)(i.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"detectors"}),": List of detectors to run. Each detector can be specified with a ",(0,t.jsx)(i.code,{children:"className"})," and optionally a ",(0,t.jsx)(i.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"modulePath"})," (string, optional): The file path of the detector module."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"ignored_projects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"soufflePath"})," (string, optional): Directory to save generated Souffl\xe9 files which is helpful for debugging purposes. If not set, a temporary directory will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"tactStdlibPath"})," (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"unusedPrefix"}),' (string, default: "_"): Identifiers starting with this prefix won\'t be reported as unused by built-in detectors.']}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"verbosity"})," (string, optional): Verbosity level of the logs. Possible values are ",(0,t.jsx)(i.code,{children:"quiet"}),", ",(0,t.jsx)(i.code,{children:"debug"}),", and ",(0,t.jsx)(i.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(i.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,t.jsx)(i.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsx)(i.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,t.jsx)(i.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,t.jsx)(i.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-json",children:'{\n "detectorsEnabled": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n { "className": "BranchDuplicate" },\n { "className": "FieldDoubleInit" },\n { "className": "PreferAugmentedAssign" }\n ],\n "ignoredProjects": [],\n "unusedPrefix": "_",\n "verbosity": "default"\n}\n'})}),"\n",(0,t.jsxs)(i.p,{children:["All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,t.jsxs)(i.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,t.jsx)(i.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --dump-config test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsxs)(i.p,{children:["If there is no Misti config in the ",(0,t.jsx)(i.code,{children:"simple"})," directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors."]}),"\n",(0,t.jsx)(i.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,t.jsxs)(i.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,t.jsx)(i.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function u(e={}){const{wrapper:i}={...(0,s.R)(),...e.components};return i?(0,t.jsx)(i,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>r,x:()=>l});var t=n(6540);const s={},o=t.createContext(s);function r(e){const i=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/bce595e9.46a0cb1c.js b/assets/js/bce595e9.46a0cb1c.js new file mode 100644 index 000000000..540387f5b --- /dev/null +++ b/assets/js/bce595e9.46a0cb1c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8692],{3117:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var t=i(4848),s=i(8453);const r={},o="Contributing Guide",a={id:"hacking/contributing",title:"Contributing Guide",description:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.",source:"@site/versioned_docs/version-0.2.2/hacking/contributing.md",sourceDirName:"hacking",slug:"/hacking/contributing",permalink:"/tools/misti/docs/0.2.2/hacking/contributing",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/hacking/contributing.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Prefer Augmented Assignment",permalink:"/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign"},next:{title:"Design Overview",permalink:"/tools/misti/docs/0.2.2/hacking/design"}},c={},d=[{value:"Issues reporting",id:"issues-reporting",level:2},{value:"Documentation contribution",id:"documentation-contribution",level:2},{value:"Code contribution",id:"code-contribution",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"contributing-guide",children:"Contributing Guide"}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better."}),"\n",(0,t.jsx)(n.h2,{id:"issues-reporting",children:"Issues reporting"}),"\n",(0,t.jsx)(n.p,{children:"When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.\nPlease help us by publishing it and the input sources at:\nhttps://github.com/nowarp/misti/issues/new.\n"})}),"\n",(0,t.jsx)(n.p,{children:"We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users."}),"\n",(0,t.jsx)(n.h2,{id:"documentation-contribution",children:"Documentation contribution"}),"\n",(0,t.jsxs)(n.p,{children:["We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/nowarp.github.io/issues",children:"nowarp.github.io Issues"}),". Additionally, many documentation pages have an ",(0,t.jsx)(n.code,{children:"Edit"})," button that allows you to make direct contributions easily."]}),"\n",(0,t.jsx)(n.h2,{id:"code-contribution",children:"Code contribution"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Navigate Issues and Find Tasks"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Browse the issues ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"here"}),". Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues."]}),"\n",(0,t.jsx)(n.li,{children:"Choose an issue suitable for you and mention in the issue that you're working on it."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Implement Your Changes"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Implement your changes. Feel free to ask questions in the issue if needed."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Ensure Tests Pass"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Before creating a PR, make sure all tests and CI checks are passing by running:","\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn test-all\n"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Create a PR"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Submit your pull request ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/pulls",children:"here"})]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Add a CHANGELOG entry"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Describe your changes in the ",(0,t.jsx)(n.code,{children:"CHANGELOG.md"})," file according to the existing structure."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/HACKING.md",children:"HACKING.md"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your contributions!"})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>o,x:()=>a});var t=i(6540);const s={},r=t.createContext(s);function o(e){const n=t.useContext(r);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),t.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/bd72ef9b.45e20252.js b/assets/js/bd72ef9b.45e20252.js new file mode 100644 index 000000000..1a77b20ad --- /dev/null +++ b/assets/js/bd72ef9b.45e20252.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1114],{9712:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>r,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>d,toc:()=>l});var n=i(4848),s=i(8453);const o={},a="Field Initialized Twice",d={id:"detectors/FieldDoubleInit",title:"Field Initialized Twice",description:"A detector that highlights cases where a field is initialized both in the init function and at the point of definition.",source:"@site/versioned_docs/version-0.2.0/detectors/FieldDoubleInit.md",sourceDirName:"detectors",slug:"/detectors/FieldDoubleInit",permalink:"/tools/misti/docs/0.2.0/detectors/FieldDoubleInit",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/FieldDoubleInit.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"`dump` Is Used",permalink:"/tools/misti/docs/0.2.0/detectors/DumpIsUsed"},next:{title:"Prefer Augmented Assignment",permalink:"/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign"}},r={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"field-initialized-twice",children:"Field Initialized Twice"}),"\n",(0,n.jsxs)(t.p,{children:["A detector that highlights cases where a field is initialized both in the ",(0,n.jsx)(t.code,{children:"init"})," function and at the point of definition."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["Double initialization of fields can either be a programmer's mistake or simply a waste of gas. It is always preferred to initialize values in the field declaration if they have a compile-time evaluatable default value, or in the ",(0,n.jsx)(t.code,{children:"init"})," function if they must be initialized dynamically."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int = 0; // Bad\n init(x: Int) { self.a = x }\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int; // Fixed\n init(x: Int) { self.a = x }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>a,x:()=>d});var n=i(6540);const s={},o=n.createContext(s);function a(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/be8ab43b.f4a8e3dd.js b/assets/js/be8ab43b.f4a8e3dd.js new file mode 100644 index 000000000..64cb49c57 --- /dev/null +++ b/assets/js/be8ab43b.f4a8e3dd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6584],{3308:(i,e,t)=>{t.r(e),t.d(e,{assets:()=>o,contentTitle:()=>I,default:()=>c,frontMatter:()=>l,metadata:()=>d,toc:()=>g});var n=t(4848),s=t(8453);const l={},I="Tools Guide",d={id:"hacking/tools",title:"Tools Guide",description:"This page describes the internal analyzer tools available in Misti to aid in development and debugging.",source:"@site/versioned_docs/version-0.3.1/hacking/tools.md",sourceDirName:"hacking",slug:"/hacking/tools",permalink:"/tools/misti/docs/0.3.1/hacking/tools",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/hacking/tools.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.3.1/hacking/souffle"},next:{title:"Custom Detectors",permalink:"/tools/misti/docs/0.3.1/hacking/custom-detector"}},o={},g=[{value:"CFG Dump",id:"cfg-dump",level:2},{value:"Usage",id:"usage",level:3},{value:"Converting DOT to SVG",id:"converting-dot-to-svg",level:3},{value:"Viewing the SVG",id:"viewing-the-svg",level:3},{value:"VS Code Plugin",id:"vs-code-plugin",level:3},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function a(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"tools-guide",children:"Tools Guide"}),"\n",(0,n.jsx)(e.p,{children:"This page describes the internal analyzer tools available in Misti to aid in development and debugging."}),"\n",(0,n.jsx)(e.h2,{id:"cfg-dump",children:"CFG Dump"}),"\n",(0,n.jsx)(e.p,{children:"Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts."}),"\n",(0,n.jsx)(e.h3,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in JSON format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in DOT format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.h3,{id:"converting-dot-to-svg",children:"Converting DOT to SVG"}),"\n",(0,n.jsxs)(e.p,{children:["To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use ",(0,n.jsx)(e.a,{href:"https://graphviz.org",children:"Graphviz"})," with the following command:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot\ndot -Tsvg output.dot -o output.svg\n'})}),"\n",(0,n.jsx)(e.h3,{id:"viewing-the-svg",children:"Viewing the SVG"}),"\n",(0,n.jsx)(e.p,{children:"To view the SVG file in Firefox, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"firefox output.svg\n"})}),"\n",(0,n.jsx)(e.p,{children:"For example, for the following contract:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:"fun test(): Int {\n let sum: Int = 0;\n let i: Int = 0;\n repeat (10) {\n i = i + 1;\n sum = sum + i;\n }\n return sum;\n}\n"})}),"\n",(0,n.jsx)(e.p,{children:"The following CFG will be generated:"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"CFG Example",src:t(685).A+"",width:"337",height:"516"})}),"\n",(0,n.jsx)(e.h3,{id:"vs-code-plugin",children:"VS Code Plugin"}),"\n",(0,n.jsxs)(e.p,{children:["For real-time visualization of DOT files, you can use ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/search?term=tag%3Agraphviz&target=VSCode&category=All%20categories&sortBy=Relevance",children:"one of the available"})," Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development."]}),"\n",(0,n.jsx)(e.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"JSON Dumps"}),": These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"DOT Dumps"}),": These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(e.p,{children:"By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors."})]})}function c(i={}){const{wrapper:e}={...(0,s.R)(),...i.components};return e?(0,n.jsx)(e,{...i,children:(0,n.jsx)(a,{...i})}):a(i)}},685:(i,e,t)=>{t.d(e,{A:()=>n});const n="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDIuNCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBsb29wcyYjNDU7MyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjUzcHQiIGhlaWdodD0iMzg3cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjUzLjAwIDM4Ny4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzODMpIj4KPHRpdGxlPmxvb3BzJiM0NTszPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzgzIDI0OSwtMzgzIDI0OSw0IC00LDQiLz4KPGcgaWQ9ImNsdXN0MSIgY2xhc3M9ImNsdXN0ZXIiPgo8dGl0bGU+Y2x1c3Rlcl90ZXN0PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI4LC04IDgsLTM3MSAyMzcsLTM3MSAyMzcsLTggOCwtOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIuNSIgeT0iLTM1NS44IiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnRlc3Q8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0MSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT50ZXN0XzE0MTwvdGl0bGU+Cjxwb2x5Z29uIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjI0LjUsLTM0MCA5NS41LC0zNDAgOTUuNSwtMzA0IDIyNC41LC0zMDQgMjI0LjUsLTM0MCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNjAiIHk9Ii0zMTguMyIgZm9udC1mYW1pbHk9IlRpbWVzLHNlcmlmIiBmb250LXNpemU9IjE0LjAwIj5sZXQgc3VtOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDI8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMiwtMjY4IDEwOCwtMjY4IDEwOCwtMjMyIDIxMiwtMjMyIDIxMiwtMjY4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTI0Ni4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPmxldCBpOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDEmIzQ1OyZndDt0ZXN0XzE0MiAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MSYjNDU7Jmd0O3Rlc3RfMTQyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMzAzLjdDMTYwLC0yOTUuOTggMTYwLC0yODYuNzEgMTYwLC0yNzguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTI3OC4xIDE2MCwtMjY4LjEgMTU2LjUsLTI3OC4xIDE2My41LC0yNzguMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDQ8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOCwtMTk2IDExMiwtMTk2IDExMiwtMTYwIDIwOCwtMTYwIDIwOCwtMTk2Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTE3NC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnJlcGVhdCAoMTApPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDImIzQ1OyZndDt0ZXN0XzE0NCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MiYjNDU7Jmd0O3Rlc3RfMTQ0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMjMxLjdDMTYwLC0yMjMuOTggMTYwLC0yMTQuNzEgMTYwLC0yMDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTIwNi4xIDE2MCwtMTk2LjEgMTU2LjUsLTIwNi4xIDE2My41LC0yMDYuMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDYgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDY8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjkzLjUsLTEyNCAxNi41LC0xMjQgMTYuNSwtODggOTMuNSwtODggOTMuNSwtMTI0Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjU1IiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+aSA9IGkgKyAxPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE0NiAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0NCYjNDU7Jmd0O3Rlc3RfMTQ2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEzNC4zMSwtMTU5Ljg4QzEyMC43MSwtMTUwLjgxIDEwMy44MywtMTM5LjU1IDg5LjE0LC0xMjkuNzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iOTEuMDUsLTEyNi44MiA4MC43OCwtMTI0LjE5IDg3LjE2LC0xMzIuNjUgOTEuMDUsLTEyNi44MiIvPgo8L2c+CjwhLS0gdGVzdF8xNTEgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNTE8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjNjZhN2RiIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOC41LC0xMjQgMTExLjUsLTEyNCAxMTEuNSwtODggMjA4LjUsLTg4IDIwOC41LC0xMjQiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTYwIiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+cmV0dXJuIHN1bTwvdGV4dD4KPC9nPgo8IS0tIHRlc3RfMTQ0JiM0NTsmZ3Q7dGVzdF8xNTEgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE1MTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNjAsLTE1OS43QzE2MCwtMTUxLjk4IDE2MCwtMTQyLjcxIDE2MCwtMTM0LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2My41LC0xMzQuMSAxNjAsLTEyNC4xIDE1Ni41LC0xMzQuMSAxNjMuNSwtMTM0LjEiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPnRlc3RfMTQ4PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxODMuNSwtNTIgNjAuNSwtNTIgNjAuNSwtMTYgMTgzLjUsLTE2IDE4My41LC01MiIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIiIHk9Ii0zMC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnN1bSA9IHN1bSArIGk8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0NiYjNDU7Jmd0O3Rlc3RfMTQ4IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPnRlc3RfMTQ2JiM0NTsmZ3Q7dGVzdF8xNDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuNTYsLTg3LjdDNzkuNjgsLTc5LjIyIDg5LjU5LC02OC44NiA5OC40NywtNTkuNTgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAxLjI0LC02MS43NSAxMDUuNjMsLTUyLjEgOTYuMTksLTU2LjkxIDEwMS4yNCwtNjEuNzUiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4JiM0NTsmZ3Q7dGVzdF8xNDQgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDgmIzQ1OyZndDt0ZXN0XzE0NDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzUuMjIsLTUyLjA0QzE5MS44OSwtNjAuMTYgMjA4LjQyLC03MS43NyAyMTgsLTg4IDIyNi4xMywtMTAxLjc4IDIyNC40NSwtMTA5LjM2IDIxOCwtMTI0IDIxMy4wMSwtMTM1LjMxIDIwNC4yOSwtMTQ1LjI2IDE5NS4xLC0xNTMuMzgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTkyLjgzLC0xNTAuNzIgMTg3LjM0LC0xNTkuNzcgMTk3LjI4LC0xNTYuMTIgMTkyLjgzLC0xNTAuNzIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8453:(i,e,t)=>{t.d(e,{R:()=>I,x:()=>d});var n=t(6540);const s={},l=n.createContext(s);function I(i){const e=n.useContext(l);return n.useMemo((function(){return"function"==typeof i?i(e):{...e,...i}}),[e,i])}function d(i){let e;return e=i.disableParentContext?"function"==typeof i.components?i.components(s):i.components||s:I(i.components),n.createElement(l.Provider,{value:e},i.children)}}}]); \ No newline at end of file diff --git a/assets/js/c00ee666.951c69ba.js b/assets/js/c00ee666.951c69ba.js new file mode 100644 index 000000000..47ad41f4f --- /dev/null +++ b/assets/js/c00ee666.951c69ba.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[906],{3425:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>p,frontMatter:()=>d,metadata:()=>o,toc:()=>l});var r=n(4848),s=n(8453);const d={},i="PreferredStdlibApi",o={id:"detectors/PreferredStdlibApi",title:"PreferredStdlibApi",description:"An optional detector that flags the use of advanced functions from the standard library.",source:"@site/versioned_docs/version-0.3.0/detectors/PreferredStdlibApi.md",sourceDirName:"detectors",slug:"/detectors/PreferredStdlibApi",permalink:"/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/PreferredStdlibApi.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"PreferAugmentedAssign",permalink:"/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign"},next:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables"}},a={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"preferredstdlibapi",children:"PreferredStdlibApi"}),"\n",(0,r.jsx)(t.p,{children:"An optional detector that flags the use of advanced functions from the standard library."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"Auditors should pay extra attention to these functions, as incorrect usage can\nlead to subtle bugs. Safer stdlib alternatives should be preferred in the code."}),"\n",(0,r.jsx)(t.p,{children:"Supported functions:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Use ",(0,r.jsx)(t.code,{children:"send"})," instead of ",(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-advanced#nativesendmessage",children:(0,r.jsx)(t.code,{children:"nativeSendMessage"})})]}),"\n",(0,r.jsxs)(t.li,{children:["Prefer ",(0,r.jsx)(t.code,{children:"randomInt"})," instead of ",(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-advanced#nativerandom",children:(0,r.jsx)(t.code,{children:"nativeRandom"})})]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"let pkg: Slice = msg.transfer;\nlet _seqno: Int = pkg.loadInt(32);\nlet mode: Int = pkg.loadInt(8);\nlet body: Cell = pkg.loadRef();\n// Bad: prefer `send` to avoid low-level manipulation of Slice\nnativeSendMessage(body, mode);\n"})}),"\n",(0,r.jsx)(t.p,{children:"Use instead:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"// Safer: More explicit definition of the send operation\nsend(SendParameters{ value: amount,\n to: self.owner,\n mode: mode,\n body: beginCell().endCell() });\n"})})]})}function p(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var r=n(6540);const s={},d=r.createContext(s);function i(e){const t=r.useContext(d);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(d.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c05c6791.1dfb4d97.js b/assets/js/c05c6791.1dfb4d97.js new file mode 100644 index 000000000..bc92eddad --- /dev/null +++ b/assets/js/c05c6791.1dfb4d97.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8677],{3820:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>p,frontMatter:()=>d,metadata:()=>o,toc:()=>l});var r=n(4848),s=n(8453);const d={},i="PreferredStdlibApi",o={id:"detectors/PreferredStdlibApi",title:"PreferredStdlibApi",description:"An optional detector that flags the use of advanced functions from the standard library.",source:"@site/versioned_docs/version-0.3.1/detectors/PreferredStdlibApi.md",sourceDirName:"detectors",slug:"/detectors/PreferredStdlibApi",permalink:"/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/PreferredStdlibApi.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"PreferAugmentedAssign",permalink:"/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign"},next:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables"}},a={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"preferredstdlibapi",children:"PreferredStdlibApi"}),"\n",(0,r.jsx)(t.p,{children:"An optional detector that flags the use of advanced functions from the standard library."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"Auditors should pay extra attention to these functions, as incorrect usage can\nlead to subtle bugs. Safer stdlib alternatives should be preferred in the code."}),"\n",(0,r.jsx)(t.p,{children:"Supported functions:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Use ",(0,r.jsx)(t.code,{children:"send"})," instead of ",(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-advanced#nativesendmessage",children:(0,r.jsx)(t.code,{children:"nativeSendMessage"})})]}),"\n",(0,r.jsxs)(t.li,{children:["Prefer ",(0,r.jsx)(t.code,{children:"randomInt"})," instead of ",(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-advanced#nativerandom",children:(0,r.jsx)(t.code,{children:"nativeRandom"})})]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"let pkg: Slice = msg.transfer;\nlet _seqno: Int = pkg.loadInt(32);\nlet mode: Int = pkg.loadInt(8);\nlet body: Cell = pkg.loadRef();\n// Bad: prefer `send` to avoid low-level manipulation of Slice\nnativeSendMessage(body, mode);\n"})}),"\n",(0,r.jsx)(t.p,{children:"Use instead:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"// Safer: More explicit definition of the send operation\nsend(SendParameters{ value: amount,\n to: self.owner,\n mode: mode,\n body: beginCell().endCell() });\n"})})]})}function p(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var r=n(6540);const s={},d=r.createContext(s);function i(e){const t=r.useContext(d);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),r.createElement(d.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c252c345.a3cf3637.js b/assets/js/c252c345.a3cf3637.js new file mode 100644 index 000000000..6c56472e9 --- /dev/null +++ b/assets/js/c252c345.a3cf3637.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2798],{3618:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>c});var n=s(4848),i=s(8453);const o={},r="AsmIsUsed",a={id:"detectors/AsmIsUsed",title:"AsmIsUsed",description:"An optional detector that highlights all the asm functions.",source:"@site/versioned_docs/version-0.3.0/detectors/AsmIsUsed.md",sourceDirName:"detectors",slug:"/detectors/AsmIsUsed",permalink:"/tools/misti/docs/0.3.0/detectors/AsmIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/AsmIsUsed.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"ArgCopyMutation",permalink:"/tools/misti/docs/0.3.0/detectors/ArgCopyMutation"},next:{title:"BranchDuplicate",permalink:"/tools/misti/docs/0.3.0/detectors/BranchDuplicate"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"asmisused",children:"AsmIsUsed"}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"asm"})," functions."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Using TVM Assembly is a potentially dangerous operation that requires additional\nattention from an auditor. This optional detector will highlight all its uses to\nassist in contract security audits."}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"// Highlighted: the asm function use should be audited\nasm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE }\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>r,x:()=>a});var n=s(6540);const i={},o=n.createContext(i);function r(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c377a04b.8c30a29b.js b/assets/js/c377a04b.8c30a29b.js new file mode 100644 index 000000000..afe0ac6a0 --- /dev/null +++ b/assets/js/c377a04b.8c30a29b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3361],{8321:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>l});var i=n(4848),s=n(8453);const o={id:"intro",title:"Introduction",slug:"/",sidebar_position:1},r=void 0,a={id:"intro",title:"Introduction",description:"Misti is a static analysis tool designed for smart contracts on the TON blockchain.",source:"@site/docs/index.md",sourceDirName:".",slug:"/",permalink:"/tools/misti/docs/next/",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/index.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{id:"intro",title:"Introduction",slug:"/",sidebar_position:1},sidebar:"sidebar",next:{title:"Getting Started",permalink:"/tools/misti/docs/next/tutorial/getting-started"}},c={},l=[{value:"Use Cases",id:"use-cases",level:2},{value:"Name Origin",id:"name-origin",level:2},{value:"Funding",id:"funding",level:2}];function d(e){const t={a:"a",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Misti is a static analysis tool designed for smart contracts on the ",(0,i.jsx)(t.a,{href:"https://ton.org/",children:"TON blockchain"}),"."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Language Support:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://tact-lang.org/",children:"Tact"})," 1.5 is supported."]}),"\n",(0,i.jsxs)(t.li,{children:["Support for ",(0,i.jsx)(t.a,{href:"https://docs.ton.org/develop/func/overview",children:"FunC"})," ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/56",children:"is planned"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,i.jsx)(t.p,{children:"Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Detect Vulnerabilities:"})," Identify and fix potential security flaws early in the development cycle."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Improve Code Quality:"})," Maintain high standards by catching bugs and enforcing best practices automatically."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Streamline Development:"})," Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Custom Detectors:"})," Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow."}),"\n",(0,i.jsx)(t.h2,{id:"name-origin",children:"Name Origin"}),"\n",(0,i.jsx)(t.p,{children:'The name "Misti" comes from the Misti volcano in Peru. It was chosen because it\'s catchy and easy to remember.'}),"\n",(0,i.jsx)(t.h2,{id:"funding",children:"Funding"}),"\n",(0,i.jsxs)(t.p,{children:["Misti has been funded by the following ",(0,i.jsx)(t.a,{href:"https://ton.foundation",children:"TON Foundation"})," grants:"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/436",children:"TON Static Analyzer \xb7 #436"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/777",children:"Upgrade Misti with Advanced Tact Detectors \xb7 #777"})}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"This support has enabled us to develop and maintain the tool."})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c49af6bd.85a90098.js b/assets/js/c49af6bd.85a90098.js new file mode 100644 index 000000000..70cc8e264 --- /dev/null +++ b/assets/js/c49af6bd.85a90098.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1006],{8765:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>a});var n=s(4848),i=s(8453);const o={},d="dump Is Used",r={id:"detectors/DumpIsUsed",title:"dump Is Used",description:"An optional detector that highlights all the dump function calls.",source:"@site/versioned_docs/version-0.2.1/detectors/DumpIsUsed.md",sourceDirName:"detectors",slug:"/detectors/DumpIsUsed",permalink:"/tools/misti/docs/0.2.1/detectors/DumpIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/DumpIsUsed.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Branch Duplicate",permalink:"/tools/misti/docs/0.2.1/detectors/BranchDuplicate"},next:{title:"Field Initialized Twice",permalink:"/tools/misti/docs/0.2.1/detectors/FieldDoubleInit"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(t.h1,{id:"dump-is-used",children:[(0,n.jsx)(t.code,{children:"dump"})," Is Used"]}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"dump"})," function calls."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"dump"})," function is a debug print that shouldn't be in the final code. Even though the compiler removes it in production, its presence suggests the developer was debugging something. This can flag areas where issues might exist, so auditors should take a closer look at these parts of the code."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = (RANDOM_SEED >> half_shift) &\n (MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;\n dump(combined); // Suspicious: Highlighted by the detector\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = this.seed ^ shift_mask\n // OK: The code was reviewed and simplified; `dump` was removed\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>d,x:()=>r});var n=s(6540);const i={},o=n.createContext(i);function d(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c55f1521.cb9c8e4f.js b/assets/js/c55f1521.cb9c8e4f.js new file mode 100644 index 000000000..b6b1e77bf --- /dev/null +++ b/assets/js/c55f1521.cb9c8e4f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7083],{384:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var s=n(4848),o=n(8453);const r={},d="ConstantAddress",a={id:"detectors/ConstantAddress",title:"ConstantAddress",description:"An optional detector that highlights all the constant addresses appearing in the source code.",source:"@site/versioned_docs/version-0.3.0/detectors/ConstantAddress.md",sourceDirName:"detectors",slug:"/detectors/ConstantAddress",permalink:"/tools/misti/docs/0.3.0/detectors/ConstantAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/ConstantAddress.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"BranchDuplicate",permalink:"/tools/misti/docs/0.3.0/detectors/BranchDuplicate"},next:{title:"DivideBeforeMultiply",permalink:"/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply"}},i={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"constantaddress",children:"ConstantAddress"}),"\n",(0,s.jsx)(t.p,{children:"An optional detector that highlights all the constant addresses appearing in the source code."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsxs)(t.p,{children:["Using hardcoded addresses can sometimes indicate poor contract design.\nSome constant addresses may need to be set dynamically, e.g., using\n",(0,s.jsx)(t.code,{children:"contractAddress"}),", or at least have a way to change them at runtime, for\nexample, when upgrading a contract."]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'contract Main {\n proxy: Address;\n init() {\n // Bad: Constant address highlighted by the analyzer.\n self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");\n }\n}\n'})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"contract Main {\n proxy: Address;\n init() {\n let proxy: Proxy = initOf Proxy(myAddress());\n // OK: Address depends on how the proxy contact has been deployed\n self.proxy = contractAddress(proxy);\n }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>a});var s=n(6540);const o={},r=s.createContext(o);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c5c1850c.d97c4482.js b/assets/js/c5c1850c.d97c4482.js new file mode 100644 index 000000000..3fe12d664 --- /dev/null +++ b/assets/js/c5c1850c.d97c4482.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7837],{2134:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var t=n(4848),s=n(8453);const o={},r="Configuration",l={id:"tutorial/configuration",title:"Configuration",description:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.",source:"@site/versioned_docs/version-0.2.2/tutorial/configuration.md",sourceDirName:"tutorial",slug:"/tutorial/configuration",permalink:"/tools/misti/docs/0.2.2/tutorial/configuration",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/tutorial/configuration.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.2.2/tutorial/ci-cd"},next:{title:"Using with Blueprint",permalink:"/tools/misti/docs/0.2.2/tutorial/blueprint"}},a={},c=[{value:"Configuration Options",id:"configuration-options",level:3},{value:"Running Misti with Configuration",id:"running-misti-with-configuration",level:2},{value:"Default Configuration File",id:"default-configuration-file",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const i={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(i.h1,{id:"configuration",children:"Configuration"}),"\n",(0,t.jsx)(i.p,{children:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set."}),"\n",(0,t.jsx)(i.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"detectors"}),": List of detectors to run. Each detector can be specified with a ",(0,t.jsx)(i.code,{children:"className"})," and optionally a ",(0,t.jsx)(i.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"modulePath"})," (string, optional): The file path of the detector module."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"ignored_projects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"soufflePath"})," (string, optional): Directory to save generated Souffl\xe9 files which is helpful for debugging purposes. If not set, a temporary directory will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"tactStdlibPath"})," (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"unusedPrefix"}),' (string, default: "_"): Identifiers starting with this prefix won\'t be reported as unused by built-in detectors.']}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"verbosity"})," (string, optional): Verbosity level of the logs. Possible values are ",(0,t.jsx)(i.code,{children:"quiet"}),", ",(0,t.jsx)(i.code,{children:"debug"}),", and ",(0,t.jsx)(i.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(i.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,t.jsx)(i.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsx)(i.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,t.jsx)(i.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,t.jsx)(i.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-json",children:'{\n "detectorsEnabled": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n { "className": "BranchDuplicate" },\n { "className": "FieldDoubleInit" },\n { "className": "PreferAugmentedAssign" }\n ],\n "ignoredProjects": [],\n "unusedPrefix": "_",\n "verbosity": "default"\n}\n'})}),"\n",(0,t.jsxs)(i.p,{children:["All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,t.jsxs)(i.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,t.jsx)(i.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --dump-config test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsxs)(i.p,{children:["If there is no Misti config in the ",(0,t.jsx)(i.code,{children:"simple"})," directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors."]}),"\n",(0,t.jsx)(i.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,t.jsxs)(i.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,t.jsx)(i.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function u(e={}){const{wrapper:i}={...(0,s.R)(),...e.components};return i?(0,t.jsx)(i,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>r,x:()=>l});var t=n(6540);const s={},o=t.createContext(s);function r(e){const i=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c5d65102.924539a3.js b/assets/js/c5d65102.924539a3.js new file mode 100644 index 000000000..1137f146f --- /dev/null +++ b/assets/js/c5d65102.924539a3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8221],{415:(e,s,t)=>{t.r(s),t.d(s,{assets:()=>a,contentTitle:()=>d,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>c});var n=t(4848),o=t(8453);const r={},d="Zero Address",i={id:"detectors/ZeroAddress",title:"Zero Address",description:"A detector that identifies uses of the zero address.",source:"@site/versioned_docs/version-0.2.2/detectors/ZeroAddress.md",sourceDirName:"detectors",slug:"/detectors/ZeroAddress",permalink:"/tools/misti/docs/0.2.2/detectors/ZeroAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/ZeroAddress.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Unbound Loops",permalink:"/tools/misti/docs/0.2.2/detectors/UnboundLoops"},next:{title:"Constant Address",permalink:"/tools/misti/docs/0.2.2/detectors/ConstantAddress"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const s={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(s.h1,{id:"zero-address",children:"Zero Address"}),"\n",(0,n.jsx)(s.p,{children:"A detector that identifies uses of the zero address."}),"\n",(0,n.jsx)(s.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(s.p,{children:"Using the zero address in smart contracts is typically problematic because it can be\nexploited as a default or uninitialized address, leading to unintended transfers and\nsecurity vulnerabilities. Additionally, operations involving the zero address can\nresult in loss of funds or tokens, as there is no private key to access this address."}),"\n",(0,n.jsx)(s.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init() {\n // Warning: Insecure usage of zero address as default value\n self.to = newAddress(0, 0);\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})}),"\n",(0,n.jsx)(s.p,{children:"Use instead:"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-tact",children:"contract Proxy {\n to: Address;\n init(to: Address) {\n // Fixed: Using the input value on initializaiton.\n self.to = to;\n }\n fun setAddress(to: Address) {\n self.to = to\n }\n}\n"})})]})}function u(e={}){const{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,s,t)=>{t.d(s,{R:()=>d,x:()=>i});var n=t(6540);const o={},r=n.createContext(o);function d(e){const s=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function i(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),n.createElement(r.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c7ee6afe.0b86ae18.js b/assets/js/c7ee6afe.0b86ae18.js new file mode 100644 index 000000000..b50140d1e --- /dev/null +++ b/assets/js/c7ee6afe.0b86ae18.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5459],{4729:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>l});var i=n(4848),s=n(8453);const o={id:"intro",title:"Introduction",slug:"/",sidebar_position:1},r=void 0,a={id:"intro",title:"Introduction",description:"Misti is a static analysis tool designed for smart contracts on the TON blockchain.",source:"@site/versioned_docs/version-0.4.0/index.md",sourceDirName:".",slug:"/",permalink:"/tools/misti/docs/",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/index.md",tags:[],version:"0.4.0",sidebarPosition:1,frontMatter:{id:"intro",title:"Introduction",slug:"/",sidebar_position:1},sidebar:"sidebar",next:{title:"Getting Started",permalink:"/tools/misti/docs/tutorial/getting-started"}},c={},l=[{value:"Use Cases",id:"use-cases",level:2},{value:"Name Origin",id:"name-origin",level:2},{value:"Funding",id:"funding",level:2}];function d(e){const t={a:"a",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Misti is a static analysis tool designed for smart contracts on the ",(0,i.jsx)(t.a,{href:"https://ton.org/",children:"TON blockchain"}),"."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Language Support:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://tact-lang.org/",children:"Tact"})," 1.5 is supported."]}),"\n",(0,i.jsxs)(t.li,{children:["Support for ",(0,i.jsx)(t.a,{href:"https://docs.ton.org/develop/func/overview",children:"FunC"})," ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/56",children:"is planned"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,i.jsx)(t.p,{children:"Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Detect Vulnerabilities:"})," Identify and fix potential security flaws early in the development cycle."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Improve Code Quality:"})," Maintain high standards by catching bugs and enforcing best practices automatically."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Streamline Development:"})," Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Custom Detectors:"})," Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow."}),"\n",(0,i.jsx)(t.h2,{id:"name-origin",children:"Name Origin"}),"\n",(0,i.jsx)(t.p,{children:'The name "Misti" comes from the Misti volcano in Peru. It was chosen because it\'s catchy and easy to remember.'}),"\n",(0,i.jsx)(t.h2,{id:"funding",children:"Funding"}),"\n",(0,i.jsxs)(t.p,{children:["Misti has been funded by the following ",(0,i.jsx)(t.a,{href:"https://ton.foundation",children:"TON Foundation"})," grants:"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/436",children:"TON Static Analyzer \xb7 #436"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/777",children:"Upgrade Misti with Advanced Tact Detectors \xb7 #777"})}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"This support has enabled us to develop and maintain the tool."})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c82192ae.b860298b.js b/assets/js/c82192ae.b860298b.js new file mode 100644 index 000000000..2ceb8c774 --- /dev/null +++ b/assets/js/c82192ae.b860298b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5321],{4482:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>o,contentTitle:()=>n,default:()=>x,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var d=s(4848),r=s(8453);const i={id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},n="Detectors Overview",c={id:"detectors",title:"Detectors Overview",description:"Misti currently supports 20 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:",source:"@site/versioned_docs/version-0.4.0/detectors.md",sourceDirName:".",slug:"/detectors",permalink:"/tools/misti/docs/detectors",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors.md",tags:[],version:"0.4.0",frontMatter:{id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},sidebar:"sidebar",previous:{title:"Using with Blueprint",permalink:"/tools/misti/docs/tutorial/blueprint"},next:{title:"ArgCopyMutation",permalink:"/tools/misti/docs/detectors/ArgCopyMutation"}},o={},l=[];function h(e){const t={a:"a",code:"code",h1:"h1",p:"p",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,r.R)(),...e.components};return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(t.h1,{id:"detectors-overview",children:"Detectors Overview"}),"\n",(0,d.jsx)(t.p,{children:"Misti currently supports 20 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:"}),"\n",(0,d.jsxs)(t.table,{children:[(0,d.jsx)(t.thead,{children:(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.th,{children:"#"}),(0,d.jsx)(t.th,{children:"Detector"}),(0,d.jsx)(t.th,{children:"Severity"}),(0,d.jsx)(t.th,{children:"Requires Souffl\xe9"}),(0,d.jsx)(t.th,{children:"Enabled by default"})]})}),(0,d.jsxs)(t.tbody,{children:[(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"1"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/ArgCopyMutation",children:"ArgCopyMutation"})}),(0,d.jsx)(t.td,{children:"High"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"2"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/AsmIsUsed",children:"AsmIsUsed"})}),(0,d.jsx)(t.td,{children:"Info"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"3"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/BranchDuplicate",children:"BranchDuplicate"})}),(0,d.jsx)(t.td,{children:"High"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"4"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/ConstantAddress",children:"ConstantAddress"})}),(0,d.jsx)(t.td,{children:"Info"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"5"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/DivideBeforeMultiply",children:"DivideBeforeMultiply"})}),(0,d.jsx)(t.td,{children:"High"}),(0,d.jsx)(t.td,{children:"\u2714"}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"6"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/DumpIsUsed",children:"DumpIsUsed"})}),(0,d.jsx)(t.td,{children:"Info"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"7"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/DuplicatedCondition",children:"DuplicatedCondition"})}),(0,d.jsx)(t.td,{children:"High"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"8"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/EnsurePrgSeed",children:"EnsurePrgSeed"})}),(0,d.jsx)(t.td,{children:"Medium"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"9"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/FalseCondition",children:"FalseCondition"})}),(0,d.jsx)(t.td,{children:"Medium"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"10"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/FieldDoubleInit",children:"FieldDoubleInit"})}),(0,d.jsx)(t.td,{children:"Medium"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"11"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/InheritedStateMutation",children:"InheritedStateMutation"})}),(0,d.jsx)(t.td,{children:"Low"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"12"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/NeverAccessedVariables",children:"NeverAccessedVariables"})}),(0,d.jsx)(t.td,{children:"Medium"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"13"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/OptimalMathFunction",children:"OptimalMathFunction"})}),(0,d.jsx)(t.td,{children:"Low"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"14"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/PreferAugmentedAssign",children:"PreferAugmentedAssign"})}),(0,d.jsx)(t.td,{children:"Info"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"15"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/PreferredStdlibApi",children:"PreferredStdlibApi"})}),(0,d.jsx)(t.td,{children:"Info"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"16"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/ReadOnlyVariables",children:"ReadOnlyVariables"})}),(0,d.jsx)(t.td,{children:"Medium"}),(0,d.jsx)(t.td,{children:"\u2714"}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"17"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/StringReceiversOverlap",children:"StringReceiversOverlap"})}),(0,d.jsx)(t.td,{children:"High"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"18"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/UnboundLoops",children:"UnboundLoops"})}),(0,d.jsx)(t.td,{children:"High"}),(0,d.jsx)(t.td,{children:"\u2714"}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"19"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/UnusedOptional",children:"UnusedOptional"})}),(0,d.jsx)(t.td,{children:"Low"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(0,d.jsxs)(t.tr,{children:[(0,d.jsx)(t.td,{children:"20"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/ZeroAddress",children:"ZeroAddress"})}),(0,d.jsx)(t.td,{children:"Low"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]})]})]}),"\n",(0,d.jsxs)(t.p,{children:["Some of the detectors require ",(0,d.jsx)(t.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})," to be installed. If no Souffl\xe9 installation is found, these detectors won't be executed."]}),"\n",(0,d.jsxs)(t.p,{children:["A few detectors are optional and aimed at auditors to help uncover subtle issues in the source code. To enable all detectors, use the ",(0,d.jsx)(t.code,{children:"--all-detectors"})," option. You can find a full list of configuration options on the ",(0,d.jsx)(t.a,{href:"/tools/misti/docs/tutorial/configuration",children:"configuration page"}),"."]}),"\n",(0,d.jsx)(t.p,{children:"Each detector targets a specific type of problem in your code. Click on the detector name to learn more."})]})}function x(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,d.jsx)(t,{...e,children:(0,d.jsx)(h,{...e})}):h(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>n,x:()=>c});var d=s(6540);const r={},i=d.createContext(r);function n(e){const t=d.useContext(i);return d.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:n(e.components),d.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c926d0d4.30e3ae68.js b/assets/js/c926d0d4.30e3ae68.js new file mode 100644 index 000000000..ce8d109eb --- /dev/null +++ b/assets/js/c926d0d4.30e3ae68.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8771],{3608:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>a,frontMatter:()=>i,metadata:()=>n,toc:()=>l});var r=s(4848),d=s(8453);const i={id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},o="Detectors Overview",n={id:"detectors",title:"Detectors Overview",description:"Misti currently supports 15 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:",source:"@site/versioned_docs/version-0.3.1/detectors.md",sourceDirName:".",slug:"/detectors",permalink:"/tools/misti/docs/0.3.1/detectors",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors.md",tags:[],version:"0.3.1",frontMatter:{id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},sidebar:"sidebar",previous:{title:"Using with Blueprint",permalink:"/tools/misti/docs/0.3.1/tutorial/blueprint"},next:{title:"ArgCopyMutation",permalink:"/tools/misti/docs/0.3.1/detectors/ArgCopyMutation"}},c={},l=[];function h(e){const t={a:"a",code:"code",h1:"h1",p:"p",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,d.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"detectors-overview",children:"Detectors Overview"}),"\n",(0,r.jsx)(t.p,{children:"Misti currently supports 15 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:"}),"\n",(0,r.jsxs)(t.table,{children:[(0,r.jsx)(t.thead,{children:(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.th,{children:"#"}),(0,r.jsx)(t.th,{children:"Detector"}),(0,r.jsx)(t.th,{children:"Requires Souffl\xe9"}),(0,r.jsx)(t.th,{children:"Enabled by default"})]})}),(0,r.jsxs)(t.tbody,{children:[(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"1"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/ArgCopyMutation",children:"ArgCopyMutation"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"2"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/AsmIsUsed",children:"AsmIsUsed"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"3"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/BranchDuplicate",children:"BranchDuplicate"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"4"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/ConstantAddress",children:"ConstantAddress"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"5"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply",children:"DivideBeforeMultiply"})}),(0,r.jsx)(t.td,{children:"\u2714"}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"6"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/DumpIsUsed",children:"DumpIsUsed"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"7"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/FieldDoubleInit",children:"FieldDoubleInit"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"8"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/InheritedStateMutation",children:"InheritedStateMutation"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"9"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables",children:"NeverAccessedVariables"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"10"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign",children:"PreferAugmentedAssign"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"11"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi",children:"PreferredStdlibApi"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"12"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables",children:"ReadOnlyVariables"})}),(0,r.jsx)(t.td,{children:"\u2714"}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"13"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap",children:"StringReceiversOverlap"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"14"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/UnboundLoops",children:"UnboundLoops"})}),(0,r.jsx)(t.td,{children:"\u2714"}),(0,r.jsx)(t.td,{children:"\u2714"})]}),(0,r.jsxs)(t.tr,{children:[(0,r.jsx)(t.td,{children:"15"}),(0,r.jsx)(t.td,{children:(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/detectors/ZeroAddress",children:"ZeroAddress"})}),(0,r.jsx)(t.td,{}),(0,r.jsx)(t.td,{children:"\u2714"})]})]})]}),"\n",(0,r.jsxs)(t.p,{children:["Some of the detectors require ",(0,r.jsx)(t.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})," to be installed. If no Souffl\xe9 installation is found, these detectors won't be executed."]}),"\n",(0,r.jsxs)(t.p,{children:["A few detectors are optional and aimed at auditors to help uncover subtle issues in the source code. To enable all detectors, use the ",(0,r.jsx)(t.code,{children:"--all-detectors"})," option. You can find a full list of configuration options on the ",(0,r.jsx)(t.a,{href:"/tools/misti/docs/0.3.1/tutorial/configuration",children:"configuration page"}),"."]}),"\n",(0,r.jsx)(t.p,{children:"Each detector targets a specific type of problem in your code. Click on the detector name to learn more."})]})}function a(e={}){const{wrapper:t}={...(0,d.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>o,x:()=>n});var r=s(6540);const d={},i=r.createContext(d);function o(e){const t=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function n(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:o(e.components),r.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c96954fa.f94afa3f.js b/assets/js/c96954fa.f94afa3f.js new file mode 100644 index 000000000..99ddb6852 --- /dev/null +++ b/assets/js/c96954fa.f94afa3f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2312],{263:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>a});var n=i(4848),r=i(8453);const o={},s="Divide before Multiply",l={id:"detectors/DivideBeforeMultiply",title:"Divide before Multiply",description:"A detector that identifies and corrects instances of division before multiplication to",source:"@site/versioned_docs/version-0.2.2/detectors/DivideBeforeMultiply.md",sourceDirName:"detectors",slug:"/detectors/DivideBeforeMultiply",permalink:"/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/DivideBeforeMultiply.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.2.2/detectors"},next:{title:"Never-accessed Variables",permalink:"/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function d(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"divide-before-multiply",children:"Divide before Multiply"}),"\n",(0,n.jsx)(t.p,{children:"A detector that identifies and corrects instances of division before multiplication to\nensure accurate mathematical operations."}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers."}),"\n",(0,n.jsx)(t.li,{children:"Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations."}),"\n",(0,n.jsx)(t.li,{children:"Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging."}),"\n"]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Bad: Division before multiplication\nlet result: Int = a / b * c;\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"let a: Int = 10;\nlet b: Int = 3;\nlet c: Int = 2;\n// Correct: Multiplication before division\nlet result: Int = a * c / b;\n"})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>l});var n=i(6540);const r={},o=n.createContext(r);function s(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ca178ca4.7d6ff74e.js b/assets/js/ca178ca4.7d6ff74e.js new file mode 100644 index 000000000..cae8f22d2 --- /dev/null +++ b/assets/js/ca178ca4.7d6ff74e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2195],{5778:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var a=t(4848),i=t(8453);const r={},s="Read-only Variables",o={id:"detectors/ReadOnlyVariables",title:"Read-only Variables",description:"A detector that identifies read-only variables and fields.",source:"@site/versioned_docs/version-0.2.2/detectors/ReadOnlyVariables.md",sourceDirName:"detectors",slug:"/detectors/ReadOnlyVariables",permalink:"/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/ReadOnlyVariables.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Never-accessed Variables",permalink:"/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables"},next:{title:"Unbound Loops",permalink:"/tools/misti/docs/0.2.2/detectors/UnboundLoops"}},l={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.h1,{id:"read-only-variables",children:"Read-only Variables"}),"\n",(0,a.jsx)(n.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,a.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,a.jsx)(n.p,{children:"These variables could typically be replaced with constants to optimize performance.\nAlternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally."}),"\n",(0,a.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-tact",children:"fun calculateFinalPrice(price: Int): Int {\n // Warning: the developer uses a read-only variable that could be a constant\n let DISCOUNT_AMOUNT: Int = 10;\n return price - DISCOUNT_AMOUNT;\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:"Use instead:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-tact",children:"const DISCOUNT_AMOUNT: Int = 10;\n\nfun calculateFinalPrice(price: Int): Int {\n // OK: Fixed after the linter highlighted this warning\n return price - DISCOUNT_AMOUNT;\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>o});var a=t(6540);const i={},r=a.createContext(i);function s(e){const n=a.useContext(r);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),a.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/cb77e040.4c34ff27.js b/assets/js/cb77e040.4c34ff27.js new file mode 100644 index 000000000..a011a8942 --- /dev/null +++ b/assets/js/cb77e040.4c34ff27.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6757],{4318:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>p,frontMatter:()=>s,metadata:()=>o,toc:()=>l});var r=n(4848),d=n(8453);const s={},i="PreferredStdlibApi",o={id:"detectors/PreferredStdlibApi",title:"PreferredStdlibApi",description:"An optional detector that flags the use of advanced functions from the standard library.",source:"@site/docs/detectors/PreferredStdlibApi.md",sourceDirName:"detectors",slug:"/detectors/PreferredStdlibApi",permalink:"/tools/misti/docs/next/detectors/PreferredStdlibApi",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/PreferredStdlibApi.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"PreferAugmentedAssign",permalink:"/tools/misti/docs/next/detectors/PreferAugmentedAssign"},next:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/next/detectors/ReadOnlyVariables"}},a={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,d.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"preferredstdlibapi",children:"PreferredStdlibApi"}),"\n",(0,r.jsx)(t.p,{children:"An optional detector that flags the use of advanced functions from the standard library."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"Auditors should pay extra attention to these functions, as incorrect usage can\nlead to subtle bugs. Safer stdlib alternatives should be preferred in the code."}),"\n",(0,r.jsx)(t.p,{children:"Supported functions:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Use ",(0,r.jsx)(t.code,{children:"send"})," instead of ",(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-advanced#nativesendmessage",children:(0,r.jsx)(t.code,{children:"nativeSendMessage"})})]}),"\n",(0,r.jsxs)(t.li,{children:["Prefer ",(0,r.jsx)(t.code,{children:"randomInt"})," instead of ",(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-advanced#nativerandom",children:(0,r.jsx)(t.code,{children:"nativeRandom"})})]}),"\n"]}),"\n",(0,r.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"let pkg: Slice = msg.transfer;\nlet _seqno: Int = pkg.loadInt(32);\nlet mode: Int = pkg.loadInt(8);\nlet body: Cell = pkg.loadRef();\n// Bad: prefer `send` to avoid low-level manipulation of Slice\nnativeSendMessage(body, mode);\n"})}),"\n",(0,r.jsx)(t.p,{children:"Use instead:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"// Safer: More explicit definition of the send operation\nsend(SendParameters{ value: amount,\n to: self.owner,\n mode: mode,\n body: beginCell().endCell() });\n"})})]})}function p(e={}){const{wrapper:t}={...(0,d.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var r=n(6540);const d={},s=r.createContext(d);function i(e){const t=r.useContext(s);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:i(e.components),r.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/cc6d1ce2.2f552c48.js b/assets/js/cc6d1ce2.2f552c48.js new file mode 100644 index 000000000..d8856b268 --- /dev/null +++ b/assets/js/cc6d1ce2.2f552c48.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3750],{433:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=n(4848),o=n(8453);const i={},a="ArgCopyMutation",r={id:"detectors/ArgCopyMutation",title:"ArgCopyMutation",description:"A detector that highlights cases where function argument mutations are ineffective",source:"@site/versioned_docs/version-0.3.0/detectors/ArgCopyMutation.md",sourceDirName:"detectors",slug:"/detectors/ArgCopyMutation",permalink:"/tools/misti/docs/0.3.0/detectors/ArgCopyMutation",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/ArgCopyMutation.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.3.0/detectors"},next:{title:"AsmIsUsed",permalink:"/tools/misti/docs/0.3.0/detectors/AsmIsUsed"}},c={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function d(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"argcopymutation",children:"ArgCopyMutation"}),"\n",(0,s.jsx)(t.p,{children:"A detector that highlights cases where function argument mutations are ineffective\ndue to call-by-value semantics in Tact."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"In Tact, function arguments are passed by value, meaning that any mutations applied\nto these arguments will only affect the local copy of the variable within the function.\nSuch mutations are unobservable outside the function, except for potentially\nincreasing gas consumption or causing exceptions."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"fun addEntry(m: map<Int,Int>) {\n m.set(1, 10); // Bad: Mutating the copy\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"fun addEntry() {\n self.m.set(1, 10); // OK: Changing contract's state\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Alternatively, you could redesign the method:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"fun generateNewValue(): Int {\n // ... produce new value for the map\n return self.nextValue + 1;\n}\n\nm.set(self.nextKey, self.generateNewValue()); // OK\n"})})]})}function u(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var s=n(6540);const o={},i=s.createContext(o);function a(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/cd411a47.dbdd6a6b.js b/assets/js/cd411a47.dbdd6a6b.js new file mode 100644 index 000000000..b8583a558 --- /dev/null +++ b/assets/js/cd411a47.dbdd6a6b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4442],{4802:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>f});var t=i(4848),r=i(8453);const s={},a="Souffl\xe9 Integration Guide",o={id:"hacking/souffle",title:"Souffl\xe9 Integration Guide",description:"What is Souffl\xe9?",source:"@site/versioned_docs/version-0.1.2/hacking/souffle.md",sourceDirName:"hacking",slug:"/hacking/souffle",permalink:"/tools/misti/docs/0.1.2/hacking/souffle",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/hacking/souffle.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Design Overview",permalink:"/tools/misti/docs/0.1.2/hacking/design"},next:{title:"Tools",permalink:"/tools/misti/docs/0.1.2/hacking/tools"}},l={},f=[{value:"What is Souffl\xe9?",id:"what-is-souffl\xe9",level:2},{value:"Benefits of Using Souffl\xe9 for Static Analysis",id:"benefits-of-using-souffl\xe9-for-static-analysis",level:2},{value:"Souffl\xe9 Integration in Misti",id:"souffl\xe9-integration-in-misti",level:2},{value:"Creating Souffl\xe9 Programs",id:"creating-souffl\xe9-programs",level:3},{value:"Generating Facts and Executing Souffl\xe9",id:"generating-facts-and-executing-souffl\xe9",level:3},{value:"Learning from Existing Code",id:"learning-from-existing-code",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"souffl\xe9-integration-guide",children:"Souffl\xe9 Integration Guide"}),"\n",(0,t.jsx)(n.h2,{id:"what-is-souffl\xe9",children:"What is Souffl\xe9?"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io",children:"Souffl\xe9"})," is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Souffl\xe9, Misti can perform deep and scalable analyses of smart contracts."]}),"\n",(0,t.jsx)(n.h2,{id:"benefits-of-using-souffl\xe9-for-static-analysis",children:"Benefits of Using Souffl\xe9 for Static Analysis"}),"\n",(0,t.jsx)(n.p,{children:"Souffl\xe9 allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Souffl\xe9 program might be more straightforward then implementing a complex transfer function in for a classic monotone framework."}),"\n",(0,t.jsx)(n.h2,{id:"souffl\xe9-integration-in-misti",children:"Souffl\xe9 Integration in Misti"}),"\n",(0,t.jsxs)(n.p,{children:["The API for interacting with Souffl\xe9 in Misti is detailed ",(0,t.jsx)(n.a,{href:"https://nowarp.github.io/docs/misti/api/modules/internals_souffle.html",children:"here"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"creating-souffl\xe9-programs",children:"Creating Souffl\xe9 Programs"}),"\n",(0,t.jsx)(n.p,{children:'To create a Souffl\xe9 program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:'}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addDecls(ctx: Context<SrcInfo>) {\n ctx.add(\n Relation.from(\n "varDecl",\n [\n ["var", FactType.Symbol],\n ["func", FactType.Symbol],\n ],\n undefined,\n ),\n );\n // other declarations\n}\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addRules(ctx: Context<SrcInfo>) {\n // readOnly(var, func) :-\n // varDecl(var, func),\n // !varAssign(var, func),\n // !varUse(var, func).\n ctx.add(\n Rule.from(\n [makeAtom("readOnly", ["var", "func"])],\n makeRuleBody(makeAtom("varDecl", ["var", "func"])),\n makeRuleBody(makeAtom("varAssign", ["var", "func"]), {\n negated: true,\n }),\n makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),\n ),\n );\n }\n'})}),"\n",(0,t.jsx)(n.h3,{id:"generating-facts-and-executing-souffl\xe9",children:"Generating Facts and Executing Souffl\xe9"}),"\n",(0,t.jsx)(n.p,{children:"After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Souffl\xe9 executor to run the analysis:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"const executor = ctx.config.soufflePath\n ? new Executor<SrcInfo>({\n inputDir: ctx.config.soufflePath,\n outputDir: ctx.config.soufflePath,\n })\n : new Executor<SrcInfo>();\n\nconst result = executor.executeSync(program);\n\nif (!result.success) {\n throw new Error(\n `Error executing Souffl\xe9 for ${this.id}:\\n${result.stderr}`,\n );\n}\n\nconst warnings = Array.from(result.results.entries.values()).map((fact) => {\n // raise warnings\n});\n"})}),"\n",(0,t.jsx)(n.h3,{id:"learning-from-existing-code",children:"Learning from Existing Code"}),"\n",(0,t.jsx)(n.p,{children:"We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Souffl\xe9 with Misti. This will help you understand the intricacies of generating IR and executing Souffl\xe9 programs effectively."}),"\n",(0,t.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,t.jsxs)(n.p,{children:["For a deeper understanding of static analysis using Souffl\xe9, refer to the textbook ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.a,{href:"https://arxiv.org/pdf/2012.10086",children:"Program Analysis: An Appetizer"})})," by Flemming Nielson and Hanne Riis Nielson. It discusses Souffl\xe9-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field."]})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>a,x:()=>o});var t=i(6540);const r={},s=t.createContext(r);function a(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ce7f72c2.19df7abf.js b/assets/js/ce7f72c2.19df7abf.js new file mode 100644 index 000000000..f2d1a26aa --- /dev/null +++ b/assets/js/ce7f72c2.19df7abf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5200],{4795:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var t=i(4848),s=i(8453);const o={},r="Contributing Guide",a={id:"hacking/contributing",title:"Contributing Guide",description:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.",source:"@site/versioned_docs/version-0.3.1/hacking/contributing.md",sourceDirName:"hacking",slug:"/hacking/contributing",permalink:"/tools/misti/docs/0.3.1/hacking/contributing",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/hacking/contributing.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"ZeroAddress",permalink:"/tools/misti/docs/0.3.1/detectors/ZeroAddress"},next:{title:"Design Overview",permalink:"/tools/misti/docs/0.3.1/hacking/design"}},c={},d=[{value:"Issues reporting",id:"issues-reporting",level:2},{value:"Documentation contribution",id:"documentation-contribution",level:2},{value:"Code contribution",id:"code-contribution",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"contributing-guide",children:"Contributing Guide"}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better."}),"\n",(0,t.jsx)(n.h2,{id:"issues-reporting",children:"Issues reporting"}),"\n",(0,t.jsx)(n.p,{children:"When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.\nPlease help us by publishing it and the input sources at:\nhttps://github.com/nowarp/misti/issues/new.\n"})}),"\n",(0,t.jsx)(n.p,{children:"We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users."}),"\n",(0,t.jsx)(n.h2,{id:"documentation-contribution",children:"Documentation contribution"}),"\n",(0,t.jsxs)(n.p,{children:["We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/nowarp.github.io/issues",children:"nowarp.github.io Issues"}),". Additionally, many documentation pages have an ",(0,t.jsx)(n.code,{children:"Edit"})," button that allows you to make direct contributions easily."]}),"\n",(0,t.jsx)(n.h2,{id:"code-contribution",children:"Code contribution"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Navigate Issues and Find Tasks"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Browse the issues ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"here"}),". Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues."]}),"\n",(0,t.jsx)(n.li,{children:"Choose an issue suitable for you and mention in the issue that you're working on it."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Implement Your Changes"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Implement your changes. Feel free to ask questions in the issue if needed."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Ensure Tests Pass"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Before creating a PR, make sure all tests and CI checks are passing by running:","\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn test-all\n"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Create a PR"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Submit your pull request ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/pulls",children:"here"})]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Add a CHANGELOG entry"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Describe your changes in the ",(0,t.jsx)(n.code,{children:"CHANGELOG.md"})," file according to the existing structure."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/HACKING.md",children:"HACKING.md"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your contributions!"})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>a});var t=i(6540);const s={},o=t.createContext(s);function r(e){const n=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/cf2c24d9.167088de.js b/assets/js/cf2c24d9.167088de.js new file mode 100644 index 000000000..3af88a2eb --- /dev/null +++ b/assets/js/cf2c24d9.167088de.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[338],{9:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var o=t(4848),s=t(8453);const i={},r="UnboundLoops",a={id:"detectors/UnboundLoops",title:"UnboundLoops",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/versioned_docs/version-0.4.0/detectors/UnboundLoops.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoops",permalink:"/tools/misti/docs/detectors/UnboundLoops",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/UnboundLoops.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/detectors/StringReceiversOverlap"},next:{title:"UnusedOptional",permalink:"/tools/misti/docs/detectors/UnusedOptional"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"unboundloops",children:"UnboundLoops"}),"\n",(0,o.jsx)(n.p,{children:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria."}),"\n",(0,o.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsx)(n.p,{children:"An unbounded loop can be problematic for several reasons:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Unexpected Behavior:"})," Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Out-of-gas Attacks:"})," Continuous looping without termination can lead to out-of-gas attacks."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"DoS Attacks:"})," Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability."]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n // Bad: x is not changed due looping\n send(SendParameters{ to: sender(), ... });\n}\n"})}),"\n",(0,o.jsx)(n.p,{children:"Use instead:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-tact",children:"let x: Int = 10;\nwhile (x > 0) {\n send(SendParameters{ to: sender(), ... });\n x = x - 1;\n}\n"})})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var o=t(6540);const s={},i=o.createContext(s);function r(e){const n=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/cf5f971a.651efe6f.js b/assets/js/cf5f971a.651efe6f.js new file mode 100644 index 000000000..c83dcc8e5 --- /dev/null +++ b/assets/js/cf5f971a.651efe6f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7003],{1963:(i,e,t)=>{t.r(e),t.d(e,{assets:()=>o,contentTitle:()=>I,default:()=>c,frontMatter:()=>l,metadata:()=>d,toc:()=>g});var n=t(4848),s=t(8453);const l={},I="Tools Guide",d={id:"hacking/tools",title:"Tools Guide",description:"This page describes the internal analyzer tools available in Misti to aid in development and debugging.",source:"@site/versioned_docs/version-0.1.2/hacking/tools.md",sourceDirName:"hacking",slug:"/hacking/tools",permalink:"/tools/misti/docs/0.1.2/hacking/tools",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/hacking/tools.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.1.2/hacking/souffle"},next:{title:"Custom Detectors",permalink:"/tools/misti/docs/0.1.2/hacking/custom-detector"}},o={},g=[{value:"CFG Dump",id:"cfg-dump",level:2},{value:"Usage",id:"usage",level:3},{value:"Converting DOT to SVG",id:"converting-dot-to-svg",level:3},{value:"Viewing the SVG",id:"viewing-the-svg",level:3},{value:"VS Code Plugin",id:"vs-code-plugin",level:3},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function a(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"tools-guide",children:"Tools Guide"}),"\n",(0,n.jsx)(e.p,{children:"This page describes the internal analyzer tools available in Misti to aid in development and debugging."}),"\n",(0,n.jsx)(e.h2,{id:"cfg-dump",children:"CFG Dump"}),"\n",(0,n.jsx)(e.p,{children:"Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts."}),"\n",(0,n.jsx)(e.h3,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in JSON format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in DOT format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.h3,{id:"converting-dot-to-svg",children:"Converting DOT to SVG"}),"\n",(0,n.jsxs)(e.p,{children:["To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use ",(0,n.jsx)(e.a,{href:"https://graphviz.org",children:"Graphviz"})," with the following command:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot\ndot -Tsvg output.dot -o output.svg\n'})}),"\n",(0,n.jsx)(e.h3,{id:"viewing-the-svg",children:"Viewing the SVG"}),"\n",(0,n.jsx)(e.p,{children:"To view the SVG file in Firefox, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"firefox output.svg\n"})}),"\n",(0,n.jsx)(e.p,{children:"For example, for the following contract:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{children:"fun test(): Int {\n let sum: Int = 0;\n let i: Int = 0;\n repeat (10) {\n i = i + 1;\n sum = sum + i;\n }\n return sum;\n}\n"})}),"\n",(0,n.jsx)(e.p,{children:"The following CFG will be generated:"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"CFG Example",src:t(685).A+"",width:"337",height:"516"})}),"\n",(0,n.jsx)(e.h3,{id:"vs-code-plugin",children:"VS Code Plugin"}),"\n",(0,n.jsxs)(e.p,{children:["For real-time visualization of DOT files, you can use ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/search?term=tag%3Agraphviz&target=VSCode&category=All%20categories&sortBy=Relevance",children:"one of the available"})," Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development."]}),"\n",(0,n.jsx)(e.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"JSON Dumps"}),": These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"DOT Dumps"}),": These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(e.p,{children:"By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors."})]})}function c(i={}){const{wrapper:e}={...(0,s.R)(),...i.components};return e?(0,n.jsx)(e,{...i,children:(0,n.jsx)(a,{...i})}):a(i)}},685:(i,e,t)=>{t.d(e,{A:()=>n});const n="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDIuNCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBsb29wcyYjNDU7MyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjUzcHQiIGhlaWdodD0iMzg3cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjUzLjAwIDM4Ny4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzODMpIj4KPHRpdGxlPmxvb3BzJiM0NTszPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzgzIDI0OSwtMzgzIDI0OSw0IC00LDQiLz4KPGcgaWQ9ImNsdXN0MSIgY2xhc3M9ImNsdXN0ZXIiPgo8dGl0bGU+Y2x1c3Rlcl90ZXN0PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI4LC04IDgsLTM3MSAyMzcsLTM3MSAyMzcsLTggOCwtOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIuNSIgeT0iLTM1NS44IiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnRlc3Q8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0MSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT50ZXN0XzE0MTwvdGl0bGU+Cjxwb2x5Z29uIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjI0LjUsLTM0MCA5NS41LC0zNDAgOTUuNSwtMzA0IDIyNC41LC0zMDQgMjI0LjUsLTM0MCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNjAiIHk9Ii0zMTguMyIgZm9udC1mYW1pbHk9IlRpbWVzLHNlcmlmIiBmb250LXNpemU9IjE0LjAwIj5sZXQgc3VtOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDI8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMiwtMjY4IDEwOCwtMjY4IDEwOCwtMjMyIDIxMiwtMjMyIDIxMiwtMjY4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTI0Ni4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPmxldCBpOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDEmIzQ1OyZndDt0ZXN0XzE0MiAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MSYjNDU7Jmd0O3Rlc3RfMTQyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMzAzLjdDMTYwLC0yOTUuOTggMTYwLC0yODYuNzEgMTYwLC0yNzguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTI3OC4xIDE2MCwtMjY4LjEgMTU2LjUsLTI3OC4xIDE2My41LC0yNzguMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDQ8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOCwtMTk2IDExMiwtMTk2IDExMiwtMTYwIDIwOCwtMTYwIDIwOCwtMTk2Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTE3NC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnJlcGVhdCAoMTApPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDImIzQ1OyZndDt0ZXN0XzE0NCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MiYjNDU7Jmd0O3Rlc3RfMTQ0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMjMxLjdDMTYwLC0yMjMuOTggMTYwLC0yMTQuNzEgMTYwLC0yMDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTIwNi4xIDE2MCwtMTk2LjEgMTU2LjUsLTIwNi4xIDE2My41LC0yMDYuMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDYgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDY8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjkzLjUsLTEyNCAxNi41LC0xMjQgMTYuNSwtODggOTMuNSwtODggOTMuNSwtMTI0Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjU1IiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+aSA9IGkgKyAxPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE0NiAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0NCYjNDU7Jmd0O3Rlc3RfMTQ2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEzNC4zMSwtMTU5Ljg4QzEyMC43MSwtMTUwLjgxIDEwMy44MywtMTM5LjU1IDg5LjE0LC0xMjkuNzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iOTEuMDUsLTEyNi44MiA4MC43OCwtMTI0LjE5IDg3LjE2LC0xMzIuNjUgOTEuMDUsLTEyNi44MiIvPgo8L2c+CjwhLS0gdGVzdF8xNTEgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNTE8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjNjZhN2RiIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOC41LC0xMjQgMTExLjUsLTEyNCAxMTEuNSwtODggMjA4LjUsLTg4IDIwOC41LC0xMjQiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTYwIiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+cmV0dXJuIHN1bTwvdGV4dD4KPC9nPgo8IS0tIHRlc3RfMTQ0JiM0NTsmZ3Q7dGVzdF8xNTEgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE1MTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNjAsLTE1OS43QzE2MCwtMTUxLjk4IDE2MCwtMTQyLjcxIDE2MCwtMTM0LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2My41LC0xMzQuMSAxNjAsLTEyNC4xIDE1Ni41LC0xMzQuMSAxNjMuNSwtMTM0LjEiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPnRlc3RfMTQ4PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxODMuNSwtNTIgNjAuNSwtNTIgNjAuNSwtMTYgMTgzLjUsLTE2IDE4My41LC01MiIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIiIHk9Ii0zMC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnN1bSA9IHN1bSArIGk8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0NiYjNDU7Jmd0O3Rlc3RfMTQ4IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPnRlc3RfMTQ2JiM0NTsmZ3Q7dGVzdF8xNDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuNTYsLTg3LjdDNzkuNjgsLTc5LjIyIDg5LjU5LC02OC44NiA5OC40NywtNTkuNTgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAxLjI0LC02MS43NSAxMDUuNjMsLTUyLjEgOTYuMTksLTU2LjkxIDEwMS4yNCwtNjEuNzUiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4JiM0NTsmZ3Q7dGVzdF8xNDQgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDgmIzQ1OyZndDt0ZXN0XzE0NDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzUuMjIsLTUyLjA0QzE5MS44OSwtNjAuMTYgMjA4LjQyLC03MS43NyAyMTgsLTg4IDIyNi4xMywtMTAxLjc4IDIyNC40NSwtMTA5LjM2IDIxOCwtMTI0IDIxMy4wMSwtMTM1LjMxIDIwNC4yOSwtMTQ1LjI2IDE5NS4xLC0xNTMuMzgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTkyLjgzLC0xNTAuNzIgMTg3LjM0LC0xNTkuNzcgMTk3LjI4LC0xNTYuMTIgMTkyLjgzLC0xNTAuNzIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8453:(i,e,t)=>{t.d(e,{R:()=>I,x:()=>d});var n=t(6540);const s={},l=n.createContext(s);function I(i){const e=n.useContext(l);return n.useMemo((function(){return"function"==typeof i?i(e):{...e,...i}}),[e,i])}function d(i){let e;return e=i.disableParentContext?"function"==typeof i.components?i.components(s):i.components||s:I(i.components),n.createElement(l.Provider,{value:e},i.children)}}}]); \ No newline at end of file diff --git a/assets/js/d147047e.c3db349f.js b/assets/js/d147047e.c3db349f.js new file mode 100644 index 000000000..25d074cb9 --- /dev/null +++ b/assets/js/d147047e.c3db349f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7965],{2643:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var i=n(4848),a=n(8453);const r={},s="InheritedStateMutation",o={id:"detectors/InheritedStateMutation",title:"InheritedStateMutation",description:"An optional detector that highlights all instances where inherited trait variables",source:"@site/versioned_docs/version-0.3.1/detectors/InheritedStateMutation.md",sourceDirName:"detectors",slug:"/detectors/InheritedStateMutation",permalink:"/tools/misti/docs/0.3.1/detectors/InheritedStateMutation",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/detectors/InheritedStateMutation.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"FieldDoubleInit",permalink:"/tools/misti/docs/0.3.1/detectors/FieldDoubleInit"},next:{title:"NeverAccessedVariables",permalink:"/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"inheritedstatemutation",children:"InheritedStateMutation"}),"\n",(0,i.jsx)(t.p,{children:"An optional detector that highlights all instances where inherited trait variables\nare directly modified."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsxs)(t.p,{children:["Traits should provide setter methods to ensure that invariants related to their\nstate are preserved. Directly modifying trait variables (e.g., ",(0,i.jsx)(t.code,{children:"self.traitVar = 42"}),")\ncan violate these invariants, leading to potential bugs or security vulnerabilities.\nThis detector warns when such direct modifications occur, prompting further review\nby auditors."]}),"\n",(0,i.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"trait T {\n balance: Int;\n}\n\ncontract C with T {\n balance: Int = 42;\n fun updateBalance() {\n self.balance = 100; // Suspicious: Highlighted by the detector\n }\n}\n"})}),"\n",(0,i.jsx)(t.p,{children:"Use instead:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:'trait T {\n balance: Int;\n fun setBalance(newBalance: Int) {\n require(newBalance > 0, "balance cannot be negative"); // Invariant check\n self.balance = newBalance;\n }\n}\n\ncontract C with T {\n balance: Int = 42;\n fun updateBalance() {\n self.setBalance(100); // OK: Invariant preserved\n }\n}\n'})})]})}function h(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>o});var i=n(6540);const a={},r=i.createContext(a);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d15cc687.df08049f.js b/assets/js/d15cc687.df08049f.js new file mode 100644 index 000000000..3df3a99d9 --- /dev/null +++ b/assets/js/d15cc687.df08049f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6406],{7033:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>p,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),i=n(8453);const r={},c="Branch Duplicate",o={id:"detectors/BranchDuplicate",title:"Branch Duplicate",description:"Detector that reports duplicated code in conditional branches.",source:"@site/versioned_docs/version-0.2.1/detectors/BranchDuplicate.md",sourceDirName:"detectors",slug:"/detectors/BranchDuplicate",permalink:"/tools/misti/docs/0.2.1/detectors/BranchDuplicate",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/BranchDuplicate.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Constant Address",permalink:"/tools/misti/docs/0.2.1/detectors/ConstantAddress"},next:{title:"`dump` Is Used",permalink:"/tools/misti/docs/0.2.1/detectors/DumpIsUsed"}},a={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"branch-duplicate",children:"Branch Duplicate"}),"\n",(0,s.jsx)(t.p,{children:"Detector that reports duplicated code in conditional branches."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Duplicated code in branches is bad because it:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Reduces Readability"}),": Repetition makes the code harder to understand."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Increases Maintenance"}),": Changes must be made in multiple places, risking errors."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Signals Poor Design"}),": It suggests missed opportunities for cleaner, more abstract code."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = 43; // bad: duplicated code\n} else {\n a = 43;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = inc(b); // ok\n} else {\n a = 43;\n}\n"})})]})}function p(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>o});var s=n(6540);const i={},r=s.createContext(i);function c(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:c(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d1781038.35abe5aa.js b/assets/js/d1781038.35abe5aa.js new file mode 100644 index 000000000..2e049a1f4 --- /dev/null +++ b/assets/js/d1781038.35abe5aa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6633],{5e3:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var i=n(4848),s=n(8453);const o={id:"intro",title:"Introduction",slug:"/",sidebar_position:1},r=void 0,a={id:"intro",title:"Introduction",description:"Misti is a static analysis tool designed for smart contracts on the TON blockchain.",source:"@site/versioned_docs/version-0.2.1/index.md",sourceDirName:".",slug:"/",permalink:"/tools/misti/docs/0.2.1/",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/index.md",tags:[],version:"0.2.1",sidebarPosition:1,frontMatter:{id:"intro",title:"Introduction",slug:"/",sidebar_position:1},sidebar:"sidebar",next:{title:"Getting Started",permalink:"/tools/misti/docs/0.2.1/tutorial/getting-started"}},c={},d=[{value:"Use Cases",id:"use-cases",level:2},{value:"Funding",id:"funding",level:2}];function l(e){const t={a:"a",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Misti is a static analysis tool designed for smart contracts on the ",(0,i.jsx)(t.a,{href:"https://ton.org/",children:"TON blockchain"}),"."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Language Support:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://tact-lang.org/",children:"Tact"})," 1.4.4 is supported."]}),"\n",(0,i.jsxs)(t.li,{children:["Support for ",(0,i.jsx)(t.a,{href:"https://docs.ton.org/develop/func/overview",children:"FunC"})," ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/56",children:"is planned"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,i.jsx)(t.p,{children:"Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Detect Vulnerabilities:"})," Identify and fix potential security flaws early in the development cycle."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Improve Code Quality:"})," Maintain high standards by catching bugs and enforcing best practices automatically."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Streamline Development:"})," Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Custom Detectors:"})," Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow."}),"\n",(0,i.jsx)(t.h2,{id:"funding",children:"Funding"}),"\n",(0,i.jsxs)(t.p,{children:["Misti has been ",(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/436",children:"funded"})," by ",(0,i.jsx)(t.a,{href:"https://ton.foundation",children:"TON Foundation"}),". This support has enabled us to develop and maintain the tool."]})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d2aaf676.0ddaefea.js b/assets/js/d2aaf676.0ddaefea.js new file mode 100644 index 000000000..2a2bc2e98 --- /dev/null +++ b/assets/js/d2aaf676.0ddaefea.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4040],{9323:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),a=n(8453);const r={},i="NeverAccessedVariables",o={id:"detectors/NeverAccessedVariables",title:"NeverAccessedVariables",description:"A detector that identifies write-only or unused variables, fields and constants.",source:"@site/docs/detectors/NeverAccessedVariables.md",sourceDirName:"detectors",slug:"/detectors/NeverAccessedVariables",permalink:"/tools/misti/docs/next/detectors/NeverAccessedVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/NeverAccessedVariables.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"InheritedStateMutation",permalink:"/tools/misti/docs/next/detectors/InheritedStateMutation"},next:{title:"OptimalMathFunction",permalink:"/tools/misti/docs/next/detectors/OptimalMathFunction"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"neveraccessedvariables",children:"NeverAccessedVariables"}),"\n",(0,s.jsx)(t.p,{children:"A detector that identifies write-only or unused variables, fields and constants."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"These variables are either assigned but never used in any meaningful computation,\nor they are declared and never used at all, which may indicate redundant code\nor an incomplete implementation of the intended logic."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"// Error: the developer forgot to use the constant\nconst MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'const MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n // OK: Fixed after the analyzer highlighted this warning\n require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(6540);const a={},r=s.createContext(a);function i(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d2d53d04.404d4960.js b/assets/js/d2d53d04.404d4960.js new file mode 100644 index 000000000..552cc4375 --- /dev/null +++ b/assets/js/d2d53d04.404d4960.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2537],{8023:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>l,contentTitle:()=>o,default:()=>d,frontMatter:()=>s,metadata:()=>c,toc:()=>a});var i=n(4848),r=n(8453);const s={},o="Using Misti with Blueprint",c={id:"tutorial/blueprint",title:"Using Misti with Blueprint",description:"Blueprint is a development environment for writing, testing, and deploying TON smart contracts.",source:"@site/versioned_docs/version-0.2.2/tutorial/blueprint.md",sourceDirName:"tutorial",slug:"/tutorial/blueprint",permalink:"/tools/misti/docs/0.2.2/tutorial/blueprint",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/tutorial/blueprint.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/tools/misti/docs/0.2.2/tutorial/configuration"},next:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.2.2/detectors"}},l={},a=[{value:"Getting started",id:"getting-started",level:2},{value:"Resources",id:"resources",level:2}];function u(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"using-misti-with-blueprint",children:"Using Misti with Blueprint"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:"https://github.com/ton-org/blueprint",children:"Blueprint"})," is a development environment for writing, testing, and deploying TON smart contracts."]}),"\n",(0,i.jsxs)(e.p,{children:["Misti can be used in Blueprint projects by leveraging the ",(0,i.jsx)(e.a,{href:"https://github.com/nowarp/blueprint-misti",children:(0,i.jsx)(e.code,{children:"blueprint-misti"})})," plugin."]}),"\n",(0,i.jsx)(e.h2,{id:"getting-started",children:"Getting started"}),"\n",(0,i.jsxs)(e.p,{children:["Add the plugin and the recent version of Tact to the ",(0,i.jsx)(e.code,{children:"package.json"})," of your Blueprint project by running:"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn add @tact-lang/compiler\nyarn add @nowarp/blueprint-misti\n"})}),"\n",(0,i.jsxs)(e.p,{children:["Then, add this configuration to ",(0,i.jsx)(e.code,{children:"blueprint.config.ts"}),":"]}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-ts",children:"import { MistiPlugin } from '@nowarp/blueprint-misti';\nexport const config = {\n plugins: [\n new MistiPlugin(),\n ],\n};\n"})}),"\n",(0,i.jsx)(e.p,{children:"Now, try to run Misti:"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-bash",children:"yarn blueprint misti ./path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(e.h2,{id:"resources",children:"Resources"}),"\n",(0,i.jsxs)(e.p,{children:["For more information, please refer to the README of the ",(0,i.jsx)(e.a,{href:"https://github.com/nowarp/blueprint-misti",children:(0,i.jsx)(e.code,{children:"blueprint-misti"})})," project. If you have any problems, feel free to reach out to us in the ",(0,i.jsx)(e.a,{href:"https://t.me/misti_dev",children:"Misti discussion group"}),"."]})]})}function d(t={}){const{wrapper:e}={...(0,r.R)(),...t.components};return e?(0,i.jsx)(e,{...t,children:(0,i.jsx)(u,{...t})}):u(t)}},8453:(t,e,n)=>{n.d(e,{R:()=>o,x:()=>c});var i=n(6540);const r={},s=i.createContext(r);function o(t){const e=i.useContext(s);return i.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function c(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(r):t.components||r:o(t.components),i.createElement(s.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/d2f295f4.6d5ee62f.js b/assets/js/d2f295f4.6d5ee62f.js new file mode 100644 index 000000000..929d3ab7d --- /dev/null +++ b/assets/js/d2f295f4.6d5ee62f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7242],{5077:(i,e,t)=>{t.r(e),t.d(e,{assets:()=>o,contentTitle:()=>d,default:()=>g,frontMatter:()=>l,metadata:()=>a,toc:()=>r});var n=t(4848),s=t(8453);const l={},d="DumpCfg",a={id:"tools/DumpCfg",title:"DumpCfg",description:"Misti provides a feature to dump the Control Flow Graph (CFG) in JSON, DOT, and Mermaid formats. This is essential for understanding the Internal Representation (IR) of the code and analyzing the control flow within contracts.",source:"@site/docs/tools/DumpCfg.md",sourceDirName:"tools",slug:"/tools/DumpCfg",permalink:"/tools/misti/docs/next/tools/DumpCfg",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tools/DumpCfg.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpAst",permalink:"/tools/misti/docs/next/tools/DumpAst"},next:{title:"DumpConfig",permalink:"/tools/misti/docs/next/tools/DumpConfig"}},o={},r=[{value:"Usage",id:"usage",level:2},{value:"Working with Mermaid",id:"working-with-mermaid",level:2},{value:"Working with Graphviz",id:"working-with-graphviz",level:2},{value:"Converting DOT to SVG",id:"converting-dot-to-svg",level:3},{value:"Viewing the SVG",id:"viewing-the-svg",level:3},{value:"VS Code Plugin",id:"vs-code-plugin",level:3},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function I(i){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...i.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h1,{id:"dumpcfg",children:"DumpCfg"}),"\n",(0,n.jsxs)(e.p,{children:["Misti provides a feature to dump the ",(0,n.jsx)(e.a,{href:"https://en.wikipedia.org/wiki/Control-flow_graph",children:"Control Flow Graph (CFG)"})," in JSON, DOT, and Mermaid formats. This is essential for understanding the Internal Representation (IR) of the code and analyzing the control flow within contracts."]}),"\n",(0,n.jsx)(e.h2,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in Mermaid format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=mmd" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in Graphviz DOT format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in JSON format, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=json" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsxs)(e.p,{children:["You could also include Tact standard library functions to the dump adding ",(0,n.jsx)(e.code,{children:"dumpStdlib=true"})," to the ",(0,n.jsx)(e.code,{children:"DumpCfg"})," options."]}),"\n",(0,n.jsx)(e.h2,{id:"working-with-mermaid",children:"Working with Mermaid"}),"\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.a,{href:"https://mermaid.js.org",children:"Mermaid"})," is a JavaScript-based diagramming and charting tool that allows you to create dynamic visualizations, such as flowcharts and sequence diagrams, using a simple syntax. It is integrated into various platforms, including Visual Studio Code."]}),"\n",(0,n.jsxs)(e.p,{children:["To view Mermaid diagrams in Visual Studio Code, you can use the ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/items?itemName=bierner.markdown-mermaid",children:"Markdown Preview Mermaid Support"})," extension. You can also use the ",(0,n.jsx)(e.a,{href:"https://mermaid.live",children:"Mermaid Live Editor"})," to preview your diagrams online."]}),"\n",(0,n.jsx)(e.p,{children:"To dump the CFG in Mermaid format using Misti, run the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=mermaid" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(e.p,{children:"The output can be viewed directly in the VS Code plugin or the online editor."}),"\n",(0,n.jsx)(e.h2,{id:"working-with-graphviz",children:"Working with Graphviz"}),"\n",(0,n.jsx)(e.h3,{id:"converting-dot-to-svg",children:"Converting DOT to SVG"}),"\n",(0,n.jsxs)(e.p,{children:["To convert the resulting DOT file to an SVG for visualization, save the generated DOT dump to a file and use ",(0,n.jsx)(e.a,{href:"https://graphviz.org",children:"Graphviz"})," with the following command:"]}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:'npx misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot\ndot -Tsvg output.dot -o output.svg\n'})}),"\n",(0,n.jsx)(e.h3,{id:"viewing-the-svg",children:"Viewing the SVG"}),"\n",(0,n.jsx)(e.p,{children:"To view the SVG file in Firefox, use the following command:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-bash",children:"firefox output.svg\n"})}),"\n",(0,n.jsx)(e.p,{children:"For example, for the following contract:"}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-tact",children:"fun test(): Int {\n let sum: Int = 0;\n let i: Int = 0;\n repeat (10) {\n i = i + 1;\n sum = sum + i;\n }\n return sum;\n}\n"})}),"\n",(0,n.jsx)(e.p,{children:"The following CFG will be generated:"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"CFG Example",src:t(685).A+"",width:"337",height:"516"})}),"\n",(0,n.jsx)(e.h3,{id:"vs-code-plugin",children:"VS Code Plugin"}),"\n",(0,n.jsxs)(e.p,{children:["For real-time visualization of DOT files, you can use ",(0,n.jsx)(e.a,{href:"https://marketplace.visualstudio.com/search?term=tag%3Agraphviz&target=VSCode&category=All%20categories&sortBy=Relevance",children:"one of the available"})," Graphviz plugins for Visual Studio Code. These plugins allow you to view DOT diagrams directly within the editor, facilitating easier debugging and development."]}),"\n",(0,n.jsx)(e.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(e.ul,{children:["\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"JSON Dumps"}),": These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"DOT Dumps"}),": These provide a visual representation of the contract's control flow. They are particularly useful for understanding the control flow within contracts, making it easier to identify issues and optimize the code."]}),"\n"]}),"\n",(0,n.jsxs)(e.li,{children:["\n",(0,n.jsxs)(e.p,{children:[(0,n.jsx)(e.strong,{children:"Mermaid Dumps"}),": The Mermaid format allows you to generate flowcharts that are easy to read and share. They offer a convenient way to visualize the CFG without requiring additional tools, as they can be directly embedded in markdown files or viewed in the Mermaid Live Editor."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(e.p,{children:"By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors."})]})}function g(i={}){const{wrapper:e}={...(0,s.R)(),...i.components};return e?(0,n.jsx)(e,{...i,children:(0,n.jsx)(I,{...i})}):I(i)}},685:(i,e,t)=>{t.d(e,{A:()=>n});const n="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDIuNCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBsb29wcyYjNDU7MyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjUzcHQiIGhlaWdodD0iMzg3cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjUzLjAwIDM4Ny4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzODMpIj4KPHRpdGxlPmxvb3BzJiM0NTszPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzgzIDI0OSwtMzgzIDI0OSw0IC00LDQiLz4KPGcgaWQ9ImNsdXN0MSIgY2xhc3M9ImNsdXN0ZXIiPgo8dGl0bGU+Y2x1c3Rlcl90ZXN0PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI4LC04IDgsLTM3MSAyMzcsLTM3MSAyMzcsLTggOCwtOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIuNSIgeT0iLTM1NS44IiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnRlc3Q8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0MSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT50ZXN0XzE0MTwvdGl0bGU+Cjxwb2x5Z29uIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjI0LjUsLTM0MCA5NS41LC0zNDAgOTUuNSwtMzA0IDIyNC41LC0zMDQgMjI0LjUsLTM0MCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNjAiIHk9Ii0zMTguMyIgZm9udC1mYW1pbHk9IlRpbWVzLHNlcmlmIiBmb250LXNpemU9IjE0LjAwIj5sZXQgc3VtOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDI8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMiwtMjY4IDEwOCwtMjY4IDEwOCwtMjMyIDIxMiwtMjMyIDIxMiwtMjY4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTI0Ni4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPmxldCBpOiBJbnQgPSAwPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDEmIzQ1OyZndDt0ZXN0XzE0MiAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MSYjNDU7Jmd0O3Rlc3RfMTQyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMzAzLjdDMTYwLC0yOTUuOTggMTYwLC0yODYuNzEgMTYwLC0yNzguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTI3OC4xIDE2MCwtMjY4LjEgMTU2LjUsLTI3OC4xIDE2My41LC0yNzguMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDQ8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOCwtMTk2IDExMiwtMTk2IDExMiwtMTYwIDIwOCwtMTYwIDIwOCwtMTk2Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE2MCIgeT0iLTE3NC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnJlcGVhdCAoMTApPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDImIzQ1OyZndDt0ZXN0XzE0NCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0MiYjNDU7Jmd0O3Rlc3RfMTQ0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE2MCwtMjMxLjdDMTYwLC0yMjMuOTggMTYwLC0yMTQuNzEgMTYwLC0yMDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYzLjUsLTIwNi4xIDE2MCwtMTk2LjEgMTU2LjUsLTIwNi4xIDE2My41LC0yMDYuMSIvPgo8L2c+CjwhLS0gdGVzdF8xNDYgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNDY8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjkzLjUsLTEyNCAxNi41LC0xMjQgMTYuNSwtODggOTMuNSwtODggOTMuNSwtMTI0Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjU1IiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+aSA9IGkgKyAxPC90ZXh0Pgo8L2c+CjwhLS0gdGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE0NiAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT50ZXN0XzE0NCYjNDU7Jmd0O3Rlc3RfMTQ2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEzNC4zMSwtMTU5Ljg4QzEyMC43MSwtMTUwLjgxIDEwMy44MywtMTM5LjU1IDg5LjE0LC0xMjkuNzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iOTEuMDUsLTEyNi44MiA4MC43OCwtMTI0LjE5IDg3LjE2LC0xMzIuNjUgOTEuMDUsLTEyNi44MiIvPgo8L2c+CjwhLS0gdGVzdF8xNTEgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+dGVzdF8xNTE8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjNjZhN2RiIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIwOC41LC0xMjQgMTExLjUsLTEyNCAxMTEuNSwtODggMjA4LjUsLTg4IDIwOC41LC0xMjQiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTYwIiB5PSItMTAyLjMiIGZvbnQtZmFtaWx5PSJUaW1lcyxzZXJpZiIgZm9udC1zaXplPSIxNC4wMCI+cmV0dXJuIHN1bTwvdGV4dD4KPC9nPgo8IS0tIHRlc3RfMTQ0JiM0NTsmZ3Q7dGVzdF8xNTEgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDQmIzQ1OyZndDt0ZXN0XzE1MTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNjAsLTE1OS43QzE2MCwtMTUxLjk4IDE2MCwtMTQyLjcxIDE2MCwtMTM0LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2My41LC0xMzQuMSAxNjAsLTEyNC4xIDE1Ni41LC0xMzQuMSAxNjMuNSwtMTM0LjEiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPnRlc3RfMTQ4PC90aXRsZT4KPHBvbHlnb24gZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxODMuNSwtNTIgNjAuNSwtNTIgNjAuNSwtMTYgMTgzLjUsLTE2IDE4My41LC01MiIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjIiIHk9Ii0zMC4zIiBmb250LWZhbWlseT0iVGltZXMsc2VyaWYiIGZvbnQtc2l6ZT0iMTQuMDAiPnN1bSA9IHN1bSArIGk8L3RleHQ+CjwvZz4KPCEtLSB0ZXN0XzE0NiYjNDU7Jmd0O3Rlc3RfMTQ4IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPnRlc3RfMTQ2JiM0NTsmZ3Q7dGVzdF8xNDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuNTYsLTg3LjdDNzkuNjgsLTc5LjIyIDg5LjU5LC02OC44NiA5OC40NywtNTkuNTgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAxLjI0LC02MS43NSAxMDUuNjMsLTUyLjEgOTYuMTksLTU2LjkxIDEwMS4yNCwtNjEuNzUiLz4KPC9nPgo8IS0tIHRlc3RfMTQ4JiM0NTsmZ3Q7dGVzdF8xNDQgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+dGVzdF8xNDgmIzQ1OyZndDt0ZXN0XzE0NDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzUuMjIsLTUyLjA0QzE5MS44OSwtNjAuMTYgMjA4LjQyLC03MS43NyAyMTgsLTg4IDIyNi4xMywtMTAxLjc4IDIyNC40NSwtMTA5LjM2IDIxOCwtMTI0IDIxMy4wMSwtMTM1LjMxIDIwNC4yOSwtMTQ1LjI2IDE5NS4xLC0xNTMuMzgiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTkyLjgzLC0xNTAuNzIgMTg3LjM0LC0xNTkuNzcgMTk3LjI4LC0xNTYuMTIgMTkyLjgzLC0xNTAuNzIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8453:(i,e,t)=>{t.d(e,{R:()=>d,x:()=>a});var n=t(6540);const s={},l=n.createContext(s);function d(i){const e=n.useContext(l);return n.useMemo((function(){return"function"==typeof i?i(e):{...e,...i}}),[e,i])}function a(i){let e;return e=i.disableParentContext?"function"==typeof i.components?i.components(s):i.components||s:d(i.components),n.createElement(l.Provider,{value:e},i.children)}}}]); \ No newline at end of file diff --git a/assets/js/d3996cd7.0ca74802.js b/assets/js/d3996cd7.0ca74802.js new file mode 100644 index 000000000..c4fc689c0 --- /dev/null +++ b/assets/js/d3996cd7.0ca74802.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5664],{9735:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>l,frontMatter:()=>r,metadata:()=>d,toc:()=>c});var n=s(4848),o=s(8453);const r={},i="DumpAst",d={id:"tools/DumpAst",title:"DumpAst",description:"The DumpAst tool in Misti enables users to output the Abstract Syntax Tree (AST) of project modules in JSON format. This is particularly useful when writing custom detectors, as it helps understand the structure and components of the code.",source:"@site/docs/tools/DumpAst.md",sourceDirName:"tools",slug:"/tools/DumpAst",permalink:"/tools/misti/docs/next/tools/DumpAst",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tools/DumpAst.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Overview",permalink:"/tools/misti/docs/next/tools"},next:{title:"DumpCfg",permalink:"/tools/misti/docs/next/tools/DumpCfg"}},a={},c=[{value:"Usage",id:"usage",level:2},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2}];function u(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"dumpast",children:"DumpAst"}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"DumpAst"})," tool in Misti enables users to output the ",(0,n.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Abstract_syntax_tree",children:"Abstract Syntax Tree (AST)"})," of project modules in JSON format. This is particularly useful when writing custom detectors, as it helps understand the structure and components of the code."]}),"\n",(0,n.jsx)(t.h2,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(t.p,{children:"To dump the AST in JSON format, use the following command:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:'npx misti -t "DumpAst" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsxs)(t.p,{children:["If you wish to include the standard library in the dump, set ",(0,n.jsx)(t.code,{children:"dumpStdlib"})," to ",(0,n.jsx)(t.code,{children:"true"}),":"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:'npx misti -t "DumpAst:dumpStdlib=true" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,n.jsx)(t.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,n.jsxs)(t.p,{children:["The AST provides a detailed breakdown of code components, offering insights into its structure. This is essential when creating or debugging ",(0,n.jsx)(t.a,{href:"/tools/misti/docs/next/hacking/custom-detector",children:"custom detectors"}),", as it allows a deeper understanding of how code is represented internally by the analyzer."]}),"\n",(0,n.jsxs)(t.p,{children:["By leveraging the ",(0,n.jsx)(t.code,{children:"DumpAst"})," tool, developers can more effectively navigate and interpret the project's syntax, supporting the development of accurate and efficient detectors."]})]})}function l(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(u,{...e})}):u(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>i,x:()=>d});var n=s(6540);const o={},r=n.createContext(o);function i(e){const t=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:i(e.components),n.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d46ee8ed.7ed1c3f4.js b/assets/js/d46ee8ed.7ed1c3f4.js new file mode 100644 index 000000000..b115152fb --- /dev/null +++ b/assets/js/d46ee8ed.7ed1c3f4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8072],{7884:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.3.1","label":"0.3.1","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.3.1","isLast":false,"docsSidebars":{"sidebar":[{"type":"link","label":"Introduction","href":"/tools/misti/docs/0.3.1/","docId":"intro","unlisted":false},{"type":"category","label":"Tutorial","items":[{"type":"link","label":"Getting Started","href":"/tools/misti/docs/0.3.1/tutorial/getting-started","docId":"tutorial/getting-started","unlisted":false},{"type":"link","label":"CI/CD Integration","href":"/tools/misti/docs/0.3.1/tutorial/ci-cd","docId":"tutorial/ci-cd","unlisted":false},{"type":"link","label":"Command-Line Interface","href":"/tools/misti/docs/0.3.1/tutorial/cli","docId":"tutorial/cli","unlisted":false},{"type":"link","label":"Configuration","href":"/tools/misti/docs/0.3.1/tutorial/configuration","docId":"tutorial/configuration","unlisted":false},{"type":"link","label":"Using with Blueprint","href":"/tools/misti/docs/0.3.1/tutorial/blueprint","docId":"tutorial/blueprint","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Detectors Overview","href":"/tools/misti/docs/0.3.1/detectors","docId":"detectors","unlisted":false},{"type":"category","label":"Detectors","items":[{"type":"link","label":"ArgCopyMutation","href":"/tools/misti/docs/0.3.1/detectors/ArgCopyMutation","docId":"detectors/ArgCopyMutation","unlisted":false},{"type":"link","label":"AsmIsUsed","href":"/tools/misti/docs/0.3.1/detectors/AsmIsUsed","docId":"detectors/AsmIsUsed","unlisted":false},{"type":"link","label":"BranchDuplicate","href":"/tools/misti/docs/0.3.1/detectors/BranchDuplicate","docId":"detectors/BranchDuplicate","unlisted":false},{"type":"link","label":"ConstantAddress","href":"/tools/misti/docs/0.3.1/detectors/ConstantAddress","docId":"detectors/ConstantAddress","unlisted":false},{"type":"link","label":"DivideBeforeMultiply","href":"/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply","docId":"detectors/DivideBeforeMultiply","unlisted":false},{"type":"link","label":"DumpIsUsed","href":"/tools/misti/docs/0.3.1/detectors/DumpIsUsed","docId":"detectors/DumpIsUsed","unlisted":false},{"type":"link","label":"FieldDoubleInit","href":"/tools/misti/docs/0.3.1/detectors/FieldDoubleInit","docId":"detectors/FieldDoubleInit","unlisted":false},{"type":"link","label":"InheritedStateMutation","href":"/tools/misti/docs/0.3.1/detectors/InheritedStateMutation","docId":"detectors/InheritedStateMutation","unlisted":false},{"type":"link","label":"NeverAccessedVariables","href":"/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables","docId":"detectors/NeverAccessedVariables","unlisted":false},{"type":"link","label":"PreferAugmentedAssign","href":"/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign","docId":"detectors/PreferAugmentedAssign","unlisted":false},{"type":"link","label":"PreferredStdlibApi","href":"/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi","docId":"detectors/PreferredStdlibApi","unlisted":false},{"type":"link","label":"ReadOnlyVariables","href":"/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables","docId":"detectors/ReadOnlyVariables","unlisted":false},{"type":"link","label":"StringReceiversOverlap","href":"/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap","docId":"detectors/StringReceiversOverlap","unlisted":false},{"type":"link","label":"UnboundLoops","href":"/tools/misti/docs/0.3.1/detectors/UnboundLoops","docId":"detectors/UnboundLoops","unlisted":false},{"type":"link","label":"ZeroAddress","href":"/tools/misti/docs/0.3.1/detectors/ZeroAddress","docId":"detectors/ZeroAddress","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacking","items":[{"type":"link","label":"Contributing","href":"/tools/misti/docs/0.3.1/hacking/contributing","docId":"hacking/contributing","unlisted":false},{"type":"link","label":"Design Overview","href":"/tools/misti/docs/0.3.1/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/0.3.1/hacking/souffle","docId":"hacking/souffle","unlisted":false},{"type":"link","label":"Tools","href":"/tools/misti/docs/0.3.1/hacking/tools","docId":"hacking/tools","unlisted":false},{"type":"link","label":"Custom Detectors","href":"/tools/misti/docs/0.3.1/hacking/custom-detector","docId":"hacking/custom-detector","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"detectors":{"id":"detectors","title":"Detectors Overview","description":"Misti currently supports 15 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:","sidebar":"sidebar"},"detectors/ArgCopyMutation":{"id":"detectors/ArgCopyMutation","title":"ArgCopyMutation","description":"A detector that highlights cases where function argument mutations are ineffective","sidebar":"sidebar"},"detectors/AsmIsUsed":{"id":"detectors/AsmIsUsed","title":"AsmIsUsed","description":"An optional detector that highlights all the asm functions.","sidebar":"sidebar"},"detectors/BranchDuplicate":{"id":"detectors/BranchDuplicate","title":"BranchDuplicate","description":"Detector that reports duplicated code in conditional branches.","sidebar":"sidebar"},"detectors/ConstantAddress":{"id":"detectors/ConstantAddress","title":"ConstantAddress","description":"An optional detector that highlights all the constant addresses appearing in the source code.","sidebar":"sidebar"},"detectors/DivideBeforeMultiply":{"id":"detectors/DivideBeforeMultiply","title":"DivideBeforeMultiply","description":"A detector that identifies and corrects instances of division before multiplication to","sidebar":"sidebar"},"detectors/DumpIsUsed":{"id":"detectors/DumpIsUsed","title":"DumpIsUsed","description":"An optional detector that highlights all the dump function calls.","sidebar":"sidebar"},"detectors/FieldDoubleInit":{"id":"detectors/FieldDoubleInit","title":"FieldDoubleInit","description":"A detector that highlights cases where a field is initialized both in the","sidebar":"sidebar"},"detectors/InheritedStateMutation":{"id":"detectors/InheritedStateMutation","title":"InheritedStateMutation","description":"An optional detector that highlights all instances where inherited trait variables","sidebar":"sidebar"},"detectors/NeverAccessedVariables":{"id":"detectors/NeverAccessedVariables","title":"NeverAccessedVariables","description":"A detector that identifies write-only or unused variables, fields and constants.","sidebar":"sidebar"},"detectors/PreferAugmentedAssign":{"id":"detectors/PreferAugmentedAssign","title":"PreferAugmentedAssign","description":"Detects non-idiomatic statements that can be written using augmented assignment","sidebar":"sidebar"},"detectors/PreferredStdlibApi":{"id":"detectors/PreferredStdlibApi","title":"PreferredStdlibApi","description":"An optional detector that flags the use of advanced functions from the standard library.","sidebar":"sidebar"},"detectors/ReadOnlyVariables":{"id":"detectors/ReadOnlyVariables","title":"ReadOnlyVariables","description":"A detector that identifies read-only variables and fields.","sidebar":"sidebar"},"detectors/StringReceiversOverlap":{"id":"detectors/StringReceiversOverlap","title":"StringReceiversOverlap","description":"A detector that finds overlapping messages between general string receivers and string receivers.","sidebar":"sidebar"},"detectors/UnboundLoops":{"id":"detectors/UnboundLoops","title":"UnboundLoops","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/ZeroAddress":{"id":"detectors/ZeroAddress","title":"ZeroAddress","description":"A detector that identifies uses of the zero address.","sidebar":"sidebar"},"hacking/contributing":{"id":"hacking/contributing","title":"Contributing Guide","description":"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.","sidebar":"sidebar"},"hacking/custom-detector":{"id":"hacking/custom-detector","title":"Custom Detector Guide","description":"Introduction","sidebar":"sidebar"},"hacking/design":{"id":"hacking/design","title":"Design Overview","description":"Static Analysis","sidebar":"sidebar"},"hacking/souffle":{"id":"hacking/souffle","title":"Souffl\xe9 Integration Guide","description":"What is Souffl\xe9?","sidebar":"sidebar"},"hacking/tools":{"id":"hacking/tools","title":"Tools Guide","description":"This page describes the internal analyzer tools available in Misti to aid in development and debugging.","sidebar":"sidebar"},"intro":{"id":"intro","title":"Introduction","description":"Misti is a static analysis tool designed for smart contracts on the TON blockchain.","sidebar":"sidebar"},"tutorial/blueprint":{"id":"tutorial/blueprint","title":"Using Misti with Blueprint","description":"Blueprint is a development environment for writing, testing, and deploying TON smart contracts.","sidebar":"sidebar"},"tutorial/ci-cd":{"id":"tutorial/ci-cd","title":"Integrating Misti into CI/CD","description":"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.","sidebar":"sidebar"},"tutorial/cli":{"id":"tutorial/cli","title":"Command-Line Interface","description":"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.","sidebar":"sidebar"},"tutorial/configuration":{"id":"tutorial/configuration","title":"Configuration","description":"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.","sidebar":"sidebar"},"tutorial/getting-started":{"id":"tutorial/getting-started","title":"Getting started","description":"This guide will walk you through the steps to install and set up the Misti static analyzer.","sidebar":"sidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/d6f3e79e.d1be0df5.js b/assets/js/d6f3e79e.d1be0df5.js new file mode 100644 index 000000000..e70d9d318 --- /dev/null +++ b/assets/js/d6f3e79e.d1be0df5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1678],{1747:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var a=t(4848),i=t(8453);const r={},s="Read-only Variables",o={id:"detectors/ReadOnlyVariables",title:"Read-only Variables",description:"A detector that identifies read-only variables and fields.",source:"@site/versioned_docs/version-0.1.2/detectors/ReadOnlyVariables.md",sourceDirName:"detectors",slug:"/detectors/ReadOnlyVariables",permalink:"/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/detectors/ReadOnlyVariables.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Never-accessed Variables",permalink:"/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables"},next:{title:"Unbound Loops",permalink:"/tools/misti/docs/0.1.2/detectors/UnboundLoops"}},l={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const n={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.h1,{id:"read-only-variables",children:"Read-only Variables"}),"\n",(0,a.jsx)(n.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,a.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,a.jsx)(n.p,{children:"These variables could typically be replaced with constants to optimize performance.\nAlternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally."}),"\n",(0,a.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-tact",children:"fun calculateFinalPrice(price: Int): Int {\n // Warning: the developer uses a read-only variable that could be a constant\n let DISCOUNT_AMOUNT: Int = 10;\n return price - DISCOUNT_AMOUNT;\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:"Use instead:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-tact",children:"const DISCOUNT_AMOUNT: Int = 10;\n\nfun calculateFinalPrice(price: Int): Int {\n // OK: Fixed after the linter highlighted this warning\n return price - DISCOUNT_AMOUNT;\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>o});var a=t(6540);const i={},r=a.createContext(i);function s(e){const n=a.useContext(r);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:s(e.components),a.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d7c99f30.b0b05326.js b/assets/js/d7c99f30.b0b05326.js new file mode 100644 index 000000000..f93b09601 --- /dev/null +++ b/assets/js/d7c99f30.b0b05326.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8904],{7389:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>l});var i=n(4848),s=n(8453);const o={},r="OptimalMathFunction",a={id:"detectors/OptimalMathFunction",title:"OptimalMathFunction",description:"A detector that highlights standard library math function calls that have more gas-efficient alternatives.",source:"@site/versioned_docs/version-0.4.0/detectors/OptimalMathFunction.md",sourceDirName:"detectors",slug:"/detectors/OptimalMathFunction",permalink:"/tools/misti/docs/detectors/OptimalMathFunction",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/OptimalMathFunction.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"NeverAccessedVariables",permalink:"/tools/misti/docs/detectors/NeverAccessedVariables"},next:{title:"PreferAugmentedAssign",permalink:"/tools/misti/docs/detectors/PreferAugmentedAssign"}},c={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function d(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"optimalmathfunction",children:"OptimalMathFunction"}),"\n",(0,i.jsx)(t.p,{children:"A detector that highlights standard library math function calls that have more gas-efficient alternatives."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsxs)(t.p,{children:["Tact supports ",(0,i.jsx)(t.code,{children:"log2"}),"/",(0,i.jsx)(t.code,{children:"pow2"})," functions, which are more gas-efficient than ",(0,i.jsx)(t.code,{children:"log(x, 2)"}),"/",(0,i.jsx)(t.code,{children:"pow(x, 2)"}),"."]}),"\n",(0,i.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"log(x, 2);\n"})}),"\n",(0,i.jsx)(t.p,{children:"Use instead:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"log2(x)\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d7d99e1d.67e2d007.js b/assets/js/d7d99e1d.67e2d007.js new file mode 100644 index 000000000..0f74a1ddd --- /dev/null +++ b/assets/js/d7d99e1d.67e2d007.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9076],{668:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),a=n(8453);const r={},i="Never-accessed Variables",o={id:"detectors/NeverAccessedVariables",title:"Never-accessed Variables",description:"A detector that identifies write-only or unused variables, fields and constants.",source:"@site/versioned_docs/version-0.2.2/detectors/NeverAccessedVariables.md",sourceDirName:"detectors",slug:"/detectors/NeverAccessedVariables",permalink:"/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/NeverAccessedVariables.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Divide before Multiply",permalink:"/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply"},next:{title:"Read-only Variables",permalink:"/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"never-accessed-variables",children:"Never-accessed Variables"}),"\n",(0,s.jsx)(t.p,{children:"A detector that identifies write-only or unused variables, fields and constants."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"These variables are either assigned but never used in any meaningful computation,\nor they are declared and never used at all, which may indicate redundant code\nor an incomplete implementation of the intended logic."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"// Error: the developer forgot to use the constant\nconst MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'const MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n // OK: Fixed after the linter highlighted this warning\n require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(6540);const a={},r=s.createContext(a);function i(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d9542fcf.bbcb88d0.js b/assets/js/d9542fcf.bbcb88d0.js new file mode 100644 index 000000000..033f9c03f --- /dev/null +++ b/assets/js/d9542fcf.bbcb88d0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3590],{2866:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>p,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),i=n(8453);const r={},c="Branch Duplicate",o={id:"detectors/BranchDuplicate",title:"Branch Duplicate",description:"Detector that reports duplicated code in conditional branches.",source:"@site/versioned_docs/version-0.2.0/detectors/BranchDuplicate.md",sourceDirName:"detectors",slug:"/detectors/BranchDuplicate",permalink:"/tools/misti/docs/0.2.0/detectors/BranchDuplicate",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors/BranchDuplicate.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Constant Address",permalink:"/tools/misti/docs/0.2.0/detectors/ConstantAddress"},next:{title:"`dump` Is Used",permalink:"/tools/misti/docs/0.2.0/detectors/DumpIsUsed"}},a={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"branch-duplicate",children:"Branch Duplicate"}),"\n",(0,s.jsx)(t.p,{children:"Detector that reports duplicated code in conditional branches."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Duplicated code in branches is bad because it:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Reduces Readability"}),": Repetition makes the code harder to understand."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Increases Maintenance"}),": Changes must be made in multiple places, risking errors."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Signals Poor Design"}),": It suggests missed opportunities for cleaner, more abstract code."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = 43; // bad: duplicated code\n} else {\n a = 43;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = inc(b); // ok\n} else {\n a = 43;\n}\n"})})]})}function p(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>o});var s=n(6540);const i={},r=s.createContext(i);function c(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:c(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/dc55925b.1af0a38f.js b/assets/js/dc55925b.1af0a38f.js new file mode 100644 index 000000000..e0a56cdff --- /dev/null +++ b/assets/js/dc55925b.1af0a38f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8546],{5729:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var i=t(4848),r=t(8453);const o={},a="EnsurePrgSeed",s={id:"detectors/EnsurePrgSeed",title:"EnsurePrgSeed",description:"A detector that identifies all calls to nativeRandom and nativeRandomInterval",source:"@site/docs/detectors/EnsurePrgSeed.md",sourceDirName:"detectors",slug:"/detectors/EnsurePrgSeed",permalink:"/tools/misti/docs/next/detectors/EnsurePrgSeed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/EnsurePrgSeed.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"DuplicatedCondition",permalink:"/tools/misti/docs/next/detectors/DuplicatedCondition"},next:{title:"FalseCondition",permalink:"/tools/misti/docs/next/detectors/FalseCondition"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const n={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"ensureprgseed",children:"EnsurePrgSeed"}),"\n",(0,i.jsxs)(n.p,{children:["A detector that identifies all calls to ",(0,i.jsx)(n.code,{children:"nativeRandom"})," and ",(0,i.jsx)(n.code,{children:"nativeRandomInterval"}),"\nwithout a preceding PRG seed initialization."]}),"\n",(0,i.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsxs)(n.p,{children:["Using ",(0,i.jsx)(n.code,{children:"nativeRandom"})," or ",(0,i.jsx)(n.code,{children:"nativeRandomInterval"})," without first initializing the PRG seed via\n",(0,i.jsx)(n.code,{children:"nativePrepareRandom"}),", ",(0,i.jsx)(n.code,{children:"nativeRandomize"}),", or ",(0,i.jsx)(n.code,{children:"nativeRandomizeLt"})," may lead to unintended behavior\nor weak random number generation. This detector ensures that PRG seed initialization\nis always performed before any use of random functions, enhancing contract security."]}),"\n",(0,i.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"// Bad: `nativeRandom` is used without prior PRG seed initialization\nfun generateRandomValue(): Int {\n return nativeRandom()\n}\n"})}),"\n",(0,i.jsx)(n.p,{children:"Use instead:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"fun test(): Int {\n nativePrepareRandom();\n}\n\n// OK: PRG has been initialized somewhere in the contract\nfun generateRandomValue(): Int {\n return nativeRandom()\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>s});var i=t(6540);const r={},o=i.createContext(r);function a(e){const n=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),i.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/dd8730c9.aeb151c7.js b/assets/js/dd8730c9.aeb151c7.js new file mode 100644 index 000000000..5422e7c2d --- /dev/null +++ b/assets/js/dd8730c9.aeb151c7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8137],{2205:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"Next","banner":"unreleased","badge":true,"noIndex":false,"className":"docs-version-current","isLast":false,"docsSidebars":{"sidebar":[{"type":"link","label":"Introduction","href":"/tools/misti/docs/next/","docId":"intro","unlisted":false},{"type":"category","label":"Tutorial","items":[{"type":"link","label":"Getting Started","href":"/tools/misti/docs/next/tutorial/getting-started","docId":"tutorial/getting-started","unlisted":false},{"type":"link","label":"CI/CD Integration","href":"/tools/misti/docs/next/tutorial/ci-cd","docId":"tutorial/ci-cd","unlisted":false},{"type":"link","label":"Command-Line Interface","href":"/tools/misti/docs/next/tutorial/cli","docId":"tutorial/cli","unlisted":false},{"type":"link","label":"Configuration","href":"/tools/misti/docs/next/tutorial/configuration","docId":"tutorial/configuration","unlisted":false},{"type":"link","label":"Using with Blueprint","href":"/tools/misti/docs/next/tutorial/blueprint","docId":"tutorial/blueprint","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"html","value":"<hr class=\\"sidebars-separator\\" />"},{"type":"html","value":"<span class=\'menu__link\'><b> Detectors </b></span>"},{"type":"link","label":"Overview","href":"/tools/misti/docs/next/detectors","docId":"detectors","unlisted":false},{"type":"category","label":"Built-in Detectors","items":[{"type":"link","label":"ArgCopyMutation","href":"/tools/misti/docs/next/detectors/ArgCopyMutation","docId":"detectors/ArgCopyMutation","unlisted":false},{"type":"link","label":"AsmIsUsed","href":"/tools/misti/docs/next/detectors/AsmIsUsed","docId":"detectors/AsmIsUsed","unlisted":false},{"type":"link","label":"BranchDuplicate","href":"/tools/misti/docs/next/detectors/BranchDuplicate","docId":"detectors/BranchDuplicate","unlisted":false},{"type":"link","label":"ConstantAddress","href":"/tools/misti/docs/next/detectors/ConstantAddress","docId":"detectors/ConstantAddress","unlisted":false},{"type":"link","label":"DivideBeforeMultiply","href":"/tools/misti/docs/next/detectors/DivideBeforeMultiply","docId":"detectors/DivideBeforeMultiply","unlisted":false},{"type":"link","label":"DumpIsUsed","href":"/tools/misti/docs/next/detectors/DumpIsUsed","docId":"detectors/DumpIsUsed","unlisted":false},{"type":"link","label":"DuplicatedCondition","href":"/tools/misti/docs/next/detectors/DuplicatedCondition","docId":"detectors/DuplicatedCondition","unlisted":false},{"type":"link","label":"EnsurePrgSeed","href":"/tools/misti/docs/next/detectors/EnsurePrgSeed","docId":"detectors/EnsurePrgSeed","unlisted":false},{"type":"link","label":"FalseCondition","href":"/tools/misti/docs/next/detectors/FalseCondition","docId":"detectors/FalseCondition","unlisted":false},{"type":"link","label":"FieldDoubleInit","href":"/tools/misti/docs/next/detectors/FieldDoubleInit","docId":"detectors/FieldDoubleInit","unlisted":false},{"type":"link","label":"InheritedStateMutation","href":"/tools/misti/docs/next/detectors/InheritedStateMutation","docId":"detectors/InheritedStateMutation","unlisted":false},{"type":"link","label":"NeverAccessedVariables","href":"/tools/misti/docs/next/detectors/NeverAccessedVariables","docId":"detectors/NeverAccessedVariables","unlisted":false},{"type":"link","label":"OptimalMathFunction","href":"/tools/misti/docs/next/detectors/OptimalMathFunction","docId":"detectors/OptimalMathFunction","unlisted":false},{"type":"link","label":"PreferAugmentedAssign","href":"/tools/misti/docs/next/detectors/PreferAugmentedAssign","docId":"detectors/PreferAugmentedAssign","unlisted":false},{"type":"link","label":"PreferredStdlibApi","href":"/tools/misti/docs/next/detectors/PreferredStdlibApi","docId":"detectors/PreferredStdlibApi","unlisted":false},{"type":"link","label":"ReadOnlyVariables","href":"/tools/misti/docs/next/detectors/ReadOnlyVariables","docId":"detectors/ReadOnlyVariables","unlisted":false},{"type":"link","label":"StringReceiversOverlap","href":"/tools/misti/docs/next/detectors/StringReceiversOverlap","docId":"detectors/StringReceiversOverlap","unlisted":false},{"type":"link","label":"UnboundLoops","href":"/tools/misti/docs/next/detectors/UnboundLoops","docId":"detectors/UnboundLoops","unlisted":false},{"type":"link","label":"UnusedOptional","href":"/tools/misti/docs/next/detectors/UnusedOptional","docId":"detectors/UnusedOptional","unlisted":false},{"type":"link","label":"ZeroAddress","href":"/tools/misti/docs/next/detectors/ZeroAddress","docId":"detectors/ZeroAddress","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"html","value":"<hr class=\\"sidebars-separator\\" />"},{"type":"html","value":"<span class=\'menu__link\'><b> Tools </b></span>"},{"type":"link","label":"Overview","href":"/tools/misti/docs/next/tools","docId":"tools","unlisted":false},{"type":"category","label":"Built-in Tools","items":[{"type":"link","label":"DumpAst","href":"/tools/misti/docs/next/tools/DumpAst","docId":"tools/DumpAst","unlisted":false},{"type":"link","label":"DumpCfg","href":"/tools/misti/docs/next/tools/DumpCfg","docId":"tools/DumpCfg","unlisted":false},{"type":"link","label":"DumpConfig","href":"/tools/misti/docs/next/tools/DumpConfig","docId":"tools/DumpConfig","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"html","value":"<hr class=\\"sidebars-separator\\" />"},{"type":"html","value":"<span class=\'menu__link\'><b> Development </b></span>"},{"type":"category","label":"Misti Design","items":[{"type":"link","label":"Design Overview","href":"/tools/misti/docs/next/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/next/hacking/souffle","docId":"hacking/souffle","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacking","items":[{"type":"link","label":"Contributing","href":"/tools/misti/docs/next/hacking/contributing","docId":"hacking/contributing","unlisted":false},{"type":"link","label":"Developing Misti","href":"/tools/misti/docs/next/hacking/developing-misti","docId":"hacking/developing-misti","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Writing Custom Detectors","href":"/tools/misti/docs/next/hacking/custom-detector","docId":"hacking/custom-detector","unlisted":false}]},"docs":{"detectors":{"id":"detectors","title":"Detectors Overview","description":"Misti currently supports 21 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices.","sidebar":"sidebar"},"detectors/ArgCopyMutation":{"id":"detectors/ArgCopyMutation","title":"ArgCopyMutation","description":"A detector that highlights cases where function argument mutations are ineffective","sidebar":"sidebar"},"detectors/AsmIsUsed":{"id":"detectors/AsmIsUsed","title":"AsmIsUsed","description":"An optional detector that highlights all the asm functions.","sidebar":"sidebar"},"detectors/BranchDuplicate":{"id":"detectors/BranchDuplicate","title":"BranchDuplicate","description":"Detector that reports duplicated code in conditional branches.","sidebar":"sidebar"},"detectors/ConstantAddress":{"id":"detectors/ConstantAddress","title":"ConstantAddress","description":"An optional detector that highlights all the constant addresses appearing in the source code.","sidebar":"sidebar"},"detectors/DivideBeforeMultiply":{"id":"detectors/DivideBeforeMultiply","title":"DivideBeforeMultiply","description":"A detector that identifies and corrects instances of division before multiplication to","sidebar":"sidebar"},"detectors/DumpIsUsed":{"id":"detectors/DumpIsUsed","title":"DumpIsUsed","description":"An optional detector that highlights all the dump debug prints.","sidebar":"sidebar"},"detectors/DuplicatedCondition":{"id":"detectors/DuplicatedCondition","title":"DuplicatedCondition","description":"A detector that finds duplicated conditions appearing in conditional expressions.","sidebar":"sidebar"},"detectors/EnsurePrgSeed":{"id":"detectors/EnsurePrgSeed","title":"EnsurePrgSeed","description":"A detector that identifies all calls to nativeRandom and nativeRandomInterval","sidebar":"sidebar"},"detectors/FalseCondition":{"id":"detectors/FalseCondition","title":"FalseCondition","description":"A detector that highlights conditions that evaluate to a constant true or false","sidebar":"sidebar"},"detectors/FieldDoubleInit":{"id":"detectors/FieldDoubleInit","title":"FieldDoubleInit","description":"A detector that highlights cases where a field is initialized both in the","sidebar":"sidebar"},"detectors/InheritedStateMutation":{"id":"detectors/InheritedStateMutation","title":"InheritedStateMutation","description":"An optional detector that highlights all instances where inherited trait variables","sidebar":"sidebar"},"detectors/NeverAccessedVariables":{"id":"detectors/NeverAccessedVariables","title":"NeverAccessedVariables","description":"A detector that identifies write-only or unused variables, fields and constants.","sidebar":"sidebar"},"detectors/OptimalMathFunction":{"id":"detectors/OptimalMathFunction","title":"OptimalMathFunction","description":"A detector that highlights standard library math function calls that have more gas-efficient alternatives.","sidebar":"sidebar"},"detectors/PreferAugmentedAssign":{"id":"detectors/PreferAugmentedAssign","title":"PreferAugmentedAssign","description":"Detects non-idiomatic statements that can be written using augmented assignment","sidebar":"sidebar"},"detectors/PreferredStdlibApi":{"id":"detectors/PreferredStdlibApi","title":"PreferredStdlibApi","description":"An optional detector that flags the use of advanced functions from the standard library.","sidebar":"sidebar"},"detectors/ReadOnlyVariables":{"id":"detectors/ReadOnlyVariables","title":"ReadOnlyVariables","description":"A detector that identifies read-only variables and fields.","sidebar":"sidebar"},"detectors/StringReceiversOverlap":{"id":"detectors/StringReceiversOverlap","title":"StringReceiversOverlap","description":"A detector that finds overlapping messages between general string receivers and string receivers.","sidebar":"sidebar"},"detectors/UnboundLoops":{"id":"detectors/UnboundLoops","title":"UnboundLoops","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/UnusedOptional":{"id":"detectors/UnusedOptional","title":"UnusedOptional","description":"A detector variables and fields with unused optional modifier.","sidebar":"sidebar"},"detectors/ZeroAddress":{"id":"detectors/ZeroAddress","title":"ZeroAddress","description":"A detector that identifies uses of the zero address.","sidebar":"sidebar"},"hacking/contributing":{"id":"hacking/contributing","title":"Contributing Guide","description":"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.","sidebar":"sidebar"},"hacking/custom-detector":{"id":"hacking/custom-detector","title":"Custom Detector Guide","description":"Introduction","sidebar":"sidebar"},"hacking/design":{"id":"hacking/design","title":"Design Overview","description":"Static Analysis","sidebar":"sidebar"},"hacking/developing-misti":{"id":"hacking/developing-misti","title":"Developing Misti","description":"Prerequisites","sidebar":"sidebar"},"hacking/souffle":{"id":"hacking/souffle","title":"Souffl\xe9 Integration Guide","description":"What is Souffl\xe9?","sidebar":"sidebar"},"intro":{"id":"intro","title":"Introduction","description":"Misti is a static analysis tool designed for smart contracts on the TON blockchain.","sidebar":"sidebar"},"tools":{"id":"tools","title":"Tools Overview","description":"Misti Tools are additional modules designed to work alongside detectors, enabling various tasks beyond code analysis.","sidebar":"sidebar"},"tools/DumpAst":{"id":"tools/DumpAst","title":"DumpAst","description":"The DumpAst tool in Misti enables users to output the Abstract Syntax Tree (AST) of project modules in JSON format. This is particularly useful when writing custom detectors, as it helps understand the structure and components of the code.","sidebar":"sidebar"},"tools/DumpCfg":{"id":"tools/DumpCfg","title":"DumpCfg","description":"Misti provides a feature to dump the Control Flow Graph (CFG) in JSON, DOT, and Mermaid formats. This is essential for understanding the Internal Representation (IR) of the code and analyzing the control flow within contracts.","sidebar":"sidebar"},"tools/DumpConfig":{"id":"tools/DumpConfig","title":"DumpConfig","description":"The DumpConfig tool in Misti allows you to print the current configuration file used by the analyzer. This is useful for obtaining the default configuration to use as a starting point for your custom setup or to inspect and understand the existing configuration in use.","sidebar":"sidebar"},"tutorial/blueprint":{"id":"tutorial/blueprint","title":"Using Misti with Blueprint","description":"Blueprint is a platform to compile, test, and deploy contracts on the TON blockchain. It is quite similar to Hardhat and Truffle for Ethereum.","sidebar":"sidebar"},"tutorial/ci-cd":{"id":"tutorial/ci-cd","title":"Integrating Misti into CI/CD","description":"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.","sidebar":"sidebar"},"tutorial/cli":{"id":"tutorial/cli","title":"Command-Line Interface","description":"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.","sidebar":"sidebar"},"tutorial/configuration":{"id":"tutorial/configuration","title":"Configuration","description":"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.","sidebar":"sidebar"},"tutorial/getting-started":{"id":"tutorial/getting-started","title":"Getting started","description":"This guide will walk you through the steps to install and set up the Misti static analyzer.","sidebar":"sidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/e1c88a01.26b5c812.js b/assets/js/e1c88a01.26b5c812.js new file mode 100644 index 000000000..4dacb8281 --- /dev/null +++ b/assets/js/e1c88a01.26b5c812.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[488],{9423:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.2.2","label":"0.2.2","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.2.2","isLast":false,"docsSidebars":{"sidebar":[{"type":"link","label":"Introduction","href":"/tools/misti/docs/0.2.2/","docId":"intro","unlisted":false},{"type":"category","label":"Tutorial","items":[{"type":"link","label":"Getting Started","href":"/tools/misti/docs/0.2.2/tutorial/getting-started","docId":"tutorial/getting-started","unlisted":false},{"type":"link","label":"CI/CD Integration","href":"/tools/misti/docs/0.2.2/tutorial/ci-cd","docId":"tutorial/ci-cd","unlisted":false},{"type":"link","label":"Configuration","href":"/tools/misti/docs/0.2.2/tutorial/configuration","docId":"tutorial/configuration","unlisted":false},{"type":"link","label":"Using with Blueprint","href":"/tools/misti/docs/0.2.2/tutorial/blueprint","docId":"tutorial/blueprint","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Detectors Overview","href":"/tools/misti/docs/0.2.2/detectors","docId":"detectors","unlisted":false},{"type":"category","label":"Detectors","items":[{"type":"link","label":"Divide before Multiply","href":"/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply","docId":"detectors/DivideBeforeMultiply","unlisted":false},{"type":"link","label":"Never-accessed Variables","href":"/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables","docId":"detectors/NeverAccessedVariables","unlisted":false},{"type":"link","label":"Read-only Variables","href":"/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables","docId":"detectors/ReadOnlyVariables","unlisted":false},{"type":"link","label":"Unbound Loops","href":"/tools/misti/docs/0.2.2/detectors/UnboundLoops","docId":"detectors/UnboundLoops","unlisted":false},{"type":"link","label":"Zero Address","href":"/tools/misti/docs/0.2.2/detectors/ZeroAddress","docId":"detectors/ZeroAddress","unlisted":false},{"type":"link","label":"Constant Address","href":"/tools/misti/docs/0.2.2/detectors/ConstantAddress","docId":"detectors/ConstantAddress","unlisted":false},{"type":"link","label":"Branch Duplicate","href":"/tools/misti/docs/0.2.2/detectors/BranchDuplicate","docId":"detectors/BranchDuplicate","unlisted":false},{"type":"link","label":"`dump` Is Used","href":"/tools/misti/docs/0.2.2/detectors/DumpIsUsed","docId":"detectors/DumpIsUsed","unlisted":false},{"type":"link","label":"Field Initialized Twice","href":"/tools/misti/docs/0.2.2/detectors/FieldDoubleInit","docId":"detectors/FieldDoubleInit","unlisted":false},{"type":"link","label":"Prefer Augmented Assignment","href":"/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign","docId":"detectors/PreferAugmentedAssign","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacking","items":[{"type":"link","label":"Contributing","href":"/tools/misti/docs/0.2.2/hacking/contributing","docId":"hacking/contributing","unlisted":false},{"type":"link","label":"Design Overview","href":"/tools/misti/docs/0.2.2/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/0.2.2/hacking/souffle","docId":"hacking/souffle","unlisted":false},{"type":"link","label":"Tools","href":"/tools/misti/docs/0.2.2/hacking/tools","docId":"hacking/tools","unlisted":false},{"type":"link","label":"Custom Detectors","href":"/tools/misti/docs/0.2.2/hacking/custom-detector","docId":"hacking/custom-detector","unlisted":false}],"collapsed":true,"collapsible":true}]},"docs":{"detectors":{"id":"detectors","title":"Detectors Overview","description":"Here\'s a list of all the detectors:","sidebar":"sidebar"},"detectors/BranchDuplicate":{"id":"detectors/BranchDuplicate","title":"Branch Duplicate","description":"Detector that reports duplicated code in conditional branches.","sidebar":"sidebar"},"detectors/ConstantAddress":{"id":"detectors/ConstantAddress","title":"Constant Address","description":"An optional detector that highlights all the constant addresses appearing in the source code.","sidebar":"sidebar"},"detectors/DivideBeforeMultiply":{"id":"detectors/DivideBeforeMultiply","title":"Divide before Multiply","description":"A detector that identifies and corrects instances of division before multiplication to","sidebar":"sidebar"},"detectors/DumpIsUsed":{"id":"detectors/DumpIsUsed","title":"dump Is Used","description":"An optional detector that highlights all the dump function calls.","sidebar":"sidebar"},"detectors/FieldDoubleInit":{"id":"detectors/FieldDoubleInit","title":"Field Initialized Twice","description":"A detector that highlights cases where a field is initialized both in the init function and at the point of definition.","sidebar":"sidebar"},"detectors/NeverAccessedVariables":{"id":"detectors/NeverAccessedVariables","title":"Never-accessed Variables","description":"A detector that identifies write-only or unused variables, fields and constants.","sidebar":"sidebar"},"detectors/PreferAugmentedAssign":{"id":"detectors/PreferAugmentedAssign","title":"Prefer Augmented Assignment","description":"Detects non-idiomatic statements that can be written using augmented assignment operators like +=, -=, etc.","sidebar":"sidebar"},"detectors/ReadOnlyVariables":{"id":"detectors/ReadOnlyVariables","title":"Read-only Variables","description":"A detector that identifies read-only variables and fields.","sidebar":"sidebar"},"detectors/UnboundLoops":{"id":"detectors/UnboundLoops","title":"Unbound Loops","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/ZeroAddress":{"id":"detectors/ZeroAddress","title":"Zero Address","description":"A detector that identifies uses of the zero address.","sidebar":"sidebar"},"hacking/contributing":{"id":"hacking/contributing","title":"Contributing Guide","description":"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.","sidebar":"sidebar"},"hacking/custom-detector":{"id":"hacking/custom-detector","title":"Custom Detector Guide","description":"Introduction","sidebar":"sidebar"},"hacking/design":{"id":"hacking/design","title":"Design Overview","description":"Static Analysis","sidebar":"sidebar"},"hacking/souffle":{"id":"hacking/souffle","title":"Souffl\xe9 Integration Guide","description":"What is Souffl\xe9?","sidebar":"sidebar"},"hacking/tools":{"id":"hacking/tools","title":"Tools Guide","description":"This page describes the internal analyzer tools available in Misti to aid in development and debugging.","sidebar":"sidebar"},"intro":{"id":"intro","title":"Introduction","description":"Misti is a static analysis tool designed for smart contracts on the TON blockchain.","sidebar":"sidebar"},"tutorial/blueprint":{"id":"tutorial/blueprint","title":"Using Misti with Blueprint","description":"Blueprint is a development environment for writing, testing, and deploying TON smart contracts.","sidebar":"sidebar"},"tutorial/ci-cd":{"id":"tutorial/ci-cd","title":"Integrating Misti into CI/CD","description":"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.","sidebar":"sidebar"},"tutorial/configuration":{"id":"tutorial/configuration","title":"Configuration","description":"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.","sidebar":"sidebar"},"tutorial/getting-started":{"id":"tutorial/getting-started","title":"Getting started","description":"This guide will walk you through the steps to install and set up the Misti static analyzer.","sidebar":"sidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/e2ad9c7a.573d9426.js b/assets/js/e2ad9c7a.573d9426.js new file mode 100644 index 000000000..561e6fc1e --- /dev/null +++ b/assets/js/e2ad9c7a.573d9426.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5945],{4193:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var s=n(4848),t=n(8453);const a={},o="Design Overview",l={id:"hacking/design",title:"Design Overview",description:"Static Analysis",source:"@site/versioned_docs/version-0.3.1/hacking/design.md",sourceDirName:"hacking",slug:"/hacking/design",permalink:"/tools/misti/docs/0.3.1/hacking/design",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/hacking/design.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Contributing",permalink:"/tools/misti/docs/0.3.1/hacking/contributing"},next:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.3.1/hacking/souffle"}},r={},c=[{value:"Static Analysis",id:"static-analysis",level:2},{value:"Souffle Datalog Solver",id:"souffle-datalog-solver",level:2},{value:"Dataflow Analysis in Misti",id:"dataflow-analysis-in-misti",level:2},{value:"References",id:"references",level:2}];function d(e){const i={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"design-overview",children:"Design Overview"}),"\n",(0,s.jsx)(i.h2,{id:"static-analysis",children:"Static Analysis"}),"\n",(0,s.jsx)(i.p,{children:"Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues."}),"\n",(0,s.jsx)(i.h2,{id:"souffle-datalog-solver",children:"Souffle Datalog Solver"}),"\n",(0,s.jsxs)(i.p,{children:["Misti leverages the ",(0,s.jsx)(i.a,{href:"https://souffle-lang.github.io",children:"Souffle Datalog solver"}),", an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases."]}),"\n",(0,s.jsx)(i.h2,{id:"dataflow-analysis-in-misti",children:"Dataflow Analysis in Misti"}),"\n",(0,s.jsx)(i.p,{children:"Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code."}),"\n",(0,s.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,s.jsx)(i.p,{children:"For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.a,{href:"https://cs.au.dk/~amoeller/spa/spa.pdf",children:"Anders M\xf8ller and Michael I. Schwartzbach \u2013 Static Program Analysis"})}),"\n",(0,s.jsx)(i.li,{children:"Uday Khedker et al. \u2013 Data Flow Analysis: Theory and Practice"}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"These resources provide a solid foundation in the theory and practice of static and dataflow analysis."})]})}function h(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>o,x:()=>l});var s=n(6540);const t={},a=s.createContext(t);function o(e){const i=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e3b47995.2fccb84f.js b/assets/js/e3b47995.2fccb84f.js new file mode 100644 index 000000000..b163119b0 --- /dev/null +++ b/assets/js/e3b47995.2fccb84f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1171],{7112:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>c,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var s=n(4848),i=n(8453);const r={},c="BranchDuplicate",a={id:"detectors/BranchDuplicate",title:"BranchDuplicate",description:"Detector that reports duplicated code in conditional branches.",source:"@site/docs/detectors/BranchDuplicate.md",sourceDirName:"detectors",slug:"/detectors/BranchDuplicate",permalink:"/tools/misti/docs/next/detectors/BranchDuplicate",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/BranchDuplicate.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"AsmIsUsed",permalink:"/tools/misti/docs/next/detectors/AsmIsUsed"},next:{title:"ConstantAddress",permalink:"/tools/misti/docs/next/detectors/ConstantAddress"}},o={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"branchduplicate",children:"BranchDuplicate"}),"\n",(0,s.jsx)(t.p,{children:"Detector that reports duplicated code in conditional branches."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Duplicated code in branches is bad because it:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Reduces Readability"}),": Repetition makes the code harder to understand."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Increases Maintenance"}),": Changes must be made in multiple places, risking errors."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Signals Poor Design"}),": It suggests missed opportunities for cleaner, more abstract code."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = 43; // bad: duplicated code\n} else {\n a = 43;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = inc(b); // ok\n} else {\n a = 43;\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>a});var s=n(6540);const i={},r=s.createContext(i);function c(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:c(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e3c4fe0a.bf2b73e2.js b/assets/js/e3c4fe0a.bf2b73e2.js new file mode 100644 index 000000000..0914e4dd4 --- /dev/null +++ b/assets/js/e3c4fe0a.bf2b73e2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9428],{503:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=i(4848),s=i(8453);const o={},a="FieldDoubleInit",r={id:"detectors/FieldDoubleInit",title:"FieldDoubleInit",description:"A detector that highlights cases where a field is initialized both in the",source:"@site/versioned_docs/version-0.3.0/detectors/FieldDoubleInit.md",sourceDirName:"detectors",slug:"/detectors/FieldDoubleInit",permalink:"/tools/misti/docs/0.3.0/detectors/FieldDoubleInit",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/FieldDoubleInit.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpIsUsed",permalink:"/tools/misti/docs/0.3.0/detectors/DumpIsUsed"},next:{title:"InheritedStateMutation",permalink:"/tools/misti/docs/0.3.0/detectors/InheritedStateMutation"}},d={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"fielddoubleinit",children:"FieldDoubleInit"}),"\n",(0,n.jsxs)(t.p,{children:["A detector that highlights cases where a field is initialized both in the\n",(0,n.jsx)(t.code,{children:"init"})," function and at the point of definition."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["Double initialization of fields can either be a programmer's mistake or simply\na waste of gas. It is always preferred to initialize values in the field declaration\nif they have a compile-time evaluatable default value, or in the ",(0,n.jsx)(t.code,{children:"init"})," function if\nthey must be initialized dynamically."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int = 0; // Bad\n init(x: Int) { self.a = x }\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int; // Fixed\n init(x: Int) { self.a = x }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>a,x:()=>r});var n=i(6540);const s={},o=n.createContext(s);function a(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e4a43c7d.d2da82aa.js b/assets/js/e4a43c7d.d2da82aa.js new file mode 100644 index 000000000..1ac0722a8 --- /dev/null +++ b/assets/js/e4a43c7d.d2da82aa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7348],{3888:(e,s,t)=>{t.r(s),t.d(s,{default:()=>o});t(6540);var i=t(781);const r={heroBanner:"heroBanner_hAhw",buttons:"buttons_YgGx"};var c=t(4848);function o(){return(0,c.jsxs)(i.A,{title:"Welcome to Misti",description:"The TON Static Analyzer",children:[(0,c.jsxs)("header",{className:r.heroBanner,children:[(0,c.jsx)("h1",{className:r.heroTitle,children:"Welcome to Misti"}),(0,c.jsxs)("p",{className:r.heroSubtitle,children:["The tool for static analysis in the ",(0,c.jsx)("a",{href:"https://ton.org/",children:"TON"})," ecosystem."]}),(0,c.jsx)("div",{className:r.buttons,children:(0,c.jsx)("a",{className:"button button--primary button--lg",href:"/tools/misti/docs/",children:"Get Started"})})]}),(0,c.jsxs)("main",{children:[(0,c.jsx)("section",{className:r.features,children:(0,c.jsx)("div",{className:"container",children:(0,c.jsxs)("div",{className:"row",children:[(0,c.jsxs)("div",{className:"col col--4",children:[(0,c.jsx)("h2",{children:"\ud83d\udd12 Detect Code Issues"}),(0,c.jsxs)("p",{children:["Identify and fix potential ",(0,c.jsx)("a",{href:"/tools/misti/docs/detectors",children:"security flaws and code problems"})," early in the development cycle."]})]}),(0,c.jsxs)("div",{className:"col col--4",children:[(0,c.jsx)("h2",{children:"\u2699\ufe0f Streamline Development"}),(0,c.jsxs)("p",{children:[(0,c.jsx)("a",{href:"/tools/misti/docs/tutorial/ci-cd",children:"Integrate"})," Misti into your CI/CD pipeline to ensure continuous code quality checks."]})]}),(0,c.jsxs)("div",{className:"col col--4",children:[(0,c.jsx)("h2",{children:"\ud83d\udee0\ufe0f Custom Detectors"}),(0,c.jsxs)("p",{children:["Create ",(0,c.jsx)("a",{href:"/tools/misti/docs/hacking/custom-detector",children:"custom detectors"})," to solve specific problems in your code or to provide a thorough security review if you are an auditor."]})]})]})})}),(0,c.jsx)("section",{children:(0,c.jsx)("div",{className:"container",style:{textAlign:"right",marginTop:"30px"},children:(0,c.jsx)("div",{className:"row",children:(0,c.jsx)("div",{className:"col col--12",children:(0,c.jsxs)("p",{children:["\ud83d\udcac ",(0,c.jsx)("strong",{children:"Need more?"})," Reach me out:\xa0",(0,c.jsx)("a",{href:"https://t.me/jubnzv",target:"_blank",rel:"noopener noreferrer",children:"@jubnzv"})]})})})})})]})]})}}}]); \ No newline at end of file diff --git a/assets/js/e5aa38d8.17e7d0ef.js b/assets/js/e5aa38d8.17e7d0ef.js new file mode 100644 index 000000000..d420580b0 --- /dev/null +++ b/assets/js/e5aa38d8.17e7d0ef.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4082],{7817:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var n=s(4848),i=s(8453);const o={},d="DumpIsUsed",r={id:"detectors/DumpIsUsed",title:"DumpIsUsed",description:"An optional detector that highlights all the dump function calls.",source:"@site/versioned_docs/version-0.3.0/detectors/DumpIsUsed.md",sourceDirName:"detectors",slug:"/detectors/DumpIsUsed",permalink:"/tools/misti/docs/0.3.0/detectors/DumpIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/DumpIsUsed.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"DivideBeforeMultiply",permalink:"/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply"},next:{title:"FieldDoubleInit",permalink:"/tools/misti/docs/0.3.0/detectors/FieldDoubleInit"}},c={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function a(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"dumpisused",children:"DumpIsUsed"}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"dump"})," function calls."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"dump"})," function is a debug print that shouldn't be in the final code.\nEven though the compiler removes it in production, its presence suggests the\ndeveloper was debugging something. This can flag areas where issues might exist,\nso auditors should take a closer look at these parts of the code."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = (RANDOM_SEED >> half_shift) &\n (MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;\n dump(combined); // Suspicious: Highlighted by the detector\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = this.seed ^ shift_mask\n // OK: The code was reviewed and simplified; `dump` was removed\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(a,{...e})}):a(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>d,x:()=>r});var n=s(6540);const i={},o=n.createContext(i);function d(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e63578c3.6cc338fe.js b/assets/js/e63578c3.6cc338fe.js new file mode 100644 index 000000000..af9666219 --- /dev/null +++ b/assets/js/e63578c3.6cc338fe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9641],{7717:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var t=n(4848),s=n(8453);const o={},r="Configuration",l={id:"tutorial/configuration",title:"Configuration",description:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.",source:"@site/versioned_docs/version-0.3.0/tutorial/configuration.md",sourceDirName:"tutorial",slug:"/tutorial/configuration",permalink:"/tools/misti/docs/0.3.0/tutorial/configuration",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/tutorial/configuration.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Command-Line Interface",permalink:"/tools/misti/docs/0.3.0/tutorial/cli"},next:{title:"Using with Blueprint",permalink:"/tools/misti/docs/0.3.0/tutorial/blueprint"}},a={},c=[{value:"Configuration Options",id:"configuration-options",level:3},{value:"Running Misti with Configuration",id:"running-misti-with-configuration",level:2},{value:"Default Configuration File",id:"default-configuration-file",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const i={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(i.h1,{id:"configuration",children:"Configuration"}),"\n",(0,t.jsx)(i.p,{children:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set."}),"\n",(0,t.jsx)(i.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"detectors"}),": List of detectors to run. Each detector can be specified with a ",(0,t.jsx)(i.code,{children:"className"})," and optionally a ",(0,t.jsx)(i.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,t.jsxs)(i.ul,{children:["\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,t.jsxs)(i.li,{children:[(0,t.jsx)(i.strong,{children:"modulePath"})," (string, optional): The file path of the detector module."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"ignoredProjects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"soufflePath"})," (string, optional): Directory to save generated Souffl\xe9 files which is helpful for debugging purposes. If not set, a temporary directory will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"souffleVerbose"})," (boolean, optional): If set, generates more readable Souffl\xe9 files instead of making the result source code smaller."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"tactStdlibPath"})," (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used."]}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"unusedPrefix"}),' (string, default: "_"): Identifiers starting with this prefix won\'t be reported as unused by built-in detectors.']}),"\n"]}),"\n",(0,t.jsxs)(i.li,{children:["\n",(0,t.jsxs)(i.p,{children:[(0,t.jsx)(i.strong,{children:"verbosity"})," (string, optional): Verbosity level of the logs. Possible values are ",(0,t.jsx)(i.code,{children:"quiet"}),", ",(0,t.jsx)(i.code,{children:"debug"}),", and ",(0,t.jsx)(i.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(i.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,t.jsx)(i.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsx)(i.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,t.jsx)(i.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,t.jsx)(i.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-json",children:'{\n "detectors": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n { "className": "BranchDuplicate" },\n { "className": "FieldDoubleInit" },\n { "className": "PreferAugmentedAssign" },\n { "className": "StringReceiversOverlap" },\n { "className": "ArgCopyMutation" }\n ],\n "ignoredProjects": [],\n "soufflePath": "/tmp/misti/souffle",\n "souffleVerbose": false,\n "unusedPrefix": "_",\n "verbosity": "default"\n}\n'})}),"\n",(0,t.jsxs)(i.p,{children:["All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,t.jsxs)(i.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,t.jsx)(i.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,t.jsx)(i.pre,{children:(0,t.jsx)(i.code,{className:"language-bash",children:"npx misti --dump-config test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsxs)(i.p,{children:["If there is no Misti config in the ",(0,t.jsx)(i.code,{children:"simple"})," directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors."]}),"\n",(0,t.jsx)(i.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,t.jsxs)(i.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,t.jsx)(i.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,t.jsx)(i.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function u(e={}){const{wrapper:i}={...(0,s.R)(),...e.components};return i?(0,t.jsx)(i,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>r,x:()=>l});var t=n(6540);const s={},o=t.createContext(s);function r(e){const i=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e6ef21e7.de959db6.js b/assets/js/e6ef21e7.de959db6.js new file mode 100644 index 000000000..9226e822d --- /dev/null +++ b/assets/js/e6ef21e7.de959db6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4984],{1053:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>d,toc:()=>a});var i=n(4848),o=n(8453);const s={},r="DuplicatedCondition",d={id:"detectors/DuplicatedCondition",title:"DuplicatedCondition",description:"A detector that finds duplicated conditions appearing in conditional expressions.",source:"@site/versioned_docs/version-0.4.0/detectors/DuplicatedCondition.md",sourceDirName:"detectors",slug:"/detectors/DuplicatedCondition",permalink:"/tools/misti/docs/detectors/DuplicatedCondition",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/DuplicatedCondition.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpIsUsed",permalink:"/tools/misti/docs/detectors/DumpIsUsed"},next:{title:"EnsurePrgSeed",permalink:"/tools/misti/docs/detectors/EnsurePrgSeed"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"duplicatedcondition",children:"DuplicatedCondition"}),"\n",(0,i.jsx)(t.p,{children:"A detector that finds duplicated conditions appearing in conditional expressions."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsx)(t.p,{children:"Typically, these cases are developer errors caused by copy-pasting code, leading\nto unreachable code."}),"\n",(0,i.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"fun test(a: Int): Int {\n if (a < 1) { return 1; }\n else if (a > 4) { return 2; }\n // Bad: A developer copy-pasted the condition\n else if (a > 4) { return 3; }\n return 4;\n}\n"})}),"\n",(0,i.jsx)(t.p,{children:"Use instead:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tact",children:"fun test(a: Int): Int {\n if (a < 1) { return 1; }\n else if (a > 4) { return 2; }\n // OK: Fixed\n else if (a < x) { return 3; }\n return 4;\n}\n"})})]})}function p(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>d});var i=n(6540);const o={},s=i.createContext(o);function r(e){const t=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:r(e.components),i.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e9524270.4f13728a.js b/assets/js/e9524270.4f13728a.js new file mode 100644 index 000000000..3ab8f0c17 --- /dev/null +++ b/assets/js/e9524270.4f13728a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2167],{7019:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>a,toc:()=>l});var i=n(4848),s=n(8453);const o={},r="Integrating Misti into CI/CD",a={id:"tutorial/ci-cd",title:"Integrating Misti into CI/CD",description:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.",source:"@site/docs/tutorial/ci-cd.md",sourceDirName:"tutorial",slug:"/tutorial/ci-cd",permalink:"/tools/misti/docs/next/tutorial/ci-cd",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tutorial/ci-cd.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Getting Started",permalink:"/tools/misti/docs/next/tutorial/getting-started"},next:{title:"Command-Line Interface",permalink:"/tools/misti/docs/next/tutorial/cli"}},c={},l=[{value:"Using Tact Template",id:"using-tact-template",level:2},{value:"GitHub Actions",id:"github-actions",level:2},{value:"Integration with Blueprint Projects",id:"integration-with-blueprint-projects",level:2}];function u(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,s.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"integrating-misti-into-cicd",children:"Integrating Misti into CI/CD"}),"\n",(0,i.jsx)(e.p,{children:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle."}),"\n",(0,i.jsx)(e.h2,{id:"using-tact-template",children:"Using Tact Template"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:"https://github.com/tact-lang/tact-template",children:(0,i.jsx)(e.code,{children:"tact-template"})})," is a template project for Tact. If you started your project from this template, Misti is already installed in ",(0,i.jsx)(e.a,{href:"https://github.com/tact-lang/tact-template/tree/main/.github/workflows",children:"the CI"}),". You also have the ",(0,i.jsx)(e.code,{children:"yarn lint"})," command available in your ",(0,i.jsx)(e.code,{children:"package.json"}),"."]}),"\n",(0,i.jsx)(e.h2,{id:"github-actions",children:"GitHub Actions"}),"\n",(0,i.jsx)(e.p,{children:"To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:"}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"1. Open your GitHub repository"})}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"2. Create or edit the GitHub Actions workflow YAML file"})}),"\n",(0,i.jsxs)(e.p,{children:["It could be located at e.g., ",(0,i.jsx)(e.code,{children:".github/workflows/ci.yml"}),"."]}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"3. Add the step to run Misti to your YAML file"})}),"\n",(0,i.jsx)(e.p,{children:"For example:"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-yaml",children:'name: CI\n\non:\n push:\n branches: [ "main" ]\n pull_request:\n branches: [ "main" ]\n workflow_dispatch:\n\njobs:\n test:\n strategy:\n fail-fast: false\n matrix:\n node-version: [22]\n os: [ubuntu-latest]\n runs-on: ${{ matrix.os }}\n steps:\n - name: Checkout code\n uses: actions/checkout@v2\n\n - name: Install Souffl\xe9 on Ubuntu\n if: matrix.os == \'ubuntu-latest\'\n run: |\n sudo wget https://souffle-lang.github.io/ppa/souffle-key.public -O /usr/share/keyrings/souffle-archive-keyring.gpg\n echo "deb [signed-by=/usr/share/keyrings/souffle-archive-keyring.gpg] https://souffle-lang.github.io/ppa/ubuntu/ stable main" | sudo tee /etc/apt/sources.list.d/souffle.list\n sudo apt update\n sudo apt install souffle\n\n - name: Setup Node.js\n uses: actions/setup-node@v3\n with:\n node-version: ${{ matrix.node-version }}\n\n - name: Install dependencies\n run: yarn install\n\n - name: Run Misti\n run: yarn misti --min-severity medium /path/to/your/tact.config.json\n'})}),"\n",(0,i.jsxs)(e.p,{children:["The ",(0,i.jsx)(e.code,{children:"yarn misti --min-severity medium /path/to/your/tact.config.json"})," command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail."]}),"\n",(0,i.jsxs)(e.p,{children:["The ",(0,i.jsx)(e.code,{children:"--min-severity medium"})," will filter out low-priority warnings. You can always run Misti with all the detectors enabled locally in order to get the most comprehensive warnings output: ",(0,i.jsx)(e.code,{children:"yarn misti --all-detectors /path/to/your/tact.config.json"})]}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"4. Adjusting the Misti Configuration"})}),"\n",(0,i.jsxs)(e.p,{children:["If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the ",(0,i.jsx)(e.a,{href:"./configuration",children:"Configuration"})," section for more details on how to customize your settings."]}),"\n",(0,i.jsx)(e.h2,{id:"integration-with-blueprint-projects",children:"Integration with Blueprint Projects"}),"\n",(0,i.jsx)(e.p,{children:"To add Misti to the CI for your Blueprint project, follow these steps:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.a,{href:"/tools/misti/docs/next/tutorial/blueprint",children:["Install ",(0,i.jsx)(e.code,{children:"blueprint-misti"})]}),"."]}),"\n",(0,i.jsxs)(e.li,{children:["Follow the steps to set up the GitHub action above, but replace the ",(0,i.jsx)(e.code,{children:"yarn misti"})," command with ",(0,i.jsx)(e.code,{children:"npx blueprint misti --blueprint-project <PROJECT_NAME>"}),", where ",(0,i.jsx)(e.code,{children:"<PROJECT_NAME>"})," is the name of the project displayed when you run ",(0,i.jsx)(e.code,{children:"npx blueprint build"}),"."]}),"\n"]})]})}function d(t={}){const{wrapper:e}={...(0,s.R)(),...t.components};return e?(0,i.jsx)(e,{...t,children:(0,i.jsx)(u,{...t})}):u(t)}},8453:(t,e,n)=>{n.d(e,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(t){const e=i.useContext(o);return i.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function a(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(s):t.components||s:r(t.components),i.createElement(o.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/ea064c97.7b1162bd.js b/assets/js/ea064c97.7b1162bd.js new file mode 100644 index 000000000..1466f9c16 --- /dev/null +++ b/assets/js/ea064c97.7b1162bd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5508],{3195:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>c});var n=s(4848),i=s(8453);const o={},r="AsmIsUsed",a={id:"detectors/AsmIsUsed",title:"AsmIsUsed",description:"An optional detector that highlights all the asm functions.",source:"@site/versioned_docs/version-0.4.0/detectors/AsmIsUsed.md",sourceDirName:"detectors",slug:"/detectors/AsmIsUsed",permalink:"/tools/misti/docs/detectors/AsmIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/AsmIsUsed.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"ArgCopyMutation",permalink:"/tools/misti/docs/detectors/ArgCopyMutation"},next:{title:"BranchDuplicate",permalink:"/tools/misti/docs/detectors/BranchDuplicate"}},d={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"asmisused",children:"AsmIsUsed"}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"asm"})," functions."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Using TVM Assembly is a potentially dangerous operation that requires additional\nattention from an auditor. This optional detector will highlight all its uses to\nassist in contract security audits."}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"// Highlighted: the asm function use should be audited\nasm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE }\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>r,x:()=>a});var n=s(6540);const i={},o=n.createContext(i);function r(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ea8d0df0.a9834690.js b/assets/js/ea8d0df0.a9834690.js new file mode 100644 index 000000000..0a0844603 --- /dev/null +++ b/assets/js/ea8d0df0.a9834690.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[335],{4905:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>a,contentTitle:()=>c,default:()=>l,frontMatter:()=>r,metadata:()=>s,toc:()=>d});var i=n(4848),o=n(8453);const r={},c="Custom Detector Guide",s={id:"hacking/custom-detector",title:"Custom Detector Guide",description:"Introduction",source:"@site/docs/hacking/custom-detector.md",sourceDirName:"hacking",slug:"/hacking/custom-detector",permalink:"/tools/misti/docs/next/hacking/custom-detector",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/hacking/custom-detector.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Developing Misti",permalink:"/tools/misti/docs/next/hacking/developing-misti"}},a={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Creating a Detector",id:"creating-a-detector",level:2},{value:"Testing the detector",id:"testing-the-detector",level:3},{value:"Saving the configuration",id:"saving-the-configuration",level:3},{value:"Example Detectors",id:"example-detectors",level:2}];function h(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,o.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"custom-detector-guide",children:"Custom Detector Guide"}),"\n",(0,i.jsx)(e.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsxs)(e.p,{children:["Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: ",(0,i.jsx)(e.a,{href:"https://nowarp.io/tools/misti/api/",children:"Misti API Reference"}),"."]}),"\n",(0,i.jsxs)(e.p,{children:["Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the ",(0,i.jsx)(e.a,{href:"https://nowarp.io/tools/misti/api/classes/detectors_detector.Detector.html",children:(0,i.jsx)(e.code,{children:"Detector"})})," interface."]}),"\n",(0,i.jsx)(e.h2,{id:"creating-a-detector",children:"Creating a Detector"}),"\n",(0,i.jsxs)(e.p,{children:["You can create a new custom detector by executing Misti with the ",(0,i.jsx)(e.code,{children:"--new-detector"})," option: ",(0,i.jsx)(e.code,{children:"npx misti --new-detector implicitInit"}),"."]}),"\n",(0,i.jsxs)(e.p,{children:["This will create the ",(0,i.jsx)(e.code,{children:"implicitInit.ts"})," file, which contains the template code for writing your own custom detector logic leveraging the Misti API."]}),"\n",(0,i.jsx)(e.p,{children:"Here's an example of how to implement a custom detector using Misti API:"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-typescript",children:'import { ASTDetector } from "@nowarp/misti/dist/detectors/detector";\nimport { CompilationUnit } from "@nowarp/misti/dist/internals/ir";\nimport {\n MistiTactWarning,\n Severity,\n} from "@nowarp/misti/dist/internals/errors";\n\n/**\n * An example of a custom detector that showcases the usage of the detector API.\n *\n * It reports all the contracts that doesn\'t have an explicit implementation of the init function.\n */\nexport class ImplicitInit extends ASTDetector {\n severity = Severity.INFO;\n\n async check(cu: CompilationUnit): Promise<MistiTactWarning[]> {\n return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {\n if (!cu.findMethodCFGByName(contract.name, "init")) {\n const err = this.makeWarning(\n `Contract ${contract.name} doesn\'t define an init function`,\n contract.ref,\n );\n foundErrors.push(err);\n }\n return foundErrors;\n }, [] as MistiTactWarning[]);\n }\n}\n\n'})}),"\n",(0,i.jsx)(e.h3,{id:"testing-the-detector",children:"Testing the detector"}),"\n",(0,i.jsxs)(e.p,{children:["To run Misti with only your new detector, use the ",(0,i.jsx)(e.code,{children:"--detectors"})," option, specifying the path to the detector and the Detector class name: ",(0,i.jsx)(e.code,{children:"npx misti path/to/your/tact.config.json --detectors path/to/implicitInit.ts:ImplicitInit"}),"."]}),"\n",(0,i.jsxs)(e.p,{children:["That's a good way to test the detector on the first run. You could also use the ",(0,i.jsx)(e.code,{children:"--verbose"})," CLI option and set the environment variable ",(0,i.jsx)(e.code,{children:"MISTI_TRACE=1"})," to facilitate debugging."]}),"\n",(0,i.jsx)(e.h3,{id:"saving-the-configuration",children:"Saving the configuration"}),"\n",(0,i.jsx)(e.p,{children:"After testing the detector, you can specify it in your configuration to enable it in future runs. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{children:'{\n "detectors": [\n // Other detectors...\n { "className": "ImplicitInit", "modulePath": "ImplicitInit.ts" }\n ],\n}\n'})}),"\n",(0,i.jsxs)(e.p,{children:["After this, you could run Misti specifying a path to a custom configuration ",(0,i.jsx)(e.code,{children:"npx misti --config path/to/misti.config.json path/to/your/tact.config.json"}),"."]}),"\n",(0,i.jsx)(e.h2,{id:"example-detectors",children:"Example Detectors"}),"\n",(0,i.jsxs)(e.p,{children:["The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the ",(0,i.jsx)(e.a,{href:"https://github.com/nowarp/misti/tree/master/examples",children:"examples directory"})," in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors."]})]})}function l(t={}){const{wrapper:e}={...(0,o.R)(),...t.components};return e?(0,i.jsx)(e,{...t,children:(0,i.jsx)(h,{...t})}):h(t)}},8453:(t,e,n)=>{n.d(e,{R:()=>c,x:()=>s});var i=n(6540);const o={},r=i.createContext(o);function c(t){const e=i.useContext(r);return i.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function s(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(o):t.components||o:c(t.components),i.createElement(r.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/ebcc9167.b433e15d.js b/assets/js/ebcc9167.b433e15d.js new file mode 100644 index 000000000..d96ecde6a --- /dev/null +++ b/assets/js/ebcc9167.b433e15d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6387],{4416:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>o,toc:()=>d});var s=n(4848),r=n(8453);const a={},i="NeverAccessedVariables",o={id:"detectors/NeverAccessedVariables",title:"NeverAccessedVariables",description:"A detector that identifies write-only or unused variables, fields and constants.",source:"@site/versioned_docs/version-0.3.0/detectors/NeverAccessedVariables.md",sourceDirName:"detectors",slug:"/detectors/NeverAccessedVariables",permalink:"/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/NeverAccessedVariables.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"InheritedStateMutation",permalink:"/tools/misti/docs/0.3.0/detectors/InheritedStateMutation"},next:{title:"PreferAugmentedAssign",permalink:"/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"neveraccessedvariables",children:"NeverAccessedVariables"}),"\n",(0,s.jsx)(t.p,{children:"A detector that identifies write-only or unused variables, fields and constants."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"These variables are either assigned but never used in any meaningful computation,\nor they are declared and never used at all, which may indicate redundant code\nor an incomplete implementation of the intended logic."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"// Error: the developer forgot to use the constant\nconst MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'const MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n // OK: Fixed after the analyzer highlighted this warning\n require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(6540);const r={},a=s.createContext(r);function i(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ed017323.30666872.js b/assets/js/ed017323.30666872.js new file mode 100644 index 000000000..87d17af7f --- /dev/null +++ b/assets/js/ed017323.30666872.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4138],{8065:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var t=i(4848),s=i(8453);const o={},r="Contributing Guide",c={id:"hacking/contributing",title:"Contributing Guide",description:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.",source:"@site/docs/hacking/contributing.md",sourceDirName:"hacking",slug:"/hacking/contributing",permalink:"/tools/misti/docs/next/hacking/contributing",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/hacking/contributing.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Souffl\xe9",permalink:"/tools/misti/docs/next/hacking/souffle"},next:{title:"Developing Misti",permalink:"/tools/misti/docs/next/hacking/developing-misti"}},a={},l=[{value:"Issues reporting",id:"issues-reporting",level:2},{value:"Documentation contribution",id:"documentation-contribution",level:2},{value:"Code contribution",id:"code-contribution",level:2}];function u(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"contributing-guide",children:"Contributing Guide"}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better."}),"\n",(0,t.jsx)(n.h2,{id:"issues-reporting",children:"Issues reporting"}),"\n",(0,t.jsx)(n.p,{children:"When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.\nPlease help us by publishing it and the input sources at:\nhttps://github.com/nowarp/misti/issues/new.\n"})}),"\n",(0,t.jsx)(n.p,{children:"We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users."}),"\n",(0,t.jsx)(n.h2,{id:"documentation-contribution",children:"Documentation contribution"}),"\n",(0,t.jsxs)(n.p,{children:["We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/nowarp.github.io/issues",children:"nowarp.github.io Issues"}),". Additionally, many documentation pages have an ",(0,t.jsx)(n.code,{children:"Edit"})," button that allows you to make direct contributions easily."]}),"\n",(0,t.jsx)(n.h2,{id:"code-contribution",children:"Code contribution"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Navigate Issues and Find Tasks"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Browse the issues ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"here"}),". Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues."]}),"\n",(0,t.jsx)(n.li,{children:"Choose an issue suitable for you and mention in the issue that you're working on it."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Implement Your Changes"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Implement your changes. Feel free to ask questions in the issue if needed."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Ensure Tests Pass"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Before creating a PR, make sure all tests and CI checks are passing by running:","\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn test-all\n"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Create a PR"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Submit your pull request ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/pulls",children:"here"})]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Add a CHANGELOG entry"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Describe your changes in the ",(0,t.jsx)(n.code,{children:"CHANGELOG.md"})," file according to the existing structure."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["See ",(0,t.jsx)(n.a,{href:"/tools/misti/docs/next/hacking/developing-misti",children:"Developing Misti"})," for information about initializing the environment and additional hacking tips."]}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your contributions!"})]})}function d(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(u,{...e})}):u(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>c});var t=i(6540);const s={},o=t.createContext(s);function r(e){const n=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ed2e6971.1441e217.js b/assets/js/ed2e6971.1441e217.js new file mode 100644 index 000000000..3a08a31a2 --- /dev/null +++ b/assets/js/ed2e6971.1441e217.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8300],{8315:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>u,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=n(4848),o=n(8453);const i={},a="UnusedOptional",r={id:"detectors/UnusedOptional",title:"UnusedOptional",description:"A detector variables and fields with unused optional modifier.",source:"@site/docs/detectors/UnusedOptional.md",sourceDirName:"detectors",slug:"/detectors/UnusedOptional",permalink:"/tools/misti/docs/next/detectors/UnusedOptional",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/UnusedOptional.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"UnboundLoops",permalink:"/tools/misti/docs/next/detectors/UnboundLoops"},next:{title:"ZeroAddress",permalink:"/tools/misti/docs/next/detectors/ZeroAddress"}},d={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"unusedoptional",children:"UnusedOptional"}),"\n",(0,s.jsx)(t.p,{children:"A detector variables and fields with unused optional modifier."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"Optional"})," is a nullable value that has a special ",(0,s.jsx)(t.code,{children:"null"})," value indicating the absence\nof a value. If a developer creates an optional variable or field, he should leverage\nits functionality by accessing the ",(0,s.jsx)(t.code,{children:"null"})," value somewhere in his code. Otherwise,\nthe optional type should be removed to simplify and optimize the code."]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int?; // Bad: null value is never accessed\n init() { self.a = 42; }\n get fun getA(): Int { return self.a!!; }\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int = 42; // OK: Removed optional\n get fun getA(): Int { return self.a; }\n}\n"})})]})}function u(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>a,x:()=>r});var s=n(6540);const o={},i=s.createContext(o);function a(e){const t=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:a(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/edf1e52e.7e8e467f.js b/assets/js/edf1e52e.7e8e467f.js new file mode 100644 index 000000000..76349e9da --- /dev/null +++ b/assets/js/edf1e52e.7e8e467f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3434],{3744:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),a=n(8453);const r={},i="Never-accessed Variables",o={id:"detectors/NeverAccessedVariables",title:"Never-accessed Variables",description:"A detector that identifies write-only or unused variables, fields and constants.",source:"@site/versioned_docs/version-0.1.2/detectors/NeverAccessedVariables.md",sourceDirName:"detectors",slug:"/detectors/NeverAccessedVariables",permalink:"/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/detectors/NeverAccessedVariables.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Divide before Multiply",permalink:"/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply"},next:{title:"Read-only Variables",permalink:"/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"never-accessed-variables",children:"Never-accessed Variables"}),"\n",(0,s.jsx)(t.p,{children:"A detector that identifies write-only or unused variables, fields and constants."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"These variables are either assigned but never used in any meaningful computation,\nor they are declared and never used at all, which may indicate redundant code\nor an incomplete implementation of the intended logic."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"// Error: the developer forgot to use the constant\nconst MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'const MAX_SUPPLY: Int = 1000;\n\nfun mint(to: Address, amount: Int) {\n // OK: Fixed after the linter highlighted this warning\n require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");\n balances.set(to, balances.get(to)!! + amount);\n totalSupply += amount;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>o});var s=n(6540);const a={},r=s.createContext(a);function i(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:i(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/effcc73a.68126485.js b/assets/js/effcc73a.68126485.js new file mode 100644 index 000000000..fe7c17937 --- /dev/null +++ b/assets/js/effcc73a.68126485.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[485],{968:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>f});var t=i(4848),r=i(8453);const s={},a="Souffl\xe9 Integration Guide",o={id:"hacking/souffle",title:"Souffl\xe9 Integration Guide",description:"What is Souffl\xe9?",source:"@site/versioned_docs/version-0.4.0/hacking/souffle.md",sourceDirName:"hacking",slug:"/hacking/souffle",permalink:"/tools/misti/docs/hacking/souffle",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/hacking/souffle.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Design Overview",permalink:"/tools/misti/docs/hacking/design"},next:{title:"Custom Detectors",permalink:"/tools/misti/docs/hacking/custom-detector"}},l={},f=[{value:"What is Souffl\xe9?",id:"what-is-souffl\xe9",level:2},{value:"Benefits of Using Souffl\xe9 for Static Analysis",id:"benefits-of-using-souffl\xe9-for-static-analysis",level:2},{value:"Souffl\xe9 Integration in Misti",id:"souffl\xe9-integration-in-misti",level:2},{value:"Creating Souffl\xe9 Programs",id:"creating-souffl\xe9-programs",level:3},{value:"Generating Facts and Executing Souffl\xe9",id:"generating-facts-and-executing-souffl\xe9",level:3},{value:"Learning from Existing Code",id:"learning-from-existing-code",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"souffl\xe9-integration-guide",children:"Souffl\xe9 Integration Guide"}),"\n",(0,t.jsx)(n.h2,{id:"what-is-souffl\xe9",children:"What is Souffl\xe9?"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io",children:"Souffl\xe9"})," is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Souffl\xe9, Misti can perform deep and scalable analyses of smart contracts."]}),"\n",(0,t.jsx)(n.h2,{id:"benefits-of-using-souffl\xe9-for-static-analysis",children:"Benefits of Using Souffl\xe9 for Static Analysis"}),"\n",(0,t.jsx)(n.p,{children:"Souffl\xe9 allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Souffl\xe9 program might be more straightforward then implementing a complex transfer function in for a classic monotone framework."}),"\n",(0,t.jsx)(n.h2,{id:"souffl\xe9-integration-in-misti",children:"Souffl\xe9 Integration in Misti"}),"\n",(0,t.jsxs)(n.p,{children:["The API for interacting with Souffl\xe9 in Misti is implemented in the ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/souffle.js",children:"Souffle.js library"}),". See the ",(0,t.jsx)(n.a,{href:"https://nowarp.io/lib/souffle-js/api/",children:"Souffle.js API reference"})," for more detailed information."]}),"\n",(0,t.jsx)(n.h3,{id:"creating-souffl\xe9-programs",children:"Creating Souffl\xe9 Programs"}),"\n",(0,t.jsx)(n.p,{children:'To create a Souffl\xe9 program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:'}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addDecls(ctx: Context<SrcInfo>) {\n ctx.add(\n Relation.from(\n "varDecl",\n [\n ["var", FactType.Symbol],\n ["func", FactType.Symbol],\n ],\n undefined,\n ),\n );\n // other declarations\n}\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addRules(ctx: Context<SrcInfo>) {\n // readOnly(var, func) :-\n // varDecl(var, func),\n // !varAssign(var, func),\n // !varUse(var, func).\n ctx.add(\n Rule.from(\n [makeAtom("readOnly", ["var", "func"])],\n makeRuleBody(makeAtom("varDecl", ["var", "func"])),\n makeRuleBody(makeAtom("varAssign", ["var", "func"]), {\n negated: true,\n }),\n makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),\n ),\n );\n }\n'})}),"\n",(0,t.jsx)(n.h3,{id:"generating-facts-and-executing-souffl\xe9",children:"Generating Facts and Executing Souffl\xe9"}),"\n",(0,t.jsx)(n.p,{children:"After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Souffl\xe9 executor to run the analysis:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"const executor = ctx.config.soufflePath\n ? new Executor<SrcInfo>({\n inputDir: ctx.config.soufflePath,\n outputDir: ctx.config.soufflePath,\n })\n : new Executor<SrcInfo>();\n\nconst result = executor.executeSync(program);\n\nif (!result.success) {\n throw new Error(\n `Error executing Souffl\xe9 for ${this.id}:\\n${result.stderr}`,\n );\n}\n\nconst warnings = Array.from(result.results.entries.values()).map((fact) => {\n // raise warnings\n});\n"})}),"\n",(0,t.jsx)(n.h3,{id:"learning-from-existing-code",children:"Learning from Existing Code"}),"\n",(0,t.jsx)(n.p,{children:"We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Souffl\xe9 with Misti. This will help you understand the intricacies of generating IR and executing Souffl\xe9 programs effectively."}),"\n",(0,t.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,t.jsxs)(n.p,{children:["For a deeper understanding of static analysis using Souffl\xe9, refer to the textbook ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.a,{href:"https://arxiv.org/pdf/2012.10086",children:"Program Analysis: An Appetizer"})})," by Flemming Nielson and Hanne Riis Nielson. It discusses Souffl\xe9-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field."]})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>a,x:()=>o});var t=i(6540);const r={},s=t.createContext(r);function a(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f18c7db7.502a736a.js b/assets/js/f18c7db7.502a736a.js new file mode 100644 index 000000000..31515d8ef --- /dev/null +++ b/assets/js/f18c7db7.502a736a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9959],{4172:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>n,metadata:()=>c,toc:()=>l});var s=r(4848),i=r(8453);const n={id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},o="Detectors Overview",c={id:"detectors",title:"Detectors Overview",description:"Here's a list of all the detectors:",source:"@site/versioned_docs/version-0.2.0/detectors.md",sourceDirName:".",slug:"/detectors",permalink:"/tools/misti/docs/0.2.0/detectors",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/detectors.md",tags:[],version:"0.2.0",frontMatter:{id:"detectors",title:"Detectors Overview",sidebar_label:"Detectors Overview"},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/tools/misti/docs/0.2.0/tutorial/configuration"},next:{title:"Divide before Multiply",permalink:"/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply"}},d={},l=[];function a(e){const t={a:"a",code:"code",h1:"h1",li:"li",p:"p",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"detectors-overview",children:"Detectors Overview"}),"\n",(0,s.jsx)(t.p,{children:"Here's a list of all the detectors:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/DivideBeforeMultiply",children:"Divide before Multiply"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/NeverAccessedVariables",children:"Never-accessed Variables"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/ReadOnlyVariables",children:"Read-only Variables"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/UnboundLoops",children:"Unbound Loops"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/ZeroAddress",children:"Zero Address"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/ConstantAddress",children:"Constant Address"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/BranchDuplicate",children:"Branch Duplicate"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsxs)(t.a,{href:"./detectors/DumpIsUsed",children:[(0,s.jsx)(t.code,{children:"dump"})," Is Used"]})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/FieldDoubleInit",children:"Field Initialized Twice"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"./detectors/PreferAugmentedAssign",children:"Prefer Augmented Assignment"})}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"Each detector is designed to catch specific issues in your code. Click on any of them to learn more."})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},8453:(e,t,r)=>{r.d(t,{R:()=>o,x:()=>c});var s=r(6540);const i={},n=s.createContext(i);function o(e){const t=s.useContext(n);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(n.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f2bdb0f5.256a666a.js b/assets/js/f2bdb0f5.256a666a.js new file mode 100644 index 000000000..43a72c0ff --- /dev/null +++ b/assets/js/f2bdb0f5.256a666a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8836],{1582:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>u,frontMatter:()=>s,metadata:()=>o,toc:()=>f});var t=i(4848),r=i(8453);const s={},a="Souffl\xe9 Integration Guide",o={id:"hacking/souffle",title:"Souffl\xe9 Integration Guide",description:"What is Souffl\xe9?",source:"@site/versioned_docs/version-0.2.1/hacking/souffle.md",sourceDirName:"hacking",slug:"/hacking/souffle",permalink:"/tools/misti/docs/0.2.1/hacking/souffle",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/hacking/souffle.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Design Overview",permalink:"/tools/misti/docs/0.2.1/hacking/design"},next:{title:"Tools",permalink:"/tools/misti/docs/0.2.1/hacking/tools"}},l={},f=[{value:"What is Souffl\xe9?",id:"what-is-souffl\xe9",level:2},{value:"Benefits of Using Souffl\xe9 for Static Analysis",id:"benefits-of-using-souffl\xe9-for-static-analysis",level:2},{value:"Souffl\xe9 Integration in Misti",id:"souffl\xe9-integration-in-misti",level:2},{value:"Creating Souffl\xe9 Programs",id:"creating-souffl\xe9-programs",level:3},{value:"Generating Facts and Executing Souffl\xe9",id:"generating-facts-and-executing-souffl\xe9",level:3},{value:"Learning from Existing Code",id:"learning-from-existing-code",level:3},{value:"Further Reading",id:"further-reading",level:2}];function c(e){const n={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"souffl\xe9-integration-guide",children:"Souffl\xe9 Integration Guide"}),"\n",(0,t.jsx)(n.h2,{id:"what-is-souffl\xe9",children:"What is Souffl\xe9?"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://souffle-lang.github.io",children:"Souffl\xe9"})," is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Souffl\xe9, Misti can perform deep and scalable analyses of smart contracts."]}),"\n",(0,t.jsx)(n.h2,{id:"benefits-of-using-souffl\xe9-for-static-analysis",children:"Benefits of Using Souffl\xe9 for Static Analysis"}),"\n",(0,t.jsx)(n.p,{children:"Souffl\xe9 allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Souffl\xe9 program might be more straightforward then implementing a complex transfer function in for a classic monotone framework."}),"\n",(0,t.jsx)(n.h2,{id:"souffl\xe9-integration-in-misti",children:"Souffl\xe9 Integration in Misti"}),"\n",(0,t.jsxs)(n.p,{children:["The API for interacting with Souffl\xe9 in Misti is detailed ",(0,t.jsx)(n.a,{href:"https://nowarp.github.io/docs/misti/api/modules/internals_souffle.html",children:"here"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"creating-souffl\xe9-programs",children:"Creating Souffl\xe9 Programs"}),"\n",(0,t.jsx)(n.p,{children:'To create a Souffl\xe9 program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:'}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addDecls(ctx: Context<SrcInfo>) {\n ctx.add(\n Relation.from(\n "varDecl",\n [\n ["var", FactType.Symbol],\n ["func", FactType.Symbol],\n ],\n undefined,\n ),\n );\n // other declarations\n}\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:'addRules(ctx: Context<SrcInfo>) {\n // readOnly(var, func) :-\n // varDecl(var, func),\n // !varAssign(var, func),\n // !varUse(var, func).\n ctx.add(\n Rule.from(\n [makeAtom("readOnly", ["var", "func"])],\n makeRuleBody(makeAtom("varDecl", ["var", "func"])),\n makeRuleBody(makeAtom("varAssign", ["var", "func"]), {\n negated: true,\n }),\n makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),\n ),\n );\n }\n'})}),"\n",(0,t.jsx)(n.h3,{id:"generating-facts-and-executing-souffl\xe9",children:"Generating Facts and Executing Souffl\xe9"}),"\n",(0,t.jsx)(n.p,{children:"After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Souffl\xe9 executor to run the analysis:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"const executor = ctx.config.soufflePath\n ? new Executor<SrcInfo>({\n inputDir: ctx.config.soufflePath,\n outputDir: ctx.config.soufflePath,\n })\n : new Executor<SrcInfo>();\n\nconst result = executor.executeSync(program);\n\nif (!result.success) {\n throw new Error(\n `Error executing Souffl\xe9 for ${this.id}:\\n${result.stderr}`,\n );\n}\n\nconst warnings = Array.from(result.results.entries.values()).map((fact) => {\n // raise warnings\n});\n"})}),"\n",(0,t.jsx)(n.h3,{id:"learning-from-existing-code",children:"Learning from Existing Code"}),"\n",(0,t.jsx)(n.p,{children:"We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Souffl\xe9 with Misti. This will help you understand the intricacies of generating IR and executing Souffl\xe9 programs effectively."}),"\n",(0,t.jsx)(n.h2,{id:"further-reading",children:"Further Reading"}),"\n",(0,t.jsxs)(n.p,{children:["For a deeper understanding of static analysis using Souffl\xe9, refer to the textbook ",(0,t.jsx)(n.em,{children:(0,t.jsx)(n.a,{href:"https://arxiv.org/pdf/2012.10086",children:"Program Analysis: An Appetizer"})})," by Flemming Nielson and Hanne Riis Nielson. It discusses Souffl\xe9-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field."]})]})}function u(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>a,x:()=>o});var t=i(6540);const r={},s=t.createContext(r);function a(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f3297ff5.b24f1896.js b/assets/js/f3297ff5.b24f1896.js new file mode 100644 index 000000000..bb7d3e36e --- /dev/null +++ b/assets/js/f3297ff5.b24f1896.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1537],{7942:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>s,default:()=>p,frontMatter:()=>i,metadata:()=>l,toc:()=>o});var r=n(4848),a=n(8453);const i={},s="ReadOnlyVariables",l={id:"detectors/ReadOnlyVariables",title:"ReadOnlyVariables",description:"A detector that identifies read-only variables and fields.",source:"@site/docs/detectors/ReadOnlyVariables.md",sourceDirName:"detectors",slug:"/detectors/ReadOnlyVariables",permalink:"/tools/misti/docs/next/detectors/ReadOnlyVariables",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/ReadOnlyVariables.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/next/detectors/PreferredStdlibApi"},next:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/next/detectors/StringReceiversOverlap"}},d={},o=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,a.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"readonlyvariables",children:"ReadOnlyVariables"}),"\n",(0,r.jsx)(t.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"These variables could typically be replaced with constants to optimize performance.\nAlternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally."}),"\n",(0,r.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"fun calculateFinalPrice(price: Int): Int {\n // Warning: the developer uses a read-only variable that could be a constant\n let DISCOUNT_AMOUNT: Int = 10;\n return price - DISCOUNT_AMOUNT;\n}\n"})}),"\n",(0,r.jsx)(t.p,{children:"Use instead:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-tact",children:"const DISCOUNT_AMOUNT: Int = 10;\n\nfun calculateFinalPrice(price: Int): Int {\n // OK: Fixed after the analyzer highlighted this warning\n return price - DISCOUNT_AMOUNT;\n}\n"})})]})}function p(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>l});var r=n(6540);const a={},i=r.createContext(a);function s(e){const t=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),r.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f3466e67.b2bd9e44.js b/assets/js/f3466e67.b2bd9e44.js new file mode 100644 index 000000000..ae83b47cd --- /dev/null +++ b/assets/js/f3466e67.b2bd9e44.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[278],{252:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var i=n(4848),s=n(8453);const o={id:"intro",title:"Introduction",slug:"/",sidebar_position:1},r=void 0,a={id:"intro",title:"Introduction",description:"Misti is a static analysis tool designed for smart contracts on the TON blockchain.",source:"@site/versioned_docs/version-0.1.2/index.md",sourceDirName:".",slug:"/",permalink:"/tools/misti/docs/0.1.2/",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/index.md",tags:[],version:"0.1.2",sidebarPosition:1,frontMatter:{id:"intro",title:"Introduction",slug:"/",sidebar_position:1},sidebar:"sidebar",next:{title:"Getting Started",permalink:"/tools/misti/docs/0.1.2/tutorial/getting-started"}},c={},d=[{value:"Use Cases",id:"use-cases",level:2},{value:"Funding",id:"funding",level:2}];function l(e){const t={a:"a",h2:"h2",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Misti is a static analysis tool designed for smart contracts on the ",(0,i.jsx)(t.a,{href:"https://ton.org/",children:"TON blockchain"}),"."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Language Support:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://tact-lang.org/",children:"Tact"})," 1.4.1 is supported."]}),"\n",(0,i.jsxs)(t.li,{children:["Support for ",(0,i.jsx)(t.a,{href:"https://docs.ton.org/develop/func/overview",children:"FunC"})," ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/56",children:"is planned"}),"."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"use-cases",children:"Use Cases"}),"\n",(0,i.jsx)(t.p,{children:"Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Detect Vulnerabilities:"})," Identify and fix potential security flaws early in the development cycle."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Improve Code Quality:"})," Maintain high standards by catching bugs and enforcing best practices automatically."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Streamline Development:"})," Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Custom Detectors:"})," Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor."]}),"\n"]}),"\n",(0,i.jsx)(t.p,{children:"Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow."}),"\n",(0,i.jsx)(t.h2,{id:"funding",children:"Funding"}),"\n",(0,i.jsxs)(t.p,{children:["Misti has been ",(0,i.jsx)(t.a,{href:"https://github.com/ton-society/grants-and-bounties/issues/436",children:"funded"})," by ",(0,i.jsx)(t.a,{href:"https://ton.foundation",children:"TON Foundation"}),". This support has enabled us to develop and maintain the tool."]})]})}function u(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(e){const t=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f34cb5e0.b26c4fc7.js b/assets/js/f34cb5e0.b26c4fc7.js new file mode 100644 index 000000000..886ad2b7c --- /dev/null +++ b/assets/js/f34cb5e0.b26c4fc7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9337],{9385:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>a,toc:()=>d});var o=n(4848),i=n(8453);const s={},r="FalseCondition",a={id:"detectors/FalseCondition",title:"FalseCondition",description:"A detector that highlights conditions that evaluate to a constant true or false",source:"@site/docs/detectors/FalseCondition.md",sourceDirName:"detectors",slug:"/detectors/FalseCondition",permalink:"/tools/misti/docs/next/detectors/FalseCondition",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/FalseCondition.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"EnsurePrgSeed",permalink:"/tools/misti/docs/next/detectors/EnsurePrgSeed"},next:{title:"FieldDoubleInit",permalink:"/tools/misti/docs/next/detectors/FieldDoubleInit"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h1,{id:"falsecondition",children:"FalseCondition"}),"\n",(0,o.jsxs)(t.p,{children:["A detector that highlights conditions that evaluate to a constant ",(0,o.jsx)(t.code,{children:"true"})," or ",(0,o.jsx)(t.code,{children:"false"}),"\nin ",(0,o.jsx)(t.code,{children:"if"}),", ",(0,o.jsx)(t.code,{children:"while"}),", or ",(0,o.jsx)(t.code,{children:"until"})," statements, and zero iterations in ",(0,o.jsx)(t.code,{children:"repeat"})," statements."]}),"\n",(0,o.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsxs)(t.p,{children:["Conditions that always evaluate to a constant ",(0,o.jsx)(t.code,{children:"true"})," or ",(0,o.jsx)(t.code,{children:"false"})," are likely the result of a typo\nor logic error. Such conditions can lead to unintended behavior, dead code, or incorrect control flow.\nThis detector helps identify these cases so they can be corrected, improving the code's reliability."]}),"\n",(0,o.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-tact",children:"const FALSE: Bool = false;\n// Bad: Always false because of operator precedence\nif ((param | value) & FALSE) {\n // ... never executed\n}\n"})}),"\n",(0,o.jsx)(t.p,{children:"Use instead:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-tact",children:"const FALSE: Bool = false;\n// OK: Fixed after the analyzer highlighted this\nif (param) {}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>a});var o=n(6540);const i={},s=o.createContext(i);function r(e){const t=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),o.createElement(s.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f4d075b1.8ca57b63.js b/assets/js/f4d075b1.8ca57b63.js new file mode 100644 index 000000000..7ad8f1031 --- /dev/null +++ b/assets/js/f4d075b1.8ca57b63.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7378],{462:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>r,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>d,toc:()=>l});var n=i(4848),s=i(8453);const o={},a="Field Initialized Twice",d={id:"detectors/FieldDoubleInit",title:"Field Initialized Twice",description:"A detector that highlights cases where a field is initialized both in the init function and at the point of definition.",source:"@site/versioned_docs/version-0.2.2/detectors/FieldDoubleInit.md",sourceDirName:"detectors",slug:"/detectors/FieldDoubleInit",permalink:"/tools/misti/docs/0.2.2/detectors/FieldDoubleInit",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/FieldDoubleInit.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"`dump` Is Used",permalink:"/tools/misti/docs/0.2.2/detectors/DumpIsUsed"},next:{title:"Prefer Augmented Assignment",permalink:"/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign"}},r={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"field-initialized-twice",children:"Field Initialized Twice"}),"\n",(0,n.jsxs)(t.p,{children:["A detector that highlights cases where a field is initialized both in the ",(0,n.jsx)(t.code,{children:"init"})," function and at the point of definition."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["Double initialization of fields can either be a programmer's mistake or simply a waste of gas. It is always preferred to initialize values in the field declaration if they have a compile-time evaluatable default value, or in the ",(0,n.jsx)(t.code,{children:"init"})," function if they must be initialized dynamically."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int = 0; // Bad\n init(x: Int) { self.a = x }\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int; // Fixed\n init(x: Int) { self.a = x }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>a,x:()=>d});var n=i(6540);const s={},o=n.createContext(s);function a(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f503d00c.e7655ff6.js b/assets/js/f503d00c.e7655ff6.js new file mode 100644 index 000000000..218261073 --- /dev/null +++ b/assets/js/f503d00c.e7655ff6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2819],{7563:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>r,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>d,toc:()=>l});var n=i(4848),s=i(8453);const o={},a="Field Initialized Twice",d={id:"detectors/FieldDoubleInit",title:"Field Initialized Twice",description:"A detector that highlights cases where a field is initialized both in the init function and at the point of definition.",source:"@site/versioned_docs/version-0.2.1/detectors/FieldDoubleInit.md",sourceDirName:"detectors",slug:"/detectors/FieldDoubleInit",permalink:"/tools/misti/docs/0.2.1/detectors/FieldDoubleInit",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/FieldDoubleInit.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"`dump` Is Used",permalink:"/tools/misti/docs/0.2.1/detectors/DumpIsUsed"},next:{title:"Prefer Augmented Assignment",permalink:"/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign"}},r={},l=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function c(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"field-initialized-twice",children:"Field Initialized Twice"}),"\n",(0,n.jsxs)(t.p,{children:["A detector that highlights cases where a field is initialized both in the ",(0,n.jsx)(t.code,{children:"init"})," function and at the point of definition."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["Double initialization of fields can either be a programmer's mistake or simply a waste of gas. It is always preferred to initialize values in the field declaration if they have a compile-time evaluatable default value, or in the ",(0,n.jsx)(t.code,{children:"init"})," function if they must be initialized dynamically."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int = 0; // Bad\n init(x: Int) { self.a = x }\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"contract Test {\n a: Int; // Fixed\n init(x: Int) { self.a = x }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>a,x:()=>d});var n=i(6540);const s={},o=n.createContext(s);function a(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f553073e.8eca43d2.js b/assets/js/f553073e.8eca43d2.js new file mode 100644 index 000000000..5f509a2b1 --- /dev/null +++ b/assets/js/f553073e.8eca43d2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[223],{6141:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>a,toc:()=>d});var n=t(4848),s=t(8453);const i={},o="StringReceiversOverlap",a={id:"detectors/StringReceiversOverlap",title:"StringReceiversOverlap",description:"A detector that finds overlapping messages between general string receivers and string receivers.",source:"@site/versioned_docs/version-0.4.0/detectors/StringReceiversOverlap.md",sourceDirName:"detectors",slug:"/detectors/StringReceiversOverlap",permalink:"/tools/misti/docs/detectors/StringReceiversOverlap",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/detectors/StringReceiversOverlap.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/detectors/ReadOnlyVariables"},next:{title:"UnboundLoops",permalink:"/tools/misti/docs/detectors/UnboundLoops"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const r={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.h1,{id:"stringreceiversoverlap",children:"StringReceiversOverlap"}),"\n",(0,n.jsx)(r.p,{children:"A detector that finds overlapping messages between general string receivers and string receivers."}),"\n",(0,n.jsx)(r.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(r.p,{children:"Constant string receivers and general string receivers can have overlapping messages\nin which case the constant string receiver always takes precedence."}),"\n",(0,n.jsx)(r.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-tact",children:'contract Test {\n receive("foobar") { throw(1042) }\n receive(msg: String) {\n if (msg == "foobar") { throw(1043) } // Bad: Dead code\n }\n}\n'})}),"\n",(0,n.jsx)(r.p,{children:"Use instead:"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-tact",children:'contract Test {\n receive("foobar") { throw(1042) }\n receive(msg: String) {}\n}\n'})})]})}function p(e={}){const{wrapper:r}={...(0,s.R)(),...e.components};return r?(0,n.jsx)(r,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,r,t)=>{t.d(r,{R:()=>o,x:()=>a});var n=t(6540);const s={},i=n.createContext(s);function o(e){const r=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(r):{...r,...e}}),[r,e])}function a(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),n.createElement(i.Provider,{value:r},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f5772bf1.e894af92.js b/assets/js/f5772bf1.e894af92.js new file mode 100644 index 000000000..dd389de19 --- /dev/null +++ b/assets/js/f5772bf1.e894af92.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1697],{1611:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>l,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var i=n(4848),s=n(8453);const r={},l="Getting started",o={id:"tutorial/getting-started",title:"Getting started",description:"This guide will walk you through the steps to install and set up the Misti static analyzer.",source:"@site/versioned_docs/version-0.2.1/tutorial/getting-started.md",sourceDirName:"tutorial",slug:"/tutorial/getting-started",permalink:"/tools/misti/docs/0.2.1/tutorial/getting-started",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/tutorial/getting-started.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Introduction",permalink:"/tools/misti/docs/0.2.1/"},next:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.2.1/tutorial/ci-cd"}},a={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Installation",id:"installation",level:2},{value:"Using Development Version",id:"using-development-version",level:3},{value:"Running the analysis",id:"running-the-analysis",level:2},{value:"Troubleshooting",id:"troubleshooting",level:2}];function c(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,i.jsx)(t.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,i.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsx)(t.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Git"}),"\n",(0,i.jsx)(t.li,{children:"Yarn"}),"\n",(0,i.jsx)(t.li,{children:"Node.js"}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"installation",children:"Installation"}),"\n",(0,i.jsxs)(t.p,{children:["Misti is distributed via npm and should be added to your Tact project ",(0,i.jsx)(t.a,{href:"https://github.com/tact-lang/tact?tab=readme-ov-file#installation",children:"in the same way"})," as Tact itself:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"yarn add @nowarp/misti\n"})}),"\n",(0,i.jsx)(t.h3,{id:"using-development-version",children:"Using Development Version"}),"\n",(0,i.jsx)(t.p,{children:"The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis."}),"\n",(0,i.jsx)(t.p,{children:"To install the latest development version you should:"}),"\n",(0,i.jsxs)(t.ol,{children:["\n",(0,i.jsxs)(t.li,{children:["Clone Misti: ",(0,i.jsx)(t.code,{children:"git clone https://github.com/nowarp/misti"})]}),"\n",(0,i.jsxs)(t.li,{children:["Build it: ",(0,i.jsx)(t.code,{children:"cd misti && yarn install && yarn build"})]}),"\n",(0,i.jsxs)(t.li,{children:["Use it in your Tact project: ",(0,i.jsx)(t.code,{children:"cd /path/to/tact/project && yarn add file:/path/to/misti"})]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,i.jsx)(t.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{children:"npx misti test/projects/simple/tactConfig.json\n"})}),"\n",(0,i.jsx)(t.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,i.jsxs)(t.p,{children:["You can also add a script to your ",(0,i.jsx)(t.code,{children:"package.json"})," to simplify running the linting process:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-json",children:'{\n "scripts": {\n "lint": "npx misti test/projects/simple/tactConfig.json"\n }\n}\n'})}),"\n",(0,i.jsx)(t.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsxs)(t.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,i.jsx)(t.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>l,x:()=>o});var i=n(6540);const s={},r=i.createContext(s);function l(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f58fcc43.833fdf0f.js b/assets/js/f58fcc43.833fdf0f.js new file mode 100644 index 000000000..ee8fba782 --- /dev/null +++ b/assets/js/f58fcc43.833fdf0f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[219],{9089:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>l,frontMatter:()=>r,metadata:()=>c,toc:()=>d});var i=n(4848),o=n(8453);const r={},s="Custom Detector Guide",c={id:"hacking/custom-detector",title:"Custom Detector Guide",description:"Introduction",source:"@site/versioned_docs/version-0.4.0/hacking/custom-detector.md",sourceDirName:"hacking",slug:"/hacking/custom-detector",permalink:"/tools/misti/docs/hacking/custom-detector",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/hacking/custom-detector.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Souffl\xe9",permalink:"/tools/misti/docs/hacking/souffle"}},a={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Creating a Detector",id:"creating-a-detector",level:2},{value:"Testing the detector",id:"testing-the-detector",level:3},{value:"Saving the configuration",id:"saving-the-configuration",level:3},{value:"Example Detectors",id:"example-detectors",level:2}];function h(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"custom-detector-guide",children:"Custom Detector Guide"}),"\n",(0,i.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsxs)(t.p,{children:["Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: ",(0,i.jsx)(t.a,{href:"https://nowarp.io/tools/misti/api/",children:"Misti API Reference"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the ",(0,i.jsx)(t.a,{href:"https://nowarp.io/tools/misti/api/classes/detectors_detector.Detector.html",children:(0,i.jsx)(t.code,{children:"Detector"})})," interface."]}),"\n",(0,i.jsx)(t.h2,{id:"creating-a-detector",children:"Creating a Detector"}),"\n",(0,i.jsxs)(t.p,{children:["You can create a new custom detector by executing Misti with the ",(0,i.jsx)(t.code,{children:"--new-detector"})," option: ",(0,i.jsx)(t.code,{children:"npx misti --new-detector implicitInit"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["This will create the ",(0,i.jsx)(t.code,{children:"implicitInit.ts"})," file, which contains the template code for writing your own custom detector logic leveraging the Misti API."]}),"\n",(0,i.jsx)(t.p,{children:"Here's an example of how to implement a custom detector using Misti API:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-typescript",children:'import { ASTDetector } from "@nowarp/misti/dist/detectors/detector";\nimport { CompilationUnit } from "@nowarp/misti/dist/internals/ir";\nimport {\n MistiTactWarning,\n Severity,\n} from "@nowarp/misti/dist/internals/errors";\n\n/**\n * An example of a custom detector that showcases the usage of the detector API.\n *\n * It reports all the contracts that doesn\'t have an explicit implementation of the init function.\n */\nexport class ImplicitInit extends ASTDetector {\n severity = Severity.INFO;\n\n async check(cu: CompilationUnit): Promise<MistiTactWarning[]> {\n return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {\n if (!cu.findMethodCFGByName(contract.name, "init")) {\n const err = this.makeWarning(\n `Contract ${contract.name} doesn\'t define an init function`,\n contract.ref,\n );\n foundErrors.push(err);\n }\n return foundErrors;\n }, [] as MistiTactWarning[]);\n }\n}\n\n'})}),"\n",(0,i.jsx)(t.h3,{id:"testing-the-detector",children:"Testing the detector"}),"\n",(0,i.jsxs)(t.p,{children:["To run Misti with only your new detector, use the ",(0,i.jsx)(t.code,{children:"--detectors"})," option, specifying the path to the detector and the Detector class name: ",(0,i.jsx)(t.code,{children:"npx misti path/to/your/tact.config.json --detectors path/to/implicitInit.ts:ImplicitInit"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["That's a good way to test the detector on the first run. You could also use the ",(0,i.jsx)(t.code,{children:"--verbose"})," CLI option and set the environment variable ",(0,i.jsx)(t.code,{children:"MISTI_TRACE=1"})," to facilitate debugging."]}),"\n",(0,i.jsx)(t.h3,{id:"saving-the-configuration",children:"Saving the configuration"}),"\n",(0,i.jsx)(t.p,{children:"After testing the detector, you can specify it in your configuration to enable it in future runs. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{children:'{\n "detectors": [\n // Other detectors...\n { "className": "ImplicitInit", "modulePath": "ImplicitInit.ts" }\n ],\n}\n'})}),"\n",(0,i.jsxs)(t.p,{children:["After this, you could run Misti specifying a path to a custom configuration ",(0,i.jsx)(t.code,{children:"npx misti --config path/to/misti.config.json path/to/your/tact.config.json"}),"."]}),"\n",(0,i.jsx)(t.h2,{id:"example-detectors",children:"Example Detectors"}),"\n",(0,i.jsxs)(t.p,{children:["The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the ",(0,i.jsx)(t.a,{href:"https://github.com/nowarp/misti/tree/master/examples",children:"examples directory"})," in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors."]})]})}function l(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>c});var i=n(6540);const o={},r=i.createContext(o);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f5bf49b8.3b9a5601.js b/assets/js/f5bf49b8.3b9a5601.js new file mode 100644 index 000000000..fa2b367c8 --- /dev/null +++ b/assets/js/f5bf49b8.3b9a5601.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[243],{7857:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var s=n(4848),i=n(8453);const r={},o="Prefer Augmented Assignment",a={id:"detectors/PreferAugmentedAssign",title:"Prefer Augmented Assignment",description:"Detects non-idiomatic statements that can be written using augmented assignment operators like +=, -=, etc.",source:"@site/versioned_docs/version-0.2.1/detectors/PreferAugmentedAssign.md",sourceDirName:"detectors",slug:"/detectors/PreferAugmentedAssign",permalink:"/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.1/detectors/PreferAugmentedAssign.md",tags:[],version:"0.2.1",frontMatter:{},sidebar:"sidebar",previous:{title:"Field Initialized Twice",permalink:"/tools/misti/docs/0.2.1/detectors/FieldDoubleInit"},next:{title:"Contributing",permalink:"/tools/misti/docs/0.2.1/hacking/contributing"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"prefer-augmented-assignment",children:"Prefer Augmented Assignment"}),"\n",(0,s.jsxs)(t.p,{children:["Detects non-idiomatic statements that can be written using augmented assignment operators like ",(0,s.jsx)(t.code,{children:"+="}),", ",(0,s.jsx)(t.code,{children:"-="}),", etc."]}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Using augmented assignment operations improves the readability of the source code and reduces the risk of mistakes, such as those that occur during copy-pasting and refactoring code."}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue = (msgValue - ctx.readForwardFee());\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"msgValue -= ctx.readForwardFee());\n"})})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>a});var s=n(6540);const i={},r=s.createContext(i);function o(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f6f2b22b.1f2e8cc1.js b/assets/js/f6f2b22b.1f2e8cc1.js new file mode 100644 index 000000000..c2c56e07b --- /dev/null +++ b/assets/js/f6f2b22b.1f2e8cc1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2091],{5208:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>o});var i=s(4848),l=s(8453);const t={},d="Command-Line Interface",r={id:"tutorial/cli",title:"Command-Line Interface",description:"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.",source:"@site/versioned_docs/version-0.3.1/tutorial/cli.md",sourceDirName:"tutorial",slug:"/tutorial/cli",permalink:"/tools/misti/docs/0.3.1/tutorial/cli",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.1/tutorial/cli.md",tags:[],version:"0.3.1",frontMatter:{},sidebar:"sidebar",previous:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.3.1/tutorial/ci-cd"},next:{title:"Configuration",permalink:"/tools/misti/docs/0.3.1/tutorial/configuration"}},c={},o=[{value:"<code>--dump-cfg <json|dot></code>",id:"--dump-cfg-jsondot",level:3},{value:"<code>--dump-ast</code>",id:"--dump-ast",level:3},{value:"<code>--dump-output <PATH></code>",id:"--dump-output-path",level:3},{value:"<code>--dump-include-stdlib</code>",id:"--dump-include-stdlib",level:3},{value:"<code>--dump-config</code>",id:"--dump-config",level:3},{value:"<code>--souffle-binary <PATH></code>",id:"--souffle-binary-path",level:3},{value:"<code>--souffle-path <PATH></code>",id:"--souffle-path-path",level:3},{value:"<code>--souffle-verbose</code>",id:"--souffle-verbose",level:3},{value:"<code>--tact-stdlib-path <PATH></code>",id:"--tact-stdlib-path-path",level:3},{value:"<code>--verbose</code>",id:"--verbose",level:3},{value:"<code>--quiet</code>",id:"--quiet",level:3},{value:"<code>--detectors <name|path:name></code>",id:"--detectors-namepathname",level:3},{value:"<code>--suppress <names></code>",id:"--suppress-names",level:3},{value:"<code>--all-detectors</code>",id:"--all-detectors",level:3},{value:"<code>--config <PATH></code>",id:"--config-path",level:3},{value:"<code>--new-detector <PATH></code>",id:"--new-detector-path",level:3}];function a(e){const n={code:"code",h1:"h1",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"command-line-interface",children:"Command-Line Interface"}),"\n",(0,i.jsx)(n.p,{children:"Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each."}),"\n",(0,i.jsx)(n.h3,{id:"--dump-cfg-jsondot",children:(0,i.jsx)(n.code,{children:"--dump-cfg <json|dot>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Dumps the Control Flow Graph (CFG) in the requested format: JSON or Graphviz Dot."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"undefined"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--dump-ast",children:(0,i.jsx)(n.code,{children:"--dump-ast"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Dumps the Abstract Syntax Tree (AST) in JSON format."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--dump-output-path",children:(0,i.jsx)(n.code,{children:"--dump-output <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Specifies the directory to save the AST/CFG dump. If ",(0,i.jsx)(n.code,{children:"<PATH>"})," is ",(0,i.jsx)(n.code,{children:"-"}),", then the output is sent to stdout."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": Value of ",(0,i.jsx)(n.code,{children:"DUMP_STDOUT_PATH"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--dump-include-stdlib",children:(0,i.jsx)(n.code,{children:"--dump-include-stdlib"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Includes standard library components in the AST/CFG dump."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--dump-config",children:(0,i.jsx)(n.code,{children:"--dump-config"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Dumps the Misti JSON configuration file in use."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--souffle-binary-path",children:(0,i.jsx)(n.code,{children:"--souffle-binary <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Path to the Souffl\xe9 binary."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:'"souffle"'})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--souffle-path-path",children:(0,i.jsx)(n.code,{children:"--souffle-path <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Directory to save the generated Souffl\xe9 files."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:'"/tmp/misti/souffle"'})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--souffle-verbose",children:(0,i.jsx)(n.code,{children:"--souffle-verbose"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Generates human-readable, but more verbose, Souffl\xe9 files."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--tact-stdlib-path-path",children:(0,i.jsx)(n.code,{children:"--tact-stdlib-path <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Path to the Tact standard library."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--verbose",children:(0,i.jsx)(n.code,{children:"--verbose"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Enables verbose output."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--quiet",children:(0,i.jsx)(n.code,{children:"--quiet"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Suppresses all output."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--detectors-namepathname",children:(0,i.jsx)(n.code,{children:"--detectors <name|path:name>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": A comma-separated list of detectors to enable."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Argument Validation"}),": Requires a non-empty list of detector names."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"undefined"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--suppress-names",children:(0,i.jsx)(n.code,{children:"--suppress <names>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": A comma-separated list of detector names to suppress."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Argument Validation"}),": Requires a non-empty list of detector names."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"undefined"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--all-detectors",children:(0,i.jsx)(n.code,{children:"--all-detectors"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Enables all the available built-in detectors."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"false"})]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--config-path",children:(0,i.jsx)(n.code,{children:"--config <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Path to the Misti configuration file."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"--new-detector-path",children:(0,i.jsx)(n.code,{children:"--new-detector <PATH>"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Description"}),": Creates a new custom detector at the specified path."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Default"}),": ",(0,i.jsx)(n.code,{children:"undefined"})]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(a,{...e})}):a(e)}},8453:(e,n,s)=>{s.d(n,{R:()=>d,x:()=>r});var i=s(6540);const l={},t=i.createContext(l);function d(e){const n=i.useContext(t);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(l):e.components||l:d(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f752d1db.9ec62e05.js b/assets/js/f752d1db.9ec62e05.js new file mode 100644 index 000000000..8d55ac73e --- /dev/null +++ b/assets/js/f752d1db.9ec62e05.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5900],{8656:(t,e,n)=>{n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>a,toc:()=>l});var i=n(4848),s=n(8453);const o={},r="Integrating Misti into CI/CD",a={id:"tutorial/ci-cd",title:"Integrating Misti into CI/CD",description:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.",source:"@site/versioned_docs/version-0.4.0/tutorial/ci-cd.md",sourceDirName:"tutorial",slug:"/tutorial/ci-cd",permalink:"/tools/misti/docs/tutorial/ci-cd",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.4.0/tutorial/ci-cd.md",tags:[],version:"0.4.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Getting Started",permalink:"/tools/misti/docs/tutorial/getting-started"},next:{title:"Command-Line Interface",permalink:"/tools/misti/docs/tutorial/cli"}},c={},l=[{value:"Using Tact Template",id:"using-tact-template",level:2},{value:"GitHub Actions",id:"github-actions",level:2},{value:"Integration with Blueprint Projects",id:"integration-with-blueprint-projects",level:2}];function u(t){const e={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,s.R)(),...t.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"integrating-misti-into-cicd",children:"Integrating Misti into CI/CD"}),"\n",(0,i.jsx)(e.p,{children:"Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle."}),"\n",(0,i.jsx)(e.h2,{id:"using-tact-template",children:"Using Tact Template"}),"\n",(0,i.jsxs)(e.p,{children:[(0,i.jsx)(e.a,{href:"https://github.com/tact-lang/tact-template",children:(0,i.jsx)(e.code,{children:"tact-template"})})," is a template project for Tact. If you started your project from this template, Misti is already installed in ",(0,i.jsx)(e.a,{href:"https://github.com/tact-lang/tact-template/tree/main/.github/workflows",children:"the CI"}),". You also have the ",(0,i.jsx)(e.code,{children:"yarn lint"})," command available in your ",(0,i.jsx)(e.code,{children:"package.json"}),"."]}),"\n",(0,i.jsx)(e.h2,{id:"github-actions",children:"GitHub Actions"}),"\n",(0,i.jsx)(e.p,{children:"To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:"}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"1. Open your GitHub repository"})}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"2. Create or edit the GitHub Actions workflow YAML file"})}),"\n",(0,i.jsxs)(e.p,{children:["It could be located at e.g., ",(0,i.jsx)(e.code,{children:".github/workflows/ci.yml"}),"."]}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"3. Add the step to run Misti to your YAML file"})}),"\n",(0,i.jsx)(e.p,{children:"For example:"}),"\n",(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-yaml",children:'name: CI\n\non:\n push:\n branches: [ "main" ]\n pull_request:\n branches: [ "main" ]\n workflow_dispatch:\n\njobs:\n test:\n strategy:\n fail-fast: false\n matrix:\n node-version: [22]\n os: [ubuntu-latest]\n runs-on: ${{ matrix.os }}\n steps:\n - name: Checkout code\n uses: actions/checkout@v2\n\n - name: Install Souffl\xe9 on Ubuntu\n if: matrix.os == \'ubuntu-latest\'\n run: |\n sudo wget https://souffle-lang.github.io/ppa/souffle-key.public -O /usr/share/keyrings/souffle-archive-keyring.gpg\n echo "deb [signed-by=/usr/share/keyrings/souffle-archive-keyring.gpg] https://souffle-lang.github.io/ppa/ubuntu/ stable main" | sudo tee /etc/apt/sources.list.d/souffle.list\n sudo apt update\n sudo apt install souffle\n\n - name: Setup Node.js\n uses: actions/setup-node@v3\n with:\n node-version: ${{ matrix.node-version }}\n\n - name: Install dependencies\n run: yarn install\n\n - name: Run Misti\n run: yarn misti --min-severity medium /path/to/your/tact.config.json\n'})}),"\n",(0,i.jsxs)(e.p,{children:["The ",(0,i.jsx)(e.code,{children:"yarn misti --min-severity medium /path/to/your/tact.config.json"})," command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail."]}),"\n",(0,i.jsxs)(e.p,{children:["The ",(0,i.jsx)(e.code,{children:"--min-severity medium"})," will filter out low-priority warnings. You can always run Misti with all the detectors enabled locally in order to get the most comprehensive warnings output: ",(0,i.jsx)(e.code,{children:"yarn misti --all-detectors /path/to/your/tact.config.json"})]}),"\n",(0,i.jsx)(e.p,{children:(0,i.jsx)(e.strong,{children:"4. Adjusting the Misti Configuration"})}),"\n",(0,i.jsxs)(e.p,{children:["If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the ",(0,i.jsx)(e.a,{href:"./configuration",children:"Configuration"})," section for more details on how to customize your settings."]}),"\n",(0,i.jsx)(e.h2,{id:"integration-with-blueprint-projects",children:"Integration with Blueprint Projects"}),"\n",(0,i.jsx)(e.p,{children:"To add Misti to the CI for your Blueprint project, follow these steps:"}),"\n",(0,i.jsxs)(e.ol,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsxs)(e.a,{href:"/tools/misti/docs/tutorial/blueprint",children:["Install ",(0,i.jsx)(e.code,{children:"blueprint-misti"})]}),"."]}),"\n",(0,i.jsxs)(e.li,{children:["Follow the steps to set up the GitHub action above, but replace the ",(0,i.jsx)(e.code,{children:"yarn misti"})," command with ",(0,i.jsx)(e.code,{children:"npx blueprint misti --blueprint-project <PROJECT_NAME>"}),", where ",(0,i.jsx)(e.code,{children:"<PROJECT_NAME>"})," is the name of the project displayed when you run ",(0,i.jsx)(e.code,{children:"npx blueprint build"}),"."]}),"\n"]})]})}function d(t={}){const{wrapper:e}={...(0,s.R)(),...t.components};return e?(0,i.jsx)(e,{...t,children:(0,i.jsx)(u,{...t})}):u(t)}},8453:(t,e,n)=>{n.d(e,{R:()=>r,x:()=>a});var i=n(6540);const s={},o=i.createContext(s);function r(t){const e=i.useContext(o);return i.useMemo((function(){return"function"==typeof t?t(e):{...e,...t}}),[e,t])}function a(t){let e;return e=t.disableParentContext?"function"==typeof t.components?t.components(s):t.components||s:r(t.components),i.createElement(o.Provider,{value:e},t.children)}}}]); \ No newline at end of file diff --git a/assets/js/f7ab1f3a.096a7a59.js b/assets/js/f7ab1f3a.096a7a59.js new file mode 100644 index 000000000..10aea86ba --- /dev/null +++ b/assets/js/f7ab1f3a.096a7a59.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3754],{4856:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var s=n(4848),t=n(8453);const a={},o="Design Overview",l={id:"hacking/design",title:"Design Overview",description:"Static Analysis",source:"@site/versioned_docs/version-0.1.2/hacking/design.md",sourceDirName:"hacking",slug:"/hacking/design",permalink:"/tools/misti/docs/0.1.2/hacking/design",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.1.2/hacking/design.md",tags:[],version:"0.1.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Contributing",permalink:"/tools/misti/docs/0.1.2/hacking/contributing"},next:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.1.2/hacking/souffle"}},r={},c=[{value:"Static Analysis",id:"static-analysis",level:2},{value:"Souffle Datalog Solver",id:"souffle-datalog-solver",level:2},{value:"Dataflow Analysis in Misti",id:"dataflow-analysis-in-misti",level:2},{value:"References",id:"references",level:2}];function d(e){const i={a:"a",h1:"h1",h2:"h2",li:"li",p:"p",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"design-overview",children:"Design Overview"}),"\n",(0,s.jsx)(i.h2,{id:"static-analysis",children:"Static Analysis"}),"\n",(0,s.jsx)(i.p,{children:"Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues."}),"\n",(0,s.jsx)(i.h2,{id:"souffle-datalog-solver",children:"Souffle Datalog Solver"}),"\n",(0,s.jsxs)(i.p,{children:["Misti leverages the ",(0,s.jsx)(i.a,{href:"https://souffle-lang.github.io",children:"Souffle Datalog solver"}),", an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases."]}),"\n",(0,s.jsx)(i.h2,{id:"dataflow-analysis-in-misti",children:"Dataflow Analysis in Misti"}),"\n",(0,s.jsx)(i.p,{children:"Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code."}),"\n",(0,s.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,s.jsx)(i.p,{children:"For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsx)(i.li,{children:(0,s.jsx)(i.a,{href:"https://cs.au.dk/~amoeller/spa/spa.pdf",children:"Anders M\xf8ller and Michael I. Schwartzbach \u2013 Static Program Analysis"})}),"\n",(0,s.jsx)(i.li,{children:"Uday Khedker et al. \u2013 Data Flow Analysis: Theory and Practice"}),"\n"]}),"\n",(0,s.jsx)(i.p,{children:"These resources provide a solid foundation in the theory and practice of static and dataflow analysis."})]})}function h(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>o,x:()=>l});var s=n(6540);const t={},a=s.createContext(t);function o(e){const i=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f97c3fca.6a842194.js b/assets/js/f97c3fca.6a842194.js new file mode 100644 index 000000000..26ce96dda --- /dev/null +++ b/assets/js/f97c3fca.6a842194.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[877],{4297:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var s=n(4848),o=n(8453);const r={},d="ConstantAddress",a={id:"detectors/ConstantAddress",title:"ConstantAddress",description:"An optional detector that highlights all the constant addresses appearing in the source code.",source:"@site/docs/detectors/ConstantAddress.md",sourceDirName:"detectors",slug:"/detectors/ConstantAddress",permalink:"/tools/misti/docs/next/detectors/ConstantAddress",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/ConstantAddress.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"BranchDuplicate",permalink:"/tools/misti/docs/next/detectors/BranchDuplicate"},next:{title:"DivideBeforeMultiply",permalink:"/tools/misti/docs/next/detectors/DivideBeforeMultiply"}},i={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"constantaddress",children:"ConstantAddress"}),"\n",(0,s.jsx)(t.p,{children:"An optional detector that highlights all the constant addresses appearing in the source code."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsxs)(t.p,{children:["Using hardcoded addresses can sometimes indicate poor contract design.\nSome constant addresses may need to be set dynamically, e.g., using\n",(0,s.jsx)(t.code,{children:"contractAddress"}),", or at least have a way to change them at runtime, for\nexample, when upgrading a contract."]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:'contract Main {\n proxy: Address;\n init() {\n // Bad: Constant address highlighted by the analyzer.\n self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");\n }\n}\n'})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"contract Main {\n proxy: Address;\n init() {\n let proxy: Proxy = initOf Proxy(myAddress());\n // OK: Address depends on how the proxy contact has been deployed\n self.proxy = contractAddress(proxy);\n }\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>a});var s=n(6540);const o={},r=s.createContext(o);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/faae61e5.d4f77930.js b/assets/js/faae61e5.d4f77930.js new file mode 100644 index 000000000..d95e8aba0 --- /dev/null +++ b/assets/js/faae61e5.d4f77930.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5859],{8714:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>o,contentTitle:()=>n,default:()=>a,frontMatter:()=>r,metadata:()=>c,toc:()=>l});var i=s(4848),d=s(8453);const r={id:"detectors",title:"Detectors Overview"},n="Detectors Overview",c={id:"detectors",title:"Detectors Overview",description:"Misti currently supports 21 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices.",source:"@site/docs/detectors.md",sourceDirName:".",slug:"/detectors",permalink:"/tools/misti/docs/next/detectors",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors.md",tags:[],version:"current",frontMatter:{id:"detectors",title:"Detectors Overview"},sidebar:"sidebar",previous:{title:"Using with Blueprint",permalink:"/tools/misti/docs/next/tutorial/blueprint"},next:{title:"ArgCopyMutation",permalink:"/tools/misti/docs/next/detectors/ArgCopyMutation"}},o={},l=[{value:"Solved Problems",id:"solved-problems",level:2},{value:"TON and Tact Specific",id:"ton-and-tact-specific",level:3},{value:"DoS Attacks",id:"dos-attacks",level:3},{value:"Arithmetic Errors",id:"arithmetic-errors",level:3},{value:"Optimization",id:"optimization",level:3},{value:"Suspicious Patterns",id:"suspicious-patterns",level:3},{value:"List of Built-in detectors",id:"list-of-built-in-detectors",level:2}];function h(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"detectors-overview",children:"Detectors Overview"}),"\n",(0,i.jsx)(t.p,{children:"Misti currently supports 21 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices."}),"\n",(0,i.jsx)(t.h2,{id:"solved-problems",children:"Solved Problems"}),"\n",(0,i.jsx)(t.h3,{id:"ton-and-tact-specific",children:"TON and Tact Specific"}),"\n",(0,i.jsx)(t.p,{children:"There are language-specific patterns in TON and Tact that may lead to unintended behavior if not handled correctly."}),"\n",(0,i.jsx)(t.p,{children:"Example detectors:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/StringReceiversOverlap",children:"StringReceiversOverlap"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/EnsurePrgSeed",children:"EnsurePrgSeed"})}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"dos-attacks",children:"DoS Attacks"}),"\n",(0,i.jsx)(t.p,{children:"Denial of Service (DoS) and out-of-gas attacks can disrupt the execution of contracts, making them inaccessible or non-functional."}),"\n",(0,i.jsx)(t.p,{children:"Example detectors:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"SendInLoop"}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"arithmetic-errors",children:"Arithmetic Errors"}),"\n",(0,i.jsx)(t.p,{children:"Arithmetic errors in blockchain code can lead to incorrect calculations, potentially causing serious issues such as overflows or underflows."}),"\n",(0,i.jsx)(t.p,{children:"Example detectors:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/DivideBeforeMultiply",children:"DivideBeforeMultiply"})}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"optimization",children:"Optimization"}),"\n",(0,i.jsxs)(t.p,{children:["Misti provides various detectors aimed at optimizing code. While these may not identify security vulnerabilities, they help improve project quality by optimizing gas usage and enhancing code readability. These detectors are typically available when running Misti with the ",(0,i.jsx)(t.code,{children:"--all-detectors"})," flag."]}),"\n",(0,i.jsx)(t.p,{children:"Example detectors:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/OptimalMathFunction",children:"OptimalMathFunction"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/PreferAugmentedAssign",children:"PreferAugmentedAssign"})}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"suspicious-patterns",children:"Suspicious Patterns"}),"\n",(0,i.jsx)(t.p,{children:"There are numerous suspicious patterns in source code that auditors should pay attention to. These detectors are generally disabled by default but can be enabled during audits to provide deeper insights into the code structure and highlight areas for manual review."}),"\n",(0,i.jsx)(t.p,{children:"Example detectors:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/ZeroAddress",children:"ZeroAddress"})}),"\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/InheritedStateMutation",children:"InheritedStateMutation"})}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"list-of-built-in-detectors",children:"List of Built-in detectors"}),"\n",(0,i.jsxs)(t.table,{children:[(0,i.jsx)(t.thead,{children:(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.th,{children:"#"}),(0,i.jsx)(t.th,{children:"Detector"}),(0,i.jsx)(t.th,{children:"Severity"}),(0,i.jsx)(t.th,{children:"Requires Souffl\xe9"}),(0,i.jsx)(t.th,{children:"Enabled by default"})]})}),(0,i.jsxs)(t.tbody,{children:[(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"1"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/ArgCopyMutation",children:"ArgCopyMutation"})}),(0,i.jsx)(t.td,{children:"High"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"2"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/AsmIsUsed",children:"AsmIsUsed"})}),(0,i.jsx)(t.td,{children:"Info"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"3"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/BranchDuplicate",children:"BranchDuplicate"})}),(0,i.jsx)(t.td,{children:"High"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"4"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/ConstantAddress",children:"ConstantAddress"})}),(0,i.jsx)(t.td,{children:"Info"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"5"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/DivideBeforeMultiply",children:"DivideBeforeMultiply"})}),(0,i.jsx)(t.td,{children:"High"}),(0,i.jsx)(t.td,{children:"\u2714"}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"6"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/DumpIsUsed",children:"DumpIsUsed"})}),(0,i.jsx)(t.td,{children:"Info"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"7"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/DuplicatedCondition",children:"DuplicatedCondition"})}),(0,i.jsx)(t.td,{children:"High"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"8"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/EnsurePrgSeed",children:"EnsurePrgSeed"})}),(0,i.jsx)(t.td,{children:"Medium"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"9"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/FalseCondition",children:"FalseCondition"})}),(0,i.jsx)(t.td,{children:"Medium"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"10"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/FieldDoubleInit",children:"FieldDoubleInit"})}),(0,i.jsx)(t.td,{children:"Medium"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"11"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/InheritedStateMutation",children:"InheritedStateMutation"})}),(0,i.jsx)(t.td,{children:"Low"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"12"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/NeverAccessedVariables",children:"NeverAccessedVariables"})}),(0,i.jsx)(t.td,{children:"Medium"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"13"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/OptimalMathFunction",children:"OptimalMathFunction"})}),(0,i.jsx)(t.td,{children:"Low"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"14"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/PreferAugmentedAssign",children:"PreferAugmentedAssign"})}),(0,i.jsx)(t.td,{children:"Info"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"15"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/PreferredStdlibApi",children:"PreferredStdlibApi"})}),(0,i.jsx)(t.td,{children:"Info"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"16"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/ReadOnlyVariables",children:"ReadOnlyVariables"})}),(0,i.jsx)(t.td,{children:"Medium"}),(0,i.jsx)(t.td,{children:"\u2714"}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"17"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/StringReceiversOverlap",children:"StringReceiversOverlap"})}),(0,i.jsx)(t.td,{children:"High"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"18"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/UnboundLoops",children:"UnboundLoops"})}),(0,i.jsx)(t.td,{children:"High"}),(0,i.jsx)(t.td,{children:"\u2714"}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"19"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/UnusedOptional",children:"UnusedOptional"})}),(0,i.jsx)(t.td,{children:"Low"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:"20"}),(0,i.jsx)(t.td,{children:(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/ZeroAddress",children:"ZeroAddress"})}),(0,i.jsx)(t.td,{children:"Low"}),(0,i.jsx)(t.td,{}),(0,i.jsx)(t.td,{children:"\u2714"})]})]})]}),"\n",(0,i.jsxs)(t.p,{children:["Some of the detectors require ",(0,i.jsx)(t.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})," to be installed. If no Souffl\xe9 installation is found, these detectors won't be executed."]}),"\n",(0,i.jsxs)(t.p,{children:["A few detectors are optional and aimed at auditors to help uncover subtle issues in the source code. To enable all detectors, use the ",(0,i.jsx)(t.code,{children:"--all-detectors"})," option. You can find a full list of configuration options on the ",(0,i.jsx)(t.a,{href:"/tools/misti/docs/next/tutorial/configuration",children:"configuration page"}),"."]}),"\n",(0,i.jsx)(t.p,{children:"Each detector targets a specific type of problem in your code. Click on the detector name to learn more."})]})}function a(e={}){const{wrapper:t}={...(0,d.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>n,x:()=>c});var i=s(6540);const d={},r=i.createContext(d);function n(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:n(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/fafa7ec8.f8fc7c04.js b/assets/js/fafa7ec8.f8fc7c04.js new file mode 100644 index 000000000..845a67ed1 --- /dev/null +++ b/assets/js/fafa7ec8.f8fc7c04.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4330],{706:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>d,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>a});var n=s(4848),i=s(8453);const o={},d="dump Is Used",r={id:"detectors/DumpIsUsed",title:"dump Is Used",description:"An optional detector that highlights all the dump function calls.",source:"@site/versioned_docs/version-0.2.2/detectors/DumpIsUsed.md",sourceDirName:"detectors",slug:"/detectors/DumpIsUsed",permalink:"/tools/misti/docs/0.2.2/detectors/DumpIsUsed",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/detectors/DumpIsUsed.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Branch Duplicate",permalink:"/tools/misti/docs/0.2.2/detectors/BranchDuplicate"},next:{title:"Field Initialized Twice",permalink:"/tools/misti/docs/0.2.2/detectors/FieldDoubleInit"}},c={},a=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(t.h1,{id:"dump-is-used",children:[(0,n.jsx)(t.code,{children:"dump"})," Is Used"]}),"\n",(0,n.jsxs)(t.p,{children:["An optional detector that highlights all the ",(0,n.jsx)(t.code,{children:"dump"})," function calls."]}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"dump"})," function is a debug print that shouldn't be in the final code. Even though the compiler removes it in production, its presence suggests the developer was debugging something. This can flag areas where issues might exist, so auditors should take a closer look at these parts of the code."]}),"\n",(0,n.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = (RANDOM_SEED >> half_shift) &\n (MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;\n dump(combined); // Suspicious: Highlighted by the detector\n}\n"})}),"\n",(0,n.jsx)(t.p,{children:"Use instead:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-tact",children:"fun test(): Int {\n // ... other computations\n let combined: Int = this.seed ^ shift_mask\n // OK: The code was reviewed and simplified; `dump` was removed\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>d,x:()=>r});var n=s(6540);const i={},o=n.createContext(i);function d(e){const t=n.useContext(o);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),n.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/fbbe250b.022d69c3.js b/assets/js/fbbe250b.022d69c3.js new file mode 100644 index 000000000..a1e836b7c --- /dev/null +++ b/assets/js/fbbe250b.022d69c3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7173],{3034:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var t=i(4848),s=i(8453);const o={},r="Configuration",l={id:"tutorial/configuration",title:"Configuration",description:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.",source:"@site/docs/tutorial/configuration.md",sourceDirName:"tutorial",slug:"/tutorial/configuration",permalink:"/tools/misti/docs/next/tutorial/configuration",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tutorial/configuration.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Command-Line Interface",permalink:"/tools/misti/docs/next/tutorial/cli"},next:{title:"Using with Blueprint",permalink:"/tools/misti/docs/next/tutorial/blueprint"}},a={},c=[{value:"Configuration Options",id:"configuration-options",level:3},{value:"Running Misti with Configuration",id:"running-misti-with-configuration",level:2},{value:"Default Configuration File",id:"default-configuration-file",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"configuration",children:"Configuration"}),"\n",(0,t.jsx)(n.p,{children:"This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set."}),"\n",(0,t.jsx)(n.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"detectors"})," (array of objects, optional): List of detectors to run. Each detector can be specified with a ",(0,t.jsx)(n.code,{children:"className"})," and optionally a ",(0,t.jsx)(n.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"modulePath"})," (string, optional): The file path of the detector module if it's a custom implementation."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"tools"})," (array of objects, optional): List of tools to enable, each with its own configuration."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"className"})," (string, required): The class name of the tool."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"options"})," (object, optional): Key-value configuration options for the tool."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"suppressions"})," (array of objects, optional): A list of suppressions for warnings."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"detector"})," (string, required): The detector to suppress warnings for."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"position"})," (string, required): The position in the code where the warning should be suppressed."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"ignoredProjects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"soufflePath"})," (string, optional): Directory to save generated Souffl\xe9 files, useful for debugging purposes. If not set, a temporary directory will be used."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"souffleVerbose"})," (boolean, optional): If set, generates more readable Souffl\xe9 files instead of optimizing the output for size."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"tactStdlibPath"})," (string, optional): Path to the Tact standard library. If not set, the default standard library from the active Tact setup will be used."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"unusedPrefix"}),' (string, default: "_"): Identifiers starting with this prefix won\'t be reported as unused by the built-in detectors.']}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"verbosity"}),' (string, optional, default: "default"): Verbosity level of the logs. Possible values are ',(0,t.jsx)(n.code,{children:"quiet"}),", ",(0,t.jsx)(n.code,{children:"debug"}),", and ",(0,t.jsx)(n.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,t.jsx)(n.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,t.jsx)(n.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,t.jsx)(n.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "detectors": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n { "className": "BranchDuplicate" },\n { "className": "FieldDoubleInit" },\n { "className": "PreferAugmentedAssign" },\n { "className": "StringReceiversOverlap" },\n { "className": "ArgCopyMutation" }\n ],\n "ignoredProjects": [],\n "soufflePath": "/tmp/misti/souffle",\n "souffleVerbose": false,\n "unusedPrefix": "_",\n "verbosity": "default"\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,t.jsx)(n.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"npx misti --dump-config path/to/your/tact.config.json\n"})}),"\n",(0,t.jsx)(n.p,{children:"If there is no Misti config in the directory, Misti dumps the default config. This can be used to adjust it, such as adding or suppressing some detectors."}),"\n",(0,t.jsx)(n.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,t.jsxs)(n.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,t.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>l});var t=i(6540);const s={},o=t.createContext(s);function r(e){const n=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/fcd86191.e1395157.js b/assets/js/fcd86191.e1395157.js new file mode 100644 index 000000000..b0cf64236 --- /dev/null +++ b/assets/js/fcd86191.e1395157.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6752],{6493:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>u,frontMatter:()=>i,metadata:()=>c,toc:()=>d});var o=n(4848),r=n(8453);const i={},s="Custom Detector Guide",c={id:"hacking/custom-detector",title:"Custom Detector Guide",description:"Introduction",source:"@site/versioned_docs/version-0.2.2/hacking/custom-detector.md",sourceDirName:"hacking",slug:"/hacking/custom-detector",permalink:"/tools/misti/docs/0.2.2/hacking/custom-detector",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.2/hacking/custom-detector.md",tags:[],version:"0.2.2",frontMatter:{},sidebar:"sidebar",previous:{title:"Tools",permalink:"/tools/misti/docs/0.2.2/hacking/tools"}},a={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Writing a Detector",id:"writing-a-detector",level:2},{value:"Example Detectors",id:"example-detectors",level:2}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.h1,{id:"custom-detector-guide",children:"Custom Detector Guide"}),"\n",(0,o.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,o.jsxs)(t.p,{children:["Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: ",(0,o.jsx)(t.a,{href:"https://nowarp.github.io/tools/misti/api/",children:"Misti API Reference"}),"."]}),"\n",(0,o.jsxs)(t.p,{children:["Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the ",(0,o.jsx)(t.a,{href:"https://nowarp.github.io/tools/misti/api/classes/detectors_detector.Detector.html",children:(0,o.jsx)(t.code,{children:"Detector"})})," interface."]}),"\n",(0,o.jsx)(t.h2,{id:"writing-a-detector",children:"Writing a Detector"}),"\n",(0,o.jsx)(t.p,{children:"To write a custom detector, create a TypeScript file using the Misti API. Here's an example of how to implement a custom detector:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-typescript",children:'import { Detector } from "../../src/detectors/detector";\nimport { MistiContext } from "../../src/internals/context";\nimport { CompilationUnit } from "../../src/internals/ir";\nimport {\n createError,\n MistiTactError,\n Severity,\n} from "../../src/internals/errors";\n\n/**\n * An example of a custom detector that showcases the usage of the detector API.\n *\n * It reports all the contracts that don\'t have an explicit implementation of the init function.\n */\nexport class ImplicitInit extends Detector {\n check(ctx: MistiContext, cu: CompilationUnit): MistiTactError[] {\n return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {\n if (!cu.findMethodCFGByName(contract.name, "init")) {\n const err = createError(\n ctx,\n `contract ${contract.name} doesn\'t define an init function`,\n Severity.INFO,\n contract.ref,\n );\n foundErrors.push(err);\n }\n return foundErrors;\n }, [] as MistiTactError[]);\n }\n}\n'})}),"\n",(0,o.jsx)(t.p,{children:"After creating a detector, you need to specify it in your configuration. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{children:'{\n "detectors": [\n { "className": "DivideBeforeMultiply" },\n { "className": "ReadOnlyVariables" },\n { "className": "NeverAccessedVariables" },\n { "className": "UnboundLoops" },\n { "className": "ZeroAddress" },\n\n { "className": "ImplicitInit", "modulePath": "/path/to/implicitInit.ts" }\n ],\n "ignored_projects": [],\n "verbosity": "default"\n}\n\n'})}),"\n",(0,o.jsxs)(t.p,{children:["After this, you could run the created detector specifying a path to it: ",(0,o.jsx)(t.code,{children:"--config path/to/mistiConfig.json test/projects/simple/tactConfig.json"}),"."]}),"\n",(0,o.jsx)(t.h2,{id:"example-detectors",children:"Example Detectors"}),"\n",(0,o.jsxs)(t.p,{children:["The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the ",(0,o.jsx)(t.a,{href:"https://github.com/nowarp/misti/tree/master/examples",children:"examples directory"})," in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors."]})]})}function u(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>c});var o=n(6540);const r={},i=o.createContext(r);function s(e){const t=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function c(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),o.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/fe7c01fc.f82580ba.js b/assets/js/fe7c01fc.f82580ba.js new file mode 100644 index 000000000..dfdf3125b --- /dev/null +++ b/assets/js/fe7c01fc.f82580ba.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6854],{7437:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>c,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>d});var s=n(4848),i=n(8453);const r={},c="BranchDuplicate",o={id:"detectors/BranchDuplicate",title:"BranchDuplicate",description:"Detector that reports duplicated code in conditional branches.",source:"@site/versioned_docs/version-0.3.0/detectors/BranchDuplicate.md",sourceDirName:"detectors",slug:"/detectors/BranchDuplicate",permalink:"/tools/misti/docs/0.3.0/detectors/BranchDuplicate",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.3.0/detectors/BranchDuplicate.md",tags:[],version:"0.3.0",frontMatter:{},sidebar:"sidebar",previous:{title:"AsmIsUsed",permalink:"/tools/misti/docs/0.3.0/detectors/AsmIsUsed"},next:{title:"ConstantAddress",permalink:"/tools/misti/docs/0.3.0/detectors/ConstantAddress"}},a={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function l(e){const t={code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"branchduplicate",children:"BranchDuplicate"}),"\n",(0,s.jsx)(t.p,{children:"Detector that reports duplicated code in conditional branches."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Duplicated code in branches is bad because it:"}),"\n",(0,s.jsxs)(t.ol,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Reduces Readability"}),": Repetition makes the code harder to understand."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Increases Maintenance"}),": Changes must be made in multiple places, risking errors."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"Signals Poor Design"}),": It suggests missed opportunities for cleaner, more abstract code."]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = 43; // bad: duplicated code\n} else {\n a = 43;\n}\n"})}),"\n",(0,s.jsx)(t.p,{children:"Use instead:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-tact",children:"if (a > 42) {\n a = inc(b); // ok\n} else {\n a = 43;\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>c,x:()=>o});var s=n(6540);const i={},r=s.createContext(i);function c(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:c(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ff0db780.e64f7648.js b/assets/js/ff0db780.e64f7648.js new file mode 100644 index 000000000..df8869dc4 --- /dev/null +++ b/assets/js/ff0db780.e64f7648.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1598],{4263:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var t=i(4848),s=i(8453);const r={},o="Contributing Guide",a={id:"hacking/contributing",title:"Contributing Guide",description:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.",source:"@site/versioned_docs/version-0.2.0/hacking/contributing.md",sourceDirName:"hacking",slug:"/hacking/contributing",permalink:"/tools/misti/docs/0.2.0/hacking/contributing",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.2.0/hacking/contributing.md",tags:[],version:"0.2.0",frontMatter:{},sidebar:"sidebar",previous:{title:"Prefer Augmented Assignment",permalink:"/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign"},next:{title:"Design Overview",permalink:"/tools/misti/docs/0.2.0/hacking/design"}},c={},d=[{value:"Issues reporting",id:"issues-reporting",level:2},{value:"Documentation contribution",id:"documentation-contribution",level:2},{value:"Code contribution",id:"code-contribution",level:2}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"contributing-guide",children:"Contributing Guide"}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better."}),"\n",(0,t.jsx)(n.h2,{id:"issues-reporting",children:"Issues reporting"}),"\n",(0,t.jsx)(n.p,{children:"When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.\nPlease help us by publishing it and the input sources at:\nhttps://github.com/nowarp/misti/issues/new.\n"})}),"\n",(0,t.jsx)(n.p,{children:"We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users."}),"\n",(0,t.jsx)(n.h2,{id:"documentation-contribution",children:"Documentation contribution"}),"\n",(0,t.jsxs)(n.p,{children:["We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/nowarp.github.io/issues",children:"nowarp.github.io Issues"}),". Additionally, many documentation pages have an ",(0,t.jsx)(n.code,{children:"Edit"})," button that allows you to make direct contributions easily."]}),"\n",(0,t.jsx)(n.h2,{id:"code-contribution",children:"Code contribution"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Navigate Issues and Find Tasks"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Browse the issues ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"here"}),". Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues."]}),"\n",(0,t.jsx)(n.li,{children:"Choose an issue suitable for you and mention in the issue that you're working on it."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Implement Your Changes"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Implement your changes. Feel free to ask questions in the issue if needed."}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Ensure Tests Pass"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Before creating a PR, make sure all tests and CI checks are passing by running:","\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn test-all\n"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Create a PR"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Submit your pull request ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/pulls",children:"here"})]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Add a CHANGELOG entry"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Describe your changes in the ",(0,t.jsx)(n.code,{children:"CHANGELOG.md"})," file according to the existing structure."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to ",(0,t.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/HACKING.md",children:"HACKING.md"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"Thank you for your contributions!"})]})}function u(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>o,x:()=>a});var t=i(6540);const s={},r=t.createContext(s);function o(e){const n=t.useContext(r);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),t.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/main.0656ce4d.js b/assets/js/main.0656ce4d.js new file mode 100644 index 000000000..34327981f --- /dev/null +++ b/assets/js/main.0656ce4d.js @@ -0,0 +1,2 @@ +/*! For license information please see main.0656ce4d.js.LICENSE.txt */ +(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8792],{8328:(e,t,n)=>{"use strict";n.d(t,{A:()=>p});n(6540);var o=n(3259),r=n.n(o),i=n(4054);const s={"012e8e66":[()=>n.e(8700).then(n.bind(n,7337)),"@site/docs/tools/DumpConfig.md",7337],"01419b1f":[()=>n.e(4371).then(n.bind(n,4622)),"@site/versioned_docs/version-0.2.0/tutorial/getting-started.md",4622],"06bf7bd2":[()=>n.e(804).then(n.bind(n,6538)),"@site/versioned_docs/version-0.2.2/hacking/tools.md",6538],"070671b7":[()=>n.e(8607).then(n.bind(n,3620)),"@site/docs/detectors/PreferAugmentedAssign.md",3620],"07f2fad9":[()=>n.e(3462).then(n.bind(n,8092)),"@site/versioned_docs/version-0.3.0/index.md",8092],"0ac52da9":[()=>n.e(7702).then(n.bind(n,8288)),"@site/versioned_docs/version-0.3.1/tutorial/configuration.md",8288],"0b705376":[()=>n.e(2903).then(n.bind(n,9153)),"@site/versioned_docs/version-0.3.1/detectors/AsmIsUsed.md",9153],"0c390d31":[()=>n.e(1200).then(n.bind(n,934)),"@site/versioned_docs/version-0.4.0/tutorial/cli.md",934],"0c3de8e2":[()=>n.e(4875).then(n.bind(n,9689)),"@site/docs/detectors/InheritedStateMutation.md",9689],"0c8d0168":[()=>n.e(607).then(n.bind(n,5843)),"@site/docs/tutorial/blueprint.md",5843],"0e4e7ef7":[()=>n.e(1070).then(n.bind(n,2210)),"@site/versioned_docs/version-0.4.0/tutorial/configuration.md",2210],"0f37fc5e":[()=>n.e(9692).then(n.bind(n,7141)),"@site/docs/detectors/StringReceiversOverlap.md",7141],"0fb6ae9c":[()=>n.e(5983).then(n.bind(n,5091)),"@site/docs/hacking/souffle.md",5091],"104c66c9":[()=>n.e(6695).then(n.bind(n,1806)),"@site/versioned_docs/version-0.2.1/detectors/ZeroAddress.md",1806],"122f6b32":[()=>n.e(25).then(n.bind(n,9648)),"@site/versioned_docs/version-0.3.0/detectors/DivideBeforeMultiply.md",9648],"1295da86":[()=>n.e(559).then(n.bind(n,7413)),"@site/versioned_docs/version-0.3.1/tutorial/blueprint.md",7413],"138db073":[()=>n.e(1519).then(n.bind(n,3331)),"@site/docs/detectors/AsmIsUsed.md",3331],"1418388c":[()=>n.e(8917).then(n.bind(n,0)),"@site/versioned_docs/version-0.2.1/hacking/custom-detector.md",0],"150b97d9":[()=>n.e(1258).then(n.bind(n,7254)),"@site/versioned_docs/version-0.4.0/tools.md",7254],"1598dd73":[()=>n.e(8708).then(n.bind(n,4661)),"@site/versioned_docs/version-0.1.2/tutorial/configuration.md",4661],"15d13f14":[()=>n.e(3884).then(n.bind(n,6662)),"@site/versioned_docs/version-0.2.1/hacking/contributing.md",6662],"17406c9d":[()=>n.e(8513).then(n.bind(n,1027)),"@site/versioned_docs/version-0.3.0/detectors/ReadOnlyVariables.md",1027],17896441:[()=>Promise.all([n.e(1869),n.e(3658),n.e(8401)]).then(n.bind(n,6365)),"@theme/DocItem",6365],"1869ccd1":[()=>n.e(9108).then(n.bind(n,9400)),"@site/versioned_docs/version-0.2.2/detectors/PreferAugmentedAssign.md",9400],"1a50d306":[()=>n.e(6999).then(n.bind(n,5669)),"@site/versioned_docs/version-0.3.1/detectors/NeverAccessedVariables.md",5669],"1a8310a1":[()=>n.e(7743).then(n.bind(n,9881)),"@site/versioned_docs/version-0.4.0/hacking/contributing.md",9881],"1b73222b":[()=>n.e(3420).then(n.t.bind(n,5274,19)),"@generated/docusaurus-plugin-content-docs/default/p/tools-misti-docs-0-3-0-3f9.json",5274],"1b960128":[()=>n.e(8920).then(n.bind(n,3265)),"@site/versioned_docs/version-0.4.0/tools/DumpConfig.md",3265],"1c26cb06":[()=>n.e(5602).then(n.bind(n,8164)),"@site/versioned_docs/version-0.2.2/tutorial/ci-cd.md",8164],"1df93b7f":[()=>n.e(4583).then(n.bind(n,6866)),"@site/src/pages/index.tsx",6866],"1f391b9e":[()=>Promise.all([n.e(1869),n.e(3658),n.e(6061)]).then(n.bind(n,7973)),"@theme/MDXPage",7973],"2018b81b":[()=>n.e(7677).then(n.bind(n,6964)),"@site/versioned_docs/version-0.3.0/tutorial/blueprint.md",6964],"2257d06b":[()=>n.e(1687).then(n.bind(n,111)),"@site/versioned_docs/version-0.2.1/detectors.md",111],"23b0c962":[()=>n.e(6784).then(n.bind(n,7838)),"@site/docs/tutorial/cli.md",7838],"2424092d":[()=>n.e(420).then(n.bind(n,512)),"@site/versioned_docs/version-0.2.0/detectors/ReadOnlyVariables.md",512],"24652b08":[()=>n.e(7406).then(n.bind(n,2208)),"@site/versioned_docs/version-0.2.0/detectors/DumpIsUsed.md",2208],"26592ea2":[()=>n.e(3543).then(n.bind(n,3178)),"@site/docs/detectors/FieldDoubleInit.md",3178],"273168fb":[()=>n.e(1492).then(n.bind(n,7079)),"@site/versioned_docs/version-0.1.2/tutorial/getting-started.md",7079],"299f32b1":[()=>n.e(853).then(n.bind(n,1665)),"@site/docs/detectors/UnboundLoops.md",1665],"2aa59687":[()=>n.e(3196).then(n.bind(n,542)),"@site/versioned_docs/version-0.3.1/tutorial/ci-cd.md",542],"2ace25e9":[()=>n.e(4013).then(n.bind(n,5111)),"@site/versioned_docs/version-0.2.1/hacking/tools.md",5111],"2b6a80d0":[()=>n.e(1084).then(n.bind(n,3646)),"@site/docs/detectors/DumpIsUsed.md",3646],"2b785902":[()=>n.e(4806).then(n.bind(n,2814)),"@site/docs/tools.md",2814],"2bdf0f82":[()=>n.e(321).then(n.bind(n,3842)),"@site/versioned_docs/version-0.1.2/hacking/CHANGELOG.md",3842],"2cebbb1e":[()=>n.e(5345).then(n.bind(n,730)),"@site/versioned_docs/version-0.3.1/detectors/PreferAugmentedAssign.md",730],"2d07d137":[()=>n.e(5097).then(n.bind(n,6097)),"@site/versioned_docs/version-0.2.0/detectors/DivideBeforeMultiply.md",6097],"2f30e490":[()=>n.e(1638).then(n.bind(n,2380)),"@site/versioned_docs/version-0.2.1/detectors/DivideBeforeMultiply.md",2380],"304edb56":[()=>n.e(4088).then(n.bind(n,8271)),"@site/docs/detectors/ArgCopyMutation.md",8271],"36ebdf3e":[()=>n.e(7787).then(n.bind(n,7162)),"@site/versioned_docs/version-0.1.2/detectors/ZeroAddress.md",7162],"377c4f81":[()=>n.e(3448).then(n.bind(n,235)),"@site/versioned_docs/version-0.3.0/hacking/tools.md",235],"393be207":[()=>n.e(4134).then(n.bind(n,633)),"@site/src/pages/markdown-page.md",633],"3b3a1a75":[()=>n.e(2478).then(n.bind(n,4727)),"@site/versioned_docs/version-0.4.0/detectors/ArgCopyMutation.md",4727],"3bfe497f":[()=>n.e(5381).then(n.bind(n,4512)),"@site/versioned_docs/version-0.4.0/detectors/DivideBeforeMultiply.md",4512],"3db5102b":[()=>n.e(6774).then(n.bind(n,6931)),"@site/versioned_docs/version-0.2.1/tutorial/ci-cd.md",6931],"40be7dfa":[()=>n.e(6602).then(n.bind(n,7991)),"@site/versioned_docs/version-0.2.0/index.md",7991],"42510f93":[()=>n.e(2913).then(n.bind(n,5875)),"@site/versioned_docs/version-0.4.0/hacking/developing-misti.md",5875],"432cb5a5":[()=>n.e(3840).then(n.bind(n,4303)),"@site/versioned_docs/version-0.4.0/hacking/design.md",4303],"43c93918":[()=>n.e(1299).then(n.bind(n,955)),"@site/versioned_docs/version-0.3.1/index.md",955],"4518efa7":[()=>n.e(6544).then(n.bind(n,2308)),"@site/versioned_docs/version-0.2.2/detectors/BranchDuplicate.md",2308],"474ce197":[()=>n.e(4069).then(n.t.bind(n,7715,19)),"@generated/docusaurus-plugin-content-docs/default/p/tools-misti-docs-0-2-1-a64.json",7715],49256311:[()=>n.e(2734).then(n.bind(n,9475)),"@site/versioned_docs/version-0.3.1/detectors/ConstantAddress.md",9475],"4ab26116":[()=>n.e(9276).then(n.bind(n,1857)),"@site/versioned_docs/version-0.4.0/detectors/ConstantAddress.md",1857],"4b89306f":[()=>n.e(6769).then(n.bind(n,1821)),"@site/versioned_docs/version-0.3.1/hacking/souffle.md",1821],"4d74b396":[()=>n.e(9802).then(n.bind(n,1167)),"@site/versioned_docs/version-0.2.1/detectors/ReadOnlyVariables.md",1167],"4f2bb7ce":[()=>n.e(6156).then(n.bind(n,8867)),"@site/versioned_docs/version-0.3.1/hacking/custom-detector.md",8867],"4fd06f05":[()=>n.e(6948).then(n.bind(n,7402)),"@site/versioned_docs/version-0.2.0/tutorial/ci-cd.md",7402],"51fe41a6":[()=>n.e(8290).then(n.bind(n,723)),"@site/versioned_docs/version-0.4.0/detectors/NeverAccessedVariables.md",723],"55e1201d":[()=>n.e(8422).then(n.bind(n,2165)),"@site/docs/detectors/OptimalMathFunction.md",2165],"563af34e":[()=>n.e(3890).then(n.bind(n,1410)),"@site/versioned_docs/version-0.3.0/detectors/StringReceiversOverlap.md",1410],"566d8483":[()=>n.e(6551).then(n.bind(n,5437)),"@site/versioned_docs/version-0.2.2/index.md",5437],"5815e0d3":[()=>n.e(186).then(n.bind(n,9644)),"@site/versioned_docs/version-0.2.0/tutorial/configuration.md",9644],59016342:[()=>n.e(6751).then(n.bind(n,9027)),"@site/versioned_docs/version-0.4.0/detectors/UnusedOptional.md",9027],"5a7ecd5b":[()=>n.e(1417).then(n.bind(n,26)),"@site/versioned_docs/version-0.3.0/detectors/ZeroAddress.md",26],"5e95c892":[()=>n.e(9647).then(n.bind(n,7121)),"@theme/DocsRoot",7121],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,4784)),"@generated/docusaurus.config",4784],"5ec2195c":[()=>n.e(9708).then(n.bind(n,1484)),"@site/versioned_docs/version-0.2.1/detectors/ConstantAddress.md",1484],"602c5d84":[()=>n.e(4719).then(n.bind(n,8930)),"@site/versioned_docs/version-0.4.0/detectors/FieldDoubleInit.md",8930],"61c19607":[()=>n.e(5794).then(n.bind(n,8628)),"@site/versioned_docs/version-0.2.2/tutorial/getting-started.md",8628],"6362ac9f":[()=>n.e(9431).then(n.bind(n,2219)),"@site/versioned_docs/version-0.4.0/tutorial/blueprint.md",2219],"63a541b5":[()=>n.e(5122).then(n.bind(n,1105)),"@site/versioned_docs/version-0.3.1/detectors/ArgCopyMutation.md",1105],"63bb535a":[()=>n.e(3684).then(n.bind(n,3494)),"@site/versioned_docs/version-0.4.0/detectors/PreferredStdlibApi.md",3494],"6696f09b":[()=>n.e(9417).then(n.bind(n,1469)),"@site/versioned_docs/version-0.4.0/tools/DumpCfg.md",1469],"6934ebe4":[()=>n.e(3175).then(n.bind(n,4919)),"@site/versioned_docs/version-0.3.0/tutorial/ci-cd.md",4919],"693ffdbc":[()=>n.e(1204).then(n.bind(n,7567)),"@site/versioned_docs/version-0.2.2/hacking/souffle.md",7567],"6f277b0e":[()=>n.e(6340).then(n.bind(n,701)),"@site/versioned_docs/version-0.2.2/detectors/UnboundLoops.md",701],"6f60ccd2":[()=>n.e(4861).then(n.bind(n,3316)),"@site/versioned_docs/version-0.3.1/detectors/ReadOnlyVariables.md",3316],"719e5d48":[()=>n.e(106).then(n.bind(n,4878)),"@site/versioned_docs/version-0.4.0/detectors/ReadOnlyVariables.md",4878],"72b7ad48":[()=>n.e(2378).then(n.bind(n,6878)),"@site/versioned_docs/version-0.2.1/detectors/UnboundLoops.md",6878],"743bfbca":[()=>n.e(121).then(n.bind(n,3372)),"@site/versioned_docs/version-0.1.2/hacking/custom-detector.md",3372],"7499c02a":[()=>n.e(3150).then(n.bind(n,6400)),"@site/versioned_docs/version-0.4.0/detectors/BranchDuplicate.md",6400],"754ccd45":[()=>n.e(3304).then(n.bind(n,1643)),"@site/docs/hacking/developing-misti.md",1643],76268162:[()=>n.e(7005).then(n.bind(n,1943)),"@site/versioned_docs/version-0.2.0/detectors/UnboundLoops.md",1943],"773c7ee4":[()=>n.e(1564).then(n.bind(n,9113)),"@site/versioned_docs/version-0.2.0/hacking/souffle.md",9113],"775287ab":[()=>n.e(8342).then(n.bind(n,1402)),"@site/versioned_docs/version-0.1.2/hacking/contributing.md",1402],"776efca7":[()=>n.e(7151).then(n.bind(n,1883)),"@site/versioned_docs/version-0.3.1/detectors/StringReceiversOverlap.md",1883],"7b5b3cc2":[()=>n.e(6612).then(n.bind(n,8962)),"@site/versioned_docs/version-0.3.0/detectors/InheritedStateMutation.md",8962],"81087c81":[()=>n.e(6869).then(n.bind(n,2140)),"@site/versioned_docs/version-0.3.0/hacking/custom-detector.md",2140],"8272dc48":[()=>n.e(1529).then(n.bind(n,2184)),"@site/versioned_docs/version-0.2.0/hacking/tools.md",2184],"8306354c":[()=>n.e(7877).then(n.bind(n,9164)),"@site/versioned_docs/version-0.4.0/detectors/PreferAugmentedAssign.md",9164],"844f22a2":[()=>n.e(5316).then(n.bind(n,9095)),"@site/versioned_docs/version-0.3.0/tutorial/getting-started.md",9095],"866ed13d":[()=>n.e(6974).then(n.bind(n,9515)),"@site/docs/detectors/ZeroAddress.md",9515],"86d22c3d":[()=>n.e(1407).then(n.t.bind(n,5012,19)),"@generated/docusaurus-plugin-content-docs/default/p/tools-misti-docs-653.json",5012],"86d70222":[()=>n.e(3812).then(n.bind(n,2759)),"@site/versioned_docs/version-0.2.0/hacking/custom-detector.md",2759],"87ce9660":[()=>n.e(7495).then(n.bind(n,7049)),"@site/versioned_docs/version-0.2.0/detectors/ZeroAddress.md",7049],"883df8cc":[()=>n.e(7238).then(n.bind(n,6395)),"@site/docs/detectors/DivideBeforeMultiply.md",6395],"8c01191f":[()=>n.e(494).then(n.bind(n,1017)),"@site/versioned_docs/version-0.2.0/detectors/NeverAccessedVariables.md",1017],"8c0243db":[()=>n.e(7839).then(n.bind(n,9520)),"@site/versioned_docs/version-0.1.2/detectors/DivideBeforeMultiply.md",9520],"8c74c05e":[()=>n.e(9198).then(n.bind(n,8981)),"@site/versioned_docs/version-0.2.0/hacking/design.md",8981],"8c9dd45b":[()=>n.e(6286).then(n.bind(n,7579)),"@site/versioned_docs/version-0.2.2/hacking/design.md",7579],"8cf7c613":[()=>n.e(6274).then(n.bind(n,2234)),"@site/versioned_docs/version-0.3.1/tutorial/getting-started.md",2234],"8d6fa39c":[()=>n.e(2187).then(n.bind(n,453)),"@site/versioned_docs/version-0.2.2/detectors/ConstantAddress.md",453],"8d91c04d":[()=>n.e(4024).then(n.bind(n,2850)),"@site/versioned_docs/version-0.3.0/detectors/UnboundLoops.md",2850],"8df82fb6":[()=>n.e(301).then(n.bind(n,2964)),"@site/versioned_docs/version-0.2.1/detectors/NeverAccessedVariables.md",2964],"8e426e62":[()=>n.e(2991).then(n.bind(n,8966)),"@site/versioned_docs/version-0.4.0/detectors/DumpIsUsed.md",8966],"8e8fe4d7":[()=>n.e(9924).then(n.bind(n,2917)),"@site/versioned_docs/version-0.3.1/detectors/DivideBeforeMultiply.md",2917],"90b5d830":[()=>n.e(4318).then(n.bind(n,7230)),"@site/versioned_docs/version-0.2.2/detectors.md",7230],"91acf703":[()=>n.e(3291).then(n.bind(n,7619)),"@site/versioned_docs/version-0.4.0/detectors/ZeroAddress.md",7619],"91ee281c":[()=>n.e(2397).then(n.bind(n,3505)),"@site/versioned_docs/version-0.3.0/tutorial/cli.md",3505],"94d07e36":[()=>n.e(8235).then(n.bind(n,2345)),"@site/versioned_docs/version-0.4.0/detectors/EnsurePrgSeed.md",2345],"96e77fcb":[()=>n.e(5922).then(n.bind(n,7021)),"@site/versioned_docs/version-0.3.0/detectors/PreferAugmentedAssign.md",7021],"972c9666":[()=>n.e(1179).then(n.bind(n,590)),"@site/versioned_docs/version-0.2.0/detectors/PreferAugmentedAssign.md",590],"987a8a5d":[()=>n.e(1318).then(n.bind(n,9490)),"@site/versioned_docs/version-0.1.2/detectors/UnboundLoops.md",9490],"988b076a":[()=>n.e(9758).then(n.bind(n,2426)),"@site/versioned_docs/version-0.3.0/hacking/contributing.md",2426],"9fedf60a":[()=>n.e(3388).then(n.bind(n,9957)),"@site/versioned_docs/version-0.3.1/detectors/ZeroAddress.md",9957],a291c19d:[()=>n.e(4903).then(n.bind(n,7937)),"@site/versioned_docs/version-0.4.0/detectors/InheritedStateMutation.md",7937],a3df6930:[()=>n.e(767).then(n.bind(n,4152)),"@site/versioned_docs/version-0.4.0/tutorial/getting-started.md",4152],a4516edb:[()=>n.e(9415).then(n.t.bind(n,1664,19)),"@generated/docusaurus-plugin-content-docs/default/p/tools-misti-docs-0-1-2-a72.json",1664],a5055d90:[()=>n.e(5484).then(n.bind(n,535)),"@site/docs/hacking/design.md",535],a66f2ff0:[()=>n.e(1332).then(n.bind(n,5467)),"@site/versioned_docs/version-0.3.1/detectors/UnboundLoops.md",5467],a7456010:[()=>n.e(1235).then(n.t.bind(n,8552,19)),"@generated/docusaurus-plugin-content-pages/default/__plugin.json",8552],a7bd4aaa:[()=>n.e(7098).then(n.bind(n,4532)),"@theme/DocVersionRoot",4532],a7eb4927:[()=>n.e(8262).then(n.bind(n,936)),"@site/versioned_docs/version-0.3.0/hacking/design.md",936],a8c496ca:[()=>n.e(9304).then(n.bind(n,8812)),"@site/versioned_docs/version-0.3.1/detectors/DumpIsUsed.md",8812],a8d7d639:[()=>n.e(6701).then(n.t.bind(n,1831,19)),"@generated/docusaurus-plugin-content-docs/default/p/tools-misti-docs-0-2-0-5cb.json",1831],a94703ab:[()=>Promise.all([n.e(1869),n.e(9048)]).then(n.bind(n,2559)),"@theme/DocRoot",2559],aac87eb6:[()=>n.e(684).then(n.bind(n,4646)),"@site/versioned_docs/version-0.3.1/detectors/BranchDuplicate.md",4646],aba21aa0:[()=>n.e(5742).then(n.t.bind(n,7093,19)),"@generated/docusaurus-plugin-content-docs/default/__plugin.json",7093],acef80f0:[()=>n.e(1468).then(n.bind(n,2492)),"@site/versioned_docs/version-0.2.1/hacking/design.md",2492],aee0b8cc:[()=>n.e(5622).then(n.bind(n,3023)),"@site/versioned_docs/version-0.4.0/tools/DumpAst.md",3023],b05af762:[()=>n.e(6670).then(n.bind(n,6683)),"@site/versioned_docs/version-0.3.0/detectors.md",6683],b12d76e5:[()=>n.e(9359).then(n.bind(n,9813)),"@site/docs/detectors/DuplicatedCondition.md",9813],b3799bec:[()=>n.e(8031).then(n.bind(n,4207)),"@site/versioned_docs/version-0.2.0/detectors/ConstantAddress.md",4207],b64540ae:[()=>n.e(6412).then(n.bind(n,8560)),"@site/docs/tutorial/getting-started.md",8560],b64aaedd:[()=>n.e(5588).then(n.bind(n,4913)),"@site/versioned_docs/version-0.4.0/detectors/FalseCondition.md",4913],b78952d0:[()=>n.e(7682).then(n.bind(n,4428)),"@site/versioned_docs/version-0.3.1/detectors/FieldDoubleInit.md",4428],b80eaa74:[()=>n.e(4111).then(n.bind(n,8050)),"@site/versioned_docs/version-0.3.0/hacking/souffle.md",8050],b91dc83b:[()=>n.e(9601).then(n.bind(n,3137)),"@site/versioned_docs/version-0.2.1/tutorial/configuration.md",3137],bce595e9:[()=>n.e(8692).then(n.bind(n,3117)),"@site/versioned_docs/version-0.2.2/hacking/contributing.md",3117],bd72ef9b:[()=>n.e(1114).then(n.bind(n,9712)),"@site/versioned_docs/version-0.2.0/detectors/FieldDoubleInit.md",9712],be8ab43b:[()=>n.e(6584).then(n.bind(n,3308)),"@site/versioned_docs/version-0.3.1/hacking/tools.md",3308],c00ee666:[()=>n.e(906).then(n.bind(n,3425)),"@site/versioned_docs/version-0.3.0/detectors/PreferredStdlibApi.md",3425],c05c6791:[()=>n.e(8677).then(n.bind(n,3820)),"@site/versioned_docs/version-0.3.1/detectors/PreferredStdlibApi.md",3820],c252c345:[()=>n.e(2798).then(n.bind(n,3618)),"@site/versioned_docs/version-0.3.0/detectors/AsmIsUsed.md",3618],c377a04b:[()=>n.e(3361).then(n.bind(n,8321)),"@site/docs/index.md",8321],c49af6bd:[()=>n.e(1006).then(n.bind(n,8765)),"@site/versioned_docs/version-0.2.1/detectors/DumpIsUsed.md",8765],c55f1521:[()=>n.e(7083).then(n.bind(n,384)),"@site/versioned_docs/version-0.3.0/detectors/ConstantAddress.md",384],c5c1850c:[()=>n.e(7837).then(n.bind(n,2134)),"@site/versioned_docs/version-0.2.2/tutorial/configuration.md",2134],c5d65102:[()=>n.e(8221).then(n.bind(n,415)),"@site/versioned_docs/version-0.2.2/detectors/ZeroAddress.md",415],c7ee6afe:[()=>n.e(5459).then(n.bind(n,4729)),"@site/versioned_docs/version-0.4.0/index.md",4729],c82192ae:[()=>n.e(5321).then(n.bind(n,4482)),"@site/versioned_docs/version-0.4.0/detectors.md",4482],c926d0d4:[()=>n.e(8771).then(n.bind(n,3608)),"@site/versioned_docs/version-0.3.1/detectors.md",3608],c96954fa:[()=>n.e(2312).then(n.bind(n,263)),"@site/versioned_docs/version-0.2.2/detectors/DivideBeforeMultiply.md",263],ca178ca4:[()=>n.e(2195).then(n.bind(n,5778)),"@site/versioned_docs/version-0.2.2/detectors/ReadOnlyVariables.md",5778],cb77e040:[()=>n.e(6757).then(n.bind(n,4318)),"@site/docs/detectors/PreferredStdlibApi.md",4318],cc6d1ce2:[()=>n.e(3750).then(n.bind(n,433)),"@site/versioned_docs/version-0.3.0/detectors/ArgCopyMutation.md",433],cd411a47:[()=>n.e(4442).then(n.bind(n,4802)),"@site/versioned_docs/version-0.1.2/hacking/souffle.md",4802],ce7f72c2:[()=>n.e(5200).then(n.bind(n,4795)),"@site/versioned_docs/version-0.3.1/hacking/contributing.md",4795],cf2c24d9:[()=>n.e(338).then(n.bind(n,9)),"@site/versioned_docs/version-0.4.0/detectors/UnboundLoops.md",9],cf5f971a:[()=>n.e(7003).then(n.bind(n,1963)),"@site/versioned_docs/version-0.1.2/hacking/tools.md",1963],d147047e:[()=>n.e(7965).then(n.bind(n,2643)),"@site/versioned_docs/version-0.3.1/detectors/InheritedStateMutation.md",2643],d15cc687:[()=>n.e(6406).then(n.bind(n,7033)),"@site/versioned_docs/version-0.2.1/detectors/BranchDuplicate.md",7033],d1781038:[()=>n.e(6633).then(n.bind(n,5e3)),"@site/versioned_docs/version-0.2.1/index.md",5e3],d2aaf676:[()=>n.e(4040).then(n.bind(n,9323)),"@site/docs/detectors/NeverAccessedVariables.md",9323],d2d53d04:[()=>n.e(2537).then(n.bind(n,8023)),"@site/versioned_docs/version-0.2.2/tutorial/blueprint.md",8023],d2f295f4:[()=>n.e(7242).then(n.bind(n,5077)),"@site/docs/tools/DumpCfg.md",5077],d3996cd7:[()=>n.e(5664).then(n.bind(n,9735)),"@site/docs/tools/DumpAst.md",9735],d46ee8ed:[()=>n.e(8072).then(n.t.bind(n,7884,19)),"@generated/docusaurus-plugin-content-docs/default/p/tools-misti-docs-0-3-1-0dc.json",7884],d6f3e79e:[()=>n.e(1678).then(n.bind(n,1747)),"@site/versioned_docs/version-0.1.2/detectors/ReadOnlyVariables.md",1747],d7c99f30:[()=>n.e(8904).then(n.bind(n,7389)),"@site/versioned_docs/version-0.4.0/detectors/OptimalMathFunction.md",7389],d7d99e1d:[()=>n.e(9076).then(n.bind(n,668)),"@site/versioned_docs/version-0.2.2/detectors/NeverAccessedVariables.md",668],d9542fcf:[()=>n.e(3590).then(n.bind(n,2866)),"@site/versioned_docs/version-0.2.0/detectors/BranchDuplicate.md",2866],dc55925b:[()=>n.e(8546).then(n.bind(n,5729)),"@site/docs/detectors/EnsurePrgSeed.md",5729],dd8730c9:[()=>n.e(8137).then(n.t.bind(n,2205,19)),"@generated/docusaurus-plugin-content-docs/default/p/tools-misti-docs-next-ec9.json",2205],e1c88a01:[()=>n.e(488).then(n.t.bind(n,9423,19)),"@generated/docusaurus-plugin-content-docs/default/p/tools-misti-docs-0-2-2-574.json",9423],e2ad9c7a:[()=>n.e(5945).then(n.bind(n,4193)),"@site/versioned_docs/version-0.3.1/hacking/design.md",4193],e3b47995:[()=>n.e(1171).then(n.bind(n,7112)),"@site/docs/detectors/BranchDuplicate.md",7112],e3c4fe0a:[()=>n.e(9428).then(n.bind(n,503)),"@site/versioned_docs/version-0.3.0/detectors/FieldDoubleInit.md",503],e4a43c7d:[()=>Promise.all([n.e(1869),n.e(7348)]).then(n.bind(n,3888)),"@site/src/pages/tools/misti/index.tsx",3888],e5aa38d8:[()=>n.e(4082).then(n.bind(n,7817)),"@site/versioned_docs/version-0.3.0/detectors/DumpIsUsed.md",7817],e63578c3:[()=>n.e(9641).then(n.bind(n,7717)),"@site/versioned_docs/version-0.3.0/tutorial/configuration.md",7717],e6ef21e7:[()=>n.e(4984).then(n.bind(n,1053)),"@site/versioned_docs/version-0.4.0/detectors/DuplicatedCondition.md",1053],e9524270:[()=>n.e(2167).then(n.bind(n,7019)),"@site/docs/tutorial/ci-cd.md",7019],ea064c97:[()=>n.e(5508).then(n.bind(n,3195)),"@site/versioned_docs/version-0.4.0/detectors/AsmIsUsed.md",3195],ea8d0df0:[()=>n.e(335).then(n.bind(n,4905)),"@site/docs/hacking/custom-detector.md",4905],ebcc9167:[()=>n.e(6387).then(n.bind(n,4416)),"@site/versioned_docs/version-0.3.0/detectors/NeverAccessedVariables.md",4416],ed017323:[()=>n.e(4138).then(n.bind(n,8065)),"@site/docs/hacking/contributing.md",8065],ed2e6971:[()=>n.e(8300).then(n.bind(n,8315)),"@site/docs/detectors/UnusedOptional.md",8315],edf1e52e:[()=>n.e(3434).then(n.bind(n,3744)),"@site/versioned_docs/version-0.1.2/detectors/NeverAccessedVariables.md",3744],effcc73a:[()=>n.e(485).then(n.bind(n,968)),"@site/versioned_docs/version-0.4.0/hacking/souffle.md",968],f18c7db7:[()=>n.e(9959).then(n.bind(n,4172)),"@site/versioned_docs/version-0.2.0/detectors.md",4172],f2bdb0f5:[()=>n.e(8836).then(n.bind(n,1582)),"@site/versioned_docs/version-0.2.1/hacking/souffle.md",1582],f3297ff5:[()=>n.e(1537).then(n.bind(n,7942)),"@site/docs/detectors/ReadOnlyVariables.md",7942],f3466e67:[()=>n.e(278).then(n.bind(n,252)),"@site/versioned_docs/version-0.1.2/index.md",252],f34cb5e0:[()=>n.e(9337).then(n.bind(n,9385)),"@site/docs/detectors/FalseCondition.md",9385],f4d075b1:[()=>n.e(7378).then(n.bind(n,462)),"@site/versioned_docs/version-0.2.2/detectors/FieldDoubleInit.md",462],f503d00c:[()=>n.e(2819).then(n.bind(n,7563)),"@site/versioned_docs/version-0.2.1/detectors/FieldDoubleInit.md",7563],f553073e:[()=>n.e(223).then(n.bind(n,6141)),"@site/versioned_docs/version-0.4.0/detectors/StringReceiversOverlap.md",6141],f5772bf1:[()=>n.e(1697).then(n.bind(n,1611)),"@site/versioned_docs/version-0.2.1/tutorial/getting-started.md",1611],f58fcc43:[()=>n.e(219).then(n.bind(n,9089)),"@site/versioned_docs/version-0.4.0/hacking/custom-detector.md",9089],f5bf49b8:[()=>n.e(243).then(n.bind(n,7857)),"@site/versioned_docs/version-0.2.1/detectors/PreferAugmentedAssign.md",7857],f6f2b22b:[()=>n.e(2091).then(n.bind(n,5208)),"@site/versioned_docs/version-0.3.1/tutorial/cli.md",5208],f752d1db:[()=>n.e(5900).then(n.bind(n,8656)),"@site/versioned_docs/version-0.4.0/tutorial/ci-cd.md",8656],f7ab1f3a:[()=>n.e(3754).then(n.bind(n,4856)),"@site/versioned_docs/version-0.1.2/hacking/design.md",4856],f97c3fca:[()=>n.e(877).then(n.bind(n,4297)),"@site/docs/detectors/ConstantAddress.md",4297],faae61e5:[()=>n.e(5859).then(n.bind(n,8714)),"@site/docs/detectors.md",8714],fafa7ec8:[()=>n.e(4330).then(n.bind(n,706)),"@site/versioned_docs/version-0.2.2/detectors/DumpIsUsed.md",706],fbbe250b:[()=>n.e(7173).then(n.bind(n,3034)),"@site/docs/tutorial/configuration.md",3034],fcd86191:[()=>n.e(6752).then(n.bind(n,6493)),"@site/versioned_docs/version-0.2.2/hacking/custom-detector.md",6493],fe7c01fc:[()=>n.e(6854).then(n.bind(n,7437)),"@site/versioned_docs/version-0.3.0/detectors/BranchDuplicate.md",7437],ff0db780:[()=>n.e(1598).then(n.bind(n,4263)),"@site/versioned_docs/version-0.2.0/hacking/contributing.md",4263]};var a=n(4848);function l(e){let{error:t,retry:n,pastDelay:o}=e;return t?(0,a.jsxs)("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"},children:[(0,a.jsx)("p",{children:String(t)}),(0,a.jsx)("div",{children:(0,a.jsx)("button",{type:"button",onClick:n,children:"Retry"})})]}):o?(0,a.jsx)("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:(0,a.jsx)("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb",children:(0,a.jsxs)("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2",children:[(0,a.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,a.jsx)("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,a.jsx)("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,a.jsx)("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,a.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,a.jsx)("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,a.jsx)("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,a.jsx)("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,a.jsx)("circle",{cx:"22",cy:"22",r:"8",children:(0,a.jsx)("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"})})]})})}):null}var c=n(6921),d=n(3102);function u(e,t){if("*"===e)return r()({loading:l,loader:()=>n.e(2237).then(n.bind(n,2237)),modules:["@theme/NotFound"],webpack:()=>[2237],render(e,t){const n=e.default;return(0,a.jsx)(d.W,{value:{plugin:{name:"native",id:"default"}},children:(0,a.jsx)(n,{...t})})}});const o=i[`${e}-${t}`],u={},p=[],f=[],m=(0,c.A)(o);return Object.entries(m).forEach((e=>{let[t,n]=e;const o=s[n];o&&(u[t]=o[0],p.push(o[1]),f.push(o[2]))})),r().Map({loading:l,loader:u,modules:p,webpack:()=>f,render(t,n){const r=JSON.parse(JSON.stringify(o));Object.entries(t).forEach((t=>{let[n,o]=t;const i=o.default;if(!i)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof i&&"function"!=typeof i||Object.keys(o).filter((e=>"default"!==e)).forEach((e=>{i[e]=o[e]}));let s=r;const a=n.split(".");a.slice(0,-1).forEach((e=>{s=s[e]})),s[a[a.length-1]]=i}));const i=r.__comp;delete r.__comp;const s=r.__context;delete r.__context;const l=r.__props;return delete r.__props,(0,a.jsx)(d.W,{value:s,children:(0,a.jsx)(i,{...r,...l,...n})})}})}const p=[{path:"/markdown-page",component:u("/markdown-page","3d7"),exact:!0},{path:"/tools/misti/",component:u("/tools/misti/","64a"),exact:!0},{path:"/tools/misti/docs",component:u("/tools/misti/docs","63f"),routes:[{path:"/tools/misti/docs/0.1.2",component:u("/tools/misti/docs/0.1.2","f8a"),routes:[{path:"/tools/misti/docs/0.1.2",component:u("/tools/misti/docs/0.1.2","a68"),routes:[{path:"/tools/misti/docs/0.1.2/",component:u("/tools/misti/docs/0.1.2/","e00"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply","d7c"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables","95b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables","ec0"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/detectors/UnboundLoops",component:u("/tools/misti/docs/0.1.2/detectors/UnboundLoops","097"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/detectors/ZeroAddress",component:u("/tools/misti/docs/0.1.2/detectors/ZeroAddress","051"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/hacking/CHANGELOG",component:u("/tools/misti/docs/0.1.2/hacking/CHANGELOG","87f"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/hacking/contributing",component:u("/tools/misti/docs/0.1.2/hacking/contributing","a2a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/hacking/custom-detector",component:u("/tools/misti/docs/0.1.2/hacking/custom-detector","00e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/hacking/design",component:u("/tools/misti/docs/0.1.2/hacking/design","745"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/hacking/souffle",component:u("/tools/misti/docs/0.1.2/hacking/souffle","cc7"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/hacking/tools",component:u("/tools/misti/docs/0.1.2/hacking/tools","d9d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/tutorial/configuration",component:u("/tools/misti/docs/0.1.2/tutorial/configuration","c1b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.1.2/tutorial/getting-started",component:u("/tools/misti/docs/0.1.2/tutorial/getting-started","3e0"),exact:!0,sidebar:"sidebar"}]}]},{path:"/tools/misti/docs/0.2.0",component:u("/tools/misti/docs/0.2.0","2c6"),routes:[{path:"/tools/misti/docs/0.2.0",component:u("/tools/misti/docs/0.2.0","635"),routes:[{path:"/tools/misti/docs/0.2.0/",component:u("/tools/misti/docs/0.2.0/","7ad"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors",component:u("/tools/misti/docs/0.2.0/detectors","e72"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/BranchDuplicate",component:u("/tools/misti/docs/0.2.0/detectors/BranchDuplicate","69d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/ConstantAddress",component:u("/tools/misti/docs/0.2.0/detectors/ConstantAddress","969"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply","505"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/DumpIsUsed",component:u("/tools/misti/docs/0.2.0/detectors/DumpIsUsed","02c"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/FieldDoubleInit",component:u("/tools/misti/docs/0.2.0/detectors/FieldDoubleInit","785"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables","308"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign",component:u("/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign","653"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables","89d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/UnboundLoops",component:u("/tools/misti/docs/0.2.0/detectors/UnboundLoops","e75"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/detectors/ZeroAddress",component:u("/tools/misti/docs/0.2.0/detectors/ZeroAddress","f88"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/hacking/contributing",component:u("/tools/misti/docs/0.2.0/hacking/contributing","576"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/hacking/custom-detector",component:u("/tools/misti/docs/0.2.0/hacking/custom-detector","7e7"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/hacking/design",component:u("/tools/misti/docs/0.2.0/hacking/design","0d7"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/hacking/souffle",component:u("/tools/misti/docs/0.2.0/hacking/souffle","7c7"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/hacking/tools",component:u("/tools/misti/docs/0.2.0/hacking/tools","a79"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/tutorial/ci-cd",component:u("/tools/misti/docs/0.2.0/tutorial/ci-cd","d75"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/tutorial/configuration",component:u("/tools/misti/docs/0.2.0/tutorial/configuration","cf5"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.0/tutorial/getting-started",component:u("/tools/misti/docs/0.2.0/tutorial/getting-started","692"),exact:!0,sidebar:"sidebar"}]}]},{path:"/tools/misti/docs/0.2.1",component:u("/tools/misti/docs/0.2.1","5f6"),routes:[{path:"/tools/misti/docs/0.2.1",component:u("/tools/misti/docs/0.2.1","ee6"),routes:[{path:"/tools/misti/docs/0.2.1/",component:u("/tools/misti/docs/0.2.1/","b26"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors",component:u("/tools/misti/docs/0.2.1/detectors","854"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/BranchDuplicate",component:u("/tools/misti/docs/0.2.1/detectors/BranchDuplicate","763"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/ConstantAddress",component:u("/tools/misti/docs/0.2.1/detectors/ConstantAddress","265"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply","607"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/DumpIsUsed",component:u("/tools/misti/docs/0.2.1/detectors/DumpIsUsed","f66"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/FieldDoubleInit",component:u("/tools/misti/docs/0.2.1/detectors/FieldDoubleInit","9c2"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables","586"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign",component:u("/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign","10d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables","c93"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/UnboundLoops",component:u("/tools/misti/docs/0.2.1/detectors/UnboundLoops","56e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/detectors/ZeroAddress",component:u("/tools/misti/docs/0.2.1/detectors/ZeroAddress","460"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/hacking/contributing",component:u("/tools/misti/docs/0.2.1/hacking/contributing","2b2"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/hacking/custom-detector",component:u("/tools/misti/docs/0.2.1/hacking/custom-detector","be8"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/hacking/design",component:u("/tools/misti/docs/0.2.1/hacking/design","813"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/hacking/souffle",component:u("/tools/misti/docs/0.2.1/hacking/souffle","844"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/hacking/tools",component:u("/tools/misti/docs/0.2.1/hacking/tools","452"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/tutorial/ci-cd",component:u("/tools/misti/docs/0.2.1/tutorial/ci-cd","988"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/tutorial/configuration",component:u("/tools/misti/docs/0.2.1/tutorial/configuration","910"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.1/tutorial/getting-started",component:u("/tools/misti/docs/0.2.1/tutorial/getting-started","f03"),exact:!0,sidebar:"sidebar"}]}]},{path:"/tools/misti/docs/0.2.2",component:u("/tools/misti/docs/0.2.2","211"),routes:[{path:"/tools/misti/docs/0.2.2",component:u("/tools/misti/docs/0.2.2","1f0"),routes:[{path:"/tools/misti/docs/0.2.2/",component:u("/tools/misti/docs/0.2.2/","4ce"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors",component:u("/tools/misti/docs/0.2.2/detectors","a63"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/BranchDuplicate",component:u("/tools/misti/docs/0.2.2/detectors/BranchDuplicate","c5b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/ConstantAddress",component:u("/tools/misti/docs/0.2.2/detectors/ConstantAddress","21b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply","4dc"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/DumpIsUsed",component:u("/tools/misti/docs/0.2.2/detectors/DumpIsUsed","fe3"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/FieldDoubleInit",component:u("/tools/misti/docs/0.2.2/detectors/FieldDoubleInit","50d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables","716"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign",component:u("/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign","0d0"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables","3b1"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/UnboundLoops",component:u("/tools/misti/docs/0.2.2/detectors/UnboundLoops","b9e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/detectors/ZeroAddress",component:u("/tools/misti/docs/0.2.2/detectors/ZeroAddress","98a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/hacking/contributing",component:u("/tools/misti/docs/0.2.2/hacking/contributing","894"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/hacking/custom-detector",component:u("/tools/misti/docs/0.2.2/hacking/custom-detector","2df"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/hacking/design",component:u("/tools/misti/docs/0.2.2/hacking/design","fe0"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/hacking/souffle",component:u("/tools/misti/docs/0.2.2/hacking/souffle","8b1"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/hacking/tools",component:u("/tools/misti/docs/0.2.2/hacking/tools","191"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/tutorial/blueprint",component:u("/tools/misti/docs/0.2.2/tutorial/blueprint","9e1"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/tutorial/ci-cd",component:u("/tools/misti/docs/0.2.2/tutorial/ci-cd","260"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/tutorial/configuration",component:u("/tools/misti/docs/0.2.2/tutorial/configuration","7d4"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.2.2/tutorial/getting-started",component:u("/tools/misti/docs/0.2.2/tutorial/getting-started","825"),exact:!0,sidebar:"sidebar"}]}]},{path:"/tools/misti/docs/0.3.0",component:u("/tools/misti/docs/0.3.0","d97"),routes:[{path:"/tools/misti/docs/0.3.0",component:u("/tools/misti/docs/0.3.0","be7"),routes:[{path:"/tools/misti/docs/0.3.0/",component:u("/tools/misti/docs/0.3.0/","d94"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors",component:u("/tools/misti/docs/0.3.0/detectors","558"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/ArgCopyMutation",component:u("/tools/misti/docs/0.3.0/detectors/ArgCopyMutation","0ef"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/AsmIsUsed",component:u("/tools/misti/docs/0.3.0/detectors/AsmIsUsed","dc6"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/BranchDuplicate",component:u("/tools/misti/docs/0.3.0/detectors/BranchDuplicate","656"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/ConstantAddress",component:u("/tools/misti/docs/0.3.0/detectors/ConstantAddress","74f"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply","963"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/DumpIsUsed",component:u("/tools/misti/docs/0.3.0/detectors/DumpIsUsed","e8b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/FieldDoubleInit",component:u("/tools/misti/docs/0.3.0/detectors/FieldDoubleInit","aa1"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/InheritedStateMutation",component:u("/tools/misti/docs/0.3.0/detectors/InheritedStateMutation","911"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables","6bb"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign",component:u("/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign","46a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi",component:u("/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi","544"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables","460"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap",component:u("/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap","bea"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/UnboundLoops",component:u("/tools/misti/docs/0.3.0/detectors/UnboundLoops","d61"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/detectors/ZeroAddress",component:u("/tools/misti/docs/0.3.0/detectors/ZeroAddress","7e8"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/hacking/contributing",component:u("/tools/misti/docs/0.3.0/hacking/contributing","e13"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/hacking/custom-detector",component:u("/tools/misti/docs/0.3.0/hacking/custom-detector","178"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/hacking/design",component:u("/tools/misti/docs/0.3.0/hacking/design","653"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/hacking/souffle",component:u("/tools/misti/docs/0.3.0/hacking/souffle","35c"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/hacking/tools",component:u("/tools/misti/docs/0.3.0/hacking/tools","b51"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/tutorial/blueprint",component:u("/tools/misti/docs/0.3.0/tutorial/blueprint","894"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/tutorial/ci-cd",component:u("/tools/misti/docs/0.3.0/tutorial/ci-cd","2c5"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/tutorial/cli",component:u("/tools/misti/docs/0.3.0/tutorial/cli","e3e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/tutorial/configuration",component:u("/tools/misti/docs/0.3.0/tutorial/configuration","1f6"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.0/tutorial/getting-started",component:u("/tools/misti/docs/0.3.0/tutorial/getting-started","989"),exact:!0,sidebar:"sidebar"}]}]},{path:"/tools/misti/docs/0.3.1",component:u("/tools/misti/docs/0.3.1","ce6"),routes:[{path:"/tools/misti/docs/0.3.1",component:u("/tools/misti/docs/0.3.1","7d2"),routes:[{path:"/tools/misti/docs/0.3.1/",component:u("/tools/misti/docs/0.3.1/","6da"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors",component:u("/tools/misti/docs/0.3.1/detectors","36d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/ArgCopyMutation",component:u("/tools/misti/docs/0.3.1/detectors/ArgCopyMutation","742"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/AsmIsUsed",component:u("/tools/misti/docs/0.3.1/detectors/AsmIsUsed","f46"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/BranchDuplicate",component:u("/tools/misti/docs/0.3.1/detectors/BranchDuplicate","a80"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/ConstantAddress",component:u("/tools/misti/docs/0.3.1/detectors/ConstantAddress","eb7"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply","908"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/DumpIsUsed",component:u("/tools/misti/docs/0.3.1/detectors/DumpIsUsed","6bc"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/FieldDoubleInit",component:u("/tools/misti/docs/0.3.1/detectors/FieldDoubleInit","385"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/InheritedStateMutation",component:u("/tools/misti/docs/0.3.1/detectors/InheritedStateMutation","810"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables","7d1"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign",component:u("/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign","e3f"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi",component:u("/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi","05c"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables","501"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap",component:u("/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap","1a3"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/UnboundLoops",component:u("/tools/misti/docs/0.3.1/detectors/UnboundLoops","92f"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/detectors/ZeroAddress",component:u("/tools/misti/docs/0.3.1/detectors/ZeroAddress","ccb"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/hacking/contributing",component:u("/tools/misti/docs/0.3.1/hacking/contributing","b74"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/hacking/custom-detector",component:u("/tools/misti/docs/0.3.1/hacking/custom-detector","3e6"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/hacking/design",component:u("/tools/misti/docs/0.3.1/hacking/design","40b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/hacking/souffle",component:u("/tools/misti/docs/0.3.1/hacking/souffle","53a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/hacking/tools",component:u("/tools/misti/docs/0.3.1/hacking/tools","035"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/tutorial/blueprint",component:u("/tools/misti/docs/0.3.1/tutorial/blueprint","5ec"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/tutorial/ci-cd",component:u("/tools/misti/docs/0.3.1/tutorial/ci-cd","e30"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/tutorial/cli",component:u("/tools/misti/docs/0.3.1/tutorial/cli","3c0"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/tutorial/configuration",component:u("/tools/misti/docs/0.3.1/tutorial/configuration","160"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.3.1/tutorial/getting-started",component:u("/tools/misti/docs/0.3.1/tutorial/getting-started","493"),exact:!0,sidebar:"sidebar"}]}]},{path:"/tools/misti/docs/next",component:u("/tools/misti/docs/next","14d"),routes:[{path:"/tools/misti/docs/next",component:u("/tools/misti/docs/next","6d6"),routes:[{path:"/tools/misti/docs/next/",component:u("/tools/misti/docs/next/","ac0"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors",component:u("/tools/misti/docs/next/detectors","3fb"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/ArgCopyMutation",component:u("/tools/misti/docs/next/detectors/ArgCopyMutation","e79"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/AsmIsUsed",component:u("/tools/misti/docs/next/detectors/AsmIsUsed","be7"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/BranchDuplicate",component:u("/tools/misti/docs/next/detectors/BranchDuplicate","046"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/ConstantAddress",component:u("/tools/misti/docs/next/detectors/ConstantAddress","6d7"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/next/detectors/DivideBeforeMultiply","004"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/DumpIsUsed",component:u("/tools/misti/docs/next/detectors/DumpIsUsed","58e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/DuplicatedCondition",component:u("/tools/misti/docs/next/detectors/DuplicatedCondition","f7a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/EnsurePrgSeed",component:u("/tools/misti/docs/next/detectors/EnsurePrgSeed","d1b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/FalseCondition",component:u("/tools/misti/docs/next/detectors/FalseCondition","472"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/FieldDoubleInit",component:u("/tools/misti/docs/next/detectors/FieldDoubleInit","c32"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/InheritedStateMutation",component:u("/tools/misti/docs/next/detectors/InheritedStateMutation","d8d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/next/detectors/NeverAccessedVariables","94c"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/OptimalMathFunction",component:u("/tools/misti/docs/next/detectors/OptimalMathFunction","b0f"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/PreferAugmentedAssign",component:u("/tools/misti/docs/next/detectors/PreferAugmentedAssign","951"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/PreferredStdlibApi",component:u("/tools/misti/docs/next/detectors/PreferredStdlibApi","ed1"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/next/detectors/ReadOnlyVariables","c98"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/StringReceiversOverlap",component:u("/tools/misti/docs/next/detectors/StringReceiversOverlap","992"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/UnboundLoops",component:u("/tools/misti/docs/next/detectors/UnboundLoops","8e3"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/UnusedOptional",component:u("/tools/misti/docs/next/detectors/UnusedOptional","1be"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/ZeroAddress",component:u("/tools/misti/docs/next/detectors/ZeroAddress","f62"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/hacking/contributing",component:u("/tools/misti/docs/next/hacking/contributing","6f2"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/hacking/custom-detector",component:u("/tools/misti/docs/next/hacking/custom-detector","249"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/hacking/design",component:u("/tools/misti/docs/next/hacking/design","f37"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/hacking/developing-misti",component:u("/tools/misti/docs/next/hacking/developing-misti","1c9"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/hacking/souffle",component:u("/tools/misti/docs/next/hacking/souffle","6f2"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/tools",component:u("/tools/misti/docs/next/tools","13f"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/tools/DumpAst",component:u("/tools/misti/docs/next/tools/DumpAst","959"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/tools/DumpCfg",component:u("/tools/misti/docs/next/tools/DumpCfg","579"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/tools/DumpConfig",component:u("/tools/misti/docs/next/tools/DumpConfig","d2a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/tutorial/blueprint",component:u("/tools/misti/docs/next/tutorial/blueprint","885"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/tutorial/ci-cd",component:u("/tools/misti/docs/next/tutorial/ci-cd","c7b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/tutorial/cli",component:u("/tools/misti/docs/next/tutorial/cli","a3d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/tutorial/configuration",component:u("/tools/misti/docs/next/tutorial/configuration","79b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/tutorial/getting-started",component:u("/tools/misti/docs/next/tutorial/getting-started","390"),exact:!0,sidebar:"sidebar"}]}]},{path:"/tools/misti/docs",component:u("/tools/misti/docs","e20"),routes:[{path:"/tools/misti/docs",component:u("/tools/misti/docs","38f"),routes:[{path:"/tools/misti/docs/",component:u("/tools/misti/docs/","e5d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors",component:u("/tools/misti/docs/detectors","554"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/ArgCopyMutation",component:u("/tools/misti/docs/detectors/ArgCopyMutation","b98"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/AsmIsUsed",component:u("/tools/misti/docs/detectors/AsmIsUsed","956"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/BranchDuplicate",component:u("/tools/misti/docs/detectors/BranchDuplicate","959"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/ConstantAddress",component:u("/tools/misti/docs/detectors/ConstantAddress","680"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/detectors/DivideBeforeMultiply","5ee"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/DumpIsUsed",component:u("/tools/misti/docs/detectors/DumpIsUsed","d1c"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/DuplicatedCondition",component:u("/tools/misti/docs/detectors/DuplicatedCondition","dd5"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/EnsurePrgSeed",component:u("/tools/misti/docs/detectors/EnsurePrgSeed","2e8"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/FalseCondition",component:u("/tools/misti/docs/detectors/FalseCondition","b57"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/FieldDoubleInit",component:u("/tools/misti/docs/detectors/FieldDoubleInit","201"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/InheritedStateMutation",component:u("/tools/misti/docs/detectors/InheritedStateMutation","955"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/detectors/NeverAccessedVariables","9ec"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/OptimalMathFunction",component:u("/tools/misti/docs/detectors/OptimalMathFunction","54a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/PreferAugmentedAssign",component:u("/tools/misti/docs/detectors/PreferAugmentedAssign","945"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/PreferredStdlibApi",component:u("/tools/misti/docs/detectors/PreferredStdlibApi","f75"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/detectors/ReadOnlyVariables","3db"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/StringReceiversOverlap",component:u("/tools/misti/docs/detectors/StringReceiversOverlap","640"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/UnboundLoops",component:u("/tools/misti/docs/detectors/UnboundLoops","2e9"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/UnusedOptional",component:u("/tools/misti/docs/detectors/UnusedOptional","0d4"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/ZeroAddress",component:u("/tools/misti/docs/detectors/ZeroAddress","a60"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/contributing",component:u("/tools/misti/docs/hacking/contributing","76d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/custom-detector",component:u("/tools/misti/docs/hacking/custom-detector","939"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/design",component:u("/tools/misti/docs/hacking/design","c80"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/developing-misti",component:u("/tools/misti/docs/hacking/developing-misti","3fc"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/souffle",component:u("/tools/misti/docs/hacking/souffle","f7e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tools",component:u("/tools/misti/docs/tools","945"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tools/DumpAst",component:u("/tools/misti/docs/tools/DumpAst","603"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tools/DumpCfg",component:u("/tools/misti/docs/tools/DumpCfg","9f0"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tools/DumpConfig",component:u("/tools/misti/docs/tools/DumpConfig","d0f"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/blueprint",component:u("/tools/misti/docs/tutorial/blueprint","697"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/ci-cd",component:u("/tools/misti/docs/tutorial/ci-cd","768"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/cli",component:u("/tools/misti/docs/tutorial/cli","04c"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/configuration",component:u("/tools/misti/docs/tutorial/configuration","408"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/getting-started",component:u("/tools/misti/docs/tutorial/getting-started","da2"),exact:!0,sidebar:"sidebar"}]}]}]},{path:"/",component:u("/","e5f"),exact:!0},{path:"*",component:u("*")}]},6125:(e,t,n)=>{"use strict";n.d(t,{o:()=>i,x:()=>s});var o=n(6540),r=n(4848);const i=o.createContext(!1);function s(e){let{children:t}=e;const[n,s]=(0,o.useState)(!1);return(0,o.useEffect)((()=>{s(!0)}),[]),(0,r.jsx)(i.Provider,{value:n,children:t})}},8536:(e,t,n)=>{"use strict";var o=n(6540),r=n(5338),i=n(545),s=n(4625),a=n(4784),l=n(8193);const c=[n(119),n(661),n(6294),n(1043)];var d=n(8328),u=n(6347),p=n(2831),f=n(4848);function m(e){let{children:t}=e;return(0,f.jsx)(f.Fragment,{children:t})}var h=n(5260),g=n(4586),b=n(6025),v=n(6342),y=n(1003),w=n(2131),k=n(4090),x=n(2967),_=n(440),S=n(1463);function A(){const{i18n:{currentLocale:e,defaultLocale:t,localeConfigs:n}}=(0,g.A)(),o=(0,w.o)(),r=n[e].htmlLang,i=e=>e.replace("-","_");return(0,f.jsxs)(h.A,{children:[Object.entries(n).map((e=>{let[t,{htmlLang:n}]=e;return(0,f.jsx)("link",{rel:"alternate",href:o.createUrl({locale:t,fullyQualified:!0}),hrefLang:n},t)})),(0,f.jsx)("link",{rel:"alternate",href:o.createUrl({locale:t,fullyQualified:!0}),hrefLang:"x-default"}),(0,f.jsx)("meta",{property:"og:locale",content:i(r)}),Object.values(n).filter((e=>r!==e.htmlLang)).map((e=>(0,f.jsx)("meta",{property:"og:locale:alternate",content:i(e.htmlLang)},`meta-og-${e.htmlLang}`)))]})}function C(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,g.A)(),o=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,g.A)(),{pathname:o}=(0,u.zy)();return e+(0,_.applyTrailingSlash)((0,b.Ay)(o),{trailingSlash:n,baseUrl:t})}(),r=t?`${n}${t}`:o;return(0,f.jsxs)(h.A,{children:[(0,f.jsx)("meta",{property:"og:url",content:r}),(0,f.jsx)("link",{rel:"canonical",href:r})]})}function E(){const{i18n:{currentLocale:e}}=(0,g.A)(),{metadata:t,image:n}=(0,v.p)();return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsxs)(h.A,{children:[(0,f.jsx)("meta",{name:"twitter:card",content:"summary_large_image"}),(0,f.jsx)("body",{className:k.w})]}),n&&(0,f.jsx)(y.be,{image:n}),(0,f.jsx)(C,{}),(0,f.jsx)(A,{}),(0,f.jsx)(S.A,{tag:x.Cy,locale:e}),(0,f.jsx)(h.A,{children:t.map(((e,t)=>(0,f.jsx)("meta",{...e},t)))})]})}const T=new Map;var D=n(6125),L=n(6988),R=n(205);function N(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o<t;o++)n[o-1]=arguments[o];const r=c.map((t=>{const o=t.default?.[e]??t[e];return o?.(...n)}));return()=>r.forEach((e=>e?.()))}const j=function(e){let{children:t,location:n,previousLocation:o}=e;return(0,R.A)((()=>{o!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const o=t.pathname===n.pathname,r=t.hash===n.hash,i=t.search===n.search;if(o&&r&&!i)return;const{hash:s}=t;if(s){const e=decodeURIComponent(s.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:o}),N("onRouteDidUpdate",{previousLocation:o,location:n}))}),[o,n]),t};function P(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,p.u)(d.A,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class O extends o.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.A.canUseDOM?N("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=N("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),P(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return(0,f.jsx)(j,{previousLocation:this.previousLocation,location:t,children:(0,f.jsx)(u.qh,{location:t,render:()=>e})})}}const I=O,M="__docusaurus-base-url-issue-banner-container",F="__docusaurus-base-url-issue-banner",B="__docusaurus-base-url-issue-banner-suggestion-container";function U(e){return`\ndocument.addEventListener('DOMContentLoaded', function maybeInsertBanner() {\n var shouldInsert = typeof window['docusaurus'] === 'undefined';\n shouldInsert && insertBanner();\n});\n\nfunction insertBanner() {\n var bannerContainer = document.createElement('div');\n bannerContainer.id = '${M}';\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="${F}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${B}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n document.body.prepend(bannerContainer);\n var suggestionContainer = document.getElementById('${B}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function z(){const{siteConfig:{baseUrl:e}}=(0,g.A)();return(0,f.jsx)(f.Fragment,{children:!l.A.canUseDOM&&(0,f.jsx)(h.A,{children:(0,f.jsx)("script",{children:U(e)})})})}function $(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,g.A)(),{pathname:n}=(0,u.zy)();return t&&n===e?(0,f.jsx)(z,{}):null}function V(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:o,localeConfigs:r}}=(0,g.A)(),i=(0,b.Ay)(e),{htmlLang:s,direction:a}=r[o];return(0,f.jsxs)(h.A,{children:[(0,f.jsx)("html",{lang:s,dir:a}),(0,f.jsx)("title",{children:t}),(0,f.jsx)("meta",{property:"og:title",content:t}),(0,f.jsx)("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&(0,f.jsx)("meta",{name:"robots",content:"noindex, nofollow"}),e&&(0,f.jsx)("link",{rel:"icon",href:i})]})}var q=n(7489),H=n(2303);function G(){const e=(0,H.A)();return(0,f.jsx)(h.A,{children:(0,f.jsx)("html",{"data-has-hydrated":e})})}const W=(0,p.v)(d.A);function Z(){const e=function(e){if(T.has(e.pathname))return{...e,pathname:T.get(e.pathname)};if((0,p.u)(d.A,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return T.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return T.set(e.pathname,t),{...e,pathname:t}}((0,u.zy)());return(0,f.jsx)(I,{location:e,children:W})}function Q(){return(0,f.jsx)(q.A,{children:(0,f.jsx)(L.l,{children:(0,f.jsxs)(D.x,{children:[(0,f.jsxs)(m,{children:[(0,f.jsx)(V,{}),(0,f.jsx)(E,{}),(0,f.jsx)($,{}),(0,f.jsx)(Z,{})]}),(0,f.jsx)(G,{})]})})})}var K=n(4054);const Y=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const o=document.createElement("link");o.setAttribute("rel","prefetch"),o.setAttribute("href",e),o.onload=()=>t(),o.onerror=()=>n();const r=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;r?.appendChild(o)}))}:function(e){return new Promise(((t,n)=>{const o=new XMLHttpRequest;o.open("GET",e,!0),o.withCredentials=!0,o.onload=()=>{200===o.status?t():n()},o.send(null)}))};var X=n(6921);const J=new Set,ee=new Set,te=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,ne={prefetch:e=>{if(!(e=>!te()&&!ee.has(e)&&!J.has(e))(e))return!1;J.add(e);const t=(0,p.u)(d.A,e).flatMap((e=>{return t=e.route.path,Object.entries(K).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,X.A)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?Y(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!te()&&!ee.has(e))(e)&&(ee.add(e),P(e))},oe=Object.freeze(ne);function re(e){let{children:t}=e;return"hash"===a.default.future.experimental_router?(0,f.jsx)(s.I9,{children:t}):(0,f.jsx)(s.Kd,{children:t})}const ie=Boolean(!0);if(l.A.canUseDOM){window.docusaurus=oe;const e=document.getElementById("__docusaurus"),t=(0,f.jsx)(i.vd,{children:(0,f.jsx)(re,{children:(0,f.jsx)(Q,{})})}),n=(e,t)=>{console.error("Docusaurus React Root onRecoverableError:",e,t)},s=()=>{if(window.docusaurusRoot)window.docusaurusRoot.render(t);else if(ie)window.docusaurusRoot=r.hydrateRoot(e,t,{onRecoverableError:n});else{const o=r.createRoot(e,{onRecoverableError:n});o.render(t),window.docusaurusRoot=o}};P(window.location.pathname).then((()=>{(0,o.startTransition)(s)}))}},6988:(e,t,n)=>{"use strict";n.d(t,{o:()=>u,l:()=>p});var o=n(6540),r=n(4784);const i=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/tools/misti/docs","versions":[{"name":"current","label":"Next","isLast":false,"path":"/tools/misti/docs/next","mainDocId":"intro","docs":[{"id":"detectors","path":"/tools/misti/docs/next/detectors","sidebar":"sidebar"},{"id":"detectors/ArgCopyMutation","path":"/tools/misti/docs/next/detectors/ArgCopyMutation","sidebar":"sidebar"},{"id":"detectors/AsmIsUsed","path":"/tools/misti/docs/next/detectors/AsmIsUsed","sidebar":"sidebar"},{"id":"detectors/BranchDuplicate","path":"/tools/misti/docs/next/detectors/BranchDuplicate","sidebar":"sidebar"},{"id":"detectors/ConstantAddress","path":"/tools/misti/docs/next/detectors/ConstantAddress","sidebar":"sidebar"},{"id":"detectors/DivideBeforeMultiply","path":"/tools/misti/docs/next/detectors/DivideBeforeMultiply","sidebar":"sidebar"},{"id":"detectors/DumpIsUsed","path":"/tools/misti/docs/next/detectors/DumpIsUsed","sidebar":"sidebar"},{"id":"detectors/DuplicatedCondition","path":"/tools/misti/docs/next/detectors/DuplicatedCondition","sidebar":"sidebar"},{"id":"detectors/EnsurePrgSeed","path":"/tools/misti/docs/next/detectors/EnsurePrgSeed","sidebar":"sidebar"},{"id":"detectors/FalseCondition","path":"/tools/misti/docs/next/detectors/FalseCondition","sidebar":"sidebar"},{"id":"detectors/FieldDoubleInit","path":"/tools/misti/docs/next/detectors/FieldDoubleInit","sidebar":"sidebar"},{"id":"detectors/InheritedStateMutation","path":"/tools/misti/docs/next/detectors/InheritedStateMutation","sidebar":"sidebar"},{"id":"detectors/NeverAccessedVariables","path":"/tools/misti/docs/next/detectors/NeverAccessedVariables","sidebar":"sidebar"},{"id":"detectors/OptimalMathFunction","path":"/tools/misti/docs/next/detectors/OptimalMathFunction","sidebar":"sidebar"},{"id":"detectors/PreferAugmentedAssign","path":"/tools/misti/docs/next/detectors/PreferAugmentedAssign","sidebar":"sidebar"},{"id":"detectors/PreferredStdlibApi","path":"/tools/misti/docs/next/detectors/PreferredStdlibApi","sidebar":"sidebar"},{"id":"detectors/ReadOnlyVariables","path":"/tools/misti/docs/next/detectors/ReadOnlyVariables","sidebar":"sidebar"},{"id":"detectors/StringReceiversOverlap","path":"/tools/misti/docs/next/detectors/StringReceiversOverlap","sidebar":"sidebar"},{"id":"detectors/UnboundLoops","path":"/tools/misti/docs/next/detectors/UnboundLoops","sidebar":"sidebar"},{"id":"detectors/UnusedOptional","path":"/tools/misti/docs/next/detectors/UnusedOptional","sidebar":"sidebar"},{"id":"detectors/ZeroAddress","path":"/tools/misti/docs/next/detectors/ZeroAddress","sidebar":"sidebar"},{"id":"hacking/contributing","path":"/tools/misti/docs/next/hacking/contributing","sidebar":"sidebar"},{"id":"hacking/custom-detector","path":"/tools/misti/docs/next/hacking/custom-detector","sidebar":"sidebar"},{"id":"hacking/design","path":"/tools/misti/docs/next/hacking/design","sidebar":"sidebar"},{"id":"hacking/developing-misti","path":"/tools/misti/docs/next/hacking/developing-misti","sidebar":"sidebar"},{"id":"hacking/souffle","path":"/tools/misti/docs/next/hacking/souffle","sidebar":"sidebar"},{"id":"intro","path":"/tools/misti/docs/next/","sidebar":"sidebar"},{"id":"tools","path":"/tools/misti/docs/next/tools","sidebar":"sidebar"},{"id":"tools/DumpAst","path":"/tools/misti/docs/next/tools/DumpAst","sidebar":"sidebar"},{"id":"tools/DumpCfg","path":"/tools/misti/docs/next/tools/DumpCfg","sidebar":"sidebar"},{"id":"tools/DumpConfig","path":"/tools/misti/docs/next/tools/DumpConfig","sidebar":"sidebar"},{"id":"tutorial/blueprint","path":"/tools/misti/docs/next/tutorial/blueprint","sidebar":"sidebar"},{"id":"tutorial/ci-cd","path":"/tools/misti/docs/next/tutorial/ci-cd","sidebar":"sidebar"},{"id":"tutorial/cli","path":"/tools/misti/docs/next/tutorial/cli","sidebar":"sidebar"},{"id":"tutorial/configuration","path":"/tools/misti/docs/next/tutorial/configuration","sidebar":"sidebar"},{"id":"tutorial/getting-started","path":"/tools/misti/docs/next/tutorial/getting-started","sidebar":"sidebar"}],"draftIds":[],"sidebars":{"sidebar":{"link":{"path":"/tools/misti/docs/next/","label":"Introduction"}}}},{"name":"0.4.0","label":"0.4.0","isLast":true,"path":"/tools/misti/docs","mainDocId":"intro","docs":[{"id":"detectors","path":"/tools/misti/docs/detectors","sidebar":"sidebar"},{"id":"detectors/ArgCopyMutation","path":"/tools/misti/docs/detectors/ArgCopyMutation","sidebar":"sidebar"},{"id":"detectors/AsmIsUsed","path":"/tools/misti/docs/detectors/AsmIsUsed","sidebar":"sidebar"},{"id":"detectors/BranchDuplicate","path":"/tools/misti/docs/detectors/BranchDuplicate","sidebar":"sidebar"},{"id":"detectors/ConstantAddress","path":"/tools/misti/docs/detectors/ConstantAddress","sidebar":"sidebar"},{"id":"detectors/DivideBeforeMultiply","path":"/tools/misti/docs/detectors/DivideBeforeMultiply","sidebar":"sidebar"},{"id":"detectors/DumpIsUsed","path":"/tools/misti/docs/detectors/DumpIsUsed","sidebar":"sidebar"},{"id":"detectors/DuplicatedCondition","path":"/tools/misti/docs/detectors/DuplicatedCondition","sidebar":"sidebar"},{"id":"detectors/EnsurePrgSeed","path":"/tools/misti/docs/detectors/EnsurePrgSeed","sidebar":"sidebar"},{"id":"detectors/FalseCondition","path":"/tools/misti/docs/detectors/FalseCondition","sidebar":"sidebar"},{"id":"detectors/FieldDoubleInit","path":"/tools/misti/docs/detectors/FieldDoubleInit","sidebar":"sidebar"},{"id":"detectors/InheritedStateMutation","path":"/tools/misti/docs/detectors/InheritedStateMutation","sidebar":"sidebar"},{"id":"detectors/NeverAccessedVariables","path":"/tools/misti/docs/detectors/NeverAccessedVariables","sidebar":"sidebar"},{"id":"detectors/OptimalMathFunction","path":"/tools/misti/docs/detectors/OptimalMathFunction","sidebar":"sidebar"},{"id":"detectors/PreferAugmentedAssign","path":"/tools/misti/docs/detectors/PreferAugmentedAssign","sidebar":"sidebar"},{"id":"detectors/PreferredStdlibApi","path":"/tools/misti/docs/detectors/PreferredStdlibApi","sidebar":"sidebar"},{"id":"detectors/ReadOnlyVariables","path":"/tools/misti/docs/detectors/ReadOnlyVariables","sidebar":"sidebar"},{"id":"detectors/StringReceiversOverlap","path":"/tools/misti/docs/detectors/StringReceiversOverlap","sidebar":"sidebar"},{"id":"detectors/UnboundLoops","path":"/tools/misti/docs/detectors/UnboundLoops","sidebar":"sidebar"},{"id":"detectors/UnusedOptional","path":"/tools/misti/docs/detectors/UnusedOptional","sidebar":"sidebar"},{"id":"detectors/ZeroAddress","path":"/tools/misti/docs/detectors/ZeroAddress","sidebar":"sidebar"},{"id":"hacking/contributing","path":"/tools/misti/docs/hacking/contributing","sidebar":"sidebar"},{"id":"hacking/custom-detector","path":"/tools/misti/docs/hacking/custom-detector","sidebar":"sidebar"},{"id":"hacking/design","path":"/tools/misti/docs/hacking/design","sidebar":"sidebar"},{"id":"hacking/developing-misti","path":"/tools/misti/docs/hacking/developing-misti","sidebar":"sidebar"},{"id":"hacking/souffle","path":"/tools/misti/docs/hacking/souffle","sidebar":"sidebar"},{"id":"intro","path":"/tools/misti/docs/","sidebar":"sidebar"},{"id":"tools","path":"/tools/misti/docs/tools","sidebar":"sidebar"},{"id":"tools/DumpAst","path":"/tools/misti/docs/tools/DumpAst","sidebar":"sidebar"},{"id":"tools/DumpCfg","path":"/tools/misti/docs/tools/DumpCfg","sidebar":"sidebar"},{"id":"tools/DumpConfig","path":"/tools/misti/docs/tools/DumpConfig","sidebar":"sidebar"},{"id":"tutorial/blueprint","path":"/tools/misti/docs/tutorial/blueprint","sidebar":"sidebar"},{"id":"tutorial/ci-cd","path":"/tools/misti/docs/tutorial/ci-cd","sidebar":"sidebar"},{"id":"tutorial/cli","path":"/tools/misti/docs/tutorial/cli","sidebar":"sidebar"},{"id":"tutorial/configuration","path":"/tools/misti/docs/tutorial/configuration","sidebar":"sidebar"},{"id":"tutorial/getting-started","path":"/tools/misti/docs/tutorial/getting-started","sidebar":"sidebar"}],"draftIds":[],"sidebars":{"sidebar":{"link":{"path":"/tools/misti/docs/","label":"Introduction"}}}},{"name":"0.3.1","label":"0.3.1","isLast":false,"path":"/tools/misti/docs/0.3.1","mainDocId":"intro","docs":[{"id":"detectors","path":"/tools/misti/docs/0.3.1/detectors","sidebar":"sidebar"},{"id":"detectors/ArgCopyMutation","path":"/tools/misti/docs/0.3.1/detectors/ArgCopyMutation","sidebar":"sidebar"},{"id":"detectors/AsmIsUsed","path":"/tools/misti/docs/0.3.1/detectors/AsmIsUsed","sidebar":"sidebar"},{"id":"detectors/BranchDuplicate","path":"/tools/misti/docs/0.3.1/detectors/BranchDuplicate","sidebar":"sidebar"},{"id":"detectors/ConstantAddress","path":"/tools/misti/docs/0.3.1/detectors/ConstantAddress","sidebar":"sidebar"},{"id":"detectors/DivideBeforeMultiply","path":"/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply","sidebar":"sidebar"},{"id":"detectors/DumpIsUsed","path":"/tools/misti/docs/0.3.1/detectors/DumpIsUsed","sidebar":"sidebar"},{"id":"detectors/FieldDoubleInit","path":"/tools/misti/docs/0.3.1/detectors/FieldDoubleInit","sidebar":"sidebar"},{"id":"detectors/InheritedStateMutation","path":"/tools/misti/docs/0.3.1/detectors/InheritedStateMutation","sidebar":"sidebar"},{"id":"detectors/NeverAccessedVariables","path":"/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables","sidebar":"sidebar"},{"id":"detectors/PreferAugmentedAssign","path":"/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign","sidebar":"sidebar"},{"id":"detectors/PreferredStdlibApi","path":"/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi","sidebar":"sidebar"},{"id":"detectors/ReadOnlyVariables","path":"/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables","sidebar":"sidebar"},{"id":"detectors/StringReceiversOverlap","path":"/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap","sidebar":"sidebar"},{"id":"detectors/UnboundLoops","path":"/tools/misti/docs/0.3.1/detectors/UnboundLoops","sidebar":"sidebar"},{"id":"detectors/ZeroAddress","path":"/tools/misti/docs/0.3.1/detectors/ZeroAddress","sidebar":"sidebar"},{"id":"hacking/contributing","path":"/tools/misti/docs/0.3.1/hacking/contributing","sidebar":"sidebar"},{"id":"hacking/custom-detector","path":"/tools/misti/docs/0.3.1/hacking/custom-detector","sidebar":"sidebar"},{"id":"hacking/design","path":"/tools/misti/docs/0.3.1/hacking/design","sidebar":"sidebar"},{"id":"hacking/souffle","path":"/tools/misti/docs/0.3.1/hacking/souffle","sidebar":"sidebar"},{"id":"hacking/tools","path":"/tools/misti/docs/0.3.1/hacking/tools","sidebar":"sidebar"},{"id":"intro","path":"/tools/misti/docs/0.3.1/","sidebar":"sidebar"},{"id":"tutorial/blueprint","path":"/tools/misti/docs/0.3.1/tutorial/blueprint","sidebar":"sidebar"},{"id":"tutorial/ci-cd","path":"/tools/misti/docs/0.3.1/tutorial/ci-cd","sidebar":"sidebar"},{"id":"tutorial/cli","path":"/tools/misti/docs/0.3.1/tutorial/cli","sidebar":"sidebar"},{"id":"tutorial/configuration","path":"/tools/misti/docs/0.3.1/tutorial/configuration","sidebar":"sidebar"},{"id":"tutorial/getting-started","path":"/tools/misti/docs/0.3.1/tutorial/getting-started","sidebar":"sidebar"}],"draftIds":[],"sidebars":{"sidebar":{"link":{"path":"/tools/misti/docs/0.3.1/","label":"Introduction"}}}},{"name":"0.3.0","label":"0.3.0","isLast":false,"path":"/tools/misti/docs/0.3.0","mainDocId":"intro","docs":[{"id":"detectors","path":"/tools/misti/docs/0.3.0/detectors","sidebar":"sidebar"},{"id":"detectors/ArgCopyMutation","path":"/tools/misti/docs/0.3.0/detectors/ArgCopyMutation","sidebar":"sidebar"},{"id":"detectors/AsmIsUsed","path":"/tools/misti/docs/0.3.0/detectors/AsmIsUsed","sidebar":"sidebar"},{"id":"detectors/BranchDuplicate","path":"/tools/misti/docs/0.3.0/detectors/BranchDuplicate","sidebar":"sidebar"},{"id":"detectors/ConstantAddress","path":"/tools/misti/docs/0.3.0/detectors/ConstantAddress","sidebar":"sidebar"},{"id":"detectors/DivideBeforeMultiply","path":"/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply","sidebar":"sidebar"},{"id":"detectors/DumpIsUsed","path":"/tools/misti/docs/0.3.0/detectors/DumpIsUsed","sidebar":"sidebar"},{"id":"detectors/FieldDoubleInit","path":"/tools/misti/docs/0.3.0/detectors/FieldDoubleInit","sidebar":"sidebar"},{"id":"detectors/InheritedStateMutation","path":"/tools/misti/docs/0.3.0/detectors/InheritedStateMutation","sidebar":"sidebar"},{"id":"detectors/NeverAccessedVariables","path":"/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables","sidebar":"sidebar"},{"id":"detectors/PreferAugmentedAssign","path":"/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign","sidebar":"sidebar"},{"id":"detectors/PreferredStdlibApi","path":"/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi","sidebar":"sidebar"},{"id":"detectors/ReadOnlyVariables","path":"/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables","sidebar":"sidebar"},{"id":"detectors/StringReceiversOverlap","path":"/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap","sidebar":"sidebar"},{"id":"detectors/UnboundLoops","path":"/tools/misti/docs/0.3.0/detectors/UnboundLoops","sidebar":"sidebar"},{"id":"detectors/ZeroAddress","path":"/tools/misti/docs/0.3.0/detectors/ZeroAddress","sidebar":"sidebar"},{"id":"hacking/contributing","path":"/tools/misti/docs/0.3.0/hacking/contributing","sidebar":"sidebar"},{"id":"hacking/custom-detector","path":"/tools/misti/docs/0.3.0/hacking/custom-detector","sidebar":"sidebar"},{"id":"hacking/design","path":"/tools/misti/docs/0.3.0/hacking/design","sidebar":"sidebar"},{"id":"hacking/souffle","path":"/tools/misti/docs/0.3.0/hacking/souffle","sidebar":"sidebar"},{"id":"hacking/tools","path":"/tools/misti/docs/0.3.0/hacking/tools","sidebar":"sidebar"},{"id":"intro","path":"/tools/misti/docs/0.3.0/","sidebar":"sidebar"},{"id":"tutorial/blueprint","path":"/tools/misti/docs/0.3.0/tutorial/blueprint","sidebar":"sidebar"},{"id":"tutorial/ci-cd","path":"/tools/misti/docs/0.3.0/tutorial/ci-cd","sidebar":"sidebar"},{"id":"tutorial/cli","path":"/tools/misti/docs/0.3.0/tutorial/cli","sidebar":"sidebar"},{"id":"tutorial/configuration","path":"/tools/misti/docs/0.3.0/tutorial/configuration","sidebar":"sidebar"},{"id":"tutorial/getting-started","path":"/tools/misti/docs/0.3.0/tutorial/getting-started","sidebar":"sidebar"}],"draftIds":[],"sidebars":{"sidebar":{"link":{"path":"/tools/misti/docs/0.3.0/","label":"Introduction"}}}},{"name":"0.2.2","label":"0.2.2","isLast":false,"path":"/tools/misti/docs/0.2.2","mainDocId":"intro","docs":[{"id":"detectors","path":"/tools/misti/docs/0.2.2/detectors","sidebar":"sidebar"},{"id":"detectors/BranchDuplicate","path":"/tools/misti/docs/0.2.2/detectors/BranchDuplicate","sidebar":"sidebar"},{"id":"detectors/ConstantAddress","path":"/tools/misti/docs/0.2.2/detectors/ConstantAddress","sidebar":"sidebar"},{"id":"detectors/DivideBeforeMultiply","path":"/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply","sidebar":"sidebar"},{"id":"detectors/DumpIsUsed","path":"/tools/misti/docs/0.2.2/detectors/DumpIsUsed","sidebar":"sidebar"},{"id":"detectors/FieldDoubleInit","path":"/tools/misti/docs/0.2.2/detectors/FieldDoubleInit","sidebar":"sidebar"},{"id":"detectors/NeverAccessedVariables","path":"/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables","sidebar":"sidebar"},{"id":"detectors/PreferAugmentedAssign","path":"/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign","sidebar":"sidebar"},{"id":"detectors/ReadOnlyVariables","path":"/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables","sidebar":"sidebar"},{"id":"detectors/UnboundLoops","path":"/tools/misti/docs/0.2.2/detectors/UnboundLoops","sidebar":"sidebar"},{"id":"detectors/ZeroAddress","path":"/tools/misti/docs/0.2.2/detectors/ZeroAddress","sidebar":"sidebar"},{"id":"hacking/contributing","path":"/tools/misti/docs/0.2.2/hacking/contributing","sidebar":"sidebar"},{"id":"hacking/custom-detector","path":"/tools/misti/docs/0.2.2/hacking/custom-detector","sidebar":"sidebar"},{"id":"hacking/design","path":"/tools/misti/docs/0.2.2/hacking/design","sidebar":"sidebar"},{"id":"hacking/souffle","path":"/tools/misti/docs/0.2.2/hacking/souffle","sidebar":"sidebar"},{"id":"hacking/tools","path":"/tools/misti/docs/0.2.2/hacking/tools","sidebar":"sidebar"},{"id":"intro","path":"/tools/misti/docs/0.2.2/","sidebar":"sidebar"},{"id":"tutorial/blueprint","path":"/tools/misti/docs/0.2.2/tutorial/blueprint","sidebar":"sidebar"},{"id":"tutorial/ci-cd","path":"/tools/misti/docs/0.2.2/tutorial/ci-cd","sidebar":"sidebar"},{"id":"tutorial/configuration","path":"/tools/misti/docs/0.2.2/tutorial/configuration","sidebar":"sidebar"},{"id":"tutorial/getting-started","path":"/tools/misti/docs/0.2.2/tutorial/getting-started","sidebar":"sidebar"}],"draftIds":[],"sidebars":{"sidebar":{"link":{"path":"/tools/misti/docs/0.2.2/","label":"Introduction"}}}},{"name":"0.2.1","label":"0.2.1","isLast":false,"path":"/tools/misti/docs/0.2.1","mainDocId":"intro","docs":[{"id":"detectors","path":"/tools/misti/docs/0.2.1/detectors","sidebar":"sidebar"},{"id":"detectors/BranchDuplicate","path":"/tools/misti/docs/0.2.1/detectors/BranchDuplicate","sidebar":"sidebar"},{"id":"detectors/ConstantAddress","path":"/tools/misti/docs/0.2.1/detectors/ConstantAddress","sidebar":"sidebar"},{"id":"detectors/DivideBeforeMultiply","path":"/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply","sidebar":"sidebar"},{"id":"detectors/DumpIsUsed","path":"/tools/misti/docs/0.2.1/detectors/DumpIsUsed","sidebar":"sidebar"},{"id":"detectors/FieldDoubleInit","path":"/tools/misti/docs/0.2.1/detectors/FieldDoubleInit","sidebar":"sidebar"},{"id":"detectors/NeverAccessedVariables","path":"/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables","sidebar":"sidebar"},{"id":"detectors/PreferAugmentedAssign","path":"/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign","sidebar":"sidebar"},{"id":"detectors/ReadOnlyVariables","path":"/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables","sidebar":"sidebar"},{"id":"detectors/UnboundLoops","path":"/tools/misti/docs/0.2.1/detectors/UnboundLoops","sidebar":"sidebar"},{"id":"detectors/ZeroAddress","path":"/tools/misti/docs/0.2.1/detectors/ZeroAddress","sidebar":"sidebar"},{"id":"hacking/contributing","path":"/tools/misti/docs/0.2.1/hacking/contributing","sidebar":"sidebar"},{"id":"hacking/custom-detector","path":"/tools/misti/docs/0.2.1/hacking/custom-detector","sidebar":"sidebar"},{"id":"hacking/design","path":"/tools/misti/docs/0.2.1/hacking/design","sidebar":"sidebar"},{"id":"hacking/souffle","path":"/tools/misti/docs/0.2.1/hacking/souffle","sidebar":"sidebar"},{"id":"hacking/tools","path":"/tools/misti/docs/0.2.1/hacking/tools","sidebar":"sidebar"},{"id":"intro","path":"/tools/misti/docs/0.2.1/","sidebar":"sidebar"},{"id":"tutorial/ci-cd","path":"/tools/misti/docs/0.2.1/tutorial/ci-cd","sidebar":"sidebar"},{"id":"tutorial/configuration","path":"/tools/misti/docs/0.2.1/tutorial/configuration","sidebar":"sidebar"},{"id":"tutorial/getting-started","path":"/tools/misti/docs/0.2.1/tutorial/getting-started","sidebar":"sidebar"}],"draftIds":[],"sidebars":{"sidebar":{"link":{"path":"/tools/misti/docs/0.2.1/","label":"Introduction"}}}},{"name":"0.2.0","label":"0.2.0","isLast":false,"path":"/tools/misti/docs/0.2.0","mainDocId":"intro","docs":[{"id":"detectors","path":"/tools/misti/docs/0.2.0/detectors","sidebar":"sidebar"},{"id":"detectors/BranchDuplicate","path":"/tools/misti/docs/0.2.0/detectors/BranchDuplicate","sidebar":"sidebar"},{"id":"detectors/ConstantAddress","path":"/tools/misti/docs/0.2.0/detectors/ConstantAddress","sidebar":"sidebar"},{"id":"detectors/DivideBeforeMultiply","path":"/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply","sidebar":"sidebar"},{"id":"detectors/DumpIsUsed","path":"/tools/misti/docs/0.2.0/detectors/DumpIsUsed","sidebar":"sidebar"},{"id":"detectors/FieldDoubleInit","path":"/tools/misti/docs/0.2.0/detectors/FieldDoubleInit","sidebar":"sidebar"},{"id":"detectors/NeverAccessedVariables","path":"/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables","sidebar":"sidebar"},{"id":"detectors/PreferAugmentedAssign","path":"/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign","sidebar":"sidebar"},{"id":"detectors/ReadOnlyVariables","path":"/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables","sidebar":"sidebar"},{"id":"detectors/UnboundLoops","path":"/tools/misti/docs/0.2.0/detectors/UnboundLoops","sidebar":"sidebar"},{"id":"detectors/ZeroAddress","path":"/tools/misti/docs/0.2.0/detectors/ZeroAddress","sidebar":"sidebar"},{"id":"hacking/contributing","path":"/tools/misti/docs/0.2.0/hacking/contributing","sidebar":"sidebar"},{"id":"hacking/custom-detector","path":"/tools/misti/docs/0.2.0/hacking/custom-detector","sidebar":"sidebar"},{"id":"hacking/design","path":"/tools/misti/docs/0.2.0/hacking/design","sidebar":"sidebar"},{"id":"hacking/souffle","path":"/tools/misti/docs/0.2.0/hacking/souffle","sidebar":"sidebar"},{"id":"hacking/tools","path":"/tools/misti/docs/0.2.0/hacking/tools","sidebar":"sidebar"},{"id":"intro","path":"/tools/misti/docs/0.2.0/","sidebar":"sidebar"},{"id":"tutorial/ci-cd","path":"/tools/misti/docs/0.2.0/tutorial/ci-cd","sidebar":"sidebar"},{"id":"tutorial/configuration","path":"/tools/misti/docs/0.2.0/tutorial/configuration","sidebar":"sidebar"},{"id":"tutorial/getting-started","path":"/tools/misti/docs/0.2.0/tutorial/getting-started","sidebar":"sidebar"}],"draftIds":[],"sidebars":{"sidebar":{"link":{"path":"/tools/misti/docs/0.2.0/","label":"Introduction"}}}},{"name":"0.1.2","label":"0.1.2","isLast":false,"path":"/tools/misti/docs/0.1.2","mainDocId":"intro","docs":[{"id":"detectors/DivideBeforeMultiply","path":"/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply","sidebar":"sidebar"},{"id":"detectors/NeverAccessedVariables","path":"/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables","sidebar":"sidebar"},{"id":"detectors/ReadOnlyVariables","path":"/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables","sidebar":"sidebar"},{"id":"detectors/UnboundLoops","path":"/tools/misti/docs/0.1.2/detectors/UnboundLoops","sidebar":"sidebar"},{"id":"detectors/ZeroAddress","path":"/tools/misti/docs/0.1.2/detectors/ZeroAddress","sidebar":"sidebar"},{"id":"hacking/CHANGELOG","path":"/tools/misti/docs/0.1.2/hacking/CHANGELOG","sidebar":"sidebar"},{"id":"hacking/contributing","path":"/tools/misti/docs/0.1.2/hacking/contributing","sidebar":"sidebar"},{"id":"hacking/custom-detector","path":"/tools/misti/docs/0.1.2/hacking/custom-detector","sidebar":"sidebar"},{"id":"hacking/design","path":"/tools/misti/docs/0.1.2/hacking/design","sidebar":"sidebar"},{"id":"hacking/souffle","path":"/tools/misti/docs/0.1.2/hacking/souffle","sidebar":"sidebar"},{"id":"hacking/tools","path":"/tools/misti/docs/0.1.2/hacking/tools","sidebar":"sidebar"},{"id":"intro","path":"/tools/misti/docs/0.1.2/","sidebar":"sidebar"},{"id":"tutorial/configuration","path":"/tools/misti/docs/0.1.2/tutorial/configuration","sidebar":"sidebar"},{"id":"tutorial/getting-started","path":"/tools/misti/docs/0.1.2/tutorial/getting-started","sidebar":"sidebar"}],"draftIds":[],"sidebars":{"sidebar":{"link":{"path":"/tools/misti/docs/0.1.2/","label":"Introduction"}}}}],"breadcrumbs":true}}}'),s=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var a=n(2654);const l=JSON.parse('{"docusaurusVersion":"3.4.0","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"3.4.0"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"3.4.0"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"3.4.0"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"3.4.0"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"3.4.0"}}}');var c=n(4848);const d={siteConfig:r.default,siteMetadata:l,globalData:i,i18n:s,codeTranslations:a},u=o.createContext(d);function p(e){let{children:t}=e;return(0,c.jsx)(u.Provider,{value:d,children:t})}},7489:(e,t,n)=>{"use strict";n.d(t,{A:()=>h});var o=n(6540),r=n(8193),i=n(5260),s=n(440),a=n(781),l=n(3102),c=n(4848);function d(e){let{error:t,tryAgain:n}=e;return(0,c.jsxs)("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"},children:[(0,c.jsx)("h1",{style:{fontSize:"3rem"},children:"This page crashed"}),(0,c.jsx)("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"},children:"Try again"}),(0,c.jsx)(u,{error:t})]})}function u(e){let{error:t}=e;const n=(0,s.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,c.jsx)("p",{style:{whiteSpace:"pre-wrap"},children:n})}function p(e){let{children:t}=e;return(0,c.jsx)(l.W,{value:{plugin:{name:"docusaurus-core-error-boundary",id:"default"}},children:t})}function f(e){let{error:t,tryAgain:n}=e;return(0,c.jsx)(p,{children:(0,c.jsxs)(h,{fallback:()=>(0,c.jsx)(d,{error:t,tryAgain:n}),children:[(0,c.jsx)(i.A,{children:(0,c.jsx)("title",{children:"Page Error"})}),(0,c.jsx)(a.A,{children:(0,c.jsx)(d,{error:t,tryAgain:n})})]})})}const m=e=>(0,c.jsx)(f,{...e});class h extends o.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){r.A.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??m)(e)}return e??null}}},8193:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const o="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,r={canUseDOM:o,canUseEventListeners:o&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:o&&"IntersectionObserver"in window,canUseViewport:o&&"screen"in window}},5260:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});n(6540);var o=n(545),r=n(4848);function i(e){return(0,r.jsx)(o.mg,{...e})}},8774:(e,t,n)=>{"use strict";n.d(t,{A:()=>f});var o=n(6540),r=n(4625),i=n(440),s=n(4586),a=n(6654),l=n(8193),c=n(3427),d=n(6025),u=n(4848);function p(e,t){let{isNavLink:n,to:p,href:f,activeClassName:m,isActive:h,"data-noBrokenLinkCheck":g,autoAddBaseUrl:b=!0,...v}=e;const{siteConfig:y}=(0,s.A)(),{trailingSlash:w,baseUrl:k}=y,x=y.future.experimental_router,{withBaseUrl:_}=(0,d.hH)(),S=(0,c.A)(),A=(0,o.useRef)(null);(0,o.useImperativeHandle)(t,(()=>A.current));const C=p||f;const E=(0,a.A)(C),T=C?.replace("pathname://","");let D=void 0!==T?(L=T,b&&(e=>e.startsWith("/"))(L)?_(L):L):void 0;var L;"hash"===x&&D?.startsWith("./")&&(D=D?.slice(1)),D&&E&&(D=(0,i.applyTrailingSlash)(D,{trailingSlash:w,baseUrl:k}));const R=(0,o.useRef)(!1),N=n?r.k2:r.N_,j=l.A.canUseIntersectionObserver,P=(0,o.useRef)(),O=()=>{R.current||null==D||(window.docusaurus.preload(D),R.current=!0)};(0,o.useEffect)((()=>(!j&&E&&null!=D&&window.docusaurus.prefetch(D),()=>{j&&P.current&&P.current.disconnect()})),[P,D,j,E]);const I=D?.startsWith("#")??!1,M=!v.target||"_self"===v.target,F=!D||!E||!M;return g||!I&&F||S.collectLink(D),v.id&&S.collectAnchor(v.id),F?(0,u.jsx)("a",{ref:A,href:D,...C&&!E&&{target:"_blank",rel:"noopener noreferrer"},...v}):(0,u.jsx)(N,{...v,onMouseEnter:O,onTouchStart:O,innerRef:e=>{A.current=e,j&&e&&E&&(P.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(P.current.unobserve(e),P.current.disconnect(),null!=D&&window.docusaurus.prefetch(D))}))})),P.current.observe(e))},to:D,...n&&{isActive:h,activeClassName:m}})}const f=o.forwardRef(p)},418:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});const o=()=>null},1312:(e,t,n)=>{"use strict";n.d(t,{A:()=>c,T:()=>l});var o=n(6540),r=n(4848);function i(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,o.isValidElement)(e)))?n.map(((e,t)=>(0,o.isValidElement)(e)?o.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var s=n(2654);function a(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return s[t??n]??n??t}function l(e,t){let{message:n,id:o}=e;return i(a({message:n,id:o}),t)}function c(e){let{children:t,id:n,values:o}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const s=a({message:t,id:n});return(0,r.jsx)(r.Fragment,{children:i(s,o)})}},7065:(e,t,n)=>{"use strict";n.d(t,{W:()=>o});const o="default"},6654:(e,t,n)=>{"use strict";function o(e){return/^(?:\w*:|\/\/)/.test(e)}function r(e){return void 0!==e&&!o(e)}n.d(t,{A:()=>r,z:()=>o})},6025:(e,t,n)=>{"use strict";n.d(t,{Ay:()=>a,hH:()=>s});var o=n(6540),r=n(4586),i=n(6654);function s(){const{siteConfig:e}=(0,r.A)(),{baseUrl:t,url:n}=e,s=e.future.experimental_router,a=(0,o.useCallback)(((e,o)=>function(e){let{siteUrl:t,baseUrl:n,url:o,options:{forcePrependBaseUrl:r=!1,absolute:s=!1}={},router:a}=e;if(!o||o.startsWith("#")||(0,i.z)(o))return o;if("hash"===a)return o.startsWith("/")?`.${o}`:`./${o}`;if(r)return n+o.replace(/^\//,"");if(o===n.replace(/\/$/,""))return n;const l=o.startsWith(n)?o:n+o.replace(/^\//,"");return s?t+l:l}({siteUrl:n,baseUrl:t,url:e,options:o,router:s})),[n,t,s]);return{withBaseUrl:a}}function a(e,t){void 0===t&&(t={});const{withBaseUrl:n}=s();return n(e,t)}},3427:(e,t,n)=>{"use strict";n.d(t,{A:()=>s});var o=n(6540);n(4848);const r=o.createContext({collectAnchor:()=>{},collectLink:()=>{}}),i=()=>(0,o.useContext)(r);function s(){return i()}},4586:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var o=n(6540),r=n(6988);function i(){return(0,o.useContext)(r.o)}},2303:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var o=n(6540),r=n(6125);function i(){return(0,o.useContext)(r.o)}},205:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});var o=n(6540);const r=n(8193).A.canUseDOM?o.useLayoutEffect:o.useEffect},6921:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const o=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function r(e){const t={};return function e(n,r){Object.entries(n).forEach((n=>{let[i,s]=n;const a=r?`${r}.${i}`:i;o(s)?e(s,a):t[a]=s}))}(e),t}},3102:(e,t,n)=>{"use strict";n.d(t,{W:()=>s,o:()=>i});var o=n(6540),r=n(4848);const i=o.createContext(null);function s(e){let{children:t,value:n}=e;const s=o.useContext(i),a=(0,o.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const o={...t.data,...n?.data};return{plugin:t.plugin,data:o}}({parent:s,value:n})),[s,n]);return(0,r.jsx)(i.Provider,{value:a,children:t})}},4070:(e,t,n)=>{"use strict";n.d(t,{zK:()=>h,vT:()=>p,Gy:()=>d,HW:()=>g,ht:()=>u,r7:()=>m,jh:()=>f});var o=n(6347),r=n(4586),i=n(7065);function s(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,r.A)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const a=e=>e.versions.find((e=>e.isLast));function l(e,t){const n=function(e,t){const n=a(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,o.B6)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),r=n?.docs.find((e=>!!(0,o.B6)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:r,alternateDocVersions:r?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((o=>{o.id===t&&(n[e.name]=o)}))})),n}(r.id):{}}}const c={},d=()=>s("docusaurus-plugin-content-docs")??c,u=e=>{try{return function(e,t,n){void 0===t&&(t=i.W),void 0===n&&(n={});const o=s(e),r=o?.[t];if(!r&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return r}("docusaurus-plugin-content-docs",e,{failfast:!0})}catch(t){throw new Error("You are using a feature of the Docusaurus docs plugin, but this plugin does not seem to be enabled"+("Default"===e?"":` (pluginId=${e}`),{cause:t})}};function p(e){void 0===e&&(e={});const t=d(),{pathname:n}=(0,o.zy)();return function(e,t,n){void 0===n&&(n={});const r=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,o.B6)(t,{path:n.path,exact:!1,strict:!1})})),i=r?{pluginId:r[0],pluginData:r[1]}:void 0;if(!i&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return i}(t,n,e)}function f(e){return u(e).versions}function m(e){const t=u(e);return a(t)}function h(e){const t=u(e),{pathname:n}=(0,o.zy)();return l(t,n)}function g(e){const t=u(e),{pathname:n}=(0,o.zy)();return function(e,t){const n=a(e);return{latestDocSuggestion:l(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},6294:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>i});var o=n(5947),r=n.n(o);r().configure({showSpinner:!1});const i={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{r().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){r().done()}}},661:(e,t,n)=>{"use strict";var o=n(1765),r=n(4784);!function(e){const{themeConfig:{prism:t}}=r.default,{additionalLanguages:o}=t;globalThis.Prism=e,o.forEach((e=>{n(8692)(`./prism-${e}`)})),n(9325),n(8287),delete globalThis.Prism}(o.My)},1107:(e,t,n)=>{"use strict";n.d(t,{A:()=>d});n(6540);var o=n(4164),r=n(1312),i=n(6342),s=n(8774),a=n(3427);const l={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};var c=n(4848);function d(e){let{as:t,id:n,...d}=e;const u=(0,a.A)(),{navbar:{hideOnScroll:p}}=(0,i.p)();if("h1"===t||!n)return(0,c.jsx)(t,{...d,id:void 0});u.collectAnchor(n);const f=(0,r.T)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof d.children?d.children:n});return(0,c.jsxs)(t,{...d,className:(0,o.A)("anchor",p?l.anchorWithHideOnScrollNavbar:l.anchorWithStickyNavbar,d.className),id:n,children:[d.children,(0,c.jsx)(s.A,{className:"hash-link",to:`#${n}`,"aria-label":f,title:f,children:"\u200b"})]})}},3186:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});n(6540);const o={iconExternalLink:"iconExternalLink_nPIU"};var r=n(4848);function i(e){let{width:t=13.5,height:n=13.5}=e;return(0,r.jsx)("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:o.iconExternalLink,children:(0,r.jsx)("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"})})}},781:(e,t,n)=>{"use strict";n.d(t,{A:()=>ft});var o=n(6540),r=n(4164),i=n(7489),s=n(1003),a=n(6347),l=n(1312),c=n(5062),d=n(4848);const u="__docusaurus_skipToContent_fallback";function p(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function f(){const e=(0,o.useRef)(null),{action:t}=(0,a.W6)(),n=(0,o.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(u);t&&p(t)}),[]);return(0,c.$)((n=>{let{location:o}=n;e.current&&!o.hash&&"PUSH"===t&&p(e.current)})),{containerRef:e,onClick:n}}const m=(0,l.T)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function h(e){const t=e.children??m,{containerRef:n,onClick:o}=f();return(0,d.jsx)("div",{ref:n,role:"region","aria-label":m,children:(0,d.jsx)("a",{...e,href:`#${u}`,onClick:o,children:t})})}var g=n(7559),b=n(4090);const v={skipToContent:"skipToContent_fXgn"};function y(){return(0,d.jsx)(h,{className:v.skipToContent})}var w=n(6342),k=n(5041);function x(e){let{width:t=21,height:n=21,color:o="currentColor",strokeWidth:r=1.2,className:i,...s}=e;return(0,d.jsx)("svg",{viewBox:"0 0 15 15",width:t,height:n,...s,children:(0,d.jsx)("g",{stroke:o,strokeWidth:r,children:(0,d.jsx)("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})})})}const _={closeButton:"closeButton_CVFx"};function S(e){return(0,d.jsx)("button",{type:"button","aria-label":(0,l.T)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"}),...e,className:(0,r.A)("clean-btn close",_.closeButton,e.className),children:(0,d.jsx)(x,{width:14,height:14,strokeWidth:3.1})})}const A={content:"content_knG7"};function C(e){const{announcementBar:t}=(0,w.p)(),{content:n}=t;return(0,d.jsx)("div",{...e,className:(0,r.A)(A.content,e.className),dangerouslySetInnerHTML:{__html:n}})}const E={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function T(){const{announcementBar:e}=(0,w.p)(),{isActive:t,close:n}=(0,k.M)();if(!t)return null;const{backgroundColor:o,textColor:r,isCloseable:i}=e;return(0,d.jsxs)("div",{className:E.announcementBar,style:{backgroundColor:o,color:r},role:"banner",children:[i&&(0,d.jsx)("div",{className:E.announcementBarPlaceholder}),(0,d.jsx)(C,{className:E.announcementBarContent}),i&&(0,d.jsx)(S,{onClick:n,className:E.announcementBarClose})]})}var D=n(9876),L=n(3104);var R=n(9532),N=n(5600);const j=o.createContext(null);function P(e){let{children:t}=e;const n=function(){const e=(0,D.M)(),t=(0,N.YL)(),[n,r]=(0,o.useState)(!1),i=null!==t.component,s=(0,R.ZC)(i);return(0,o.useEffect)((()=>{i&&!s&&r(!0)}),[i,s]),(0,o.useEffect)((()=>{i?e.shown||r(!0):r(!1)}),[e.shown,i]),(0,o.useMemo)((()=>[n,r]),[n])}();return(0,d.jsx)(j.Provider,{value:n,children:t})}function O(e){if(e.component){const t=e.component;return(0,d.jsx)(t,{...e.props})}}function I(){const e=(0,o.useContext)(j);if(!e)throw new R.dV("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,r=(0,o.useCallback)((()=>n(!1)),[n]),i=(0,N.YL)();return(0,o.useMemo)((()=>({shown:t,hide:r,content:O(i)})),[r,i,t])}function M(e){let{header:t,primaryMenu:n,secondaryMenu:o}=e;const{shown:i}=I();return(0,d.jsxs)("div",{className:"navbar-sidebar",children:[t,(0,d.jsxs)("div",{className:(0,r.A)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i}),children:[(0,d.jsx)("div",{className:"navbar-sidebar__item menu",children:n}),(0,d.jsx)("div",{className:"navbar-sidebar__item menu",children:o})]})]})}var F=n(5293),B=n(2303);function U(e){return(0,d.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,d.jsx)("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"})})}function z(e){return(0,d.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,d.jsx)("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"})})}const $={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function V(e){let{className:t,buttonClassName:n,value:o,onChange:i}=e;const s=(0,B.A)(),a=(0,l.T)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===o?(0,l.T)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,l.T)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return(0,d.jsx)("div",{className:(0,r.A)($.toggle,t),children:(0,d.jsxs)("button",{className:(0,r.A)("clean-btn",$.toggleButton,!s&&$.toggleButtonDisabled,n),type:"button",onClick:()=>i("dark"===o?"light":"dark"),disabled:!s,title:a,"aria-label":a,"aria-live":"polite",children:[(0,d.jsx)(U,{className:(0,r.A)($.toggleIcon,$.lightToggleIcon)}),(0,d.jsx)(z,{className:(0,r.A)($.toggleIcon,$.darkToggleIcon)})]})})}const q=o.memo(V),H={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function G(e){let{className:t}=e;const n=(0,w.p)().navbar.style,o=(0,w.p)().colorMode.disableSwitch,{colorMode:r,setColorMode:i}=(0,F.G)();return o?null:(0,d.jsx)(q,{className:t,buttonClassName:"dark"===n?H.darkNavbarColorModeToggle:void 0,value:r,onChange:i})}var W=n(3465);function Z(){return(0,d.jsx)(W.A,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function Q(){const e=(0,D.M)();return(0,d.jsx)("button",{type:"button","aria-label":(0,l.T)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle(),children:(0,d.jsx)(x,{color:"var(--ifm-color-emphasis-600)"})})}function K(){return(0,d.jsxs)("div",{className:"navbar-sidebar__brand",children:[(0,d.jsx)(Z,{}),(0,d.jsx)(G,{className:"margin-right--md"}),(0,d.jsx)(Q,{})]})}var Y=n(8774),X=n(6025),J=n(6654);function ee(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var te=n(3186);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:o,href:r,label:i,html:s,isDropdownLink:a,prependBaseUrlToHref:l,...c}=e;const u=(0,X.Ay)(o),p=(0,X.Ay)(t),f=(0,X.Ay)(r,{forcePrependBaseUrl:!0}),m=i&&r&&!(0,J.A)(r),h=s?{dangerouslySetInnerHTML:{__html:s}}:{children:(0,d.jsxs)(d.Fragment,{children:[i,m&&(0,d.jsx)(te.A,{...a&&{width:12,height:12}})]})};return r?(0,d.jsx)(Y.A,{href:l?f:r,...c,...h}):(0,d.jsx)(Y.A,{to:u,isNavLink:!0,...(t||n)&&{isActive:(e,t)=>n?ee(n,t.pathname):t.pathname.startsWith(p)},...c,...h})}function oe(e){let{className:t,isDropdownItem:n=!1,...o}=e;const i=(0,d.jsx)(ne,{className:(0,r.A)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n,...o});return n?(0,d.jsx)("li",{children:i}):i}function re(e){let{className:t,isDropdownItem:n,...o}=e;return(0,d.jsx)("li",{className:"menu__list-item",children:(0,d.jsx)(ne,{className:(0,r.A)("menu__link",t),...o})})}function ie(e){let{mobile:t=!1,position:n,...o}=e;const r=t?re:oe;return(0,d.jsx)(r,{...o,activeClassName:o.activeClassName??(t?"menu__link--active":"navbar__link--active")})}var se=n(1422),ae=n(9169),le=n(4586);const ce={dropdownNavbarItemMobile:"dropdownNavbarItemMobile_S0Fm"};function de(e,t){return e.some((e=>function(e,t){return!!(0,ae.ys)(e.to,t)||!!ee(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ue(e){let{items:t,position:n,className:i,onClick:s,...a}=e;const l=(0,o.useRef)(null),[c,u]=(0,o.useState)(!1);return(0,o.useEffect)((()=>{const e=e=>{l.current&&!l.current.contains(e.target)&&u(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[l]),(0,d.jsxs)("div",{ref:l,className:(0,r.A)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":c}),children:[(0,d.jsx)(ne,{"aria-haspopup":"true","aria-expanded":c,role:"button",href:a.to?void 0:"#",className:(0,r.A)("navbar__link",i),...a,onClick:a.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),u(!c))},children:a.children??a.label}),(0,d.jsx)("ul",{className:"dropdown__menu",children:t.map(((e,t)=>(0,o.createElement)(Ae,{isDropdownItem:!0,activeClassName:"dropdown__link--active",...e,key:t})))})]})}function pe(e){let{items:t,className:n,position:i,onClick:s,...l}=e;const c=function(){const{siteConfig:{baseUrl:e}}=(0,le.A)(),{pathname:t}=(0,a.zy)();return t.replace(e,"/")}(),u=de(t,c),{collapsed:p,toggleCollapsed:f,setCollapsed:m}=(0,se.u)({initialState:()=>!u});return(0,o.useEffect)((()=>{u&&m(!u)}),[c,u,m]),(0,d.jsxs)("li",{className:(0,r.A)("menu__list-item",{"menu__list-item--collapsed":p}),children:[(0,d.jsx)(ne,{role:"button",className:(0,r.A)(ce.dropdownNavbarItemMobile,"menu__link menu__link--sublist menu__link--sublist-caret",n),...l,onClick:e=>{e.preventDefault(),f()},children:l.children??l.label}),(0,d.jsx)(se.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:p,children:t.map(((e,t)=>(0,o.createElement)(Ae,{mobile:!0,isDropdownItem:!0,onClick:s,activeClassName:"menu__link--active",...e,key:t})))})]})}function fe(e){let{mobile:t=!1,...n}=e;const o=t?pe:ue;return(0,d.jsx)(o,{...n})}var me=n(2131);function he(e){let{width:t=20,height:n=20,...o}=e;return(0,d.jsx)("svg",{viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0,...o,children:(0,d.jsx)("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"})})}const ge="iconLanguage_nlXk";var be=n(418);const ve={navbarSearchContainer:"navbarSearchContainer_Bca1"};function ye(e){let{children:t,className:n}=e;return(0,d.jsx)("div",{className:(0,r.A)(n,ve.navbarSearchContainer),children:t})}var we=n(4070),ke=n(1754);var xe=n(5597);const _e=e=>e.docs.find((t=>t.id===e.mainDocId));const Se={default:ie,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:o,queryString:r="",...i}=e;const{i18n:{currentLocale:s,locales:c,localeConfigs:u}}=(0,le.A)(),p=(0,me.o)(),{search:f,hash:m}=(0,a.zy)(),h=[...n,...c.map((e=>{const n=`${`pathname://${p.createUrl({locale:e,fullyQualified:!1})}`}${f}${m}${r}`;return{label:u[e].label,lang:u[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===s?t?"menu__link--active":"dropdown__link--active":""}})),...o],g=t?(0,l.T)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):u[s].label;return(0,d.jsx)(fe,{...i,mobile:t,label:(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(he,{className:ge}),g]}),items:h})},search:function(e){let{mobile:t,className:n}=e;return t?null:(0,d.jsx)(ye,{className:n,children:(0,d.jsx)(be.A,{})})},dropdown:fe,html:function(e){let{value:t,className:n,mobile:o=!1,isDropdownItem:i=!1}=e;const s=i?"li":"div";return(0,d.jsx)(s,{className:(0,r.A)({navbar__item:!o&&!i,"menu__list-item":o},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:o,...r}=e;const{activeDoc:i}=(0,we.zK)(o),s=(0,ke.QB)(t,o),a=i?.path===s?.path;return null===s||s.unlisted&&!a?null:(0,d.jsx)(ie,{exact:!0,...r,isActive:()=>a||!!i?.sidebar&&i.sidebar===s.sidebar,label:n??s.id,to:s.path})},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:o,...r}=e;const{activeDoc:i}=(0,we.zK)(o),s=(0,ke.fW)(t,o).link;if(!s)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return(0,d.jsx)(ie,{exact:!0,...r,isActive:()=>i?.sidebar===t,label:n??s.label,to:s.path})},docsVersion:function(e){let{label:t,to:n,docsPluginId:o,...r}=e;const i=(0,ke.Vd)(o)[0],s=t??i.label,a=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return(0,d.jsx)(ie,{...r,label:s,to:a})},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:o,dropdownItemsBefore:r,dropdownItemsAfter:i,...s}=e;const{search:c,hash:u}=(0,a.zy)(),p=(0,we.zK)(n),f=(0,we.jh)(n),{savePreferredVersionName:m}=(0,xe.g1)(n),h=[...r,...f.map((e=>{const t=p.alternateDocVersions[e.name]??_e(e);return{label:e.label,to:`${t.path}${c}${u}`,isActive:()=>e===p.activeVersion,onClick:()=>m(e.name)}})),...i],g=(0,ke.Vd)(n)[0],b=t&&h.length>1?(0,l.T)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):g.label,v=t&&h.length>1?void 0:_e(g).path;return h.length<=1?(0,d.jsx)(ie,{...s,mobile:t,label:b,to:v,isActive:o?()=>!1:void 0}):(0,d.jsx)(fe,{...s,mobile:t,label:b,to:v,items:h,isActive:o?()=>!1:void 0})}};function Ae(e){let{type:t,...n}=e;const o=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),r=Se[o];if(!r)throw new Error(`No NavbarItem component found for type "${t}".`);return(0,d.jsx)(r,{...n})}function Ce(){const e=(0,D.M)(),t=(0,w.p)().navbar.items;return(0,d.jsx)("ul",{className:"menu__list",children:t.map(((t,n)=>(0,o.createElement)(Ae,{mobile:!0,...t,onClick:()=>e.toggle(),key:n})))})}function Ee(e){return(0,d.jsx)("button",{...e,type:"button",className:"clean-btn navbar-sidebar__back",children:(0,d.jsx)(l.A,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)",children:"\u2190 Back to main menu"})})}function Te(){const e=0===(0,w.p)().navbar.items.length,t=I();return(0,d.jsxs)(d.Fragment,{children:[!e&&(0,d.jsx)(Ee,{onClick:()=>t.hide()}),t.content]})}function De(){const e=(0,D.M)();var t;return void 0===(t=e.shown)&&(t=!0),(0,o.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?(0,d.jsx)(M,{header:(0,d.jsx)(K,{}),primaryMenu:(0,d.jsx)(Ce,{}),secondaryMenu:(0,d.jsx)(Te,{})}):null}const Le={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Re(e){return(0,d.jsx)("div",{role:"presentation",...e,className:(0,r.A)("navbar-sidebar__backdrop",e.className)})}function Ne(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:i}}=(0,w.p)(),s=(0,D.M)(),{navbarRef:a,isNavbarVisible:u}=function(e){const[t,n]=(0,o.useState)(e),r=(0,o.useRef)(!1),i=(0,o.useRef)(0),s=(0,o.useCallback)((e=>{null!==e&&(i.current=e.getBoundingClientRect().height)}),[]);return(0,L.Mq)(((t,o)=>{let{scrollY:s}=t;if(!e)return;if(s<i.current)return void n(!0);if(r.current)return void(r.current=!1);const a=o?.scrollY,l=document.documentElement.scrollHeight-i.current,c=window.innerHeight;a&&s>=a?n(!1):s+c<l&&n(!0)})),(0,c.$)((t=>{if(!e)return;const o=t.location.hash;if(o?document.getElementById(o.substring(1)):void 0)return r.current=!0,void n(!1);n(!0)})),{navbarRef:s,isNavbarVisible:t}}(n);return(0,d.jsxs)("nav",{ref:a,"aria-label":(0,l.T)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,r.A)("navbar","navbar--fixed-top",n&&[Le.navbarHideable,!u&&Le.navbarHidden],{"navbar--dark":"dark"===i,"navbar--primary":"primary"===i,"navbar-sidebar--show":s.shown}),children:[t,(0,d.jsx)(Re,{onClick:s.toggle}),(0,d.jsx)(De,{})]})}var je=n(440);const Pe={errorBoundaryError:"errorBoundaryError_a6uf",errorBoundaryFallback:"errorBoundaryFallback_VBag"};function Oe(e){return(0,d.jsx)("button",{type:"button",...e,children:(0,d.jsx)(l.A,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error",children:"Try again"})})}function Ie(e){let{error:t}=e;const n=(0,je.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,d.jsx)("p",{className:Pe.errorBoundaryError,children:n})}class Me extends o.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const Fe="right";function Be(e){let{width:t=30,height:n=30,className:o,...r}=e;return(0,d.jsx)("svg",{className:o,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true",...r,children:(0,d.jsx)("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"})})}function Ue(){const{toggle:e,shown:t}=(0,D.M)();return(0,d.jsx)("button",{onClick:e,"aria-label":(0,l.T)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button",children:(0,d.jsx)(Be,{})})}const ze={colorModeToggle:"colorModeToggle_DEke"};function $e(e){let{items:t}=e;return(0,d.jsx)(d.Fragment,{children:t.map(((e,t)=>(0,d.jsx)(Me,{onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t}),children:(0,d.jsx)(Ae,{...e})},t)))})}function Ve(e){let{left:t,right:n}=e;return(0,d.jsxs)("div",{className:"navbar__inner",children:[(0,d.jsx)("div",{className:"navbar__items",children:t}),(0,d.jsx)("div",{className:"navbar__items navbar__items--right",children:n})]})}function qe(){const e=(0,D.M)(),t=(0,w.p)().navbar.items,[n,o]=function(e){function t(e){return"left"===(e.position??Fe)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),r=t.find((e=>"search"===e.type));return(0,d.jsx)(Ve,{left:(0,d.jsxs)(d.Fragment,{children:[!e.disabled&&(0,d.jsx)(Ue,{}),(0,d.jsx)(Z,{}),(0,d.jsx)($e,{items:n})]}),right:(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)($e,{items:o}),(0,d.jsx)(G,{className:ze.colorModeToggle}),!r&&(0,d.jsx)(ye,{children:(0,d.jsx)(be.A,{})})]})})}function He(){return(0,d.jsx)(Ne,{children:(0,d.jsx)(qe,{})})}function Ge(e){let{item:t}=e;const{to:n,href:o,label:r,prependBaseUrlToHref:i,...s}=t,a=(0,X.Ay)(n),l=(0,X.Ay)(o,{forcePrependBaseUrl:!0});return(0,d.jsxs)(Y.A,{className:"footer__link-item",...o?{href:i?l:o}:{to:a},...s,children:[r,o&&!(0,J.A)(o)&&(0,d.jsx)(te.A,{})]})}function We(e){let{item:t}=e;return t.html?(0,d.jsx)("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):(0,d.jsx)("li",{className:"footer__item",children:(0,d.jsx)(Ge,{item:t})},t.href??t.to)}function Ze(e){let{column:t}=e;return(0,d.jsxs)("div",{className:"col footer__col",children:[(0,d.jsx)("div",{className:"footer__title",children:t.title}),(0,d.jsx)("ul",{className:"footer__items clean-list",children:t.items.map(((e,t)=>(0,d.jsx)(We,{item:e},t)))})]})}function Qe(e){let{columns:t}=e;return(0,d.jsx)("div",{className:"row footer__links",children:t.map(((e,t)=>(0,d.jsx)(Ze,{column:e},t)))})}function Ke(){return(0,d.jsx)("span",{className:"footer__link-separator",children:"\xb7"})}function Ye(e){let{item:t}=e;return t.html?(0,d.jsx)("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):(0,d.jsx)(Ge,{item:t})}function Xe(e){let{links:t}=e;return(0,d.jsx)("div",{className:"footer__links text--center",children:(0,d.jsx)("div",{className:"footer__links",children:t.map(((e,n)=>(0,d.jsxs)(o.Fragment,{children:[(0,d.jsx)(Ye,{item:e}),t.length!==n+1&&(0,d.jsx)(Ke,{})]},n)))})})}function Je(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?(0,d.jsx)(Qe,{columns:t}):(0,d.jsx)(Xe,{links:t})}var et=n(1122);const tt={footerLogoLink:"footerLogoLink_BH7S"};function nt(e){let{logo:t}=e;const{withBaseUrl:n}=(0,X.hH)(),o={light:n(t.src),dark:n(t.srcDark??t.src)};return(0,d.jsx)(et.A,{className:(0,r.A)("footer__logo",t.className),alt:t.alt,sources:o,width:t.width,height:t.height,style:t.style})}function ot(e){let{logo:t}=e;return t.href?(0,d.jsx)(Y.A,{href:t.href,className:tt.footerLogoLink,target:t.target,children:(0,d.jsx)(nt,{logo:t})}):(0,d.jsx)(nt,{logo:t})}function rt(e){let{copyright:t}=e;return(0,d.jsx)("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function it(e){let{style:t,links:n,logo:o,copyright:i}=e;return(0,d.jsx)("footer",{className:(0,r.A)("footer",{"footer--dark":"dark"===t}),children:(0,d.jsxs)("div",{className:"container container-fluid",children:[n,(o||i)&&(0,d.jsxs)("div",{className:"footer__bottom text--center",children:[o&&(0,d.jsx)("div",{className:"margin-bottom--sm",children:o}),i]})]})})}function st(){const{footer:e}=(0,w.p)();if(!e)return null;const{copyright:t,links:n,logo:o,style:r}=e;return(0,d.jsx)(it,{style:r,links:n&&n.length>0&&(0,d.jsx)(Je,{links:n}),logo:o&&(0,d.jsx)(ot,{logo:o}),copyright:t&&(0,d.jsx)(rt,{copyright:t})})}const at=o.memo(st),lt=(0,R.fM)([F.a,k.o,L.Tv,xe.VQ,s.Jx,function(e){let{children:t}=e;return(0,d.jsx)(N.y_,{children:(0,d.jsx)(D.e,{children:(0,d.jsx)(P,{children:t})})})}]);function ct(e){let{children:t}=e;return(0,d.jsx)(lt,{children:t})}var dt=n(1107);function ut(e){let{error:t,tryAgain:n}=e;return(0,d.jsx)("main",{className:"container margin-vert--xl",children:(0,d.jsx)("div",{className:"row",children:(0,d.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,d.jsx)(dt.A,{as:"h1",className:"hero__title",children:(0,d.jsx)(l.A,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed",children:"This page crashed."})}),(0,d.jsx)("div",{className:"margin-vert--lg",children:(0,d.jsx)(Oe,{onClick:n,className:"button button--primary shadow--lw"})}),(0,d.jsx)("hr",{}),(0,d.jsx)("div",{className:"margin-vert--md",children:(0,d.jsx)(Ie,{error:t})})]})})})}const pt={mainWrapper:"mainWrapper_z2l0"};function ft(e){const{children:t,noFooter:n,wrapperClassName:o,title:a,description:l}=e;return(0,b.J)(),(0,d.jsxs)(ct,{children:[(0,d.jsx)(s.be,{title:a,description:l}),(0,d.jsx)(y,{}),(0,d.jsx)(T,{}),(0,d.jsx)(He,{}),(0,d.jsx)("div",{id:u,className:(0,r.A)(g.G.wrapper.main,pt.mainWrapper,o),children:(0,d.jsx)(i.A,{fallback:e=>(0,d.jsx)(ut,{...e}),children:t})}),!n&&(0,d.jsx)(at,{})]})}},3465:(e,t,n)=>{"use strict";n.d(t,{A:()=>d});n(6540);var o=n(8774),r=n(6025),i=n(4586),s=n(6342),a=n(1122),l=n(4848);function c(e){let{logo:t,alt:n,imageClassName:o}=e;const i={light:(0,r.Ay)(t.src),dark:(0,r.Ay)(t.srcDark||t.src)},s=(0,l.jsx)(a.A,{className:t.className,sources:i,height:t.height,width:t.width,alt:n,style:t.style});return o?(0,l.jsx)("div",{className:o,children:s}):s}function d(e){const{siteConfig:{title:t}}=(0,i.A)(),{navbar:{title:n,logo:a}}=(0,s.p)(),{imageClassName:d,titleClassName:u,...p}=e,f=(0,r.Ay)(a?.href||"/"),m=n?"":t,h=a?.alt??m;return(0,l.jsxs)(o.A,{to:f,...p,...a?.target&&{target:a.target},children:[a&&(0,l.jsx)(c,{logo:a,alt:h,imageClassName:d}),null!=n&&(0,l.jsx)("b",{className:u,children:n})]})}},1463:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});n(6540);var o=n(5260),r=n(4848);function i(e){let{locale:t,version:n,tag:i}=e;const s=t;return(0,r.jsxs)(o.A,{children:[t&&(0,r.jsx)("meta",{name:"docusaurus_locale",content:t}),n&&(0,r.jsx)("meta",{name:"docusaurus_version",content:n}),i&&(0,r.jsx)("meta",{name:"docusaurus_tag",content:i}),s&&(0,r.jsx)("meta",{name:"docsearch:language",content:s}),n&&(0,r.jsx)("meta",{name:"docsearch:version",content:n}),i&&(0,r.jsx)("meta",{name:"docsearch:docusaurus_tag",content:i})]})}},1122:(e,t,n)=>{"use strict";n.d(t,{A:()=>d});var o=n(6540),r=n(4164),i=n(2303),s=n(5293);const a={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var l=n(4848);function c(e){let{className:t,children:n}=e;const c=(0,i.A)(),{colorMode:d}=(0,s.G)();return(0,l.jsx)(l.Fragment,{children:(c?"dark"===d?["dark"]:["light"]:["light","dark"]).map((e=>{const i=n({theme:e,className:(0,r.A)(t,a.themedComponent,a[`themedComponent--${e}`])});return(0,l.jsx)(o.Fragment,{children:i},e)}))})}function d(e){const{sources:t,className:n,alt:o,...r}=e;return(0,l.jsx)(c,{className:n,children:e=>{let{theme:n,className:i}=e;return(0,l.jsx)("img",{src:t[n],alt:o,className:i,...r})}})}},1422:(e,t,n)=>{"use strict";n.d(t,{N:()=>b,u:()=>c});var o=n(6540),r=n(8193),i=n(205),s=n(3109),a=n(4848);const l="ease-in-out";function c(e){let{initialState:t}=e;const[n,r]=(0,o.useState)(t??!1),i=(0,o.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:i}}const d={display:"none",overflow:"hidden",height:"0px"},u={display:"block",overflow:"visible",height:"auto"};function p(e,t){const n=t?d:u;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function f(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const i=(0,o.useRef)(!1);(0,o.useEffect)((()=>{const e=t.current;function o(){const t=e.scrollHeight,n=r?.duration??function(e){if((0,s.O)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${r?.easing??l}`,height:`${t}px`}}function a(){const t=o();e.style.transition=t.transition,e.style.height=t.height}if(!i.current)return p(e,n),void(i.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(a(),requestAnimationFrame((()=>{e.style.height=d.height,e.style.overflow=d.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{a()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function m(e){if(!r.A.canUseDOM)return e?d:u}function h(e){let{as:t="div",collapsed:n,children:r,animation:i,onCollapseTransitionEnd:s,className:l,disableSSRStyle:c}=e;const d=(0,o.useRef)(null);return f({collapsibleRef:d,collapsed:n,animation:i}),(0,a.jsx)(t,{ref:d,style:c?void 0:m(n),onTransitionEnd:e=>{"height"===e.propertyName&&(p(d.current,n),s?.(n))},className:l,children:r})}function g(e){let{collapsed:t,...n}=e;const[r,s]=(0,o.useState)(!t),[l,c]=(0,o.useState)(t);return(0,i.A)((()=>{t||s(!0)}),[t]),(0,i.A)((()=>{r&&c(t)}),[r,t]),r?(0,a.jsx)(h,{...n,collapsed:l}):null}function b(e){let{lazy:t,...n}=e;const o=t?g:h;return(0,a.jsx)(o,{...n})}},5041:(e,t,n)=>{"use strict";n.d(t,{M:()=>h,o:()=>m});var o=n(6540),r=n(2303),i=n(679),s=n(9532),a=n(6342),l=n(4848);const c=(0,i.Wf)("docusaurus.announcement.dismiss"),d=(0,i.Wf)("docusaurus.announcement.id"),u=()=>"true"===c.get(),p=e=>c.set(String(e)),f=o.createContext(null);function m(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,a.p)(),t=(0,r.A)(),[n,i]=(0,o.useState)((()=>!!t&&u()));(0,o.useEffect)((()=>{i(u())}),[]);const s=(0,o.useCallback)((()=>{p(!0),i(!0)}),[]);return(0,o.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=d.get();"annoucement-bar"===n&&(n="announcement-bar");const o=t!==n;d.set(t),o&&p(!1),!o&&u()||i(!1)}),[e]),(0,o.useMemo)((()=>({isActive:!!e&&!n,close:s})),[e,n,s])}();return(0,l.jsx)(f.Provider,{value:n,children:t})}function h(){const e=(0,o.useContext)(f);if(!e)throw new s.dV("AnnouncementBarProvider");return e}},5293:(e,t,n)=>{"use strict";n.d(t,{G:()=>b,a:()=>g});var o=n(6540),r=n(8193),i=n(9532),s=n(679),a=n(6342),l=n(4848);const c=o.createContext(void 0),d="theme",u=(0,s.Wf)(d),p={light:"light",dark:"dark"},f=e=>e===p.dark?p.dark:p.light,m=e=>r.A.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e),h=e=>{u.set(f(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,a.p)(),[r,i]=(0,o.useState)(m(e));(0,o.useEffect)((()=>{t&&u.del()}),[t]);const s=(0,o.useCallback)((function(t,o){void 0===o&&(o={});const{persist:r=!0}=o;t?(i(t),r&&h(t)):(i(n?window.matchMedia("(prefers-color-scheme: dark)").matches?p.dark:p.light:e),u.del())}),[n,e]);(0,o.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(r))}),[r]),(0,o.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==d)return;const t=u.get();null!==t&&s(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,s]);const l=(0,o.useRef)(!1);return(0,o.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),o=()=>{window.matchMedia("print").matches||l.current?l.current=window.matchMedia("print").matches:s(null)};return e.addListener(o),()=>e.removeListener(o)}),[s,t,n]),(0,o.useMemo)((()=>({colorMode:r,setColorMode:s,get isDarkTheme(){return r===p.dark},setLightTheme(){s(p.light)},setDarkTheme(){s(p.dark)}})),[r,s])}();return(0,l.jsx)(c.Provider,{value:n,children:t})}function b(){const e=(0,o.useContext)(c);if(null==e)throw new i.dV("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},5597:(e,t,n)=>{"use strict";n.d(t,{VQ:()=>b,g1:()=>y});var o=n(6540),r=n(4070),i=n(7065),s=n(6342),a=n(1754),l=n(9532),c=n(679),d=n(4848);const u=e=>`docs-preferred-version-${e}`,p={save:(e,t,n)=>{(0,c.Wf)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.Wf)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.Wf)(u(e),{persistence:t}).del()}},f=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const m=o.createContext(null);function h(){const e=(0,r.Gy)(),t=(0,s.p)().docs.versionPersistence,n=(0,o.useMemo)((()=>Object.keys(e)),[e]),[i,a]=(0,o.useState)((()=>f(n)));(0,o.useEffect)((()=>{a(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:o}=e;function r(e){const t=p.read(e,n);return o[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(p.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,r(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[i,(0,o.useMemo)((()=>({savePreferredVersion:function(e,n){p.save(e,t,n),a((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=h();return(0,d.jsx)(m.Provider,{value:n,children:t})}function b(e){let{children:t}=e;return a.C5?(0,d.jsx)(g,{children:t}):(0,d.jsx)(d.Fragment,{children:t})}function v(){const e=(0,o.useContext)(m);if(!e)throw new l.dV("DocsPreferredVersionContextProvider");return e}function y(e){void 0===e&&(e=i.W);const t=(0,r.ht)(e),[n,s]=v(),{preferredVersionName:a}=n[e];return{preferredVersion:t.versions.find((e=>e.name===a))??null,savePreferredVersionName:(0,o.useCallback)((t=>{s.savePreferredVersion(e,t)}),[s,e])}}},6588:(e,t,n)=>{"use strict";n.d(t,{V:()=>l,t:()=>c});var o=n(6540),r=n(9532),i=n(4848);const s=Symbol("EmptyContext"),a=o.createContext(s);function l(e){let{children:t,name:n,items:r}=e;const s=(0,o.useMemo)((()=>n&&r?{name:n,items:r}:null),[n,r]);return(0,i.jsx)(a.Provider,{value:s,children:t})}function c(){const e=(0,o.useContext)(a);if(e===s)throw new r.dV("DocsSidebarProvider");return e}},2252:(e,t,n)=>{"use strict";n.d(t,{n:()=>a,r:()=>l});var o=n(6540),r=n(9532),i=n(4848);const s=o.createContext(null);function a(e){let{children:t,version:n}=e;return(0,i.jsx)(s.Provider,{value:n,children:t})}function l(){const e=(0,o.useContext)(s);if(null===e)throw new r.dV("DocsVersionProvider");return e}},9876:(e,t,n)=>{"use strict";n.d(t,{e:()=>f,M:()=>m});var o=n(6540),r=n(5600),i=n(4581),s=n(6347),a=n(9532);function l(e){!function(e){const t=(0,s.W6)(),n=(0,a._q)(e);(0,o.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var c=n(6342),d=n(4848);const u=o.createContext(void 0);function p(){const e=function(){const e=(0,r.YL)(),{items:t}=(0,c.p)().navbar;return 0===t.length&&!e.component}(),t=(0,i.l)(),n=!e&&"mobile"===t,[s,a]=(0,o.useState)(!1);l((()=>{if(s)return a(!1),!1}));const d=(0,o.useCallback)((()=>{a((e=>!e))}),[]);return(0,o.useEffect)((()=>{"desktop"===t&&a(!1)}),[t]),(0,o.useMemo)((()=>({disabled:e,shouldRender:n,toggle:d,shown:s})),[e,n,d,s])}function f(e){let{children:t}=e;const n=p();return(0,d.jsx)(u.Provider,{value:n,children:t})}function m(){const e=o.useContext(u);if(void 0===e)throw new a.dV("NavbarMobileSidebarProvider");return e}},5600:(e,t,n)=>{"use strict";n.d(t,{GX:()=>c,YL:()=>l,y_:()=>a});var o=n(6540),r=n(9532),i=n(4848);const s=o.createContext(null);function a(e){let{children:t}=e;const n=(0,o.useState)({component:null,props:null});return(0,i.jsx)(s.Provider,{value:n,children:t})}function l(){const e=(0,o.useContext)(s);if(!e)throw new r.dV("NavbarSecondaryMenuContentProvider");return e[0]}function c(e){let{component:t,props:n}=e;const i=(0,o.useContext)(s);if(!i)throw new r.dV("NavbarSecondaryMenuContentProvider");const[,a]=i,l=(0,r.Be)(n);return(0,o.useEffect)((()=>{a({component:t,props:l})}),[a,t,l]),(0,o.useEffect)((()=>()=>a({component:null,props:null})),[a]),null}},4090:(e,t,n)=>{"use strict";n.d(t,{w:()=>r,J:()=>i});var o=n(6540);const r="navigation-with-keyboard";function i(){(0,o.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(r),"mousedown"===e.type&&document.body.classList.remove(r)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(r),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},4581:(e,t,n)=>{"use strict";n.d(t,{l:()=>a});var o=n(6540),r=n(8193);const i={desktop:"desktop",mobile:"mobile",ssr:"ssr"},s=996;function a(e){let{desktopBreakpoint:t=s}=void 0===e?{}:e;const[n,a]=(0,o.useState)((()=>"ssr"));return(0,o.useEffect)((()=>{function e(){a(function(e){if(!r.A.canUseDOM)throw new Error("getWindowSize() should only be called after React hydration");return window.innerWidth>e?i.desktop:i.mobile}(t))}return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[t]),n}},7559:(e,t,n)=>{"use strict";n.d(t,{G:()=>o});const o={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",unlistedBanner:"theme-unlisted-banner",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{blogFooterTagsRow:"theme-blog-footer-tags-row",blogFooterEditMetaRow:"theme-blog-footer-edit-meta-row"},pages:{pageFooterEditMetaRow:"theme-pages-footer-edit-meta-row"}}},3109:(e,t,n)=>{"use strict";function o(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{O:()=>o})},1754:(e,t,n)=>{"use strict";n.d(t,{Nr:()=>f,w8:()=>g,C5:()=>p,B5:()=>S,Vd:()=>k,QB:()=>_,fW:()=>x,OF:()=>w,Y:()=>v});var o=n(6540),r=n(6347),i=n(2831),s=n(4070),a=n(5597),l=n(2252),c=n(6588);function d(e){return Array.from(new Set(e))}var u=n(9169);const p=!!s.Gy;function f(e){return"link"!==e.type||e.unlisted?"category"===e.type?function(e){if(e.href&&!e.linkUnlisted)return e.href;for(const t of e.items){const e=f(t);if(e)return e}}(e):void 0:e.href}const m=(e,t)=>void 0!==e&&(0,u.ys)(e,t),h=(e,t)=>e.some((e=>g(e,t)));function g(e,t){return"link"===e.type?m(e.href,t):"category"===e.type&&(m(e.href,t)||h(e.items,t))}function b(e,t){switch(e.type){case"category":return g(e,t)||e.items.some((e=>b(e,t)));case"link":return!e.unlisted||g(e,t);default:return!0}}function v(e,t){return(0,o.useMemo)((()=>e.filter((e=>b(e,t)))),[e,t])}function y(e){let{sidebarItems:t,pathname:n,onlyCategories:o=!1}=e;const r=[];return function e(t){for(const i of t)if("category"===i.type&&((0,u.ys)(i.href,n)||e(i.items))||"link"===i.type&&(0,u.ys)(i.href,n)){return o&&"category"!==i.type||r.unshift(i),!0}return!1}(t),r}function w(){const e=(0,c.t)(),{pathname:t}=(0,r.zy)(),n=(0,s.vT)()?.pluginData.breadcrumbs;return!1!==n&&e?y({sidebarItems:e.items,pathname:t}):null}function k(e){const{activeVersion:t}=(0,s.zK)(e),{preferredVersion:n}=(0,a.g1)(e),r=(0,s.r7)(e);return(0,o.useMemo)((()=>d([t,n,r].filter(Boolean))),[t,n,r])}function x(e,t){const n=k(t);return(0,o.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),o=t.find((t=>t[0]===e));if(!o)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return o[1]}),[e,n])}function _(e,t){const n=k(t);return(0,o.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),o=t.find((t=>t.id===e));if(!o){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${d(t.map((e=>e.id))).join("\n- ")}`)}return o}),[e,n])}function S(e){let{route:t}=e;const n=(0,r.zy)(),o=(0,l.r)(),s=t.routes,a=s.find((e=>(0,r.B6)(n.pathname,e)));if(!a)return null;const c=a.sidebar,d=c?o.docsSidebars[c]:void 0;return{docElement:(0,i.v)(s),sidebarName:c,sidebarItems:d}}},1003:(e,t,n)=>{"use strict";n.d(t,{e3:()=>f,be:()=>u,Jx:()=>m});var o=n(6540),r=n(4164),i=n(5260),s=n(3102);function a(){const e=o.useContext(s.o);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var l=n(6025),c=n(4586);var d=n(4848);function u(e){let{title:t,description:n,keywords:o,image:r,children:s}=e;const a=function(e){const{siteConfig:t}=(0,c.A)(),{title:n,titleDelimiter:o}=t;return e?.trim().length?`${e.trim()} ${o} ${n}`:n}(t),{withBaseUrl:u}=(0,l.hH)(),p=r?u(r,{absolute:!0}):void 0;return(0,d.jsxs)(i.A,{children:[t&&(0,d.jsx)("title",{children:a}),t&&(0,d.jsx)("meta",{property:"og:title",content:a}),n&&(0,d.jsx)("meta",{name:"description",content:n}),n&&(0,d.jsx)("meta",{property:"og:description",content:n}),o&&(0,d.jsx)("meta",{name:"keywords",content:Array.isArray(o)?o.join(","):o}),p&&(0,d.jsx)("meta",{property:"og:image",content:p}),p&&(0,d.jsx)("meta",{name:"twitter:image",content:p}),s]})}const p=o.createContext(void 0);function f(e){let{className:t,children:n}=e;const s=o.useContext(p),a=(0,r.A)(s,t);return(0,d.jsxs)(p.Provider,{value:a,children:[(0,d.jsx)(i.A,{children:(0,d.jsx)("html",{className:a})}),n]})}function m(e){let{children:t}=e;const n=a(),o=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const i=`plugin-id-${n.plugin.id}`;return(0,d.jsx)(f,{className:(0,r.A)(o,i),children:t})}},9532:(e,t,n)=>{"use strict";n.d(t,{Be:()=>c,ZC:()=>a,_q:()=>s,dV:()=>l,fM:()=>d});var o=n(6540),r=n(205),i=n(4848);function s(e){const t=(0,o.useRef)(e);return(0,r.A)((()=>{t.current=e}),[e]),(0,o.useCallback)((function(){return t.current(...arguments)}),[])}function a(e){const t=(0,o.useRef)();return(0,r.A)((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function c(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,o.useMemo)((()=>e),t.flat())}function d(e){return t=>{let{children:n}=t;return(0,i.jsx)(i.Fragment,{children:e.reduceRight(((e,t)=>(0,i.jsx)(t,{children:e})),n)})}}},9169:(e,t,n)=>{"use strict";n.d(t,{Dt:()=>a,ys:()=>s});var o=n(6540),r=n(8328),i=n(4586);function s(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function a(){const{baseUrl:e}=(0,i.A)().siteConfig;return(0,o.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function o(e){return e.path===t&&!0===e.exact}function r(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(o)||e(t.filter(r).flatMap((e=>e.routes??[])))}(n)}({routes:r.A,baseUrl:e})),[e])}},3104:(e,t,n)=>{"use strict";n.d(t,{Mq:()=>p,Tv:()=>c,gk:()=>f});var o=n(6540),r=n(8193),i=n(2303),s=(n(205),n(9532)),a=n(4848);const l=o.createContext(void 0);function c(e){let{children:t}=e;const n=function(){const e=(0,o.useRef)(!0);return(0,o.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return(0,a.jsx)(l.Provider,{value:n,children:t})}function d(){const e=(0,o.useContext)(l);if(null==e)throw new s.dV("ScrollControllerProvider");return e}const u=()=>r.A.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function p(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=d(),r=(0,o.useRef)(u()),i=(0,s._q)(e);(0,o.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();i(e,r.current),r.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[i,n,...t])}function f(){const e=(0,o.useRef)(null),t=(0,i.A)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function o(){const r=document.documentElement.scrollTop;(n&&r>e||!n&&r<e)&&(t=requestAnimationFrame(o),window.scrollTo(0,Math.floor(.85*(r-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},2967:(e,t,n)=>{"use strict";n.d(t,{Cy:()=>o,tU:()=>r});n(4586);const o="default";function r(e,t){return`docs-${e}-${t}`}},679:(e,t,n)=>{"use strict";n.d(t,{Wf:()=>c});n(6540);const o=JSON.parse('{"N":"localStorage","M":""}'),r=o.N;function i(e){let{key:t,oldValue:n,newValue:o,storage:r}=e;if(n===o)return;const i=document.createEvent("StorageEvent");i.initStorageEvent("storage",!1,!1,t,n,o,window.location.href,r),window.dispatchEvent(i)}function s(e){if(void 0===e&&(e=r),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,a||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),a=!0),null}var t}let a=!1;const l={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function c(e,t){const n=`${e}${o.M}`;if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(n);const r=s(t?.persistence);return null===r?l:{get:()=>{try{return r.getItem(n)}catch(e){return console.error(`Docusaurus storage error, can't get key=${n}`,e),null}},set:e=>{try{const t=r.getItem(n);r.setItem(n,e),i({key:n,oldValue:t,newValue:e,storage:r})}catch(t){console.error(`Docusaurus storage error, can't set ${n}=${e}`,t)}},del:()=>{try{const e=r.getItem(n);r.removeItem(n),i({key:n,oldValue:e,newValue:null,storage:r})}catch(e){console.error(`Docusaurus storage error, can't delete key=${n}`,e)}},listen:e=>{try{const t=t=>{t.storageArea===r&&t.key===n&&e(t)};return window.addEventListener("storage",t),()=>window.removeEventListener("storage",t)}catch(t){return console.error(`Docusaurus storage error, can't listen for changes of key=${n}`,t),()=>{}}}}}},2131:(e,t,n)=>{"use strict";n.d(t,{o:()=>s});var o=n(4586),r=n(6347),i=n(440);function s(){const{siteConfig:{baseUrl:e,url:t,trailingSlash:n},i18n:{defaultLocale:s,currentLocale:a}}=(0,o.A)(),{pathname:l}=(0,r.zy)(),c=(0,i.applyTrailingSlash)(l,{trailingSlash:n,baseUrl:e}),d=a===s?e:e.replace(`/${a}/`,"/"),u=c.replace(e,"");return{createUrl:function(e){let{locale:n,fullyQualified:o}=e;return`${o?t:""}${function(e){return e===s?`${d}`:`${d}${e}/`}(n)}${u}`}}}},5062:(e,t,n)=>{"use strict";n.d(t,{$:()=>s});var o=n(6540),r=n(6347),i=n(9532);function s(e){const t=(0,r.zy)(),n=(0,i.ZC)(t),s=(0,i._q)(e);(0,o.useEffect)((()=>{n&&t!==n&&s({location:t,previousLocation:n})}),[s,t,n])}},6342:(e,t,n)=>{"use strict";n.d(t,{p:()=>r});var o=n(4586);function r(){return(0,o.A)().siteConfig.themeConfig}},2983:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.removeTrailingSlash=t.addLeadingSlash=t.addTrailingSlash=void 0;const o=n(2566);function r(e){return e.endsWith("/")?e:`${e}/`}function i(e){return(0,o.removeSuffix)(e,"/")}t.addTrailingSlash=r,t.default=function(e,t){const{trailingSlash:n,baseUrl:o}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[s]=e.split(/[#?]/),a="/"===s||s===o?s:(l=s,n?r(l):i(l));var l;return e.replace(s,a)},t.addLeadingSlash=function(e){return(0,o.addPrefix)(e,"/")},t.removeTrailingSlash=i},253:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},440:function(e,t,n){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.removePrefix=t.addSuffix=t.removeSuffix=t.addPrefix=t.removeTrailingSlash=t.addLeadingSlash=t.addTrailingSlash=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var r=n(2983);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return o(r).default}}),Object.defineProperty(t,"addTrailingSlash",{enumerable:!0,get:function(){return r.addTrailingSlash}}),Object.defineProperty(t,"addLeadingSlash",{enumerable:!0,get:function(){return r.addLeadingSlash}}),Object.defineProperty(t,"removeTrailingSlash",{enumerable:!0,get:function(){return r.removeTrailingSlash}});var i=n(2566);Object.defineProperty(t,"addPrefix",{enumerable:!0,get:function(){return i.addPrefix}}),Object.defineProperty(t,"removeSuffix",{enumerable:!0,get:function(){return i.removeSuffix}}),Object.defineProperty(t,"addSuffix",{enumerable:!0,get:function(){return i.addSuffix}}),Object.defineProperty(t,"removePrefix",{enumerable:!0,get:function(){return i.removePrefix}});var s=n(253);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return s.getErrorCausalChain}})},2566:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.removePrefix=t.addSuffix=t.removeSuffix=t.addPrefix=void 0,t.addPrefix=function(e,t){return e.startsWith(t)?e:`${t}${e}`},t.removeSuffix=function(e,t){return""===t?e:e.endsWith(t)?e.slice(0,-t.length):e},t.addSuffix=function(e,t){return e.endsWith(t)?e:`${e}${t}`},t.removePrefix=function(e,t){return e.startsWith(t)?e.slice(t.length):e}},8287:()=>{!function(e){var t=[{pattern:/"""[\s\S]*?"""[Hhcusa]?/,greedy:!0,inside:{symbol:{pattern:/("""[\s\S]*?""")[Hhcusa]/,lookbehind:!0,greedy:!0}}},{pattern:/"[^\n"]*"[Hhcusa]?/,greedy:!0,inside:{symbol:{pattern:/("[^\n"]*")[Hhcusa]/,lookbehind:!0,greedy:!0}}}],n=/(?:!=|\?|:|%=|%|&=|&|\*=|\*|\+=|\+|->|-=|-|\/%|\/=|\/|<=>|<<=|<<|<=|<|==|=|>>=|>>|>=|>|\^>>=|\^>>|\^=|\^\/=|\^\/|\^%=|\^%|\^|\|=|\||~>>=|~>>|~\/=|~\/|~%|~)(?=\s)/,o=[/`[^`\n]+`/,/[^\.~,;\[\]\(\)\s]+/];e.languages.func={comment:[{pattern:/;;.*/,lookbehind:!0,greedy:!0},{pattern:/\{-[\s\S]*?(?:-\}|$)/,lookbehind:!0,greedy:!0},{pattern:/\b_\b(?![^\.~,;\[\]\(\)\s])/}],pragma:{pattern:/#pragma(.*);/,inside:{keyword:/(?:#pragma|test-version-set|not-version|version|allow-post-modification|compute-asm-ltr)\b/,number:/(?:\d+)(?:.\d+)?(?:.\d+)?/,operator:/=|\^|<=|>=|<|>/,string:t,punctuation:/;/}},include:{pattern:/#include(.*);/,inside:{keyword:/#include\b/,string:t,punctuation:/;/}},builtin:/\b(?:int|cell|slice|builder|cont|tuple|type)\b/,boolean:/\b(?:false|true|nil|Nil)\b/,keyword:/\b(?:forall|extern|global|asm|impure|inline_ref|inline|auto_apply|method_id|operator|infixl|infixr|infix|const|return|var|repeat|do|while|until|try|catch|ifnot|if|then|elseifnot|elseif|else)\b/,number:/-?\b(?:\d+|0x[\da-fA-F]+)\b(?![^\.~,;\[\]\(\)\s])/,string:t,operator:n,punctuation:[/[\.,;\(\)\[\]]/,/[\{\}](?![^\.~,;\[\]\(\)\s])/],function:[{pattern:new RegExp(o[0].source+/(?=\s*\()/.source),greedy:!0},{pattern:/~_/,greedy:!0},{pattern:new RegExp(/\^?_/.source+n.source+/_/.source),greedy:!0},{pattern:new RegExp(/[\.~]?/.source+o[1].source+/(?=\s*\()/.source),greedy:!0},{pattern:/\b(?:divmod|moddiv|muldiv|muldivr|muldivc|muldivmod|null\?|throw|throw_if|throw_unless|throw_arg|throw_arg_if|throw_arg_unless|load_int|load_uint|preload_int|preload_uint|store_int|store_uint|load_bits|preload_bits|int_at|cell_at|slice_at|tuple_at|at|touch|touch2|run_method0|run_method1|run_method2|run_method3|~divmod|~moddiv|~store_int|~store_uint|~touch|~touch2|~dump|~stdump)\b/,greedy:!0}],"class-name":/[A-Z][^\.~,;\[\]\(\)\s]*/,variable:o.map((e=>({pattern:e,greedy:!0})))},e.languages.fc=e.languages.func}(Prism)},9325:()=>{!function(e){e.languages.tact={keyword:[{pattern:/\b(?:abstract|asm|as|catch|const|contract(?!:)|do|else|extend|extends|foreach|fun|get|if|in|import|initOf|inline|let|message(?!:)|mutates|native|override|primitive|public|repeat|return|self|struct(?!:)|trait(?!:)|try|until|virtual|while|with)\b/},{pattern:/\b(?:bounced|external|init|receive)\b(?=\()/}],builtin:[{pattern:/\b(?:Address|Bool|Builder|Cell|Int|Slice|String|StringBuilder)\b/},{pattern:/(\bas\s+)(?:coins|remaining|bytes32|bytes64|int257|u?int(?:2[0-5][0-6]|1[0-9][0-9]|[1-9][0-9]?))\b/,lookbehind:!0,greedy:!0}],constant:[{pattern:/\bnull\b/},{pattern:/\b[A-Z][A-Z0-9_]*\b/}],"class-name":{pattern:/\b[A-Z]\w*\b/},attribute:[{pattern:/@name/,inside:{function:/.+/}},{pattern:/@interface/,inside:{function:/.+/}}],function:{pattern:/\b\w+(?=\()/},boolean:{pattern:/\b(?:false|true)\b/},number:[{pattern:/\b0x[0-9a-f](?:_?[0-9a-f])*\b/i},{pattern:/\b0o[0-7](?:_?[0-7])*\b/i},{pattern:/\b0b[01](?:_?[01])*\b/i},{pattern:/\b0\d*\b/},{pattern:/\b[1-9](?:_?\d)*\b/}],string:void 0,punctuation:{pattern:/[{}[\]();,.:?]/},comment:[{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/\b_\b/}],operator:{pattern:/![!=]?|->|[+\-*/%=]=?|[<>]=|<<?|>>?|~|\|[\|=]?|&[&=]?|\^=?/},variable:{pattern:/\b[a-zA-Z_]\w*\b/}},e.languages.insertBefore("tact","string",{"string-literal":{pattern:/(?:(")(?:\\.|(?!\1)[^\\\r\n])*\1(?!\1))/,greedy:!0,inside:{regex:[{pattern:/\\[\\"nrtvbf]/},{pattern:/\\x[0-9a-fA-F]{2}/},{pattern:/\\u[0-9a-fA-F]{4}/},{pattern:/\\u\{[0-9a-fA-F]{1,6}\}/}],string:{pattern:/[\s\S]+/}}}}),e.languages.insertBefore("tact","keyword",{generics:{pattern:/(?:\b(?:bounced|map)\b<[^\\\r\n]*>)/,greedy:!0,inside:{builtin:[...e.languages.tact.builtin,{pattern:/\b(?:bounced(?=<)|map(?=<))\b/}],"class-name":e.languages.tact["class-name"],punctuation:{pattern:/[<>(),.?]/},keyword:{pattern:/\bas\b/}}}})}(Prism)},1513:(e,t,n)=>{"use strict";n.d(t,{zR:()=>w,TM:()=>C,yJ:()=>f,sC:()=>T,AO:()=>p});var o=n(8168);function r(e){return"/"===e.charAt(0)}function i(e,t){for(var n=t,o=n+1,r=e.length;o<r;n+=1,o+=1)e[n]=e[o];e.pop()}const s=function(e,t){void 0===t&&(t="");var n,o=e&&e.split("/")||[],s=t&&t.split("/")||[],a=e&&r(e),l=t&&r(t),c=a||l;if(e&&r(e)?s=o:o.length&&(s.pop(),s=s.concat(o)),!s.length)return"/";if(s.length){var d=s[s.length-1];n="."===d||".."===d||""===d}else n=!1;for(var u=0,p=s.length;p>=0;p--){var f=s[p];"."===f?i(s,p):".."===f?(i(s,p),u++):u&&(i(s,p),u--)}if(!c)for(;u--;u)s.unshift("..");!c||""===s[0]||s[0]&&r(s[0])||s.unshift("");var m=s.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var a=n(1561);function l(e){return"/"===e.charAt(0)?e:"/"+e}function c(e){return"/"===e.charAt(0)?e.substr(1):e}function d(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function u(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function p(e){var t=e.pathname,n=e.search,o=e.hash,r=t||"/";return n&&"?"!==n&&(r+="?"===n.charAt(0)?n:"?"+n),o&&"#"!==o&&(r+="#"===o.charAt(0)?o:"#"+o),r}function f(e,t,n,r){var i;"string"==typeof e?(i=function(e){var t=e||"/",n="",o="",r=t.indexOf("#");-1!==r&&(o=t.substr(r),t=t.substr(0,r));var i=t.indexOf("?");return-1!==i&&(n=t.substr(i),t=t.substr(0,i)),{pathname:t,search:"?"===n?"":n,hash:"#"===o?"":o}}(e),i.state=t):(void 0===(i=(0,o.A)({},e)).pathname&&(i.pathname=""),i.search?"?"!==i.search.charAt(0)&&(i.search="?"+i.search):i.search="",i.hash?"#"!==i.hash.charAt(0)&&(i.hash="#"+i.hash):i.hash="",void 0!==t&&void 0===i.state&&(i.state=t));try{i.pathname=decodeURI(i.pathname)}catch(a){throw a instanceof URIError?new URIError('Pathname "'+i.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):a}return n&&(i.key=n),r?i.pathname?"/"!==i.pathname.charAt(0)&&(i.pathname=s(i.pathname,r.pathname)):i.pathname=r.pathname:i.pathname||(i.pathname="/"),i}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,o,r){if(null!=e){var i="function"==typeof e?e(t,n):e;"string"==typeof i?"function"==typeof o?o(i,r):r(!0):r(!1!==i)}else r(!0)},appendListener:function(e){var n=!0;function o(){n&&e.apply(void 0,arguments)}return t.push(o),function(){n=!1,t=t.filter((function(e){return e!==o}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),o=0;o<e;o++)n[o]=arguments[o];t.forEach((function(e){return e.apply(void 0,n)}))}}}var h=!("undefined"==typeof window||!window.document||!window.document.createElement);function g(e,t){t(window.confirm(e))}var b="popstate",v="hashchange";function y(){try{return window.history.state||{}}catch(e){return{}}}function w(e){void 0===e&&(e={}),h||(0,a.A)(!1);var t,n=window.history,r=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,i=!(-1===window.navigator.userAgent.indexOf("Trident")),s=e,c=s.forceRefresh,w=void 0!==c&&c,k=s.getUserConfirmation,x=void 0===k?g:k,_=s.keyLength,S=void 0===_?6:_,A=e.basename?u(l(e.basename)):"";function C(e){var t=e||{},n=t.key,o=t.state,r=window.location,i=r.pathname+r.search+r.hash;return A&&(i=d(i,A)),f(i,o,n)}function E(){return Math.random().toString(36).substr(2,S)}var T=m();function D(e){(0,o.A)(z,e),z.length=n.length,T.notifyListeners(z.location,z.action)}function L(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||j(C(e.state))}function R(){j(C(y()))}var N=!1;function j(e){if(N)N=!1,D();else{T.confirmTransitionTo(e,"POP",x,(function(t){t?D({action:"POP",location:e}):function(e){var t=z.location,n=O.indexOf(t.key);-1===n&&(n=0);var o=O.indexOf(e.key);-1===o&&(o=0);var r=n-o;r&&(N=!0,M(r))}(e)}))}}var P=C(y()),O=[P.key];function I(e){return A+p(e)}function M(e){n.go(e)}var F=0;function B(e){1===(F+=e)&&1===e?(window.addEventListener(b,L),i&&window.addEventListener(v,R)):0===F&&(window.removeEventListener(b,L),i&&window.removeEventListener(v,R))}var U=!1;var z={length:n.length,action:"POP",location:P,createHref:I,push:function(e,t){var o="PUSH",i=f(e,t,E(),z.location);T.confirmTransitionTo(i,o,x,(function(e){if(e){var t=I(i),s=i.key,a=i.state;if(r)if(n.pushState({key:s,state:a},null,t),w)window.location.href=t;else{var l=O.indexOf(z.location.key),c=O.slice(0,l+1);c.push(i.key),O=c,D({action:o,location:i})}else window.location.href=t}}))},replace:function(e,t){var o="REPLACE",i=f(e,t,E(),z.location);T.confirmTransitionTo(i,o,x,(function(e){if(e){var t=I(i),s=i.key,a=i.state;if(r)if(n.replaceState({key:s,state:a},null,t),w)window.location.replace(t);else{var l=O.indexOf(z.location.key);-1!==l&&(O[l]=i.key),D({action:o,location:i})}else window.location.replace(t)}}))},go:M,goBack:function(){M(-1)},goForward:function(){M(1)},block:function(e){void 0===e&&(e=!1);var t=T.setPrompt(e);return U||(B(1),U=!0),function(){return U&&(U=!1,B(-1)),t()}},listen:function(e){var t=T.appendListener(e);return B(1),function(){B(-1),t()}}};return z}var k="hashchange",x={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+c(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:c,decodePath:l},slash:{encodePath:l,decodePath:l}};function _(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function S(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function A(e){window.location.replace(_(window.location.href)+"#"+e)}function C(e){void 0===e&&(e={}),h||(0,a.A)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),r=n.getUserConfirmation,i=void 0===r?g:r,s=n.hashType,c=void 0===s?"slash":s,b=e.basename?u(l(e.basename)):"",v=x[c],y=v.encodePath,w=v.decodePath;function C(){var e=w(S());return b&&(e=d(e,b)),f(e)}var E=m();function T(e){(0,o.A)(U,e),U.length=t.length,E.notifyListeners(U.location,U.action)}var D=!1,L=null;function R(){var e,t,n=S(),o=y(n);if(n!==o)A(o);else{var r=C(),s=U.location;if(!D&&(t=r,(e=s).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(L===p(r))return;L=null,function(e){if(D)D=!1,T();else{var t="POP";E.confirmTransitionTo(e,t,i,(function(n){n?T({action:t,location:e}):function(e){var t=U.location,n=O.lastIndexOf(p(t));-1===n&&(n=0);var o=O.lastIndexOf(p(e));-1===o&&(o=0);var r=n-o;r&&(D=!0,I(r))}(e)}))}}(r)}}var N=S(),j=y(N);N!==j&&A(j);var P=C(),O=[p(P)];function I(e){t.go(e)}var M=0;function F(e){1===(M+=e)&&1===e?window.addEventListener(k,R):0===M&&window.removeEventListener(k,R)}var B=!1;var U={length:t.length,action:"POP",location:P,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=_(window.location.href)),n+"#"+y(b+p(e))},push:function(e,t){var n="PUSH",o=f(e,void 0,void 0,U.location);E.confirmTransitionTo(o,n,i,(function(e){if(e){var t=p(o),r=y(b+t);if(S()!==r){L=t,function(e){window.location.hash=e}(r);var i=O.lastIndexOf(p(U.location)),s=O.slice(0,i+1);s.push(t),O=s,T({action:n,location:o})}else T()}}))},replace:function(e,t){var n="REPLACE",o=f(e,void 0,void 0,U.location);E.confirmTransitionTo(o,n,i,(function(e){if(e){var t=p(o),r=y(b+t);S()!==r&&(L=t,A(r));var i=O.indexOf(p(U.location));-1!==i&&(O[i]=t),T({action:n,location:o})}}))},go:I,goBack:function(){I(-1)},goForward:function(){I(1)},block:function(e){void 0===e&&(e=!1);var t=E.setPrompt(e);return B||(F(1),B=!0),function(){return B&&(B=!1,F(-1)),t()}},listen:function(e){var t=E.appendListener(e);return F(1),function(){F(-1),t()}}};return U}function E(e,t,n){return Math.min(Math.max(e,t),n)}function T(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,r=t.initialEntries,i=void 0===r?["/"]:r,s=t.initialIndex,a=void 0===s?0:s,l=t.keyLength,c=void 0===l?6:l,d=m();function u(e){(0,o.A)(w,e),w.length=w.entries.length,d.notifyListeners(w.location,w.action)}function h(){return Math.random().toString(36).substr(2,c)}var g=E(a,0,i.length-1),b=i.map((function(e){return f(e,void 0,"string"==typeof e?h():e.key||h())})),v=p;function y(e){var t=E(w.index+e,0,w.entries.length-1),o=w.entries[t];d.confirmTransitionTo(o,"POP",n,(function(e){e?u({action:"POP",location:o,index:t}):u()}))}var w={length:b.length,action:"POP",location:b[g],index:g,entries:b,createHref:v,push:function(e,t){var o="PUSH",r=f(e,t,h(),w.location);d.confirmTransitionTo(r,o,n,(function(e){if(e){var t=w.index+1,n=w.entries.slice(0);n.length>t?n.splice(t,n.length-t,r):n.push(r),u({action:o,location:r,index:t,entries:n})}}))},replace:function(e,t){var o="REPLACE",r=f(e,t,h(),w.location);d.confirmTransitionTo(r,o,n,(function(e){e&&(w.entries[w.index]=r,u({action:o,location:r}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t<w.entries.length},block:function(e){return void 0===e&&(e=!1),d.setPrompt(e)},listen:function(e){return d.appendListener(e)}};return w}},4146:(e,t,n)=>{"use strict";var o=n(4363),r={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},i={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},s={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},a={};function l(e){return o.isMemo(e)?s:a[e.$$typeof]||r}a[o.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},a[o.Memo]=s;var c=Object.defineProperty,d=Object.getOwnPropertyNames,u=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,o){if("string"!=typeof n){if(m){var r=f(n);r&&r!==m&&e(t,r,o)}var s=d(n);u&&(s=s.concat(u(n)));for(var a=l(t),h=l(n),g=0;g<s.length;++g){var b=s[g];if(!(i[b]||o&&o[b]||h&&h[b]||a&&a[b])){var v=p(n,b);try{c(t,b,v)}catch(y){}}}}return t}},311:e=>{"use strict";e.exports=function(e,t,n,o,r,i,s,a){if(!e){var l;if(void 0===t)l=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,o,r,i,s,a],d=0;(l=new Error(t.replace(/%s/g,(function(){return c[d++]})))).name="Invariant Violation"}throw l.framesToPop=1,l}}},4634:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},119:(e,t,n)=>{"use strict";n.r(t)},1043:(e,t,n)=>{"use strict";n.r(t)},5947:function(e,t,n){var o,r;o=function(){var e,t,n={version:"0.2.0"},o=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function r(e,t,n){return e<t?t:e>n?n:e}function i(e){return 100*(-1+e)}function s(e,t,n){var r;return(r="translate3d"===o.positionUsing?{transform:"translate3d("+i(e)+"%,0,0)"}:"translate"===o.positionUsing?{transform:"translate("+i(e)+"%,0)"}:{"margin-left":i(e)+"%"}).transition="all "+t+"ms "+n,r}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(o[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=r(e,o.minimum,1),n.status=1===e?null:e;var i=n.render(!t),c=i.querySelector(o.barSelector),d=o.speed,u=o.easing;return i.offsetWidth,a((function(t){""===o.positionUsing&&(o.positionUsing=n.getPositioningCSS()),l(c,s(e,d,u)),1===e?(l(i,{transition:"none",opacity:1}),i.offsetWidth,setTimeout((function(){l(i,{transition:"all "+d+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),d)}),d)):setTimeout(t,d)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),o.trickleSpeed)};return o.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*r(Math.random()*t,.1,.95)),t=r(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*o.trickleRate)},e=0,t=0,n.promise=function(o){return o&&"resolved"!==o.state()?(0===t&&n.start(),e++,t++,o.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");d(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=o.template;var r,s=t.querySelector(o.barSelector),a=e?"-100":i(n.status||0),c=document.querySelector(o.parent);return l(s,{transition:"all 0 linear",transform:"translate3d("+a+"%,0,0)"}),o.showSpinner||(r=t.querySelector(o.spinnerSelector))&&f(r),c!=document.body&&d(c,"nprogress-custom-parent"),c.appendChild(t),t},n.remove=function(){u(document.documentElement,"nprogress-busy"),u(document.querySelector(o.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&f(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var a=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),l=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function o(t){var n=document.body.style;if(t in n)return t;for(var o,r=e.length,i=t.charAt(0).toUpperCase()+t.slice(1);r--;)if((o=e[r]+i)in n)return o;return t}function r(e){return e=n(e),t[e]||(t[e]=o(e))}function i(e,t,n){t=r(t),e.style[t]=n}return function(e,t){var n,o,r=arguments;if(2==r.length)for(n in t)void 0!==(o=t[n])&&t.hasOwnProperty(n)&&i(e,n,o);else i(e,r[1],r[2])}}();function c(e,t){return("string"==typeof e?e:p(e)).indexOf(" "+t+" ")>=0}function d(e,t){var n=p(e),o=n+t;c(n,t)||(e.className=o.substring(1))}function u(e,t){var n,o=p(e);c(e,t)&&(n=o.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function p(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function f(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(r="function"==typeof o?o.call(t,n,t,e):o)||(e.exports=r)},6969:e=>{e.exports&&(e.exports={core:{meta:{path:"components/prism-core.js",option:"mandatory"},core:"Core"},themes:{meta:{path:"themes/{id}.css",link:"index.html?theme={id}",exclusive:!0},prism:{title:"Default",option:"default"},"prism-dark":"Dark","prism-funky":"Funky","prism-okaidia":{title:"Okaidia",owner:"ocodia"},"prism-twilight":{title:"Twilight",owner:"remybach"},"prism-coy":{title:"Coy",owner:"tshedor"},"prism-solarizedlight":{title:"Solarized Light",owner:"hectormatos2011 "},"prism-tomorrow":{title:"Tomorrow Night",owner:"Rosey"}},languages:{meta:{path:"components/prism-{id}",noCSS:!0,examplesPath:"examples/prism-{id}",addCheckAll:!0},markup:{title:"Markup",alias:["html","xml","svg","mathml","ssml","atom","rss"],aliasTitles:{html:"HTML",xml:"XML",svg:"SVG",mathml:"MathML",ssml:"SSML",atom:"Atom",rss:"RSS"},option:"default"},css:{title:"CSS",option:"default",modify:"markup"},clike:{title:"C-like",option:"default"},javascript:{title:"JavaScript",require:"clike",modify:"markup",optional:"regex",alias:"js",option:"default"},abap:{title:"ABAP",owner:"dellagustin"},abnf:{title:"ABNF",owner:"RunDevelopment"},actionscript:{title:"ActionScript",require:"javascript",modify:"markup",owner:"Golmote"},ada:{title:"Ada",owner:"Lucretia"},agda:{title:"Agda",owner:"xy-ren"},al:{title:"AL",owner:"RunDevelopment"},antlr4:{title:"ANTLR4",alias:"g4",owner:"RunDevelopment"},apacheconf:{title:"Apache Configuration",owner:"GuiTeK"},apex:{title:"Apex",require:["clike","sql"],owner:"RunDevelopment"},apl:{title:"APL",owner:"ngn"},applescript:{title:"AppleScript",owner:"Golmote"},aql:{title:"AQL",owner:"RunDevelopment"},arduino:{title:"Arduino",require:"cpp",alias:"ino",owner:"dkern"},arff:{title:"ARFF",owner:"Golmote"},armasm:{title:"ARM Assembly",alias:"arm-asm",owner:"RunDevelopment"},arturo:{title:"Arturo",alias:"art",optional:["bash","css","javascript","markup","markdown","sql"],owner:"drkameleon"},asciidoc:{alias:"adoc",title:"AsciiDoc",owner:"Golmote"},aspnet:{title:"ASP.NET (C#)",require:["markup","csharp"],owner:"nauzilus"},asm6502:{title:"6502 Assembly",owner:"kzurawel"},asmatmel:{title:"Atmel AVR Assembly",owner:"cerkit"},autohotkey:{title:"AutoHotkey",owner:"aviaryan"},autoit:{title:"AutoIt",owner:"Golmote"},avisynth:{title:"AviSynth",alias:"avs",owner:"Zinfidel"},"avro-idl":{title:"Avro IDL",alias:"avdl",owner:"RunDevelopment"},awk:{title:"AWK",alias:"gawk",aliasTitles:{gawk:"GAWK"},owner:"RunDevelopment"},bash:{title:"Bash",alias:["sh","shell"],aliasTitles:{sh:"Shell",shell:"Shell"},owner:"zeitgeist87"},basic:{title:"BASIC",owner:"Golmote"},batch:{title:"Batch",owner:"Golmote"},bbcode:{title:"BBcode",alias:"shortcode",aliasTitles:{shortcode:"Shortcode"},owner:"RunDevelopment"},bbj:{title:"BBj",owner:"hyyan"},bicep:{title:"Bicep",owner:"johnnyreilly"},birb:{title:"Birb",require:"clike",owner:"Calamity210"},bison:{title:"Bison",require:"c",owner:"Golmote"},bnf:{title:"BNF",alias:"rbnf",aliasTitles:{rbnf:"RBNF"},owner:"RunDevelopment"},bqn:{title:"BQN",owner:"yewscion"},brainfuck:{title:"Brainfuck",owner:"Golmote"},brightscript:{title:"BrightScript",owner:"RunDevelopment"},bro:{title:"Bro",owner:"wayward710"},bsl:{title:"BSL (1C:Enterprise)",alias:"oscript",aliasTitles:{oscript:"OneScript"},owner:"Diversus23"},c:{title:"C",require:"clike",owner:"zeitgeist87"},csharp:{title:"C#",require:"clike",alias:["cs","dotnet"],owner:"mvalipour"},cpp:{title:"C++",require:"c",owner:"zeitgeist87"},cfscript:{title:"CFScript",require:"clike",alias:"cfc",owner:"mjclemente"},chaiscript:{title:"ChaiScript",require:["clike","cpp"],owner:"RunDevelopment"},cil:{title:"CIL",owner:"sbrl"},cilkc:{title:"Cilk/C",require:"c",alias:"cilk-c",owner:"OpenCilk"},cilkcpp:{title:"Cilk/C++",require:"cpp",alias:["cilk-cpp","cilk"],owner:"OpenCilk"},clojure:{title:"Clojure",owner:"troglotit"},cmake:{title:"CMake",owner:"mjrogozinski"},cobol:{title:"COBOL",owner:"RunDevelopment"},coffeescript:{title:"CoffeeScript",require:"javascript",alias:"coffee",owner:"R-osey"},concurnas:{title:"Concurnas",alias:"conc",owner:"jasontatton"},csp:{title:"Content-Security-Policy",owner:"ScottHelme"},cooklang:{title:"Cooklang",owner:"ahue"},coq:{title:"Coq",owner:"RunDevelopment"},crystal:{title:"Crystal",require:"ruby",owner:"MakeNowJust"},"css-extras":{title:"CSS Extras",require:"css",modify:"css",owner:"milesj"},csv:{title:"CSV",owner:"RunDevelopment"},cue:{title:"CUE",owner:"RunDevelopment"},cypher:{title:"Cypher",owner:"RunDevelopment"},d:{title:"D",require:"clike",owner:"Golmote"},dart:{title:"Dart",require:"clike",owner:"Golmote"},dataweave:{title:"DataWeave",owner:"machaval"},dax:{title:"DAX",owner:"peterbud"},dhall:{title:"Dhall",owner:"RunDevelopment"},diff:{title:"Diff",owner:"uranusjr"},django:{title:"Django/Jinja2",require:"markup-templating",alias:"jinja2",owner:"romanvm"},"dns-zone-file":{title:"DNS zone file",owner:"RunDevelopment",alias:"dns-zone"},docker:{title:"Docker",alias:"dockerfile",owner:"JustinBeckwith"},dot:{title:"DOT (Graphviz)",alias:"gv",optional:"markup",owner:"RunDevelopment"},ebnf:{title:"EBNF",owner:"RunDevelopment"},editorconfig:{title:"EditorConfig",owner:"osipxd"},eiffel:{title:"Eiffel",owner:"Conaclos"},ejs:{title:"EJS",require:["javascript","markup-templating"],owner:"RunDevelopment",alias:"eta",aliasTitles:{eta:"Eta"}},elixir:{title:"Elixir",owner:"Golmote"},elm:{title:"Elm",owner:"zwilias"},etlua:{title:"Embedded Lua templating",require:["lua","markup-templating"],owner:"RunDevelopment"},erb:{title:"ERB",require:["ruby","markup-templating"],owner:"Golmote"},erlang:{title:"Erlang",owner:"Golmote"},"excel-formula":{title:"Excel Formula",alias:["xlsx","xls"],owner:"RunDevelopment"},fsharp:{title:"F#",require:"clike",owner:"simonreynolds7"},factor:{title:"Factor",owner:"catb0t"},false:{title:"False",owner:"edukisto"},"firestore-security-rules":{title:"Firestore security rules",require:"clike",owner:"RunDevelopment"},flow:{title:"Flow",require:"javascript",owner:"Golmote"},fortran:{title:"Fortran",owner:"Golmote"},ftl:{title:"FreeMarker Template Language",require:"markup-templating",owner:"RunDevelopment"},gml:{title:"GameMaker Language",alias:"gamemakerlanguage",require:"clike",owner:"LiarOnce"},gap:{title:"GAP (CAS)",owner:"RunDevelopment"},gcode:{title:"G-code",owner:"RunDevelopment"},gdscript:{title:"GDScript",owner:"RunDevelopment"},gedcom:{title:"GEDCOM",owner:"Golmote"},gettext:{title:"gettext",alias:"po",owner:"RunDevelopment"},gherkin:{title:"Gherkin",owner:"hason"},git:{title:"Git",owner:"lgiraudel"},glsl:{title:"GLSL",require:"c",owner:"Golmote"},gn:{title:"GN",alias:"gni",owner:"RunDevelopment"},"linker-script":{title:"GNU Linker Script",alias:"ld",owner:"RunDevelopment"},go:{title:"Go",require:"clike",owner:"arnehormann"},"go-module":{title:"Go module",alias:"go-mod",owner:"RunDevelopment"},gradle:{title:"Gradle",require:"clike",owner:"zeabdelkhalek-badido18"},graphql:{title:"GraphQL",optional:"markdown",owner:"Golmote"},groovy:{title:"Groovy",require:"clike",owner:"robfletcher"},haml:{title:"Haml",require:"ruby",optional:["css","css-extras","coffeescript","erb","javascript","less","markdown","scss","textile"],owner:"Golmote"},handlebars:{title:"Handlebars",require:"markup-templating",alias:["hbs","mustache"],aliasTitles:{mustache:"Mustache"},owner:"Golmote"},haskell:{title:"Haskell",alias:"hs",owner:"bholst"},haxe:{title:"Haxe",require:"clike",optional:"regex",owner:"Golmote"},hcl:{title:"HCL",owner:"outsideris"},hlsl:{title:"HLSL",require:"c",owner:"RunDevelopment"},hoon:{title:"Hoon",owner:"matildepark"},http:{title:"HTTP",optional:["csp","css","hpkp","hsts","javascript","json","markup","uri"],owner:"danielgtaylor"},hpkp:{title:"HTTP Public-Key-Pins",owner:"ScottHelme"},hsts:{title:"HTTP Strict-Transport-Security",owner:"ScottHelme"},ichigojam:{title:"IchigoJam",owner:"BlueCocoa"},icon:{title:"Icon",owner:"Golmote"},"icu-message-format":{title:"ICU Message Format",owner:"RunDevelopment"},idris:{title:"Idris",alias:"idr",owner:"KeenS",require:"haskell"},ignore:{title:".ignore",owner:"osipxd",alias:["gitignore","hgignore","npmignore"],aliasTitles:{gitignore:".gitignore",hgignore:".hgignore",npmignore:".npmignore"}},inform7:{title:"Inform 7",owner:"Golmote"},ini:{title:"Ini",owner:"aviaryan"},io:{title:"Io",owner:"AlesTsurko"},j:{title:"J",owner:"Golmote"},java:{title:"Java",require:"clike",owner:"sherblot"},javadoc:{title:"JavaDoc",require:["markup","java","javadoclike"],modify:"java",optional:"scala",owner:"RunDevelopment"},javadoclike:{title:"JavaDoc-like",modify:["java","javascript","php"],owner:"RunDevelopment"},javastacktrace:{title:"Java stack trace",owner:"RunDevelopment"},jexl:{title:"Jexl",owner:"czosel"},jolie:{title:"Jolie",require:"clike",owner:"thesave"},jq:{title:"JQ",owner:"RunDevelopment"},jsdoc:{title:"JSDoc",require:["javascript","javadoclike","typescript"],modify:"javascript",optional:["actionscript","coffeescript"],owner:"RunDevelopment"},"js-extras":{title:"JS Extras",require:"javascript",modify:"javascript",optional:["actionscript","coffeescript","flow","n4js","typescript"],owner:"RunDevelopment"},json:{title:"JSON",alias:"webmanifest",aliasTitles:{webmanifest:"Web App Manifest"},owner:"CupOfTea696"},json5:{title:"JSON5",require:"json",owner:"RunDevelopment"},jsonp:{title:"JSONP",require:"json",owner:"RunDevelopment"},jsstacktrace:{title:"JS stack trace",owner:"sbrl"},"js-templates":{title:"JS Templates",require:"javascript",modify:"javascript",optional:["css","css-extras","graphql","markdown","markup","sql"],owner:"RunDevelopment"},julia:{title:"Julia",owner:"cdagnino"},keepalived:{title:"Keepalived Configure",owner:"dev-itsheng"},keyman:{title:"Keyman",owner:"mcdurdin"},kotlin:{title:"Kotlin",alias:["kt","kts"],aliasTitles:{kts:"Kotlin Script"},require:"clike",owner:"Golmote"},kumir:{title:"KuMir (\u041a\u0443\u041c\u0438\u0440)",alias:"kum",owner:"edukisto"},kusto:{title:"Kusto",owner:"RunDevelopment"},latex:{title:"LaTeX",alias:["tex","context"],aliasTitles:{tex:"TeX",context:"ConTeXt"},owner:"japborst"},latte:{title:"Latte",require:["clike","markup-templating","php"],owner:"nette"},less:{title:"Less",require:"css",optional:"css-extras",owner:"Golmote"},lilypond:{title:"LilyPond",require:"scheme",alias:"ly",owner:"RunDevelopment"},liquid:{title:"Liquid",require:"markup-templating",owner:"cinhtau"},lisp:{title:"Lisp",alias:["emacs","elisp","emacs-lisp"],owner:"JuanCaicedo"},livescript:{title:"LiveScript",owner:"Golmote"},llvm:{title:"LLVM IR",owner:"porglezomp"},log:{title:"Log file",optional:"javastacktrace",owner:"RunDevelopment"},lolcode:{title:"LOLCODE",owner:"Golmote"},lua:{title:"Lua",owner:"Golmote"},magma:{title:"Magma (CAS)",owner:"RunDevelopment"},makefile:{title:"Makefile",owner:"Golmote"},markdown:{title:"Markdown",require:"markup",optional:"yaml",alias:"md",owner:"Golmote"},"markup-templating":{title:"Markup templating",require:"markup",owner:"Golmote"},mata:{title:"Mata",owner:"RunDevelopment"},matlab:{title:"MATLAB",owner:"Golmote"},maxscript:{title:"MAXScript",owner:"RunDevelopment"},mel:{title:"MEL",owner:"Golmote"},mermaid:{title:"Mermaid",owner:"RunDevelopment"},metafont:{title:"METAFONT",owner:"LaeriExNihilo"},mizar:{title:"Mizar",owner:"Golmote"},mongodb:{title:"MongoDB",owner:"airs0urce",require:"javascript"},monkey:{title:"Monkey",owner:"Golmote"},moonscript:{title:"MoonScript",alias:"moon",owner:"RunDevelopment"},n1ql:{title:"N1QL",owner:"TMWilds"},n4js:{title:"N4JS",require:"javascript",optional:"jsdoc",alias:"n4jsd",owner:"bsmith-n4"},"nand2tetris-hdl":{title:"Nand To Tetris HDL",owner:"stephanmax"},naniscript:{title:"Naninovel Script",owner:"Elringus",alias:"nani"},nasm:{title:"NASM",owner:"rbmj"},neon:{title:"NEON",owner:"nette"},nevod:{title:"Nevod",owner:"nezaboodka"},nginx:{title:"nginx",owner:"volado"},nim:{title:"Nim",owner:"Golmote"},nix:{title:"Nix",owner:"Golmote"},nsis:{title:"NSIS",owner:"idleberg"},objectivec:{title:"Objective-C",require:"c",alias:"objc",owner:"uranusjr"},ocaml:{title:"OCaml",owner:"Golmote"},odin:{title:"Odin",owner:"edukisto"},opencl:{title:"OpenCL",require:"c",modify:["c","cpp"],owner:"Milania1"},openqasm:{title:"OpenQasm",alias:"qasm",owner:"RunDevelopment"},oz:{title:"Oz",owner:"Golmote"},parigp:{title:"PARI/GP",owner:"Golmote"},parser:{title:"Parser",require:"markup",owner:"Golmote"},pascal:{title:"Pascal",alias:"objectpascal",aliasTitles:{objectpascal:"Object Pascal"},owner:"Golmote"},pascaligo:{title:"Pascaligo",owner:"DefinitelyNotAGoat"},psl:{title:"PATROL Scripting Language",owner:"bertysentry"},pcaxis:{title:"PC-Axis",alias:"px",owner:"RunDevelopment"},peoplecode:{title:"PeopleCode",alias:"pcode",owner:"RunDevelopment"},perl:{title:"Perl",owner:"Golmote"},php:{title:"PHP",require:"markup-templating",owner:"milesj"},phpdoc:{title:"PHPDoc",require:["php","javadoclike"],modify:"php",owner:"RunDevelopment"},"php-extras":{title:"PHP Extras",require:"php",modify:"php",owner:"milesj"},"plant-uml":{title:"PlantUML",alias:"plantuml",owner:"RunDevelopment"},plsql:{title:"PL/SQL",require:"sql",owner:"Golmote"},powerquery:{title:"PowerQuery",alias:["pq","mscript"],owner:"peterbud"},powershell:{title:"PowerShell",owner:"nauzilus"},processing:{title:"Processing",require:"clike",owner:"Golmote"},prolog:{title:"Prolog",owner:"Golmote"},promql:{title:"PromQL",owner:"arendjr"},properties:{title:".properties",owner:"Golmote"},protobuf:{title:"Protocol Buffers",require:"clike",owner:"just-boris"},pug:{title:"Pug",require:["markup","javascript"],optional:["coffeescript","ejs","handlebars","less","livescript","markdown","scss","stylus","twig"],owner:"Golmote"},puppet:{title:"Puppet",owner:"Golmote"},pure:{title:"Pure",optional:["c","cpp","fortran"],owner:"Golmote"},purebasic:{title:"PureBasic",require:"clike",alias:"pbfasm",owner:"HeX0R101"},purescript:{title:"PureScript",require:"haskell",alias:"purs",owner:"sriharshachilakapati"},python:{title:"Python",alias:"py",owner:"multipetros"},qsharp:{title:"Q#",require:"clike",alias:"qs",owner:"fedonman"},q:{title:"Q (kdb+ database)",owner:"Golmote"},qml:{title:"QML",require:"javascript",owner:"RunDevelopment"},qore:{title:"Qore",require:"clike",owner:"temnroegg"},r:{title:"R",owner:"Golmote"},racket:{title:"Racket",require:"scheme",alias:"rkt",owner:"RunDevelopment"},cshtml:{title:"Razor C#",alias:"razor",require:["markup","csharp"],optional:["css","css-extras","javascript","js-extras"],owner:"RunDevelopment"},jsx:{title:"React JSX",require:["markup","javascript"],optional:["jsdoc","js-extras","js-templates"],owner:"vkbansal"},tsx:{title:"React TSX",require:["jsx","typescript"]},reason:{title:"Reason",require:"clike",owner:"Golmote"},regex:{title:"Regex",owner:"RunDevelopment"},rego:{title:"Rego",owner:"JordanSh"},renpy:{title:"Ren'py",alias:"rpy",owner:"HyuchiaDiego"},rescript:{title:"ReScript",alias:"res",owner:"vmarcosp"},rest:{title:"reST (reStructuredText)",owner:"Golmote"},rip:{title:"Rip",owner:"ravinggenius"},roboconf:{title:"Roboconf",owner:"Golmote"},robotframework:{title:"Robot Framework",alias:"robot",owner:"RunDevelopment"},ruby:{title:"Ruby",require:"clike",alias:"rb",owner:"samflores"},rust:{title:"Rust",owner:"Golmote"},sas:{title:"SAS",optional:["groovy","lua","sql"],owner:"Golmote"},sass:{title:"Sass (Sass)",require:"css",optional:"css-extras",owner:"Golmote"},scss:{title:"Sass (SCSS)",require:"css",optional:"css-extras",owner:"MoOx"},scala:{title:"Scala",require:"java",owner:"jozic"},scheme:{title:"Scheme",owner:"bacchus123"},"shell-session":{title:"Shell session",require:"bash",alias:["sh-session","shellsession"],owner:"RunDevelopment"},smali:{title:"Smali",owner:"RunDevelopment"},smalltalk:{title:"Smalltalk",owner:"Golmote"},smarty:{title:"Smarty",require:"markup-templating",optional:"php",owner:"Golmote"},sml:{title:"SML",alias:"smlnj",aliasTitles:{smlnj:"SML/NJ"},owner:"RunDevelopment"},solidity:{title:"Solidity (Ethereum)",alias:"sol",require:"clike",owner:"glachaud"},"solution-file":{title:"Solution file",alias:"sln",owner:"RunDevelopment"},soy:{title:"Soy (Closure Template)",require:"markup-templating",owner:"Golmote"},sparql:{title:"SPARQL",require:"turtle",owner:"Triply-Dev",alias:"rq"},"splunk-spl":{title:"Splunk SPL",owner:"RunDevelopment"},sqf:{title:"SQF: Status Quo Function (Arma 3)",require:"clike",owner:"RunDevelopment"},sql:{title:"SQL",owner:"multipetros"},squirrel:{title:"Squirrel",require:"clike",owner:"RunDevelopment"},stan:{title:"Stan",owner:"RunDevelopment"},stata:{title:"Stata Ado",require:["mata","java","python"],owner:"RunDevelopment"},iecst:{title:"Structured Text (IEC 61131-3)",owner:"serhioromano"},stylus:{title:"Stylus",owner:"vkbansal"},supercollider:{title:"SuperCollider",alias:"sclang",owner:"RunDevelopment"},swift:{title:"Swift",owner:"chrischares"},systemd:{title:"Systemd configuration file",owner:"RunDevelopment"},"t4-templating":{title:"T4 templating",owner:"RunDevelopment"},"t4-cs":{title:"T4 Text Templates (C#)",require:["t4-templating","csharp"],alias:"t4",owner:"RunDevelopment"},"t4-vb":{title:"T4 Text Templates (VB)",require:["t4-templating","vbnet"],owner:"RunDevelopment"},tap:{title:"TAP",owner:"isaacs",require:"yaml"},tcl:{title:"Tcl",owner:"PeterChaplin"},tt2:{title:"Template Toolkit 2",require:["clike","markup-templating"],owner:"gflohr"},textile:{title:"Textile",require:"markup",optional:"css",owner:"Golmote"},toml:{title:"TOML",owner:"RunDevelopment"},tremor:{title:"Tremor",alias:["trickle","troy"],owner:"darach",aliasTitles:{trickle:"trickle",troy:"troy"}},turtle:{title:"Turtle",alias:"trig",aliasTitles:{trig:"TriG"},owner:"jakubklimek"},twig:{title:"Twig",require:"markup-templating",owner:"brandonkelly"},typescript:{title:"TypeScript",require:"javascript",optional:"js-templates",alias:"ts",owner:"vkbansal"},typoscript:{title:"TypoScript",alias:"tsconfig",aliasTitles:{tsconfig:"TSConfig"},owner:"dkern"},unrealscript:{title:"UnrealScript",alias:["uscript","uc"],owner:"RunDevelopment"},uorazor:{title:"UO Razor Script",owner:"jaseowns"},uri:{title:"URI",alias:"url",aliasTitles:{url:"URL"},owner:"RunDevelopment"},v:{title:"V",require:"clike",owner:"taggon"},vala:{title:"Vala",require:"clike",optional:"regex",owner:"TemplarVolk"},vbnet:{title:"VB.Net",require:"basic",owner:"Bigsby"},velocity:{title:"Velocity",require:"markup",owner:"Golmote"},verilog:{title:"Verilog",owner:"a-rey"},vhdl:{title:"VHDL",owner:"a-rey"},vim:{title:"vim",owner:"westonganger"},"visual-basic":{title:"Visual Basic",alias:["vb","vba"],aliasTitles:{vba:"VBA"},owner:"Golmote"},warpscript:{title:"WarpScript",owner:"RunDevelopment"},wasm:{title:"WebAssembly",owner:"Golmote"},"web-idl":{title:"Web IDL",alias:"webidl",owner:"RunDevelopment"},wgsl:{title:"WGSL",owner:"Dr4gonthree"},wiki:{title:"Wiki markup",require:"markup",owner:"Golmote"},wolfram:{title:"Wolfram language",alias:["mathematica","nb","wl"],aliasTitles:{mathematica:"Mathematica",nb:"Mathematica Notebook"},owner:"msollami"},wren:{title:"Wren",owner:"clsource"},xeora:{title:"Xeora",require:"markup",alias:"xeoracube",aliasTitles:{xeoracube:"XeoraCube"},owner:"freakmaxi"},"xml-doc":{title:"XML doc (.net)",require:"markup",modify:["csharp","fsharp","vbnet"],owner:"RunDevelopment"},xojo:{title:"Xojo (REALbasic)",owner:"Golmote"},xquery:{title:"XQuery",require:"markup",owner:"Golmote"},yaml:{title:"YAML",alias:"yml",owner:"hason"},yang:{title:"YANG",owner:"RunDevelopment"},zig:{title:"Zig",owner:"RunDevelopment"}},plugins:{meta:{path:"plugins/{id}/prism-{id}",link:"plugins/{id}/"},"line-highlight":{title:"Line Highlight",description:"Highlights specific lines and/or line ranges."},"line-numbers":{title:"Line Numbers",description:"Line number at the beginning of code lines.",owner:"kuba-kubula"},"show-invisibles":{title:"Show Invisibles",description:"Show hidden characters such as tabs and line breaks.",optional:["autolinker","data-uri-highlight"]},autolinker:{title:"Autolinker",description:"Converts URLs and emails in code to clickable links. Parses Markdown links in comments."},wpd:{title:"WebPlatform Docs",description:'Makes tokens link to <a href="https://webplatform.github.io/docs/">WebPlatform.org documentation</a>. The links open in a new tab.'},"custom-class":{title:"Custom Class",description:"This plugin allows you to prefix Prism's default classes (<code>.comment</code> can become <code>.namespace--comment</code>) or replace them with your defined ones (like <code>.editor__comment</code>). You can even add new classes.",owner:"dvkndn",noCSS:!0},"file-highlight":{title:"File Highlight",description:"Fetch external files and highlight them with Prism. Used on the Prism website itself.",noCSS:!0},"show-language":{title:"Show Language",description:"Display the highlighted language in code blocks (inline code does not show the label).",owner:"nauzilus",noCSS:!0,require:"toolbar"},"jsonp-highlight":{title:"JSONP Highlight",description:"Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).",noCSS:!0,owner:"nauzilus"},"highlight-keywords":{title:"Highlight Keywords",description:"Adds special CSS classes for each keyword for fine-grained highlighting.",owner:"vkbansal",noCSS:!0},"remove-initial-line-feed":{title:"Remove initial line feed",description:"Removes the initial line feed in code blocks.",owner:"Golmote",noCSS:!0},"inline-color":{title:"Inline color",description:"Adds a small inline preview for colors in style sheets.",require:"css-extras",owner:"RunDevelopment"},previewers:{title:"Previewers",description:"Previewers for angles, colors, gradients, easing and time.",require:"css-extras",owner:"Golmote"},autoloader:{title:"Autoloader",description:"Automatically loads the needed languages to highlight the code blocks.",owner:"Golmote",noCSS:!0},"keep-markup":{title:"Keep Markup",description:"Prevents custom markup from being dropped out during highlighting.",owner:"Golmote",optional:"normalize-whitespace",noCSS:!0},"command-line":{title:"Command Line",description:"Display a command line with a prompt and, optionally, the output/response from the commands.",owner:"chriswells0"},"unescaped-markup":{title:"Unescaped Markup",description:"Write markup without having to escape anything."},"normalize-whitespace":{title:"Normalize Whitespace",description:"Supports multiple operations to normalize whitespace in code blocks.",owner:"zeitgeist87",optional:"unescaped-markup",noCSS:!0},"data-uri-highlight":{title:"Data-URI Highlight",description:"Highlights data-URI contents.",owner:"Golmote",noCSS:!0},toolbar:{title:"Toolbar",description:"Attach a toolbar for plugins to easily register buttons on the top of a code block.",owner:"mAAdhaTTah"},"copy-to-clipboard":{title:"Copy to Clipboard Button",description:"Add a button that copies the code block to the clipboard when clicked.",owner:"mAAdhaTTah",require:"toolbar",noCSS:!0},"download-button":{title:"Download Button",description:"A button in the toolbar of a code block adding a convenient way to download a code file.",owner:"Golmote",require:"toolbar",noCSS:!0},"match-braces":{title:"Match braces",description:"Highlights matching braces.",owner:"RunDevelopment"},"diff-highlight":{title:"Diff Highlight",description:"Highlights the code inside diff blocks.",owner:"RunDevelopment",require:"diff"},"filter-highlight-all":{title:"Filter highlightAll",description:"Filters the elements the <code>highlightAll</code> and <code>highlightAllUnder</code> methods actually highlight.",owner:"RunDevelopment",noCSS:!0},treeview:{title:"Treeview",description:"A language with special styles to highlight file system tree structures.",owner:"Golmote"}}})},8722:(e,t,n)=>{const o=n(6969),r=n(8380),i=new Set;function s(e){void 0===e?e=Object.keys(o.languages).filter((e=>"meta"!=e)):Array.isArray(e)||(e=[e]);const t=[...i,...Object.keys(Prism.languages)];r(o,e,t).load((e=>{if(!(e in o.languages))return void(s.silent||console.warn("Language does not exist: "+e));const t="./prism-"+e;delete n.c[n(3157).resolve(t)],delete Prism.languages[e],n(3157)(t),i.add(e)}))}s.silent=!1,e.exports=s},8692:(e,t,n)=>{var o={"./":8722};function r(e){var t=i(e);return n(t)}function i(e){if(!n.o(o,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return o[e]}r.keys=function(){return Object.keys(o)},r.resolve=i,e.exports=r,r.id=8692},3157:(e,t,n)=>{var o={"./":8722};function r(e){var t=i(e);return n(t)}function i(e){if(!n.o(o,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return o[e]}r.keys=function(){return Object.keys(o)},r.resolve=i,e.exports=r,r.id=3157},8380:e=>{"use strict";var t=function(){var e=function(){};function t(e,t){Array.isArray(e)?e.forEach(t):null!=e&&t(e,0)}function n(e){for(var t={},n=0,o=e.length;n<o;n++)t[e[n]]=!0;return t}function o(e){var n={},o=[];function r(o,i){if(!(o in n)){i.push(o);var s=i.indexOf(o);if(s<i.length-1)throw new Error("Circular dependency: "+i.slice(s).join(" -> "));var a={},l=e[o];if(l){function c(t){if(!(t in e))throw new Error(o+" depends on an unknown component "+t);if(!(t in a))for(var s in r(t,i),a[t]=!0,n[t])a[s]=!0}t(l.require,c),t(l.optional,c),t(l.modify,c)}n[o]=a,i.pop()}}return function(e){var t=n[e];return t||(r(e,o),t=n[e]),t}}function r(e){for(var t in e)return!0;return!1}return function(i,s,a){var l=function(e){var t={};for(var n in e){var o=e[n];for(var r in o)if("meta"!=r){var i=o[r];t[r]="string"==typeof i?{title:i}:i}}return t}(i),c=function(e){var n;return function(o){if(o in e)return o;if(!n)for(var r in n={},e){var i=e[r];t(i&&i.alias,(function(t){if(t in n)throw new Error(t+" cannot be alias for both "+r+" and "+n[t]);if(t in e)throw new Error(t+" cannot be alias of "+r+" because it is a component.");n[t]=r}))}return n[o]||o}}(l);s=s.map(c),a=(a||[]).map(c);var d=n(s),u=n(a);s.forEach((function e(n){var o=l[n];t(o&&o.require,(function(t){t in u||(d[t]=!0,e(t))}))}));for(var p,f=o(l),m=d;r(m);){for(var h in p={},m){var g=l[h];t(g&&g.modify,(function(e){e in u&&(p[e]=!0)}))}for(var b in u)if(!(b in d))for(var v in f(b))if(v in d){p[b]=!0;break}for(var y in m=p)d[y]=!0}var w={getIds:function(){var e=[];return w.load((function(t){e.push(t)})),e},load:function(t,n){return function(t,n,o,r){var i=r?r.series:void 0,s=r?r.parallel:e,a={},l={};function c(e){if(e in a)return a[e];l[e]=!0;var r,d=[];for(var u in t(e))u in n&&d.push(u);if(0===d.length)r=o(e);else{var p=s(d.map((function(e){var t=c(e);return delete l[e],t})));i?r=i(p,(function(){return o(e)})):o(e)}return a[e]=r}for(var d in n)c(d);var u=[];for(var p in l)u.push(a[p]);return s(u)}(f,d,t,n)}};return w}}();e.exports=t},2694:(e,t,n)=>{"use strict";var o=n(6925);function r(){}function i(){}i.resetWarningCache=r,e.exports=function(){function e(e,t,n,r,i,s){if(s!==o){var a=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw a.name="Invariant Violation",a}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:i,resetWarningCache:r};return n.PropTypes=n,n}},5556:(e,t,n)=>{e.exports=n(2694)()},6925:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},2551:(e,t,n)=>{"use strict";var o=n(6540),r=n(9982);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var s=new Set,a={};function l(e,t){c(e,t),c(e+"Capture",t)}function c(e,t){for(a[e]=t,e=0;e<t.length;e++)s.add(t[e])}var d=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),u=Object.prototype.hasOwnProperty,p=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,f={},m={};function h(e,t,n,o,r,i,s){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=o,this.attributeNamespace=r,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=s}var g={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){g[e]=new h(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];g[t]=new h(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){g[e]=new h(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){g[e]=new h(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){g[e]=new h(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){g[e]=new h(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){g[e]=new h(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){g[e]=new h(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){g[e]=new h(e,5,!1,e.toLowerCase(),null,!1,!1)}));var b=/[\-:]([a-z])/g;function v(e){return e[1].toUpperCase()}function y(e,t,n,o){var r=g.hasOwnProperty(t)?g[t]:null;(null!==r?0!==r.type:o||!(2<t.length)||"o"!==t[0]&&"O"!==t[0]||"n"!==t[1]&&"N"!==t[1])&&(function(e,t,n,o){if(null==t||function(e,t,n,o){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!o&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,o))return!0;if(o)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,r,o)&&(n=null),o||null===r?function(e){return!!u.call(m,e)||!u.call(f,e)&&(p.test(e)?m[e]=!0:(f[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):r.mustUseProperty?e[r.propertyName]=null===n?3!==r.type&&"":n:(t=r.attributeName,o=r.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(r=r.type)||4===r&&!0===n?"":""+n,o?e.setAttributeNS(o,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(b,v);g[t]=new h(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(b,v);g[t]=new h(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(b,v);g[t]=new h(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){g[e]=new h(e,1,!1,e.toLowerCase(),null,!1,!1)})),g.xlinkHref=new h("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){g[e]=new h(e,1,!1,e.toLowerCase(),null,!0,!0)}));var w=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,k=Symbol.for("react.element"),x=Symbol.for("react.portal"),_=Symbol.for("react.fragment"),S=Symbol.for("react.strict_mode"),A=Symbol.for("react.profiler"),C=Symbol.for("react.provider"),E=Symbol.for("react.context"),T=Symbol.for("react.forward_ref"),D=Symbol.for("react.suspense"),L=Symbol.for("react.suspense_list"),R=Symbol.for("react.memo"),N=Symbol.for("react.lazy");Symbol.for("react.scope"),Symbol.for("react.debug_trace_mode");var j=Symbol.for("react.offscreen");Symbol.for("react.legacy_hidden"),Symbol.for("react.cache"),Symbol.for("react.tracing_marker");var P=Symbol.iterator;function O(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=P&&e[P]||e["@@iterator"])?e:null}var I,M=Object.assign;function F(e){if(void 0===I)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);I=t&&t[1]||""}return"\n"+I+e}var B=!1;function U(e,t){if(!e||B)return"";B=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(c){var o=c}Reflect.construct(e,[],t)}else{try{t.call()}catch(c){o=c}e.call(t.prototype)}else{try{throw Error()}catch(c){o=c}e()}}catch(c){if(c&&o&&"string"==typeof c.stack){for(var r=c.stack.split("\n"),i=o.stack.split("\n"),s=r.length-1,a=i.length-1;1<=s&&0<=a&&r[s]!==i[a];)a--;for(;1<=s&&0<=a;s--,a--)if(r[s]!==i[a]){if(1!==s||1!==a)do{if(s--,0>--a||r[s]!==i[a]){var l="\n"+r[s].replace(" at new "," at ");return e.displayName&&l.includes("<anonymous>")&&(l=l.replace("<anonymous>",e.displayName)),l}}while(1<=s&&0<=a);break}}}finally{B=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?F(e):""}function z(e){switch(e.tag){case 5:return F(e.type);case 16:return F("Lazy");case 13:return F("Suspense");case 19:return F("SuspenseList");case 0:case 2:case 15:return e=U(e.type,!1);case 11:return e=U(e.type.render,!1);case 1:return e=U(e.type,!0);default:return""}}function $(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case _:return"Fragment";case x:return"Portal";case A:return"Profiler";case S:return"StrictMode";case D:return"Suspense";case L:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case E:return(e.displayName||"Context")+".Consumer";case C:return(e._context.displayName||"Context")+".Provider";case T:var t=e.render;return(e=e.displayName)||(e=""!==(e=t.displayName||t.name||"")?"ForwardRef("+e+")":"ForwardRef"),e;case R:return null!==(t=e.displayName||null)?t:$(e.type)||"Memo";case N:t=e._payload,e=e._init;try{return $(e(t))}catch(n){}}return null}function V(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=(e=t.render).displayName||e.name||"",t.displayName||(""!==e?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return $(t);case 8:return t===S?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if("function"==typeof t)return t.displayName||t.name||null;if("string"==typeof t)return t}return null}function q(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":case"object":return e;default:return""}}function H(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function G(e){e._valueTracker||(e._valueTracker=function(e){var t=H(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),o=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var r=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return r.call(this)},set:function(e){o=""+e,i.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return o},setValue:function(e){o=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function W(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),o="";return e&&(o=H(e)?e.checked?"true":"false":e.value),(e=o)!==n&&(t.setValue(e),!0)}function Z(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function Q(e,t){var n=t.checked;return M({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function K(e,t){var n=null==t.defaultValue?"":t.defaultValue,o=null!=t.checked?t.checked:t.defaultChecked;n=q(null!=t.value?t.value:n),e._wrapperState={initialChecked:o,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function Y(e,t){null!=(t=t.checked)&&y(e,"checked",t,!1)}function X(e,t){Y(e,t);var n=q(t.value),o=t.type;if(null!=n)"number"===o?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===o||"reset"===o)return void e.removeAttribute("value");t.hasOwnProperty("value")?ee(e,t.type,n):t.hasOwnProperty("defaultValue")&&ee(e,t.type,q(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function J(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var o=t.type;if(!("submit"!==o&&"reset"!==o||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function ee(e,t,n){"number"===t&&Z(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var te=Array.isArray;function ne(e,t,n,o){if(e=e.options,t){t={};for(var r=0;r<n.length;r++)t["$"+n[r]]=!0;for(n=0;n<e.length;n++)r=t.hasOwnProperty("$"+e[n].value),e[n].selected!==r&&(e[n].selected=r),r&&o&&(e[n].defaultSelected=!0)}else{for(n=""+q(n),t=null,r=0;r<e.length;r++){if(e[r].value===n)return e[r].selected=!0,void(o&&(e[r].defaultSelected=!0));null!==t||e[r].disabled||(t=e[r])}null!==t&&(t.selected=!0)}}function oe(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(i(91));return M({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function re(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(i(92));if(te(n)){if(1<n.length)throw Error(i(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:q(n)}}function ie(e,t){var n=q(t.value),o=q(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=o&&(e.defaultValue=""+o)}function se(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}function ae(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function le(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?ae(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var ce,de,ue=(de=function(e,t){if("http://www.w3.org/2000/svg"!==e.namespaceURI||"innerHTML"in e)e.innerHTML=t;else{for((ce=ce||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=ce.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,o){MSApp.execUnsafeLocalFunction((function(){return de(e,t)}))}:de);function pe(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var fe={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},me=["Webkit","ms","Moz","O"];function he(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||fe.hasOwnProperty(e)&&fe[e]?(""+t).trim():t+"px"}function ge(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var o=0===n.indexOf("--"),r=he(n,t[n],o);"float"===n&&(n="cssFloat"),o?e.setProperty(n,r):e[n]=r}}Object.keys(fe).forEach((function(e){me.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),fe[t]=fe[e]}))}));var be=M({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function ve(e,t){if(t){if(be[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(i(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(i(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(i(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(i(62))}}function ye(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var we=null;function ke(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var xe=null,_e=null,Se=null;function Ae(e){if(e=wr(e)){if("function"!=typeof xe)throw Error(i(280));var t=e.stateNode;t&&(t=xr(t),xe(e.stateNode,e.type,t))}}function Ce(e){_e?Se?Se.push(e):Se=[e]:_e=e}function Ee(){if(_e){var e=_e,t=Se;if(Se=_e=null,Ae(e),t)for(e=0;e<t.length;e++)Ae(t[e])}}function Te(e,t){return e(t)}function De(){}var Le=!1;function Re(e,t,n){if(Le)return e(t,n);Le=!0;try{return Te(e,t,n)}finally{Le=!1,(null!==_e||null!==Se)&&(De(),Ee())}}function Ne(e,t){var n=e.stateNode;if(null===n)return null;var o=xr(n);if(null===o)return null;n=o[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(o=!o.disabled)||(o=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!o;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(i(231,t,typeof n));return n}var je=!1;if(d)try{var Pe={};Object.defineProperty(Pe,"passive",{get:function(){je=!0}}),window.addEventListener("test",Pe,Pe),window.removeEventListener("test",Pe,Pe)}catch(de){je=!1}function Oe(e,t,n,o,r,i,s,a,l){var c=Array.prototype.slice.call(arguments,3);try{t.apply(n,c)}catch(d){this.onError(d)}}var Ie=!1,Me=null,Fe=!1,Be=null,Ue={onError:function(e){Ie=!0,Me=e}};function ze(e,t,n,o,r,i,s,a,l){Ie=!1,Me=null,Oe.apply(Ue,arguments)}function $e(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{!!(4098&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function Ve(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function qe(e){if($e(e)!==e)throw Error(i(188))}function He(e){return null!==(e=function(e){var t=e.alternate;if(!t){if(null===(t=$e(e)))throw Error(i(188));return t!==e?null:e}for(var n=e,o=t;;){var r=n.return;if(null===r)break;var s=r.alternate;if(null===s){if(null!==(o=r.return)){n=o;continue}break}if(r.child===s.child){for(s=r.child;s;){if(s===n)return qe(r),e;if(s===o)return qe(r),t;s=s.sibling}throw Error(i(188))}if(n.return!==o.return)n=r,o=s;else{for(var a=!1,l=r.child;l;){if(l===n){a=!0,n=r,o=s;break}if(l===o){a=!0,o=r,n=s;break}l=l.sibling}if(!a){for(l=s.child;l;){if(l===n){a=!0,n=s,o=r;break}if(l===o){a=!0,o=s,n=r;break}l=l.sibling}if(!a)throw Error(i(189))}}if(n.alternate!==o)throw Error(i(190))}if(3!==n.tag)throw Error(i(188));return n.stateNode.current===n?e:t}(e))?Ge(e):null}function Ge(e){if(5===e.tag||6===e.tag)return e;for(e=e.child;null!==e;){var t=Ge(e);if(null!==t)return t;e=e.sibling}return null}var We=r.unstable_scheduleCallback,Ze=r.unstable_cancelCallback,Qe=r.unstable_shouldYield,Ke=r.unstable_requestPaint,Ye=r.unstable_now,Xe=r.unstable_getCurrentPriorityLevel,Je=r.unstable_ImmediatePriority,et=r.unstable_UserBlockingPriority,tt=r.unstable_NormalPriority,nt=r.unstable_LowPriority,ot=r.unstable_IdlePriority,rt=null,it=null;var st=Math.clz32?Math.clz32:function(e){return e>>>=0,0===e?32:31-(at(e)/lt|0)|0},at=Math.log,lt=Math.LN2;var ct=64,dt=4194304;function ut(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return 4194240&e;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return 130023424&e;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function pt(e,t){var n=e.pendingLanes;if(0===n)return 0;var o=0,r=e.suspendedLanes,i=e.pingedLanes,s=268435455&n;if(0!==s){var a=s&~r;0!==a?o=ut(a):0!==(i&=s)&&(o=ut(i))}else 0!==(s=n&~r)?o=ut(s):0!==i&&(o=ut(i));if(0===o)return 0;if(0!==t&&t!==o&&!(t&r)&&((r=o&-o)>=(i=t&-t)||16===r&&4194240&i))return t;if(4&o&&(o|=16&n),0!==(t=e.entangledLanes))for(e=e.entanglements,t&=o;0<t;)r=1<<(n=31-st(t)),o|=e[n],t&=~r;return o}function ft(e,t){switch(e){case 1:case 2:case 4:return t+250;case 8:case 16:case 32:case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;default:return-1}}function mt(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function ht(){var e=ct;return!(4194240&(ct<<=1))&&(ct=64),e}function gt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function bt(e,t,n){e.pendingLanes|=t,536870912!==t&&(e.suspendedLanes=0,e.pingedLanes=0),(e=e.eventTimes)[t=31-st(t)]=n}function vt(e,t){var n=e.entangledLanes|=t;for(e=e.entanglements;n;){var o=31-st(n),r=1<<o;r&t|e[o]&t&&(e[o]|=t),n&=~r}}var yt=0;function wt(e){return 1<(e&=-e)?4<e?268435455&e?16:536870912:4:1}var kt,xt,_t,St,At,Ct=!1,Et=[],Tt=null,Dt=null,Lt=null,Rt=new Map,Nt=new Map,jt=[],Pt="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function Ot(e,t){switch(e){case"focusin":case"focusout":Tt=null;break;case"dragenter":case"dragleave":Dt=null;break;case"mouseover":case"mouseout":Lt=null;break;case"pointerover":case"pointerout":Rt.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":Nt.delete(t.pointerId)}}function It(e,t,n,o,r,i){return null===e||e.nativeEvent!==i?(e={blockedOn:t,domEventName:n,eventSystemFlags:o,nativeEvent:i,targetContainers:[r]},null!==t&&(null!==(t=wr(t))&&xt(t)),e):(e.eventSystemFlags|=o,t=e.targetContainers,null!==r&&-1===t.indexOf(r)&&t.push(r),e)}function Mt(e){var t=yr(e.target);if(null!==t){var n=$e(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=Ve(n)))return e.blockedOn=t,void At(e.priority,(function(){_t(n)}))}else if(3===t&&n.stateNode.current.memoizedState.isDehydrated)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function Ft(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=Qt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=wr(n))&&xt(t),e.blockedOn=n,!1;var o=new(n=e.nativeEvent).constructor(n.type,n);we=o,n.target.dispatchEvent(o),we=null,t.shift()}return!0}function Bt(e,t,n){Ft(e)&&n.delete(t)}function Ut(){Ct=!1,null!==Tt&&Ft(Tt)&&(Tt=null),null!==Dt&&Ft(Dt)&&(Dt=null),null!==Lt&&Ft(Lt)&&(Lt=null),Rt.forEach(Bt),Nt.forEach(Bt)}function zt(e,t){e.blockedOn===t&&(e.blockedOn=null,Ct||(Ct=!0,r.unstable_scheduleCallback(r.unstable_NormalPriority,Ut)))}function $t(e){function t(t){return zt(t,e)}if(0<Et.length){zt(Et[0],e);for(var n=1;n<Et.length;n++){var o=Et[n];o.blockedOn===e&&(o.blockedOn=null)}}for(null!==Tt&&zt(Tt,e),null!==Dt&&zt(Dt,e),null!==Lt&&zt(Lt,e),Rt.forEach(t),Nt.forEach(t),n=0;n<jt.length;n++)(o=jt[n]).blockedOn===e&&(o.blockedOn=null);for(;0<jt.length&&null===(n=jt[0]).blockedOn;)Mt(n),null===n.blockedOn&&jt.shift()}var Vt=w.ReactCurrentBatchConfig,qt=!0;function Ht(e,t,n,o){var r=yt,i=Vt.transition;Vt.transition=null;try{yt=1,Wt(e,t,n,o)}finally{yt=r,Vt.transition=i}}function Gt(e,t,n,o){var r=yt,i=Vt.transition;Vt.transition=null;try{yt=4,Wt(e,t,n,o)}finally{yt=r,Vt.transition=i}}function Wt(e,t,n,o){if(qt){var r=Qt(e,t,n,o);if(null===r)Ho(e,t,o,Zt,n),Ot(e,o);else if(function(e,t,n,o,r){switch(t){case"focusin":return Tt=It(Tt,e,t,n,o,r),!0;case"dragenter":return Dt=It(Dt,e,t,n,o,r),!0;case"mouseover":return Lt=It(Lt,e,t,n,o,r),!0;case"pointerover":var i=r.pointerId;return Rt.set(i,It(Rt.get(i)||null,e,t,n,o,r)),!0;case"gotpointercapture":return i=r.pointerId,Nt.set(i,It(Nt.get(i)||null,e,t,n,o,r)),!0}return!1}(r,e,t,n,o))o.stopPropagation();else if(Ot(e,o),4&t&&-1<Pt.indexOf(e)){for(;null!==r;){var i=wr(r);if(null!==i&&kt(i),null===(i=Qt(e,t,n,o))&&Ho(e,t,o,Zt,n),i===r)break;r=i}null!==r&&o.stopPropagation()}else Ho(e,t,o,null,n)}}var Zt=null;function Qt(e,t,n,o){if(Zt=null,null!==(e=yr(e=ke(o))))if(null===(t=$e(e)))e=null;else if(13===(n=t.tag)){if(null!==(e=Ve(t)))return e;e=null}else if(3===n){if(t.stateNode.current.memoizedState.isDehydrated)return 3===t.tag?t.stateNode.containerInfo:null;e=null}else t!==e&&(e=null);return Zt=e,null}function Kt(e){switch(e){case"cancel":case"click":case"close":case"contextmenu":case"copy":case"cut":case"auxclick":case"dblclick":case"dragend":case"dragstart":case"drop":case"focusin":case"focusout":case"input":case"invalid":case"keydown":case"keypress":case"keyup":case"mousedown":case"mouseup":case"paste":case"pause":case"play":case"pointercancel":case"pointerdown":case"pointerup":case"ratechange":case"reset":case"resize":case"seeked":case"submit":case"touchcancel":case"touchend":case"touchstart":case"volumechange":case"change":case"selectionchange":case"textInput":case"compositionstart":case"compositionend":case"compositionupdate":case"beforeblur":case"afterblur":case"beforeinput":case"blur":case"fullscreenchange":case"focus":case"hashchange":case"popstate":case"select":case"selectstart":return 1;case"drag":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"mousemove":case"mouseout":case"mouseover":case"pointermove":case"pointerout":case"pointerover":case"scroll":case"toggle":case"touchmove":case"wheel":case"mouseenter":case"mouseleave":case"pointerenter":case"pointerleave":return 4;case"message":switch(Xe()){case Je:return 1;case et:return 4;case tt:case nt:return 16;case ot:return 536870912;default:return 16}default:return 16}}var Yt=null,Xt=null,Jt=null;function en(){if(Jt)return Jt;var e,t,n=Xt,o=n.length,r="value"in Yt?Yt.value:Yt.textContent,i=r.length;for(e=0;e<o&&n[e]===r[e];e++);var s=o-e;for(t=1;t<=s&&n[o-t]===r[i-t];t++);return Jt=r.slice(e,1<t?1-t:void 0)}function tn(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function nn(){return!0}function on(){return!1}function rn(e){function t(t,n,o,r,i){for(var s in this._reactName=t,this._targetInst=o,this.type=n,this.nativeEvent=r,this.target=i,this.currentTarget=null,e)e.hasOwnProperty(s)&&(t=e[s],this[s]=t?t(r):r[s]);return this.isDefaultPrevented=(null!=r.defaultPrevented?r.defaultPrevented:!1===r.returnValue)?nn:on,this.isPropagationStopped=on,this}return M(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=nn)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=nn)},persist:function(){},isPersistent:nn}),t}var sn,an,ln,cn={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},dn=rn(cn),un=M({},cn,{view:0,detail:0}),pn=rn(un),fn=M({},un,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:An,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==ln&&(ln&&"mousemove"===e.type?(sn=e.screenX-ln.screenX,an=e.screenY-ln.screenY):an=sn=0,ln=e),sn)},movementY:function(e){return"movementY"in e?e.movementY:an}}),mn=rn(fn),hn=rn(M({},fn,{dataTransfer:0})),gn=rn(M({},un,{relatedTarget:0})),bn=rn(M({},cn,{animationName:0,elapsedTime:0,pseudoElement:0})),vn=M({},cn,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),yn=rn(vn),wn=rn(M({},cn,{data:0})),kn={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},xn={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},_n={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function Sn(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=_n[e])&&!!t[e]}function An(){return Sn}var Cn=M({},un,{key:function(e){if(e.key){var t=kn[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=tn(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?xn[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:An,charCode:function(e){return"keypress"===e.type?tn(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?tn(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),En=rn(Cn),Tn=rn(M({},fn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),Dn=rn(M({},un,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:An})),Ln=rn(M({},cn,{propertyName:0,elapsedTime:0,pseudoElement:0})),Rn=M({},fn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),Nn=rn(Rn),jn=[9,13,27,32],Pn=d&&"CompositionEvent"in window,On=null;d&&"documentMode"in document&&(On=document.documentMode);var In=d&&"TextEvent"in window&&!On,Mn=d&&(!Pn||On&&8<On&&11>=On),Fn=String.fromCharCode(32),Bn=!1;function Un(e,t){switch(e){case"keyup":return-1!==jn.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function zn(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var $n=!1;var Vn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function qn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Vn[e.type]:"textarea"===t}function Hn(e,t,n,o){Ce(o),0<(t=Wo(t,"onChange")).length&&(n=new dn("onChange","change",null,n,o),e.push({event:n,listeners:t}))}var Gn=null,Wn=null;function Zn(e){Bo(e,0)}function Qn(e){if(W(kr(e)))return e}function Kn(e,t){if("change"===e)return t}var Yn=!1;if(d){var Xn;if(d){var Jn="oninput"in document;if(!Jn){var eo=document.createElement("div");eo.setAttribute("oninput","return;"),Jn="function"==typeof eo.oninput}Xn=Jn}else Xn=!1;Yn=Xn&&(!document.documentMode||9<document.documentMode)}function to(){Gn&&(Gn.detachEvent("onpropertychange",no),Wn=Gn=null)}function no(e){if("value"===e.propertyName&&Qn(Wn)){var t=[];Hn(t,Wn,e,ke(e)),Re(Zn,t)}}function oo(e,t,n){"focusin"===e?(to(),Wn=n,(Gn=t).attachEvent("onpropertychange",no)):"focusout"===e&&to()}function ro(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return Qn(Wn)}function io(e,t){if("click"===e)return Qn(t)}function so(e,t){if("input"===e||"change"===e)return Qn(t)}var ao="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t};function lo(e,t){if(ao(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),o=Object.keys(t);if(n.length!==o.length)return!1;for(o=0;o<n.length;o++){var r=n[o];if(!u.call(t,r)||!ao(e[r],t[r]))return!1}return!0}function co(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function uo(e,t){var n,o=co(e);for(e=0;o;){if(3===o.nodeType){if(n=e+o.textContent.length,e<=t&&n>=t)return{node:o,offset:t-e};e=n}e:{for(;o;){if(o.nextSibling){o=o.nextSibling;break e}o=o.parentNode}o=void 0}o=co(o)}}function po(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?po(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function fo(){for(var e=window,t=Z();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(o){n=!1}if(!n)break;t=Z((e=t.contentWindow).document)}return t}function mo(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}function ho(e){var t=fo(),n=e.focusedElem,o=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&po(n.ownerDocument.documentElement,n)){if(null!==o&&mo(n))if(t=o.start,void 0===(e=o.end)&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if((e=(t=n.ownerDocument||document)&&t.defaultView||window).getSelection){e=e.getSelection();var r=n.textContent.length,i=Math.min(o.start,r);o=void 0===o.end?i:Math.min(o.end,r),!e.extend&&i>o&&(r=o,o=i,i=r),r=uo(n,i);var s=uo(n,o);r&&s&&(1!==e.rangeCount||e.anchorNode!==r.node||e.anchorOffset!==r.offset||e.focusNode!==s.node||e.focusOffset!==s.offset)&&((t=t.createRange()).setStart(r.node,r.offset),e.removeAllRanges(),i>o?(e.addRange(t),e.extend(s.node,s.offset)):(t.setEnd(s.node,s.offset),e.addRange(t)))}for(t=[],e=n;e=e.parentNode;)1===e.nodeType&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for("function"==typeof n.focus&&n.focus(),n=0;n<t.length;n++)(e=t[n]).element.scrollLeft=e.left,e.element.scrollTop=e.top}}var go=d&&"documentMode"in document&&11>=document.documentMode,bo=null,vo=null,yo=null,wo=!1;function ko(e,t,n){var o=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;wo||null==bo||bo!==Z(o)||("selectionStart"in(o=bo)&&mo(o)?o={start:o.selectionStart,end:o.selectionEnd}:o={anchorNode:(o=(o.ownerDocument&&o.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:o.anchorOffset,focusNode:o.focusNode,focusOffset:o.focusOffset},yo&&lo(yo,o)||(yo=o,0<(o=Wo(vo,"onSelect")).length&&(t=new dn("onSelect","select",null,t,n),e.push({event:t,listeners:o}),t.target=bo)))}function xo(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var _o={animationend:xo("Animation","AnimationEnd"),animationiteration:xo("Animation","AnimationIteration"),animationstart:xo("Animation","AnimationStart"),transitionend:xo("Transition","TransitionEnd")},So={},Ao={};function Co(e){if(So[e])return So[e];if(!_o[e])return e;var t,n=_o[e];for(t in n)if(n.hasOwnProperty(t)&&t in Ao)return So[e]=n[t];return e}d&&(Ao=document.createElement("div").style,"AnimationEvent"in window||(delete _o.animationend.animation,delete _o.animationiteration.animation,delete _o.animationstart.animation),"TransitionEvent"in window||delete _o.transitionend.transition);var Eo=Co("animationend"),To=Co("animationiteration"),Do=Co("animationstart"),Lo=Co("transitionend"),Ro=new Map,No="abort auxClick cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" ");function jo(e,t){Ro.set(e,t),l(t,[e])}for(var Po=0;Po<No.length;Po++){var Oo=No[Po];jo(Oo.toLowerCase(),"on"+(Oo[0].toUpperCase()+Oo.slice(1)))}jo(Eo,"onAnimationEnd"),jo(To,"onAnimationIteration"),jo(Do,"onAnimationStart"),jo("dblclick","onDoubleClick"),jo("focusin","onFocus"),jo("focusout","onBlur"),jo(Lo,"onTransitionEnd"),c("onMouseEnter",["mouseout","mouseover"]),c("onMouseLeave",["mouseout","mouseover"]),c("onPointerEnter",["pointerout","pointerover"]),c("onPointerLeave",["pointerout","pointerover"]),l("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),l("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),l("onBeforeInput",["compositionend","keypress","textInput","paste"]),l("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),l("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),l("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var Io="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange resize seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Mo=new Set("cancel close invalid load scroll toggle".split(" ").concat(Io));function Fo(e,t,n){var o=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,o,r,s,a,l,c){if(ze.apply(this,arguments),Ie){if(!Ie)throw Error(i(198));var d=Me;Ie=!1,Me=null,Fe||(Fe=!0,Be=d)}}(o,t,void 0,e),e.currentTarget=null}function Bo(e,t){t=!!(4&t);for(var n=0;n<e.length;n++){var o=e[n],r=o.event;o=o.listeners;e:{var i=void 0;if(t)for(var s=o.length-1;0<=s;s--){var a=o[s],l=a.instance,c=a.currentTarget;if(a=a.listener,l!==i&&r.isPropagationStopped())break e;Fo(r,a,c),i=l}else for(s=0;s<o.length;s++){if(l=(a=o[s]).instance,c=a.currentTarget,a=a.listener,l!==i&&r.isPropagationStopped())break e;Fo(r,a,c),i=l}}}if(Fe)throw e=Be,Fe=!1,Be=null,e}function Uo(e,t){var n=t[gr];void 0===n&&(n=t[gr]=new Set);var o=e+"__bubble";n.has(o)||(qo(t,e,2,!1),n.add(o))}function zo(e,t,n){var o=0;t&&(o|=4),qo(n,e,o,t)}var $o="_reactListening"+Math.random().toString(36).slice(2);function Vo(e){if(!e[$o]){e[$o]=!0,s.forEach((function(t){"selectionchange"!==t&&(Mo.has(t)||zo(t,!1,e),zo(t,!0,e))}));var t=9===e.nodeType?e:e.ownerDocument;null===t||t[$o]||(t[$o]=!0,zo("selectionchange",!1,t))}}function qo(e,t,n,o){switch(Kt(t)){case 1:var r=Ht;break;case 4:r=Gt;break;default:r=Wt}n=r.bind(null,t,n,e),r=void 0,!je||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(r=!0),o?void 0!==r?e.addEventListener(t,n,{capture:!0,passive:r}):e.addEventListener(t,n,!0):void 0!==r?e.addEventListener(t,n,{passive:r}):e.addEventListener(t,n,!1)}function Ho(e,t,n,o,r){var i=o;if(!(1&t||2&t||null===o))e:for(;;){if(null===o)return;var s=o.tag;if(3===s||4===s){var a=o.stateNode.containerInfo;if(a===r||8===a.nodeType&&a.parentNode===r)break;if(4===s)for(s=o.return;null!==s;){var l=s.tag;if((3===l||4===l)&&((l=s.stateNode.containerInfo)===r||8===l.nodeType&&l.parentNode===r))return;s=s.return}for(;null!==a;){if(null===(s=yr(a)))return;if(5===(l=s.tag)||6===l){o=i=s;continue e}a=a.parentNode}}o=o.return}Re((function(){var o=i,r=ke(n),s=[];e:{var a=Ro.get(e);if(void 0!==a){var l=dn,c=e;switch(e){case"keypress":if(0===tn(n))break e;case"keydown":case"keyup":l=En;break;case"focusin":c="focus",l=gn;break;case"focusout":c="blur",l=gn;break;case"beforeblur":case"afterblur":l=gn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":l=mn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":l=hn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":l=Dn;break;case Eo:case To:case Do:l=bn;break;case Lo:l=Ln;break;case"scroll":l=pn;break;case"wheel":l=Nn;break;case"copy":case"cut":case"paste":l=yn;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":l=Tn}var d=!!(4&t),u=!d&&"scroll"===e,p=d?null!==a?a+"Capture":null:a;d=[];for(var f,m=o;null!==m;){var h=(f=m).stateNode;if(5===f.tag&&null!==h&&(f=h,null!==p&&(null!=(h=Ne(m,p))&&d.push(Go(m,h,f)))),u)break;m=m.return}0<d.length&&(a=new l(a,c,null,n,r),s.push({event:a,listeners:d}))}}if(!(7&t)){if(l="mouseout"===e||"pointerout"===e,(!(a="mouseover"===e||"pointerover"===e)||n===we||!(c=n.relatedTarget||n.fromElement)||!yr(c)&&!c[hr])&&(l||a)&&(a=r.window===r?r:(a=r.ownerDocument)?a.defaultView||a.parentWindow:window,l?(l=o,null!==(c=(c=n.relatedTarget||n.toElement)?yr(c):null)&&(c!==(u=$e(c))||5!==c.tag&&6!==c.tag)&&(c=null)):(l=null,c=o),l!==c)){if(d=mn,h="onMouseLeave",p="onMouseEnter",m="mouse","pointerout"!==e&&"pointerover"!==e||(d=Tn,h="onPointerLeave",p="onPointerEnter",m="pointer"),u=null==l?a:kr(l),f=null==c?a:kr(c),(a=new d(h,m+"leave",l,n,r)).target=u,a.relatedTarget=f,h=null,yr(r)===o&&((d=new d(p,m+"enter",c,n,r)).target=f,d.relatedTarget=u,h=d),u=h,l&&c)e:{for(p=c,m=0,f=d=l;f;f=Zo(f))m++;for(f=0,h=p;h;h=Zo(h))f++;for(;0<m-f;)d=Zo(d),m--;for(;0<f-m;)p=Zo(p),f--;for(;m--;){if(d===p||null!==p&&d===p.alternate)break e;d=Zo(d),p=Zo(p)}d=null}else d=null;null!==l&&Qo(s,a,l,d,!1),null!==c&&null!==u&&Qo(s,u,c,d,!0)}if("select"===(l=(a=o?kr(o):window).nodeName&&a.nodeName.toLowerCase())||"input"===l&&"file"===a.type)var g=Kn;else if(qn(a))if(Yn)g=so;else{g=ro;var b=oo}else(l=a.nodeName)&&"input"===l.toLowerCase()&&("checkbox"===a.type||"radio"===a.type)&&(g=io);switch(g&&(g=g(e,o))?Hn(s,g,n,r):(b&&b(e,a,o),"focusout"===e&&(b=a._wrapperState)&&b.controlled&&"number"===a.type&&ee(a,"number",a.value)),b=o?kr(o):window,e){case"focusin":(qn(b)||"true"===b.contentEditable)&&(bo=b,vo=o,yo=null);break;case"focusout":yo=vo=bo=null;break;case"mousedown":wo=!0;break;case"contextmenu":case"mouseup":case"dragend":wo=!1,ko(s,n,r);break;case"selectionchange":if(go)break;case"keydown":case"keyup":ko(s,n,r)}var v;if(Pn)e:{switch(e){case"compositionstart":var y="onCompositionStart";break e;case"compositionend":y="onCompositionEnd";break e;case"compositionupdate":y="onCompositionUpdate";break e}y=void 0}else $n?Un(e,n)&&(y="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(y="onCompositionStart");y&&(Mn&&"ko"!==n.locale&&($n||"onCompositionStart"!==y?"onCompositionEnd"===y&&$n&&(v=en()):(Xt="value"in(Yt=r)?Yt.value:Yt.textContent,$n=!0)),0<(b=Wo(o,y)).length&&(y=new wn(y,e,null,n,r),s.push({event:y,listeners:b}),v?y.data=v:null!==(v=zn(n))&&(y.data=v))),(v=In?function(e,t){switch(e){case"compositionend":return zn(t);case"keypress":return 32!==t.which?null:(Bn=!0,Fn);case"textInput":return(e=t.data)===Fn&&Bn?null:e;default:return null}}(e,n):function(e,t){if($n)return"compositionend"===e||!Pn&&Un(e,t)?(e=en(),Jt=Xt=Yt=null,$n=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return Mn&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(o=Wo(o,"onBeforeInput")).length&&(r=new wn("onBeforeInput","beforeinput",null,n,r),s.push({event:r,listeners:o}),r.data=v))}Bo(s,t)}))}function Go(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Wo(e,t){for(var n=t+"Capture",o=[];null!==e;){var r=e,i=r.stateNode;5===r.tag&&null!==i&&(r=i,null!=(i=Ne(e,n))&&o.unshift(Go(e,i,r)),null!=(i=Ne(e,t))&&o.push(Go(e,i,r))),e=e.return}return o}function Zo(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Qo(e,t,n,o,r){for(var i=t._reactName,s=[];null!==n&&n!==o;){var a=n,l=a.alternate,c=a.stateNode;if(null!==l&&l===o)break;5===a.tag&&null!==c&&(a=c,r?null!=(l=Ne(n,i))&&s.unshift(Go(n,l,a)):r||null!=(l=Ne(n,i))&&s.push(Go(n,l,a))),n=n.return}0!==s.length&&e.push({event:t,listeners:s})}var Ko=/\r\n?/g,Yo=/\u0000|\uFFFD/g;function Xo(e){return("string"==typeof e?e:""+e).replace(Ko,"\n").replace(Yo,"")}function Jo(e,t,n){if(t=Xo(t),Xo(e)!==t&&n)throw Error(i(425))}function er(){}var tr=null,nr=null;function or(e,t){return"textarea"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var rr="function"==typeof setTimeout?setTimeout:void 0,ir="function"==typeof clearTimeout?clearTimeout:void 0,sr="function"==typeof Promise?Promise:void 0,ar="function"==typeof queueMicrotask?queueMicrotask:void 0!==sr?function(e){return sr.resolve(null).then(e).catch(lr)}:rr;function lr(e){setTimeout((function(){throw e}))}function cr(e,t){var n=t,o=0;do{var r=n.nextSibling;if(e.removeChild(n),r&&8===r.nodeType)if("/$"===(n=r.data)){if(0===o)return e.removeChild(r),void $t(t);o--}else"$"!==n&&"$?"!==n&&"$!"!==n||o++;n=r}while(n);$t(t)}function dr(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break;if(8===t){if("$"===(t=e.data)||"$!"===t||"$?"===t)break;if("/$"===t)return null}}return e}function ur(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var pr=Math.random().toString(36).slice(2),fr="__reactFiber$"+pr,mr="__reactProps$"+pr,hr="__reactContainer$"+pr,gr="__reactEvents$"+pr,br="__reactListeners$"+pr,vr="__reactHandles$"+pr;function yr(e){var t=e[fr];if(t)return t;for(var n=e.parentNode;n;){if(t=n[hr]||n[fr]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=ur(e);null!==e;){if(n=e[fr])return n;e=ur(e)}return t}n=(e=n).parentNode}return null}function wr(e){return!(e=e[fr]||e[hr])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function kr(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(i(33))}function xr(e){return e[mr]||null}var _r=[],Sr=-1;function Ar(e){return{current:e}}function Cr(e){0>Sr||(e.current=_r[Sr],_r[Sr]=null,Sr--)}function Er(e,t){Sr++,_r[Sr]=e.current,e.current=t}var Tr={},Dr=Ar(Tr),Lr=Ar(!1),Rr=Tr;function Nr(e,t){var n=e.type.contextTypes;if(!n)return Tr;var o=e.stateNode;if(o&&o.__reactInternalMemoizedUnmaskedChildContext===t)return o.__reactInternalMemoizedMaskedChildContext;var r,i={};for(r in n)i[r]=t[r];return o&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=i),i}function jr(e){return null!=(e=e.childContextTypes)}function Pr(){Cr(Lr),Cr(Dr)}function Or(e,t,n){if(Dr.current!==Tr)throw Error(i(168));Er(Dr,t),Er(Lr,n)}function Ir(e,t,n){var o=e.stateNode;if(t=t.childContextTypes,"function"!=typeof o.getChildContext)return n;for(var r in o=o.getChildContext())if(!(r in t))throw Error(i(108,V(e)||"Unknown",r));return M({},n,o)}function Mr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Tr,Rr=Dr.current,Er(Dr,e),Er(Lr,Lr.current),!0}function Fr(e,t,n){var o=e.stateNode;if(!o)throw Error(i(169));n?(e=Ir(e,t,Rr),o.__reactInternalMemoizedMergedChildContext=e,Cr(Lr),Cr(Dr),Er(Dr,e)):Cr(Lr),Er(Lr,n)}var Br=null,Ur=!1,zr=!1;function $r(e){null===Br?Br=[e]:Br.push(e)}function Vr(){if(!zr&&null!==Br){zr=!0;var e=0,t=yt;try{var n=Br;for(yt=1;e<n.length;e++){var o=n[e];do{o=o(!0)}while(null!==o)}Br=null,Ur=!1}catch(r){throw null!==Br&&(Br=Br.slice(e+1)),We(Je,Vr),r}finally{yt=t,zr=!1}}return null}var qr=[],Hr=0,Gr=null,Wr=0,Zr=[],Qr=0,Kr=null,Yr=1,Xr="";function Jr(e,t){qr[Hr++]=Wr,qr[Hr++]=Gr,Gr=e,Wr=t}function ei(e,t,n){Zr[Qr++]=Yr,Zr[Qr++]=Xr,Zr[Qr++]=Kr,Kr=e;var o=Yr;e=Xr;var r=32-st(o)-1;o&=~(1<<r),n+=1;var i=32-st(t)+r;if(30<i){var s=r-r%5;i=(o&(1<<s)-1).toString(32),o>>=s,r-=s,Yr=1<<32-st(t)+r|n<<r|o,Xr=i+e}else Yr=1<<i|n<<r|o,Xr=e}function ti(e){null!==e.return&&(Jr(e,1),ei(e,1,0))}function ni(e){for(;e===Gr;)Gr=qr[--Hr],qr[Hr]=null,Wr=qr[--Hr],qr[Hr]=null;for(;e===Kr;)Kr=Zr[--Qr],Zr[Qr]=null,Xr=Zr[--Qr],Zr[Qr]=null,Yr=Zr[--Qr],Zr[Qr]=null}var oi=null,ri=null,ii=!1,si=null;function ai(e,t){var n=Rc(5,null,null,0);n.elementType="DELETED",n.stateNode=t,n.return=e,null===(t=e.deletions)?(e.deletions=[n],e.flags|=16):t.push(n)}function li(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,oi=e,ri=dr(t.firstChild),!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,oi=e,ri=null,!0);case 13:return null!==(t=8!==t.nodeType?null:t)&&(n=null!==Kr?{id:Yr,overflow:Xr}:null,e.memoizedState={dehydrated:t,treeContext:n,retryLane:1073741824},(n=Rc(18,null,null,0)).stateNode=t,n.return=e,e.child=n,oi=e,ri=null,!0);default:return!1}}function ci(e){return!(!(1&e.mode)||128&e.flags)}function di(e){if(ii){var t=ri;if(t){var n=t;if(!li(e,t)){if(ci(e))throw Error(i(418));t=dr(n.nextSibling);var o=oi;t&&li(e,t)?ai(o,n):(e.flags=-4097&e.flags|2,ii=!1,oi=e)}}else{if(ci(e))throw Error(i(418));e.flags=-4097&e.flags|2,ii=!1,oi=e}}}function ui(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;oi=e}function pi(e){if(e!==oi)return!1;if(!ii)return ui(e),ii=!0,!1;var t;if((t=3!==e.tag)&&!(t=5!==e.tag)&&(t="head"!==(t=e.type)&&"body"!==t&&!or(e.type,e.memoizedProps)),t&&(t=ri)){if(ci(e))throw fi(),Error(i(418));for(;t;)ai(e,t),t=dr(t.nextSibling)}if(ui(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(i(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){ri=dr(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}ri=null}}else ri=oi?dr(e.stateNode.nextSibling):null;return!0}function fi(){for(var e=ri;e;)e=dr(e.nextSibling)}function mi(){ri=oi=null,ii=!1}function hi(e){null===si?si=[e]:si.push(e)}var gi=w.ReactCurrentBatchConfig;function bi(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(i(309));var o=n.stateNode}if(!o)throw Error(i(147,e));var r=o,s=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===s?t.ref:(t=function(e){var t=r.refs;null===e?delete t[s]:t[s]=e},t._stringRef=s,t)}if("string"!=typeof e)throw Error(i(284));if(!n._owner)throw Error(i(290,e))}return e}function vi(e,t){throw e=Object.prototype.toString.call(t),Error(i(31,"[object Object]"===e?"object with keys {"+Object.keys(t).join(", ")+"}":e))}function yi(e){return(0,e._init)(e._payload)}function wi(e){function t(t,n){if(e){var o=t.deletions;null===o?(t.deletions=[n],t.flags|=16):o.push(n)}}function n(n,o){if(!e)return null;for(;null!==o;)t(n,o),o=o.sibling;return null}function o(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function r(e,t){return(e=jc(e,t)).index=0,e.sibling=null,e}function s(t,n,o){return t.index=o,e?null!==(o=t.alternate)?(o=o.index)<n?(t.flags|=2,n):o:(t.flags|=2,n):(t.flags|=1048576,n)}function a(t){return e&&null===t.alternate&&(t.flags|=2),t}function l(e,t,n,o){return null===t||6!==t.tag?((t=Mc(n,e.mode,o)).return=e,t):((t=r(t,n)).return=e,t)}function c(e,t,n,o){var i=n.type;return i===_?u(e,t,n.props.children,o,n.key):null!==t&&(t.elementType===i||"object"==typeof i&&null!==i&&i.$$typeof===N&&yi(i)===t.type)?((o=r(t,n.props)).ref=bi(e,t,n),o.return=e,o):((o=Pc(n.type,n.key,n.props,null,e.mode,o)).ref=bi(e,t,n),o.return=e,o)}function d(e,t,n,o){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=Fc(n,e.mode,o)).return=e,t):((t=r(t,n.children||[])).return=e,t)}function u(e,t,n,o,i){return null===t||7!==t.tag?((t=Oc(n,e.mode,o,i)).return=e,t):((t=r(t,n)).return=e,t)}function p(e,t,n){if("string"==typeof t&&""!==t||"number"==typeof t)return(t=Mc(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case k:return(n=Pc(t.type,t.key,t.props,null,e.mode,n)).ref=bi(e,null,t),n.return=e,n;case x:return(t=Fc(t,e.mode,n)).return=e,t;case N:return p(e,(0,t._init)(t._payload),n)}if(te(t)||O(t))return(t=Oc(t,e.mode,n,null)).return=e,t;vi(e,t)}return null}function f(e,t,n,o){var r=null!==t?t.key:null;if("string"==typeof n&&""!==n||"number"==typeof n)return null!==r?null:l(e,t,""+n,o);if("object"==typeof n&&null!==n){switch(n.$$typeof){case k:return n.key===r?c(e,t,n,o):null;case x:return n.key===r?d(e,t,n,o):null;case N:return f(e,t,(r=n._init)(n._payload),o)}if(te(n)||O(n))return null!==r?null:u(e,t,n,o,null);vi(e,n)}return null}function m(e,t,n,o,r){if("string"==typeof o&&""!==o||"number"==typeof o)return l(t,e=e.get(n)||null,""+o,r);if("object"==typeof o&&null!==o){switch(o.$$typeof){case k:return c(t,e=e.get(null===o.key?n:o.key)||null,o,r);case x:return d(t,e=e.get(null===o.key?n:o.key)||null,o,r);case N:return m(e,t,n,(0,o._init)(o._payload),r)}if(te(o)||O(o))return u(t,e=e.get(n)||null,o,r,null);vi(t,o)}return null}function h(r,i,a,l){for(var c=null,d=null,u=i,h=i=0,g=null;null!==u&&h<a.length;h++){u.index>h?(g=u,u=null):g=u.sibling;var b=f(r,u,a[h],l);if(null===b){null===u&&(u=g);break}e&&u&&null===b.alternate&&t(r,u),i=s(b,i,h),null===d?c=b:d.sibling=b,d=b,u=g}if(h===a.length)return n(r,u),ii&&Jr(r,h),c;if(null===u){for(;h<a.length;h++)null!==(u=p(r,a[h],l))&&(i=s(u,i,h),null===d?c=u:d.sibling=u,d=u);return ii&&Jr(r,h),c}for(u=o(r,u);h<a.length;h++)null!==(g=m(u,r,h,a[h],l))&&(e&&null!==g.alternate&&u.delete(null===g.key?h:g.key),i=s(g,i,h),null===d?c=g:d.sibling=g,d=g);return e&&u.forEach((function(e){return t(r,e)})),ii&&Jr(r,h),c}function g(r,a,l,c){var d=O(l);if("function"!=typeof d)throw Error(i(150));if(null==(l=d.call(l)))throw Error(i(151));for(var u=d=null,h=a,g=a=0,b=null,v=l.next();null!==h&&!v.done;g++,v=l.next()){h.index>g?(b=h,h=null):b=h.sibling;var y=f(r,h,v.value,c);if(null===y){null===h&&(h=b);break}e&&h&&null===y.alternate&&t(r,h),a=s(y,a,g),null===u?d=y:u.sibling=y,u=y,h=b}if(v.done)return n(r,h),ii&&Jr(r,g),d;if(null===h){for(;!v.done;g++,v=l.next())null!==(v=p(r,v.value,c))&&(a=s(v,a,g),null===u?d=v:u.sibling=v,u=v);return ii&&Jr(r,g),d}for(h=o(r,h);!v.done;g++,v=l.next())null!==(v=m(h,r,g,v.value,c))&&(e&&null!==v.alternate&&h.delete(null===v.key?g:v.key),a=s(v,a,g),null===u?d=v:u.sibling=v,u=v);return e&&h.forEach((function(e){return t(r,e)})),ii&&Jr(r,g),d}return function e(o,i,s,l){if("object"==typeof s&&null!==s&&s.type===_&&null===s.key&&(s=s.props.children),"object"==typeof s&&null!==s){switch(s.$$typeof){case k:e:{for(var c=s.key,d=i;null!==d;){if(d.key===c){if((c=s.type)===_){if(7===d.tag){n(o,d.sibling),(i=r(d,s.props.children)).return=o,o=i;break e}}else if(d.elementType===c||"object"==typeof c&&null!==c&&c.$$typeof===N&&yi(c)===d.type){n(o,d.sibling),(i=r(d,s.props)).ref=bi(o,d,s),i.return=o,o=i;break e}n(o,d);break}t(o,d),d=d.sibling}s.type===_?((i=Oc(s.props.children,o.mode,l,s.key)).return=o,o=i):((l=Pc(s.type,s.key,s.props,null,o.mode,l)).ref=bi(o,i,s),l.return=o,o=l)}return a(o);case x:e:{for(d=s.key;null!==i;){if(i.key===d){if(4===i.tag&&i.stateNode.containerInfo===s.containerInfo&&i.stateNode.implementation===s.implementation){n(o,i.sibling),(i=r(i,s.children||[])).return=o,o=i;break e}n(o,i);break}t(o,i),i=i.sibling}(i=Fc(s,o.mode,l)).return=o,o=i}return a(o);case N:return e(o,i,(d=s._init)(s._payload),l)}if(te(s))return h(o,i,s,l);if(O(s))return g(o,i,s,l);vi(o,s)}return"string"==typeof s&&""!==s||"number"==typeof s?(s=""+s,null!==i&&6===i.tag?(n(o,i.sibling),(i=r(i,s)).return=o,o=i):(n(o,i),(i=Mc(s,o.mode,l)).return=o,o=i),a(o)):n(o,i)}}var ki=wi(!0),xi=wi(!1),_i=Ar(null),Si=null,Ai=null,Ci=null;function Ei(){Ci=Ai=Si=null}function Ti(e){var t=_i.current;Cr(_i),e._currentValue=t}function Di(e,t,n){for(;null!==e;){var o=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,null!==o&&(o.childLanes|=t)):null!==o&&(o.childLanes&t)!==t&&(o.childLanes|=t),e===n)break;e=e.return}}function Li(e,t){Si=e,Ci=Ai=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(!!(e.lanes&t)&&(ya=!0),e.firstContext=null)}function Ri(e){var t=e._currentValue;if(Ci!==e)if(e={context:e,memoizedValue:t,next:null},null===Ai){if(null===Si)throw Error(i(308));Ai=e,Si.dependencies={lanes:0,firstContext:e}}else Ai=Ai.next=e;return t}var Ni=null;function ji(e){null===Ni?Ni=[e]:Ni.push(e)}function Pi(e,t,n,o){var r=t.interleaved;return null===r?(n.next=n,ji(t)):(n.next=r.next,r.next=n),t.interleaved=n,Oi(e,o)}function Oi(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}var Ii=!1;function Mi(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Fi(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Bi(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function Ui(e,t,n){var o=e.updateQueue;if(null===o)return null;if(o=o.shared,2&Tl){var r=o.pending;return null===r?t.next=t:(t.next=r.next,r.next=t),o.pending=t,Oi(e,n)}return null===(r=o.interleaved)?(t.next=t,ji(o)):(t.next=r.next,r.next=t),o.interleaved=t,Oi(e,n)}function zi(e,t,n){if(null!==(t=t.updateQueue)&&(t=t.shared,4194240&n)){var o=t.lanes;n|=o&=e.pendingLanes,t.lanes=n,vt(e,n)}}function $i(e,t){var n=e.updateQueue,o=e.alternate;if(null!==o&&n===(o=o.updateQueue)){var r=null,i=null;if(null!==(n=n.firstBaseUpdate)){do{var s={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===i?r=i=s:i=i.next=s,n=n.next}while(null!==n);null===i?r=i=t:i=i.next=t}else r=i=t;return n={baseState:o.baseState,firstBaseUpdate:r,lastBaseUpdate:i,shared:o.shared,effects:o.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Vi(e,t,n,o){var r=e.updateQueue;Ii=!1;var i=r.firstBaseUpdate,s=r.lastBaseUpdate,a=r.shared.pending;if(null!==a){r.shared.pending=null;var l=a,c=l.next;l.next=null,null===s?i=c:s.next=c,s=l;var d=e.alternate;null!==d&&((a=(d=d.updateQueue).lastBaseUpdate)!==s&&(null===a?d.firstBaseUpdate=c:a.next=c,d.lastBaseUpdate=l))}if(null!==i){var u=r.baseState;for(s=0,d=c=l=null,a=i;;){var p=a.lane,f=a.eventTime;if((o&p)===p){null!==d&&(d=d.next={eventTime:f,lane:0,tag:a.tag,payload:a.payload,callback:a.callback,next:null});e:{var m=e,h=a;switch(p=t,f=n,h.tag){case 1:if("function"==typeof(m=h.payload)){u=m.call(f,u,p);break e}u=m;break e;case 3:m.flags=-65537&m.flags|128;case 0:if(null==(p="function"==typeof(m=h.payload)?m.call(f,u,p):m))break e;u=M({},u,p);break e;case 2:Ii=!0}}null!==a.callback&&0!==a.lane&&(e.flags|=64,null===(p=r.effects)?r.effects=[a]:p.push(a))}else f={eventTime:f,lane:p,tag:a.tag,payload:a.payload,callback:a.callback,next:null},null===d?(c=d=f,l=u):d=d.next=f,s|=p;if(null===(a=a.next)){if(null===(a=r.shared.pending))break;a=(p=a).next,p.next=null,r.lastBaseUpdate=p,r.shared.pending=null}}if(null===d&&(l=u),r.baseState=l,r.firstBaseUpdate=c,r.lastBaseUpdate=d,null!==(t=r.shared.interleaved)){r=t;do{s|=r.lane,r=r.next}while(r!==t)}else null===i&&(r.shared.lanes=0);Il|=s,e.lanes=s,e.memoizedState=u}}function qi(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var o=e[t],r=o.callback;if(null!==r){if(o.callback=null,o=n,"function"!=typeof r)throw Error(i(191,r));r.call(o)}}}var Hi={},Gi=Ar(Hi),Wi=Ar(Hi),Zi=Ar(Hi);function Qi(e){if(e===Hi)throw Error(i(174));return e}function Ki(e,t){switch(Er(Zi,t),Er(Wi,e),Er(Gi,Hi),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:le(null,"");break;default:t=le(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}Cr(Gi),Er(Gi,t)}function Yi(){Cr(Gi),Cr(Wi),Cr(Zi)}function Xi(e){Qi(Zi.current);var t=Qi(Gi.current),n=le(t,e.type);t!==n&&(Er(Wi,e),Er(Gi,n))}function Ji(e){Wi.current===e&&(Cr(Gi),Cr(Wi))}var es=Ar(0);function ts(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(128&t.flags)return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var ns=[];function os(){for(var e=0;e<ns.length;e++)ns[e]._workInProgressVersionPrimary=null;ns.length=0}var rs=w.ReactCurrentDispatcher,is=w.ReactCurrentBatchConfig,ss=0,as=null,ls=null,cs=null,ds=!1,us=!1,ps=0,fs=0;function ms(){throw Error(i(321))}function hs(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!ao(e[n],t[n]))return!1;return!0}function gs(e,t,n,o,r,s){if(ss=s,as=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,rs.current=null===e||null===e.memoizedState?Js:ea,e=n(o,r),us){s=0;do{if(us=!1,ps=0,25<=s)throw Error(i(301));s+=1,cs=ls=null,t.updateQueue=null,rs.current=ta,e=n(o,r)}while(us)}if(rs.current=Xs,t=null!==ls&&null!==ls.next,ss=0,cs=ls=as=null,ds=!1,t)throw Error(i(300));return e}function bs(){var e=0!==ps;return ps=0,e}function vs(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===cs?as.memoizedState=cs=e:cs=cs.next=e,cs}function ys(){if(null===ls){var e=as.alternate;e=null!==e?e.memoizedState:null}else e=ls.next;var t=null===cs?as.memoizedState:cs.next;if(null!==t)cs=t,ls=e;else{if(null===e)throw Error(i(310));e={memoizedState:(ls=e).memoizedState,baseState:ls.baseState,baseQueue:ls.baseQueue,queue:ls.queue,next:null},null===cs?as.memoizedState=cs=e:cs=cs.next=e}return cs}function ws(e,t){return"function"==typeof t?t(e):t}function ks(e){var t=ys(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var o=ls,r=o.baseQueue,s=n.pending;if(null!==s){if(null!==r){var a=r.next;r.next=s.next,s.next=a}o.baseQueue=r=s,n.pending=null}if(null!==r){s=r.next,o=o.baseState;var l=a=null,c=null,d=s;do{var u=d.lane;if((ss&u)===u)null!==c&&(c=c.next={lane:0,action:d.action,hasEagerState:d.hasEagerState,eagerState:d.eagerState,next:null}),o=d.hasEagerState?d.eagerState:e(o,d.action);else{var p={lane:u,action:d.action,hasEagerState:d.hasEagerState,eagerState:d.eagerState,next:null};null===c?(l=c=p,a=o):c=c.next=p,as.lanes|=u,Il|=u}d=d.next}while(null!==d&&d!==s);null===c?a=o:c.next=l,ao(o,t.memoizedState)||(ya=!0),t.memoizedState=o,t.baseState=a,t.baseQueue=c,n.lastRenderedState=o}if(null!==(e=n.interleaved)){r=e;do{s=r.lane,as.lanes|=s,Il|=s,r=r.next}while(r!==e)}else null===r&&(n.lanes=0);return[t.memoizedState,n.dispatch]}function xs(e){var t=ys(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var o=n.dispatch,r=n.pending,s=t.memoizedState;if(null!==r){n.pending=null;var a=r=r.next;do{s=e(s,a.action),a=a.next}while(a!==r);ao(s,t.memoizedState)||(ya=!0),t.memoizedState=s,null===t.baseQueue&&(t.baseState=s),n.lastRenderedState=s}return[s,o]}function _s(){}function Ss(e,t){var n=as,o=ys(),r=t(),s=!ao(o.memoizedState,r);if(s&&(o.memoizedState=r,ya=!0),o=o.queue,Is(Es.bind(null,n,o,e),[e]),o.getSnapshot!==t||s||null!==cs&&1&cs.memoizedState.tag){if(n.flags|=2048,Rs(9,Cs.bind(null,n,o,r,t),void 0,null),null===Dl)throw Error(i(349));30&ss||As(n,t,r)}return r}function As(e,t,n){e.flags|=16384,e={getSnapshot:t,value:n},null===(t=as.updateQueue)?(t={lastEffect:null,stores:null},as.updateQueue=t,t.stores=[e]):null===(n=t.stores)?t.stores=[e]:n.push(e)}function Cs(e,t,n,o){t.value=n,t.getSnapshot=o,Ts(t)&&Ds(e)}function Es(e,t,n){return n((function(){Ts(t)&&Ds(e)}))}function Ts(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!ao(e,n)}catch(o){return!0}}function Ds(e){var t=Oi(e,1);null!==t&&nc(t,e,1,-1)}function Ls(e){var t=vs();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:ws,lastRenderedState:e},t.queue=e,e=e.dispatch=Zs.bind(null,as,e),[t.memoizedState,e]}function Rs(e,t,n,o){return e={tag:e,create:t,destroy:n,deps:o,next:null},null===(t=as.updateQueue)?(t={lastEffect:null,stores:null},as.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(o=n.next,n.next=e,e.next=o,t.lastEffect=e),e}function Ns(){return ys().memoizedState}function js(e,t,n,o){var r=vs();as.flags|=e,r.memoizedState=Rs(1|t,n,void 0,void 0===o?null:o)}function Ps(e,t,n,o){var r=ys();o=void 0===o?null:o;var i=void 0;if(null!==ls){var s=ls.memoizedState;if(i=s.destroy,null!==o&&hs(o,s.deps))return void(r.memoizedState=Rs(t,n,i,o))}as.flags|=e,r.memoizedState=Rs(1|t,n,i,o)}function Os(e,t){return js(8390656,8,e,t)}function Is(e,t){return Ps(2048,8,e,t)}function Ms(e,t){return Ps(4,2,e,t)}function Fs(e,t){return Ps(4,4,e,t)}function Bs(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function Us(e,t,n){return n=null!=n?n.concat([e]):null,Ps(4,4,Bs.bind(null,t,e),n)}function zs(){}function $s(e,t){var n=ys();t=void 0===t?null:t;var o=n.memoizedState;return null!==o&&null!==t&&hs(t,o[1])?o[0]:(n.memoizedState=[e,t],e)}function Vs(e,t){var n=ys();t=void 0===t?null:t;var o=n.memoizedState;return null!==o&&null!==t&&hs(t,o[1])?o[0]:(e=e(),n.memoizedState=[e,t],e)}function qs(e,t,n){return 21&ss?(ao(n,t)||(n=ht(),as.lanes|=n,Il|=n,e.baseState=!0),t):(e.baseState&&(e.baseState=!1,ya=!0),e.memoizedState=n)}function Hs(e,t){var n=yt;yt=0!==n&&4>n?n:4,e(!0);var o=is.transition;is.transition={};try{e(!1),t()}finally{yt=n,is.transition=o}}function Gs(){return ys().memoizedState}function Ws(e,t,n){var o=tc(e);if(n={lane:o,action:n,hasEagerState:!1,eagerState:null,next:null},Qs(e))Ks(t,n);else if(null!==(n=Pi(e,t,n,o))){nc(n,e,o,ec()),Ys(n,t,o)}}function Zs(e,t,n){var o=tc(e),r={lane:o,action:n,hasEagerState:!1,eagerState:null,next:null};if(Qs(e))Ks(t,r);else{var i=e.alternate;if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=t.lastRenderedReducer))try{var s=t.lastRenderedState,a=i(s,n);if(r.hasEagerState=!0,r.eagerState=a,ao(a,s)){var l=t.interleaved;return null===l?(r.next=r,ji(t)):(r.next=l.next,l.next=r),void(t.interleaved=r)}}catch(c){}null!==(n=Pi(e,t,r,o))&&(nc(n,e,o,r=ec()),Ys(n,t,o))}}function Qs(e){var t=e.alternate;return e===as||null!==t&&t===as}function Ks(e,t){us=ds=!0;var n=e.pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Ys(e,t,n){if(4194240&n){var o=t.lanes;n|=o&=e.pendingLanes,t.lanes=n,vt(e,n)}}var Xs={readContext:Ri,useCallback:ms,useContext:ms,useEffect:ms,useImperativeHandle:ms,useInsertionEffect:ms,useLayoutEffect:ms,useMemo:ms,useReducer:ms,useRef:ms,useState:ms,useDebugValue:ms,useDeferredValue:ms,useTransition:ms,useMutableSource:ms,useSyncExternalStore:ms,useId:ms,unstable_isNewReconciler:!1},Js={readContext:Ri,useCallback:function(e,t){return vs().memoizedState=[e,void 0===t?null:t],e},useContext:Ri,useEffect:Os,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,js(4194308,4,Bs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return js(4194308,4,e,t)},useInsertionEffect:function(e,t){return js(4,2,e,t)},useMemo:function(e,t){var n=vs();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var o=vs();return t=void 0!==n?n(t):t,o.memoizedState=o.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},o.queue=e,e=e.dispatch=Ws.bind(null,as,e),[o.memoizedState,e]},useRef:function(e){return e={current:e},vs().memoizedState=e},useState:Ls,useDebugValue:zs,useDeferredValue:function(e){return vs().memoizedState=e},useTransition:function(){var e=Ls(!1),t=e[0];return e=Hs.bind(null,e[1]),vs().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var o=as,r=vs();if(ii){if(void 0===n)throw Error(i(407));n=n()}else{if(n=t(),null===Dl)throw Error(i(349));30&ss||As(o,t,n)}r.memoizedState=n;var s={value:n,getSnapshot:t};return r.queue=s,Os(Es.bind(null,o,s,e),[e]),o.flags|=2048,Rs(9,Cs.bind(null,o,s,n,t),void 0,null),n},useId:function(){var e=vs(),t=Dl.identifierPrefix;if(ii){var n=Xr;t=":"+t+"R"+(n=(Yr&~(1<<32-st(Yr)-1)).toString(32)+n),0<(n=ps++)&&(t+="H"+n.toString(32)),t+=":"}else t=":"+t+"r"+(n=fs++).toString(32)+":";return e.memoizedState=t},unstable_isNewReconciler:!1},ea={readContext:Ri,useCallback:$s,useContext:Ri,useEffect:Is,useImperativeHandle:Us,useInsertionEffect:Ms,useLayoutEffect:Fs,useMemo:Vs,useReducer:ks,useRef:Ns,useState:function(){return ks(ws)},useDebugValue:zs,useDeferredValue:function(e){return qs(ys(),ls.memoizedState,e)},useTransition:function(){return[ks(ws)[0],ys().memoizedState]},useMutableSource:_s,useSyncExternalStore:Ss,useId:Gs,unstable_isNewReconciler:!1},ta={readContext:Ri,useCallback:$s,useContext:Ri,useEffect:Is,useImperativeHandle:Us,useInsertionEffect:Ms,useLayoutEffect:Fs,useMemo:Vs,useReducer:xs,useRef:Ns,useState:function(){return xs(ws)},useDebugValue:zs,useDeferredValue:function(e){var t=ys();return null===ls?t.memoizedState=e:qs(t,ls.memoizedState,e)},useTransition:function(){return[xs(ws)[0],ys().memoizedState]},useMutableSource:_s,useSyncExternalStore:Ss,useId:Gs,unstable_isNewReconciler:!1};function na(e,t){if(e&&e.defaultProps){for(var n in t=M({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}function oa(e,t,n,o){n=null==(n=n(o,t=e.memoizedState))?t:M({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var ra={isMounted:function(e){return!!(e=e._reactInternals)&&$e(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var o=ec(),r=tc(e),i=Bi(o,r);i.payload=t,null!=n&&(i.callback=n),null!==(t=Ui(e,i,r))&&(nc(t,e,r,o),zi(t,e,r))},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var o=ec(),r=tc(e),i=Bi(o,r);i.tag=1,i.payload=t,null!=n&&(i.callback=n),null!==(t=Ui(e,i,r))&&(nc(t,e,r,o),zi(t,e,r))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=ec(),o=tc(e),r=Bi(n,o);r.tag=2,null!=t&&(r.callback=t),null!==(t=Ui(e,r,o))&&(nc(t,e,o,n),zi(t,e,o))}};function ia(e,t,n,o,r,i,s){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(o,i,s):!t.prototype||!t.prototype.isPureReactComponent||(!lo(n,o)||!lo(r,i))}function sa(e,t,n){var o=!1,r=Tr,i=t.contextType;return"object"==typeof i&&null!==i?i=Ri(i):(r=jr(t)?Rr:Dr.current,i=(o=null!=(o=t.contextTypes))?Nr(e,r):Tr),t=new t(n,i),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=ra,e.stateNode=t,t._reactInternals=e,o&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=r,e.__reactInternalMemoizedMaskedChildContext=i),t}function aa(e,t,n,o){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,o),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,o),t.state!==e&&ra.enqueueReplaceState(t,t.state,null)}function la(e,t,n,o){var r=e.stateNode;r.props=n,r.state=e.memoizedState,r.refs={},Mi(e);var i=t.contextType;"object"==typeof i&&null!==i?r.context=Ri(i):(i=jr(t)?Rr:Dr.current,r.context=Nr(e,i)),r.state=e.memoizedState,"function"==typeof(i=t.getDerivedStateFromProps)&&(oa(e,t,i,n),r.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof r.getSnapshotBeforeUpdate||"function"!=typeof r.UNSAFE_componentWillMount&&"function"!=typeof r.componentWillMount||(t=r.state,"function"==typeof r.componentWillMount&&r.componentWillMount(),"function"==typeof r.UNSAFE_componentWillMount&&r.UNSAFE_componentWillMount(),t!==r.state&&ra.enqueueReplaceState(r,r.state,null),Vi(e,n,r,o),r.state=e.memoizedState),"function"==typeof r.componentDidMount&&(e.flags|=4194308)}function ca(e,t){try{var n="",o=t;do{n+=z(o),o=o.return}while(o);var r=n}catch(i){r="\nError generating stack: "+i.message+"\n"+i.stack}return{value:e,source:t,stack:r,digest:null}}function da(e,t,n){return{value:e,source:null,stack:null!=n?n:null,digest:null!=t?t:null}}function ua(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}var pa="function"==typeof WeakMap?WeakMap:Map;function fa(e,t,n){(n=Bi(-1,n)).tag=3,n.payload={element:null};var o=t.value;return n.callback=function(){ql||(ql=!0,Hl=o),ua(0,t)},n}function ma(e,t,n){(n=Bi(-1,n)).tag=3;var o=e.type.getDerivedStateFromError;if("function"==typeof o){var r=t.value;n.payload=function(){return o(r)},n.callback=function(){ua(0,t)}}var i=e.stateNode;return null!==i&&"function"==typeof i.componentDidCatch&&(n.callback=function(){ua(0,t),"function"!=typeof o&&(null===Gl?Gl=new Set([this]):Gl.add(this));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}function ha(e,t,n){var o=e.pingCache;if(null===o){o=e.pingCache=new pa;var r=new Set;o.set(t,r)}else void 0===(r=o.get(t))&&(r=new Set,o.set(t,r));r.has(n)||(r.add(n),e=Ac.bind(null,e,t,n),t.then(e,e))}function ga(e){do{var t;if((t=13===e.tag)&&(t=null===(t=e.memoizedState)||null!==t.dehydrated),t)return e;e=e.return}while(null!==e);return null}function ba(e,t,n,o,r){return 1&e.mode?(e.flags|=65536,e.lanes=r,e):(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,1===n.tag&&(null===n.alternate?n.tag=17:((t=Bi(-1,1)).tag=2,Ui(n,t,1))),n.lanes|=1),e)}var va=w.ReactCurrentOwner,ya=!1;function wa(e,t,n,o){t.child=null===e?xi(t,null,n,o):ki(t,e.child,n,o)}function ka(e,t,n,o,r){n=n.render;var i=t.ref;return Li(t,r),o=gs(e,t,n,o,i,r),n=bs(),null===e||ya?(ii&&n&&ti(t),t.flags|=1,wa(e,t,o,r),t.child):(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~r,qa(e,t,r))}function xa(e,t,n,o,r){if(null===e){var i=n.type;return"function"!=typeof i||Nc(i)||void 0!==i.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Pc(n.type,null,o,t,t.mode,r)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=i,_a(e,t,i,o,r))}if(i=e.child,!(e.lanes&r)){var s=i.memoizedProps;if((n=null!==(n=n.compare)?n:lo)(s,o)&&e.ref===t.ref)return qa(e,t,r)}return t.flags|=1,(e=jc(i,o)).ref=t.ref,e.return=t,t.child=e}function _a(e,t,n,o,r){if(null!==e){var i=e.memoizedProps;if(lo(i,o)&&e.ref===t.ref){if(ya=!1,t.pendingProps=o=i,!(e.lanes&r))return t.lanes=e.lanes,qa(e,t,r);131072&e.flags&&(ya=!0)}}return Ca(e,t,n,o,r)}function Sa(e,t,n){var o=t.pendingProps,r=o.children,i=null!==e?e.memoizedState:null;if("hidden"===o.mode)if(1&t.mode){if(!(1073741824&n))return e=null!==i?i.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,Er(jl,Nl),Nl|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},o=null!==i?i.baseLanes:n,Er(jl,Nl),Nl|=o}else t.memoizedState={baseLanes:0,cachePool:null,transitions:null},Er(jl,Nl),Nl|=n;else null!==i?(o=i.baseLanes|n,t.memoizedState=null):o=n,Er(jl,Nl),Nl|=o;return wa(e,t,r,n),t.child}function Aa(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}function Ca(e,t,n,o,r){var i=jr(n)?Rr:Dr.current;return i=Nr(t,i),Li(t,r),n=gs(e,t,n,o,i,r),o=bs(),null===e||ya?(ii&&o&&ti(t),t.flags|=1,wa(e,t,n,r),t.child):(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~r,qa(e,t,r))}function Ea(e,t,n,o,r){if(jr(n)){var i=!0;Mr(t)}else i=!1;if(Li(t,r),null===t.stateNode)Va(e,t),sa(t,n,o),la(t,n,o,r),o=!0;else if(null===e){var s=t.stateNode,a=t.memoizedProps;s.props=a;var l=s.context,c=n.contextType;"object"==typeof c&&null!==c?c=Ri(c):c=Nr(t,c=jr(n)?Rr:Dr.current);var d=n.getDerivedStateFromProps,u="function"==typeof d||"function"==typeof s.getSnapshotBeforeUpdate;u||"function"!=typeof s.UNSAFE_componentWillReceiveProps&&"function"!=typeof s.componentWillReceiveProps||(a!==o||l!==c)&&aa(t,s,o,c),Ii=!1;var p=t.memoizedState;s.state=p,Vi(t,o,s,r),l=t.memoizedState,a!==o||p!==l||Lr.current||Ii?("function"==typeof d&&(oa(t,n,d,o),l=t.memoizedState),(a=Ii||ia(t,n,a,o,p,l,c))?(u||"function"!=typeof s.UNSAFE_componentWillMount&&"function"!=typeof s.componentWillMount||("function"==typeof s.componentWillMount&&s.componentWillMount(),"function"==typeof s.UNSAFE_componentWillMount&&s.UNSAFE_componentWillMount()),"function"==typeof s.componentDidMount&&(t.flags|=4194308)):("function"==typeof s.componentDidMount&&(t.flags|=4194308),t.memoizedProps=o,t.memoizedState=l),s.props=o,s.state=l,s.context=c,o=a):("function"==typeof s.componentDidMount&&(t.flags|=4194308),o=!1)}else{s=t.stateNode,Fi(e,t),a=t.memoizedProps,c=t.type===t.elementType?a:na(t.type,a),s.props=c,u=t.pendingProps,p=s.context,"object"==typeof(l=n.contextType)&&null!==l?l=Ri(l):l=Nr(t,l=jr(n)?Rr:Dr.current);var f=n.getDerivedStateFromProps;(d="function"==typeof f||"function"==typeof s.getSnapshotBeforeUpdate)||"function"!=typeof s.UNSAFE_componentWillReceiveProps&&"function"!=typeof s.componentWillReceiveProps||(a!==u||p!==l)&&aa(t,s,o,l),Ii=!1,p=t.memoizedState,s.state=p,Vi(t,o,s,r);var m=t.memoizedState;a!==u||p!==m||Lr.current||Ii?("function"==typeof f&&(oa(t,n,f,o),m=t.memoizedState),(c=Ii||ia(t,n,c,o,p,m,l)||!1)?(d||"function"!=typeof s.UNSAFE_componentWillUpdate&&"function"!=typeof s.componentWillUpdate||("function"==typeof s.componentWillUpdate&&s.componentWillUpdate(o,m,l),"function"==typeof s.UNSAFE_componentWillUpdate&&s.UNSAFE_componentWillUpdate(o,m,l)),"function"==typeof s.componentDidUpdate&&(t.flags|=4),"function"==typeof s.getSnapshotBeforeUpdate&&(t.flags|=1024)):("function"!=typeof s.componentDidUpdate||a===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof s.getSnapshotBeforeUpdate||a===e.memoizedProps&&p===e.memoizedState||(t.flags|=1024),t.memoizedProps=o,t.memoizedState=m),s.props=o,s.state=m,s.context=l,o=c):("function"!=typeof s.componentDidUpdate||a===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),"function"!=typeof s.getSnapshotBeforeUpdate||a===e.memoizedProps&&p===e.memoizedState||(t.flags|=1024),o=!1)}return Ta(e,t,n,o,i,r)}function Ta(e,t,n,o,r,i){Aa(e,t);var s=!!(128&t.flags);if(!o&&!s)return r&&Fr(t,n,!1),qa(e,t,i);o=t.stateNode,va.current=t;var a=s&&"function"!=typeof n.getDerivedStateFromError?null:o.render();return t.flags|=1,null!==e&&s?(t.child=ki(t,e.child,null,i),t.child=ki(t,null,a,i)):wa(e,t,a,i),t.memoizedState=o.state,r&&Fr(t,n,!0),t.child}function Da(e){var t=e.stateNode;t.pendingContext?Or(0,t.pendingContext,t.pendingContext!==t.context):t.context&&Or(0,t.context,!1),Ki(e,t.containerInfo)}function La(e,t,n,o,r){return mi(),hi(r),t.flags|=256,wa(e,t,n,o),t.child}var Ra,Na,ja,Pa,Oa={dehydrated:null,treeContext:null,retryLane:0};function Ia(e){return{baseLanes:e,cachePool:null,transitions:null}}function Ma(e,t,n){var o,r=t.pendingProps,s=es.current,a=!1,l=!!(128&t.flags);if((o=l)||(o=(null===e||null!==e.memoizedState)&&!!(2&s)),o?(a=!0,t.flags&=-129):null!==e&&null===e.memoizedState||(s|=1),Er(es,1&s),null===e)return di(t),null!==(e=t.memoizedState)&&null!==(e=e.dehydrated)?(1&t.mode?"$!"===e.data?t.lanes=8:t.lanes=1073741824:t.lanes=1,null):(l=r.children,e=r.fallback,a?(r=t.mode,a=t.child,l={mode:"hidden",children:l},1&r||null===a?a=Ic(l,r,0,null):(a.childLanes=0,a.pendingProps=l),e=Oc(e,r,n,null),a.return=t,e.return=t,a.sibling=e,t.child=a,t.child.memoizedState=Ia(n),t.memoizedState=Oa,e):Fa(t,l));if(null!==(s=e.memoizedState)&&null!==(o=s.dehydrated))return function(e,t,n,o,r,s,a){if(n)return 256&t.flags?(t.flags&=-257,Ba(e,t,a,o=da(Error(i(422))))):null!==t.memoizedState?(t.child=e.child,t.flags|=128,null):(s=o.fallback,r=t.mode,o=Ic({mode:"visible",children:o.children},r,0,null),(s=Oc(s,r,a,null)).flags|=2,o.return=t,s.return=t,o.sibling=s,t.child=o,1&t.mode&&ki(t,e.child,null,a),t.child.memoizedState=Ia(a),t.memoizedState=Oa,s);if(!(1&t.mode))return Ba(e,t,a,null);if("$!"===r.data){if(o=r.nextSibling&&r.nextSibling.dataset)var l=o.dgst;return o=l,Ba(e,t,a,o=da(s=Error(i(419)),o,void 0))}if(l=!!(a&e.childLanes),ya||l){if(null!==(o=Dl)){switch(a&-a){case 4:r=2;break;case 16:r=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:r=32;break;case 536870912:r=268435456;break;default:r=0}0!==(r=r&(o.suspendedLanes|a)?0:r)&&r!==s.retryLane&&(s.retryLane=r,Oi(e,r),nc(o,e,r,-1))}return hc(),Ba(e,t,a,o=da(Error(i(421))))}return"$?"===r.data?(t.flags|=128,t.child=e.child,t=Ec.bind(null,e),r._reactRetry=t,null):(e=s.treeContext,ri=dr(r.nextSibling),oi=t,ii=!0,si=null,null!==e&&(Zr[Qr++]=Yr,Zr[Qr++]=Xr,Zr[Qr++]=Kr,Yr=e.id,Xr=e.overflow,Kr=t),t=Fa(t,o.children),t.flags|=4096,t)}(e,t,l,r,o,s,n);if(a){a=r.fallback,l=t.mode,o=(s=e.child).sibling;var c={mode:"hidden",children:r.children};return 1&l||t.child===s?(r=jc(s,c)).subtreeFlags=14680064&s.subtreeFlags:((r=t.child).childLanes=0,r.pendingProps=c,t.deletions=null),null!==o?a=jc(o,a):(a=Oc(a,l,n,null)).flags|=2,a.return=t,r.return=t,r.sibling=a,t.child=r,r=a,a=t.child,l=null===(l=e.child.memoizedState)?Ia(n):{baseLanes:l.baseLanes|n,cachePool:null,transitions:l.transitions},a.memoizedState=l,a.childLanes=e.childLanes&~n,t.memoizedState=Oa,r}return e=(a=e.child).sibling,r=jc(a,{mode:"visible",children:r.children}),!(1&t.mode)&&(r.lanes=n),r.return=t,r.sibling=null,null!==e&&(null===(n=t.deletions)?(t.deletions=[e],t.flags|=16):n.push(e)),t.child=r,t.memoizedState=null,r}function Fa(e,t){return(t=Ic({mode:"visible",children:t},e.mode,0,null)).return=e,e.child=t}function Ba(e,t,n,o){return null!==o&&hi(o),ki(t,e.child,null,n),(e=Fa(t,t.pendingProps.children)).flags|=2,t.memoizedState=null,e}function Ua(e,t,n){e.lanes|=t;var o=e.alternate;null!==o&&(o.lanes|=t),Di(e.return,t,n)}function za(e,t,n,o,r){var i=e.memoizedState;null===i?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:o,tail:n,tailMode:r}:(i.isBackwards=t,i.rendering=null,i.renderingStartTime=0,i.last=o,i.tail=n,i.tailMode=r)}function $a(e,t,n){var o=t.pendingProps,r=o.revealOrder,i=o.tail;if(wa(e,t,o.children,n),2&(o=es.current))o=1&o|2,t.flags|=128;else{if(null!==e&&128&e.flags)e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&Ua(e,n,t);else if(19===e.tag)Ua(e,n,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}o&=1}if(Er(es,o),1&t.mode)switch(r){case"forwards":for(n=t.child,r=null;null!==n;)null!==(e=n.alternate)&&null===ts(e)&&(r=n),n=n.sibling;null===(n=r)?(r=t.child,t.child=null):(r=n.sibling,n.sibling=null),za(t,!1,r,n,i);break;case"backwards":for(n=null,r=t.child,t.child=null;null!==r;){if(null!==(e=r.alternate)&&null===ts(e)){t.child=r;break}e=r.sibling,r.sibling=n,n=r,r=e}za(t,!0,n,null,i);break;case"together":za(t,!1,null,null,void 0);break;default:t.memoizedState=null}else t.memoizedState=null;return t.child}function Va(e,t){!(1&t.mode)&&null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2)}function qa(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),Il|=t.lanes,!(n&t.childLanes))return null;if(null!==e&&t.child!==e.child)throw Error(i(153));if(null!==t.child){for(n=jc(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=jc(e,e.pendingProps)).return=t;n.sibling=null}return t.child}function Ha(e,t){if(!ii)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var o=null;null!==n;)null!==n.alternate&&(o=n),n=n.sibling;null===o?t||null===e.tail?e.tail=null:e.tail.sibling=null:o.sibling=null}}function Ga(e){var t=null!==e.alternate&&e.alternate.child===e.child,n=0,o=0;if(t)for(var r=e.child;null!==r;)n|=r.lanes|r.childLanes,o|=14680064&r.subtreeFlags,o|=14680064&r.flags,r.return=e,r=r.sibling;else for(r=e.child;null!==r;)n|=r.lanes|r.childLanes,o|=r.subtreeFlags,o|=r.flags,r.return=e,r=r.sibling;return e.subtreeFlags|=o,e.childLanes=n,t}function Wa(e,t,n){var o=t.pendingProps;switch(ni(t),t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Ga(t),null;case 1:case 17:return jr(t.type)&&Pr(),Ga(t),null;case 3:return o=t.stateNode,Yi(),Cr(Lr),Cr(Dr),os(),o.pendingContext&&(o.context=o.pendingContext,o.pendingContext=null),null!==e&&null!==e.child||(pi(t)?t.flags|=4:null===e||e.memoizedState.isDehydrated&&!(256&t.flags)||(t.flags|=1024,null!==si&&(sc(si),si=null))),Na(e,t),Ga(t),null;case 5:Ji(t);var r=Qi(Zi.current);if(n=t.type,null!==e&&null!=t.stateNode)ja(e,t,n,o,r),e.ref!==t.ref&&(t.flags|=512,t.flags|=2097152);else{if(!o){if(null===t.stateNode)throw Error(i(166));return Ga(t),null}if(e=Qi(Gi.current),pi(t)){o=t.stateNode,n=t.type;var s=t.memoizedProps;switch(o[fr]=t,o[mr]=s,e=!!(1&t.mode),n){case"dialog":Uo("cancel",o),Uo("close",o);break;case"iframe":case"object":case"embed":Uo("load",o);break;case"video":case"audio":for(r=0;r<Io.length;r++)Uo(Io[r],o);break;case"source":Uo("error",o);break;case"img":case"image":case"link":Uo("error",o),Uo("load",o);break;case"details":Uo("toggle",o);break;case"input":K(o,s),Uo("invalid",o);break;case"select":o._wrapperState={wasMultiple:!!s.multiple},Uo("invalid",o);break;case"textarea":re(o,s),Uo("invalid",o)}for(var l in ve(n,s),r=null,s)if(s.hasOwnProperty(l)){var c=s[l];"children"===l?"string"==typeof c?o.textContent!==c&&(!0!==s.suppressHydrationWarning&&Jo(o.textContent,c,e),r=["children",c]):"number"==typeof c&&o.textContent!==""+c&&(!0!==s.suppressHydrationWarning&&Jo(o.textContent,c,e),r=["children",""+c]):a.hasOwnProperty(l)&&null!=c&&"onScroll"===l&&Uo("scroll",o)}switch(n){case"input":G(o),J(o,s,!0);break;case"textarea":G(o),se(o);break;case"select":case"option":break;default:"function"==typeof s.onClick&&(o.onclick=er)}o=r,t.updateQueue=o,null!==o&&(t.flags|=4)}else{l=9===r.nodeType?r:r.ownerDocument,"http://www.w3.org/1999/xhtml"===e&&(e=ae(n)),"http://www.w3.org/1999/xhtml"===e?"script"===n?((e=l.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof o.is?e=l.createElement(n,{is:o.is}):(e=l.createElement(n),"select"===n&&(l=e,o.multiple?l.multiple=!0:o.size&&(l.size=o.size))):e=l.createElementNS(e,n),e[fr]=t,e[mr]=o,Ra(e,t,!1,!1),t.stateNode=e;e:{switch(l=ye(n,o),n){case"dialog":Uo("cancel",e),Uo("close",e),r=o;break;case"iframe":case"object":case"embed":Uo("load",e),r=o;break;case"video":case"audio":for(r=0;r<Io.length;r++)Uo(Io[r],e);r=o;break;case"source":Uo("error",e),r=o;break;case"img":case"image":case"link":Uo("error",e),Uo("load",e),r=o;break;case"details":Uo("toggle",e),r=o;break;case"input":K(e,o),r=Q(e,o),Uo("invalid",e);break;case"option":default:r=o;break;case"select":e._wrapperState={wasMultiple:!!o.multiple},r=M({},o,{value:void 0}),Uo("invalid",e);break;case"textarea":re(e,o),r=oe(e,o),Uo("invalid",e)}for(s in ve(n,r),c=r)if(c.hasOwnProperty(s)){var d=c[s];"style"===s?ge(e,d):"dangerouslySetInnerHTML"===s?null!=(d=d?d.__html:void 0)&&ue(e,d):"children"===s?"string"==typeof d?("textarea"!==n||""!==d)&&pe(e,d):"number"==typeof d&&pe(e,""+d):"suppressContentEditableWarning"!==s&&"suppressHydrationWarning"!==s&&"autoFocus"!==s&&(a.hasOwnProperty(s)?null!=d&&"onScroll"===s&&Uo("scroll",e):null!=d&&y(e,s,d,l))}switch(n){case"input":G(e),J(e,o,!1);break;case"textarea":G(e),se(e);break;case"option":null!=o.value&&e.setAttribute("value",""+q(o.value));break;case"select":e.multiple=!!o.multiple,null!=(s=o.value)?ne(e,!!o.multiple,s,!1):null!=o.defaultValue&&ne(e,!!o.multiple,o.defaultValue,!0);break;default:"function"==typeof r.onClick&&(e.onclick=er)}switch(n){case"button":case"input":case"select":case"textarea":o=!!o.autoFocus;break e;case"img":o=!0;break e;default:o=!1}}o&&(t.flags|=4)}null!==t.ref&&(t.flags|=512,t.flags|=2097152)}return Ga(t),null;case 6:if(e&&null!=t.stateNode)Pa(e,t,e.memoizedProps,o);else{if("string"!=typeof o&&null===t.stateNode)throw Error(i(166));if(n=Qi(Zi.current),Qi(Gi.current),pi(t)){if(o=t.stateNode,n=t.memoizedProps,o[fr]=t,(s=o.nodeValue!==n)&&null!==(e=oi))switch(e.tag){case 3:Jo(o.nodeValue,n,!!(1&e.mode));break;case 5:!0!==e.memoizedProps.suppressHydrationWarning&&Jo(o.nodeValue,n,!!(1&e.mode))}s&&(t.flags|=4)}else(o=(9===n.nodeType?n:n.ownerDocument).createTextNode(o))[fr]=t,t.stateNode=o}return Ga(t),null;case 13:if(Cr(es),o=t.memoizedState,null===e||null!==e.memoizedState&&null!==e.memoizedState.dehydrated){if(ii&&null!==ri&&1&t.mode&&!(128&t.flags))fi(),mi(),t.flags|=98560,s=!1;else if(s=pi(t),null!==o&&null!==o.dehydrated){if(null===e){if(!s)throw Error(i(318));if(!(s=null!==(s=t.memoizedState)?s.dehydrated:null))throw Error(i(317));s[fr]=t}else mi(),!(128&t.flags)&&(t.memoizedState=null),t.flags|=4;Ga(t),s=!1}else null!==si&&(sc(si),si=null),s=!0;if(!s)return 65536&t.flags?t:null}return 128&t.flags?(t.lanes=n,t):((o=null!==o)!==(null!==e&&null!==e.memoizedState)&&o&&(t.child.flags|=8192,1&t.mode&&(null===e||1&es.current?0===Pl&&(Pl=3):hc())),null!==t.updateQueue&&(t.flags|=4),Ga(t),null);case 4:return Yi(),Na(e,t),null===e&&Vo(t.stateNode.containerInfo),Ga(t),null;case 10:return Ti(t.type._context),Ga(t),null;case 19:if(Cr(es),null===(s=t.memoizedState))return Ga(t),null;if(o=!!(128&t.flags),null===(l=s.rendering))if(o)Ha(s,!1);else{if(0!==Pl||null!==e&&128&e.flags)for(e=t.child;null!==e;){if(null!==(l=ts(e))){for(t.flags|=128,Ha(s,!1),null!==(o=l.updateQueue)&&(t.updateQueue=o,t.flags|=4),t.subtreeFlags=0,o=n,n=t.child;null!==n;)e=o,(s=n).flags&=14680066,null===(l=s.alternate)?(s.childLanes=0,s.lanes=e,s.child=null,s.subtreeFlags=0,s.memoizedProps=null,s.memoizedState=null,s.updateQueue=null,s.dependencies=null,s.stateNode=null):(s.childLanes=l.childLanes,s.lanes=l.lanes,s.child=l.child,s.subtreeFlags=0,s.deletions=null,s.memoizedProps=l.memoizedProps,s.memoizedState=l.memoizedState,s.updateQueue=l.updateQueue,s.type=l.type,e=l.dependencies,s.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return Er(es,1&es.current|2),t.child}e=e.sibling}null!==s.tail&&Ye()>$l&&(t.flags|=128,o=!0,Ha(s,!1),t.lanes=4194304)}else{if(!o)if(null!==(e=ts(l))){if(t.flags|=128,o=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),Ha(s,!0),null===s.tail&&"hidden"===s.tailMode&&!l.alternate&&!ii)return Ga(t),null}else 2*Ye()-s.renderingStartTime>$l&&1073741824!==n&&(t.flags|=128,o=!0,Ha(s,!1),t.lanes=4194304);s.isBackwards?(l.sibling=t.child,t.child=l):(null!==(n=s.last)?n.sibling=l:t.child=l,s.last=l)}return null!==s.tail?(t=s.tail,s.rendering=t,s.tail=t.sibling,s.renderingStartTime=Ye(),t.sibling=null,n=es.current,Er(es,o?1&n|2:1&n),t):(Ga(t),null);case 22:case 23:return uc(),o=null!==t.memoizedState,null!==e&&null!==e.memoizedState!==o&&(t.flags|=8192),o&&1&t.mode?!!(1073741824&Nl)&&(Ga(t),6&t.subtreeFlags&&(t.flags|=8192)):Ga(t),null;case 24:case 25:return null}throw Error(i(156,t.tag))}function Za(e,t){switch(ni(t),t.tag){case 1:return jr(t.type)&&Pr(),65536&(e=t.flags)?(t.flags=-65537&e|128,t):null;case 3:return Yi(),Cr(Lr),Cr(Dr),os(),65536&(e=t.flags)&&!(128&e)?(t.flags=-65537&e|128,t):null;case 5:return Ji(t),null;case 13:if(Cr(es),null!==(e=t.memoizedState)&&null!==e.dehydrated){if(null===t.alternate)throw Error(i(340));mi()}return 65536&(e=t.flags)?(t.flags=-65537&e|128,t):null;case 19:return Cr(es),null;case 4:return Yi(),null;case 10:return Ti(t.type._context),null;case 22:case 23:return uc(),null;default:return null}}Ra=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Na=function(){},ja=function(e,t,n,o){var r=e.memoizedProps;if(r!==o){e=t.stateNode,Qi(Gi.current);var i,s=null;switch(n){case"input":r=Q(e,r),o=Q(e,o),s=[];break;case"select":r=M({},r,{value:void 0}),o=M({},o,{value:void 0}),s=[];break;case"textarea":r=oe(e,r),o=oe(e,o),s=[];break;default:"function"!=typeof r.onClick&&"function"==typeof o.onClick&&(e.onclick=er)}for(d in ve(n,o),n=null,r)if(!o.hasOwnProperty(d)&&r.hasOwnProperty(d)&&null!=r[d])if("style"===d){var l=r[d];for(i in l)l.hasOwnProperty(i)&&(n||(n={}),n[i]="")}else"dangerouslySetInnerHTML"!==d&&"children"!==d&&"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&"autoFocus"!==d&&(a.hasOwnProperty(d)?s||(s=[]):(s=s||[]).push(d,null));for(d in o){var c=o[d];if(l=null!=r?r[d]:void 0,o.hasOwnProperty(d)&&c!==l&&(null!=c||null!=l))if("style"===d)if(l){for(i in l)!l.hasOwnProperty(i)||c&&c.hasOwnProperty(i)||(n||(n={}),n[i]="");for(i in c)c.hasOwnProperty(i)&&l[i]!==c[i]&&(n||(n={}),n[i]=c[i])}else n||(s||(s=[]),s.push(d,n)),n=c;else"dangerouslySetInnerHTML"===d?(c=c?c.__html:void 0,l=l?l.__html:void 0,null!=c&&l!==c&&(s=s||[]).push(d,c)):"children"===d?"string"!=typeof c&&"number"!=typeof c||(s=s||[]).push(d,""+c):"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&(a.hasOwnProperty(d)?(null!=c&&"onScroll"===d&&Uo("scroll",e),s||l===c||(s=[])):(s=s||[]).push(d,c))}n&&(s=s||[]).push("style",n);var d=s;(t.updateQueue=d)&&(t.flags|=4)}},Pa=function(e,t,n,o){n!==o&&(t.flags|=4)};var Qa=!1,Ka=!1,Ya="function"==typeof WeakSet?WeakSet:Set,Xa=null;function Ja(e,t){var n=e.ref;if(null!==n)if("function"==typeof n)try{n(null)}catch(o){Sc(e,t,o)}else n.current=null}function el(e,t,n){try{n()}catch(o){Sc(e,t,o)}}var tl=!1;function nl(e,t,n){var o=t.updateQueue;if(null!==(o=null!==o?o.lastEffect:null)){var r=o=o.next;do{if((r.tag&e)===e){var i=r.destroy;r.destroy=void 0,void 0!==i&&el(t,n,i)}r=r.next}while(r!==o)}}function ol(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null)){var n=t=t.next;do{if((n.tag&e)===e){var o=n.create;n.destroy=o()}n=n.next}while(n!==t)}}function rl(e){var t=e.ref;if(null!==t){var n=e.stateNode;e.tag,e=n,"function"==typeof t?t(e):t.current=e}}function il(e){var t=e.alternate;null!==t&&(e.alternate=null,il(t)),e.child=null,e.deletions=null,e.sibling=null,5===e.tag&&(null!==(t=e.stateNode)&&(delete t[fr],delete t[mr],delete t[gr],delete t[br],delete t[vr])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function sl(e){return 5===e.tag||3===e.tag||4===e.tag}function al(e){e:for(;;){for(;null===e.sibling;){if(null===e.return||sl(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;5!==e.tag&&6!==e.tag&&18!==e.tag;){if(2&e.flags)continue e;if(null===e.child||4===e.tag)continue e;e.child.return=e,e=e.child}if(!(2&e.flags))return e.stateNode}}function ll(e,t,n){var o=e.tag;if(5===o||6===o)e=e.stateNode,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=er));else if(4!==o&&null!==(e=e.child))for(ll(e,t,n),e=e.sibling;null!==e;)ll(e,t,n),e=e.sibling}function cl(e,t,n){var o=e.tag;if(5===o||6===o)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==o&&null!==(e=e.child))for(cl(e,t,n),e=e.sibling;null!==e;)cl(e,t,n),e=e.sibling}var dl=null,ul=!1;function pl(e,t,n){for(n=n.child;null!==n;)fl(e,t,n),n=n.sibling}function fl(e,t,n){if(it&&"function"==typeof it.onCommitFiberUnmount)try{it.onCommitFiberUnmount(rt,n)}catch(a){}switch(n.tag){case 5:Ka||Ja(n,t);case 6:var o=dl,r=ul;dl=null,pl(e,t,n),ul=r,null!==(dl=o)&&(ul?(e=dl,n=n.stateNode,8===e.nodeType?e.parentNode.removeChild(n):e.removeChild(n)):dl.removeChild(n.stateNode));break;case 18:null!==dl&&(ul?(e=dl,n=n.stateNode,8===e.nodeType?cr(e.parentNode,n):1===e.nodeType&&cr(e,n),$t(e)):cr(dl,n.stateNode));break;case 4:o=dl,r=ul,dl=n.stateNode.containerInfo,ul=!0,pl(e,t,n),dl=o,ul=r;break;case 0:case 11:case 14:case 15:if(!Ka&&(null!==(o=n.updateQueue)&&null!==(o=o.lastEffect))){r=o=o.next;do{var i=r,s=i.destroy;i=i.tag,void 0!==s&&(2&i||4&i)&&el(n,t,s),r=r.next}while(r!==o)}pl(e,t,n);break;case 1:if(!Ka&&(Ja(n,t),"function"==typeof(o=n.stateNode).componentWillUnmount))try{o.props=n.memoizedProps,o.state=n.memoizedState,o.componentWillUnmount()}catch(a){Sc(n,t,a)}pl(e,t,n);break;case 21:pl(e,t,n);break;case 22:1&n.mode?(Ka=(o=Ka)||null!==n.memoizedState,pl(e,t,n),Ka=o):pl(e,t,n);break;default:pl(e,t,n)}}function ml(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new Ya),t.forEach((function(t){var o=Tc.bind(null,e,t);n.has(t)||(n.add(t),t.then(o,o))}))}}function hl(e,t){var n=t.deletions;if(null!==n)for(var o=0;o<n.length;o++){var r=n[o];try{var s=e,a=t,l=a;e:for(;null!==l;){switch(l.tag){case 5:dl=l.stateNode,ul=!1;break e;case 3:case 4:dl=l.stateNode.containerInfo,ul=!0;break e}l=l.return}if(null===dl)throw Error(i(160));fl(s,a,r),dl=null,ul=!1;var c=r.alternate;null!==c&&(c.return=null),r.return=null}catch(d){Sc(r,t,d)}}if(12854&t.subtreeFlags)for(t=t.child;null!==t;)gl(t,e),t=t.sibling}function gl(e,t){var n=e.alternate,o=e.flags;switch(e.tag){case 0:case 11:case 14:case 15:if(hl(t,e),bl(e),4&o){try{nl(3,e,e.return),ol(3,e)}catch(g){Sc(e,e.return,g)}try{nl(5,e,e.return)}catch(g){Sc(e,e.return,g)}}break;case 1:hl(t,e),bl(e),512&o&&null!==n&&Ja(n,n.return);break;case 5:if(hl(t,e),bl(e),512&o&&null!==n&&Ja(n,n.return),32&e.flags){var r=e.stateNode;try{pe(r,"")}catch(g){Sc(e,e.return,g)}}if(4&o&&null!=(r=e.stateNode)){var s=e.memoizedProps,a=null!==n?n.memoizedProps:s,l=e.type,c=e.updateQueue;if(e.updateQueue=null,null!==c)try{"input"===l&&"radio"===s.type&&null!=s.name&&Y(r,s),ye(l,a);var d=ye(l,s);for(a=0;a<c.length;a+=2){var u=c[a],p=c[a+1];"style"===u?ge(r,p):"dangerouslySetInnerHTML"===u?ue(r,p):"children"===u?pe(r,p):y(r,u,p,d)}switch(l){case"input":X(r,s);break;case"textarea":ie(r,s);break;case"select":var f=r._wrapperState.wasMultiple;r._wrapperState.wasMultiple=!!s.multiple;var m=s.value;null!=m?ne(r,!!s.multiple,m,!1):f!==!!s.multiple&&(null!=s.defaultValue?ne(r,!!s.multiple,s.defaultValue,!0):ne(r,!!s.multiple,s.multiple?[]:"",!1))}r[mr]=s}catch(g){Sc(e,e.return,g)}}break;case 6:if(hl(t,e),bl(e),4&o){if(null===e.stateNode)throw Error(i(162));r=e.stateNode,s=e.memoizedProps;try{r.nodeValue=s}catch(g){Sc(e,e.return,g)}}break;case 3:if(hl(t,e),bl(e),4&o&&null!==n&&n.memoizedState.isDehydrated)try{$t(t.containerInfo)}catch(g){Sc(e,e.return,g)}break;case 4:default:hl(t,e),bl(e);break;case 13:hl(t,e),bl(e),8192&(r=e.child).flags&&(s=null!==r.memoizedState,r.stateNode.isHidden=s,!s||null!==r.alternate&&null!==r.alternate.memoizedState||(zl=Ye())),4&o&&ml(e);break;case 22:if(u=null!==n&&null!==n.memoizedState,1&e.mode?(Ka=(d=Ka)||u,hl(t,e),Ka=d):hl(t,e),bl(e),8192&o){if(d=null!==e.memoizedState,(e.stateNode.isHidden=d)&&!u&&1&e.mode)for(Xa=e,u=e.child;null!==u;){for(p=Xa=u;null!==Xa;){switch(m=(f=Xa).child,f.tag){case 0:case 11:case 14:case 15:nl(4,f,f.return);break;case 1:Ja(f,f.return);var h=f.stateNode;if("function"==typeof h.componentWillUnmount){o=f,n=f.return;try{t=o,h.props=t.memoizedProps,h.state=t.memoizedState,h.componentWillUnmount()}catch(g){Sc(o,n,g)}}break;case 5:Ja(f,f.return);break;case 22:if(null!==f.memoizedState){kl(p);continue}}null!==m?(m.return=f,Xa=m):kl(p)}u=u.sibling}e:for(u=null,p=e;;){if(5===p.tag){if(null===u){u=p;try{r=p.stateNode,d?"function"==typeof(s=r.style).setProperty?s.setProperty("display","none","important"):s.display="none":(l=p.stateNode,a=null!=(c=p.memoizedProps.style)&&c.hasOwnProperty("display")?c.display:null,l.style.display=he("display",a))}catch(g){Sc(e,e.return,g)}}}else if(6===p.tag){if(null===u)try{p.stateNode.nodeValue=d?"":p.memoizedProps}catch(g){Sc(e,e.return,g)}}else if((22!==p.tag&&23!==p.tag||null===p.memoizedState||p===e)&&null!==p.child){p.child.return=p,p=p.child;continue}if(p===e)break e;for(;null===p.sibling;){if(null===p.return||p.return===e)break e;u===p&&(u=null),p=p.return}u===p&&(u=null),p.sibling.return=p.return,p=p.sibling}}break;case 19:hl(t,e),bl(e),4&o&&ml(e);case 21:}}function bl(e){var t=e.flags;if(2&t){try{e:{for(var n=e.return;null!==n;){if(sl(n)){var o=n;break e}n=n.return}throw Error(i(160))}switch(o.tag){case 5:var r=o.stateNode;32&o.flags&&(pe(r,""),o.flags&=-33),cl(e,al(e),r);break;case 3:case 4:var s=o.stateNode.containerInfo;ll(e,al(e),s);break;default:throw Error(i(161))}}catch(a){Sc(e,e.return,a)}e.flags&=-3}4096&t&&(e.flags&=-4097)}function vl(e,t,n){Xa=e,yl(e,t,n)}function yl(e,t,n){for(var o=!!(1&e.mode);null!==Xa;){var r=Xa,i=r.child;if(22===r.tag&&o){var s=null!==r.memoizedState||Qa;if(!s){var a=r.alternate,l=null!==a&&null!==a.memoizedState||Ka;a=Qa;var c=Ka;if(Qa=s,(Ka=l)&&!c)for(Xa=r;null!==Xa;)l=(s=Xa).child,22===s.tag&&null!==s.memoizedState?xl(r):null!==l?(l.return=s,Xa=l):xl(r);for(;null!==i;)Xa=i,yl(i,t,n),i=i.sibling;Xa=r,Qa=a,Ka=c}wl(e)}else 8772&r.subtreeFlags&&null!==i?(i.return=r,Xa=i):wl(e)}}function wl(e){for(;null!==Xa;){var t=Xa;if(8772&t.flags){var n=t.alternate;try{if(8772&t.flags)switch(t.tag){case 0:case 11:case 15:Ka||ol(5,t);break;case 1:var o=t.stateNode;if(4&t.flags&&!Ka)if(null===n)o.componentDidMount();else{var r=t.elementType===t.type?n.memoizedProps:na(t.type,n.memoizedProps);o.componentDidUpdate(r,n.memoizedState,o.__reactInternalSnapshotBeforeUpdate)}var s=t.updateQueue;null!==s&&qi(t,s,o);break;case 3:var a=t.updateQueue;if(null!==a){if(n=null,null!==t.child)switch(t.child.tag){case 5:case 1:n=t.child.stateNode}qi(t,a,n)}break;case 5:var l=t.stateNode;if(null===n&&4&t.flags){n=l;var c=t.memoizedProps;switch(t.type){case"button":case"input":case"select":case"textarea":c.autoFocus&&n.focus();break;case"img":c.src&&(n.src=c.src)}}break;case 6:case 4:case 12:case 19:case 17:case 21:case 22:case 23:case 25:break;case 13:if(null===t.memoizedState){var d=t.alternate;if(null!==d){var u=d.memoizedState;if(null!==u){var p=u.dehydrated;null!==p&&$t(p)}}}break;default:throw Error(i(163))}Ka||512&t.flags&&rl(t)}catch(f){Sc(t,t.return,f)}}if(t===e){Xa=null;break}if(null!==(n=t.sibling)){n.return=t.return,Xa=n;break}Xa=t.return}}function kl(e){for(;null!==Xa;){var t=Xa;if(t===e){Xa=null;break}var n=t.sibling;if(null!==n){n.return=t.return,Xa=n;break}Xa=t.return}}function xl(e){for(;null!==Xa;){var t=Xa;try{switch(t.tag){case 0:case 11:case 15:var n=t.return;try{ol(4,t)}catch(l){Sc(t,n,l)}break;case 1:var o=t.stateNode;if("function"==typeof o.componentDidMount){var r=t.return;try{o.componentDidMount()}catch(l){Sc(t,r,l)}}var i=t.return;try{rl(t)}catch(l){Sc(t,i,l)}break;case 5:var s=t.return;try{rl(t)}catch(l){Sc(t,s,l)}}}catch(l){Sc(t,t.return,l)}if(t===e){Xa=null;break}var a=t.sibling;if(null!==a){a.return=t.return,Xa=a;break}Xa=t.return}}var _l,Sl=Math.ceil,Al=w.ReactCurrentDispatcher,Cl=w.ReactCurrentOwner,El=w.ReactCurrentBatchConfig,Tl=0,Dl=null,Ll=null,Rl=0,Nl=0,jl=Ar(0),Pl=0,Ol=null,Il=0,Ml=0,Fl=0,Bl=null,Ul=null,zl=0,$l=1/0,Vl=null,ql=!1,Hl=null,Gl=null,Wl=!1,Zl=null,Ql=0,Kl=0,Yl=null,Xl=-1,Jl=0;function ec(){return 6&Tl?Ye():-1!==Xl?Xl:Xl=Ye()}function tc(e){return 1&e.mode?2&Tl&&0!==Rl?Rl&-Rl:null!==gi.transition?(0===Jl&&(Jl=ht()),Jl):0!==(e=yt)?e:e=void 0===(e=window.event)?16:Kt(e.type):1}function nc(e,t,n,o){if(50<Kl)throw Kl=0,Yl=null,Error(i(185));bt(e,n,o),2&Tl&&e===Dl||(e===Dl&&(!(2&Tl)&&(Ml|=n),4===Pl&&ac(e,Rl)),oc(e,o),1===n&&0===Tl&&!(1&t.mode)&&($l=Ye()+500,Ur&&Vr()))}function oc(e,t){var n=e.callbackNode;!function(e,t){for(var n=e.suspendedLanes,o=e.pingedLanes,r=e.expirationTimes,i=e.pendingLanes;0<i;){var s=31-st(i),a=1<<s,l=r[s];-1===l?a&n&&!(a&o)||(r[s]=ft(a,t)):l<=t&&(e.expiredLanes|=a),i&=~a}}(e,t);var o=pt(e,e===Dl?Rl:0);if(0===o)null!==n&&Ze(n),e.callbackNode=null,e.callbackPriority=0;else if(t=o&-o,e.callbackPriority!==t){if(null!=n&&Ze(n),1===t)0===e.tag?function(e){Ur=!0,$r(e)}(lc.bind(null,e)):$r(lc.bind(null,e)),ar((function(){!(6&Tl)&&Vr()})),n=null;else{switch(wt(o)){case 1:n=Je;break;case 4:n=et;break;case 16:default:n=tt;break;case 536870912:n=ot}n=Dc(n,rc.bind(null,e))}e.callbackPriority=t,e.callbackNode=n}}function rc(e,t){if(Xl=-1,Jl=0,6&Tl)throw Error(i(327));var n=e.callbackNode;if(xc()&&e.callbackNode!==n)return null;var o=pt(e,e===Dl?Rl:0);if(0===o)return null;if(30&o||o&e.expiredLanes||t)t=gc(e,o);else{t=o;var r=Tl;Tl|=2;var s=mc();for(Dl===e&&Rl===t||(Vl=null,$l=Ye()+500,pc(e,t));;)try{vc();break}catch(l){fc(e,l)}Ei(),Al.current=s,Tl=r,null!==Ll?t=0:(Dl=null,Rl=0,t=Pl)}if(0!==t){if(2===t&&(0!==(r=mt(e))&&(o=r,t=ic(e,r))),1===t)throw n=Ol,pc(e,0),ac(e,o),oc(e,Ye()),n;if(6===t)ac(e,o);else{if(r=e.current.alternate,!(30&o||function(e){for(var t=e;;){if(16384&t.flags){var n=t.updateQueue;if(null!==n&&null!==(n=n.stores))for(var o=0;o<n.length;o++){var r=n[o],i=r.getSnapshot;r=r.value;try{if(!ao(i(),r))return!1}catch(a){return!1}}}if(n=t.child,16384&t.subtreeFlags&&null!==n)n.return=t,t=n;else{if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return!0;t=t.return}t.sibling.return=t.return,t=t.sibling}}return!0}(r)||(t=gc(e,o),2===t&&(s=mt(e),0!==s&&(o=s,t=ic(e,s))),1!==t)))throw n=Ol,pc(e,0),ac(e,o),oc(e,Ye()),n;switch(e.finishedWork=r,e.finishedLanes=o,t){case 0:case 1:throw Error(i(345));case 2:case 5:kc(e,Ul,Vl);break;case 3:if(ac(e,o),(130023424&o)===o&&10<(t=zl+500-Ye())){if(0!==pt(e,0))break;if(((r=e.suspendedLanes)&o)!==o){ec(),e.pingedLanes|=e.suspendedLanes&r;break}e.timeoutHandle=rr(kc.bind(null,e,Ul,Vl),t);break}kc(e,Ul,Vl);break;case 4:if(ac(e,o),(4194240&o)===o)break;for(t=e.eventTimes,r=-1;0<o;){var a=31-st(o);s=1<<a,(a=t[a])>r&&(r=a),o&=~s}if(o=r,10<(o=(120>(o=Ye()-o)?120:480>o?480:1080>o?1080:1920>o?1920:3e3>o?3e3:4320>o?4320:1960*Sl(o/1960))-o)){e.timeoutHandle=rr(kc.bind(null,e,Ul,Vl),o);break}kc(e,Ul,Vl);break;default:throw Error(i(329))}}}return oc(e,Ye()),e.callbackNode===n?rc.bind(null,e):null}function ic(e,t){var n=Bl;return e.current.memoizedState.isDehydrated&&(pc(e,t).flags|=256),2!==(e=gc(e,t))&&(t=Ul,Ul=n,null!==t&&sc(t)),e}function sc(e){null===Ul?Ul=e:Ul.push.apply(Ul,e)}function ac(e,t){for(t&=~Fl,t&=~Ml,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-st(t),o=1<<n;e[n]=-1,t&=~o}}function lc(e){if(6&Tl)throw Error(i(327));xc();var t=pt(e,0);if(!(1&t))return oc(e,Ye()),null;var n=gc(e,t);if(0!==e.tag&&2===n){var o=mt(e);0!==o&&(t=o,n=ic(e,o))}if(1===n)throw n=Ol,pc(e,0),ac(e,t),oc(e,Ye()),n;if(6===n)throw Error(i(345));return e.finishedWork=e.current.alternate,e.finishedLanes=t,kc(e,Ul,Vl),oc(e,Ye()),null}function cc(e,t){var n=Tl;Tl|=1;try{return e(t)}finally{0===(Tl=n)&&($l=Ye()+500,Ur&&Vr())}}function dc(e){null!==Zl&&0===Zl.tag&&!(6&Tl)&&xc();var t=Tl;Tl|=1;var n=El.transition,o=yt;try{if(El.transition=null,yt=1,e)return e()}finally{yt=o,El.transition=n,!(6&(Tl=t))&&Vr()}}function uc(){Nl=jl.current,Cr(jl)}function pc(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,ir(n)),null!==Ll)for(n=Ll.return;null!==n;){var o=n;switch(ni(o),o.tag){case 1:null!=(o=o.type.childContextTypes)&&Pr();break;case 3:Yi(),Cr(Lr),Cr(Dr),os();break;case 5:Ji(o);break;case 4:Yi();break;case 13:case 19:Cr(es);break;case 10:Ti(o.type._context);break;case 22:case 23:uc()}n=n.return}if(Dl=e,Ll=e=jc(e.current,null),Rl=Nl=t,Pl=0,Ol=null,Fl=Ml=Il=0,Ul=Bl=null,null!==Ni){for(t=0;t<Ni.length;t++)if(null!==(o=(n=Ni[t]).interleaved)){n.interleaved=null;var r=o.next,i=n.pending;if(null!==i){var s=i.next;i.next=r,o.next=s}n.pending=o}Ni=null}return e}function fc(e,t){for(;;){var n=Ll;try{if(Ei(),rs.current=Xs,ds){for(var o=as.memoizedState;null!==o;){var r=o.queue;null!==r&&(r.pending=null),o=o.next}ds=!1}if(ss=0,cs=ls=as=null,us=!1,ps=0,Cl.current=null,null===n||null===n.return){Pl=1,Ol=t,Ll=null;break}e:{var s=e,a=n.return,l=n,c=t;if(t=Rl,l.flags|=32768,null!==c&&"object"==typeof c&&"function"==typeof c.then){var d=c,u=l,p=u.tag;if(!(1&u.mode||0!==p&&11!==p&&15!==p)){var f=u.alternate;f?(u.updateQueue=f.updateQueue,u.memoizedState=f.memoizedState,u.lanes=f.lanes):(u.updateQueue=null,u.memoizedState=null)}var m=ga(a);if(null!==m){m.flags&=-257,ba(m,a,l,0,t),1&m.mode&&ha(s,d,t),c=d;var h=(t=m).updateQueue;if(null===h){var g=new Set;g.add(c),t.updateQueue=g}else h.add(c);break e}if(!(1&t)){ha(s,d,t),hc();break e}c=Error(i(426))}else if(ii&&1&l.mode){var b=ga(a);if(null!==b){!(65536&b.flags)&&(b.flags|=256),ba(b,a,l,0,t),hi(ca(c,l));break e}}s=c=ca(c,l),4!==Pl&&(Pl=2),null===Bl?Bl=[s]:Bl.push(s),s=a;do{switch(s.tag){case 3:s.flags|=65536,t&=-t,s.lanes|=t,$i(s,fa(0,c,t));break e;case 1:l=c;var v=s.type,y=s.stateNode;if(!(128&s.flags||"function"!=typeof v.getDerivedStateFromError&&(null===y||"function"!=typeof y.componentDidCatch||null!==Gl&&Gl.has(y)))){s.flags|=65536,t&=-t,s.lanes|=t,$i(s,ma(s,l,t));break e}}s=s.return}while(null!==s)}wc(n)}catch(w){t=w,Ll===n&&null!==n&&(Ll=n=n.return);continue}break}}function mc(){var e=Al.current;return Al.current=Xs,null===e?Xs:e}function hc(){0!==Pl&&3!==Pl&&2!==Pl||(Pl=4),null===Dl||!(268435455&Il)&&!(268435455&Ml)||ac(Dl,Rl)}function gc(e,t){var n=Tl;Tl|=2;var o=mc();for(Dl===e&&Rl===t||(Vl=null,pc(e,t));;)try{bc();break}catch(r){fc(e,r)}if(Ei(),Tl=n,Al.current=o,null!==Ll)throw Error(i(261));return Dl=null,Rl=0,Pl}function bc(){for(;null!==Ll;)yc(Ll)}function vc(){for(;null!==Ll&&!Qe();)yc(Ll)}function yc(e){var t=_l(e.alternate,e,Nl);e.memoizedProps=e.pendingProps,null===t?wc(e):Ll=t,Cl.current=null}function wc(e){var t=e;do{var n=t.alternate;if(e=t.return,32768&t.flags){if(null!==(n=Za(n,t)))return n.flags&=32767,void(Ll=n);if(null===e)return Pl=6,void(Ll=null);e.flags|=32768,e.subtreeFlags=0,e.deletions=null}else if(null!==(n=Wa(n,t,Nl)))return void(Ll=n);if(null!==(t=t.sibling))return void(Ll=t);Ll=t=e}while(null!==t);0===Pl&&(Pl=5)}function kc(e,t,n){var o=yt,r=El.transition;try{El.transition=null,yt=1,function(e,t,n,o){do{xc()}while(null!==Zl);if(6&Tl)throw Error(i(327));n=e.finishedWork;var r=e.finishedLanes;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(i(177));e.callbackNode=null,e.callbackPriority=0;var s=n.lanes|n.childLanes;if(function(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var o=e.eventTimes;for(e=e.expirationTimes;0<n;){var r=31-st(n),i=1<<r;t[r]=0,o[r]=-1,e[r]=-1,n&=~i}}(e,s),e===Dl&&(Ll=Dl=null,Rl=0),!(2064&n.subtreeFlags)&&!(2064&n.flags)||Wl||(Wl=!0,Dc(tt,(function(){return xc(),null}))),s=!!(15990&n.flags),!!(15990&n.subtreeFlags)||s){s=El.transition,El.transition=null;var a=yt;yt=1;var l=Tl;Tl|=4,Cl.current=null,function(e,t){if(tr=qt,mo(e=fo())){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{var o=(n=(n=e.ownerDocument)&&n.defaultView||window).getSelection&&n.getSelection();if(o&&0!==o.rangeCount){n=o.anchorNode;var r=o.anchorOffset,s=o.focusNode;o=o.focusOffset;try{n.nodeType,s.nodeType}catch(k){n=null;break e}var a=0,l=-1,c=-1,d=0,u=0,p=e,f=null;t:for(;;){for(var m;p!==n||0!==r&&3!==p.nodeType||(l=a+r),p!==s||0!==o&&3!==p.nodeType||(c=a+o),3===p.nodeType&&(a+=p.nodeValue.length),null!==(m=p.firstChild);)f=p,p=m;for(;;){if(p===e)break t;if(f===n&&++d===r&&(l=a),f===s&&++u===o&&(c=a),null!==(m=p.nextSibling))break;f=(p=f).parentNode}p=m}n=-1===l||-1===c?null:{start:l,end:c}}else n=null}n=n||{start:0,end:0}}else n=null;for(nr={focusedElem:e,selectionRange:n},qt=!1,Xa=t;null!==Xa;)if(e=(t=Xa).child,1028&t.subtreeFlags&&null!==e)e.return=t,Xa=e;else for(;null!==Xa;){t=Xa;try{var h=t.alternate;if(1024&t.flags)switch(t.tag){case 0:case 11:case 15:case 5:case 6:case 4:case 17:break;case 1:if(null!==h){var g=h.memoizedProps,b=h.memoizedState,v=t.stateNode,y=v.getSnapshotBeforeUpdate(t.elementType===t.type?g:na(t.type,g),b);v.__reactInternalSnapshotBeforeUpdate=y}break;case 3:var w=t.stateNode.containerInfo;1===w.nodeType?w.textContent="":9===w.nodeType&&w.documentElement&&w.removeChild(w.documentElement);break;default:throw Error(i(163))}}catch(k){Sc(t,t.return,k)}if(null!==(e=t.sibling)){e.return=t.return,Xa=e;break}Xa=t.return}h=tl,tl=!1}(e,n),gl(n,e),ho(nr),qt=!!tr,nr=tr=null,e.current=n,vl(n,e,r),Ke(),Tl=l,yt=a,El.transition=s}else e.current=n;if(Wl&&(Wl=!1,Zl=e,Ql=r),s=e.pendingLanes,0===s&&(Gl=null),function(e){if(it&&"function"==typeof it.onCommitFiberRoot)try{it.onCommitFiberRoot(rt,e,void 0,!(128&~e.current.flags))}catch(t){}}(n.stateNode),oc(e,Ye()),null!==t)for(o=e.onRecoverableError,n=0;n<t.length;n++)r=t[n],o(r.value,{componentStack:r.stack,digest:r.digest});if(ql)throw ql=!1,e=Hl,Hl=null,e;!!(1&Ql)&&0!==e.tag&&xc(),s=e.pendingLanes,1&s?e===Yl?Kl++:(Kl=0,Yl=e):Kl=0,Vr()}(e,t,n,o)}finally{El.transition=r,yt=o}return null}function xc(){if(null!==Zl){var e=wt(Ql),t=El.transition,n=yt;try{if(El.transition=null,yt=16>e?16:e,null===Zl)var o=!1;else{if(e=Zl,Zl=null,Ql=0,6&Tl)throw Error(i(331));var r=Tl;for(Tl|=4,Xa=e.current;null!==Xa;){var s=Xa,a=s.child;if(16&Xa.flags){var l=s.deletions;if(null!==l){for(var c=0;c<l.length;c++){var d=l[c];for(Xa=d;null!==Xa;){var u=Xa;switch(u.tag){case 0:case 11:case 15:nl(8,u,s)}var p=u.child;if(null!==p)p.return=u,Xa=p;else for(;null!==Xa;){var f=(u=Xa).sibling,m=u.return;if(il(u),u===d){Xa=null;break}if(null!==f){f.return=m,Xa=f;break}Xa=m}}}var h=s.alternate;if(null!==h){var g=h.child;if(null!==g){h.child=null;do{var b=g.sibling;g.sibling=null,g=b}while(null!==g)}}Xa=s}}if(2064&s.subtreeFlags&&null!==a)a.return=s,Xa=a;else e:for(;null!==Xa;){if(2048&(s=Xa).flags)switch(s.tag){case 0:case 11:case 15:nl(9,s,s.return)}var v=s.sibling;if(null!==v){v.return=s.return,Xa=v;break e}Xa=s.return}}var y=e.current;for(Xa=y;null!==Xa;){var w=(a=Xa).child;if(2064&a.subtreeFlags&&null!==w)w.return=a,Xa=w;else e:for(a=y;null!==Xa;){if(2048&(l=Xa).flags)try{switch(l.tag){case 0:case 11:case 15:ol(9,l)}}catch(x){Sc(l,l.return,x)}if(l===a){Xa=null;break e}var k=l.sibling;if(null!==k){k.return=l.return,Xa=k;break e}Xa=l.return}}if(Tl=r,Vr(),it&&"function"==typeof it.onPostCommitFiberRoot)try{it.onPostCommitFiberRoot(rt,e)}catch(x){}o=!0}return o}finally{yt=n,El.transition=t}}return!1}function _c(e,t,n){e=Ui(e,t=fa(0,t=ca(n,t),1),1),t=ec(),null!==e&&(bt(e,1,t),oc(e,t))}function Sc(e,t,n){if(3===e.tag)_c(e,e,n);else for(;null!==t;){if(3===t.tag){_c(t,e,n);break}if(1===t.tag){var o=t.stateNode;if("function"==typeof t.type.getDerivedStateFromError||"function"==typeof o.componentDidCatch&&(null===Gl||!Gl.has(o))){t=Ui(t,e=ma(t,e=ca(n,e),1),1),e=ec(),null!==t&&(bt(t,1,e),oc(t,e));break}}t=t.return}}function Ac(e,t,n){var o=e.pingCache;null!==o&&o.delete(t),t=ec(),e.pingedLanes|=e.suspendedLanes&n,Dl===e&&(Rl&n)===n&&(4===Pl||3===Pl&&(130023424&Rl)===Rl&&500>Ye()-zl?pc(e,0):Fl|=n),oc(e,t)}function Cc(e,t){0===t&&(1&e.mode?(t=dt,!(130023424&(dt<<=1))&&(dt=4194304)):t=1);var n=ec();null!==(e=Oi(e,t))&&(bt(e,t,n),oc(e,n))}function Ec(e){var t=e.memoizedState,n=0;null!==t&&(n=t.retryLane),Cc(e,n)}function Tc(e,t){var n=0;switch(e.tag){case 13:var o=e.stateNode,r=e.memoizedState;null!==r&&(n=r.retryLane);break;case 19:o=e.stateNode;break;default:throw Error(i(314))}null!==o&&o.delete(t),Cc(e,n)}function Dc(e,t){return We(e,t)}function Lc(e,t,n,o){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=o,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Rc(e,t,n,o){return new Lc(e,t,n,o)}function Nc(e){return!(!(e=e.prototype)||!e.isReactComponent)}function jc(e,t){var n=e.alternate;return null===n?((n=Rc(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=14680064&e.flags,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Pc(e,t,n,o,r,s){var a=2;if(o=e,"function"==typeof e)Nc(e)&&(a=1);else if("string"==typeof e)a=5;else e:switch(e){case _:return Oc(n.children,r,s,t);case S:a=8,r|=8;break;case A:return(e=Rc(12,n,t,2|r)).elementType=A,e.lanes=s,e;case D:return(e=Rc(13,n,t,r)).elementType=D,e.lanes=s,e;case L:return(e=Rc(19,n,t,r)).elementType=L,e.lanes=s,e;case j:return Ic(n,r,s,t);default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case C:a=10;break e;case E:a=9;break e;case T:a=11;break e;case R:a=14;break e;case N:a=16,o=null;break e}throw Error(i(130,null==e?e:typeof e,""))}return(t=Rc(a,n,t,r)).elementType=e,t.type=o,t.lanes=s,t}function Oc(e,t,n,o){return(e=Rc(7,e,o,t)).lanes=n,e}function Ic(e,t,n,o){return(e=Rc(22,e,o,t)).elementType=j,e.lanes=n,e.stateNode={isHidden:!1},e}function Mc(e,t,n){return(e=Rc(6,e,null,t)).lanes=n,e}function Fc(e,t,n){return(t=Rc(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Bc(e,t,n,o,r){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=gt(0),this.expirationTimes=gt(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=gt(0),this.identifierPrefix=o,this.onRecoverableError=r,this.mutableSourceEagerHydrationData=null}function Uc(e,t,n,o,r,i,s,a,l){return e=new Bc(e,t,n,a,l),1===t?(t=1,!0===i&&(t|=8)):t=0,i=Rc(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:o,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Mi(i),e}function zc(e){if(!e)return Tr;e:{if($e(e=e._reactInternals)!==e||1!==e.tag)throw Error(i(170));var t=e;do{switch(t.tag){case 3:t=t.stateNode.context;break e;case 1:if(jr(t.type)){t=t.stateNode.__reactInternalMemoizedMergedChildContext;break e}}t=t.return}while(null!==t);throw Error(i(171))}if(1===e.tag){var n=e.type;if(jr(n))return Ir(e,n,t)}return t}function $c(e,t,n,o,r,i,s,a,l){return(e=Uc(n,o,!0,e,0,i,0,a,l)).context=zc(null),n=e.current,(i=Bi(o=ec(),r=tc(n))).callback=null!=t?t:null,Ui(n,i,r),e.current.lanes=r,bt(e,r,o),oc(e,o),e}function Vc(e,t,n,o){var r=t.current,i=ec(),s=tc(r);return n=zc(n),null===t.context?t.context=n:t.pendingContext=n,(t=Bi(i,s)).payload={element:e},null!==(o=void 0===o?null:o)&&(t.callback=o),null!==(e=Ui(r,t,s))&&(nc(e,r,s,i),zi(e,r,s)),s}function qc(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function Hc(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function Gc(e,t){Hc(e,t),(e=e.alternate)&&Hc(e,t)}_l=function(e,t,n){if(null!==e)if(e.memoizedProps!==t.pendingProps||Lr.current)ya=!0;else{if(!(e.lanes&n||128&t.flags))return ya=!1,function(e,t,n){switch(t.tag){case 3:Da(t),mi();break;case 5:Xi(t);break;case 1:jr(t.type)&&Mr(t);break;case 4:Ki(t,t.stateNode.containerInfo);break;case 10:var o=t.type._context,r=t.memoizedProps.value;Er(_i,o._currentValue),o._currentValue=r;break;case 13:if(null!==(o=t.memoizedState))return null!==o.dehydrated?(Er(es,1&es.current),t.flags|=128,null):n&t.child.childLanes?Ma(e,t,n):(Er(es,1&es.current),null!==(e=qa(e,t,n))?e.sibling:null);Er(es,1&es.current);break;case 19:if(o=!!(n&t.childLanes),128&e.flags){if(o)return $a(e,t,n);t.flags|=128}if(null!==(r=t.memoizedState)&&(r.rendering=null,r.tail=null,r.lastEffect=null),Er(es,es.current),o)break;return null;case 22:case 23:return t.lanes=0,Sa(e,t,n)}return qa(e,t,n)}(e,t,n);ya=!!(131072&e.flags)}else ya=!1,ii&&1048576&t.flags&&ei(t,Wr,t.index);switch(t.lanes=0,t.tag){case 2:var o=t.type;Va(e,t),e=t.pendingProps;var r=Nr(t,Dr.current);Li(t,n),r=gs(null,t,o,e,r,n);var s=bs();return t.flags|=1,"object"==typeof r&&null!==r&&"function"==typeof r.render&&void 0===r.$$typeof?(t.tag=1,t.memoizedState=null,t.updateQueue=null,jr(o)?(s=!0,Mr(t)):s=!1,t.memoizedState=null!==r.state&&void 0!==r.state?r.state:null,Mi(t),r.updater=ra,t.stateNode=r,r._reactInternals=t,la(t,o,e,n),t=Ta(null,t,o,!0,s,n)):(t.tag=0,ii&&s&&ti(t),wa(null,t,r,n),t=t.child),t;case 16:o=t.elementType;e:{switch(Va(e,t),e=t.pendingProps,o=(r=o._init)(o._payload),t.type=o,r=t.tag=function(e){if("function"==typeof e)return Nc(e)?1:0;if(null!=e){if((e=e.$$typeof)===T)return 11;if(e===R)return 14}return 2}(o),e=na(o,e),r){case 0:t=Ca(null,t,o,e,n);break e;case 1:t=Ea(null,t,o,e,n);break e;case 11:t=ka(null,t,o,e,n);break e;case 14:t=xa(null,t,o,na(o.type,e),n);break e}throw Error(i(306,o,""))}return t;case 0:return o=t.type,r=t.pendingProps,Ca(e,t,o,r=t.elementType===o?r:na(o,r),n);case 1:return o=t.type,r=t.pendingProps,Ea(e,t,o,r=t.elementType===o?r:na(o,r),n);case 3:e:{if(Da(t),null===e)throw Error(i(387));o=t.pendingProps,r=(s=t.memoizedState).element,Fi(e,t),Vi(t,o,null,n);var a=t.memoizedState;if(o=a.element,s.isDehydrated){if(s={element:o,isDehydrated:!1,cache:a.cache,pendingSuspenseBoundaries:a.pendingSuspenseBoundaries,transitions:a.transitions},t.updateQueue.baseState=s,t.memoizedState=s,256&t.flags){t=La(e,t,o,n,r=ca(Error(i(423)),t));break e}if(o!==r){t=La(e,t,o,n,r=ca(Error(i(424)),t));break e}for(ri=dr(t.stateNode.containerInfo.firstChild),oi=t,ii=!0,si=null,n=xi(t,null,o,n),t.child=n;n;)n.flags=-3&n.flags|4096,n=n.sibling}else{if(mi(),o===r){t=qa(e,t,n);break e}wa(e,t,o,n)}t=t.child}return t;case 5:return Xi(t),null===e&&di(t),o=t.type,r=t.pendingProps,s=null!==e?e.memoizedProps:null,a=r.children,or(o,r)?a=null:null!==s&&or(o,s)&&(t.flags|=32),Aa(e,t),wa(e,t,a,n),t.child;case 6:return null===e&&di(t),null;case 13:return Ma(e,t,n);case 4:return Ki(t,t.stateNode.containerInfo),o=t.pendingProps,null===e?t.child=ki(t,null,o,n):wa(e,t,o,n),t.child;case 11:return o=t.type,r=t.pendingProps,ka(e,t,o,r=t.elementType===o?r:na(o,r),n);case 7:return wa(e,t,t.pendingProps,n),t.child;case 8:case 12:return wa(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(o=t.type._context,r=t.pendingProps,s=t.memoizedProps,a=r.value,Er(_i,o._currentValue),o._currentValue=a,null!==s)if(ao(s.value,a)){if(s.children===r.children&&!Lr.current){t=qa(e,t,n);break e}}else for(null!==(s=t.child)&&(s.return=t);null!==s;){var l=s.dependencies;if(null!==l){a=s.child;for(var c=l.firstContext;null!==c;){if(c.context===o){if(1===s.tag){(c=Bi(-1,n&-n)).tag=2;var d=s.updateQueue;if(null!==d){var u=(d=d.shared).pending;null===u?c.next=c:(c.next=u.next,u.next=c),d.pending=c}}s.lanes|=n,null!==(c=s.alternate)&&(c.lanes|=n),Di(s.return,n,t),l.lanes|=n;break}c=c.next}}else if(10===s.tag)a=s.type===t.type?null:s.child;else if(18===s.tag){if(null===(a=s.return))throw Error(i(341));a.lanes|=n,null!==(l=a.alternate)&&(l.lanes|=n),Di(a,n,t),a=s.sibling}else a=s.child;if(null!==a)a.return=s;else for(a=s;null!==a;){if(a===t){a=null;break}if(null!==(s=a.sibling)){s.return=a.return,a=s;break}a=a.return}s=a}wa(e,t,r.children,n),t=t.child}return t;case 9:return r=t.type,o=t.pendingProps.children,Li(t,n),o=o(r=Ri(r)),t.flags|=1,wa(e,t,o,n),t.child;case 14:return r=na(o=t.type,t.pendingProps),xa(e,t,o,r=na(o.type,r),n);case 15:return _a(e,t,t.type,t.pendingProps,n);case 17:return o=t.type,r=t.pendingProps,r=t.elementType===o?r:na(o,r),Va(e,t),t.tag=1,jr(o)?(e=!0,Mr(t)):e=!1,Li(t,n),sa(t,o,r),la(t,o,r,n),Ta(null,t,o,!0,e,n);case 19:return $a(e,t,n);case 22:return Sa(e,t,n)}throw Error(i(156,t.tag))};var Wc="function"==typeof reportError?reportError:function(e){console.error(e)};function Zc(e){this._internalRoot=e}function Qc(e){this._internalRoot=e}function Kc(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType)}function Yc(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function Xc(){}function Jc(e,t,n,o,r){var i=n._reactRootContainer;if(i){var s=i;if("function"==typeof r){var a=r;r=function(){var e=qc(s);a.call(e)}}Vc(t,s,e,r)}else s=function(e,t,n,o,r){if(r){if("function"==typeof o){var i=o;o=function(){var e=qc(s);i.call(e)}}var s=$c(t,o,e,0,null,!1,0,"",Xc);return e._reactRootContainer=s,e[hr]=s.current,Vo(8===e.nodeType?e.parentNode:e),dc(),s}for(;r=e.lastChild;)e.removeChild(r);if("function"==typeof o){var a=o;o=function(){var e=qc(l);a.call(e)}}var l=Uc(e,0,!1,null,0,!1,0,"",Xc);return e._reactRootContainer=l,e[hr]=l.current,Vo(8===e.nodeType?e.parentNode:e),dc((function(){Vc(t,l,n,o)})),l}(n,t,e,r,o);return qc(s)}Qc.prototype.render=Zc.prototype.render=function(e){var t=this._internalRoot;if(null===t)throw Error(i(409));Vc(e,t,null,null)},Qc.prototype.unmount=Zc.prototype.unmount=function(){var e=this._internalRoot;if(null!==e){this._internalRoot=null;var t=e.containerInfo;dc((function(){Vc(null,e,null,null)})),t[hr]=null}},Qc.prototype.unstable_scheduleHydration=function(e){if(e){var t=St();e={blockedOn:null,target:e,priority:t};for(var n=0;n<jt.length&&0!==t&&t<jt[n].priority;n++);jt.splice(n,0,e),0===n&&Mt(e)}},kt=function(e){switch(e.tag){case 3:var t=e.stateNode;if(t.current.memoizedState.isDehydrated){var n=ut(t.pendingLanes);0!==n&&(vt(t,1|n),oc(t,Ye()),!(6&Tl)&&($l=Ye()+500,Vr()))}break;case 13:dc((function(){var t=Oi(e,1);if(null!==t){var n=ec();nc(t,e,1,n)}})),Gc(e,1)}},xt=function(e){if(13===e.tag){var t=Oi(e,134217728);if(null!==t)nc(t,e,134217728,ec());Gc(e,134217728)}},_t=function(e){if(13===e.tag){var t=tc(e),n=Oi(e,t);if(null!==n)nc(n,e,t,ec());Gc(e,t)}},St=function(){return yt},At=function(e,t){var n=yt;try{return yt=e,t()}finally{yt=n}},xe=function(e,t,n){switch(t){case"input":if(X(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var o=n[t];if(o!==e&&o.form===e.form){var r=xr(o);if(!r)throw Error(i(90));W(o),X(o,r)}}}break;case"textarea":ie(e,n);break;case"select":null!=(t=n.value)&&ne(e,!!n.multiple,t,!1)}},Te=cc,De=dc;var ed={usingClientEntryPoint:!1,Events:[wr,kr,xr,Ce,Ee,cc]},td={findFiberByHostInstance:yr,bundleType:0,version:"18.3.1",rendererPackageName:"react-dom"},nd={bundleType:td.bundleType,version:td.version,rendererPackageName:td.rendererPackageName,rendererConfig:td.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setErrorHandler:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:w.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=He(e))?null:e.stateNode},findFiberByHostInstance:td.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null,reconcilerVersion:"18.3.1-next-f1338f8080-20240426"};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var od=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!od.isDisabled&&od.supportsFiber)try{rt=od.inject(nd),it=od}catch(de){}}t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=ed,t.createPortal=function(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!Kc(t))throw Error(i(200));return function(e,t,n){var o=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:x,key:null==o?null:""+o,children:e,containerInfo:t,implementation:n}}(e,t,null,n)},t.createRoot=function(e,t){if(!Kc(e))throw Error(i(299));var n=!1,o="",r=Wc;return null!=t&&(!0===t.unstable_strictMode&&(n=!0),void 0!==t.identifierPrefix&&(o=t.identifierPrefix),void 0!==t.onRecoverableError&&(r=t.onRecoverableError)),t=Uc(e,1,!1,null,0,n,0,o,r),e[hr]=t.current,Vo(8===e.nodeType?e.parentNode:e),new Zc(t)},t.findDOMNode=function(e){if(null==e)return null;if(1===e.nodeType)return e;var t=e._reactInternals;if(void 0===t){if("function"==typeof e.render)throw Error(i(188));throw e=Object.keys(e).join(","),Error(i(268,e))}return e=null===(e=He(t))?null:e.stateNode},t.flushSync=function(e){return dc(e)},t.hydrate=function(e,t,n){if(!Yc(t))throw Error(i(200));return Jc(null,e,t,!0,n)},t.hydrateRoot=function(e,t,n){if(!Kc(e))throw Error(i(405));var o=null!=n&&n.hydratedSources||null,r=!1,s="",a=Wc;if(null!=n&&(!0===n.unstable_strictMode&&(r=!0),void 0!==n.identifierPrefix&&(s=n.identifierPrefix),void 0!==n.onRecoverableError&&(a=n.onRecoverableError)),t=$c(t,null,e,1,null!=n?n:null,r,0,s,a),e[hr]=t.current,Vo(e),o)for(e=0;e<o.length;e++)r=(r=(n=o[e])._getVersion)(n._source),null==t.mutableSourceEagerHydrationData?t.mutableSourceEagerHydrationData=[n,r]:t.mutableSourceEagerHydrationData.push(n,r);return new Qc(t)},t.render=function(e,t,n){if(!Yc(t))throw Error(i(200));return Jc(null,e,t,!1,n)},t.unmountComponentAtNode=function(e){if(!Yc(e))throw Error(i(40));return!!e._reactRootContainer&&(dc((function(){Jc(null,null,e,!1,(function(){e._reactRootContainer=null,e[hr]=null}))})),!0)},t.unstable_batchedUpdates=cc,t.unstable_renderSubtreeIntoContainer=function(e,t,n,o){if(!Yc(n))throw Error(i(200));if(null==e||void 0===e._reactInternals)throw Error(i(38));return Jc(e,t,n,!1,o)},t.version="18.3.1-next-f1338f8080-20240426"},5338:(e,t,n)=>{"use strict";var o=n(961);t.createRoot=o.createRoot,t.hydrateRoot=o.hydrateRoot},961:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(2551)},115:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,o="function"==typeof Set,r="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function i(e,s){if(e===s)return!0;if(e&&s&&"object"==typeof e&&"object"==typeof s){if(e.constructor!==s.constructor)return!1;var a,l,c,d;if(Array.isArray(e)){if((a=e.length)!=s.length)return!1;for(l=a;0!=l--;)if(!i(e[l],s[l]))return!1;return!0}if(n&&e instanceof Map&&s instanceof Map){if(e.size!==s.size)return!1;for(d=e.entries();!(l=d.next()).done;)if(!s.has(l.value[0]))return!1;for(d=e.entries();!(l=d.next()).done;)if(!i(l.value[1],s.get(l.value[0])))return!1;return!0}if(o&&e instanceof Set&&s instanceof Set){if(e.size!==s.size)return!1;for(d=e.entries();!(l=d.next()).done;)if(!s.has(l.value[0]))return!1;return!0}if(r&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(s)){if((a=e.length)!=s.length)return!1;for(l=a;0!=l--;)if(e[l]!==s[l])return!1;return!0}if(e.constructor===RegExp)return e.source===s.source&&e.flags===s.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof s.valueOf)return e.valueOf()===s.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof s.toString)return e.toString()===s.toString();if((a=(c=Object.keys(e)).length)!==Object.keys(s).length)return!1;for(l=a;0!=l--;)if(!Object.prototype.hasOwnProperty.call(s,c[l]))return!1;if(t&&e instanceof Element)return!1;for(l=a;0!=l--;)if(("_owner"!==c[l]&&"__v"!==c[l]&&"__o"!==c[l]||!e.$$typeof)&&!i(e[c[l]],s[c[l]]))return!1;return!0}return e!=e&&s!=s}e.exports=function(e,t){try{return i(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},545:(e,t,n)=>{"use strict";n.d(t,{mg:()=>J,vd:()=>H});var o=n(6540),r=n(5556),i=n.n(r),s=n(115),a=n.n(s),l=n(311),c=n.n(l),d=n(2833),u=n.n(d);function p(){return p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},p.apply(this,arguments)}function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function h(e,t){if(null==e)return{};var n,o,r={},i=Object.keys(e);for(o=0;o<i.length;o++)t.indexOf(n=i[o])>=0||(r[n]=e[n]);return r}var g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},b={rel:["amphtml","canonical","alternate"]},v={type:["application/ld+json"]},y={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},w=Object.keys(g).map((function(e){return g[e]})),k={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},x=Object.keys(k).reduce((function(e,t){return e[k[t]]=t,e}),{}),_=function(e,t){for(var n=e.length-1;n>=0;n-=1){var o=e[n];if(Object.prototype.hasOwnProperty.call(o,t))return o[t]}return null},S=function(e){var t=_(e,g.TITLE),n=_(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var o=_(e,"defaultTitle");return t||o||void 0},A=function(e){return _(e,"onChangeClientState")||function(){}},C=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return p({},e,t)}),{})},E=function(e,t){return t.filter((function(e){return void 0!==e[g.BASE]})).map((function(e){return e[g.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var o=Object.keys(n),r=0;r<o.length;r+=1){var i=o[r].toLowerCase();if(-1!==e.indexOf(i)&&n[i])return t.concat(n)}return t}),[])},T=function(e,t,n){var o={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var r={};n.filter((function(e){for(var n,i=Object.keys(e),s=0;s<i.length;s+=1){var a=i[s],l=a.toLowerCase();-1===t.indexOf(l)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===l&&"stylesheet"===e[l].toLowerCase()||(n=l),-1===t.indexOf(a)||"innerHTML"!==a&&"cssText"!==a&&"itemprop"!==a||(n=a)}if(!n||!e[n])return!1;var c=e[n].toLowerCase();return o[n]||(o[n]={}),r[n]||(r[n]={}),!o[n][c]&&(r[n][c]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var i=Object.keys(r),s=0;s<i.length;s+=1){var a=i[s],l=p({},o[a],r[a]);o[a]=l}return e}),[]).reverse()},D=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},L=function(e){return Array.isArray(e)?e.join(""):e},R=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),o=0;o<n.length;o+=1)if(t[n[o]]&&t[n[o]].includes(e[n[o]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},N=function(e,t){var n;return p({},e,((n={})[t]=void 0,n))},j=[g.NOSCRIPT,g.SCRIPT,g.STYLE],P=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},O=function(e){return Object.keys(e).reduce((function(t,n){var o=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+o:o}),"")},I=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[k[n]||n]=e[n],t}),t)},M=function(e,t){return t.map((function(t,n){var r,i=((r={key:n})["data-rh"]=!0,r);return Object.keys(t).forEach((function(e){var n=k[e]||e;"innerHTML"===n||"cssText"===n?i.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:i[n]=t[e]})),o.createElement(e,i)}))},F=function(e,t,n){switch(e){case g.TITLE:return{toComponent:function(){return n=t.titleAttributes,(r={key:e=t.title})["data-rh"]=!0,i=I(n,r),[o.createElement(g.TITLE,i,e)];var e,n,r,i},toString:function(){return function(e,t,n,o){var r=O(n),i=L(t);return r?"<"+e+' data-rh="true" '+r+">"+P(i,o)+"</"+e+">":"<"+e+' data-rh="true">'+P(i,o)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return I(t)},toString:function(){return O(t)}};default:return{toComponent:function(){return M(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,o){var r=Object.keys(o).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var r=void 0===o[t]?t:t+'="'+P(o[t],n)+'"';return e?e+" "+r:r}),""),i=o.innerHTML||o.cssText||"",s=-1===j.indexOf(e);return t+"<"+e+' data-rh="true" '+r+(s?"/>":">"+i+"</"+e+">")}),"")}(e,t,n)}}}},B=function(e){var t=e.baseTag,n=e.bodyAttributes,o=e.encode,r=e.htmlAttributes,i=e.noscriptTags,s=e.styleTags,a=e.title,l=void 0===a?"":a,c=e.titleAttributes,d=e.linkTags,u=e.metaTags,p=e.scriptTags,f={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,o=e.encode,r=R(e.metaTags,y),i=R(t,b),s=R(n,v);return{priorityMethods:{toComponent:function(){return[].concat(M(g.META,r.priority),M(g.LINK,i.priority),M(g.SCRIPT,s.priority))},toString:function(){return F(g.META,r.priority,o)+" "+F(g.LINK,i.priority,o)+" "+F(g.SCRIPT,s.priority,o)}},metaTags:r.default,linkTags:i.default,scriptTags:s.default}}(e);f=m.priorityMethods,d=m.linkTags,u=m.metaTags,p=m.scriptTags}return{priority:f,base:F(g.BASE,t,o),bodyAttributes:F("bodyAttributes",n,o),htmlAttributes:F("htmlAttributes",r,o),link:F(g.LINK,d,o),meta:F(g.META,u,o),noscript:F(g.NOSCRIPT,i,o),script:F(g.SCRIPT,p,o),style:F(g.STYLE,s,o),title:F(g.TITLE,{title:l,titleAttributes:c},o)}},U=[],z=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?U:n.instances},add:function(e){(n.canUseDOM?U:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?U:n.instances).indexOf(e);(n.canUseDOM?U:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=B({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},$=o.createContext({}),V=i().shape({setHelmet:i().func,helmetInstances:i().shape({get:i().func,add:i().func,remove:i().func})}),q="undefined"!=typeof document,H=function(e){function t(n){var o;return(o=e.call(this,n)||this).helmetData=new z(o.props.context,t.canUseDOM),o}return f(t,e),t.prototype.render=function(){return o.createElement($.Provider,{value:this.helmetData.value},this.props.children)},t}(o.Component);H.canUseDOM=q,H.propTypes={context:i().shape({helmet:i().shape()}),children:i().node.isRequired},H.defaultProps={context:{}},H.displayName="HelmetProvider";var G=function(e,t){var n,o=document.head||document.querySelector(g.HEAD),r=o.querySelectorAll(e+"[data-rh]"),i=[].slice.call(r),s=[];return t&&t.length&&t.forEach((function(t){var o=document.createElement(e);for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&("innerHTML"===r?o.innerHTML=t.innerHTML:"cssText"===r?o.styleSheet?o.styleSheet.cssText=t.cssText:o.appendChild(document.createTextNode(t.cssText)):o.setAttribute(r,void 0===t[r]?"":t[r]));o.setAttribute("data-rh","true"),i.some((function(e,t){return n=t,o.isEqualNode(e)}))?i.splice(n,1):s.push(o)})),i.forEach((function(e){return e.parentNode.removeChild(e)})),s.forEach((function(e){return o.appendChild(e)})),{oldTags:i,newTags:s}},W=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var o=n.getAttribute("data-rh"),r=o?o.split(","):[],i=[].concat(r),s=Object.keys(t),a=0;a<s.length;a+=1){var l=s[a],c=t[l]||"";n.getAttribute(l)!==c&&n.setAttribute(l,c),-1===r.indexOf(l)&&r.push(l);var d=i.indexOf(l);-1!==d&&i.splice(d,1)}for(var u=i.length-1;u>=0;u-=1)n.removeAttribute(i[u]);r.length===i.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==s.join(",")&&n.setAttribute("data-rh",s.join(","))}},Z=function(e,t){var n=e.baseTag,o=e.htmlAttributes,r=e.linkTags,i=e.metaTags,s=e.noscriptTags,a=e.onChangeClientState,l=e.scriptTags,c=e.styleTags,d=e.title,u=e.titleAttributes;W(g.BODY,e.bodyAttributes),W(g.HTML,o),function(e,t){void 0!==e&&document.title!==e&&(document.title=L(e)),W(g.TITLE,t)}(d,u);var p={baseTag:G(g.BASE,n),linkTags:G(g.LINK,r),metaTags:G(g.META,i),noscriptTags:G(g.NOSCRIPT,s),scriptTags:G(g.SCRIPT,l),styleTags:G(g.STYLE,c)},f={},m={};Object.keys(p).forEach((function(e){var t=p[e],n=t.newTags,o=t.oldTags;n.length&&(f[e]=n),o.length&&(m[e]=p[e].oldTags)})),t&&t(),a(e,f,m)},Q=null,K=function(e){function t(){for(var t,n=arguments.length,o=new Array(n),r=0;r<n;r++)o[r]=arguments[r];return(t=e.call.apply(e,[this].concat(o))||this).rendered=!1,t}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!u()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,o=n.setHelmet,r=null,i=(e=n.helmetInstances.get().map((function(e){var t=p({},e.props);return delete t.context,t})),{baseTag:E(["href"],e),bodyAttributes:C("bodyAttributes",e),defer:_(e,"defer"),encode:_(e,"encodeSpecialCharacters"),htmlAttributes:C("htmlAttributes",e),linkTags:T(g.LINK,["rel","href"],e),metaTags:T(g.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:T(g.NOSCRIPT,["innerHTML"],e),onChangeClientState:A(e),scriptTags:T(g.SCRIPT,["src","innerHTML"],e),styleTags:T(g.STYLE,["cssText"],e),title:S(e),titleAttributes:C("titleAttributes",e),prioritizeSeoTags:D(e,"prioritizeSeoTags")});H.canUseDOM?(t=i,Q&&cancelAnimationFrame(Q),t.defer?Q=requestAnimationFrame((function(){Z(t,(function(){Q=null}))})):(Z(t),Q=null)):B&&(r=B(i)),o(r)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(o.Component);K.propTypes={context:V.isRequired},K.displayName="HelmetDispatcher";var Y=["children"],X=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}f(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!a()(N(this.props,"helmetData"),N(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:t};case g.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,o=e.arrayTypeChildren;return p({},o,((t={})[n.type]=[].concat(o[n.type]||[],[p({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,o=e.child,r=e.newProps,i=e.newChildProps,s=e.nestedChildren;switch(o.type){case g.TITLE:return p({},r,((t={})[o.type]=s,t.titleAttributes=p({},i),t));case g.BODY:return p({},r,{bodyAttributes:p({},i)});case g.HTML:return p({},r,{htmlAttributes:p({},i)});default:return p({},r,((n={})[o.type]=p({},i),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=p({},t);return Object.keys(e).forEach((function(t){var o;n=p({},n,((o={})[t]=e[t],o))})),n},n.warnOnInvalidChildren=function(e,t){return c()(w.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+w.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),c()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,r={};return o.Children.forEach(e,(function(e){if(e&&e.props){var o=e.props,i=o.children,s=h(o,Y),a=Object.keys(s).reduce((function(e,t){return e[x[t]||t]=s[t],e}),{}),l=e.type;switch("symbol"==typeof l?l=l.toString():n.warnOnInvalidChildren(e,i),l){case g.FRAGMENT:t=n.mapChildrenToProps(i,t);break;case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:r=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:r,newChildProps:a,nestedChildren:i});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:a,nestedChildren:i})}}})),this.mapArrayTypeChildrenToProps(r,t)},n.render=function(){var e=this.props,t=e.children,n=h(e,X),r=p({},n),i=n.helmetData;return t&&(r=this.mapChildrenToProps(t,r)),!i||i instanceof z||(i=new z(i.context,i.instances)),i?o.createElement(K,p({},r,{context:i.value,helmetData:void 0})):o.createElement($.Consumer,null,(function(e){return o.createElement(K,p({},r,{context:e}))}))},t}(o.Component);J.propTypes={base:i().object,bodyAttributes:i().object,children:i().oneOfType([i().arrayOf(i().node),i().node]),defaultTitle:i().string,defer:i().bool,encodeSpecialCharacters:i().bool,htmlAttributes:i().object,link:i().arrayOf(i().object),meta:i().arrayOf(i().object),noscript:i().arrayOf(i().object),onChangeClientState:i().func,script:i().arrayOf(i().object),style:i().arrayOf(i().object),title:i().string,titleAttributes:i().object,titleTemplate:i().string,prioritizeSeoTags:i().bool,helmetData:i().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},2799:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,o=n?Symbol.for("react.element"):60103,r=n?Symbol.for("react.portal"):60106,i=n?Symbol.for("react.fragment"):60107,s=n?Symbol.for("react.strict_mode"):60108,a=n?Symbol.for("react.profiler"):60114,l=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,d=n?Symbol.for("react.async_mode"):60111,u=n?Symbol.for("react.concurrent_mode"):60111,p=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,h=n?Symbol.for("react.memo"):60115,g=n?Symbol.for("react.lazy"):60116,b=n?Symbol.for("react.block"):60121,v=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function k(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case o:switch(e=e.type){case d:case u:case i:case a:case s:case f:return e;default:switch(e=e&&e.$$typeof){case c:case p:case g:case h:case l:return e;default:return t}}case r:return t}}}function x(e){return k(e)===u}t.AsyncMode=d,t.ConcurrentMode=u,t.ContextConsumer=c,t.ContextProvider=l,t.Element=o,t.ForwardRef=p,t.Fragment=i,t.Lazy=g,t.Memo=h,t.Portal=r,t.Profiler=a,t.StrictMode=s,t.Suspense=f,t.isAsyncMode=function(e){return x(e)||k(e)===d},t.isConcurrentMode=x,t.isContextConsumer=function(e){return k(e)===c},t.isContextProvider=function(e){return k(e)===l},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===o},t.isForwardRef=function(e){return k(e)===p},t.isFragment=function(e){return k(e)===i},t.isLazy=function(e){return k(e)===g},t.isMemo=function(e){return k(e)===h},t.isPortal=function(e){return k(e)===r},t.isProfiler=function(e){return k(e)===a},t.isStrictMode=function(e){return k(e)===s},t.isSuspense=function(e){return k(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===i||e===u||e===a||e===s||e===f||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===g||e.$$typeof===h||e.$$typeof===l||e.$$typeof===c||e.$$typeof===p||e.$$typeof===v||e.$$typeof===y||e.$$typeof===w||e.$$typeof===b)},t.typeOf=k},4363:(e,t,n)=>{"use strict";e.exports=n(2799)},3259:(e,t,n)=>{"use strict";function o(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function r(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(){return s=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},s.apply(this,arguments)}var a=n(6540),l=[],c=[];var d=a.createContext(null);function u(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function p(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(o){var r=u(e[o]);r.loading?t.loading=!0:(t.loaded[o]=r.loaded,t.error=r.error),n.push(r.promise),r.promise.then((function(e){t.loaded[o]=e})).catch((function(e){t.error=e}))}))}catch(o){t.error=o}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function f(e,t){return a.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var u,p;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=s({loader:null,loading:null,delay:200,timeout:null,render:f,webpack:null,modules:null},t),h=null;function g(){return h||(h=e(m.loader)),h.promise}return l.push(g),"function"==typeof m.webpack&&c.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return g()})),p=u=function(t){function n(n){var o;return i(r(r(o=t.call(this,n)||this)),"retry",(function(){o.setState({error:null,loading:!0,timedOut:!1}),h=e(m.loader),o._loadModule()})),g(),o.state={error:h.error,pastDelay:!1,timedOut:!1,loading:h.loading,loaded:h.loaded},o}o(n,t),n.preload=function(){return g()};var s=n.prototype;return s.UNSAFE_componentWillMount=function(){this._loadModule()},s.componentDidMount=function(){this._mounted=!0},s._loadModule=function(){var e=this;if(this.context&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.report(t)})),h.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:h.error,loaded:h.loaded,loading:h.loading}),e._clearTimeouts()};h.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},s.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},s._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},s.render=function(){return this.state.loading||this.state.error?a.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(a.Component),i(u,"contextType",d),p}function h(e){return m(u,e)}h.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(p,e)};var g=function(e){function t(){return e.apply(this,arguments)||this}return o(t,e),t.prototype.render=function(){return a.createElement(d.Provider,{value:{report:this.props.report}},a.Children.only(this.props.children))},t}(a.Component);function b(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return b(e)}))}h.Capture=g,h.preloadAll=function(){return new Promise((function(e,t){b(l).then(e,t)}))},h.preloadReady=function(){return new Promise((function(e,t){b(c).then(e,e)}))},e.exports=h},2831:(e,t,n)=>{"use strict";n.d(t,{u:()=>s,v:()=>a});var o=n(6347),r=n(8168),i=n(6540);function s(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var r=e.path?(0,o.B6)(t,e):n.length?n[n.length-1].match:o.Ix.computeRootMatch(t);return r&&(n.push({route:e,match:r}),e.routes&&s(e.routes,t,n)),r})),n}function a(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?i.createElement(o.dO,n,e.map((function(e,n){return i.createElement(o.qh,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,r.A)({},n,{},t,{route:e})):i.createElement(e.component,(0,r.A)({},n,t,{route:e}))}})}))):null}},4625:(e,t,n)=>{"use strict";n.d(t,{I9:()=>u,Kd:()=>d,N_:()=>b,k2:()=>w});var o=n(6347),r=n(2892),i=n(6540),s=n(1513),a=n(8168),l=n(8587),c=n(1561),d=function(e){function t(){for(var t,n=arguments.length,o=new Array(n),r=0;r<n;r++)o[r]=arguments[r];return(t=e.call.apply(e,[this].concat(o))||this).history=(0,s.zR)(t.props),t}return(0,r.A)(t,e),t.prototype.render=function(){return i.createElement(o.Ix,{history:this.history,children:this.props.children})},t}(i.Component);var u=function(e){function t(){for(var t,n=arguments.length,o=new Array(n),r=0;r<n;r++)o[r]=arguments[r];return(t=e.call.apply(e,[this].concat(o))||this).history=(0,s.TM)(t.props),t}return(0,r.A)(t,e),t.prototype.render=function(){return i.createElement(o.Ix,{history:this.history,children:this.props.children})},t}(i.Component);var p=function(e,t){return"function"==typeof e?e(t):e},f=function(e,t){return"string"==typeof e?(0,s.yJ)(e,null,null,t):e},m=function(e){return e},h=i.forwardRef;void 0===h&&(h=m);var g=h((function(e,t){var n=e.innerRef,o=e.navigate,r=e.onClick,s=(0,l.A)(e,["innerRef","navigate","onClick"]),c=s.target,d=(0,a.A)({},s,{onClick:function(e){try{r&&r(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||c&&"_self"!==c||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),o())}});return d.ref=m!==h&&t||n,i.createElement("a",d)}));var b=h((function(e,t){var n=e.component,r=void 0===n?g:n,d=e.replace,u=e.to,b=e.innerRef,v=(0,l.A)(e,["component","replace","to","innerRef"]);return i.createElement(o.XZ.Consumer,null,(function(e){e||(0,c.A)(!1);var n=e.history,o=f(p(u,e.location),e.location),l=o?n.createHref(o):"",g=(0,a.A)({},v,{href:l,navigate:function(){var t=p(u,e.location),o=(0,s.AO)(e.location)===(0,s.AO)(f(t));(d||o?n.replace:n.push)(t)}});return m!==h?g.ref=t||b:g.innerRef=b,i.createElement(r,g)}))})),v=function(e){return e},y=i.forwardRef;void 0===y&&(y=v);var w=y((function(e,t){var n=e["aria-current"],r=void 0===n?"page":n,s=e.activeClassName,d=void 0===s?"active":s,u=e.activeStyle,m=e.className,h=e.exact,g=e.isActive,w=e.location,k=e.sensitive,x=e.strict,_=e.style,S=e.to,A=e.innerRef,C=(0,l.A)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return i.createElement(o.XZ.Consumer,null,(function(e){e||(0,c.A)(!1);var n=w||e.location,s=f(p(S,n),n),l=s.pathname,E=l&&l.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),T=E?(0,o.B6)(n.pathname,{path:E,exact:h,sensitive:k,strict:x}):null,D=!!(g?g(T,n):T),L="function"==typeof m?m(D):m,R="function"==typeof _?_(D):_;D&&(L=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(L,d),R=(0,a.A)({},R,u));var N=(0,a.A)({"aria-current":D&&r||null,className:L,style:R,to:s},C);return v!==y?N.ref=t||A:N.innerRef=A,i.createElement(b,N)}))}))},6347:(e,t,n)=>{"use strict";n.d(t,{B6:()=>_,Ix:()=>y,W6:()=>N,XZ:()=>v,dO:()=>L,qh:()=>S,zy:()=>j});var o=n(2892),r=n(6540),i=n(5556),s=n.n(i),a=n(1513),l=n(1561),c=n(8168),d=n(8505),u=n.n(d),p=(n(4363),n(8587)),f=(n(4146),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var h=r.createContext||function(e,t){var n,i,a="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",l=function(e){function n(){for(var t,n,o,r=arguments.length,i=new Array(r),s=0;s<r;s++)i[s]=arguments[s];return(t=e.call.apply(e,[this].concat(i))||this).emitter=(n=t.props.value,o=[],{on:function(e){o.push(e)},off:function(e){o=o.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,o.forEach((function(e){return e(n,t)}))}}),t}(0,o.A)(n,e);var r=n.prototype;return r.getChildContext=function(){var e;return(e={})[a]=this.emitter,e},r.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,o=this.props.value,r=e.value;((i=o)===(s=r)?0!==i||1/i==1/s:i!=i&&s!=s)?n=0:(n="function"==typeof t?t(o,r):f,0!==(n|=0)&&this.emitter.set(e.value,n))}var i,s},r.render=function(){return this.props.children},n}(r.Component);l.childContextTypes=((n={})[a]=s().object.isRequired,n);var c=function(t){function n(){for(var e,n=arguments.length,o=new Array(n),r=0;r<n;r++)o[r]=arguments[r];return(e=t.call.apply(t,[this].concat(o))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){(0|e.observedBits)&n&&e.setState({value:e.getValue()})},e}(0,o.A)(n,t);var r=n.prototype;return r.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?f:t},r.componentDidMount=function(){this.context[a]&&this.context[a].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?f:e},r.componentWillUnmount=function(){this.context[a]&&this.context[a].off(this.onUpdate)},r.getValue=function(){return this.context[a]?this.context[a].get():e},r.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(r.Component);return c.contextTypes=((i={})[a]=s().object,i),{Provider:l,Consumer:c}},g=function(e){var t=h();return t.displayName=e,t},b=g("Router-History"),v=g("Router"),y=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,o.A)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return r.createElement(v.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},r.createElement(b.Provider,{children:this.props.children||null,value:this.props.history}))},t}(r.Component);r.Component;r.Component;var w={},k=1e4,x=0;function _(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,o=n.path,r=n.exact,i=void 0!==r&&r,s=n.strict,a=void 0!==s&&s,l=n.sensitive,c=void 0!==l&&l;return[].concat(o).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var o=function(e,t){var n=""+t.end+t.strict+t.sensitive,o=w[n]||(w[n]={});if(o[e])return o[e];var r=[],i={regexp:u()(e,r,t),keys:r};return x<k&&(o[e]=i,x++),i}(n,{end:i,strict:a,sensitive:c}),r=o.regexp,s=o.keys,l=r.exec(e);if(!l)return null;var d=l[0],p=l.slice(1),f=e===d;return i&&!f?null:{path:n,url:"/"===n&&""===d?"/":d,isExact:f,params:s.reduce((function(e,t,n){return e[t.name]=p[n],e}),{})}}),null)}var S=function(e){function t(){return e.apply(this,arguments)||this}return(0,o.A)(t,e),t.prototype.render=function(){var e=this;return r.createElement(v.Consumer,null,(function(t){t||(0,l.A)(!1);var n=e.props.location||t.location,o=e.props.computedMatch?e.props.computedMatch:e.props.path?_(n.pathname,e.props):t.match,i=(0,c.A)({},t,{location:n,match:o}),s=e.props,a=s.children,d=s.component,u=s.render;return Array.isArray(a)&&function(e){return 0===r.Children.count(e)}(a)&&(a=null),r.createElement(v.Provider,{value:i},i.match?a?"function"==typeof a?a(i):a:d?r.createElement(d,i):u?u(i):null:"function"==typeof a?a(i):null)}))},t}(r.Component);function A(e){return"/"===e.charAt(0)?e:"/"+e}function C(e,t){if(!e)return t;var n=A(e);return 0!==t.pathname.indexOf(n)?t:(0,c.A)({},t,{pathname:t.pathname.substr(n.length)})}function E(e){return"string"==typeof e?e:(0,a.AO)(e)}function T(e){return function(){(0,l.A)(!1)}}function D(){}r.Component;var L=function(e){function t(){return e.apply(this,arguments)||this}return(0,o.A)(t,e),t.prototype.render=function(){var e=this;return r.createElement(v.Consumer,null,(function(t){t||(0,l.A)(!1);var n,o,i=e.props.location||t.location;return r.Children.forEach(e.props.children,(function(e){if(null==o&&r.isValidElement(e)){n=e;var s=e.props.path||e.props.from;o=s?_(i.pathname,(0,c.A)({},e.props,{path:s})):t.match}})),o?r.cloneElement(n,{location:i,computedMatch:o}):null}))},t}(r.Component);var R=r.useContext;function N(){return R(b)}function j(){return R(v).location}},8505:(e,t,n)=>{var o=n(4634);e.exports=f,e.exports.parse=i,e.exports.compile=function(e,t){return a(i(e,t),t)},e.exports.tokensToFunction=a,e.exports.tokensToRegExp=p;var r=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function i(e,t){for(var n,o=[],i=0,s=0,a="",d=t&&t.delimiter||"/";null!=(n=r.exec(e));){var u=n[0],p=n[1],f=n.index;if(a+=e.slice(s,f),s=f+u.length,p)a+=p[1];else{var m=e[s],h=n[2],g=n[3],b=n[4],v=n[5],y=n[6],w=n[7];a&&(o.push(a),a="");var k=null!=h&&null!=m&&m!==h,x="+"===y||"*"===y,_="?"===y||"*"===y,S=n[2]||d,A=b||v;o.push({name:g||i++,prefix:h||"",delimiter:S,optional:_,repeat:x,partial:k,asterisk:!!w,pattern:A?c(A):w?".*":"[^"+l(S)+"]+?"})}}return s<e.length&&(a+=e.substr(s)),a&&o.push(a),o}function s(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function a(e,t){for(var n=new Array(e.length),r=0;r<e.length;r++)"object"==typeof e[r]&&(n[r]=new RegExp("^(?:"+e[r].pattern+")$",u(t)));return function(t,r){for(var i="",a=t||{},l=(r||{}).pretty?s:encodeURIComponent,c=0;c<e.length;c++){var d=e[c];if("string"!=typeof d){var u,p=a[d.name];if(null==p){if(d.optional){d.partial&&(i+=d.prefix);continue}throw new TypeError('Expected "'+d.name+'" to be defined')}if(o(p)){if(!d.repeat)throw new TypeError('Expected "'+d.name+'" to not repeat, but received `'+JSON.stringify(p)+"`");if(0===p.length){if(d.optional)continue;throw new TypeError('Expected "'+d.name+'" to not be empty')}for(var f=0;f<p.length;f++){if(u=l(p[f]),!n[c].test(u))throw new TypeError('Expected all "'+d.name+'" to match "'+d.pattern+'", but received `'+JSON.stringify(u)+"`");i+=(0===f?d.prefix:d.delimiter)+u}}else{if(u=d.asterisk?encodeURI(p).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):l(p),!n[c].test(u))throw new TypeError('Expected "'+d.name+'" to match "'+d.pattern+'", but received "'+u+'"');i+=d.prefix+u}}else i+=d}return i}}function l(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function c(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function d(e,t){return e.keys=t,e}function u(e){return e&&e.sensitive?"":"i"}function p(e,t,n){o(t)||(n=t||n,t=[]);for(var r=(n=n||{}).strict,i=!1!==n.end,s="",a=0;a<e.length;a++){var c=e[a];if("string"==typeof c)s+=l(c);else{var p=l(c.prefix),f="(?:"+c.pattern+")";t.push(c),c.repeat&&(f+="(?:"+p+f+")*"),s+=f=c.optional?c.partial?p+"("+f+")?":"(?:"+p+"("+f+"))?":p+"("+f+")"}}var m=l(n.delimiter||"/"),h=s.slice(-m.length)===m;return r||(s=(h?s.slice(0,-m.length):s)+"(?:"+m+"(?=$))?"),s+=i?"$":r&&h?"":"(?="+m+"|$)",d(new RegExp("^"+s,u(n)),t)}function f(e,t,n){return o(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var o=0;o<n.length;o++)t.push({name:o,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return d(e,t)}(e,t):o(e)?function(e,t,n){for(var o=[],r=0;r<e.length;r++)o.push(f(e[r],t,n).source);return d(new RegExp("(?:"+o.join("|")+")",u(n)),t)}(e,t,n):function(e,t,n){return p(i(e,n),t,n)}(e,t,n)}},1020:(e,t,n)=>{"use strict";var o=n(6540),r=Symbol.for("react.element"),i=Symbol.for("react.fragment"),s=Object.prototype.hasOwnProperty,a=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,l={key:!0,ref:!0,__self:!0,__source:!0};function c(e,t,n){var o,i={},c=null,d=null;for(o in void 0!==n&&(c=""+n),void 0!==t.key&&(c=""+t.key),void 0!==t.ref&&(d=t.ref),t)s.call(t,o)&&!l.hasOwnProperty(o)&&(i[o]=t[o]);if(e&&e.defaultProps)for(o in t=e.defaultProps)void 0===i[o]&&(i[o]=t[o]);return{$$typeof:r,type:e,key:c,ref:d,props:i,_owner:a.current}}t.Fragment=i,t.jsx=c,t.jsxs=c},5287:(e,t)=>{"use strict";var n=Symbol.for("react.element"),o=Symbol.for("react.portal"),r=Symbol.for("react.fragment"),i=Symbol.for("react.strict_mode"),s=Symbol.for("react.profiler"),a=Symbol.for("react.provider"),l=Symbol.for("react.context"),c=Symbol.for("react.forward_ref"),d=Symbol.for("react.suspense"),u=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),f=Symbol.iterator;var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h=Object.assign,g={};function b(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}function v(){}function y(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}b.prototype.isReactComponent={},b.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},b.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},v.prototype=b.prototype;var w=y.prototype=new v;w.constructor=y,h(w,b.prototype),w.isPureReactComponent=!0;var k=Array.isArray,x=Object.prototype.hasOwnProperty,_={current:null},S={key:!0,ref:!0,__self:!0,__source:!0};function A(e,t,o){var r,i={},s=null,a=null;if(null!=t)for(r in void 0!==t.ref&&(a=t.ref),void 0!==t.key&&(s=""+t.key),t)x.call(t,r)&&!S.hasOwnProperty(r)&&(i[r]=t[r]);var l=arguments.length-2;if(1===l)i.children=o;else if(1<l){for(var c=Array(l),d=0;d<l;d++)c[d]=arguments[d+2];i.children=c}if(e&&e.defaultProps)for(r in l=e.defaultProps)void 0===i[r]&&(i[r]=l[r]);return{$$typeof:n,type:e,key:s,ref:a,props:i,_owner:_.current}}function C(e){return"object"==typeof e&&null!==e&&e.$$typeof===n}var E=/\/+/g;function T(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function D(e,t,r,i,s){var a=typeof e;"undefined"!==a&&"boolean"!==a||(e=null);var l=!1;if(null===e)l=!0;else switch(a){case"string":case"number":l=!0;break;case"object":switch(e.$$typeof){case n:case o:l=!0}}if(l)return s=s(l=e),e=""===i?"."+T(l,0):i,k(s)?(r="",null!=e&&(r=e.replace(E,"$&/")+"/"),D(s,t,r,"",(function(e){return e}))):null!=s&&(C(s)&&(s=function(e,t){return{$$typeof:n,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(s,r+(!s.key||l&&l.key===s.key?"":(""+s.key).replace(E,"$&/")+"/")+e)),t.push(s)),1;if(l=0,i=""===i?".":i+":",k(e))for(var c=0;c<e.length;c++){var d=i+T(a=e[c],c);l+=D(a,t,r,d,s)}else if(d=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=f&&e[f]||e["@@iterator"])?e:null}(e),"function"==typeof d)for(e=d.call(e),c=0;!(a=e.next()).done;)l+=D(a=a.value,t,r,d=i+T(a,c++),s);else if("object"===a)throw t=String(e),Error("Objects are not valid as a React child (found: "+("[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return l}function L(e,t,n){if(null==e)return e;var o=[],r=0;return D(e,o,"","",(function(e){return t.call(n,e,r++)})),o}function R(e){if(-1===e._status){var t=e._result;(t=t()).then((function(t){0!==e._status&&-1!==e._status||(e._status=1,e._result=t)}),(function(t){0!==e._status&&-1!==e._status||(e._status=2,e._result=t)})),-1===e._status&&(e._status=0,e._result=t)}if(1===e._status)return e._result.default;throw e._result}var N={current:null},j={transition:null},P={ReactCurrentDispatcher:N,ReactCurrentBatchConfig:j,ReactCurrentOwner:_};function O(){throw Error("act(...) is not supported in production builds of React.")}t.Children={map:L,forEach:function(e,t,n){L(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return L(e,(function(){t++})),t},toArray:function(e){return L(e,(function(e){return e}))||[]},only:function(e){if(!C(e))throw Error("React.Children.only expected to receive a single React element child.");return e}},t.Component=b,t.Fragment=r,t.Profiler=s,t.PureComponent=y,t.StrictMode=i,t.Suspense=d,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=P,t.act=O,t.cloneElement=function(e,t,o){if(null==e)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var r=h({},e.props),i=e.key,s=e.ref,a=e._owner;if(null!=t){if(void 0!==t.ref&&(s=t.ref,a=_.current),void 0!==t.key&&(i=""+t.key),e.type&&e.type.defaultProps)var l=e.type.defaultProps;for(c in t)x.call(t,c)&&!S.hasOwnProperty(c)&&(r[c]=void 0===t[c]&&void 0!==l?l[c]:t[c])}var c=arguments.length-2;if(1===c)r.children=o;else if(1<c){l=Array(c);for(var d=0;d<c;d++)l[d]=arguments[d+2];r.children=l}return{$$typeof:n,type:e.type,key:i,ref:s,props:r,_owner:a}},t.createContext=function(e){return(e={$$typeof:l,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null}).Provider={$$typeof:a,_context:e},e.Consumer=e},t.createElement=A,t.createFactory=function(e){var t=A.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:c,render:e}},t.isValidElement=C,t.lazy=function(e){return{$$typeof:p,_payload:{_status:-1,_result:e},_init:R}},t.memo=function(e,t){return{$$typeof:u,type:e,compare:void 0===t?null:t}},t.startTransition=function(e){var t=j.transition;j.transition={};try{e()}finally{j.transition=t}},t.unstable_act=O,t.useCallback=function(e,t){return N.current.useCallback(e,t)},t.useContext=function(e){return N.current.useContext(e)},t.useDebugValue=function(){},t.useDeferredValue=function(e){return N.current.useDeferredValue(e)},t.useEffect=function(e,t){return N.current.useEffect(e,t)},t.useId=function(){return N.current.useId()},t.useImperativeHandle=function(e,t,n){return N.current.useImperativeHandle(e,t,n)},t.useInsertionEffect=function(e,t){return N.current.useInsertionEffect(e,t)},t.useLayoutEffect=function(e,t){return N.current.useLayoutEffect(e,t)},t.useMemo=function(e,t){return N.current.useMemo(e,t)},t.useReducer=function(e,t,n){return N.current.useReducer(e,t,n)},t.useRef=function(e){return N.current.useRef(e)},t.useState=function(e){return N.current.useState(e)},t.useSyncExternalStore=function(e,t,n){return N.current.useSyncExternalStore(e,t,n)},t.useTransition=function(){return N.current.useTransition()},t.version="18.3.1"},6540:(e,t,n)=>{"use strict";e.exports=n(5287)},4848:(e,t,n)=>{"use strict";e.exports=n(1020)},7463:(e,t)=>{"use strict";function n(e,t){var n=e.length;e.push(t);e:for(;0<n;){var o=n-1>>>1,r=e[o];if(!(0<i(r,t)))break e;e[o]=t,e[n]=r,n=o}}function o(e){return 0===e.length?null:e[0]}function r(e){if(0===e.length)return null;var t=e[0],n=e.pop();if(n!==t){e[0]=n;e:for(var o=0,r=e.length,s=r>>>1;o<s;){var a=2*(o+1)-1,l=e[a],c=a+1,d=e[c];if(0>i(l,n))c<r&&0>i(d,l)?(e[o]=d,e[c]=n,o=c):(e[o]=l,e[a]=n,o=a);else{if(!(c<r&&0>i(d,n)))break e;e[o]=d,e[c]=n,o=c}}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}if("object"==typeof performance&&"function"==typeof performance.now){var s=performance;t.unstable_now=function(){return s.now()}}else{var a=Date,l=a.now();t.unstable_now=function(){return a.now()-l}}var c=[],d=[],u=1,p=null,f=3,m=!1,h=!1,g=!1,b="function"==typeof setTimeout?setTimeout:null,v="function"==typeof clearTimeout?clearTimeout:null,y="undefined"!=typeof setImmediate?setImmediate:null;function w(e){for(var t=o(d);null!==t;){if(null===t.callback)r(d);else{if(!(t.startTime<=e))break;r(d),t.sortIndex=t.expirationTime,n(c,t)}t=o(d)}}function k(e){if(g=!1,w(e),!h)if(null!==o(c))h=!0,j(x);else{var t=o(d);null!==t&&P(k,t.startTime-e)}}function x(e,n){h=!1,g&&(g=!1,v(C),C=-1),m=!0;var i=f;try{for(w(n),p=o(c);null!==p&&(!(p.expirationTime>n)||e&&!D());){var s=p.callback;if("function"==typeof s){p.callback=null,f=p.priorityLevel;var a=s(p.expirationTime<=n);n=t.unstable_now(),"function"==typeof a?p.callback=a:p===o(c)&&r(c),w(n)}else r(c);p=o(c)}if(null!==p)var l=!0;else{var u=o(d);null!==u&&P(k,u.startTime-n),l=!1}return l}finally{p=null,f=i,m=!1}}"undefined"!=typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var _,S=!1,A=null,C=-1,E=5,T=-1;function D(){return!(t.unstable_now()-T<E)}function L(){if(null!==A){var e=t.unstable_now();T=e;var n=!0;try{n=A(!0,e)}finally{n?_():(S=!1,A=null)}}else S=!1}if("function"==typeof y)_=function(){y(L)};else if("undefined"!=typeof MessageChannel){var R=new MessageChannel,N=R.port2;R.port1.onmessage=L,_=function(){N.postMessage(null)}}else _=function(){b(L,0)};function j(e){A=e,S||(S=!0,_())}function P(e,n){C=b((function(){e(t.unstable_now())}),n)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){h||m||(h=!0,j(x))},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):E=0<e?Math.floor(1e3/e):5},t.unstable_getCurrentPriorityLevel=function(){return f},t.unstable_getFirstCallbackNode=function(){return o(c)},t.unstable_next=function(e){switch(f){case 1:case 2:case 3:var t=3;break;default:t=f}var n=f;f=t;try{return e()}finally{f=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=function(){},t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=f;f=e;try{return t()}finally{f=n}},t.unstable_scheduleCallback=function(e,r,i){var s=t.unstable_now();switch("object"==typeof i&&null!==i?i="number"==typeof(i=i.delay)&&0<i?s+i:s:i=s,e){case 1:var a=-1;break;case 2:a=250;break;case 5:a=1073741823;break;case 4:a=1e4;break;default:a=5e3}return e={id:u++,callback:r,priorityLevel:e,startTime:i,expirationTime:a=i+a,sortIndex:-1},i>s?(e.sortIndex=i,n(d,e),null===o(c)&&e===o(d)&&(g?(v(C),C=-1):g=!0,P(k,i-s))):(e.sortIndex=a,n(c,e),h||m||(h=!0,j(x))),e},t.unstable_shouldYield=D,t.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}},9982:(e,t,n)=>{"use strict";e.exports=n(7463)},2833:e=>{e.exports=function(e,t,n,o){var r=n?n.call(o,e,t):void 0;if(void 0!==r)return!!r;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var i=Object.keys(e),s=Object.keys(t);if(i.length!==s.length)return!1;for(var a=Object.prototype.hasOwnProperty.bind(t),l=0;l<i.length;l++){var c=i[l];if(!a(c))return!1;var d=e[c],u=t[c];if(!1===(r=n?n.call(o,d,u,c):void 0)||void 0===r&&d!==u)return!1}return!0}},4784:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});const o={title:"Misti",tagline:"TON Static Analyzer",favicon:"img/favicon.png",url:"https://nowarp.io",baseUrl:"/",organizationName:"nowarp",projectName:"misti",onBrokenLinks:"warn",onBrokenMarkdownLinks:"throw",i18n:{defaultLocale:"en",locales:["en"],path:"i18n",localeConfigs:{}},presets:[["classic",{docs:{sidebarPath:"./sidebars.ts",routeBasePath:"tools/misti/docs",editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/"},theme:{customCss:"./src/css/custom.css"}}]],themeConfig:{navbar:{title:"Misti",logo:{alt:"Misti Logo",src:"img/misti.png"},items:[{type:"docsVersionDropdown",position:"right",dropdownItemsBefore:[],dropdownItemsAfter:[]},{label:"API Reference",position:"right",items:[{label:"Misti",to:"/tools/misti/api",target:"_blank",rel:"noopener noreferrer"},{label:"Souffle.js",to:"/lib/souffle-js/api",target:"_blank",rel:"noopener noreferrer"}]}],hideOnScroll:!1},footer:{style:"dark",links:[{title:"Community",items:[{label:"Telegram",href:"https://t.me/misti_dev"},{label:"GitHub",href:"https://github.com/nowarp/misti"}]},{title:"Developers",items:[{label:"API Reference",href:"https://nowarp.io/tools/misti/api/"},{label:"Changelog",href:"https://github.com/nowarp/misti/blob/master/CHANGELOG.md"},{label:"Roadmap",href:"https://github.com/nowarp/misti/milestones"}]}],copyright:'\n <div style="display: flex; justify-content: center; align-items: center; text-align: center; width: 100%;">\n Supported by <a href="https://ton.foundation">TF</a><svg width="1.5em" height="1.5em" viewBox="0 0 32 32" fill="currentColor" xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle; margin-left: 8px;">\n <path d="M16 32C24.8366 32 32 24.8366 32 16C32 7.16344 24.8366 0 16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32Z" fill="#0098EA"></path>\n <path d="M21.4629 8.92969H10.5363C8.52724 8.92969 7.25388 11.0969 8.26459 12.8488L15.0081 24.5372C15.4482 25.3004 16.551 25.3004 16.9911 24.5372L23.736 12.8488C24.7453 11.0996 23.472 8.92969 21.4643 8.92969H21.4629ZM15.0026 21.0321L13.534 18.1897L9.99036 11.8518C9.75659 11.4461 10.0454 10.9264 10.5349 10.9264H15.0013V21.0334L15.0026 21.0321ZM22.0061 11.8504L18.4638 18.1911L16.9952 21.0321V10.925H21.4616C21.9511 10.925 22.2399 11.4448 22.0061 11.8504Z" fill="white"></path>\n </svg>\n </a>\n </div>\n '},prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{backgroundColor:"hsl(220, 13%, 18%)",color:"hsl(220, 14%, 71%)",textShadow:"0 1px rgba(0, 0, 0, 0.3)"},styles:[{types:["comment","prolog","cdata"],style:{color:"hsl(220, 10%, 40%)"}},{types:["doctype","punctuation","entity"],style:{color:"hsl(220, 14%, 71%)"}},{types:["attr-name","class-name","maybe-class-name","boolean","constant","number","atrule"],style:{color:"hsl(29, 54%, 61%)"}},{types:["keyword"],style:{color:"hsl(286, 60%, 67%)"}},{types:["property","tag","symbol","deleted","important"],style:{color:"hsl(355, 65%, 65%)"}},{types:["selector","string","char","builtin","inserted","regex","attr-value"],style:{color:"hsl(95, 38%, 62%)"}},{types:["variable","operator","function"],style:{color:"hsl(207, 82%, 66%)"}},{types:["url"],style:{color:"hsl(187, 47%, 55%)"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"hsl(220, 14%, 71%)"}}]},additionalLanguages:[],magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},colorMode:{defaultMode:"light",disableSwitch:!1,respectPrefersColorScheme:!1},docs:{versionPersistence:"localStorage",sidebar:{hideable:!1,autoCollapseCategories:!1}},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},baseUrlIssueBanner:!0,future:{experimental_storage:{type:"localStorage",namespace:!1},experimental_router:"browser"},onBrokenAnchors:"warn",onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},plugins:[],themes:[],scripts:[],headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1,markdown:{format:"mdx",mermaid:!1,mdx1Compat:{comments:!0,admonitions:!0,headingIds:!0},anchors:{maintainCase:!1}}}},8168:(e,t,n)=>{"use strict";function o(){return o=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)({}).hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},o.apply(null,arguments)}n.d(t,{A:()=>o})},2892:(e,t,n)=>{"use strict";function o(e,t){return o=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},o(e,t)}function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,o(e,t)}n.d(t,{A:()=>r})},8587:(e,t,n)=>{"use strict";function o(e,t){if(null==e)return{};var n={};for(var o in e)if({}.hasOwnProperty.call(e,o)){if(t.includes(o))continue;n[o]=e[o]}return n}n.d(t,{A:()=>o})},4164:(e,t,n)=>{"use strict";function o(e){var t,n,r="";if("string"==typeof e||"number"==typeof e)r+=e;else if("object"==typeof e)if(Array.isArray(e)){var i=e.length;for(t=0;t<i;t++)e[t]&&(n=o(e[t]))&&(r&&(r+=" "),r+=n)}else for(n in e)e[n]&&(r&&(r+=" "),r+=n);return r}n.d(t,{A:()=>r});const r=function(){for(var e,t,n=0,r="",i=arguments.length;n<i;n++)(e=arguments[n])&&(t=o(e))&&(r&&(r+=" "),r+=t);return r}},1765:(e,t,n)=>{"use strict";n.d(t,{My:()=>E,f4:()=>ee});var o,r,i,s,a,l,c,d=n(6540),u=n(4164),p=Object.create,f=Object.defineProperty,m=Object.defineProperties,h=Object.getOwnPropertyDescriptor,g=Object.getOwnPropertyDescriptors,b=Object.getOwnPropertyNames,v=Object.getOwnPropertySymbols,y=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty,k=Object.prototype.propertyIsEnumerable,x=(e,t,n)=>t in e?f(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,_=(e,t)=>{for(var n in t||(t={}))w.call(t,n)&&x(e,n,t[n]);if(v)for(var n of v(t))k.call(t,n)&&x(e,n,t[n]);return e},S=(e,t)=>m(e,g(t)),A=(e,t)=>{var n={};for(var o in e)w.call(e,o)&&t.indexOf(o)<0&&(n[o]=e[o]);if(null!=e&&v)for(var o of v(e))t.indexOf(o)<0&&k.call(e,o)&&(n[o]=e[o]);return n},C=(o={"../../node_modules/.pnpm/prismjs@1.29.0_patch_hash=vrxx3pzkik6jpmgpayxfjunetu/node_modules/prismjs/prism.js"(e,t){var n=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},o={util:{encode:function e(t){return t instanceof r?new r(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var r,i;switch(n=n||{},o.util.type(t)){case"Object":if(i=o.util.objId(t),n[i])return n[i];for(var s in r={},n[i]=r,t)t.hasOwnProperty(s)&&(r[s]=e(t[s],n));return r;case"Array":return i=o.util.objId(t),n[i]?n[i]:(r=[],n[i]=r,t.forEach((function(t,o){r[o]=e(t,n)})),r);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var o="no-"+t;e;){var r=e.classList;if(r.contains(t))return!0;if(r.contains(o))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=o.util.clone(o.languages[e]);for(var r in t)n[r]=t[r];return n},insertBefore:function(e,t,n,r){var i=(r=r||o.languages)[e],s={};for(var a in i)if(i.hasOwnProperty(a)){if(a==t)for(var l in n)n.hasOwnProperty(l)&&(s[l]=n[l]);n.hasOwnProperty(a)||(s[a]=i[a])}var c=r[e];return r[e]=s,o.languages.DFS(o.languages,(function(t,n){n===c&&t!=e&&(this[t]=s)})),s},DFS:function e(t,n,r,i){i=i||{};var s=o.util.objId;for(var a in t)if(t.hasOwnProperty(a)){n.call(t,a,t[a],r||a);var l=t[a],c=o.util.type(l);"Object"!==c||i[s(l)]?"Array"!==c||i[s(l)]||(i[s(l)]=!0,e(l,n,a,i)):(i[s(l)]=!0,e(l,n,null,i))}}},plugins:{},highlight:function(e,t,n){var i={code:e,grammar:t,language:n};if(o.hooks.run("before-tokenize",i),!i.grammar)throw new Error('The language "'+i.language+'" has no grammar.');return i.tokens=o.tokenize(i.code,i.grammar),o.hooks.run("after-tokenize",i),r.stringify(o.util.encode(i.tokens),i.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var o in n)t[o]=n[o];delete t.rest}var r=new a;return l(r,r.head,e),s(e,r,t,r.head,0),function(e){for(var t=[],n=e.head.next;n!==e.tail;)t.push(n.value),n=n.next;return t}(r)},hooks:{all:{},add:function(e,t){var n=o.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=o.hooks.all[e];if(n&&n.length)for(var r,i=0;r=n[i++];)r(t)}},Token:r};function r(e,t,n,o){this.type=e,this.content=t,this.alias=n,this.length=0|(o||"").length}function i(e,t,n,o){e.lastIndex=t;var r=e.exec(n);if(r&&o&&r[1]){var i=r[1].length;r.index+=i,r[0]=r[0].slice(i)}return r}function s(e,t,n,a,d,u){for(var p in n)if(n.hasOwnProperty(p)&&n[p]){var f=n[p];f=Array.isArray(f)?f:[f];for(var m=0;m<f.length;++m){if(u&&u.cause==p+","+m)return;var h=f[m],g=h.inside,b=!!h.lookbehind,v=!!h.greedy,y=h.alias;if(v&&!h.pattern.global){var w=h.pattern.toString().match(/[imsuy]*$/)[0];h.pattern=RegExp(h.pattern.source,w+"g")}for(var k=h.pattern||h,x=a.next,_=d;x!==t.tail&&!(u&&_>=u.reach);_+=x.value.length,x=x.next){var S=x.value;if(t.length>e.length)return;if(!(S instanceof r)){var A,C=1;if(v){if(!(A=i(k,_,e,b))||A.index>=e.length)break;var E=A.index,T=A.index+A[0].length,D=_;for(D+=x.value.length;E>=D;)D+=(x=x.next).value.length;if(_=D-=x.value.length,x.value instanceof r)continue;for(var L=x;L!==t.tail&&(D<T||"string"==typeof L.value);L=L.next)C++,D+=L.value.length;C--,S=e.slice(_,D),A.index-=_}else if(!(A=i(k,0,S,b)))continue;E=A.index;var R=A[0],N=S.slice(0,E),j=S.slice(E+R.length),P=_+S.length;u&&P>u.reach&&(u.reach=P);var O=x.prev;if(N&&(O=l(t,O,N),_+=N.length),c(t,O,C),x=l(t,O,new r(p,g?o.tokenize(R,g):R,y,R)),j&&l(t,x,j),C>1){var I={cause:p+","+m,reach:P};s(e,t,n,x.prev,_,I),u&&I.reach>u.reach&&(u.reach=I.reach)}}}}}}function a(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function l(e,t,n){var o=t.next,r={value:n,prev:t,next:o};return t.next=r,o.prev=r,e.length++,r}function c(e,t,n){for(var o=t.next,r=0;r<n&&o!==e.tail;r++)o=o.next;t.next=o,o.prev=t,e.length-=r}return r.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var r="";return t.forEach((function(t){r+=e(t,n)})),r}var i={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},s=t.alias;s&&(Array.isArray(s)?Array.prototype.push.apply(i.classes,s):i.classes.push(s)),o.hooks.run("wrap",i);var a="";for(var l in i.attributes)a+=" "+l+'="'+(i.attributes[l]||"").replace(/"/g,""")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'"'+a+">"+i.content+"</"+i.tag+">"},o}();t.exports=n,n.default=n}},function(){return r||(0,o[b(o)[0]])((r={exports:{}}).exports,r),r.exports}),E=((e,t,n)=>(n=null!=e?p(y(e)):{},((e,t,n,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let r of b(t))w.call(e,r)||r===n||f(e,r,{get:()=>t[r],enumerable:!(o=h(t,r))||o.enumerable});return e})(!t&&e&&e.__esModule?n:f(n,"default",{value:e,enumerable:!0}),e)))(C());E.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},E.languages.markup.tag.inside["attr-value"].inside.entity=E.languages.markup.entity,E.languages.markup.doctype.inside["internal-subset"].inside=E.languages.markup,E.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(E.languages.markup.tag,"addInlined",{value:function(e,t){var n;(t=((n=((n={})["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:E.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i,{"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}}))["language-"+t]={pattern:/[\s\S]+/,inside:E.languages[t]},{}))[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:n},E.languages.insertBefore("markup","cdata",t)}}),Object.defineProperty(E.languages.markup.tag,"addAttribute",{value:function(e,t){E.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:E.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),E.languages.html=E.languages.markup,E.languages.mathml=E.languages.markup,E.languages.svg=E.languages.markup,E.languages.xml=E.languages.extend("markup",{}),E.languages.ssml=E.languages.xml,E.languages.atom=E.languages.xml,E.languages.rss=E.languages.xml,i=E,s={pattern:/\\[\\(){}[\]^$+*?|.]/,alias:"escape"},l="(?:[^\\\\-]|"+(a=/\\(?:x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]+\}|0[0-7]{0,2}|[123][0-7]{2}|c[a-zA-Z]|.)/).source+")",l=RegExp(l+"-"+l),c={pattern:/(<|')[^<>']+(?=[>']$)/,lookbehind:!0,alias:"variable"},i.languages.regex={"char-class":{pattern:/((?:^|[^\\])(?:\\\\)*)\[(?:[^\\\]]|\\[\s\S])*\]/,lookbehind:!0,inside:{"char-class-negation":{pattern:/(^\[)\^/,lookbehind:!0,alias:"operator"},"char-class-punctuation":{pattern:/^\[|\]$/,alias:"punctuation"},range:{pattern:l,inside:{escape:a,"range-punctuation":{pattern:/-/,alias:"operator"}}},"special-escape":s,"char-set":{pattern:/\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},escape:a}},"special-escape":s,"char-set":{pattern:/\.|\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},backreference:[{pattern:/\\(?![123][0-7]{2})[1-9]/,alias:"keyword"},{pattern:/\\k<[^<>']+>/,alias:"keyword",inside:{"group-name":c}}],anchor:{pattern:/[$^]|\\[ABbGZz]/,alias:"function"},escape:a,group:[{pattern:/\((?:\?(?:<[^<>']+>|'[^<>']+'|[>:]|<?[=!]|[idmnsuxU]+(?:-[idmnsuxU]+)?:?))?/,alias:"punctuation",inside:{"group-name":c}},{pattern:/\)/,alias:"punctuation"}],quantifier:{pattern:/(?:[+*?]|\{\d+(?:,\d*)?\})[?+]?/,alias:"number"},alternation:{pattern:/\|/,alias:"keyword"}},E.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},E.languages.javascript=E.languages.extend("clike",{"class-name":[E.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),E.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,E.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:E.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:E.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:E.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:E.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:E.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),E.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:E.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),E.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),E.languages.markup&&(E.languages.markup.tag.addInlined("script","javascript"),E.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),E.languages.js=E.languages.javascript,E.languages.actionscript=E.languages.extend("javascript",{keyword:/\b(?:as|break|case|catch|class|const|default|delete|do|dynamic|each|else|extends|final|finally|for|function|get|if|implements|import|in|include|instanceof|interface|internal|is|namespace|native|new|null|override|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|use|var|void|while|with)\b/,operator:/\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<<?|>>?>?|[!=]=?)=?|[~?@]/}),E.languages.actionscript["class-name"].alias="function",delete E.languages.actionscript.parameter,delete E.languages.actionscript["literal-property"],E.languages.markup&&E.languages.insertBefore("actionscript","string",{xml:{pattern:/(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\[\s\S]|(?!\2)[^\\])*\2)*\s*\/?>/,lookbehind:!0,inside:E.languages.markup}}),function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(E),function(e){var t=e.languages.javadoclike={parameter:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*@(?:arg|arguments|param)\s+)\w+/m,lookbehind:!0},keyword:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*|\{)@[a-z][a-zA-Z-]+\b/m,lookbehind:!0},punctuation:/[{}]/};Object.defineProperty(t,"addSupport",{value:function(t,n){(t="string"==typeof t?[t]:t).forEach((function(t){var o=function(e){e.inside||(e.inside={}),e.inside.rest=n},r="doc-comment";if(i=e.languages[t]){var i,s=i[r];if((s=s||(i=e.languages.insertBefore(t,"comment",{"doc-comment":{pattern:/(^|[^\\])\/\*\*[^/][\s\S]*?(?:\*\/|$)/,lookbehind:!0,alias:"comment"}}))[r])instanceof RegExp&&(s=i[r]={pattern:s}),Array.isArray(s))for(var a=0,l=s.length;a<l;a++)s[a]instanceof RegExp&&(s[a]={pattern:s[a]}),o(s[a]);else o(s)}}))}}),t.addSupport(["java","javascript","php"],t)}(E),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;(t=(e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+t.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css,e.languages.markup))&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(E),function(e){var t=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,n=(t=(e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+t.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[t,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}}),{pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0}),{pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0});e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|RebeccaPurple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,number:n})}(E),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,o="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",r=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),i=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function s(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return o})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return o}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return o})).replace(/<<key>>/g,(function(){return"(?:"+r+"|"+i+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:s(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:s(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:s(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:s(i),lookbehind:!0,greedy:!0},number:{pattern:s(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(E),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var o=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,r=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return o})),i=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source,s=(e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+r+i+"(?:"+r+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+r+i+")(?:"+r+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(o),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+r+")"+i+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+r+"$"),inside:{"table-header":{pattern:RegExp(o),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,o=t.length;n<o;n++){var r,i=t[n];"code"!==i.type?e(i.content):(r=i.content[1],i=i.content[3],r&&i&&"code-language"===r.type&&"code-block"===i.type&&"string"==typeof r.content&&(r=r.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),r="language-"+(r=(/[a-z][\w-]*/i.exec(r)||[""])[0].toLowerCase()),i.alias?"string"==typeof i.alias?i.alias=[i.alias,r]:i.alias.push(r):i.alias=[r]))}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",o=0,r=t.classes.length;o<r;o++){var i=t.classes[o];if(i=/language-(.+)/.exec(i)){n=i[1];break}}var c,d=e.languages[n];d?t.content=e.highlight(t.content.replace(s,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;return"#"===(t=t.toLowerCase())[0]?(n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),l(n)):a[t]||e})),d,n):n&&"none"!==n&&e.plugins.autoloader&&(c="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random()),t.attributes.id=c,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(c);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))})))}})),RegExp(e.languages.markup.tag.pattern.source,"gi")),a={amp:"&",lt:"<",gt:">",quot:'"'},l=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(E),E.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:E.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},E.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var o=t[n++];if("keyword"===o.type&&"mutation"===o.content){var r=[];if(u(["definition-mutation","punctuation"])&&"("===d(1).content){n+=2;var i=p(/^\($/,/^\)$/);if(-1===i)continue;for(;n<i;n++){var s=d(0);"variable"===s.type&&(f(s,"variable-input"),r.push(s.content))}n=i+1}if(u(["punctuation","property-query"])&&"{"===d(0).content&&(n++,f(d(0),"property-mutation"),0<r.length)){var a=p(/^\{$/,/^\}$/);if(-1!==a)for(var l=n;l<a;l++){var c=t[l];"variable"===c.type&&0<=r.indexOf(c.content)&&f(c,"variable-input")}}}}function d(e){return t[n+e]}function u(e,t){t=t||0;for(var n=0;n<e.length;n++){var o=d(n+t);if(!o||o.type!==e[n])return}return 1}function p(e,o){for(var r=1,i=n;i<t.length;i++){var s=t[i],a=s.content;if("punctuation"===s.type&&"string"==typeof a)if(e.test(a))r++;else if(o.test(a)&&0==--r)return i}return-1}function f(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),E.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,o=t.inside.interpolation,r=o.inside["interpolation-punctuation"],i=o.pattern.source;function s(t,o){if(e.languages[t])return{pattern:RegExp("((?:"+o+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function a(t,n,o){return t={code:t,grammar:n,language:o},e.hooks.run("before-tokenize",t),t.tokens=e.tokenize(t.code,t.grammar),e.hooks.run("after-tokenize",t),t.tokens}function l(t,n,s){var l=e.tokenize(t,{interpolation:{pattern:RegExp(i),lookbehind:!0}}),c=0,d={},u=(l=a(l.map((function(e){if("string"==typeof e)return e;var n,o;for(e=e.content;-1!==t.indexOf((o=c++,n="___"+s.toUpperCase()+"_"+o+"___")););return d[n]=e,n})).join(""),n,s),Object.keys(d));return c=0,function t(n){for(var i=0;i<n.length;i++){if(c>=u.length)return;var s,l,p,f,m,h,g,b=n[i];"string"==typeof b||"string"==typeof b.content?(s=u[c],-1!==(g=(h="string"==typeof b?b:b.content).indexOf(s))&&(++c,l=h.substring(0,g),m=d[s],p=void 0,(f={})["interpolation-punctuation"]=r,3===(f=e.tokenize(m,f)).length&&((p=[1,1]).push.apply(p,a(f[1],e.languages.javascript,"javascript")),f.splice.apply(f,p)),p=new e.Token("interpolation",f,o.alias,m),f=h.substring(g+s.length),m=[],l&&m.push(l),m.push(p),f&&(t(h=[f]),m.push.apply(m,h)),"string"==typeof b?(n.splice.apply(n,[i,1].concat(m)),i+=m.length-1):b.content=m)):(g=b.content,Array.isArray(g)?t(g):t([g]))}}(l),new e.Token(s,l,"language-"+s,t)}e.languages.javascript["template-string"]=[s("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),s("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),s("svg",/\bsvg/.source),s("markdown",/\b(?:markdown|md)/.source),s("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),s("sql",/\bsql/.source),t].filter(Boolean);var c={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function d(e){return"string"==typeof e?e:Array.isArray(e)?e.map(d).join(""):d(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in c&&function t(n){for(var o=0,r=n.length;o<r;o++){var i,s,a,c=n[o];"string"!=typeof c&&(i=c.content,Array.isArray(i)?"template-string"===c.type?(c=i[1],3===i.length&&"string"!=typeof c&&"embedded-code"===c.type&&(s=d(c),c=c.alias,c=Array.isArray(c)?c[0]:c,a=e.languages[c])&&(i[1]=l(s,a,c))):t(i):"string"!=typeof i&&t([i]))}}(t.tokens)}))}(E),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(E),function(e){var t=e.languages.javascript,n=/\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})+\}/.source,o="(@(?:arg|argument|param|property)\\s+(?:"+n+"\\s+)?)";e.languages.jsdoc=e.languages.extend("javadoclike",{parameter:{pattern:RegExp(o+/(?:(?!\s)[$\w\xA0-\uFFFF.])+(?=\s|$)/.source),lookbehind:!0,inside:{punctuation:/\./}}}),e.languages.insertBefore("jsdoc","keyword",{"optional-parameter":{pattern:RegExp(o+/\[(?:(?!\s)[$\w\xA0-\uFFFF.])+(?:=[^[\]]+)?\](?=\s|$)/.source),lookbehind:!0,inside:{parameter:{pattern:/(^\[)[$\w\xA0-\uFFFF\.]+/,lookbehind:!0,inside:{punctuation:/\./}},code:{pattern:/(=)[\s\S]*(?=\]$)/,lookbehind:!0,inside:t,alias:"language-javascript"},punctuation:/[=[\]]/}},"class-name":[{pattern:RegExp(/(@(?:augments|class|extends|interface|memberof!?|template|this|typedef)\s+(?:<TYPE>\s+)?)[A-Z]\w*(?:\.[A-Z]\w*)*/.source.replace(/<TYPE>/g,(function(){return n}))),lookbehind:!0,inside:{punctuation:/\./}},{pattern:RegExp("(@[a-z]+\\s+)"+n),lookbehind:!0,inside:{string:t.string,number:t.number,boolean:t.boolean,keyword:e.languages.typescript.keyword,operator:/=>|\.\.\.|[&|?:*]/,punctuation:/[.,;=<>{}()[\]]/}}],example:{pattern:/(@example\s+(?!\s))(?:[^@\s]|\s+(?!\s))+?(?=\s*(?:\*\s*)?(?:@\w|\*\/))/,lookbehind:!0,inside:{code:{pattern:/^([\t ]*(?:\*\s*)?)\S.*$/m,lookbehind:!0,inside:t,alias:"language-javascript"}}}}),e.languages.javadoclike.addSupport("javascript",e.languages.jsdoc)}(E),function(e){e.languages.flow=e.languages.extend("javascript",{}),e.languages.insertBefore("flow","keyword",{type:[{pattern:/\b(?:[Bb]oolean|Function|[Nn]umber|[Ss]tring|[Ss]ymbol|any|mixed|null|void)\b/,alias:"class-name"}]}),e.languages.flow["function-variable"].pattern=/(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=\s*(?:function\b|(?:\([^()]*\)(?:\s*:\s*\w+)?|(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/i,delete e.languages.flow.parameter,e.languages.insertBefore("flow","operator",{"flow-punctuation":{pattern:/\{\||\|\}/,alias:"punctuation"}}),Array.isArray(e.languages.flow.keyword)||(e.languages.flow.keyword=[e.languages.flow.keyword]),e.languages.flow.keyword.unshift({pattern:/(^|[^$]\b)(?:Class|declare|opaque|type)\b(?!\$)/,lookbehind:!0},{pattern:/(^|[^$]\B)\$(?:Diff|Enum|Exact|Keys|ObjMap|PropertyType|Record|Shape|Subtype|Supertype|await)\b(?!\$)/,lookbehind:!0})}(E),E.languages.n4js=E.languages.extend("javascript",{keyword:/\b(?:Array|any|boolean|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|module|new|null|number|package|private|protected|public|return|set|static|string|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/}),E.languages.insertBefore("n4js","constant",{annotation:{pattern:/@+\w+/,alias:"operator"}}),E.languages.n4jsd=E.languages.n4js,function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],o=0;o<n.length;o++){var r=n[o],i=e.languages.javascript[r];r=(i="RegExp"===e.util.type(i)?e.languages.javascript[r]={pattern:i}:i).inside||{};(i.inside=r)["maybe-class-name"]=/^[A-Z][\s\S]*/}}(E),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,o=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,r=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function i(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return o})).replace(/<SPREAD>/g,(function(){return r})),RegExp(e,t)}function s(t){for(var n=[],o=0;o<t.length;o++){var r=t[o],i=!1;"string"!=typeof r&&("tag"===r.type&&r.content[0]&&"tag"===r.content[0].type?"</"===r.content[0].content[0].content?0<n.length&&n[n.length-1].tagName===a(r.content[0].content[1])&&n.pop():"/>"!==r.content[r.content.length-1].content&&n.push({tagName:a(r.content[0].content[1]),openedBraces:0}):0<n.length&&"punctuation"===r.type&&"{"===r.content?n[n.length-1].openedBraces++:0<n.length&&0<n[n.length-1].openedBraces&&"punctuation"===r.type&&"}"===r.content?n[n.length-1].openedBraces--:i=!0),(i||"string"==typeof r)&&0<n.length&&0===n[n.length-1].openedBraces&&(i=a(r),o<t.length-1&&("string"==typeof t[o+1]||"plain-text"===t[o+1].type)&&(i+=a(t[o+1]),t.splice(o+1,1)),0<o&&("string"==typeof t[o-1]||"plain-text"===t[o-1].type)&&(i=a(t[o-1])+i,t.splice(o-1,1),o--),t[o]=new e.Token("plain-text",i,null,i)),r.content&&"string"!=typeof r.content&&s(r.content)}}r=i(r).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=i(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:i(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:i(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var a=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(a).join(""):""};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||s(e.tokens)}))}(E),function(e){var t=e.util.clone(e.languages.typescript);(t=(e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"],e.languages.tsx.tag)).pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+t.pattern.source+")",t.pattern.flags),t.lookbehind=!0}(E),E.languages.swift={comment:{pattern:/(^|[^\\:])(?:\/\/.*|\/\*(?:[^/*]|\/(?!\*)|\*(?!\/)|\/\*(?:[^*]|\*(?!\/))*\*\/)*\*\/)/,lookbehind:!0,greedy:!0},"string-literal":[{pattern:RegExp(/(^|[^"#])/.source+"(?:"+/"(?:\\(?:\((?:[^()]|\([^()]*\))*\)|\r\n|[^(])|[^\\\r\n"])*"/.source+"|"+/"""(?:\\(?:\((?:[^()]|\([^()]*\))*\)|[^(])|[^\\"]|"(?!""))*"""/.source+")"+/(?!["#])/.source),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\\()(?:[^()]|\([^()]*\))*(?=\))/,lookbehind:!0,inside:null},"interpolation-punctuation":{pattern:/^\)|\\\($/,alias:"punctuation"},punctuation:/\\(?=[\r\n])/,string:/[\s\S]+/}},{pattern:RegExp(/(^|[^"#])(#+)/.source+"(?:"+/"(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|\r\n|[^#])|[^\\\r\n])*?"/.source+"|"+/"""(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|[^#])|[^\\])*?"""/.source+")\\2"),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\#+\()(?:[^()]|\([^()]*\))*(?=\))/,lookbehind:!0,inside:null},"interpolation-punctuation":{pattern:/^\)|\\#+\($/,alias:"punctuation"},string:/[\s\S]+/}}],directive:{pattern:RegExp(/#/.source+"(?:"+/(?:elseif|if)\b/.source+"(?:[ \t]*"+/(?:![ \t]*)?(?:\b\w+\b(?:[ \t]*\((?:[^()]|\([^()]*\))*\))?|\((?:[^()]|\([^()]*\))*\))(?:[ \t]*(?:&&|\|\|))?/.source+")+|"+/(?:else|endif)\b/.source+")"),alias:"property",inside:{"directive-name":/^#\w+/,boolean:/\b(?:false|true)\b/,number:/\b\d+(?:\.\d+)*\b/,operator:/!|&&|\|\||[<>]=?/,punctuation:/[(),]/}},literal:{pattern:/#(?:colorLiteral|column|dsohandle|file(?:ID|Literal|Path)?|function|imageLiteral|line)\b/,alias:"constant"},"other-directive":{pattern:/#\w+\b/,alias:"property"},attribute:{pattern:/@\w+/,alias:"atrule"},"function-definition":{pattern:/(\bfunc\s+)\w+/,lookbehind:!0,alias:"function"},label:{pattern:/\b(break|continue)\s+\w+|\b[a-zA-Z_]\w*(?=\s*:\s*(?:for|repeat|while)\b)/,lookbehind:!0,alias:"important"},keyword:/\b(?:Any|Protocol|Self|Type|actor|as|assignment|associatedtype|associativity|async|await|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic|else|enum|extension|fallthrough|fileprivate|final|for|func|get|guard|higherThan|if|import|in|indirect|infix|init|inout|internal|is|isolated|lazy|left|let|lowerThan|mutating|none|nonisolated|nonmutating|open|operator|optional|override|postfix|precedencegroup|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|set|some|static|struct|subscript|super|switch|throw|throws|try|typealias|unowned|unsafe|var|weak|where|while|willSet)\b/,boolean:/\b(?:false|true)\b/,nil:{pattern:/\bnil\b/,alias:"constant"},"short-argument":/\$\d+\b/,omit:{pattern:/\b_\b/,alias:"keyword"},number:/\b(?:[\d_]+(?:\.[\de_]+)?|0x[a-f0-9_]+(?:\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\b/i,"class-name":/\b[A-Z](?:[A-Z_\d]*[a-z]\w*)?\b/,function:/\b[a-z_]\w*(?=\s*\()/i,constant:/\b(?:[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\b/,operator:/[-+*/%=!<>&|^~?]+|\.[.\-+*/%=!<>&|^~?]+/,punctuation:/[{}[\]();,.:\\]/},E.languages.swift["string-literal"].forEach((function(e){e.inside.interpolation.inside=E.languages.swift})),function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(E),E.languages.c=E.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),E.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),E.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},E.languages.c.string],char:E.languages.c.char,comment:E.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:E.languages.c}}}}),E.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete E.languages.c.boolean,E.languages.objectivec=E.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete E.languages.objectivec["class-name"],E.languages.objc=E.languages.objectivec,E.languages.reason=E.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),E.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete E.languages.reason.function,function(e){for(var t=/\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source,n=0;n<2;n++)t=t.replace(/<self>/g,(function(){return t}));t=t.replace(/<self>/g,(function(){return/[^\s\S]/.source})),e.languages.rust={comment:[{pattern:RegExp(/(^|[^\\])/.source+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:"attr-name",inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:"punctuation"},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:"symbol"},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:"punctuation"},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:"function"},"type-definition":{pattern:/(\b(?:enum|struct|trait|type|union)\s+)\w+/,lookbehind:!0,alias:"class-name"},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:"namespace"},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:"namespace",inside:{punctuation:/::/}}],keyword:[/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:"property"},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<<?=?|>>?=?|[@?]/},e.languages.rust["closure-params"].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string}(E),E.languages.go=E.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),E.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete E.languages.go["class-name"],function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(E),E.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},E.languages.python["string-interpolation"].inside.interpolation.inside.rest=E.languages.python,E.languages.py=E.languages.python;((e,t)=>{for(var n in t)f(e,n,{get:t[n],enumerable:!0})})({},{dracula:()=>T,duotoneDark:()=>D,duotoneLight:()=>L,github:()=>R,jettwaveDark:()=>q,jettwaveLight:()=>H,nightOwl:()=>N,nightOwlLight:()=>j,oceanicNext:()=>I,okaidia:()=>M,oneDark:()=>G,oneLight:()=>W,palenight:()=>F,shadesOfPurple:()=>B,synthwave84:()=>U,ultramin:()=>z,vsDark:()=>$,vsLight:()=>V});var T={plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},D={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]},L={plain:{backgroundColor:"#faf8f5",color:"#728fcb"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#b6ad9a"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#063289"}},{types:["property","function"],style:{color:"#b29762"}},{types:["tag-id","selector","atrule-id"],style:{color:"#2d2006"}},{types:["attr-name"],style:{color:"#896724"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule"],style:{color:"#728fcb"}},{types:["placeholder","variable"],style:{color:"#93abdc"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#896724"}}]},R={plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},N={plain:{color:"#d6deeb",backgroundColor:"#011627"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)",fontStyle:"italic"}},{types:["inserted","attr-name"],style:{color:"rgb(173, 219, 103)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(99, 119, 119)",fontStyle:"italic"}},{types:["string","url"],style:{color:"rgb(173, 219, 103)"}},{types:["variable"],style:{color:"rgb(214, 222, 235)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation"],style:{color:"rgb(199, 146, 234)"}},{types:["selector","doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["class-name"],style:{color:"rgb(255, 203, 139)"}},{types:["tag","operator","keyword"],style:{color:"rgb(127, 219, 202)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["property"],style:{color:"rgb(128, 203, 196)"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}}]},j={plain:{color:"#403f53",backgroundColor:"#FBFBFB"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)",fontStyle:"italic"}},{types:["inserted","attr-name"],style:{color:"rgb(72, 118, 214)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(152, 159, 177)",fontStyle:"italic"}},{types:["string","builtin","char","constant","url"],style:{color:"rgb(72, 118, 214)"}},{types:["variable"],style:{color:"rgb(201, 103, 101)"}},{types:["number"],style:{color:"rgb(170, 9, 130)"}},{types:["punctuation"],style:{color:"rgb(153, 76, 195)"}},{types:["function","selector","doctype"],style:{color:"rgb(153, 76, 195)",fontStyle:"italic"}},{types:["class-name"],style:{color:"rgb(17, 17, 17)"}},{types:["tag"],style:{color:"rgb(153, 76, 195)"}},{types:["operator","property","keyword","namespace"],style:{color:"rgb(12, 150, 155)"}},{types:["boolean"],style:{color:"rgb(188, 84, 84)"}}]},P="#c5a5c5",O="#8dc891",I={plain:{backgroundColor:"#282c34",color:"#ffffff"},styles:[{types:["attr-name"],style:{color:P}},{types:["attr-value"],style:{color:O}},{types:["comment","block-comment","prolog","doctype","cdata","shebang"],style:{color:"#999999"}},{types:["property","number","function-name","constant","symbol","deleted"],style:{color:"#5a9bcf"}},{types:["boolean"],style:{color:"#ff8b50"}},{types:["tag"],style:{color:"#fc929e"}},{types:["string"],style:{color:O}},{types:["punctuation"],style:{color:O}},{types:["selector","char","builtin","inserted"],style:{color:"#D8DEE9"}},{types:["function"],style:{color:"#79b6f2"}},{types:["operator","entity","url","variable"],style:{color:"#d7deea"}},{types:["keyword"],style:{color:P}},{types:["atrule","class-name"],style:{color:"#FAC863"}},{types:["important"],style:{fontWeight:"400"}},{types:["bold"],style:{fontWeight:"bold"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}}]},M={plain:{color:"#f8f8f2",backgroundColor:"#272822"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"#f92672",fontStyle:"italic"}},{types:["inserted"],style:{color:"rgb(173, 219, 103)",fontStyle:"italic"}},{types:["comment"],style:{color:"#8292a2",fontStyle:"italic"}},{types:["string","url"],style:{color:"#a6e22e"}},{types:["variable"],style:{color:"#f8f8f2"}},{types:["number"],style:{color:"#ae81ff"}},{types:["builtin","char","constant","function","class-name"],style:{color:"#e6db74"}},{types:["punctuation"],style:{color:"#f8f8f2"}},{types:["selector","doctype"],style:{color:"#a6e22e",fontStyle:"italic"}},{types:["tag","operator","keyword"],style:{color:"#66d9ef"}},{types:["boolean"],style:{color:"#ae81ff"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)",opacity:.7}},{types:["tag","property"],style:{color:"#f92672"}},{types:["attr-name"],style:{color:"#a6e22e !important"}},{types:["doctype"],style:{color:"#8292a2"}},{types:["rule"],style:{color:"#e6db74"}}]},F={plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string","inserted"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag","deleted"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]},B={plain:{color:"#9EFEFF",backgroundColor:"#2D2A55"},styles:[{types:["changed"],style:{color:"rgb(255, 238, 128)"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)"}},{types:["inserted"],style:{color:"rgb(173, 219, 103)"}},{types:["comment"],style:{color:"rgb(179, 98, 255)",fontStyle:"italic"}},{types:["punctuation"],style:{color:"rgb(255, 255, 255)"}},{types:["constant"],style:{color:"rgb(255, 98, 140)"}},{types:["string","url"],style:{color:"rgb(165, 255, 144)"}},{types:["variable"],style:{color:"rgb(255, 238, 128)"}},{types:["number","boolean"],style:{color:"rgb(255, 98, 140)"}},{types:["attr-name"],style:{color:"rgb(255, 180, 84)"}},{types:["keyword","operator","property","namespace","tag","selector","doctype"],style:{color:"rgb(255, 157, 0)"}},{types:["builtin","char","constant","function","class-name"],style:{color:"rgb(250, 208, 0)"}}]},U={plain:{backgroundColor:"linear-gradient(to bottom, #2a2139 75%, #34294f)",backgroundImage:"#34294f",color:"#f92aad",textShadow:"0 0 2px #100c0f, 0 0 5px #dc078e33, 0 0 10px #fff3"},styles:[{types:["comment","block-comment","prolog","doctype","cdata"],style:{color:"#495495",fontStyle:"italic"}},{types:["punctuation"],style:{color:"#ccc"}},{types:["tag","attr-name","namespace","number","unit","hexcode","deleted"],style:{color:"#e2777a"}},{types:["property","selector"],style:{color:"#72f1b8",textShadow:"0 0 2px #100c0f, 0 0 10px #257c5575, 0 0 35px #21272475"}},{types:["function-name"],style:{color:"#6196cc"}},{types:["boolean","selector-id","function"],style:{color:"#fdfdfd",textShadow:"0 0 2px #001716, 0 0 3px #03edf975, 0 0 5px #03edf975, 0 0 8px #03edf975"}},{types:["class-name","maybe-class-name","builtin"],style:{color:"#fff5f6",textShadow:"0 0 2px #000, 0 0 10px #fc1f2c75, 0 0 5px #fc1f2c75, 0 0 25px #fc1f2c75"}},{types:["constant","symbol"],style:{color:"#f92aad",textShadow:"0 0 2px #100c0f, 0 0 5px #dc078e33, 0 0 10px #fff3"}},{types:["important","atrule","keyword","selector-class"],style:{color:"#f4eee4",textShadow:"0 0 2px #393a33, 0 0 8px #f39f0575, 0 0 2px #f39f0575"}},{types:["string","char","attr-value","regex","variable"],style:{color:"#f87c32"}},{types:["parameter"],style:{fontStyle:"italic"}},{types:["entity","url"],style:{color:"#67cdcc"}},{types:["operator"],style:{color:"ffffffee"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["entity"],style:{cursor:"help"}},{types:["inserted"],style:{color:"green"}}]},z={plain:{color:"#282a2e",backgroundColor:"#ffffff"},styles:[{types:["comment"],style:{color:"rgb(197, 200, 198)"}},{types:["string","number","builtin","variable"],style:{color:"rgb(150, 152, 150)"}},{types:["class-name","function","tag","attr-name"],style:{color:"rgb(40, 42, 46)"}}]},$={plain:{color:"#9CDCFE",backgroundColor:"#1E1E1E"},styles:[{types:["prolog"],style:{color:"rgb(0, 0, 128)"}},{types:["comment"],style:{color:"rgb(106, 153, 85)"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"rgb(86, 156, 214)"}},{types:["number","inserted"],style:{color:"rgb(181, 206, 168)"}},{types:["constant"],style:{color:"rgb(100, 102, 149)"}},{types:["attr-name","variable"],style:{color:"rgb(156, 220, 254)"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"rgb(206, 145, 120)"}},{types:["selector"],style:{color:"rgb(215, 186, 125)"}},{types:["tag"],style:{color:"rgb(78, 201, 176)"}},{types:["tag"],languages:["markup"],style:{color:"rgb(86, 156, 214)"}},{types:["punctuation","operator"],style:{color:"rgb(212, 212, 212)"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"rgb(220, 220, 170)"}},{types:["class-name"],style:{color:"rgb(78, 201, 176)"}},{types:["char"],style:{color:"rgb(209, 105, 105)"}}]},V={plain:{color:"#000000",backgroundColor:"#ffffff"},styles:[{types:["comment"],style:{color:"rgb(0, 128, 0)"}},{types:["builtin"],style:{color:"rgb(0, 112, 193)"}},{types:["number","variable","inserted"],style:{color:"rgb(9, 134, 88)"}},{types:["operator"],style:{color:"rgb(0, 0, 0)"}},{types:["constant","char"],style:{color:"rgb(129, 31, 63)"}},{types:["tag"],style:{color:"rgb(128, 0, 0)"}},{types:["attr-name"],style:{color:"rgb(255, 0, 0)"}},{types:["deleted","string"],style:{color:"rgb(163, 21, 21)"}},{types:["changed","punctuation"],style:{color:"rgb(4, 81, 165)"}},{types:["function","keyword"],style:{color:"rgb(0, 0, 255)"}},{types:["class-name"],style:{color:"rgb(38, 127, 153)"}}]},q={plain:{color:"#f8fafc",backgroundColor:"#011627"},styles:[{types:["prolog"],style:{color:"#000080"}},{types:["comment"],style:{color:"#6A9955"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"#569CD6"}},{types:["number","inserted"],style:{color:"#B5CEA8"}},{types:["constant"],style:{color:"#f8fafc"}},{types:["attr-name","variable"],style:{color:"#9CDCFE"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"#cbd5e1"}},{types:["selector"],style:{color:"#D7BA7D"}},{types:["tag"],style:{color:"#0ea5e9"}},{types:["tag"],languages:["markup"],style:{color:"#0ea5e9"}},{types:["punctuation","operator"],style:{color:"#D4D4D4"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"#7dd3fc"}},{types:["class-name"],style:{color:"#0ea5e9"}},{types:["char"],style:{color:"#D16969"}}]},H={plain:{color:"#0f172a",backgroundColor:"#f1f5f9"},styles:[{types:["prolog"],style:{color:"#000080"}},{types:["comment"],style:{color:"#6A9955"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"#0c4a6e"}},{types:["number","inserted"],style:{color:"#B5CEA8"}},{types:["constant"],style:{color:"#0f172a"}},{types:["attr-name","variable"],style:{color:"#0c4a6e"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"#64748b"}},{types:["selector"],style:{color:"#D7BA7D"}},{types:["tag"],style:{color:"#0ea5e9"}},{types:["tag"],languages:["markup"],style:{color:"#0ea5e9"}},{types:["punctuation","operator"],style:{color:"#475569"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"#0e7490"}},{types:["class-name"],style:{color:"#0ea5e9"}},{types:["char"],style:{color:"#D16969"}}]},G={plain:{backgroundColor:"hsl(220, 13%, 18%)",color:"hsl(220, 14%, 71%)",textShadow:"0 1px rgba(0, 0, 0, 0.3)"},styles:[{types:["comment","prolog","cdata"],style:{color:"hsl(220, 10%, 40%)"}},{types:["doctype","punctuation","entity"],style:{color:"hsl(220, 14%, 71%)"}},{types:["attr-name","class-name","maybe-class-name","boolean","constant","number","atrule"],style:{color:"hsl(29, 54%, 61%)"}},{types:["keyword"],style:{color:"hsl(286, 60%, 67%)"}},{types:["property","tag","symbol","deleted","important"],style:{color:"hsl(355, 65%, 65%)"}},{types:["selector","string","char","builtin","inserted","regex","attr-value"],style:{color:"hsl(95, 38%, 62%)"}},{types:["variable","operator","function"],style:{color:"hsl(207, 82%, 66%)"}},{types:["url"],style:{color:"hsl(187, 47%, 55%)"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"hsl(220, 14%, 71%)"}}]},W={plain:{backgroundColor:"hsl(230, 1%, 98%)",color:"hsl(230, 8%, 24%)"},styles:[{types:["comment","prolog","cdata"],style:{color:"hsl(230, 4%, 64%)"}},{types:["doctype","punctuation","entity"],style:{color:"hsl(230, 8%, 24%)"}},{types:["attr-name","class-name","boolean","constant","number","atrule"],style:{color:"hsl(35, 99%, 36%)"}},{types:["keyword"],style:{color:"hsl(301, 63%, 40%)"}},{types:["property","tag","symbol","deleted","important"],style:{color:"hsl(5, 74%, 59%)"}},{types:["selector","string","char","builtin","inserted","regex","attr-value","punctuation"],style:{color:"hsl(119, 34%, 47%)"}},{types:["variable","operator","function"],style:{color:"hsl(221, 87%, 60%)"}},{types:["url"],style:{color:"hsl(198, 99%, 37%)"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"hsl(230, 8%, 24%)"}}]},Z=(e,t)=>{const{plain:n}=e,o=e.styles.reduce(((e,n)=>{const{languages:o,style:r}=n;return o&&!o.includes(t)||n.types.forEach((t=>{const n=_(_({},e[t]),r);e[t]=n})),e}),{});return o.root=n,o.plain=S(_({},n),{backgroundColor:void 0}),o},Q=/\r\n|\r|\n/,K=e=>{0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},Y=(e,t)=>{const n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)},X=e=>{const t=[[]],n=[e],o=[0],r=[e.length];let i=0,s=0,a=[];const l=[a];for(;s>-1;){for(;(i=o[s]++)<r[s];){let e,c=t[s];const d=n[s][i];if("string"==typeof d?(c=s>0?c:["plain"],e=d):(c=Y(c,d.type),d.alias&&(c=Y(c,d.alias)),e=d.content),"string"!=typeof e){s++,t.push(c),n.push(e),o.push(0),r.push(e.length);continue}const u=e.split(Q),p=u.length;a.push({types:c,content:u[0]});for(let t=1;t<p;t++)K(a),l.push(a=[]),a.push({types:c,content:u[t]})}s--,t.pop(),n.pop(),o.pop(),r.pop()}return K(a),l},J=({children:e,language:t,code:n,theme:o,prism:r})=>{const i=t.toLowerCase(),s=((e,t)=>{const[n,o]=(0,d.useState)(Z(t,e)),r=(0,d.useRef)(),i=(0,d.useRef)();return(0,d.useEffect)((()=>{t===r.current&&e===i.current||(r.current=t,i.current=e,o(Z(t,e)))}),[e,t]),n})(i,o),a=(e=>(0,d.useCallback)((t=>{var n=t,{className:o,style:r,line:i}=n,s=A(n,["className","style","line"]);const a=S(_({},s),{className:(0,u.A)("token-line",o)});return"object"==typeof e&&"plain"in e&&(a.style=e.plain),"object"==typeof r&&(a.style=_(_({},a.style||{}),r)),a}),[e]))(s),l=(e=>{const t=(0,d.useCallback)((({types:t,empty:n})=>{if(null!=e)return 1===t.length&&"plain"===t[0]?null!=n?{display:"inline-block"}:void 0:1===t.length&&null!=n?e[t[0]]:Object.assign(null!=n?{display:"inline-block"}:{},...t.map((t=>e[t])))}),[e]);return(0,d.useCallback)((e=>{var n=e,{token:o,className:r,style:i}=n,s=A(n,["token","className","style"]);const a=S(_({},s),{className:(0,u.A)("token",...o.types,r),children:o.content,style:t(o)});return null!=i&&(a.style=_(_({},a.style||{}),i)),a}),[t])})(s),c=(({prism:e,code:t,grammar:n,language:o})=>{const r=(0,d.useRef)(e);return(0,d.useMemo)((()=>{if(null==n)return X([t]);const e={code:t,grammar:n,language:o,tokens:[]};return r.current.hooks.run("before-tokenize",e),e.tokens=r.current.tokenize(t,n),r.current.hooks.run("after-tokenize",e),X(e.tokens)}),[t,n,o])})({prism:r,language:i,code:n,grammar:r.languages[i]});return e({tokens:c,className:`prism-code language-${i}`,style:null!=s?s.root:{},getLineProps:a,getTokenProps:l})},ee=e=>(0,d.createElement)(J,S(_({},e),{prism:e.prism||E,theme:e.theme||$,code:e.code,language:e.language}))},1561:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var o=!0,r="Invariant failed";function i(e,t){if(!e){if(o)throw new Error(r);var n="function"==typeof t?t():t,i=n?"".concat(r,": ").concat(n):r;throw new Error(i)}}},2654:e=>{"use strict";e.exports={}},4054:e=>{"use strict";e.exports=JSON.parse('{"/markdown-page-3d7":{"__comp":"1f391b9e","__context":{"plugin":"a7456010"},"content":"393be207"},"/tools/misti/-64a":{"__comp":"e4a43c7d","__context":{"plugin":"a7456010"},"config":"5e9f5e1a"},"/tools/misti/docs-63f":{"__comp":"5e95c892","__context":{"plugin":"aba21aa0"}},"/tools/misti/docs/0.1.2-f8a":{"__comp":"a7bd4aaa","__props":"a4516edb"},"/tools/misti/docs/0.1.2-a68":{"__comp":"a94703ab"},"/tools/misti/docs/0.1.2/-e00":{"__comp":"17896441","content":"f3466e67"},"/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply-d7c":{"__comp":"17896441","content":"8c0243db"},"/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables-95b":{"__comp":"17896441","content":"edf1e52e"},"/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables-ec0":{"__comp":"17896441","content":"d6f3e79e"},"/tools/misti/docs/0.1.2/detectors/UnboundLoops-097":{"__comp":"17896441","content":"987a8a5d"},"/tools/misti/docs/0.1.2/detectors/ZeroAddress-051":{"__comp":"17896441","content":"36ebdf3e"},"/tools/misti/docs/0.1.2/hacking/CHANGELOG-87f":{"__comp":"17896441","content":"2bdf0f82"},"/tools/misti/docs/0.1.2/hacking/contributing-a2a":{"__comp":"17896441","content":"775287ab"},"/tools/misti/docs/0.1.2/hacking/custom-detector-00e":{"__comp":"17896441","content":"743bfbca"},"/tools/misti/docs/0.1.2/hacking/design-745":{"__comp":"17896441","content":"f7ab1f3a"},"/tools/misti/docs/0.1.2/hacking/souffle-cc7":{"__comp":"17896441","content":"cd411a47"},"/tools/misti/docs/0.1.2/hacking/tools-d9d":{"__comp":"17896441","content":"cf5f971a"},"/tools/misti/docs/0.1.2/tutorial/configuration-c1b":{"__comp":"17896441","content":"1598dd73"},"/tools/misti/docs/0.1.2/tutorial/getting-started-3e0":{"__comp":"17896441","content":"273168fb"},"/tools/misti/docs/0.2.0-2c6":{"__comp":"a7bd4aaa","__props":"a8d7d639"},"/tools/misti/docs/0.2.0-635":{"__comp":"a94703ab"},"/tools/misti/docs/0.2.0/-7ad":{"__comp":"17896441","content":"40be7dfa"},"/tools/misti/docs/0.2.0/detectors-e72":{"__comp":"17896441","content":"f18c7db7"},"/tools/misti/docs/0.2.0/detectors/BranchDuplicate-69d":{"__comp":"17896441","content":"d9542fcf"},"/tools/misti/docs/0.2.0/detectors/ConstantAddress-969":{"__comp":"17896441","content":"b3799bec"},"/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply-505":{"__comp":"17896441","content":"2d07d137"},"/tools/misti/docs/0.2.0/detectors/DumpIsUsed-02c":{"__comp":"17896441","content":"24652b08"},"/tools/misti/docs/0.2.0/detectors/FieldDoubleInit-785":{"__comp":"17896441","content":"bd72ef9b"},"/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables-308":{"__comp":"17896441","content":"8c01191f"},"/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign-653":{"__comp":"17896441","content":"972c9666"},"/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables-89d":{"__comp":"17896441","content":"2424092d"},"/tools/misti/docs/0.2.0/detectors/UnboundLoops-e75":{"__comp":"17896441","content":"76268162"},"/tools/misti/docs/0.2.0/detectors/ZeroAddress-f88":{"__comp":"17896441","content":"87ce9660"},"/tools/misti/docs/0.2.0/hacking/contributing-576":{"__comp":"17896441","content":"ff0db780"},"/tools/misti/docs/0.2.0/hacking/custom-detector-7e7":{"__comp":"17896441","content":"86d70222"},"/tools/misti/docs/0.2.0/hacking/design-0d7":{"__comp":"17896441","content":"8c74c05e"},"/tools/misti/docs/0.2.0/hacking/souffle-7c7":{"__comp":"17896441","content":"773c7ee4"},"/tools/misti/docs/0.2.0/hacking/tools-a79":{"__comp":"17896441","content":"8272dc48"},"/tools/misti/docs/0.2.0/tutorial/ci-cd-d75":{"__comp":"17896441","content":"4fd06f05"},"/tools/misti/docs/0.2.0/tutorial/configuration-cf5":{"__comp":"17896441","content":"5815e0d3"},"/tools/misti/docs/0.2.0/tutorial/getting-started-692":{"__comp":"17896441","content":"01419b1f"},"/tools/misti/docs/0.2.1-5f6":{"__comp":"a7bd4aaa","__props":"474ce197"},"/tools/misti/docs/0.2.1-ee6":{"__comp":"a94703ab"},"/tools/misti/docs/0.2.1/-b26":{"__comp":"17896441","content":"d1781038"},"/tools/misti/docs/0.2.1/detectors-854":{"__comp":"17896441","content":"2257d06b"},"/tools/misti/docs/0.2.1/detectors/BranchDuplicate-763":{"__comp":"17896441","content":"d15cc687"},"/tools/misti/docs/0.2.1/detectors/ConstantAddress-265":{"__comp":"17896441","content":"5ec2195c"},"/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply-607":{"__comp":"17896441","content":"2f30e490"},"/tools/misti/docs/0.2.1/detectors/DumpIsUsed-f66":{"__comp":"17896441","content":"c49af6bd"},"/tools/misti/docs/0.2.1/detectors/FieldDoubleInit-9c2":{"__comp":"17896441","content":"f503d00c"},"/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables-586":{"__comp":"17896441","content":"8df82fb6"},"/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign-10d":{"__comp":"17896441","content":"f5bf49b8"},"/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables-c93":{"__comp":"17896441","content":"4d74b396"},"/tools/misti/docs/0.2.1/detectors/UnboundLoops-56e":{"__comp":"17896441","content":"72b7ad48"},"/tools/misti/docs/0.2.1/detectors/ZeroAddress-460":{"__comp":"17896441","content":"104c66c9"},"/tools/misti/docs/0.2.1/hacking/contributing-2b2":{"__comp":"17896441","content":"15d13f14"},"/tools/misti/docs/0.2.1/hacking/custom-detector-be8":{"__comp":"17896441","content":"1418388c"},"/tools/misti/docs/0.2.1/hacking/design-813":{"__comp":"17896441","content":"acef80f0"},"/tools/misti/docs/0.2.1/hacking/souffle-844":{"__comp":"17896441","content":"f2bdb0f5"},"/tools/misti/docs/0.2.1/hacking/tools-452":{"__comp":"17896441","content":"2ace25e9"},"/tools/misti/docs/0.2.1/tutorial/ci-cd-988":{"__comp":"17896441","content":"3db5102b"},"/tools/misti/docs/0.2.1/tutorial/configuration-910":{"__comp":"17896441","content":"b91dc83b"},"/tools/misti/docs/0.2.1/tutorial/getting-started-f03":{"__comp":"17896441","content":"f5772bf1"},"/tools/misti/docs/0.2.2-211":{"__comp":"a7bd4aaa","__props":"e1c88a01"},"/tools/misti/docs/0.2.2-1f0":{"__comp":"a94703ab"},"/tools/misti/docs/0.2.2/-4ce":{"__comp":"17896441","content":"566d8483"},"/tools/misti/docs/0.2.2/detectors-a63":{"__comp":"17896441","content":"90b5d830"},"/tools/misti/docs/0.2.2/detectors/BranchDuplicate-c5b":{"__comp":"17896441","content":"4518efa7"},"/tools/misti/docs/0.2.2/detectors/ConstantAddress-21b":{"__comp":"17896441","content":"8d6fa39c"},"/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply-4dc":{"__comp":"17896441","content":"c96954fa"},"/tools/misti/docs/0.2.2/detectors/DumpIsUsed-fe3":{"__comp":"17896441","content":"fafa7ec8"},"/tools/misti/docs/0.2.2/detectors/FieldDoubleInit-50d":{"__comp":"17896441","content":"f4d075b1"},"/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables-716":{"__comp":"17896441","content":"d7d99e1d"},"/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign-0d0":{"__comp":"17896441","content":"1869ccd1"},"/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables-3b1":{"__comp":"17896441","content":"ca178ca4"},"/tools/misti/docs/0.2.2/detectors/UnboundLoops-b9e":{"__comp":"17896441","content":"6f277b0e"},"/tools/misti/docs/0.2.2/detectors/ZeroAddress-98a":{"__comp":"17896441","content":"c5d65102"},"/tools/misti/docs/0.2.2/hacking/contributing-894":{"__comp":"17896441","content":"bce595e9"},"/tools/misti/docs/0.2.2/hacking/custom-detector-2df":{"__comp":"17896441","content":"fcd86191"},"/tools/misti/docs/0.2.2/hacking/design-fe0":{"__comp":"17896441","content":"8c9dd45b"},"/tools/misti/docs/0.2.2/hacking/souffle-8b1":{"__comp":"17896441","content":"693ffdbc"},"/tools/misti/docs/0.2.2/hacking/tools-191":{"__comp":"17896441","content":"06bf7bd2"},"/tools/misti/docs/0.2.2/tutorial/blueprint-9e1":{"__comp":"17896441","content":"d2d53d04"},"/tools/misti/docs/0.2.2/tutorial/ci-cd-260":{"__comp":"17896441","content":"1c26cb06"},"/tools/misti/docs/0.2.2/tutorial/configuration-7d4":{"__comp":"17896441","content":"c5c1850c"},"/tools/misti/docs/0.2.2/tutorial/getting-started-825":{"__comp":"17896441","content":"61c19607"},"/tools/misti/docs/0.3.0-d97":{"__comp":"a7bd4aaa","__props":"1b73222b"},"/tools/misti/docs/0.3.0-be7":{"__comp":"a94703ab"},"/tools/misti/docs/0.3.0/-d94":{"__comp":"17896441","content":"07f2fad9"},"/tools/misti/docs/0.3.0/detectors-558":{"__comp":"17896441","content":"b05af762"},"/tools/misti/docs/0.3.0/detectors/ArgCopyMutation-0ef":{"__comp":"17896441","content":"cc6d1ce2"},"/tools/misti/docs/0.3.0/detectors/AsmIsUsed-dc6":{"__comp":"17896441","content":"c252c345"},"/tools/misti/docs/0.3.0/detectors/BranchDuplicate-656":{"__comp":"17896441","content":"fe7c01fc"},"/tools/misti/docs/0.3.0/detectors/ConstantAddress-74f":{"__comp":"17896441","content":"c55f1521"},"/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply-963":{"__comp":"17896441","content":"122f6b32"},"/tools/misti/docs/0.3.0/detectors/DumpIsUsed-e8b":{"__comp":"17896441","content":"e5aa38d8"},"/tools/misti/docs/0.3.0/detectors/FieldDoubleInit-aa1":{"__comp":"17896441","content":"e3c4fe0a"},"/tools/misti/docs/0.3.0/detectors/InheritedStateMutation-911":{"__comp":"17896441","content":"7b5b3cc2"},"/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables-6bb":{"__comp":"17896441","content":"ebcc9167"},"/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign-46a":{"__comp":"17896441","content":"96e77fcb"},"/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi-544":{"__comp":"17896441","content":"c00ee666"},"/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables-460":{"__comp":"17896441","content":"17406c9d"},"/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap-bea":{"__comp":"17896441","content":"563af34e"},"/tools/misti/docs/0.3.0/detectors/UnboundLoops-d61":{"__comp":"17896441","content":"8d91c04d"},"/tools/misti/docs/0.3.0/detectors/ZeroAddress-7e8":{"__comp":"17896441","content":"5a7ecd5b"},"/tools/misti/docs/0.3.0/hacking/contributing-e13":{"__comp":"17896441","content":"988b076a"},"/tools/misti/docs/0.3.0/hacking/custom-detector-178":{"__comp":"17896441","content":"81087c81"},"/tools/misti/docs/0.3.0/hacking/design-653":{"__comp":"17896441","content":"a7eb4927"},"/tools/misti/docs/0.3.0/hacking/souffle-35c":{"__comp":"17896441","content":"b80eaa74"},"/tools/misti/docs/0.3.0/hacking/tools-b51":{"__comp":"17896441","content":"377c4f81"},"/tools/misti/docs/0.3.0/tutorial/blueprint-894":{"__comp":"17896441","content":"2018b81b"},"/tools/misti/docs/0.3.0/tutorial/ci-cd-2c5":{"__comp":"17896441","content":"6934ebe4"},"/tools/misti/docs/0.3.0/tutorial/cli-e3e":{"__comp":"17896441","content":"91ee281c"},"/tools/misti/docs/0.3.0/tutorial/configuration-1f6":{"__comp":"17896441","content":"e63578c3"},"/tools/misti/docs/0.3.0/tutorial/getting-started-989":{"__comp":"17896441","content":"844f22a2"},"/tools/misti/docs/0.3.1-ce6":{"__comp":"a7bd4aaa","__props":"d46ee8ed"},"/tools/misti/docs/0.3.1-7d2":{"__comp":"a94703ab"},"/tools/misti/docs/0.3.1/-6da":{"__comp":"17896441","content":"43c93918"},"/tools/misti/docs/0.3.1/detectors-36d":{"__comp":"17896441","content":"c926d0d4"},"/tools/misti/docs/0.3.1/detectors/ArgCopyMutation-742":{"__comp":"17896441","content":"63a541b5"},"/tools/misti/docs/0.3.1/detectors/AsmIsUsed-f46":{"__comp":"17896441","content":"0b705376"},"/tools/misti/docs/0.3.1/detectors/BranchDuplicate-a80":{"__comp":"17896441","content":"aac87eb6"},"/tools/misti/docs/0.3.1/detectors/ConstantAddress-eb7":{"__comp":"17896441","content":"49256311"},"/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply-908":{"__comp":"17896441","content":"8e8fe4d7"},"/tools/misti/docs/0.3.1/detectors/DumpIsUsed-6bc":{"__comp":"17896441","content":"a8c496ca"},"/tools/misti/docs/0.3.1/detectors/FieldDoubleInit-385":{"__comp":"17896441","content":"b78952d0"},"/tools/misti/docs/0.3.1/detectors/InheritedStateMutation-810":{"__comp":"17896441","content":"d147047e"},"/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables-7d1":{"__comp":"17896441","content":"1a50d306"},"/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign-e3f":{"__comp":"17896441","content":"2cebbb1e"},"/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi-05c":{"__comp":"17896441","content":"c05c6791"},"/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables-501":{"__comp":"17896441","content":"6f60ccd2"},"/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap-1a3":{"__comp":"17896441","content":"776efca7"},"/tools/misti/docs/0.3.1/detectors/UnboundLoops-92f":{"__comp":"17896441","content":"a66f2ff0"},"/tools/misti/docs/0.3.1/detectors/ZeroAddress-ccb":{"__comp":"17896441","content":"9fedf60a"},"/tools/misti/docs/0.3.1/hacking/contributing-b74":{"__comp":"17896441","content":"ce7f72c2"},"/tools/misti/docs/0.3.1/hacking/custom-detector-3e6":{"__comp":"17896441","content":"4f2bb7ce"},"/tools/misti/docs/0.3.1/hacking/design-40b":{"__comp":"17896441","content":"e2ad9c7a"},"/tools/misti/docs/0.3.1/hacking/souffle-53a":{"__comp":"17896441","content":"4b89306f"},"/tools/misti/docs/0.3.1/hacking/tools-035":{"__comp":"17896441","content":"be8ab43b"},"/tools/misti/docs/0.3.1/tutorial/blueprint-5ec":{"__comp":"17896441","content":"1295da86"},"/tools/misti/docs/0.3.1/tutorial/ci-cd-e30":{"__comp":"17896441","content":"2aa59687"},"/tools/misti/docs/0.3.1/tutorial/cli-3c0":{"__comp":"17896441","content":"f6f2b22b"},"/tools/misti/docs/0.3.1/tutorial/configuration-160":{"__comp":"17896441","content":"0ac52da9"},"/tools/misti/docs/0.3.1/tutorial/getting-started-493":{"__comp":"17896441","content":"8cf7c613"},"/tools/misti/docs/next-14d":{"__comp":"a7bd4aaa","__props":"dd8730c9"},"/tools/misti/docs/next-6d6":{"__comp":"a94703ab"},"/tools/misti/docs/next/-ac0":{"__comp":"17896441","content":"c377a04b"},"/tools/misti/docs/next/detectors-3fb":{"__comp":"17896441","content":"faae61e5"},"/tools/misti/docs/next/detectors/ArgCopyMutation-e79":{"__comp":"17896441","content":"304edb56"},"/tools/misti/docs/next/detectors/AsmIsUsed-be7":{"__comp":"17896441","content":"138db073"},"/tools/misti/docs/next/detectors/BranchDuplicate-046":{"__comp":"17896441","content":"e3b47995"},"/tools/misti/docs/next/detectors/ConstantAddress-6d7":{"__comp":"17896441","content":"f97c3fca"},"/tools/misti/docs/next/detectors/DivideBeforeMultiply-004":{"__comp":"17896441","content":"883df8cc"},"/tools/misti/docs/next/detectors/DumpIsUsed-58e":{"__comp":"17896441","content":"2b6a80d0"},"/tools/misti/docs/next/detectors/DuplicatedCondition-f7a":{"__comp":"17896441","content":"b12d76e5"},"/tools/misti/docs/next/detectors/EnsurePrgSeed-d1b":{"__comp":"17896441","content":"dc55925b"},"/tools/misti/docs/next/detectors/FalseCondition-472":{"__comp":"17896441","content":"f34cb5e0"},"/tools/misti/docs/next/detectors/FieldDoubleInit-c32":{"__comp":"17896441","content":"26592ea2"},"/tools/misti/docs/next/detectors/InheritedStateMutation-d8d":{"__comp":"17896441","content":"0c3de8e2"},"/tools/misti/docs/next/detectors/NeverAccessedVariables-94c":{"__comp":"17896441","content":"d2aaf676"},"/tools/misti/docs/next/detectors/OptimalMathFunction-b0f":{"__comp":"17896441","content":"55e1201d"},"/tools/misti/docs/next/detectors/PreferAugmentedAssign-951":{"__comp":"17896441","content":"070671b7"},"/tools/misti/docs/next/detectors/PreferredStdlibApi-ed1":{"__comp":"17896441","content":"cb77e040"},"/tools/misti/docs/next/detectors/ReadOnlyVariables-c98":{"__comp":"17896441","content":"f3297ff5"},"/tools/misti/docs/next/detectors/StringReceiversOverlap-992":{"__comp":"17896441","content":"0f37fc5e"},"/tools/misti/docs/next/detectors/UnboundLoops-8e3":{"__comp":"17896441","content":"299f32b1"},"/tools/misti/docs/next/detectors/UnusedOptional-1be":{"__comp":"17896441","content":"ed2e6971"},"/tools/misti/docs/next/detectors/ZeroAddress-f62":{"__comp":"17896441","content":"866ed13d"},"/tools/misti/docs/next/hacking/contributing-6f2":{"__comp":"17896441","content":"ed017323"},"/tools/misti/docs/next/hacking/custom-detector-249":{"__comp":"17896441","content":"ea8d0df0"},"/tools/misti/docs/next/hacking/design-f37":{"__comp":"17896441","content":"a5055d90"},"/tools/misti/docs/next/hacking/developing-misti-1c9":{"__comp":"17896441","content":"754ccd45"},"/tools/misti/docs/next/hacking/souffle-6f2":{"__comp":"17896441","content":"0fb6ae9c"},"/tools/misti/docs/next/tools-13f":{"__comp":"17896441","content":"2b785902"},"/tools/misti/docs/next/tools/DumpAst-959":{"__comp":"17896441","content":"d3996cd7"},"/tools/misti/docs/next/tools/DumpCfg-579":{"__comp":"17896441","content":"d2f295f4"},"/tools/misti/docs/next/tools/DumpConfig-d2a":{"__comp":"17896441","content":"012e8e66"},"/tools/misti/docs/next/tutorial/blueprint-885":{"__comp":"17896441","content":"0c8d0168"},"/tools/misti/docs/next/tutorial/ci-cd-c7b":{"__comp":"17896441","content":"e9524270"},"/tools/misti/docs/next/tutorial/cli-a3d":{"__comp":"17896441","content":"23b0c962"},"/tools/misti/docs/next/tutorial/configuration-79b":{"__comp":"17896441","content":"fbbe250b"},"/tools/misti/docs/next/tutorial/getting-started-390":{"__comp":"17896441","content":"b64540ae"},"/tools/misti/docs-e20":{"__comp":"a7bd4aaa","__props":"86d22c3d"},"/tools/misti/docs-38f":{"__comp":"a94703ab"},"/tools/misti/docs/-e5d":{"__comp":"17896441","content":"c7ee6afe"},"/tools/misti/docs/detectors-554":{"__comp":"17896441","content":"c82192ae"},"/tools/misti/docs/detectors/ArgCopyMutation-b98":{"__comp":"17896441","content":"3b3a1a75"},"/tools/misti/docs/detectors/AsmIsUsed-956":{"__comp":"17896441","content":"ea064c97"},"/tools/misti/docs/detectors/BranchDuplicate-959":{"__comp":"17896441","content":"7499c02a"},"/tools/misti/docs/detectors/ConstantAddress-680":{"__comp":"17896441","content":"4ab26116"},"/tools/misti/docs/detectors/DivideBeforeMultiply-5ee":{"__comp":"17896441","content":"3bfe497f"},"/tools/misti/docs/detectors/DumpIsUsed-d1c":{"__comp":"17896441","content":"8e426e62"},"/tools/misti/docs/detectors/DuplicatedCondition-dd5":{"__comp":"17896441","content":"e6ef21e7"},"/tools/misti/docs/detectors/EnsurePrgSeed-2e8":{"__comp":"17896441","content":"94d07e36"},"/tools/misti/docs/detectors/FalseCondition-b57":{"__comp":"17896441","content":"b64aaedd"},"/tools/misti/docs/detectors/FieldDoubleInit-201":{"__comp":"17896441","content":"602c5d84"},"/tools/misti/docs/detectors/InheritedStateMutation-955":{"__comp":"17896441","content":"a291c19d"},"/tools/misti/docs/detectors/NeverAccessedVariables-9ec":{"__comp":"17896441","content":"51fe41a6"},"/tools/misti/docs/detectors/OptimalMathFunction-54a":{"__comp":"17896441","content":"d7c99f30"},"/tools/misti/docs/detectors/PreferAugmentedAssign-945":{"__comp":"17896441","content":"8306354c"},"/tools/misti/docs/detectors/PreferredStdlibApi-f75":{"__comp":"17896441","content":"63bb535a"},"/tools/misti/docs/detectors/ReadOnlyVariables-3db":{"__comp":"17896441","content":"719e5d48"},"/tools/misti/docs/detectors/StringReceiversOverlap-640":{"__comp":"17896441","content":"f553073e"},"/tools/misti/docs/detectors/UnboundLoops-2e9":{"__comp":"17896441","content":"cf2c24d9"},"/tools/misti/docs/detectors/UnusedOptional-0d4":{"__comp":"17896441","content":"59016342"},"/tools/misti/docs/detectors/ZeroAddress-a60":{"__comp":"17896441","content":"91acf703"},"/tools/misti/docs/hacking/contributing-76d":{"__comp":"17896441","content":"1a8310a1"},"/tools/misti/docs/hacking/custom-detector-939":{"__comp":"17896441","content":"f58fcc43"},"/tools/misti/docs/hacking/design-c80":{"__comp":"17896441","content":"432cb5a5"},"/tools/misti/docs/hacking/developing-misti-3fc":{"__comp":"17896441","content":"42510f93"},"/tools/misti/docs/hacking/souffle-f7e":{"__comp":"17896441","content":"effcc73a"},"/tools/misti/docs/tools-945":{"__comp":"17896441","content":"150b97d9"},"/tools/misti/docs/tools/DumpAst-603":{"__comp":"17896441","content":"aee0b8cc"},"/tools/misti/docs/tools/DumpCfg-9f0":{"__comp":"17896441","content":"6696f09b"},"/tools/misti/docs/tools/DumpConfig-d0f":{"__comp":"17896441","content":"1b960128"},"/tools/misti/docs/tutorial/blueprint-697":{"__comp":"17896441","content":"6362ac9f"},"/tools/misti/docs/tutorial/ci-cd-768":{"__comp":"17896441","content":"f752d1db"},"/tools/misti/docs/tutorial/cli-04c":{"__comp":"17896441","content":"0c390d31"},"/tools/misti/docs/tutorial/configuration-408":{"__comp":"17896441","content":"0e4e7ef7"},"/tools/misti/docs/tutorial/getting-started-da2":{"__comp":"17896441","content":"a3df6930"},"/-e5f":{"__comp":"1df93b7f","__context":{"plugin":"a7456010"},"config":"5e9f5e1a"}}')}},e=>{e.O(0,[1869],(()=>{return t=8536,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/assets/js/main.0656ce4d.js.LICENSE.txt b/assets/js/main.0656ce4d.js.LICENSE.txt new file mode 100644 index 000000000..72c943689 --- /dev/null +++ b/assets/js/main.0656ce4d.js.LICENSE.txt @@ -0,0 +1,81 @@ +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +/*! Bundled license information: + +prismjs/prism.js: + (** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT <https://opensource.org/licenses/MIT> + * @author Lea Verou <https://lea.verou.me> + * @namespace + * @public + *) +*/ + +/** + * @file Prism.js definition for FunC + * @link https://docs.ton.org/develop/func/overview + * @version 0.4.4 + * @author Novus Nota (https://github.com/novusnota) + * @author Nikita Sobolev (https://github.com/sobolevn) + * @license MIT + */ + +/** + * @file Prism.js definition for Tact + * @link https://tact-lang.org + * @version 1.5.0 + * @author Novus Nota (https://github.com/novusnota) + * @license MIT + */ + +/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @license React + * react-jsx-runtime.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * @license React + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v16.13.1 + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ diff --git a/assets/js/runtime~main.5d851323.js b/assets/js/runtime~main.5d851323.js new file mode 100644 index 000000000..8fbd191e0 --- /dev/null +++ b/assets/js/runtime~main.5d851323.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,c,d,a,f,b={},t={};function r(e){var c=t[e];if(void 0!==c)return c.exports;var d=t[e]={id:e,loaded:!1,exports:{}};return b[e].call(d.exports,d,d.exports,r),d.loaded=!0,d.exports}r.m=b,r.c=t,e=[],r.O=(c,d,a,f)=>{if(!d){var b=1/0;for(i=0;i<e.length;i++){d=e[i][0],a=e[i][1],f=e[i][2];for(var t=!0,o=0;o<d.length;o++)(!1&f||b>=f)&&Object.keys(r.O).every((e=>r.O[e](d[o])))?d.splice(o--,1):(t=!1,f<b&&(b=f));if(t){e.splice(i--,1);var n=a();void 0!==n&&(c=n)}}return c}f=f||0;for(var i=e.length;i>0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[d,a,f]},r.n=e=>{var c=e&&e.__esModule?()=>e.default:()=>e;return r.d(c,{a:c}),c},d=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var f=Object.create(null);r.r(f);var b={};c=c||[null,d({}),d([]),d(d)];for(var t=2&a&&e;"object"==typeof t&&!~c.indexOf(t);t=d(t))Object.getOwnPropertyNames(t).forEach((c=>b[c]=()=>e[c]));return b.default=()=>e,r.d(f,b),f},r.d=(e,c)=>{for(var d in c)r.o(c,d)&&!r.o(e,d)&&Object.defineProperty(e,d,{enumerable:!0,get:c[d]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((c,d)=>(r.f[d](e,c),c)),[])),r.u=e=>"assets/js/"+({25:"122f6b32",106:"719e5d48",121:"743bfbca",186:"5815e0d3",219:"f58fcc43",223:"f553073e",243:"f5bf49b8",278:"f3466e67",301:"8df82fb6",321:"2bdf0f82",335:"ea8d0df0",338:"cf2c24d9",420:"2424092d",485:"effcc73a",488:"e1c88a01",494:"8c01191f",559:"1295da86",607:"0c8d0168",684:"aac87eb6",767:"a3df6930",804:"06bf7bd2",853:"299f32b1",877:"f97c3fca",906:"c00ee666",1006:"c49af6bd",1070:"0e4e7ef7",1084:"2b6a80d0",1114:"bd72ef9b",1171:"e3b47995",1179:"972c9666",1200:"0c390d31",1204:"693ffdbc",1235:"a7456010",1258:"150b97d9",1299:"43c93918",1318:"987a8a5d",1332:"a66f2ff0",1407:"86d22c3d",1417:"5a7ecd5b",1468:"acef80f0",1492:"273168fb",1519:"138db073",1529:"8272dc48",1537:"f3297ff5",1564:"773c7ee4",1598:"ff0db780",1638:"2f30e490",1678:"d6f3e79e",1687:"2257d06b",1697:"f5772bf1",2091:"f6f2b22b",2167:"e9524270",2187:"8d6fa39c",2195:"ca178ca4",2312:"c96954fa",2378:"72b7ad48",2397:"91ee281c",2478:"3b3a1a75",2537:"d2d53d04",2734:"49256311",2798:"c252c345",2819:"f503d00c",2903:"0b705376",2913:"42510f93",2991:"8e426e62",3150:"7499c02a",3175:"6934ebe4",3196:"2aa59687",3291:"91acf703",3304:"754ccd45",3361:"c377a04b",3388:"9fedf60a",3420:"1b73222b",3434:"edf1e52e",3448:"377c4f81",3462:"07f2fad9",3543:"26592ea2",3590:"d9542fcf",3684:"63bb535a",3750:"cc6d1ce2",3754:"f7ab1f3a",3812:"86d70222",3840:"432cb5a5",3884:"15d13f14",3890:"563af34e",4013:"2ace25e9",4024:"8d91c04d",4040:"d2aaf676",4069:"474ce197",4082:"e5aa38d8",4088:"304edb56",4111:"b80eaa74",4134:"393be207",4138:"ed017323",4318:"90b5d830",4330:"fafa7ec8",4371:"01419b1f",4442:"cd411a47",4583:"1df93b7f",4719:"602c5d84",4806:"2b785902",4861:"6f60ccd2",4875:"0c3de8e2",4903:"a291c19d",4984:"e6ef21e7",5097:"2d07d137",5122:"63a541b5",5200:"ce7f72c2",5316:"844f22a2",5321:"c82192ae",5345:"2cebbb1e",5381:"3bfe497f",5459:"c7ee6afe",5484:"a5055d90",5508:"ea064c97",5588:"b64aaedd",5602:"1c26cb06",5622:"aee0b8cc",5664:"d3996cd7",5742:"aba21aa0",5794:"61c19607",5859:"faae61e5",5900:"f752d1db",5922:"96e77fcb",5945:"e2ad9c7a",5983:"0fb6ae9c",6061:"1f391b9e",6156:"4f2bb7ce",6274:"8cf7c613",6286:"8c9dd45b",6340:"6f277b0e",6387:"ebcc9167",6406:"d15cc687",6412:"b64540ae",6544:"4518efa7",6551:"566d8483",6584:"be8ab43b",6602:"40be7dfa",6612:"7b5b3cc2",6633:"d1781038",6670:"b05af762",6695:"104c66c9",6701:"a8d7d639",6751:"59016342",6752:"fcd86191",6757:"cb77e040",6769:"4b89306f",6774:"3db5102b",6784:"23b0c962",6854:"fe7c01fc",6869:"81087c81",6948:"4fd06f05",6974:"866ed13d",6999:"1a50d306",7003:"cf5f971a",7005:"76268162",7083:"c55f1521",7098:"a7bd4aaa",7151:"776efca7",7173:"fbbe250b",7238:"883df8cc",7242:"d2f295f4",7348:"e4a43c7d",7378:"f4d075b1",7406:"24652b08",7495:"87ce9660",7677:"2018b81b",7682:"b78952d0",7702:"0ac52da9",7743:"1a8310a1",7787:"36ebdf3e",7837:"c5c1850c",7839:"8c0243db",7877:"8306354c",7965:"d147047e",8031:"b3799bec",8072:"d46ee8ed",8137:"dd8730c9",8221:"c5d65102",8235:"94d07e36",8262:"a7eb4927",8290:"51fe41a6",8300:"ed2e6971",8342:"775287ab",8401:"17896441",8422:"55e1201d",8513:"17406c9d",8546:"dc55925b",8607:"070671b7",8677:"c05c6791",8692:"bce595e9",8700:"012e8e66",8708:"1598dd73",8771:"c926d0d4",8836:"f2bdb0f5",8904:"d7c99f30",8917:"1418388c",8920:"1b960128",9048:"a94703ab",9076:"d7d99e1d",9108:"1869ccd1",9198:"8c74c05e",9276:"4ab26116",9304:"a8c496ca",9337:"f34cb5e0",9359:"b12d76e5",9415:"a4516edb",9417:"6696f09b",9428:"e3c4fe0a",9431:"6362ac9f",9601:"b91dc83b",9641:"e63578c3",9647:"5e95c892",9692:"0f37fc5e",9708:"5ec2195c",9758:"988b076a",9802:"4d74b396",9924:"8e8fe4d7",9959:"f18c7db7"}[e]||e)+"."+{25:"f6ee1737",106:"0bc6e809",121:"ba311b0c",186:"36349d47",219:"833fdf0f",223:"8eca43d2",243:"3b9a5601",278:"b2bd9e44",301:"5a9830a2",321:"11a0dcc1",335:"a9834690",338:"167088de",420:"88efacf6",485:"68126485",488:"26b5c812",494:"93ad2656",559:"6c981ca5",607:"c0afaf27",684:"6b5bbfc3",767:"b9e3fcca",804:"93cfb521",853:"3d9263b4",877:"6a842194",906:"951c69ba",1006:"85a90098",1070:"da1fd809",1084:"3d7eb50f",1114:"45e20252",1171:"2fccb84f",1179:"e5b493f7",1200:"29054261",1204:"20a90ba4",1235:"c6eb9a57",1258:"3c57e7f9",1299:"b3c5c4ff",1318:"bdfcfd74",1332:"c39f76e5",1407:"22d9a99e",1417:"08c83086",1468:"ccd7a032",1492:"26adb4b1",1519:"578334fd",1529:"d9a84b38",1537:"b24f1896",1564:"d71f2dd0",1598:"e64f7648",1638:"cf459bb9",1678:"d1be0df5",1687:"a740c88e",1697:"e894af92",2091:"1f2e8cc1",2167:"4f13728a",2187:"f2faae22",2195:"7d6ff74e",2237:"92070aeb",2312:"f94afa3f",2378:"f6676fe3",2397:"f53980f2",2478:"976ba85c",2537:"404d4960",2734:"be5c404d",2798:"a3cf3637",2819:"e7655ff6",2903:"0f6bdf25",2913:"7a5b306e",2991:"bf0771c3",3150:"f1eb98f3",3175:"7bcf9574",3196:"16070803",3291:"c00ee771",3304:"2081d519",3361:"8c30a29b",3388:"5a24888e",3420:"c47a22da",3434:"7e8e467f",3448:"79a338ae",3462:"76f75bf4",3543:"2dd4e9ca",3590:"bbcb88d0",3658:"8fe69683",3684:"ed747652",3750:"2f552c48",3754:"096a7a59",3812:"91cb640f",3840:"17016576",3884:"3309e304",3890:"29a0e834",4013:"6114563d",4024:"ef1dbebb",4040:"0ddaefea",4069:"29e1c442",4082:"17e7d0ef",4088:"1899324d",4111:"91abd0f7",4134:"fc96af0e",4138:"30666872",4318:"c162588e",4330:"f8fc7c04",4371:"55a4ac68",4442:"dbdd6a6b",4583:"4689c496",4719:"a9af00d9",4806:"b83e29b9",4861:"91c6f358",4875:"454cb0da",4903:"f1ac0d98",4984:"de959db6",5097:"1711bd45",5122:"cf91b4ad",5200:"19df7abf",5316:"2f80fdcf",5321:"b860298b",5345:"1c80f755",5381:"a61d7e8b",5459:"0b86ae18",5484:"503ae7a2",5508:"7b1162bd",5588:"88204f90",5602:"972f1ca6",5622:"c78b2bfe",5664:"0ca74802",5742:"d087865c",5794:"94c232da",5859:"d4f77930",5900:"9ec62e05",5922:"3fb77893",5945:"573d9426",5983:"e2818ac1",6061:"d1d4beb6",6156:"0a476d8d",6274:"47582d2c",6286:"c7a96e3d",6340:"89006761",6387:"b433e15d",6406:"df08049f",6412:"4fd9953e",6544:"b9ef0cc5",6551:"942257c5",6584:"f4a8e3dd",6602:"be7d2a62",6612:"90aa7fd2",6633:"35abe5aa",6670:"c54dcfb2",6695:"61be676d",6701:"ed43e771",6751:"fc899b97",6752:"e1395157",6757:"4c34ff27",6769:"efdf0920",6774:"08380390",6784:"e0d7957b",6854:"f82580ba",6869:"7da41d03",6948:"45b0f688",6974:"d4edfa4a",6999:"ff71f994",7003:"651efe6f",7005:"332975fc",7083:"cb9c8e4f",7098:"1b32332e",7151:"78ead050",7173:"022d69c3",7238:"ec17e966",7242:"6d5ee62f",7348:"d2da82aa",7378:"8ca57b63",7406:"91ed48d5",7495:"55512f80",7677:"63a7c757",7682:"efed39b1",7702:"865948a5",7743:"e63a2b77",7787:"c81514b8",7837:"d97c4482",7839:"7de6da6a",7877:"2bbb254d",7965:"c3db349f",8031:"86c01a35",8072:"7ed1c3f4",8137:"aeb151c7",8221:"924539a3",8235:"7adad0e3",8262:"90a54648",8290:"f649c3d3",8300:"1441e217",8342:"a34207ca",8401:"dc05340c",8422:"f5805772",8513:"759681c0",8546:"1af0a38f",8607:"a81bd6a1",8677:"1dfb4d97",8692:"46a0cb1c",8700:"af4e648f",8708:"06ff38aa",8771:"30e3ae68",8836:"256a666a",8904:"b0b05326",8917:"6eb86b98",8920:"5b5b59d9",9048:"9f24e801",9076:"67e2d007",9108:"5d76a4bd",9198:"09164805",9276:"4e3dc2f6",9304:"06cbb22b",9337:"b26c4fc7",9359:"d3ad221e",9415:"19e6546c",9417:"9d59dc8d",9428:"bf2b73e2",9431:"aa3d1fc1",9601:"a57e29d3",9641:"6cc338fe",9647:"0afa16e4",9692:"4a23afc4",9708:"a723ab4e",9758:"3beed1a8",9802:"8aebea31",9924:"7a82fd74",9959:"502a736a"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,c)=>Object.prototype.hasOwnProperty.call(e,c),a={},f="nowarp-github-io:",r.l=(e,c,d,b)=>{if(a[e])a[e].push(c);else{var t,o;if(void 0!==d)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var u=n[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==f+d){t=u;break}}t||(o=!0,(t=document.createElement("script")).charset="utf-8",t.timeout=120,r.nc&&t.setAttribute("nonce",r.nc),t.setAttribute("data-webpack",f+d),t.src=e),a[e]=[c];var l=(c,d)=>{t.onerror=t.onload=null,clearTimeout(s);var f=a[e];if(delete a[e],t.parentNode&&t.parentNode.removeChild(t),f&&f.forEach((e=>e(d))),c)return c(d)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={17896441:"8401",49256311:"2734",59016342:"6751",76268162:"7005","122f6b32":"25","719e5d48":"106","743bfbca":"121","5815e0d3":"186",f58fcc43:"219",f553073e:"223",f5bf49b8:"243",f3466e67:"278","8df82fb6":"301","2bdf0f82":"321",ea8d0df0:"335",cf2c24d9:"338","2424092d":"420",effcc73a:"485",e1c88a01:"488","8c01191f":"494","1295da86":"559","0c8d0168":"607",aac87eb6:"684",a3df6930:"767","06bf7bd2":"804","299f32b1":"853",f97c3fca:"877",c00ee666:"906",c49af6bd:"1006","0e4e7ef7":"1070","2b6a80d0":"1084",bd72ef9b:"1114",e3b47995:"1171","972c9666":"1179","0c390d31":"1200","693ffdbc":"1204",a7456010:"1235","150b97d9":"1258","43c93918":"1299","987a8a5d":"1318",a66f2ff0:"1332","86d22c3d":"1407","5a7ecd5b":"1417",acef80f0:"1468","273168fb":"1492","138db073":"1519","8272dc48":"1529",f3297ff5:"1537","773c7ee4":"1564",ff0db780:"1598","2f30e490":"1638",d6f3e79e:"1678","2257d06b":"1687",f5772bf1:"1697",f6f2b22b:"2091",e9524270:"2167","8d6fa39c":"2187",ca178ca4:"2195",c96954fa:"2312","72b7ad48":"2378","91ee281c":"2397","3b3a1a75":"2478",d2d53d04:"2537",c252c345:"2798",f503d00c:"2819","0b705376":"2903","42510f93":"2913","8e426e62":"2991","7499c02a":"3150","6934ebe4":"3175","2aa59687":"3196","91acf703":"3291","754ccd45":"3304",c377a04b:"3361","9fedf60a":"3388","1b73222b":"3420",edf1e52e:"3434","377c4f81":"3448","07f2fad9":"3462","26592ea2":"3543",d9542fcf:"3590","63bb535a":"3684",cc6d1ce2:"3750",f7ab1f3a:"3754","86d70222":"3812","432cb5a5":"3840","15d13f14":"3884","563af34e":"3890","2ace25e9":"4013","8d91c04d":"4024",d2aaf676:"4040","474ce197":"4069",e5aa38d8:"4082","304edb56":"4088",b80eaa74:"4111","393be207":"4134",ed017323:"4138","90b5d830":"4318",fafa7ec8:"4330","01419b1f":"4371",cd411a47:"4442","1df93b7f":"4583","602c5d84":"4719","2b785902":"4806","6f60ccd2":"4861","0c3de8e2":"4875",a291c19d:"4903",e6ef21e7:"4984","2d07d137":"5097","63a541b5":"5122",ce7f72c2:"5200","844f22a2":"5316",c82192ae:"5321","2cebbb1e":"5345","3bfe497f":"5381",c7ee6afe:"5459",a5055d90:"5484",ea064c97:"5508",b64aaedd:"5588","1c26cb06":"5602",aee0b8cc:"5622",d3996cd7:"5664",aba21aa0:"5742","61c19607":"5794",faae61e5:"5859",f752d1db:"5900","96e77fcb":"5922",e2ad9c7a:"5945","0fb6ae9c":"5983","1f391b9e":"6061","4f2bb7ce":"6156","8cf7c613":"6274","8c9dd45b":"6286","6f277b0e":"6340",ebcc9167:"6387",d15cc687:"6406",b64540ae:"6412","4518efa7":"6544","566d8483":"6551",be8ab43b:"6584","40be7dfa":"6602","7b5b3cc2":"6612",d1781038:"6633",b05af762:"6670","104c66c9":"6695",a8d7d639:"6701",fcd86191:"6752",cb77e040:"6757","4b89306f":"6769","3db5102b":"6774","23b0c962":"6784",fe7c01fc:"6854","81087c81":"6869","4fd06f05":"6948","866ed13d":"6974","1a50d306":"6999",cf5f971a:"7003",c55f1521:"7083",a7bd4aaa:"7098","776efca7":"7151",fbbe250b:"7173","883df8cc":"7238",d2f295f4:"7242",e4a43c7d:"7348",f4d075b1:"7378","24652b08":"7406","87ce9660":"7495","2018b81b":"7677",b78952d0:"7682","0ac52da9":"7702","1a8310a1":"7743","36ebdf3e":"7787",c5c1850c:"7837","8c0243db":"7839","8306354c":"7877",d147047e:"7965",b3799bec:"8031",d46ee8ed:"8072",dd8730c9:"8137",c5d65102:"8221","94d07e36":"8235",a7eb4927:"8262","51fe41a6":"8290",ed2e6971:"8300","775287ab":"8342","55e1201d":"8422","17406c9d":"8513",dc55925b:"8546","070671b7":"8607",c05c6791:"8677",bce595e9:"8692","012e8e66":"8700","1598dd73":"8708",c926d0d4:"8771",f2bdb0f5:"8836",d7c99f30:"8904","1418388c":"8917","1b960128":"8920",a94703ab:"9048",d7d99e1d:"9076","1869ccd1":"9108","8c74c05e":"9198","4ab26116":"9276",a8c496ca:"9304",f34cb5e0:"9337",b12d76e5:"9359",a4516edb:"9415","6696f09b":"9417",e3c4fe0a:"9428","6362ac9f":"9431",b91dc83b:"9601",e63578c3:"9641","5e95c892":"9647","0f37fc5e":"9692","5ec2195c":"9708","988b076a":"9758","4d74b396":"9802","8e8fe4d7":"9924",f18c7db7:"9959"}[e]||e,r.p+r.u(e)},(()=>{var e={5354:0,1869:0};r.f.j=(c,d)=>{var a=r.o(e,c)?e[c]:void 0;if(0!==a)if(a)d.push(a[2]);else if(/^(1869|5354)$/.test(c))e[c]=0;else{var f=new Promise(((d,f)=>a=e[c]=[d,f]));d.push(a[2]=f);var b=r.p+r.u(c),t=new Error;r.l(b,(d=>{if(r.o(e,c)&&(0!==(a=e[c])&&(e[c]=void 0),a)){var f=d&&("load"===d.type?"missing":d.type),b=d&&d.target&&d.target.src;t.message="Loading chunk "+c+" failed.\n("+f+": "+b+")",t.name="ChunkLoadError",t.type=f,t.request=b,a[1](t)}}),"chunk-"+c,c)}},r.O.j=c=>0===e[c];var c=(c,d)=>{var a,f,b=d[0],t=d[1],o=d[2],n=0;if(b.some((c=>0!==e[c]))){for(a in t)r.o(t,a)&&(r.m[a]=t[a]);if(o)var i=o(r)}for(c&&c(d);n<b.length;n++)f=b[n],r.o(e,f)&&e[f]&&e[f][0](),e[f]=0;return r.O(i)},d=self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[];d.forEach(c.bind(null,0)),d.push=c.bind(null,d.push.bind(d))})()})(); \ No newline at end of file diff --git a/img/blueprint-select-project.png b/img/blueprint-select-project.png new file mode 100644 index 0000000000000000000000000000000000000000..fbc35d186ac0f1719a101413ee5f8dee76e4d84e GIT binary patch literal 11492 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 literal 0 HcmV?d00001 diff --git a/img/cfg-example.svg b/img/cfg-example.svg new file mode 100644 index 000000000..5be9f234f --- /dev/null +++ b/img/cfg-example.svg @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.42.4 (0) + --> +<!-- Title: loops-3 Pages: 1 --> +<svg width="253pt" height="387pt" + viewBox="0.00 0.00 253.00 387.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 383)"> +<title>loops-3 + + +cluster_test + +test + + + +test_141 + +let sum: Int = 0 + + + +test_142 + +let i: Int = 0 + + + +test_141->test_142 + + + + + +test_144 + +repeat (10) + + + +test_142->test_144 + + + + + +test_146 + +i = i + 1 + + + +test_144->test_146 + + + + + +test_151 + +return sum + + + +test_144->test_151 + + + + + +test_148 + +sum = sum + i + + + +test_146->test_148 + + + + + +test_148->test_144 + + + + + diff --git a/img/favicon.png b/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..dfde088c027127a378dce9283d36676c24b4a212 GIT binary patch literal 1486 zcmV;<1u^=GP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x z00(qQO+^Rj2pbJHHqX^RuK)lAL`g(JR9M69ms^ZoRT;;B-#Ys;XYS$*m*SvJ8ze24 zBDO(544~8ihD1`IAjD7;jlQS>5)B~&1__D@iNr)6Opq926*aWB7D9v~3Bf{{5=vV- z(_yBZ&Y3xvnRCuQ`?A*O!83 zFYnCD=D>ro3Y4cQfZib@&v&+ITW0aYK&F$XW!r|}jJb15f$ut+(B0{={sO(;_xP;} z*R_Xoe%^15H!Uc1W>zkaQ#aAkZtk{LzEQ2S&#I|EyFTV;|9oY23jFz z9@5W<;g0USd_Nzs1`z}h0igw6il8F|=OE2MfzXFWgsn&X!#RCKmDdoGHGaa@4ee(p zu)u0pVU%HVMj4rc-9vD)uAFSNp2up+@Px8w z&{3*`k(N3D#wcweba!&rRIR!7)i=j`Uq3i8Pi^m`9o8v=s#BA`HKt@%`Qkdm>qV%< zP-wK~l_EW5$MH#J&p~DLK*H$AB$sdOqo+GS1cpvD*!glH`(Qju+k)KE1Uymt!z7(b zy|MuB6qM1((b*#;^_WQw5fMZLI8EaH5)2=!GJa%)_l{3<)Aa)sOEE9LR-!N&S3B}v zW3EYy5aJ48;uz?PJ^rJtQtGUE4H}yoCTp4--@sP=^!HX#F_lbDPI!+{b(I4%~}mNW6zus z1tapd?{SMN!v}tI^@2Ey9>@J1mME2K&hVHBWu2vasP>=5*n1-iie)4t1I-{bx`)yCuBS$igkrEf%ESsP)Ul>Hn(Ho{I3U2tAY zb`aquKPNv(Gsf1P>vPQ|YyLL^4{zVX=le1;$Ea`kt`VLQ)XfuLa3bxjAs+CzCRwWRwWziLJKR`p+S^Fwd3??8nO>$(S$W=z%f ozCX}j=EYxJxtesJ#Q!(`3$gij!v16_WB>pF07*qoM6N<$f>}z=fdBvi literal 0 HcmV?d00001 diff --git a/img/misti.png b/img/misti.png new file mode 100644 index 0000000000000000000000000000000000000000..bfe91a01fadce08d76de368f140eb199cb9579a8 GIT binary patch literal 489531 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�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 S;|R0&Vmu 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

+ + \ No newline at end of file diff --git a/lib/souffle-js/api/.nojekyll b/lib/souffle-js/api/.nojekyll new file mode 100644 index 000000000..e2ac6616a --- /dev/null +++ b/lib/souffle-js/api/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/lib/souffle-js/api/assets/custom.css b/lib/souffle-js/api/assets/custom.css new file mode 100644 index 000000000..bba952d7d --- /dev/null +++ b/lib/souffle-js/api/assets/custom.css @@ -0,0 +1 @@ +.tsd-navigation,body{background-color:var(--background-color)}:root{--primary-color:#0a3d62;--secondary-color:#34b3f1;--accent-color:#00e6e6;--light-color:#d3d3d3;--background-color:#fff}body{color:var(--primary-color)}a{color:var(--secondary-color)}.tsd-page-title h1{color:var(--accent-color)}.tsd-kind-class,.tsd-kind-enum,.tsd-kind-interface,.tsd-kind-module{border-left:5px solid var(--primary-color)} \ No newline at end of file diff --git a/lib/souffle-js/api/assets/highlight.css b/lib/souffle-js/api/assets/highlight.css new file mode 100644 index 000000000..af47ce524 --- /dev/null +++ b/lib/souffle-js/api/assets/highlight.css @@ -0,0 +1 @@ +:root{--light-hl-0:#795e26;--dark-hl-0:#dcdcaa;--light-hl-1:#000;--dark-hl-1:#d4d4d4;--light-hl-2:#a31515;--dark-hl-2:#ce9178;--light-hl-3:#00f;--dark-hl-3:#569cd6;--light-hl-4:#0070c1;--dark-hl-4:#4fc1ff;--light-hl-5:green;--dark-hl-5:#6a9955;--light-hl-6:#001080;--dark-hl-6:#9cdcfe;--light-hl-7:#e00;--dark-hl-7:#d7ba7d;--light-hl-8:#af00db;--dark-hl-8:#c586c0;--light-hl-9:#098658;--dark-hl-9:#b5cea8;--light-hl-10:#000;--dark-hl-10:#d4d4d4;--light-hl-11:#811f3f;--dark-hl-11:#d16969;--light-code-background:#fff;--dark-code-background:#1e1e1e}:root[data-theme=light]{--hl-0:var(--light-hl-0);--hl-1:var(--light-hl-1);--hl-2:var(--light-hl-2);--hl-3:var(--light-hl-3);--hl-4:var(--light-hl-4);--hl-5:var(--light-hl-5);--hl-6:var(--light-hl-6);--hl-7:var(--light-hl-7);--hl-8:var(--light-hl-8);--hl-9:var(--light-hl-9);--hl-10:var(--light-hl-10);--hl-11:var(--light-hl-11);--code-background:var(--light-code-background)}:root[data-theme=dark]{--hl-0:var(--dark-hl-0);--hl-1:var(--dark-hl-1);--hl-2:var(--dark-hl-2);--hl-3:var(--dark-hl-3);--hl-4:var(--dark-hl-4);--hl-5:var(--dark-hl-5);--hl-6:var(--dark-hl-6);--hl-7:var(--dark-hl-7);--hl-8:var(--dark-hl-8);--hl-9:var(--dark-hl-9);--hl-10:var(--dark-hl-10);--hl-11:var(--dark-hl-11);--code-background:var(--dark-code-background)}.hl-0{color:var(--hl-0)}.hl-1{color:var(--hl-1)}.hl-2{color:var(--hl-2)}.hl-3{color:var(--hl-3)}.hl-4{color:var(--hl-4)}.hl-5{color:var(--hl-5)}.hl-6{color:var(--hl-6)}.hl-7{color:var(--hl-7)}.hl-8{color:var(--hl-8)}.hl-9{color:var(--hl-9)}.hl-10{color:var(--hl-10)}.hl-11{color:var(--hl-11)}code,pre{background:var(--code-background)}@media (prefers-color-scheme:dark){:root{--hl-0:var(--dark-hl-0);--hl-1:var(--dark-hl-1);--hl-2:var(--dark-hl-2);--hl-3:var(--dark-hl-3);--hl-4:var(--dark-hl-4);--hl-5:var(--dark-hl-5);--hl-6:var(--dark-hl-6);--hl-7:var(--dark-hl-7);--hl-8:var(--dark-hl-8);--hl-9:var(--dark-hl-9);--hl-10:var(--dark-hl-10);--hl-11:var(--dark-hl-11);--code-background:var(--dark-code-background)}}@media (prefers-color-scheme:light){:root{--hl-0:var(--light-hl-0);--hl-1:var(--light-hl-1);--hl-2:var(--light-hl-2);--hl-3:var(--light-hl-3);--hl-4:var(--light-hl-4);--hl-5:var(--light-hl-5);--hl-6:var(--light-hl-6);--hl-7:var(--light-hl-7);--hl-8:var(--light-hl-8);--hl-9:var(--light-hl-9);--hl-10:var(--light-hl-10);--hl-11:var(--light-hl-11);--code-background:var(--light-code-background)}} \ No newline at end of file diff --git a/lib/souffle-js/api/assets/icons.js b/lib/souffle-js/api/assets/icons.js new file mode 100644 index 000000000..006f19c20 --- /dev/null +++ b/lib/souffle-js/api/assets/icons.js @@ -0,0 +1 @@ +!function t(){if("loading"===document.readyState)return document.addEventListener("DOMContentLoaded",t);const r=document.body.appendChild(document.createElementNS("http://www.w3.org/2000/svg","svg"));r.innerHTML='""',r.style.display="none","file:"===location.protocol&&document.querySelectorAll("use").forEach((t=>{t.getAttribute("href").includes("#icon-")&&t.setAttribute("href",t.getAttribute("href").replace(/.*#/,"#"))}))}(); \ No newline at end of file diff --git a/lib/souffle-js/api/assets/icons.svg b/lib/souffle-js/api/assets/icons.svg new file mode 100644 index 000000000..e371b8b5d --- /dev/null +++ b/lib/souffle-js/api/assets/icons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/souffle-js/api/assets/main.js b/lib/souffle-js/api/assets/main.js new file mode 100644 index 000000000..fba6725c2 --- /dev/null +++ b/lib/souffle-js/api/assets/main.js @@ -0,0 +1,2 @@ +/*! For license information please see main.js.LICENSE.txt */ +"use strict";window.translations={copy:"Copy",copied:"Copied!",normally_hidden:"This member is normally hidden due to your filter settings."},(()=>{var e,t,r=Object.create,n=Object.defineProperty,i=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,o=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,l=(e=(e,t)=>{!function(){var r,n=function(e){var t=new n.Builder;return t.pipeline.add(n.trimmer,n.stopWordFilter,n.stemmer),t.searchPipeline.add(n.stemmer),e.call(t,t),t.build()};n.version="2.3.9",n.utils={},n.utils.warn=(r=this,function(e){r.console&&console.warn&&console.warn(e)}),n.utils.asString=function(e){return null==e?"":e.toString()},n.utils.clone=function(e){if(null==e)return e;for(var t=Object.create(null),r=Object.keys(e),n=0;n0){var u=n.utils.clone(t)||{};u.position=[a,l],u.index=s.length,s.push(new n.Token(r.slice(a,o),u))}a=o+1}}return s},n.tokenizer.separator=/[\s\-]+/,n.Pipeline=function(){this._stack=[]},n.Pipeline.registeredFunctions=Object.create(null),n.Pipeline.registerFunction=function(e,t){t in this.registeredFunctions&&n.utils.warn("Overwriting existing registered function: "+t),e.label=t,n.Pipeline.registeredFunctions[e.label]=e},n.Pipeline.warnIfFunctionNotRegistered=function(e){e.label&&e.label in this.registeredFunctions||n.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},n.Pipeline.load=function(e){var t=new n.Pipeline;return e.forEach((function(e){var r=n.Pipeline.registeredFunctions[e];if(!r)throw new Error("Cannot load unregistered function: "+e);t.add(r)})),t},n.Pipeline.prototype.add=function(){Array.prototype.slice.call(arguments).forEach((function(e){n.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)}),this)},n.Pipeline.prototype.after=function(e,t){n.Pipeline.warnIfFunctionNotRegistered(t);var r=this._stack.indexOf(e);if(-1==r)throw new Error("Cannot find existingFn");r+=1,this._stack.splice(r,0,t)},n.Pipeline.prototype.before=function(e,t){n.Pipeline.warnIfFunctionNotRegistered(t);var r=this._stack.indexOf(e);if(-1==r)throw new Error("Cannot find existingFn");this._stack.splice(r,0,t)},n.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);-1!=t&&this._stack.splice(t,1)},n.Pipeline.prototype.run=function(e){for(var t=this._stack.length,r=0;r1&&(se&&(r=i),s!=e);)n=r-t,i=t+Math.floor(n/2),s=this.elements[2*i];return s==e||s>e?2*i:sa?u+=2:o==a&&(t+=r[l+1]*n[u+1],l+=2,u+=2);return t},n.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},n.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,r=0;t0){var o,a=s.str.charAt(0);a in s.node.edges?o=s.node.edges[a]:(o=new n.TokenSet,s.node.edges[a]=o),1==s.str.length&&(o.final=!0),i.push({node:o,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(0!=s.editsRemaining){if("*"in s.node.edges)var l=s.node.edges["*"];else l=new n.TokenSet,s.node.edges["*"]=l;if(0==s.str.length&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),1==s.str.length&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var u=s.node.edges["*"];else u=new n.TokenSet,s.node.edges["*"]=u;1==s.str.length&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var c,d=s.str.charAt(0),h=s.str.charAt(1);h in s.node.edges?c=s.node.edges[h]:(c=new n.TokenSet,s.node.edges[h]=c),1==s.str.length&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:d+s.str.slice(2)})}}}return r},n.TokenSet.fromString=function(e){for(var t=new n.TokenSet,r=t,i=0,s=e.length;i=e;t--){var r=this.uncheckedNodes[t],n=r.child.toString();n in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[n]:(r.child._str=n,this.minimizedNodes[n]=r.child),this.uncheckedNodes.pop()}},n.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},n.Index.prototype.search=function(e){return this.query((function(t){new n.QueryParser(e,t).parse()}))},n.Index.prototype.query=function(e){for(var t=new n.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),l=0;l1?1:e},n.Builder.prototype.k1=function(e){this._k1=e},n.Builder.prototype.add=function(e,t){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=t||{},this.documentCount+=1;for(var s=0;s=this.length)return n.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},n.QueryLexer.prototype.width=function(){return this.pos-this.start},n.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},n.QueryLexer.prototype.backup=function(){this.pos-=1},n.QueryLexer.prototype.acceptDigitRun=function(){var e,t;do{t=(e=this.next()).charCodeAt(0)}while(t>47&&t<58);e!=n.QueryLexer.EOS&&this.backup()},n.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(n.QueryLexer.TERM)),e.ignore(),e.more())return n.QueryLexer.lexText},n.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(n.QueryLexer.EDIT_DISTANCE),n.QueryLexer.lexText},n.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(n.QueryLexer.BOOST),n.QueryLexer.lexText},n.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(n.QueryLexer.TERM)},n.QueryLexer.termSeparator=n.tokenizer.separator,n.QueryLexer.lexText=function(e){for(;;){var t=e.next();if(t==n.QueryLexer.EOS)return n.QueryLexer.lexEOS;if(92!=t.charCodeAt(0)){if(":"==t)return n.QueryLexer.lexField;if("~"==t)return e.backup(),e.width()>0&&e.emit(n.QueryLexer.TERM),n.QueryLexer.lexEditDistance;if("^"==t)return e.backup(),e.width()>0&&e.emit(n.QueryLexer.TERM),n.QueryLexer.lexBoost;if("+"==t&&1===e.width()||"-"==t&&1===e.width())return e.emit(n.QueryLexer.PRESENCE),n.QueryLexer.lexText;if(t.match(n.QueryLexer.termSeparator))return n.QueryLexer.lexTerm}else e.escapeCharacter()}},n.QueryParser=function(e,t){this.lexer=new n.QueryLexer(e),this.query=t,this.currentClause={},this.lexemeIdx=0},n.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=n.QueryParser.parseClause;e;)e=e(this);return this.query},n.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},n.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},n.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},n.QueryParser.parseClause=function(e){var t=e.peekLexeme();if(null!=t)switch(t.type){case n.QueryLexer.PRESENCE:return n.QueryParser.parsePresence;case n.QueryLexer.FIELD:return n.QueryParser.parseField;case n.QueryLexer.TERM:return n.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+t.type;throw t.str.length>=1&&(r+=" with value '"+t.str+"'"),new n.QueryParseError(r,t.start,t.end)}},n.QueryParser.parsePresence=function(e){var t=e.consumeLexeme();if(null!=t){switch(t.str){case"-":e.currentClause.presence=n.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=n.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+t.str+"'";throw new n.QueryParseError(r,t.start,t.end)}var i=e.peekLexeme();if(null==i)throw r="expecting term or field, found nothing",new n.QueryParseError(r,t.start,t.end);switch(i.type){case n.QueryLexer.FIELD:return n.QueryParser.parseField;case n.QueryLexer.TERM:return n.QueryParser.parseTerm;default:throw r="expecting term or field, found '"+i.type+"'",new n.QueryParseError(r,i.start,i.end)}}},n.QueryParser.parseField=function(e){var t=e.consumeLexeme();if(null!=t){if(-1==e.query.allFields.indexOf(t.str)){var r=e.query.allFields.map((function(e){return"'"+e+"'"})).join(", "),i="unrecognised field '"+t.str+"', possible fields: "+r;throw new n.QueryParseError(i,t.start,t.end)}e.currentClause.fields=[t.str];var s=e.peekLexeme();if(null==s)throw i="expecting term, found nothing",new n.QueryParseError(i,t.start,t.end);if(s.type===n.QueryLexer.TERM)return n.QueryParser.parseTerm;throw i="expecting term, found '"+s.type+"'",new n.QueryParseError(i,s.start,s.end)}},n.QueryParser.parseTerm=function(e){var t=e.consumeLexeme();if(null!=t){e.currentClause.term=t.str.toLowerCase(),-1!=t.str.indexOf("*")&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(null==r)return void e.nextClause();switch(r.type){case n.QueryLexer.TERM:return e.nextClause(),n.QueryParser.parseTerm;case n.QueryLexer.FIELD:return e.nextClause(),n.QueryParser.parseField;case n.QueryLexer.EDIT_DISTANCE:return n.QueryParser.parseEditDistance;case n.QueryLexer.BOOST:return n.QueryParser.parseBoost;case n.QueryLexer.PRESENCE:return e.nextClause(),n.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new n.QueryParseError(i,r.start,r.end)}}},n.QueryParser.parseEditDistance=function(e){var t=e.consumeLexeme();if(null!=t){var r=parseInt(t.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new n.QueryParseError(i,t.start,t.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(null==s)return void e.nextClause();switch(s.type){case n.QueryLexer.TERM:return e.nextClause(),n.QueryParser.parseTerm;case n.QueryLexer.FIELD:return e.nextClause(),n.QueryParser.parseField;case n.QueryLexer.EDIT_DISTANCE:return n.QueryParser.parseEditDistance;case n.QueryLexer.BOOST:return n.QueryParser.parseBoost;case n.QueryLexer.PRESENCE:return e.nextClause(),n.QueryParser.parsePresence;default:throw i="Unexpected lexeme type '"+s.type+"'",new n.QueryParseError(i,s.start,s.end)}}},n.QueryParser.parseBoost=function(e){var t=e.consumeLexeme();if(null!=t){var r=parseInt(t.str,10);if(isNaN(r)){var i="boost must be numeric";throw new n.QueryParseError(i,t.start,t.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(null==s)return void e.nextClause();switch(s.type){case n.QueryLexer.TERM:return e.nextClause(),n.QueryParser.parseTerm;case n.QueryLexer.FIELD:return e.nextClause(),n.QueryParser.parseField;case n.QueryLexer.EDIT_DISTANCE:return n.QueryParser.parseEditDistance;case n.QueryLexer.BOOST:return n.QueryParser.parseBoost;case n.QueryLexer.PRESENCE:return e.nextClause(),n.QueryParser.parsePresence;default:throw i="Unexpected lexeme type '"+s.type+"'",new n.QueryParseError(i,s.start,s.end)}}},function(r,n){"function"==typeof define&&define.amd?define(n):"object"==typeof e?t.exports=n():r.lunr=n()}(this,(function(){return n}))}()},()=>(t||e((t={exports:{}}).exports,t),t.exports)),u=[];function c(e,t){u.push({selector:t,constructor:e})}var d=(e,t=100)=>{let r;return()=>{clearTimeout(r),r=setTimeout((()=>e()),t)}},h=((e,t,l)=>(l=null!=e?r(o(e)):{},((e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let l of s(t))!a.call(e,l)&&l!==r&&n(e,l,{get:()=>t[l],enumerable:!(o=i(t,l))||o.enumerable});return e})(!t&&e&&e.__esModule?l:n(l,"default",{value:e,enumerable:!0}),e)))(l());async function p(e,t){if(!window.searchData)return;let r=await fetch(window.searchData),n=new Blob([await r.arrayBuffer()]).stream().pipeThrough(new DecompressionStream("gzip")),i=await new Response(n).json();e.data=i,e.index=h.Index.load(i.index),t.classList.remove("loading"),t.classList.add("ready")}function f(e){e.classList.remove("has-focus")}function m(e,t,r){let n=e.querySelector(".current");if(n){let e=n;if(1===r)do{e=e.nextElementSibling??void 0}while(e instanceof HTMLElement&&null==e.offsetParent);else do{e=e.previousElementSibling??void 0}while(e instanceof HTMLElement&&null==e.offsetParent);e?(n.classList.remove("current"),e.classList.add("current")):-1===r&&(n.classList.remove("current"),t.focus())}else n=e.querySelector(1==r?"li:first-child":"li:last-child"),n&&n.classList.add("current")}function y(e,t){if(""===t)return e;let r=e.toLocaleLowerCase(),n=t.toLocaleLowerCase(),i=[],s=0,o=r.indexOf(n);for(;-1!=o;)i.push(v(e.substring(s,o)),`${v(e.substring(o,o+n.length))}`),s=o+n.length,o=r.indexOf(n,s);return i.push(v(e.substring(s))),i.join("")}var g={"&":"&","<":"<",">":">","'":"'",'"':"""};function v(e){return e.replace(/[&<>"'"]/g,(e=>g[e]))}var x=class{constructor(e){this.el=e.el,this.app=e.app}},w="mousedown",E="mousemove",b="mouseup",L={x:0,y:0},k=!1,S=!1,Q=!1,T=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(T?"is-mobile":"not-mobile"),T&&"ontouchstart"in document.documentElement&&(w="touchstart",E="touchmove",b="touchend"),document.addEventListener(w,(e=>{S=!0,Q=!1;let t="touchstart"==w?e.targetTouches[0]:e;L.y=t.pageY||0,L.x=t.pageX||0})),document.addEventListener(E,(e=>{if(S&&!Q){let t="touchstart"==w?e.targetTouches[0]:e,r=L.x-(t.pageX||0),n=L.y-(t.pageY||0);Q=Math.sqrt(r*r+n*n)>10}})),document.addEventListener(b,(()=>{S=!1})),document.addEventListener("click",(e=>{k&&(e.preventDefault(),e.stopImmediatePropagation(),k=!1)}));var P;try{P=localStorage}catch{P={getItem:()=>null,setItem(){}}}var I=P,O=document.head.appendChild(document.createElement("style"));O.dataset.for="filters";var C;function R(e){document.documentElement.dataset.theme=e}async function F(){let e=document.getElementById("tsd-nav-container");if(!e||!window.navigationData)return;let t=await(await fetch(window.navigationData)).arrayBuffer(),r=new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip")),n=await new Response(r).json();(C=e.dataset.base).endsWith("/")||(C+="/"),e.innerHTML="";for(let i of n)D(i,e,[]);window.app.createComponents(e),window.app.showPage(),window.app.ensureActivePageVisible()}function D(e,t,r){let n=t.appendChild(document.createElement("li"));if(e.children){let t=[...r,e.text],i=n.appendChild(document.createElement("details"));i.className=e.class?`${e.class} tsd-accordion`:"tsd-accordion";let s=i.appendChild(document.createElement("summary"));s.className="tsd-accordion-summary",s.dataset.key=t.join("$"),s.innerHTML='',N(e,s);let o=i.appendChild(document.createElement("div"));o.className="tsd-accordion-details";let a=o.appendChild(document.createElement("ul"));a.className="tsd-nested-navigation";for(let r of e.children)D(r,a,t)}else N(e,n,e.class)}function N(e,t,r){if(e.path){let n=t.appendChild(document.createElement("a"));n.href=C+e.path,r&&(n.className=r),location.pathname===n.pathname&&!n.href.includes("#")&&n.classList.add("current"),e.kind&&(n.innerHTML=``),n.appendChild(document.createElement("span")).textContent=e.text}else t.appendChild(document.createElement("span")).textContent=e.text}c(class extends x{constructor(e){super(e),this.className=this.el.dataset.toggle||"",this.el.addEventListener(b,(e=>this.onPointerUp(e))),this.el.addEventListener("click",(e=>e.preventDefault())),document.addEventListener(w,(e=>this.onDocumentPointerDown(e))),document.addEventListener(b,(e=>this.onDocumentPointerUp(e)))}setActive(e){if(this.active==e)return;this.active=e,document.documentElement.classList.toggle("has-"+this.className,e),this.el.classList.toggle("active",e);let t=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(t),setTimeout((()=>document.documentElement.classList.remove(t)),500)}onPointerUp(e){Q||(this.setActive(!0),e.preventDefault())}onDocumentPointerDown(e){if(this.active){if(e.target.closest(".col-sidebar, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(e){if(!Q&&this.active&&e.target.closest(".col-sidebar")){let t=e.target.closest("a");if(t){let e=window.location.href;-1!=e.indexOf("#")&&(e=e.substring(0,e.indexOf("#"))),t.href.substring(0,e.length)==e&&setTimeout((()=>this.setActive(!1)),250)}}}},"a[data-toggle]"),c(class extends x{constructor(e){super(e),this.summary=this.el.querySelector(".tsd-accordion-summary"),this.icon=this.summary.querySelector("svg"),this.key=`tsd-accordion-${this.summary.dataset.key??this.summary.textContent.trim().replace(/\s+/g,"-").toLowerCase()}`;let t=I.getItem(this.key);this.el.open=t?"true"===t:this.el.open,this.el.addEventListener("toggle",(()=>this.update()));let r=this.summary.querySelector("a");r&&r.addEventListener("click",(()=>{location.assign(r.href)})),this.update()}update(){this.icon.style.transform=`rotate(${this.el.open?0:-90}deg)`,I.setItem(this.key,this.el.open.toString())}},".tsd-accordion"),c(class extends x{constructor(e){super(e),this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",(()=>{this.setLocalStorage(this.el.checked)})),this.setLocalStorage(this.fromLocalStorage()),O.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; }\n`,this.app.updateIndexVisibility()}fromLocalStorage(){let e=I.getItem(this.key);return e?"true"===e:this.el.checked}setLocalStorage(e){I.setItem(this.key,e.toString()),this.value=e,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),this.app.filterChanged(),this.app.updateIndexVisibility()}},".tsd-filter-item input[type=checkbox]");var j=document.getElementById("tsd-theme");j&&function(e){let t=I.getItem("tsd-theme")||"os";e.value=t,R(t),e.addEventListener("change",(()=>{I.setItem("tsd-theme",e.value),R(e.value)}))}(j);var _=new class{constructor(){this.alwaysVisibleMember=null,this.createComponents(document.body),this.ensureFocusedElementVisible(),this.listenForCodeCopies(),window.addEventListener("hashchange",(()=>this.ensureFocusedElementVisible())),document.body.style.display||(this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}createComponents(e){u.forEach((t=>{e.querySelectorAll(t.selector).forEach((e=>{e.dataset.hasInstance||(new t.constructor({el:e,app:this}),e.dataset.hasInstance=String(!0))}))}))}filterChanged(){this.ensureFocusedElementVisible()}showPage(){document.body.style.display&&(document.body.style.removeProperty("display"),this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}scrollToHash(){if(location.hash){let e=document.getElementById(location.hash.substring(1));if(!e)return;e.scrollIntoView({behavior:"instant",block:"start"})}}ensureActivePageVisible(){let e=document.querySelector(".tsd-navigation .current"),t=e?.parentElement;for(;t&&!t.classList.contains(".tsd-navigation");)t instanceof HTMLDetailsElement&&(t.open=!0),t=t.parentElement;if(e&&!function(e){let t=e.getBoundingClientRect(),r=Math.max(document.documentElement.clientHeight,window.innerHeight);return!(t.bottom<0||t.top-r>=0)}(e)){let t=e.getBoundingClientRect().top-document.documentElement.clientHeight/4;document.querySelector(".site-menu").scrollTop=t,document.querySelector(".col-sidebar").scrollTop=t}}updateIndexVisibility(){let e=document.querySelector(".tsd-index-content"),t=e?.open;e&&(e.open=!0),document.querySelectorAll(".tsd-index-section").forEach((e=>{e.style.display="block";let t=Array.from(e.querySelectorAll(".tsd-index-link")).every((e=>null==e.offsetParent));e.style.display=t?"none":"block"})),e&&(e.open=t)}ensureFocusedElementVisible(){if(this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null),!location.hash)return;let e=document.getElementById(location.hash.substring(1));if(!e)return;let t=e.parentElement;for(;t&&"SECTION"!==t.tagName;)t=t.parentElement;if(!t)return;let r=null==t.offsetParent,n=t;for(;n!==document.body;)n instanceof HTMLDetailsElement&&(n.open=!0),n=n.parentElement;if(null==t.offsetParent){this.alwaysVisibleMember=t,t.classList.add("always-visible");let e=document.createElement("p");e.classList.add("warning"),e.textContent=window.translations.normally_hidden,t.prepend(e)}r&&e.scrollIntoView()}listenForCodeCopies(){document.querySelectorAll("pre > button").forEach((e=>{let t;e.addEventListener("click",(()=>{e.previousElementSibling instanceof HTMLElement&&navigator.clipboard.writeText(e.previousElementSibling.innerText.trim()),e.textContent=window.translations.copied,e.classList.add("visible"),clearTimeout(t),t=setTimeout((()=>{e.classList.remove("visible"),t=setTimeout((()=>{e.textContent=window.translations.copy}),100)}),1e3)}))}))}};Object.defineProperty(window,"app",{value:_}),function(){let e=document.getElementById("tsd-search");if(!e)return;let t={base:e.dataset.base+"/"},r=document.getElementById("tsd-search-script");e.classList.add("loading"),r&&(r.addEventListener("error",(()=>{e.classList.remove("loading"),e.classList.add("failure")})),r.addEventListener("load",(()=>{p(t,e)})),p(t,e));let n=document.querySelector("#tsd-search input"),i=document.querySelector("#tsd-search .results");if(!n||!i)throw new Error("The input field or the result list wrapper was not found");i.addEventListener("mouseup",(()=>{f(e)})),n.addEventListener("focus",(()=>e.classList.add("has-focus"))),function(e,t,r,n){r.addEventListener("input",d((()=>{!function(e,t,r,n){if(!n.index||!n.data)return;t.textContent="";let i,s=r.value.trim();if(s){let e=s.split(" ").map((e=>e.length?`*${e}*`:"")).join(" ");i=n.index.search(e)}else i=[];for(let o=0;ot.score-e.score));for(let o=0,a=Math.min(10,i.length);o`,a=y(e.name,s);globalThis.DEBUG_SEARCH_WEIGHTS&&(a+=` (score: ${i[o].score.toFixed(2)})`),e.parent&&(a=`\n ${y(e.parent,s)}.${a}`);let l=document.createElement("li");l.classList.value=e.classes??"";let u=document.createElement("a");u.href=n.base+e.url,u.innerHTML=r+a,l.append(u),u.addEventListener("focus",(()=>{t.querySelector(".current")?.classList.remove("current"),l.classList.add("current")})),t.appendChild(l)}}(0,t,r,n)}),200)),r.addEventListener("keydown",(n=>{"Enter"==n.key?function(e,t){let r=e.querySelector(".current");if(r||(r=e.querySelector("li:first-child")),r){let e=r.querySelector("a");e&&(window.location.href=e.href),f(t)}}(t,e):"ArrowUp"==n.key?(m(t,r,-1),n.preventDefault()):"ArrowDown"===n.key&&(m(t,r,1),n.preventDefault())})),document.body.addEventListener("keypress",(e=>{e.altKey||e.ctrlKey||e.metaKey||!r.matches(":focus")&&"/"===e.key&&(e.preventDefault(),r.focus())})),document.body.addEventListener("keyup",(n=>{e.classList.contains("has-focus")&&("Escape"===n.key||!t.matches(":focus-within")&&!r.matches(":focus"))&&(r.blur(),f(e))}))}(e,i,n,t)}(),function(){let e=document.getElementById("tsd-nav-script");e&&(e.addEventListener("load",F),F())}()})(); \ No newline at end of file diff --git a/lib/souffle-js/api/assets/main.js.LICENSE.txt b/lib/souffle-js/api/assets/main.js.LICENSE.txt new file mode 100644 index 000000000..67510dae1 --- /dev/null +++ b/lib/souffle-js/api/assets/main.js.LICENSE.txt @@ -0,0 +1,54 @@ +/*! Bundled license information: + +lunr/lunr.js: + (** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + *) + (*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + *) + (*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + *) +*/ diff --git a/lib/souffle-js/api/assets/navigation.js b/lib/souffle-js/api/assets/navigation.js new file mode 100644 index 000000000..318f89954 --- /dev/null +++ b/lib/souffle-js/api/assets/navigation.js @@ -0,0 +1 @@ +window.navigationData="data:application/octet-stream;base64,H4sIAAAAAAAAA62a227bOBCG30W9NbZN6qbb3KWJAxgo6sDe9KYIAkamHWElSqWoNMai777QwbaGHHKGSe4C659vhucZMj//S4x8Nsl5kpaq+2uSVMI8JudJUa6bXNbvhw9/PZoiTybJv5laJ+enkyR9zPK1lio5/3mArMpms8nlpc1Kc1HXIxbUQfTJ6d9/7v5MDkxZZMZI7QY2fIgJbGaz9oHtWVBHBKZ1qWskru73qLBaCySoHjQWuRFNHNizTBuTlYpHBWoGfq6M1ErkLDoQM+C3tdjyeuOoJAapa1+JTZ/hS8xAXdQ7lc54yHcem97P9OTL9OOHaWD4lrJucmQ9ok5cK5YbdiNi4y/1jdCiwFZHCH8wIpwsGlM1Zil+M/ljPQu9MrpJTaPlOsoDMCMcreKn0oo3k+g5f/+Gk/+wPh02ZsfewKJcRNDxbic9rF7WBnsVZO2GuBEppzG9rTVCn84itgyzq2hHBzvL04cvn08+nYLNVHe6wKK+HxQx08q/4JxB2dM9lsFxqUQqV7ISWhi5vhG6RtMAxxNixhh+ZH+yxgJtylL8xgfh6KBqQ1ja47BpVNoOJOJgbADhZ1MPt53r0ezWiOLD3vwh8kZGNAKzdjzegQmbqbV8dqdr9zNrjgpTFiH7d4PAtxU/ZEro3WWpaqNFppDjfMRCxF5uud6FWb3Ab1/mUihuYIjaR07LopAE76jxU5QRmaqZAaJyH3sj0jBtEPjsC2HSR2ZgrtZHrXS51SI82Y4aH0XLXLRrKIgZibycJpdhRi/w5jiL2+vrb7P7H7Plar74HkS5WiJzIrLwMfpFKfgFteihjqBdMhaEIyWZrNmHqWkyfg2AYgcpxWxqUxb/7KrwlMLUVLHhuxtwsUcpxfzVZE8ilyqVbRBXcpOpjFxTDGPKLyx7Az4GIbeQ5INti9eWqgEXr69TffC3KFL9bG6Fek0dMlDHoHUJDxe5FxNcz2WOn20bEPzv5ZoV8qB7edXvIt+05PfhY+r9Gy2N2d3orgTkuLANSH5WZCZ7ktyN1jaI4bMnI2pFeqJTIUfKY86U0eHEGdcT9CUn7XK1TOqF3saAeznFphI8qGPQvlIliaulbsiah7Zqjj+FfYavupFD3ERlldxlyVuN8Z0S2xvYXbyfDtQ+MtkFRNuHJpCIXgMp42uBvNxusT24/511MXAlN6LJzTeLtL9IGkhAFbo3mtug0UXhwJpjlPY+cNyyKnzIgM8xl3Sew2vfXMjFbMKvNPVOGYFc1PS/R11Sg9qtv3QbKCMFdcvmK90w3iBiI93KDafuddFgcFyE2Rd6G41fVFz6ouLCkQIRRR90TDCjlsP8eM2YbmHyj3loFREwK93yETsZEwtTc4zYKpgwT+6JUYH0JXhGX7h6tiMr88TpnSgOaSWeAW6nZMLdvBMD71WRUHIfGQkj0fMFjzxfcMEgnUWRTc6dBW426wO2KiaUSGYxD6gJ0x29ECPWX0zQnGjdo78/NJrUoP9R42pYKQHsg32ugsDcroDZmZN3EqwruQnhhowhsJEB4lhODRh8rzq+qCFY4eRB4MHO/3IVpNpmIQ9giYWpzjqzSN7XLAJr2QV8OO9aQXKKJYUWz//CRaBtw4AX+NYV5G6clASQvK9eQahlFXogto/eILfCzmDAc1/CgkCNnpGQCM6YMM05bM6myK53a7Lcu911H1n7nPx1SP7Q5/Qxb6wNRvgkdY3eLAwfeEWZ7xnwSehMPIxxlhTiP7Znxt3/AnN2ea0qAAA="; \ No newline at end of file diff --git a/lib/souffle-js/api/assets/search.js b/lib/souffle-js/api/assets/search.js new file mode 100644 index 000000000..f53e765e9 --- /dev/null +++ b/lib/souffle-js/api/assets/search.js @@ -0,0 +1 @@ +window.searchData="data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/lib/souffle-js/api/assets/style.css b/lib/souffle-js/api/assets/style.css new file mode 100644 index 000000000..589d16137 --- /dev/null +++ b/lib/souffle-js/api/assets/style.css @@ -0,0 +1 @@ +.tsd-typography ol,.tsd-typography p,.tsd-typography ul,blockquote,dl,menu,ol,ul{margin:1em 0}.settings-label,.tsd-hierarchy .target,.tsd-page-toolbar a.title{font-weight:700}#tsd-search .field input,#tsd-search .title,.tsd-anchor,.tsd-member,pre{position:relative}#tsd-search .results li.current:not(.no-results),#tsd-search .results li:hover:not(.no-results),#tsd-search.has-focus,.tsd-widget.active{background-color:var(--color-accent)}:root{--light-color-background:#f2f4f8;--light-color-background-secondary:#eff0f1;--light-color-warning-text:#222;--light-color-background-warning:#e6e600;--light-color-icon-background:var(--light-color-background);--light-color-accent:#c5c7c9;--light-color-active-menu-item:var(--light-color-accent);--light-color-text:#222;--light-color-text-aside:#6e6e6e;--light-color-link:#1f70c2;--light-color-focus-outline:#3584e4;--light-color-ts-keyword:#056bd6;--light-color-ts-project:#b111c9;--light-color-ts-module:var(--light-color-ts-project);--light-color-ts-namespace:var(--light-color-ts-project);--light-color-ts-enum:#7e6f15;--light-color-ts-enum-member:var(--light-color-ts-enum);--light-color-ts-variable:#4760ec;--light-color-ts-function:#572be7;--light-color-ts-class:#1f70c2;--light-color-ts-interface:#108024;--light-color-ts-constructor:var(--light-color-ts-class);--light-color-ts-property:var(--light-color-ts-variable);--light-color-ts-method:var(--light-color-ts-function);--light-color-ts-call-signature:var(--light-color-ts-method);--light-color-ts-index-signature:var(--light-color-ts-property);--light-color-ts-constructor-signature:var(--light-color-ts-constructor);--light-color-ts-parameter:var(--light-color-ts-variable);--light-color-ts-type-parameter:#a55c0e;--light-color-ts-accessor:var(--light-color-ts-property);--light-color-ts-get-signature:var(--light-color-ts-accessor);--light-color-ts-set-signature:var(--light-color-ts-accessor);--light-color-ts-type-alias:#d51270;--light-color-document:#000;--light-external-icon:url("data:image/svg+xml;utf8,");--light-color-scheme:light;--dark-color-background:#2b2e33;--dark-color-background-secondary:#1e2024;--dark-color-background-warning:#bebe00;--dark-color-warning-text:#222;--dark-color-icon-background:var(--dark-color-background-secondary);--dark-color-accent:#9096a2;--dark-color-active-menu-item:#5d5d6a;--dark-color-text:#f5f5f5;--dark-color-text-aside:#ddd;--dark-color-link:#00aff4;--dark-color-focus-outline:#4c97f2;--dark-color-ts-keyword:#39f;--dark-color-ts-project:#e358ff;--dark-color-ts-module:var(--dark-color-ts-project);--dark-color-ts-namespace:var(--dark-color-ts-project);--dark-color-ts-enum:#f4d93e;--dark-color-ts-enum-member:var(--dark-color-ts-enum);--dark-color-ts-variable:#798dff;--dark-color-ts-function:#a280ff;--dark-color-ts-class:#8ac4ff;--dark-color-ts-interface:#6cff87;--dark-color-ts-constructor:var(--dark-color-ts-class);--dark-color-ts-property:var(--dark-color-ts-variable);--dark-color-ts-method:var(--dark-color-ts-function);--dark-color-ts-call-signature:var(--dark-color-ts-method);--dark-color-ts-index-signature:var(--dark-color-ts-property);--dark-color-ts-constructor-signature:var(--dark-color-ts-constructor);--dark-color-ts-parameter:var(--dark-color-ts-variable);--dark-color-ts-type-parameter:#e07d13;--dark-color-ts-accessor:var(--dark-color-ts-property);--dark-color-ts-get-signature:var(--dark-color-ts-accessor);--dark-color-ts-set-signature:var(--dark-color-ts-accessor);--dark-color-ts-type-alias:#ff6492;--dark-color-document:#fff;--dark-external-icon:url("data:image/svg+xml;utf8,");--dark-color-scheme:dark}html{color-scheme:var(--color-scheme)}.tsd-kind-icon~span,a.tsd-anchor-link,body{color:var(--color-text)}:root[data-theme=light]{--color-background:var(--light-color-background);--color-background-secondary:var(--light-color-background-secondary);--color-background-warning:var(--light-color-background-warning);--color-warning-text:var(--light-color-warning-text);--color-icon-background:var(--light-color-icon-background);--color-accent:var(--light-color-accent);--color-active-menu-item:var(--light-color-active-menu-item);--color-text:var(--light-color-text);--color-text-aside:var(--light-color-text-aside);--color-link:var(--light-color-link);--color-focus-outline:var(--light-color-focus-outline);--color-ts-keyword:var(--light-color-ts-keyword);--color-ts-module:var(--light-color-ts-module);--color-ts-namespace:var(--light-color-ts-namespace);--color-ts-enum:var(--light-color-ts-enum);--color-ts-enum-member:var(--light-color-ts-enum-member);--color-ts-variable:var(--light-color-ts-variable);--color-ts-function:var(--light-color-ts-function);--color-ts-class:var(--light-color-ts-class);--color-ts-interface:var(--light-color-ts-interface);--color-ts-constructor:var(--light-color-ts-constructor);--color-ts-property:var(--light-color-ts-property);--color-ts-method:var(--light-color-ts-method);--color-ts-call-signature:var(--light-color-ts-call-signature);--color-ts-index-signature:var(--light-color-ts-index-signature);--color-ts-constructor-signature:var(--light-color-ts-constructor-signature);--color-ts-parameter:var(--light-color-ts-parameter);--color-ts-type-parameter:var(--light-color-ts-type-parameter);--color-ts-accessor:var(--light-color-ts-accessor);--color-ts-get-signature:var(--light-color-ts-get-signature);--color-ts-set-signature:var(--light-color-ts-set-signature);--color-ts-type-alias:var(--light-color-ts-type-alias);--color-document:var(--light-color-document);--external-icon:var(--light-external-icon);--color-scheme:var(--light-color-scheme)}:root[data-theme=dark]{--color-background:var(--dark-color-background);--color-background-secondary:var(--dark-color-background-secondary);--color-background-warning:var(--dark-color-background-warning);--color-warning-text:var(--dark-color-warning-text);--color-icon-background:var(--dark-color-icon-background);--color-accent:var(--dark-color-accent);--color-active-menu-item:var(--dark-color-active-menu-item);--color-text:var(--dark-color-text);--color-text-aside:var(--dark-color-text-aside);--color-link:var(--dark-color-link);--color-focus-outline:var(--dark-color-focus-outline);--color-ts-keyword:var(--dark-color-ts-keyword);--color-ts-module:var(--dark-color-ts-module);--color-ts-namespace:var(--dark-color-ts-namespace);--color-ts-enum:var(--dark-color-ts-enum);--color-ts-enum-member:var(--dark-color-ts-enum-member);--color-ts-variable:var(--dark-color-ts-variable);--color-ts-function:var(--dark-color-ts-function);--color-ts-class:var(--dark-color-ts-class);--color-ts-interface:var(--dark-color-ts-interface);--color-ts-constructor:var(--dark-color-ts-constructor);--color-ts-property:var(--dark-color-ts-property);--color-ts-method:var(--dark-color-ts-method);--color-ts-call-signature:var(--dark-color-ts-call-signature);--color-ts-index-signature:var(--dark-color-ts-index-signature);--color-ts-constructor-signature:var(--dark-color-ts-constructor-signature);--color-ts-parameter:var(--dark-color-ts-parameter);--color-ts-type-parameter:var(--dark-color-ts-type-parameter);--color-ts-accessor:var(--dark-color-ts-accessor);--color-ts-get-signature:var(--dark-color-ts-get-signature);--color-ts-set-signature:var(--dark-color-ts-set-signature);--color-ts-type-alias:var(--dark-color-ts-type-alias);--color-document:var(--dark-color-document);--external-icon:var(--dark-external-icon);--color-scheme:var(--dark-color-scheme)}.tsd-accordion-summary:focus-visible svg,:focus-visible{outline:2px solid var(--color-focus-outline)}.always-visible,.always-visible .tsd-signatures{display:inherit!important}h1,h2,h3,h4,h5,h6{line-height:1.2}h1{font-size:1.875rem;margin:.67rem 0}h2{font-size:1.5rem;margin:.83rem 0}h3{font-size:1.25rem;margin:1rem 0}h4{font-size:1.05rem;margin:1.33rem 0}h5{font-size:1rem;margin:1.5rem 0}h6{font-size:.875rem;margin:2.33rem 0}dd{margin:0 0 0 40px}.container{max-width:1700px;padding:0 2rem}footer{border-top:1px solid var(--color-accent);max-height:3.5rem;padding-bottom:1rem;padding-top:1rem}footer>p{margin:0 1em}.container-main{margin:0 auto;min-height:calc(100vh - 97px - 4rem)}@keyframes a{0%{opacity:0}to{opacity:1}}@keyframes b{0%{opacity:1;visibility:visible}to{opacity:0}}@keyframes c{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes d{0%{transform:translate(0);visibility:visible}to{transform:translate(100%)}}body{margin:0;background:var(--color-background);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;font-size:16px}.tsd-signature,code,pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}a{color:var(--color-link);text-decoration:none}#tsd-toolbar-links a:hover,.tsd-breadcrumb a:hover,.tsd-navigation a:hover,.tsd-page-navigation a:hover,.tsd-page-toolbar a.title:hover,a:hover{text-decoration:underline}a.external[target=_blank]{background-image:var(--external-icon);background-position:top 3px right;background-repeat:no-repeat;padding-right:13px}code,pre{border-radius:.8em;font-size:.875rem;margin:0;padding:.2em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word;border:1px solid var(--color-accent);padding:10px}pre code{font-size:100%;padding:0}pre>button{box-sizing:border-box;opacity:0;position:absolute;right:10px;top:10px;transition:opacity .1s}pre:hover>button,pre>button.visible{opacity:1}blockquote{border-left:4px solid gray;padding-left:1em}.tsd-typography{line-height:1.333em}.tsd-typography ul{list-style:square;padding:0 0 0 20px}.tsd-index-panel .tsd-typography h3,.tsd-typography .tsd-index-panel h3,.tsd-typography h4,.tsd-typography h5,.tsd-typography h6{font-size:1em}.tsd-typography h5,.tsd-typography h6{font-weight:400}.tsd-typography table{border:none;border-collapse:collapse}.tsd-typography td,.tsd-typography th{border:1px solid var(--color-accent);padding:6px 13px}#tsd-search .results li:nth-child(2n),.tsd-typography thead,.tsd-typography tr:nth-child(2n){background-color:var(--color-background-secondary)}.tsd-breadcrumb{color:var(--color-text-aside);margin:0;padding:0}.tsd-breadcrumb a{color:var(--color-text-aside);text-decoration:none}.tsd-breadcrumb li{display:inline}.tsd-breadcrumb li:after{content:" / "}.tsd-comment-tags{display:flex;flex-direction:column}dl.tsd-comment-tag-group{align-items:center;display:flex;margin:.5em 0;overflow:hidden}dl.tsd-comment-tag-group dt{display:flex;font-size:.875em;font-weight:400;margin-right:.5em}.tsd-widget.no-caption:before,dl.tsd-comment-tag-group dd,dl.tsd-comment-tag-group p{margin:0}code.tsd-tag{border:.1em solid var(--color-accent);font-size:70%;margin-right:.25em;padding:.25em .4em}h1 code.tsd-tag:first-of-type{margin-left:.25em}dl.tsd-comment-tag-group dd:after,dl.tsd-comment-tag-group dd:before{content:" "}dl.tsd-comment-tag-group dd pre,dl.tsd-comment-tag-group dd:after{clear:both}.tsd-panel.tsd-comment .lead{font-size:1.1em;line-height:1.333em;margin-bottom:2em}#tsd-sidebar-links a:last-of-type,.tsd-panel.tsd-comment .lead:last-child{margin-bottom:0}.tsd-filter-visibility h4{font-size:1rem;margin:0;padding-bottom:.5rem;padding-top:.75rem}.tsd-filter-item:not(:last-child){margin-bottom:.5rem}.tsd-filter-input{align-items:center;cursor:pointer;display:flex;-webkit-user-select:none;user-select:none;width:-moz-fit-content;width:fit-content}.settings-label,.tsd-flag,.tsd-widget{display:inline-block}.tsd-filter-input input[type=checkbox]{cursor:pointer;height:1.5em;opacity:0;position:absolute;width:1.5em}.tsd-filter-input input[type=checkbox]:disabled{pointer-events:none}.tsd-filter-input svg{border-radius:.33em;cursor:pointer;height:1.5em;margin-right:.5em;opacity:.99;width:1.5em}.tsd-filter-input input[type=checkbox]:focus-visible+svg{outline:2px solid var(--color-focus-outline)}.tsd-checkbox-background{fill:var(--color-accent)}input[type=checkbox]:checked~svg .tsd-checkbox-checkmark{stroke:var(--color-text)}.tsd-filter-input input:disabled~svg>.tsd-checkbox-background{fill:var(--color-background);stroke:var(--color-accent);stroke-width:.25rem}.tsd-filter-input input:disabled~svg>.tsd-checkbox-checkmark{stroke:var(--color-accent)}.settings-label{text-transform:uppercase}.tsd-filter-visibility .settings-label{margin:.75rem 0 .5rem}.tsd-theme-toggle .settings-label{margin:.75rem .75rem 0 0}.tsd-hierarchy{list-style:square;margin:0}.tsd-full-hierarchy:not(:last-child){border-bottom:1px solid var(--color-accent);margin-bottom:1em;padding-bottom:1em}.tsd-full-hierarchy,.tsd-full-hierarchy ul{list-style:none;margin:0;padding:0}.tsd-full-hierarchy ul{padding-left:1.5rem}.tsd-full-hierarchy a{align-items:center;color:var(--color-text);display:inline-flex;font-size:1rem;padding:.25rem 0!important}.tsd-index-panel .tsd-index-list{column-gap:1rem;display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:auto;line-height:1.333em;list-style:none;margin:0;overflow:hidden;padding:.25rem 0 0}.tsd-index-panel .tsd-index-list li{-webkit-page-break-inside:avoid;-moz-page-break-inside:avoid;-ms-page-break-inside:avoid;-o-page-break-inside:avoid;page-break-inside:avoid}.tsd-flag{background-color:var(--color-comment-tag);border-radius:4px;color:var(--color-comment-tag-text);font-size:75%;font-weight:400;line-height:1;padding:.25em .4em;text-indent:0}.tsd-anchor{top:-100px}.tsd-member .tsd-anchor+h3{align-items:center;border-bottom:none;display:flex;margin-bottom:0;margin-top:0}.tsd-navigation.settings{margin:1rem 0}.tsd-navigation .tsd-accordion-summary,.tsd-navigation>a{align-items:center;display:flex;width:calc(100% - .25rem)}#tsd-search .results li.state,.tsd-navigation .tsd-nav-link,.tsd-panel:empty,.tsd-widget.menu,.tsd-widget.options{display:none}.tsd-navigation a,.tsd-navigation summary>span,.tsd-page-navigation a{align-items:center;box-sizing:border-box;color:var(--color-text);display:flex;padding:.25rem;text-decoration:none;width:calc(100% - .25rem)}.tsd-navigation a.current,.tsd-page-navigation a.current{background:var(--color-active-menu-item)}.tsd-navigation ul,.tsd-page-navigation ul{list-style:none;margin-bottom:0;margin-top:0;padding:0}.tsd-navigation li,.tsd-page-navigation li{max-width:100%;padding:0}.tsd-nested-navigation{margin-left:3rem}.tsd-nested-navigation>li>details,.tsd-small-nested-navigation>li>details{margin-left:-1.5rem}#tsd-toolbar-links a,.tsd-small-nested-navigation{margin-left:1.5rem}.tsd-page-navigation-section{margin-left:10px}.tsd-page-navigation-section>summary{padding:.25rem}.tsd-page-navigation-section>div{margin-left:20px}.tsd-page-navigation ul{padding-left:1.75rem}#tsd-sidebar-links a{line-height:1.25rem;margin-bottom:.5rem;margin-top:0}a.tsd-index-link{align-items:center;color:var(--color-text);display:inline-flex;font-size:1rem;line-height:1.25rem;padding:.25rem 0!important}.tsd-accordion-summary{list-style-type:none;outline:0}.tsd-accordion-summary::-webkit-details-marker{display:none}.tsd-accordion-summary,.tsd-accordion-summary a{cursor:pointer;-webkit-user-select:none;user-select:none}.tsd-accordion-summary a{width:calc(100% - 1.5rem)}.tsd-accordion-summary>*{margin-bottom:0;margin-top:0;padding-bottom:0;padding-top:0}.tsd-accordion .tsd-accordion-summary>svg{margin-left:.25rem;vertical-align:text-top}.tsd-index-content>:not(:first-child){margin-top:.75rem}.tsd-index-heading{margin-bottom:.75rem;margin-top:1.5rem}.tsd-kind-icon{height:1.25rem;margin-right:.5rem;min-height:1.25rem;min-width:1.25rem;width:1.25rem}.tsd-kind-icon path{transform:scale(1.1);transform-origin:center}.tsd-signature>.tsd-kind-icon{margin-right:.8rem}.tsd-panel{margin-bottom:2.5rem}.tsd-panel.tsd-member{margin-bottom:4rem}.tsd-panel>h1,.tsd-panel>h2,.tsd-panel>h3{margin:1.5rem -1.5rem .75rem;padding:0 1.5rem .75rem}.tsd-panel>h1.tsd-before-signature,.tsd-panel>h2.tsd-before-signature,.tsd-panel>h3.tsd-before-signature{border-bottom:none;margin-bottom:0}.tsd-panel-group,.tsd-panel-group.tsd-index-group,.tsd-panel-group.tsd-index-group details{margin:2rem 0}.tsd-panel-group>.tsd-accordion-summary{margin-bottom:1rem}#tsd-search{transition:background-color .2s}#tsd-search .title{z-index:2}#tsd-search .field{height:100%;left:0;position:absolute;right:2.5rem;top:0}#tsd-search .field input{background:#0000;border:0;box-sizing:border-box;color:var(--color-text);opacity:0;outline:0;padding:0 10px;top:-50px;width:100%;z-index:1}#tsd-search .field label{overflow:hidden;position:absolute;right:-40px}#tsd-search .field input,#tsd-search .title,#tsd-toolbar-links a{transition:opacity .2s}#tsd-search .results{box-shadow:0 0 4px #00000040;list-style:none;margin:0;padding:0;position:absolute;top:40px;visibility:hidden;width:100%}#tsd-search .results li{background-color:var(--color-background);line-height:normal;padding:4px}#tsd-search .results a{align-items:center;box-sizing:border-box;display:flex;padding:.25rem}#tsd-search .results a:before{top:10px}#tsd-search .results span.parent,.tsd-signature-symbol{color:var(--color-text-aside);font-weight:400}#tsd-search.has-focus .field input{opacity:1;top:0}#tsd-search.has-focus #tsd-toolbar-links a,#tsd-search.has-focus .title{opacity:0;z-index:0}#tsd-search.has-focus .results,.tsd-anchor-link:hover>.tsd-anchor-icon svg{visibility:visible}#tsd-search.failure .results li.state.failure,#tsd-search.loading .results li.state.loading{display:block}#tsd-toolbar-links{align-items:center;display:flex;height:100%;justify-content:flex-end;position:absolute;right:2rem;top:0}.tsd-signature{border:1px solid var(--color-accent);font-size:14px;margin:0 0 1rem;overflow-x:auto;padding:1rem .5rem}.tsd-signature-keyword{color:var(--color-ts-keyword);font-weight:400}.tsd-signature-type{font-style:italic;font-weight:400}.tsd-signatures{list-style-type:none;margin:0 0 1em;padding:0}.tsd-signatures .tsd-signature{border-color:var(--color-accent);border-width:1px 0;margin:0;transition:background-color .1s}.tsd-signatures .tsd-index-signature:not(:last-child){margin-bottom:1em}.tsd-description .tsd-signatures .tsd-signature,.tsd-signatures .tsd-index-signature .tsd-signature{border-width:1px}ul.tsd-parameter-list,ul.tsd-type-parameter-list{list-style:square;margin:0;padding-left:20px}ul.tsd-parameter-list>li.tsd-parameter-signature,ul.tsd-type-parameter-list>li.tsd-parameter-signature{list-style:none;margin-left:-20px}ul.tsd-parameter-list h5,ul.tsd-type-parameter-list h5{font-size:16px;margin:1em 0 .5em}.tsd-sources{font-size:.875em;margin-top:1rem}.tsd-sources a{color:var(--color-text-aside);text-decoration:underline}.tsd-sources ul{list-style:none;padding:0}.tsd-page-toolbar{background:var(--color-background-secondary);border-bottom:1px solid var(--color-accent);color:var(--color-text);left:0;position:sticky;top:0;transition:transform .3s ease-in-out;width:100%;z-index:1}.tsd-page-toolbar a{color:var(--color-text);text-decoration:none}.tsd-page-toolbar .tsd-toolbar-contents{display:flex;height:2.5rem;justify-content:space-between;margin:0 auto}.tsd-page-toolbar .table-cell{line-height:40px;position:relative;white-space:nowrap}.tsd-page-toolbar .table-cell:first-child{width:100%}.tsd-page-toolbar .tsd-toolbar-icon{box-sizing:border-box;line-height:0;padding:12px 0}.tsd-widget{cursor:pointer;height:40px;opacity:.8;overflow:hidden;transition:opacity .1s,background-color .2s;vertical-align:bottom}.tsd-widget:hover{opacity:.9}.tsd-widget.active{opacity:1}.tsd-widget.no-caption{width:40px}input[type=checkbox]+.tsd-widget:before{background-position:-120px 0}input[type=checkbox]:checked+.tsd-widget:before{background-position:-160px 0}img{max-width:100%}.tsd-anchor-icon{align-items:center;color:var(--color-text);display:inline-flex;margin-left:.5rem;vertical-align:middle}.tsd-anchor-icon svg{height:1em;visibility:hidden;width:1em}.deprecated{text-decoration:line-through!important}.warning{background:var(--color-background-warning);color:var(--color-warning-text);padding:1rem}.tsd-kind-project{color:var(--color-ts-project)}.tsd-kind-module{color:var(--color-ts-module)}.tsd-kind-namespace{color:var(--color-ts-namespace)}.tsd-kind-enum{color:var(--color-ts-enum)}.tsd-kind-enum-member{color:var(--color-ts-enum-member)}.tsd-kind-variable{color:var(--color-ts-variable)}.tsd-kind-function{color:var(--color-ts-function)}.tsd-kind-class{color:var(--color-ts-class)}.tsd-kind-interface{color:var(--color-ts-interface)}.tsd-kind-constructor{color:var(--color-ts-constructor)}.tsd-kind-property{color:var(--color-ts-property)}.tsd-kind-method{color:var(--color-ts-method)}.tsd-kind-call-signature{color:var(--color-ts-call-signature)}.tsd-kind-index-signature{color:var(--color-ts-index-signature)}.tsd-kind-constructor-signature{color:var(--color-ts-constructor-signature)}.tsd-kind-parameter{color:var(--color-ts-parameter)}.tsd-kind-type-literal{color:var(--color-ts-type-literal)}.tsd-kind-type-parameter{color:var(--color-ts-type-parameter)}.tsd-kind-accessor{color:var(--color-ts-accessor)}.tsd-kind-get-signature{color:var(--color-ts-get-signature)}.tsd-kind-set-signature{color:var(--color-ts-set-signature)}.tsd-kind-type-alias{color:var(--color-ts-type-alias)}*{scrollbar-color:var(--color-accent) var(--color-icon-background);scrollbar-width:thin}::-webkit-scrollbar{width:.75rem}::-webkit-scrollbar-track{background:var(--color-icon-background)}::-webkit-scrollbar-thumb{background-color:var(--color-accent);border:.25rem solid var(--color-icon-background);border-radius:999rem}@media (min-width:770px){.container-main{display:grid;grid-template-areas:"a b";grid-template-columns:minmax(0,1fr) minmax(0,2fr);margin:2rem auto}.col-sidebar{grid-area:a}.col-content{grid-area:b;padding:0 1rem}}@media (min-width:770px) and (max-width:1399px){.col-sidebar{max-height:calc(100vh - 2rem - 42px);overflow:auto;padding-top:1rem;position:sticky;top:42px}.site-menu{margin-top:1rem}}@media (min-width:1200px){.container-main{grid-template-areas:"a b c";grid-template-columns:minmax(0,1fr) minmax(0,2.5fr) minmax(0,20rem)}.col-sidebar{display:contents}.page-menu{grid-area:c;padding-left:1rem}.site-menu{grid-area:a;margin-top:1rem 0}.page-menu,.site-menu{max-height:calc(100vh - 2rem - 42px);overflow:auto;position:sticky;top:42px}}@media (max-width:1024px){.tsd-index-panel .tsd-index-list{grid-template-columns:repeat(2,1fr)}}@media (max-width:769px){.tsd-widget.menu,.tsd-widget.options{display:inline-block}.container-main,.tsd-navigation .tsd-nav-link{display:flex}html .col-content{float:none;max-width:100%;width:100%}html .col-sidebar{overflow-y:auto;position:fixed!important;-webkit-overflow-scrolling:touch;background-color:var(--color-background);bottom:0!important;left:auto!important;padding:1.5rem 1.5rem 0 0;right:0!important;top:0!important;transform:translate(100%);visibility:hidden;width:75vw;z-index:1024}html .col-sidebar>:last-child{padding-bottom:20px}html .overlay{background-color:#000000bf;bottom:0;content:"";display:block;left:0;position:fixed;right:0;top:0;visibility:hidden;z-index:1023}.to-has-menu .overlay{animation:.4s a}.to-has-menu .col-sidebar{animation:.4s c}.from-has-menu .overlay{animation:.4s b}.from-has-menu .col-sidebar{animation:.4s d}.has-menu body{overflow:hidden}.has-menu .overlay{visibility:visible}.has-menu .col-sidebar{display:flex;flex-direction:column;gap:1.5rem;max-height:100vh;padding:1rem 2rem;transform:translate(0);visibility:visible}.has-menu .tsd-navigation{max-height:100%}#tsd-toolbar-links{display:none}}@media (max-width:768px){.tsd-index-panel .tsd-index-list{grid-template-columns:repeat(1,1fr)}}@media (prefers-color-scheme:dark){:root{--color-background:var(--dark-color-background);--color-background-secondary:var(--dark-color-background-secondary);--color-background-warning:var(--dark-color-background-warning);--color-warning-text:var(--dark-color-warning-text);--color-icon-background:var(--dark-color-icon-background);--color-accent:var(--dark-color-accent);--color-active-menu-item:var(--dark-color-active-menu-item);--color-text:var(--dark-color-text);--color-text-aside:var(--dark-color-text-aside);--color-link:var(--dark-color-link);--color-focus-outline:var(--dark-color-focus-outline);--color-ts-keyword:var(--dark-color-ts-keyword);--color-ts-module:var(--dark-color-ts-module);--color-ts-namespace:var(--dark-color-ts-namespace);--color-ts-enum:var(--dark-color-ts-enum);--color-ts-enum-member:var(--dark-color-ts-enum-member);--color-ts-variable:var(--dark-color-ts-variable);--color-ts-function:var(--dark-color-ts-function);--color-ts-class:var(--dark-color-ts-class);--color-ts-interface:var(--dark-color-ts-interface);--color-ts-constructor:var(--dark-color-ts-constructor);--color-ts-property:var(--dark-color-ts-property);--color-ts-method:var(--dark-color-ts-method);--color-ts-call-signature:var(--dark-color-ts-call-signature);--color-ts-index-signature:var(--dark-color-ts-index-signature);--color-ts-constructor-signature:var(--dark-color-ts-constructor-signature);--color-ts-parameter:var(--dark-color-ts-parameter);--color-ts-type-parameter:var(--dark-color-ts-type-parameter);--color-ts-accessor:var(--dark-color-ts-accessor);--color-ts-get-signature:var(--dark-color-ts-get-signature);--color-ts-set-signature:var(--dark-color-ts-set-signature);--color-ts-type-alias:var(--dark-color-ts-type-alias);--color-document:var(--dark-color-document);--external-icon:var(--dark-external-icon);--color-scheme:var(--dark-color-scheme)}}@media (prefers-color-scheme:light){:root{--color-background:var(--light-color-background);--color-background-secondary:var(--light-color-background-secondary);--color-background-warning:var(--light-color-background-warning);--color-warning-text:var(--light-color-warning-text);--color-icon-background:var(--light-color-icon-background);--color-accent:var(--light-color-accent);--color-active-menu-item:var(--light-color-active-menu-item);--color-text:var(--light-color-text);--color-text-aside:var(--light-color-text-aside);--color-link:var(--light-color-link);--color-focus-outline:var(--light-color-focus-outline);--color-ts-keyword:var(--light-color-ts-keyword);--color-ts-module:var(--light-color-ts-module);--color-ts-namespace:var(--light-color-ts-namespace);--color-ts-enum:var(--light-color-ts-enum);--color-ts-enum-member:var(--light-color-ts-enum-member);--color-ts-variable:var(--light-color-ts-variable);--color-ts-function:var(--light-color-ts-function);--color-ts-class:var(--light-color-ts-class);--color-ts-interface:var(--light-color-ts-interface);--color-ts-constructor:var(--light-color-ts-constructor);--color-ts-property:var(--light-color-ts-property);--color-ts-method:var(--light-color-ts-method);--color-ts-call-signature:var(--light-color-ts-call-signature);--color-ts-index-signature:var(--light-color-ts-index-signature);--color-ts-constructor-signature:var(--light-color-ts-constructor-signature);--color-ts-parameter:var(--light-color-ts-parameter);--color-ts-type-parameter:var(--light-color-ts-type-parameter);--color-ts-accessor:var(--light-color-ts-accessor);--color-ts-get-signature:var(--light-color-ts-get-signature);--color-ts-set-signature:var(--light-color-ts-set-signature);--color-ts-type-alias:var(--light-color-ts-type-alias);--color-document:var(--light-color-document);--external-icon:var(--light-external-icon);--color-scheme:var(--light-color-scheme)}} \ No newline at end of file diff --git a/lib/souffle-js/api/classes/context.SouffleContext.html b/lib/souffle-js/api/classes/context.SouffleContext.html new file mode 100644 index 000000000..c5df35084 --- /dev/null +++ b/lib/souffle-js/api/classes/context.SouffleContext.html @@ -0,0 +1,40 @@ +SouffleContext | Souffle.js

Class SouffleContext<FactData>

Program generation context that maps relations, facts, and rules, and generates +a valid AST, suitable for pretty-printing and further processing by souffle.

+

FactData is an optional annotation of facts that holds some information about +their meanings. For example, it could be used to map some program entities with +generated Soufflé facts.

+

Type Parameters

  • FactData = undefined

Constructors

  • Type Parameters

    • FactData = undefined

    Parameters

    • name: string

      The unique name of the generated program.

      +
    • options: Partial<{
          addComments: boolean;
          comment: undefined | SouffleComment;
          formatWithSpacing: boolean;
          logger: ILogger;
      }> = {}

      An optional object with settings for the generated program.

      +
        +
      • comment: A docstring-like comment to be added at the top of the generated program.
      • +
      • addComments: Whether to include comments in the generated program. Defaults to false.
      • +
      • logger: A custom logger instance.
      • +
      +

    Returns SouffleContext<FactData>

Properties

addComments: boolean

Add generated comments to the output Soufflé program. +Set to false to reduce the size of produced code.

+
logger: ILogger

Logger used to report library messages.

+

Accessors

  • get filename(): string
  • Filename of the Soufflé file to be used for the generated program.

    +

    Returns string

Methods

  • Adds a new fact to an existing relation.

    +

    Parameters

    • name: string

      The name of the relation to which the fact is related.

      +
    • factValues: SouffleFactValue[]

      Fact values to add.

      +
    • Optionaldata: FactData

    Returns void

    Error if the relation does not exist.

    +
  • Collects names of relations which produce output on executing.

    +

    Returns string[]

diff --git a/lib/souffle-js/api/classes/emitter.SouffleEmitter.html b/lib/souffle-js/api/classes/emitter.SouffleEmitter.html new file mode 100644 index 000000000..b6ee40ac1 --- /dev/null +++ b/lib/souffle-js/api/classes/emitter.SouffleEmitter.html @@ -0,0 +1,9 @@ +SouffleEmitter | Souffle.js

Class SouffleEmitter<FactData>

Emits Souffle entries to a file.

+

Type Parameters

  • FactData = undefined

Methods

Methods

  • Asynchronously emits the Soufflé program to a file within the specified directory.

    +

    Parameters

    • dir: string

      The directory where the Soufflé fact files should be written.

      +

    Returns Promise<void>

  • Synchronously emits the Soufflé program to a file within the specified directory.

    +

    Parameters

    • dir: string

      The directory where the Soufflé fact files should be written.

      +

    Returns void

diff --git a/lib/souffle-js/api/classes/errors.SouffleError.html b/lib/souffle-js/api/classes/errors.SouffleError.html new file mode 100644 index 000000000..bca453a4e --- /dev/null +++ b/lib/souffle-js/api/classes/errors.SouffleError.html @@ -0,0 +1,3 @@ +SouffleError | Souffle.js

Hierarchy (view full)

Constructors

Methods

Constructors

Methods

  • Parameters

    • type: string
    • error: unknown

    Returns Error

diff --git a/lib/souffle-js/api/classes/errors.SouffleExecutionError.html b/lib/souffle-js/api/classes/errors.SouffleExecutionError.html new file mode 100644 index 000000000..fadaa6262 --- /dev/null +++ b/lib/souffle-js/api/classes/errors.SouffleExecutionError.html @@ -0,0 +1,3 @@ +SouffleExecutionError | Souffle.js

Class SouffleExecutionError

Hierarchy (view full)

Constructors

Methods

Constructors

Methods

diff --git a/lib/souffle-js/api/classes/errors.SouffleInternalError.html b/lib/souffle-js/api/classes/errors.SouffleInternalError.html new file mode 100644 index 000000000..0c6c24cdc --- /dev/null +++ b/lib/souffle-js/api/classes/errors.SouffleInternalError.html @@ -0,0 +1,3 @@ +SouffleInternalError | Souffle.js

Class SouffleInternalError

Hierarchy (view full)

Constructors

Methods

Constructors

Methods

diff --git a/lib/souffle-js/api/classes/errors.SouffleUsageError.html b/lib/souffle-js/api/classes/errors.SouffleUsageError.html new file mode 100644 index 000000000..72edbc46c --- /dev/null +++ b/lib/souffle-js/api/classes/errors.SouffleUsageError.html @@ -0,0 +1,3 @@ +SouffleUsageError | Souffle.js

Class SouffleUsageError

Hierarchy (view full)

Constructors

Methods

Constructors

Methods

diff --git a/lib/souffle-js/api/classes/executor_executor.SouffleAsyncExecutor.html b/lib/souffle-js/api/classes/executor_executor.SouffleAsyncExecutor.html new file mode 100644 index 000000000..fed487c3b --- /dev/null +++ b/lib/souffle-js/api/classes/executor_executor.SouffleAsyncExecutor.html @@ -0,0 +1,12 @@ +SouffleAsyncExecutor | Souffle.js

Class SouffleAsyncExecutor<FactData>

Manages the process of executing Soufflé and parsing its output.

+

Type Parameters

  • FactData

Hierarchy (view full)

Constructors

Properties

inputDir: string
outputDir: string
processResults: boolean
soufflePath: string

Methods

diff --git a/lib/souffle-js/api/classes/executor_executor.SouffleExecutor.html b/lib/souffle-js/api/classes/executor_executor.SouffleExecutor.html new file mode 100644 index 000000000..2af422670 --- /dev/null +++ b/lib/souffle-js/api/classes/executor_executor.SouffleExecutor.html @@ -0,0 +1,10 @@ +SouffleExecutor | Souffle.js

Class SouffleExecutor<FactData>Abstract

Manages the process of executing Soufflé and parsing its output.

+

Type Parameters

  • FactData

Hierarchy (view full)

Constructors

Properties

inputDir: string
outputDir: string
processResults: boolean
soufflePath: string

Methods

diff --git a/lib/souffle-js/api/classes/executor_executor.SouffleSyncExecutor.html b/lib/souffle-js/api/classes/executor_executor.SouffleSyncExecutor.html new file mode 100644 index 000000000..012f143f4 --- /dev/null +++ b/lib/souffle-js/api/classes/executor_executor.SouffleSyncExecutor.html @@ -0,0 +1,12 @@ +SouffleSyncExecutor | Souffle.js

Class SouffleSyncExecutor<FactData>

Manages the process of executing Soufflé and parsing its output.

+

Type Parameters

  • FactData

Hierarchy (view full)

Constructors

Properties

inputDir: string
outputDir: string
processResults: boolean
soufflePath: string

Methods

diff --git a/lib/souffle-js/api/classes/executor_results.SouffleOutputStructured.html b/lib/souffle-js/api/classes/executor_results.SouffleOutputStructured.html new file mode 100644 index 000000000..f280a8a12 --- /dev/null +++ b/lib/souffle-js/api/classes/executor_results.SouffleOutputStructured.html @@ -0,0 +1,7 @@ +SouffleOutputStructured | Souffle.js

Class SouffleOutputStructured<FactData>

Structured Soufflé output that contains information about facts with additional +annotations added to the executed Context.

+

Type Parameters

  • FactData

Properties

Methods

Properties

entries: Map<string, SouffleFact<FactData>[]>

Methods

diff --git a/lib/souffle-js/api/classes/executor_results.SpaceSeparatedParser.html b/lib/souffle-js/api/classes/executor_results.SpaceSeparatedParser.html new file mode 100644 index 000000000..89613cdc3 --- /dev/null +++ b/lib/souffle-js/api/classes/executor_results.SpaceSeparatedParser.html @@ -0,0 +1,820 @@ +SpaceSeparatedParser | Souffle.js

Custom Transform Stream to parse space-separated values.

+

Hierarchy

  • Transform
    • SpaceSeparatedParser

Constructors

Properties

allowHalfOpen: boolean

If false then the stream will automatically end the writable side when the +readable side ends. Set initially by the allowHalfOpen constructor option, +which defaults to true.

+

This can be changed manually to change the half-open behavior of an existing +Duplex stream instance, but must be changed before the 'end' event is emitted.

+

v0.9.4

+
closed: boolean

Is true after 'close' has been emitted.

+

v18.0.0

+
destroyed: boolean

Is true after readable.destroy() has been called.

+

v8.0.0

+
errored: null | Error

Returns error if the stream has been destroyed with an error.

+

v18.0.0

+
readable: boolean

Is true if it is safe to call read, which means +the stream has not been destroyed or emitted 'error' or 'end'.

+

v11.4.0

+
readableAborted: boolean

Returns whether the stream was destroyed or errored before emitting 'end'.

+

v16.8.0

+
readableDidRead: boolean

Returns whether 'data' has been emitted.

+

v16.7.0, v14.18.0

+
readableEncoding: null | BufferEncoding

Getter for the property encoding of a given Readable stream. The encoding property can be set using the setEncoding method.

+

v12.7.0

+
readableEnded: boolean

Becomes true when 'end' event is emitted.

+

v12.9.0

+
readableFlowing: null | boolean

This property reflects the current state of a Readable stream as described +in the Three states section.

+

v9.4.0

+
readableHighWaterMark: number

Returns the value of highWaterMark passed when creating this Readable.

+

v9.3.0

+
readableLength: number

This property contains the number of bytes (or objects) in the queue +ready to be read. The value provides introspection data regarding +the status of the highWaterMark.

+

v9.4.0

+
readableObjectMode: boolean

Getter for the property objectMode of a given Readable stream.

+

v12.3.0

+
writable: boolean

Is true if it is safe to call writable.write(), which means +the stream has not been destroyed, errored, or ended.

+

v11.4.0

+
writableCorked: number

Number of times writable.uncork() needs to be +called in order to fully uncork the stream.

+

v13.2.0, v12.16.0

+
writableEnded: boolean

Is true after writable.end() has been called. This property +does not indicate whether the data has been flushed, for this use writable.writableFinished instead.

+

v12.9.0

+
writableFinished: boolean

Is set to true immediately before the 'finish' event is emitted.

+

v12.6.0

+
writableHighWaterMark: number

Return the value of highWaterMark passed when creating this Writable.

+

v9.3.0

+
writableLength: number

This property contains the number of bytes (or objects) in the queue +ready to be written. The value provides introspection data regarding +the status of the highWaterMark.

+

v9.4.0

+
writableNeedDrain: boolean

Is true if the stream's buffer has been full and stream will emit 'drain'.

+

v15.2.0, v14.17.0

+
writableObjectMode: boolean

Getter for the property objectMode of a given Writable stream.

+

v12.3.0

+
captureRejections: boolean

Value: boolean

+

Change the default captureRejections option on all new EventEmitter objects.

+

v13.4.0, v12.16.0

+
captureRejectionSymbol: typeof captureRejectionSymbol

Value: Symbol.for('nodejs.rejection')

+

See how to write a custom rejection handler.

+

v13.4.0, v12.16.0

+
defaultMaxListeners: number

By default, a maximum of 10 listeners can be registered for any single +event. This limit can be changed for individual EventEmitter instances +using the emitter.setMaxListeners(n) method. To change the default +for allEventEmitter instances, the events.defaultMaxListeners property +can be used. If this value is not a positive number, a RangeError is thrown.

+

Take caution when setting the events.defaultMaxListeners because the +change affects all EventEmitter instances, including those created before +the change is made. However, calling emitter.setMaxListeners(n) still has +precedence over events.defaultMaxListeners.

+

This is not a hard limit. The EventEmitter instance will allow +more listeners to be added but will output a trace warning to stderr indicating +that a "possible EventEmitter memory leak" has been detected. For any single +EventEmitter, the emitter.getMaxListeners() and emitter.setMaxListeners() methods can be used to +temporarily avoid this warning:

+
import { EventEmitter } from 'node:events';
const emitter = new EventEmitter();
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once('event', () => {
// do stuff
emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
}); +
+ +

The --trace-warnings command-line flag can be used to display the +stack trace for such warnings.

+

The emitted warning can be inspected with process.on('warning') and will +have the additional emitter, type, and count properties, referring to +the event emitter instance, the event's name and the number of attached +listeners, respectively. +Its name property is set to 'MaxListenersExceededWarning'.

+

v0.11.2

+
errorMonitor: typeof errorMonitor

This symbol shall be used to install a listener for only monitoring 'error' events. Listeners installed using this symbol are called before the regular 'error' listeners are called.

+

Installing a listener using this symbol does not change the behavior once an 'error' event is emitted. Therefore, the process will still crash if no +regular 'error' listener is installed.

+

v13.6.0, v12.17.0

+

Methods

  • Parameters

    • callback: ((error?: null | Error) => void)
        • (error?): void
        • Parameters

          • Optionalerror: null | Error

          Returns void

    Returns void

  • Parameters

    • error: null | Error
    • callback: ((error?: null | Error) => void)
        • (error?): void
        • Parameters

          • Optionalerror: null | Error

          Returns void

    Returns void

  • Parameters

    • callback: ((error?: null | Error) => void)
        • (error?): void
        • Parameters

          • Optionalerror: null | Error

          Returns void

    Returns void

  • Parameters

    • callback: TransformCallback

    Returns void

  • Parameters

    • size: number

    Returns void

  • Parameters

    • chunk: string | Buffer
    • _: BufferEncoding
    • callback: TransformCallback

    Returns void

  • Parameters

    • chunk: any
    • encoding: BufferEncoding
    • callback: ((error?: null | Error) => void)
        • (error?): void
        • Parameters

          • Optionalerror: null | Error

          Returns void

    Returns void

  • Parameters

    • chunks: {
          chunk: any;
          encoding: BufferEncoding;
      }[]
    • callback: ((error?: null | Error) => void)
        • (error?): void
        • Parameters

          • Optionalerror: null | Error

          Returns void

    Returns void

  • Calls readable.destroy() with an AbortError and returns a promise that fulfills when the stream is finished.

    +

    Returns Promise<void>

    v20.4.0

    +
  • Returns AsyncIterableIterator<any>

  • Type Parameters

    • K

    Parameters

    • error: Error
    • event: string | symbol
    • Rest...args: AnyRest

    Returns void

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. drain
    6. +
    7. end
    8. +
    9. error
    10. +
    11. finish
    12. +
    13. pause
    14. +
    15. pipe
    16. +
    17. readable
    18. +
    19. resume
    20. +
    21. unpipe
    22. +
    +

    Parameters

    • event: "close"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "data"
    • listener: ((chunk: any) => void)
        • (chunk): void
        • Parameters

          • chunk: any

          Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "drain"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "end"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "error"
    • listener: ((err: Error) => void)
        • (err): void
        • Parameters

          • err: Error

          Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "finish"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "pause"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "pipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "readable"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "resume"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: "unpipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Event emitter +The defined events on documents including:

    +
      +
    1. close
    2. +
    3. data
    4. +
    5. end
    6. +
    7. error
    8. +
    9. pause
    10. +
    11. readable
    12. +
    13. resume
    14. +
    +

    Parameters

    • event: string | symbol
    • listener: ((...args: any[]) => void)
        • (...args): void
        • Parameters

          • Rest...args: any[]

          Returns void

    Returns this

  • This method returns a new stream with chunks of the underlying stream paired with a counter +in the form [index, chunk]. The first index value is 0 and it increases by 1 for each chunk produced.

    +

    Parameters

    • Optionaloptions: Pick<ArrayOptions, "signal">

    Returns Readable

    a stream of indexed pairs.

    +

    v17.5.0

    +
  • Type Parameters

    • T extends ReadableStream<T>

    Parameters

    • stream:
          | T
          | ComposeFnParam
          | Iterable<T>
          | AsyncIterable<T>
    • Optionaloptions: {
          signal: AbortSignal;
      }
      • signal: AbortSignal

    Returns T

  • The writable.cork() method forces all written data to be buffered in memory. +The buffered data will be flushed when either the uncork or end methods are called.

    +

    The primary intent of writable.cork() is to accommodate a situation in which +several small chunks are written to the stream in rapid succession. Instead of +immediately forwarding them to the underlying destination, writable.cork() buffers all the chunks until writable.uncork() is called, which will pass them +all to writable._writev(), if present. This prevents a head-of-line blocking +situation where data is being buffered while waiting for the first small chunk +to be processed. However, use of writable.cork() without implementing writable._writev() may have an adverse effect on throughput.

    +

    See also: writable.uncork(), writable._writev().

    +

    Returns void

    v0.11.2

    +
  • Destroy the stream. Optionally emit an 'error' event, and emit a 'close' event (unless emitClose is set to false). After this call, the readable +stream will release any internal resources and subsequent calls to push() will be ignored.

    +

    Once destroy() has been called any further calls will be a no-op and no +further errors except from _destroy() may be emitted as 'error'.

    +

    Implementors should not override this method, but instead implement readable._destroy().

    +

    Parameters

    • Optionalerror: Error

      Error which will be passed as payload in 'error' event

      +

    Returns this

    v8.0.0

    +
  • This method returns a new stream with the first limit chunks dropped from the start.

    +

    Parameters

    • limit: number

      the number of chunks to drop from the readable.

      +
    • Optionaloptions: Pick<ArrayOptions, "signal">

    Returns Readable

    a stream with limit chunks dropped from the start.

    +

    v17.5.0

    +
  • Parameters

    • event: "close"

    Returns boolean

  • Parameters

    • event: "data"
    • chunk: any

    Returns boolean

  • Parameters

    • event: "drain"

    Returns boolean

  • Parameters

    • event: "end"

    Returns boolean

  • Parameters

    • event: "error"
    • err: Error

    Returns boolean

  • Parameters

    • event: "finish"

    Returns boolean

  • Parameters

    • event: "pause"

    Returns boolean

  • Parameters

    • event: "pipe"
    • src: Readable

    Returns boolean

  • Parameters

    • event: "readable"

    Returns boolean

  • Parameters

    • event: "resume"

    Returns boolean

  • Parameters

    • event: "unpipe"
    • src: Readable

    Returns boolean

  • Parameters

    • event: string | symbol
    • Rest...args: any[]

    Returns boolean

  • Calling the writable.end() method signals that no more data will be written +to the Writable. The optional chunk and encoding arguments allow one +final additional chunk of data to be written immediately before closing the +stream.

    +

    Calling the write method after calling end will raise an error.

    +
    // Write 'hello, ' and then end with 'world!'.
    const fs = require('node:fs');
    const file = fs.createWriteStream('example.txt');
    file.write('hello, ');
    file.end('world!');
    // Writing more now is not allowed! +
    + +

    Parameters

    • Optionalcb: (() => void)
        • (): void
        • Returns void

    Returns this

    v0.9.4

    +
  • Calling the writable.end() method signals that no more data will be written +to the Writable. The optional chunk and encoding arguments allow one +final additional chunk of data to be written immediately before closing the +stream.

    +

    Calling the write method after calling end will raise an error.

    +
    // Write 'hello, ' and then end with 'world!'.
    const fs = require('node:fs');
    const file = fs.createWriteStream('example.txt');
    file.write('hello, ');
    file.end('world!');
    // Writing more now is not allowed! +
    + +

    Parameters

    • chunk: any

      Optional data to write. For streams not operating in object mode, chunk must be a {string}, {Buffer}, +{TypedArray} or {DataView}. For object mode streams, chunk may be any JavaScript value other than null.

      +
    • Optionalcb: (() => void)
        • (): void
        • Returns void

    Returns this

    v0.9.4

    +
  • Calling the writable.end() method signals that no more data will be written +to the Writable. The optional chunk and encoding arguments allow one +final additional chunk of data to be written immediately before closing the +stream.

    +

    Calling the write method after calling end will raise an error.

    +
    // Write 'hello, ' and then end with 'world!'.
    const fs = require('node:fs');
    const file = fs.createWriteStream('example.txt');
    file.write('hello, ');
    file.end('world!');
    // Writing more now is not allowed! +
    + +

    Parameters

    • chunk: any

      Optional data to write. For streams not operating in object mode, chunk must be a {string}, {Buffer}, +{TypedArray} or {DataView}. For object mode streams, chunk may be any JavaScript value other than null.

      +
    • Optionalencoding: BufferEncoding

      The encoding if chunk is a string

      +
    • Optionalcb: (() => void)
        • (): void
        • Returns void

    Returns this

    v0.9.4

    +
  • Returns an array listing the events for which the emitter has registered +listeners. The values in the array are strings or Symbols.

    +
    import { EventEmitter } from 'node:events';

    const myEE = new EventEmitter();
    myEE.on('foo', () => {});
    myEE.on('bar', () => {});

    const sym = Symbol('symbol');
    myEE.on(sym, () => {});

    console.log(myEE.eventNames());
    // Prints: [ 'foo', 'bar', Symbol(symbol) ] +
    + +

    Returns (string | symbol)[]

    v6.0.0

    +
  • This method is similar to Array.prototype.every and calls fn on each chunk in the stream +to check if all awaited return values are truthy value for fn. Once an fn call on a chunk +awaited return value is falsy, the stream is destroyed and the promise is fulfilled with false. +If all of the fn calls on the chunks return a truthy value, the promise is fulfilled with true.

    +

    Parameters

    • fn: ((data: any, options?: Pick<ArrayOptions, "signal">) => boolean | Promise<boolean>)

      a function to call on each chunk of the stream. Async or not.

      +
        • (data, options?): boolean | Promise<boolean>
        • Parameters

          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns boolean | Promise<boolean>

    • Optionaloptions: ArrayOptions

    Returns Promise<boolean>

    a promise evaluating to true if fn returned a truthy value for every one of the chunks.

    +

    v17.5.0

    +
  • This method allows filtering the stream. For each chunk in the stream the fn function will be called +and if it returns a truthy value, the chunk will be passed to the result stream. +If the fn function returns a promise - that promise will be awaited.

    +

    Parameters

    • fn: ((data: any, options?: Pick<ArrayOptions, "signal">) => boolean | Promise<boolean>)

      a function to filter chunks from the stream. Async or not.

      +
        • (data, options?): boolean | Promise<boolean>
        • Parameters

          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns boolean | Promise<boolean>

    • Optionaloptions: ArrayOptions

    Returns Readable

    a stream filtered with the predicate fn.

    +

    v17.4.0, v16.14.0

    +
  • This method is similar to Array.prototype.find and calls fn on each chunk in the stream +to find a chunk with a truthy value for fn. Once an fn call's awaited return value is truthy, +the stream is destroyed and the promise is fulfilled with value for which fn returned a truthy value. +If all of the fn calls on the chunks return a falsy value, the promise is fulfilled with undefined.

    +

    Type Parameters

    • T

    Parameters

    • fn: ((data: any, options?: Pick<ArrayOptions, "signal">) => data is T)

      a function to call on each chunk of the stream. Async or not.

      +
        • (data, options?): data is T
        • Parameters

          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns data is T

    • Optionaloptions: ArrayOptions

    Returns Promise<undefined | T>

    a promise evaluating to the first chunk for which fn evaluated with a truthy value, +or undefined if no element was found.

    +

    v17.5.0

    +
  • Parameters

    • fn: ((data: any, options?: Pick<ArrayOptions, "signal">) => boolean | Promise<boolean>)
        • (data, options?): boolean | Promise<boolean>
        • Parameters

          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns boolean | Promise<boolean>

    • Optionaloptions: ArrayOptions

    Returns Promise<any>

  • This method returns a new stream by applying the given callback to each chunk of the stream +and then flattening the result.

    +

    It is possible to return a stream or another iterable or async iterable from fn and the result streams +will be merged (flattened) into the returned stream.

    +

    Parameters

    • fn: ((data: any, options?: Pick<ArrayOptions, "signal">) => any)

      a function to map over every chunk in the stream. May be async. May be a stream or generator.

      +
        • (data, options?): any
        • Parameters

          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns any

    • Optionaloptions: ArrayOptions

    Returns Readable

    a stream flat-mapped with the function fn.

    +

    v17.5.0

    +
  • This method allows iterating a stream. For each chunk in the stream the fn function will be called. +If the fn function returns a promise - that promise will be awaited.

    +

    This method is different from for await...of loops in that it can optionally process chunks concurrently. +In addition, a forEach iteration can only be stopped by having passed a signal option +and aborting the related AbortController while for await...of can be stopped with break or return. +In either case the stream will be destroyed.

    +

    This method is different from listening to the 'data' event in that it uses the readable event +in the underlying machinary and can limit the number of concurrent fn calls.

    +

    Parameters

    • fn: ((data: any, options?: Pick<ArrayOptions, "signal">) => void | Promise<void>)

      a function to call on each chunk of the stream. Async or not.

      +
        • (data, options?): void | Promise<void>
        • Parameters

          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns void | Promise<void>

    • Optionaloptions: ArrayOptions

    Returns Promise<void>

    a promise for when the stream has finished.

    +

    v17.5.0

    +
  • Returns the current max listener value for the EventEmitter which is either +set by emitter.setMaxListeners(n) or defaults to defaultMaxListeners.

    +

    Returns number

    v1.0.0

    +
  • The readable.isPaused() method returns the current operating state of the Readable. +This is used primarily by the mechanism that underlies the readable.pipe() method. +In most typical cases, there will be no reason to use this method directly.

    +
    const readable = new stream.Readable();

    readable.isPaused(); // === false
    readable.pause();
    readable.isPaused(); // === true
    readable.resume();
    readable.isPaused(); // === false +
    + +

    Returns boolean

    v0.11.14

    +
  • The iterator created by this method gives users the option to cancel the destruction +of the stream if the for await...of loop is exited by return, break, or throw, +or if the iterator should destroy the stream if the stream emitted an error during iteration.

    +

    Parameters

    • Optionaloptions: {
          destroyOnReturn?: boolean;
      }
      • OptionaldestroyOnReturn?: boolean

        When set to false, calling return on the async iterator, +or exiting a for await...of iteration using a break, return, or throw will not destroy the stream. +Default: true.

        +

    Returns AsyncIterableIterator<any>

    v16.3.0

    +
  • Returns the number of listeners listening for the event named eventName. +If listener is provided, it will return how many times the listener is found +in the list of the listeners of the event.

    +

    Type Parameters

    • K

    Parameters

    • eventName: string | symbol

      The name of the event being listened for

      +
    • Optionallistener: Function

      The event handler function

      +

    Returns number

    v3.2.0

    +
  • Returns a copy of the array of listeners for the event named eventName.

    +
    server.on('connection', (stream) => {
    console.log('someone connected!');
    });
    console.log(util.inspect(server.listeners('connection')));
    // Prints: [ [Function] ] +
    + +

    Type Parameters

    • K

    Parameters

    • eventName: string | symbol

    Returns Function[]

    v0.1.26

    +
  • This method allows mapping over the stream. The fn function will be called for every chunk in the stream. +If the fn function returns a promise - that promise will be awaited before being passed to the result stream.

    +

    Parameters

    • fn: ((data: any, options?: Pick<ArrayOptions, "signal">) => any)

      a function to map over every chunk in the stream. Async or not.

      +
        • (data, options?): any
        • Parameters

          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns any

    • Optionaloptions: ArrayOptions

    Returns Readable

    a stream mapped with the function fn.

    +

    v17.4.0, v16.14.0

    +
  • Alias for emitter.removeListener().

    +

    Type Parameters

    • K

    Parameters

    • eventName: string | symbol
    • listener: ((...args: any[]) => void)
        • (...args): void
        • Parameters

          • Rest...args: any[]

          Returns void

    Returns this

    v10.0.0

    +
  • Parameters

    • event: "close"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "data"
    • listener: ((chunk: any) => void)
        • (chunk): void
        • Parameters

          • chunk: any

          Returns void

    Returns this

  • Parameters

    • event: "drain"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "end"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "error"
    • listener: ((err: Error) => void)
        • (err): void
        • Parameters

          • err: Error

          Returns void

    Returns this

  • Parameters

    • event: "finish"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pause"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: "readable"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "resume"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "unpipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: string | symbol
    • listener: ((...args: any[]) => void)
        • (...args): void
        • Parameters

          • Rest...args: any[]

          Returns void

    Returns this

  • Parameters

    • event: "close"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "data"
    • listener: ((chunk: any) => void)
        • (chunk): void
        • Parameters

          • chunk: any

          Returns void

    Returns this

  • Parameters

    • event: "drain"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "end"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "error"
    • listener: ((err: Error) => void)
        • (err): void
        • Parameters

          • err: Error

          Returns void

    Returns this

  • Parameters

    • event: "finish"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pause"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: "readable"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "resume"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "unpipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: string | symbol
    • listener: ((...args: any[]) => void)
        • (...args): void
        • Parameters

          • Rest...args: any[]

          Returns void

    Returns this

  • The readable.pause() method will cause a stream in flowing mode to stop +emitting 'data' events, switching out of flowing mode. Any data that +becomes available will remain in the internal buffer.

    +
    const readable = getReadableStreamSomehow();
    readable.on('data', (chunk) => {
    console.log(`Received ${chunk.length} bytes of data.`);
    readable.pause();
    console.log('There will be no additional data for 1 second.');
    setTimeout(() => {
    console.log('Now data will start flowing again.');
    readable.resume();
    }, 1000);
    }); +
    + +

    The readable.pause() method has no effect if there is a 'readable' event listener.

    +

    Returns this

    v0.9.4

    +
  • Type Parameters

    • T extends WritableStream<T>

    Parameters

    • destination: T
    • Optionaloptions: {
          end?: boolean;
      }
      • Optionalend?: boolean

    Returns T

  • Parameters

    • event: "close"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "data"
    • listener: ((chunk: any) => void)
        • (chunk): void
        • Parameters

          • chunk: any

          Returns void

    Returns this

  • Parameters

    • event: "drain"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "end"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "error"
    • listener: ((err: Error) => void)
        • (err): void
        • Parameters

          • err: Error

          Returns void

    Returns this

  • Parameters

    • event: "finish"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pause"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: "readable"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "resume"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "unpipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: string | symbol
    • listener: ((...args: any[]) => void)
        • (...args): void
        • Parameters

          • Rest...args: any[]

          Returns void

    Returns this

  • Parameters

    • event: "close"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "data"
    • listener: ((chunk: any) => void)
        • (chunk): void
        • Parameters

          • chunk: any

          Returns void

    Returns this

  • Parameters

    • event: "drain"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "end"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "error"
    • listener: ((err: Error) => void)
        • (err): void
        • Parameters

          • err: Error

          Returns void

    Returns this

  • Parameters

    • event: "finish"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pause"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: "readable"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "resume"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "unpipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: string | symbol
    • listener: ((...args: any[]) => void)
        • (...args): void
        • Parameters

          • Rest...args: any[]

          Returns void

    Returns this

  • Parameters

    • chunk: any
    • Optionalencoding: BufferEncoding

    Returns boolean

  • Returns a copy of the array of listeners for the event named eventName, +including any wrappers (such as those created by .once()).

    +
    import { EventEmitter } from 'node:events';
    const emitter = new EventEmitter();
    emitter.once('log', () => console.log('log once'));

    // Returns a new Array with a function `onceWrapper` which has a property
    // `listener` which contains the original listener bound above
    const listeners = emitter.rawListeners('log');
    const logFnWrapper = listeners[0];

    // Logs "log once" to the console and does not unbind the `once` event
    logFnWrapper.listener();

    // Logs "log once" to the console and removes the listener
    logFnWrapper();

    emitter.on('log', () => console.log('log persistently'));
    // Will return a new Array with a single function bound by `.on()` above
    const newListeners = emitter.rawListeners('log');

    // Logs "log persistently" twice
    newListeners[0]();
    emitter.emit('log'); +
    + +

    Type Parameters

    • K

    Parameters

    • eventName: string | symbol

    Returns Function[]

    v9.4.0

    +
  • The readable.read() method reads data out of the internal buffer and +returns it. If no data is available to be read, null is returned. By default, +the data is returned as a Buffer object unless an encoding has been +specified using the readable.setEncoding() method or the stream is operating +in object mode.

    +

    The optional size argument specifies a specific number of bytes to read. If +size bytes are not available to be read, null will be returned unless the +stream has ended, in which case all of the data remaining in the internal buffer +will be returned.

    +

    If the size argument is not specified, all of the data contained in the +internal buffer will be returned.

    +

    The size argument must be less than or equal to 1 GiB.

    +

    The readable.read() method should only be called on Readable streams +operating in paused mode. In flowing mode, readable.read() is called +automatically until the internal buffer is fully drained.

    +
    const readable = getReadableStreamSomehow();

    // 'readable' may be triggered multiple times as data is buffered in
    readable.on('readable', () => {
    let chunk;
    console.log('Stream is readable (new data received in buffer)');
    // Use a loop to make sure we read all currently available data
    while (null !== (chunk = readable.read())) {
    console.log(`Read ${chunk.length} bytes of data...`);
    }
    });

    // 'end' will be triggered once when there is no more data available
    readable.on('end', () => {
    console.log('Reached end of stream.');
    }); +
    + +

    Each call to readable.read() returns a chunk of data, or null. The chunks +are not concatenated. A while loop is necessary to consume all data +currently in the buffer. When reading a large file .read() may return null, +having consumed all buffered content so far, but there is still more data to +come not yet buffered. In this case a new 'readable' event will be emitted +when there is more data in the buffer. Finally the 'end' event will be +emitted when there is no more data to come.

    +

    Therefore to read a file's whole contents from a readable, it is necessary +to collect chunks across multiple 'readable' events:

    +
    const chunks = [];

    readable.on('readable', () => {
    let chunk;
    while (null !== (chunk = readable.read())) {
    chunks.push(chunk);
    }
    });

    readable.on('end', () => {
    const content = chunks.join('');
    }); +
    + +

    A Readable stream in object mode will always return a single item from +a call to readable.read(size), regardless of the value of the size argument.

    +

    If the readable.read() method returns a chunk of data, a 'data' event will +also be emitted.

    +

    Calling read after the 'end' event has +been emitted will return null. No runtime error will be raised.

    +

    Parameters

    • Optionalsize: number

      Optional argument to specify how much data to read.

      +

    Returns any

    v0.9.4

    +
  • This method calls fn on each chunk of the stream in order, passing it the result from the calculation +on the previous element. It returns a promise for the final value of the reduction.

    +

    If no initial value is supplied the first chunk of the stream is used as the initial value. +If the stream is empty, the promise is rejected with a TypeError with the ERR_INVALID_ARGS code property.

    +

    The reducer function iterates the stream element-by-element which means that there is no concurrency parameter +or parallelism. To perform a reduce concurrently, you can extract the async function to readable.map method.

    +

    Type Parameters

    • T = any

    Parameters

    • fn: ((previous: any, data: any, options?: Pick<ArrayOptions, "signal">) => T)

      a reducer function to call over every chunk in the stream. Async or not.

      +
        • (previous, data, options?): T
        • Parameters

          • previous: any
          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns T

    • Optionalinitial: undefined

      the initial value to use in the reduction.

      +
    • Optionaloptions: Pick<ArrayOptions, "signal">

    Returns Promise<T>

    a promise for the final value of the reduction.

    +

    v17.5.0

    +
  • Type Parameters

    • T = any

    Parameters

    • fn: ((previous: T, data: any, options?: Pick<ArrayOptions, "signal">) => T)
        • (previous, data, options?): T
        • Parameters

          • previous: T
          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns T

    • initial: T
    • Optionaloptions: Pick<ArrayOptions, "signal">

    Returns Promise<T>

  • Removes all listeners, or those of the specified eventName.

    +

    It is bad practice to remove listeners added elsewhere in the code, +particularly when the EventEmitter instance was created by some other +component or module (e.g. sockets or file streams).

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    Parameters

    • OptionaleventName: string | symbol

    Returns this

    v0.1.26

    +
  • Parameters

    • event: "close"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "data"
    • listener: ((chunk: any) => void)
        • (chunk): void
        • Parameters

          • chunk: any

          Returns void

    Returns this

  • Parameters

    • event: "drain"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "end"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "error"
    • listener: ((err: Error) => void)
        • (err): void
        • Parameters

          • err: Error

          Returns void

    Returns this

  • Parameters

    • event: "finish"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pause"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "pipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: "readable"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "resume"
    • listener: (() => void)
        • (): void
        • Returns void

    Returns this

  • Parameters

    • event: "unpipe"
    • listener: ((src: Readable) => void)
        • (src): void
        • Parameters

          • src: Readable

          Returns void

    Returns this

  • Parameters

    • event: string | symbol
    • listener: ((...args: any[]) => void)
        • (...args): void
        • Parameters

          • Rest...args: any[]

          Returns void

    Returns this

  • The readable.resume() method causes an explicitly paused Readable stream to +resume emitting 'data' events, switching the stream into flowing mode.

    +

    The readable.resume() method can be used to fully consume the data from a +stream without actually processing any of that data:

    +
    getReadableStreamSomehow()
    .resume()
    .on('end', () => {
    console.log('Reached the end, but did not read anything.');
    }); +
    + +

    The readable.resume() method has no effect if there is a 'readable' event listener.

    +

    Returns this

    v0.9.4

    +
  • The writable.setDefaultEncoding() method sets the default encoding for a Writable stream.

    +

    Parameters

    • encoding: BufferEncoding

      The new default encoding

      +

    Returns this

    v0.11.15

    +
  • The readable.setEncoding() method sets the character encoding for +data read from the Readable stream.

    +

    By default, no encoding is assigned and stream data will be returned as Buffer objects. Setting an encoding causes the stream data +to be returned as strings of the specified encoding rather than as Buffer objects. For instance, calling readable.setEncoding('utf8') will cause the +output data to be interpreted as UTF-8 data, and passed as strings. Calling readable.setEncoding('hex') will cause the data to be encoded in hexadecimal +string format.

    +

    The Readable stream will properly handle multi-byte characters delivered +through the stream that would otherwise become improperly decoded if simply +pulled from the stream as Buffer objects.

    +
    const readable = getReadableStreamSomehow();
    readable.setEncoding('utf8');
    readable.on('data', (chunk) => {
    assert.equal(typeof chunk, 'string');
    console.log('Got %d characters of string data:', chunk.length);
    }); +
    + +

    Parameters

    • encoding: BufferEncoding

      The encoding to use.

      +

    Returns this

    v0.9.4

    +
  • By default EventEmitters will print a warning if more than 10 listeners are +added for a particular event. This is a useful default that helps finding +memory leaks. The emitter.setMaxListeners() method allows the limit to be +modified for this specific EventEmitter instance. The value can be set to Infinity (or 0) to indicate an unlimited number of listeners.

    +

    Returns a reference to the EventEmitter, so that calls can be chained.

    +

    Parameters

    • n: number

    Returns this

    v0.3.5

    +
  • This method is similar to Array.prototype.some and calls fn on each chunk in the stream +until the awaited return value is true (or any truthy value). Once an fn call on a chunk +awaited return value is truthy, the stream is destroyed and the promise is fulfilled with true. +If none of the fn calls on the chunks return a truthy value, the promise is fulfilled with false.

    +

    Parameters

    • fn: ((data: any, options?: Pick<ArrayOptions, "signal">) => boolean | Promise<boolean>)

      a function to call on each chunk of the stream. Async or not.

      +
        • (data, options?): boolean | Promise<boolean>
        • Parameters

          • data: any
          • Optionaloptions: Pick<ArrayOptions, "signal">

          Returns boolean | Promise<boolean>

    • Optionaloptions: ArrayOptions

    Returns Promise<boolean>

    a promise evaluating to true if fn returned a truthy value for at least one of the chunks.

    +

    v17.5.0

    +
  • This method returns a new stream with the first limit chunks.

    +

    Parameters

    • limit: number

      the number of chunks to take from the readable.

      +
    • Optionaloptions: Pick<ArrayOptions, "signal">

    Returns Readable

    a stream with limit chunks taken.

    +

    v17.5.0

    +
  • This method allows easily obtaining the contents of a stream.

    +

    As this method reads the entire stream into memory, it negates the benefits of streams. It's intended +for interoperability and convenience, not as the primary way to consume streams.

    +

    Parameters

    • Optionaloptions: Pick<ArrayOptions, "signal">

    Returns Promise<any[]>

    a promise containing an array with the contents of the stream.

    +

    v17.5.0

    +
  • The writable.uncork() method flushes all data buffered since cork was called.

    +

    When using writable.cork() and writable.uncork() to manage the buffering +of writes to a stream, defer calls to writable.uncork() using process.nextTick(). Doing so allows batching of all writable.write() calls that occur within a given Node.js event +loop phase.

    +
    stream.cork();
    stream.write('some ');
    stream.write('data ');
    process.nextTick(() => stream.uncork()); +
    + +

    If the writable.cork() method is called multiple times on a stream, the +same number of calls to writable.uncork() must be called to flush the buffered +data.

    +
    stream.cork();
    stream.write('some ');
    stream.cork();
    stream.write('data ');
    process.nextTick(() => {
    stream.uncork();
    // The data will not be flushed until uncork() is called a second time.
    stream.uncork();
    }); +
    + +

    See also: writable.cork().

    +

    Returns void

    v0.11.2

    +
  • The readable.unpipe() method detaches a Writable stream previously attached +using the pipe method.

    +

    If the destination is not specified, then all pipes are detached.

    +

    If the destination is specified, but no pipe is set up for it, then +the method does nothing.

    +
    const fs = require('node:fs');
    const readable = getReadableStreamSomehow();
    const writable = fs.createWriteStream('file.txt');
    // All the data from readable goes into 'file.txt',
    // but only for the first second.
    readable.pipe(writable);
    setTimeout(() => {
    console.log('Stop writing to file.txt.');
    readable.unpipe(writable);
    console.log('Manually close the file stream.');
    writable.end();
    }, 1000); +
    + +

    Parameters

    • Optionaldestination: WritableStream

      Optional specific stream to unpipe

      +

    Returns this

    v0.9.4

    +
  • Passing chunk as null signals the end of the stream (EOF) and behaves the +same as readable.push(null), after which no more data can be written. The EOF +signal is put at the end of the buffer and any buffered data will still be +flushed.

    +

    The readable.unshift() method pushes a chunk of data back into the internal +buffer. This is useful in certain situations where a stream is being consumed by +code that needs to "un-consume" some amount of data that it has optimistically +pulled out of the source, so that the data can be passed on to some other party.

    +

    The stream.unshift(chunk) method cannot be called after the 'end' event +has been emitted or a runtime error will be thrown.

    +

    Developers using stream.unshift() often should consider switching to +use of a Transform stream instead. See the API for stream implementers section for more information.

    +
    // Pull off a header delimited by \n\n.
    // Use unshift() if we get too much.
    // Call the callback with (error, header, stream).
    const { StringDecoder } = require('node:string_decoder');
    function parseHeader(stream, callback) {
    stream.on('error', callback);
    stream.on('readable', onReadable);
    const decoder = new StringDecoder('utf8');
    let header = '';
    function onReadable() {
    let chunk;
    while (null !== (chunk = stream.read())) {
    const str = decoder.write(chunk);
    if (str.includes('\n\n')) {
    // Found the header boundary.
    const split = str.split(/\n\n/);
    header += split.shift();
    const remaining = split.join('\n\n');
    const buf = Buffer.from(remaining, 'utf8');
    stream.removeListener('error', callback);
    // Remove the 'readable' listener before unshifting.
    stream.removeListener('readable', onReadable);
    if (buf.length)
    stream.unshift(buf);
    // Now the body of the message can be read from the stream.
    callback(null, header, stream);
    return;
    }
    // Still reading the header.
    header += str;
    }
    }
    } +
    + +

    Unlike push, stream.unshift(chunk) will not +end the reading process by resetting the internal reading state of the stream. +This can cause unexpected results if readable.unshift() is called during a +read (i.e. from within a _read implementation on a +custom stream). Following the call to readable.unshift() with an immediate push will reset the reading state appropriately, +however it is best to simply avoid calling readable.unshift() while in the +process of performing a read.

    +

    Parameters

    • chunk: any

      Chunk of data to unshift onto the read queue. For streams not operating in object mode, chunk must +be a {string}, {Buffer}, {TypedArray}, {DataView} or null. For object mode streams, chunk may be any JavaScript value.

      +
    • Optionalencoding: BufferEncoding

      Encoding of string chunks. Must be a valid Buffer encoding, such as 'utf8' or 'ascii'.

      +

    Returns void

    v0.9.11

    +
  • Prior to Node.js 0.10, streams did not implement the entire node:stream module API as it is currently defined. (See Compatibility for more +information.)

    +

    When using an older Node.js library that emits 'data' events and has a pause method that is advisory only, the readable.wrap() method can be used to create a Readable +stream that uses +the old stream as its data source.

    +

    It will rarely be necessary to use readable.wrap() but the method has been +provided as a convenience for interacting with older Node.js applications and +libraries.

    +
    const { OldReader } = require('./old-api-module.js');
    const { Readable } = require('node:stream');
    const oreader = new OldReader();
    const myReader = new Readable().wrap(oreader);

    myReader.on('readable', () => {
    myReader.read(); // etc.
    }); +
    + +

    Parameters

    • stream: ReadableStream

      An "old style" readable stream

      +

    Returns this

    v0.9.4

    +
  • The writable.write() method writes some data to the stream, and calls the +supplied callback once the data has been fully handled. If an error +occurs, the callback will be called with the error as its +first argument. The callback is called asynchronously and before 'error' is +emitted.

    +

    The return value is true if the internal buffer is less than the highWaterMark configured when the stream was created after admitting chunk. +If false is returned, further attempts to write data to the stream should +stop until the 'drain' event is emitted.

    +

    While a stream is not draining, calls to write() will buffer chunk, and +return false. Once all currently buffered chunks are drained (accepted for +delivery by the operating system), the 'drain' event will be emitted. +Once write() returns false, do not write more chunks +until the 'drain' event is emitted. While calling write() on a stream that +is not draining is allowed, Node.js will buffer all written chunks until +maximum memory usage occurs, at which point it will abort unconditionally. +Even before it aborts, high memory usage will cause poor garbage collector +performance and high RSS (which is not typically released back to the system, +even after the memory is no longer required). Since TCP sockets may never +drain if the remote peer does not read the data, writing a socket that is +not draining may lead to a remotely exploitable vulnerability.

    +

    Writing data while the stream is not draining is particularly +problematic for a Transform, because the Transform streams are paused +by default until they are piped or a 'data' or 'readable' event handler +is added.

    +

    If the data to be written can be generated or fetched on demand, it is +recommended to encapsulate the logic into a Readable and use pipe. However, if calling write() is preferred, it is +possible to respect backpressure and avoid memory issues using the 'drain' event:

    +
    function write(data, cb) {
    if (!stream.write(data)) {
    stream.once('drain', cb);
    } else {
    process.nextTick(cb);
    }
    }

    // Wait for cb to be called before doing any other write.
    write('hello', () => {
    console.log('Write completed, do more writes now.');
    }); +
    + +

    A Writable stream in object mode will always ignore the encoding argument.

    +

    Parameters

    • chunk: any

      Optional data to write. For streams not operating in object mode, chunk must be a {string}, {Buffer}, +{TypedArray} or {DataView}. For object mode streams, chunk may be any JavaScript value other than null.

      +
    • Optionalencoding: BufferEncoding

      The encoding, if chunk is a string.

      +
    • Optionalcb: ((error: undefined | null | Error) => void)
        • (error): void
        • Parameters

          • error: undefined | null | Error

          Returns void

    Returns boolean

    false if the stream wishes for the calling code to wait for the 'drain' event to be emitted before continuing to write additional data; otherwise true.

    +

    v0.9.4

    +
  • The writable.write() method writes some data to the stream, and calls the +supplied callback once the data has been fully handled. If an error +occurs, the callback will be called with the error as its +first argument. The callback is called asynchronously and before 'error' is +emitted.

    +

    The return value is true if the internal buffer is less than the highWaterMark configured when the stream was created after admitting chunk. +If false is returned, further attempts to write data to the stream should +stop until the 'drain' event is emitted.

    +

    While a stream is not draining, calls to write() will buffer chunk, and +return false. Once all currently buffered chunks are drained (accepted for +delivery by the operating system), the 'drain' event will be emitted. +Once write() returns false, do not write more chunks +until the 'drain' event is emitted. While calling write() on a stream that +is not draining is allowed, Node.js will buffer all written chunks until +maximum memory usage occurs, at which point it will abort unconditionally. +Even before it aborts, high memory usage will cause poor garbage collector +performance and high RSS (which is not typically released back to the system, +even after the memory is no longer required). Since TCP sockets may never +drain if the remote peer does not read the data, writing a socket that is +not draining may lead to a remotely exploitable vulnerability.

    +

    Writing data while the stream is not draining is particularly +problematic for a Transform, because the Transform streams are paused +by default until they are piped or a 'data' or 'readable' event handler +is added.

    +

    If the data to be written can be generated or fetched on demand, it is +recommended to encapsulate the logic into a Readable and use pipe. However, if calling write() is preferred, it is +possible to respect backpressure and avoid memory issues using the 'drain' event:

    +
    function write(data, cb) {
    if (!stream.write(data)) {
    stream.once('drain', cb);
    } else {
    process.nextTick(cb);
    }
    }

    // Wait for cb to be called before doing any other write.
    write('hello', () => {
    console.log('Write completed, do more writes now.');
    }); +
    + +

    A Writable stream in object mode will always ignore the encoding argument.

    +

    Parameters

    • chunk: any

      Optional data to write. For streams not operating in object mode, chunk must be a {string}, {Buffer}, +{TypedArray} or {DataView}. For object mode streams, chunk may be any JavaScript value other than null.

      +
    • Optionalcb: ((error: undefined | null | Error) => void)
        • (error): void
        • Parameters

          • error: undefined | null | Error

          Returns void

    Returns boolean

    false if the stream wishes for the calling code to wait for the 'drain' event to be emitted before continuing to write additional data; otherwise true.

    +

    v0.9.4

    +
  • Experimental

    Listens once to the abort event on the provided signal.

    +

    Listening to the abort event on abort signals is unsafe and may +lead to resource leaks since another third party with the signal can +call e.stopImmediatePropagation(). Unfortunately Node.js cannot change +this since it would violate the web standard. Additionally, the original +API makes it easy to forget to remove listeners.

    +

    This API allows safely using AbortSignals in Node.js APIs by solving these +two issues by listening to the event such that stopImmediatePropagation does +not prevent the listener from running.

    +

    Returns a disposable so that it may be unsubscribed from more easily.

    +
    import { addAbortListener } from 'node:events';

    function example(signal) {
    let disposable;
    try {
    signal.addEventListener('abort', (e) => e.stopImmediatePropagation());
    disposable = addAbortListener(signal, (e) => {
    // Do something when signal is aborted.
    });
    } finally {
    disposable?.[Symbol.dispose]();
    }
    } +
    + +

    Parameters

    • signal: AbortSignal
    • resource: ((event: Event) => void)
        • (event): void
        • Parameters

          • event: Event

          Returns void

    Returns Disposable

    Disposable that removes the abort listener.

    +

    v20.5.0

    +
  • A utility method for creating duplex streams.

    +
      +
    • Stream converts writable stream into writable Duplex and readable stream +to Duplex.
    • +
    • Blob converts into readable Duplex.
    • +
    • string converts into readable Duplex.
    • +
    • ArrayBuffer converts into readable Duplex.
    • +
    • AsyncIterable converts into a readable Duplex. Cannot yield null.
    • +
    • AsyncGeneratorFunction converts into a readable/writable transform +Duplex. Must take a source AsyncIterable as first parameter. Cannot yield +null.
    • +
    • AsyncFunction converts into a writable Duplex. Must return +either null or undefined
    • +
    • Object ({ writable, readable }) converts readable and +writable into Stream and then combines them into Duplex where the +Duplex will write to the writable and read from the readable.
    • +
    • Promise converts into readable Duplex. Value null is ignored.
    • +
    +

    Parameters

    • src:
          | string
          | Object
          | Stream
          | Promise<any>
          | Blob
          | ArrayBuffer
          | Iterable<any>
          | AsyncIterable<any>
          | AsyncGeneratorFunction

    Returns Duplex

    v16.8.0

    +
  • Experimental

    A utility method for creating a Duplex from a web ReadableStream and WritableStream.

    +

    Parameters

    • duplexStream: {
          readable: ReadableStream<any>;
          writable: WritableStream<any>;
      }
      • readable: ReadableStream<any>
      • writable: WritableStream<any>
    • Optionaloptions: Pick<DuplexOptions,
          | "objectMode"
          | "encoding"
          | "allowHalfOpen"
          | "decodeStrings"
          | "highWaterMark"
          | "signal">

    Returns Duplex

    v17.0.0

    +
  • Returns a copy of the array of listeners for the event named eventName.

    +

    For EventEmitters this behaves exactly the same as calling .listeners on +the emitter.

    +

    For EventTargets this is the only way to get the event listeners for the +event target. This is useful for debugging and diagnostic purposes.

    +
    import { getEventListeners, EventEmitter } from 'node:events';

    {
    const ee = new EventEmitter();
    const listener = () => console.log('Events are fun');
    ee.on('foo', listener);
    console.log(getEventListeners(ee, 'foo')); // [ [Function: listener] ]
    }
    {
    const et = new EventTarget();
    const listener = () => console.log('Events are fun');
    et.addEventListener('foo', listener);
    console.log(getEventListeners(et, 'foo')); // [ [Function: listener] ]
    } +
    + +

    Parameters

    • emitter: EventEmitter<DefaultEventMap> | EventTarget
    • name: string | symbol

    Returns Function[]

    v15.2.0, v14.17.0

    +
  • Returns the currently set max amount of listeners.

    +

    For EventEmitters this behaves exactly the same as calling .getMaxListeners on +the emitter.

    +

    For EventTargets this is the only way to get the max event listeners for the +event target. If the number of event handlers on a single EventTarget exceeds +the max set, the EventTarget will print a warning.

    +
    import { getMaxListeners, setMaxListeners, EventEmitter } from 'node:events';

    {
    const ee = new EventEmitter();
    console.log(getMaxListeners(ee)); // 10
    setMaxListeners(11, ee);
    console.log(getMaxListeners(ee)); // 11
    }
    {
    const et = new EventTarget();
    console.log(getMaxListeners(et)); // 10
    setMaxListeners(11, et);
    console.log(getMaxListeners(et)); // 11
    } +
    + +

    Parameters

    • emitter: EventEmitter<DefaultEventMap> | EventTarget

    Returns number

    v19.9.0

    +
  • Returns whether the stream has been read from or cancelled.

    +

    Parameters

    • stream: Readable | ReadableStream

    Returns boolean

    v16.8.0

    +
  • A class method that returns the number of listeners for the given eventName registered on the given emitter.

    +
    import { EventEmitter, listenerCount } from 'node:events';

    const myEmitter = new EventEmitter();
    myEmitter.on('event', () => {});
    myEmitter.on('event', () => {});
    console.log(listenerCount(myEmitter, 'event'));
    // Prints: 2 +
    + +

    Parameters

    • emitter: EventEmitter<DefaultEventMap>

      The emitter to query

      +
    • eventName: string | symbol

      The event name

      +

    Returns number

    v0.9.12

    +

    Since v3.2.0 - Use listenerCount instead.

    +
  • import { on, EventEmitter } from 'node:events';
    import process from 'node:process';

    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here +
    + +

    Returns an AsyncIterator that iterates eventName events. It will throw +if the EventEmitter emits 'error'. It removes all listeners when +exiting the loop. The value returned by each iteration is an array +composed of the emitted event arguments.

    +

    An AbortSignal can be used to cancel waiting on events:

    +
    import { on, EventEmitter } from 'node:events';
    import process from 'node:process';

    const ac = new AbortController();

    (async () => {
    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    });

    for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
    }
    // Unreachable here
    })();

    process.nextTick(() => ac.abort()); +
    + +

    Use the close option to specify an array of event names that will end the iteration:

    +
    import { on, EventEmitter } from 'node:events';
    import process from 'node:process';

    const ee = new EventEmitter();

    // Emit later on
    process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
    ee.emit('close');
    });

    for await (const event of on(ee, 'foo', { close: ['close'] })) {
    console.log(event); // prints ['bar'] [42]
    }
    // the loop will exit after 'close' is emitted
    console.log('done'); // prints 'done' +
    + +

    Parameters

    • emitter: EventEmitter<DefaultEventMap>
    • eventName: string | symbol
    • Optionaloptions: StaticEventEmitterIteratorOptions

    Returns AsyncIterableIterator<any[]>

    An AsyncIterator that iterates eventName events emitted by the emitter

    +

    v13.6.0, v12.16.0

    +
  • Parameters

    • emitter: EventTarget
    • eventName: string
    • Optionaloptions: StaticEventEmitterIteratorOptions

    Returns AsyncIterableIterator<any[]>

  • Creates a Promise that is fulfilled when the EventEmitter emits the given +event or that is rejected if the EventEmitter emits 'error' while waiting. +The Promise will resolve with an array of all the arguments emitted to the +given event.

    +

    This method is intentionally generic and works with the web platform EventTarget interface, which has no special'error' event +semantics and does not listen to the 'error' event.

    +
    import { once, EventEmitter } from 'node:events';
    import process from 'node:process';

    const ee = new EventEmitter();

    process.nextTick(() => {
    ee.emit('myevent', 42);
    });

    const [value] = await once(ee, 'myevent');
    console.log(value);

    const err = new Error('kaboom');
    process.nextTick(() => {
    ee.emit('error', err);
    });

    try {
    await once(ee, 'myevent');
    } catch (err) {
    console.error('error happened', err);
    } +
    + +

    The special handling of the 'error' event is only used when events.once() is used to wait for another event. If events.once() is used to wait for the +'error' event itself, then it is treated as any other kind of event without +special handling:

    +
    import { EventEmitter, once } from 'node:events';

    const ee = new EventEmitter();

    once(ee, 'error')
    .then(([err]) => console.log('ok', err.message))
    .catch((err) => console.error('error', err.message));

    ee.emit('error', new Error('boom'));

    // Prints: ok boom +
    + +

    An AbortSignal can be used to cancel waiting for the event:

    +
    import { EventEmitter, once } from 'node:events';

    const ee = new EventEmitter();
    const ac = new AbortController();

    async function foo(emitter, event, signal) {
    try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
    } catch (error) {
    if (error.name === 'AbortError') {
    console.error('Waiting for the event was canceled!');
    } else {
    console.error('There was an error', error.message);
    }
    }
    }

    foo(ee, 'foo', ac.signal);
    ac.abort(); // Abort waiting for the event
    ee.emit('foo'); // Prints: Waiting for the event was canceled! +
    + +

    Parameters

    • emitter: EventEmitter<DefaultEventMap>
    • eventName: string | symbol
    • Optionaloptions: StaticEventEmitterOptions

    Returns Promise<any[]>

    v11.13.0, v10.16.0

    +
  • Parameters

    • emitter: EventTarget
    • eventName: string
    • Optionaloptions: StaticEventEmitterOptions

    Returns Promise<any[]>

  • import { setMaxListeners, EventEmitter } from 'node:events';

    const target = new EventTarget();
    const emitter = new EventEmitter();

    setMaxListeners(5, target, emitter); +
    + +

    Parameters

    • Optionaln: number

      A non-negative number. The maximum number of listeners per EventTarget event.

      +
    • Rest...eventTargets: (EventEmitter<DefaultEventMap> | EventTarget)[]

    Returns void

    v15.4.0

    +
  • Experimental

    A utility method for creating a web ReadableStream and WritableStream from a Duplex.

    +

    Parameters

    • streamDuplex: Duplex

    Returns {
        readable: ReadableStream<any>;
        writable: WritableStream<any>;
    }

    • Experimentalreadable: ReadableStream<any>
    • Experimentalwritable: WritableStream<any>

    v17.0.0

    +
diff --git a/lib/souffle-js/api/classes/logger.DefaultLogger.html b/lib/souffle-js/api/classes/logger.DefaultLogger.html new file mode 100644 index 000000000..102f3c1a8 --- /dev/null +++ b/lib/souffle-js/api/classes/logger.DefaultLogger.html @@ -0,0 +1,6 @@ +DefaultLogger | Souffle.js

Implements

Constructors

Methods

Constructors

Methods

diff --git a/lib/souffle-js/api/classes/prettyPrinter.SoufflePrettyPrinter.html b/lib/souffle-js/api/classes/prettyPrinter.SoufflePrettyPrinter.html new file mode 100644 index 000000000..6cc5c107b --- /dev/null +++ b/lib/souffle-js/api/classes/prettyPrinter.SoufflePrettyPrinter.html @@ -0,0 +1,4 @@ +SoufflePrettyPrinter | Souffle.js

Class SoufflePrettyPrinter<FactData>

Pretty-prints Souffle entries.

+

Type Parameters

  • FactData = undefined

Methods

Methods

diff --git a/lib/souffle-js/api/classes/syntaxConstructors.Type.html b/lib/souffle-js/api/classes/syntaxConstructors.Type.html new file mode 100644 index 000000000..883a821fb --- /dev/null +++ b/lib/souffle-js/api/classes/syntaxConstructors.Type.html @@ -0,0 +1,6 @@ +Type | Souffle.js
diff --git a/lib/souffle-js/api/classes/syntaxConstructors.TypeDef.html b/lib/souffle-js/api/classes/syntaxConstructors.TypeDef.html new file mode 100644 index 000000000..6deba7ab7 --- /dev/null +++ b/lib/souffle-js/api/classes/syntaxConstructors.TypeDef.html @@ -0,0 +1,3 @@ +TypeDef | Souffle.js

Methods

diff --git a/lib/souffle-js/api/functions/executor_results.parseResults.html b/lib/souffle-js/api/functions/executor_results.parseResults.html new file mode 100644 index 000000000..37a7af58b --- /dev/null +++ b/lib/souffle-js/api/functions/executor_results.parseResults.html @@ -0,0 +1,4 @@ +parseResults | Souffle.js
diff --git a/lib/souffle-js/api/functions/executor_results.parseResultsSync.html b/lib/souffle-js/api/functions/executor_results.parseResultsSync.html new file mode 100644 index 000000000..62905e3cf --- /dev/null +++ b/lib/souffle-js/api/functions/executor_results.parseResultsSync.html @@ -0,0 +1,4 @@ +parseResultsSync | Souffle.js
diff --git a/lib/souffle-js/api/functions/executor_results.parseSpaceSeparatedValues.html b/lib/souffle-js/api/functions/executor_results.parseSpaceSeparatedValues.html new file mode 100644 index 000000000..0a29a6f30 --- /dev/null +++ b/lib/souffle-js/api/functions/executor_results.parseSpaceSeparatedValues.html @@ -0,0 +1,2 @@ +parseSpaceSeparatedValues | Souffle.js

Function parseSpaceSeparatedValues

diff --git a/lib/souffle-js/api/functions/syntaxConstructors.atom.html b/lib/souffle-js/api/functions/syntaxConstructors.atom.html new file mode 100644 index 000000000..9e54c2639 --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.atom.html @@ -0,0 +1 @@ +atom | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.binaryConstraint.html b/lib/souffle-js/api/functions/syntaxConstructors.binaryConstraint.html new file mode 100644 index 000000000..d52e18276 --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.binaryConstraint.html @@ -0,0 +1 @@ +binaryConstraint | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.body.html b/lib/souffle-js/api/functions/syntaxConstructors.body.html new file mode 100644 index 000000000..d1498ca68 --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.body.html @@ -0,0 +1 @@ +body | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.booleanConstraint.html b/lib/souffle-js/api/functions/syntaxConstructors.booleanConstraint.html new file mode 100644 index 000000000..5c677e6ad --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.booleanConstraint.html @@ -0,0 +1 @@ +booleanConstraint | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.comment.html b/lib/souffle-js/api/functions/syntaxConstructors.comment.html new file mode 100644 index 000000000..3e10baad3 --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.comment.html @@ -0,0 +1 @@ +comment | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.containsConstraint.html b/lib/souffle-js/api/functions/syntaxConstructors.containsConstraint.html new file mode 100644 index 000000000..86aedb804 --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.containsConstraint.html @@ -0,0 +1 @@ +containsConstraint | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.fact.html b/lib/souffle-js/api/functions/syntaxConstructors.fact.html new file mode 100644 index 000000000..6b083883d --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.fact.html @@ -0,0 +1 @@ +fact | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.matchConstraint.html b/lib/souffle-js/api/functions/syntaxConstructors.matchConstraint.html new file mode 100644 index 000000000..b0eb36f82 --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.matchConstraint.html @@ -0,0 +1 @@ +matchConstraint | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.program.html b/lib/souffle-js/api/functions/syntaxConstructors.program.html new file mode 100644 index 000000000..f76bea544 --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.program.html @@ -0,0 +1 @@ +program | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.relation.html b/lib/souffle-js/api/functions/syntaxConstructors.relation.html new file mode 100644 index 000000000..55100ccd3 --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.relation.html @@ -0,0 +1 @@ +relation | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxConstructors.rule.html b/lib/souffle-js/api/functions/syntaxConstructors.rule.html new file mode 100644 index 000000000..9c7025681 --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxConstructors.rule.html @@ -0,0 +1 @@ +rule | Souffle.js
diff --git a/lib/souffle-js/api/functions/syntaxUtils.eqFactValues.html b/lib/souffle-js/api/functions/syntaxUtils.eqFactValues.html new file mode 100644 index 000000000..fe43da0dc --- /dev/null +++ b/lib/souffle-js/api/functions/syntaxUtils.eqFactValues.html @@ -0,0 +1 @@ +eqFactValues | Souffle.js
diff --git a/lib/souffle-js/api/hierarchy.html b/lib/souffle-js/api/hierarchy.html new file mode 100644 index 000000000..52f85e71f --- /dev/null +++ b/lib/souffle-js/api/hierarchy.html @@ -0,0 +1 @@ +Souffle.js
diff --git a/lib/souffle-js/api/index.html b/lib/souffle-js/api/index.html new file mode 100644 index 000000000..7dec728f6 --- /dev/null +++ b/lib/souffle-js/api/index.html @@ -0,0 +1,14 @@ +Souffle.js

Souffle.js

Souffle.js

Souffle.js offers bindings to Soufflé, an open-source, parallel logic programming language.

+

Install the library with Yarn:

+
yarn add @nowarp/souffle
+
+ +

Here is an example implementing the Simple Typed VarPointsTo example:

+
const ctx = new SouffleContext("VarPointsTo");

// Declare relations
ctx.add(
relation("assign", [
["a", Type.symbol()],
["b", Type.symbol()],
]),
);

// Add facts
ctx.addFact("assign", ["v1", "v2"]);

// Define and output rules
ctx.add(
relation(
"alias",
[
["a", Type.symbol()],
["b", Type.symbol()],
],
"output",
),
);
ctx.add(rule([atom("alias", ["X", "X"])], [body(atom("assign", ["X", "_"]))]));

// Execute the Soufflé program
const executor = new SouffleSyncExecutor();
const out = executor.execute(ctx);
console.log("Raw Soufflé output:\n", out.results); +
+ +

For the full example, see the source here.

+
    +
  • nowarp/misti – Static analyzer for TON smart contracts
  • +
+
diff --git a/lib/souffle-js/api/interfaces/executor_executor.SouffleExecutorParams.html b/lib/souffle-js/api/interfaces/executor_executor.SouffleExecutorParams.html new file mode 100644 index 000000000..f4de597e9 --- /dev/null +++ b/lib/souffle-js/api/interfaces/executor_executor.SouffleExecutorParams.html @@ -0,0 +1,9 @@ +SouffleExecutorParams | Souffle.js
interface SouffleExecutorParams {
    inputDir?: string;
    outputDir?: string;
    processResults?: boolean;
    soufflePath?: string;
}

Properties

inputDir?: string

Temporary directory to store input facts for Soufflé.

+
outputDir?: string

Temporary directory or path to CSV output from Soufflé.

+
processResults?: boolean

Try to process results to get the structured output.

+
soufflePath?: string

Path to the Soufflé binary.

+
diff --git a/lib/souffle-js/api/interfaces/logger.ILogger.html b/lib/souffle-js/api/interfaces/logger.ILogger.html new file mode 100644 index 000000000..2b72e787d --- /dev/null +++ b/lib/souffle-js/api/interfaces/logger.ILogger.html @@ -0,0 +1,5 @@ +ILogger | Souffle.js

Interface ILogger

interface ILogger {
    debug: ((message: string) => void);
    error: ((message: string) => void);
    info: ((message: string) => void);
    warn: ((message: string) => void);
}

Implemented by

Properties

Properties

debug: ((message: string) => void)
error: ((message: string) => void)
info: ((message: string) => void)
warn: ((message: string) => void)
diff --git a/lib/souffle-js/api/media/simpleTypedVarPointsTo.ts b/lib/souffle-js/api/media/simpleTypedVarPointsTo.ts new file mode 100644 index 000000000..0571b0a1e --- /dev/null +++ b/lib/souffle-js/api/media/simpleTypedVarPointsTo.ts @@ -0,0 +1,125 @@ +// +// Implements https://souffle-lang.github.io/examples#simple-typed-symbolpointsto in Souffle.js +// + +import { + SouffleContext, + SouffleSyncExecutor, + relation, + rule, + atom, + body, + Type, +} from "../src"; + +// Initialize the Souffle context that keeps the created program entries. +const ctx = new SouffleContext("VarPointsTo"); + +// Add relation declarations: +// .decl assign( a:symbol , b:symbol ) +// .decl new( v:symbol, o:symbol ) +// .decl ld( a:symbol, b:symbol, f:symbol ) +// .decl st( a:symbol, f:symbol, b:symbol ) +ctx.add( + relation("assign", [ + ["a", Type.symbol()], + ["b", Type.symbol()], + ]), +); +ctx.add( + relation("new", [ + ["v", Type.symbol()], + ["o", Type.symbol()], + ]), +); +ctx.add( + relation("ld", [ + ["a", Type.symbol()], + ["b", Type.symbol()], + ["f", Type.symbol()], + ]), +); +ctx.add( + relation("st", [ + ["a", Type.symbol()], + ["f", Type.symbol()], + ["b", Type.symbol()], + ]), +); + +// Add facts: +// assign("v1","v2"). +// new("v1","h1"). +// new("v2","h2"). +// new("v3","h3"). +// st("v1","f","v3"). +// ld("v4","v1","f"). +ctx.addFact("assign", ["v1", "v2"]); +ctx.addFact("new", ["v1", "h1"]); +ctx.addFact("new", ["v2", "h2"]); +ctx.addFact("new", ["v3", "h3"]); +ctx.addFact("st", ["v1", "f", "v3"]); +ctx.addFact("ld", ["v4", "v1", "f"]); + +// Add rules: +// .decl alias( a:symbol, b:symbol ) +// .output alias +// alias(X,X) :- assign(X,_). +// alias(X,X) :- assign(_,X). +// alias(X,Y) :- assign(X,Y). +// alias(X,Y) :- ld(X,A,F), alias(A,B), st(B,F,Y). +ctx.add( + relation( + "alias", + [ + ["a", Type.symbol()], + ["b", Type.symbol()], + ], + "output", + ), +); +ctx.add(rule([atom("alias", ["X", "X"])], [body(atom("assign", ["X", "_"]))])); +ctx.add(rule([atom("alias", ["X", "X"])], [body(atom("assign", ["_", "X"]))])); +ctx.add(rule([atom("alias", ["X", "Y"])], [body(atom("assign", ["X", "Y"]))])); +ctx.add( + rule( + [atom("alias", ["X", "Y"])], + [ + body(atom("ld", ["X", "A", "F"])), + body(atom("alias", ["A", "B"])), + body(atom("st", ["B", "F", "Y"])), + ], + ), +); + +// .decl pointsTo( a:symbol, o:symbol ) +// .output pointsTo +// pointsTo(X,Y) :- new(X,Y). +// pointsTo(X,Y) :- alias(X,Z), pointsTo(Z,Y). +ctx.add( + relation( + "pointsTo", + [ + ["a", Type.symbol()], + ["o", Type.symbol()], + ], + "output", + ), +); +ctx.add(rule([atom("pointsTo", ["X", "Y"])], [body(atom("new", ["X", "Y"]))])); +ctx.add( + rule( + [atom("pointsTo", ["X", "Y"])], + [body(atom("alias", ["X", "Z"])), body(atom("pointsTo", ["Z", "Y"]))], + ), +); + +// Execute the generated Soufflé program containing all the added entries +const executor = new SouffleSyncExecutor(); +const out = executor.execute(ctx); +if (out.kind !== "raw") { + throw new Error( + `Error executing Soufflé:\n${out.kind === "error" ? out.stderr : "impossible"}`, + ); +} +console.log("Raw Soufflé output:\n", out.results); diff --git a/lib/souffle-js/api/modules/context.html b/lib/souffle-js/api/modules/context.html new file mode 100644 index 000000000..57f235df0 --- /dev/null +++ b/lib/souffle-js/api/modules/context.html @@ -0,0 +1,2 @@ +context | Souffle.js

Module context

Index

Classes

diff --git a/lib/souffle-js/api/modules/emitter.html b/lib/souffle-js/api/modules/emitter.html new file mode 100644 index 000000000..e5008bdad --- /dev/null +++ b/lib/souffle-js/api/modules/emitter.html @@ -0,0 +1,2 @@ +emitter | Souffle.js

Module emitter

Index

Classes

diff --git a/lib/souffle-js/api/modules/errors.html b/lib/souffle-js/api/modules/errors.html new file mode 100644 index 000000000..2c678ae9e --- /dev/null +++ b/lib/souffle-js/api/modules/errors.html @@ -0,0 +1,5 @@ +errors | Souffle.js
diff --git a/lib/souffle-js/api/modules/executor.html b/lib/souffle-js/api/modules/executor.html new file mode 100644 index 000000000..c896131dc --- /dev/null +++ b/lib/souffle-js/api/modules/executor.html @@ -0,0 +1,8 @@ +executor | Souffle.js

Module executor

References

Re-exports SouffleAsyncExecutor
Re-exports SouffleExecutionResult
Re-exports SouffleExecutor
Re-exports SouffleExecutorParams
Re-exports SouffleOutputRaw
Re-exports SouffleOutputStructured
Re-exports SouffleSyncExecutor
diff --git a/lib/souffle-js/api/modules/executor_executor.html b/lib/souffle-js/api/modules/executor_executor.html new file mode 100644 index 000000000..eeb45e5c5 --- /dev/null +++ b/lib/souffle-js/api/modules/executor_executor.html @@ -0,0 +1,6 @@ +executor/executor | Souffle.js
diff --git a/lib/souffle-js/api/modules/executor_results.html b/lib/souffle-js/api/modules/executor_results.html new file mode 100644 index 000000000..9df1ad142 --- /dev/null +++ b/lib/souffle-js/api/modules/executor_results.html @@ -0,0 +1,7 @@ +executor/results | Souffle.js
diff --git a/lib/souffle-js/api/modules/index.html b/lib/souffle-js/api/modules/index.html new file mode 100644 index 000000000..ce9e69865 --- /dev/null +++ b/lib/souffle-js/api/modules/index.html @@ -0,0 +1,48 @@ +index | Souffle.js

Module index

References

Re-exports atom
Re-exports binaryConstraint
Re-exports body
Re-exports booleanConstraint
Re-exports comment
Re-exports containsConstraint
Re-exports fact
Re-exports matchConstraint
Re-exports program
Re-exports relation
Re-exports rule
Re-exports SOUFFLE_VERSION
Re-exports SouffleAsyncExecutor
Re-exports SouffleAtom
Re-exports SouffleComment
Re-exports SouffleConstraint
Re-exports SouffleContext
Re-exports SouffleCustomType
Re-exports SouffleEmitter
Re-exports SouffleEquivalenceTypeDefinition
Re-exports SouffleError
Re-exports SouffleExecutionError
Re-exports SouffleExecutionResult
Re-exports SouffleExecutor
Re-exports SouffleExecutorParams
Re-exports SouffleFact
Re-exports SouffleFactValue
Re-exports SouffleInternalError
Re-exports SouffleNode
Re-exports SouffleOutputRaw
Re-exports SouffleOutputStructured
Re-exports SoufflePrettyPrinter
Re-exports SoufflePrimitiveType
Re-exports SoufflePrimitiveTypeValue
Re-exports SouffleProgram
Re-exports SouffleProgramEntry
Re-exports SouffleRelation
Re-exports SouffleRelationArg
Re-exports SouffleRule
Re-exports SouffleRuleBody
Re-exports SouffleSubtypeTypeDefinition
Re-exports SouffleSyncExecutor
Re-exports SouffleType
Re-exports SouffleTypeDefinition
Re-exports SouffleUsageError
Re-exports Type
Re-exports TypeDef
diff --git a/lib/souffle-js/api/modules/logger.html b/lib/souffle-js/api/modules/logger.html new file mode 100644 index 000000000..16b4f6de0 --- /dev/null +++ b/lib/souffle-js/api/modules/logger.html @@ -0,0 +1,3 @@ +logger | Souffle.js

Module logger

Index

Classes

Interfaces

diff --git a/lib/souffle-js/api/modules/prettyPrinter.html b/lib/souffle-js/api/modules/prettyPrinter.html new file mode 100644 index 000000000..bfc6a500b --- /dev/null +++ b/lib/souffle-js/api/modules/prettyPrinter.html @@ -0,0 +1,2 @@ +prettyPrinter | Souffle.js

Module prettyPrinter

Index

Classes

diff --git a/lib/souffle-js/api/modules/syntax.html b/lib/souffle-js/api/modules/syntax.html new file mode 100644 index 000000000..9f7e3dec2 --- /dev/null +++ b/lib/souffle-js/api/modules/syntax.html @@ -0,0 +1,23 @@ +syntax | Souffle.js
diff --git a/lib/souffle-js/api/modules/syntaxConstructors.html b/lib/souffle-js/api/modules/syntaxConstructors.html new file mode 100644 index 000000000..6b10860d4 --- /dev/null +++ b/lib/souffle-js/api/modules/syntaxConstructors.html @@ -0,0 +1,15 @@ +syntaxConstructors | Souffle.js
diff --git a/lib/souffle-js/api/modules/syntaxUtils.html b/lib/souffle-js/api/modules/syntaxUtils.html new file mode 100644 index 000000000..be6abb47b --- /dev/null +++ b/lib/souffle-js/api/modules/syntaxUtils.html @@ -0,0 +1,2 @@ +syntaxUtils | Souffle.js

Module syntaxUtils

Index

Functions

diff --git a/lib/souffle-js/api/modules/version.html b/lib/souffle-js/api/modules/version.html new file mode 100644 index 000000000..58701e173 --- /dev/null +++ b/lib/souffle-js/api/modules/version.html @@ -0,0 +1,2 @@ +version | Souffle.js

Module version

Index

Variables

diff --git a/lib/souffle-js/api/types/executor_executor.SouffleExecutionResult.html b/lib/souffle-js/api/types/executor_executor.SouffleExecutionResult.html new file mode 100644 index 000000000..59c06baee --- /dev/null +++ b/lib/souffle-js/api/types/executor_executor.SouffleExecutionResult.html @@ -0,0 +1,6 @@ +SouffleExecutionResult | Souffle.js

Type Alias SouffleExecutionResult<FactData>

SouffleExecutionResult<FactData>: {
    kind: "structured";
    results: SouffleOutputStructured<FactData>;
} | {
    kind: "raw";
    results: Map<string, SouffleOutputRaw>;
} | {
    kind: "error";
    stderr: string;
}

Encapsulates results of the Soufflé execution.

+

Type Parameters

  • FactData
  • {
        kind: "structured";
        results: SouffleOutputStructured<FactData>;
    }

    The structured result which values are assigned to something meaningful with +respect to FactData.

    +
  • {
        kind: "raw";
        results: Map<string, SouffleOutputRaw>;
    }

    It was not possible to further process the raw results.

    +
  • {
        kind: "error";
        stderr: string;
    }

    An error occurred.

    +
diff --git a/lib/souffle-js/api/types/executor_results.SouffleOutputRaw.html b/lib/souffle-js/api/types/executor_results.SouffleOutputRaw.html new file mode 100644 index 000000000..2c7f3e9d6 --- /dev/null +++ b/lib/souffle-js/api/types/executor_results.SouffleOutputRaw.html @@ -0,0 +1,3 @@ +SouffleOutputRaw | Souffle.js
SouffleOutputRaw: string[][]

Raw strings parsed from the Soufflé CSV-like output in the following format: +rule_name |-> [relation_name, fact_name]

+
diff --git a/lib/souffle-js/api/types/syntax.SouffleAtom.html b/lib/souffle-js/api/types/syntax.SouffleAtom.html new file mode 100644 index 000000000..9f3ebbfa8 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleAtom.html @@ -0,0 +1,3 @@ +SouffleAtom | Souffle.js

Type Alias SouffleAtom

SouffleAtom: {
    args: string[];
    kind: "atom";
    name: string;
}

An atom of the Soufflé rule. +See: https://souffle-lang.github.io/rules#atom

+
diff --git a/lib/souffle-js/api/types/syntax.SouffleComment.html b/lib/souffle-js/api/types/syntax.SouffleComment.html new file mode 100644 index 000000000..7705aa5d2 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleComment.html @@ -0,0 +1,3 @@ +SouffleComment | Souffle.js

Type Alias SouffleComment

SouffleComment: {
    kind: "comment";
    lines: string[];
    style: "//" | "/*";
}

Comments in the source code. +See: https://souffle-lang.github.io/program#comments

+
diff --git a/lib/souffle-js/api/types/syntax.SouffleConstraint.html b/lib/souffle-js/api/types/syntax.SouffleConstraint.html new file mode 100644 index 000000000..81cf68eb8 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleConstraint.html @@ -0,0 +1,3 @@ +SouffleConstraint | Souffle.js

Type Alias SouffleConstraint

SouffleConstraint:
    | {
        kind: "binary";
        lhs: SouffleConstraintArg;
        op: SouffleConstraintOp;
        rhs: SouffleConstraintArg;
    }
    | {
        kind: "match";
        lhs: SouffleConstraintArg;
        rhs: SouffleConstraintArg;
    }
    | {
        kind: "contains";
        lhs: SouffleConstraintArg;
        rhs: SouffleConstraintArg;
    }
    | {
        kind: "boolean";
        value: boolean;
    }

A predicate used in rules to produce boolean values. +See: https://souffle-lang.github.io/constraints

+
diff --git a/lib/souffle-js/api/types/syntax.SouffleConstraintArg.html b/lib/souffle-js/api/types/syntax.SouffleConstraintArg.html new file mode 100644 index 000000000..9a92d2870 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleConstraintArg.html @@ -0,0 +1 @@ +SouffleConstraintArg | Souffle.js

Type Alias SouffleConstraintArg

SouffleConstraintArg: string | number
diff --git a/lib/souffle-js/api/types/syntax.SouffleConstraintOp.html b/lib/souffle-js/api/types/syntax.SouffleConstraintOp.html new file mode 100644 index 000000000..f83c49469 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleConstraintOp.html @@ -0,0 +1 @@ +SouffleConstraintOp | Souffle.js

Type Alias SouffleConstraintOp

SouffleConstraintOp:
    | "<"
    | ">"
    | "<="
    | ">="
    | "="
    | "!="
diff --git a/lib/souffle-js/api/types/syntax.SouffleCustomType.html b/lib/souffle-js/api/types/syntax.SouffleCustomType.html new file mode 100644 index 000000000..c41e3dc84 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleCustomType.html @@ -0,0 +1 @@ +SouffleCustomType | Souffle.js

Type Alias SouffleCustomType

SouffleCustomType: {
    kind: "custom_type";
    value: string;
}
diff --git a/lib/souffle-js/api/types/syntax.SouffleEquivalenceTypeDefinition.html b/lib/souffle-js/api/types/syntax.SouffleEquivalenceTypeDefinition.html new file mode 100644 index 000000000..671e6dcbe --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleEquivalenceTypeDefinition.html @@ -0,0 +1 @@ +SouffleEquivalenceTypeDefinition | Souffle.js

Type Alias SouffleEquivalenceTypeDefinition

SouffleEquivalenceTypeDefinition: {
    kind: "equivalence_type_definition";
    name: string;
    type: SouffleType;
}
diff --git a/lib/souffle-js/api/types/syntax.SouffleFact.html b/lib/souffle-js/api/types/syntax.SouffleFact.html new file mode 100644 index 000000000..ef5125359 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleFact.html @@ -0,0 +1,5 @@ +SouffleFact | Souffle.js

Type Alias SouffleFact<FactData>

SouffleFact<FactData>: {
    data?: FactData;
    kind: "fact";
    relationName: string;
    values: SouffleFactValue[];
}

Soufflé facts are always connected to relation declarations, which define their +type. Thus, in most cases, you should use SouffleContext.addFact to introduce +new facts bound to relations. +See: https://souffle-lang.github.io/facts

+

Type Parameters

  • FactData = undefined
diff --git a/lib/souffle-js/api/types/syntax.SouffleFactValue.html b/lib/souffle-js/api/types/syntax.SouffleFactValue.html new file mode 100644 index 000000000..d07623a1b --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleFactValue.html @@ -0,0 +1 @@ +SouffleFactValue | Souffle.js

Type Alias SouffleFactValue

SouffleFactValue: string | number
diff --git a/lib/souffle-js/api/types/syntax.SouffleNode.html b/lib/souffle-js/api/types/syntax.SouffleNode.html new file mode 100644 index 000000000..89b691b9a --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleNode.html @@ -0,0 +1 @@ +SouffleNode | Souffle.js

Type Alias SouffleNode<FactData>

SouffleNode<FactData>:
    | SouffleComment
    | SouffleTypeDefinition
    | SouffleProgram<FactData>
    | SouffleFact<FactData>
    | SouffleRelation
    | SouffleRule
    | SouffleAtom

Type Parameters

  • FactData = undefined
diff --git a/lib/souffle-js/api/types/syntax.SoufflePrimitiveType.html b/lib/souffle-js/api/types/syntax.SoufflePrimitiveType.html new file mode 100644 index 000000000..0af50fd23 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SoufflePrimitiveType.html @@ -0,0 +1 @@ +SoufflePrimitiveType | Souffle.js

Type Alias SoufflePrimitiveType

SoufflePrimitiveType: {
    kind: "primitive_type";
    value: SoufflePrimitiveTypeValue;
}
diff --git a/lib/souffle-js/api/types/syntax.SoufflePrimitiveTypeValue.html b/lib/souffle-js/api/types/syntax.SoufflePrimitiveTypeValue.html new file mode 100644 index 000000000..8cb1c6bff --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SoufflePrimitiveTypeValue.html @@ -0,0 +1 @@ +SoufflePrimitiveTypeValue | Souffle.js

Type Alias SoufflePrimitiveTypeValue

SoufflePrimitiveTypeValue:
    | "Symbol"
    | "Number"
    | "Unsigned"
    | "Float"
diff --git a/lib/souffle-js/api/types/syntax.SouffleProgram.html b/lib/souffle-js/api/types/syntax.SouffleProgram.html new file mode 100644 index 000000000..198c6b15c --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleProgram.html @@ -0,0 +1,3 @@ +SouffleProgram | Souffle.js

Type Alias SouffleProgram<FactData>

SouffleProgram<FactData>: {
    comment: SouffleComment | undefined;
    entries: SouffleProgramEntry<FactData>[];
    kind: "program";
    name: string;
}

Soufflé program present in a single source file. +See: https://souffle-lang.github.io/program

+

Type Parameters

  • FactData = undefined
diff --git a/lib/souffle-js/api/types/syntax.SouffleProgramEntry.html b/lib/souffle-js/api/types/syntax.SouffleProgramEntry.html new file mode 100644 index 000000000..494c6a738 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleProgramEntry.html @@ -0,0 +1 @@ +SouffleProgramEntry | Souffle.js

Type Alias SouffleProgramEntry<FactData>

SouffleProgramEntry<FactData>:
    | SouffleComment
    | SouffleTypeDefinition
    | SouffleFact<FactData>
    | SouffleRelation
    | SouffleRule

Type Parameters

  • FactData = undefined
diff --git a/lib/souffle-js/api/types/syntax.SouffleRelation.html b/lib/souffle-js/api/types/syntax.SouffleRelation.html new file mode 100644 index 000000000..ec8d2a37a --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleRelation.html @@ -0,0 +1,3 @@ +SouffleRelation | Souffle.js

Type Alias SouffleRelation

SouffleRelation: {
    args: SouffleRelationArg[];
    comment: SouffleComment | undefined;
    io: SouffleRelationIO | undefined;
    kind: "relation";
    name: string;
}

Declaration of a Soufflé relation. +See: https://souffle-lang.github.io/relations

+
diff --git a/lib/souffle-js/api/types/syntax.SouffleRelationArg.html b/lib/souffle-js/api/types/syntax.SouffleRelationArg.html new file mode 100644 index 000000000..c0ba78cca --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleRelationArg.html @@ -0,0 +1 @@ +SouffleRelationArg | Souffle.js

Type Alias SouffleRelationArg

SouffleRelationArg: {
    name: string;
    type: SouffleType;
}
diff --git a/lib/souffle-js/api/types/syntax.SouffleRelationIO.html b/lib/souffle-js/api/types/syntax.SouffleRelationIO.html new file mode 100644 index 000000000..e6142825a --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleRelationIO.html @@ -0,0 +1 @@ +SouffleRelationIO | Souffle.js

Type Alias SouffleRelationIO

SouffleRelationIO: "input" | "output"
diff --git a/lib/souffle-js/api/types/syntax.SouffleRule.html b/lib/souffle-js/api/types/syntax.SouffleRule.html new file mode 100644 index 000000000..532b9eaef --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleRule.html @@ -0,0 +1,3 @@ +SouffleRule | Souffle.js

Type Alias SouffleRule

SouffleRule: {
    body: SouffleRuleBody[];
    comment: SouffleComment | undefined;
    heads: SouffleAtom[];
    kind: "rule";
}
diff --git a/lib/souffle-js/api/types/syntax.SouffleRuleBody.html b/lib/souffle-js/api/types/syntax.SouffleRuleBody.html new file mode 100644 index 000000000..44bf59653 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleRuleBody.html @@ -0,0 +1,3 @@ +SouffleRuleBody | Souffle.js

Type Alias SouffleRuleBody

SouffleRuleBody: {
    kind: "atom";
    negated: boolean;
    value: SouffleAtom;
} | {
    kind: "constraint";
    negated: boolean;
    value: SouffleConstraint;
}

Body of a rule which is present as a conjunction of (negated) atoms/constraints/disjunctions. +See: https://souffle-lang.github.io/rules#conjunction

+
diff --git a/lib/souffle-js/api/types/syntax.SouffleSubtypeTypeDefinition.html b/lib/souffle-js/api/types/syntax.SouffleSubtypeTypeDefinition.html new file mode 100644 index 000000000..084d75ee2 --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleSubtypeTypeDefinition.html @@ -0,0 +1 @@ +SouffleSubtypeTypeDefinition | Souffle.js

Type Alias SouffleSubtypeTypeDefinition

SouffleSubtypeTypeDefinition: {
    kind: "subtype_type_definition";
    name: string;
    type: SouffleType;
}
diff --git a/lib/souffle-js/api/types/syntax.SouffleType.html b/lib/souffle-js/api/types/syntax.SouffleType.html new file mode 100644 index 000000000..051f6ddec --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleType.html @@ -0,0 +1,2 @@ +SouffleType | Souffle.js

Type Alias SouffleType

Souffle type annotations as they appear in the source code.

+
diff --git a/lib/souffle-js/api/types/syntax.SouffleTypeDefinition.html b/lib/souffle-js/api/types/syntax.SouffleTypeDefinition.html new file mode 100644 index 000000000..f103499dd --- /dev/null +++ b/lib/souffle-js/api/types/syntax.SouffleTypeDefinition.html @@ -0,0 +1,3 @@ +SouffleTypeDefinition | Souffle.js
diff --git a/lib/souffle-js/api/types/syntaxConstructors.CommentValue.html b/lib/souffle-js/api/types/syntaxConstructors.CommentValue.html new file mode 100644 index 000000000..8e6b3f80c --- /dev/null +++ b/lib/souffle-js/api/types/syntaxConstructors.CommentValue.html @@ -0,0 +1 @@ +CommentValue | Souffle.js
CommentValue: string | string[]
diff --git a/lib/souffle-js/api/variables/version.SOUFFLE_VERSION.html b/lib/souffle-js/api/variables/version.SOUFFLE_VERSION.html new file mode 100644 index 000000000..be113102d --- /dev/null +++ b/lib/souffle-js/api/variables/version.SOUFFLE_VERSION.html @@ -0,0 +1,2 @@ +SOUFFLE_VERSION | Souffle.js

Variable SOUFFLE_VERSIONConst

SOUFFLE_VERSION: "2.4.1" = "2.4.1"

Supported Souffle version.

+
diff --git a/markdown-page/index.html b/markdown-page/index.html new file mode 100644 index 000000000..6626a48a9 --- /dev/null +++ b/markdown-page/index.html @@ -0,0 +1,22 @@ + + + + + +Markdown page example | Misti + + + + +

Markdown page example

+

You don't need React to write simple standalone pages.

+ + \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 000000000..e6b8cdc6c --- /dev/null +++ b/sitemap.xml @@ -0,0 +1 @@ +https://nowarp.io/markdown-pageweekly0.5https://nowarp.io/tools/misti/weekly0.5https://nowarp.io/tools/misti/docs/0.1.2/weekly0.5https://nowarp.io/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiplyweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/detectors/NeverAccessedVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/detectors/ReadOnlyVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/detectors/UnboundLoopsweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/detectors/ZeroAddressweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/hacking/CHANGELOGweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/hacking/contributingweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/hacking/custom-detectorweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/hacking/designweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/hacking/souffleweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/hacking/toolsweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/tutorial/configurationweekly0.5https://nowarp.io/tools/misti/docs/0.1.2/tutorial/getting-startedweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/weekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectorsweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/BranchDuplicateweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/ConstantAddressweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiplyweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/DumpIsUsedweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/FieldDoubleInitweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/NeverAccessedVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssignweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/ReadOnlyVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/UnboundLoopsweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/detectors/ZeroAddressweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/hacking/contributingweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/hacking/custom-detectorweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/hacking/designweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/hacking/souffleweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/hacking/toolsweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/tutorial/ci-cdweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/tutorial/configurationweekly0.5https://nowarp.io/tools/misti/docs/0.2.0/tutorial/getting-startedweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/weekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectorsweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/BranchDuplicateweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/ConstantAddressweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiplyweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/DumpIsUsedweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/FieldDoubleInitweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/NeverAccessedVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssignweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/ReadOnlyVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/UnboundLoopsweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/detectors/ZeroAddressweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/hacking/contributingweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/hacking/custom-detectorweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/hacking/designweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/hacking/souffleweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/hacking/toolsweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/tutorial/ci-cdweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/tutorial/configurationweekly0.5https://nowarp.io/tools/misti/docs/0.2.1/tutorial/getting-startedweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/weekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectorsweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/BranchDuplicateweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/ConstantAddressweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiplyweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/DumpIsUsedweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/FieldDoubleInitweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/NeverAccessedVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssignweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/ReadOnlyVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/UnboundLoopsweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/detectors/ZeroAddressweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/hacking/contributingweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/hacking/custom-detectorweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/hacking/designweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/hacking/souffleweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/hacking/toolsweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/tutorial/blueprintweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/tutorial/ci-cdweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/tutorial/configurationweekly0.5https://nowarp.io/tools/misti/docs/0.2.2/tutorial/getting-startedweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/weekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectorsweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/ArgCopyMutationweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/AsmIsUsedweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/BranchDuplicateweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/ConstantAddressweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiplyweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/DumpIsUsedweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/FieldDoubleInitweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/InheritedStateMutationweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/NeverAccessedVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssignweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/PreferredStdlibApiweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/ReadOnlyVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/StringReceiversOverlapweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/UnboundLoopsweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/detectors/ZeroAddressweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/hacking/contributingweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/hacking/custom-detectorweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/hacking/designweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/hacking/souffleweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/hacking/toolsweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/tutorial/blueprintweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/tutorial/ci-cdweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/tutorial/cliweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/tutorial/configurationweekly0.5https://nowarp.io/tools/misti/docs/0.3.0/tutorial/getting-startedweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/weekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectorsweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/ArgCopyMutationweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/AsmIsUsedweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/BranchDuplicateweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/ConstantAddressweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiplyweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/DumpIsUsedweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/FieldDoubleInitweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/InheritedStateMutationweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/NeverAccessedVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssignweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/PreferredStdlibApiweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/ReadOnlyVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/StringReceiversOverlapweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/UnboundLoopsweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/detectors/ZeroAddressweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/hacking/contributingweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/hacking/custom-detectorweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/hacking/designweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/hacking/souffleweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/hacking/toolsweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/tutorial/blueprintweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/tutorial/ci-cdweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/tutorial/cliweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/tutorial/configurationweekly0.5https://nowarp.io/tools/misti/docs/0.3.1/tutorial/getting-startedweekly0.5https://nowarp.io/tools/misti/docs/next/weekly0.5https://nowarp.io/tools/misti/docs/next/detectorsweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/ArgCopyMutationweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/AsmIsUsedweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/BranchDuplicateweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/ConstantAddressweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/DivideBeforeMultiplyweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/DumpIsUsedweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/DuplicatedConditionweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/EnsurePrgSeedweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/FalseConditionweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/FieldDoubleInitweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/InheritedStateMutationweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/NeverAccessedVariablesweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/OptimalMathFunctionweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/PreferAugmentedAssignweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/PreferredStdlibApiweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/ReadOnlyVariablesweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/StringReceiversOverlapweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/UnboundLoopsweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/UnusedOptionalweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/ZeroAddressweekly0.5https://nowarp.io/tools/misti/docs/next/hacking/contributingweekly0.5https://nowarp.io/tools/misti/docs/next/hacking/custom-detectorweekly0.5https://nowarp.io/tools/misti/docs/next/hacking/designweekly0.5https://nowarp.io/tools/misti/docs/next/hacking/developing-mistiweekly0.5https://nowarp.io/tools/misti/docs/next/hacking/souffleweekly0.5https://nowarp.io/tools/misti/docs/next/toolsweekly0.5https://nowarp.io/tools/misti/docs/next/tools/DumpAstweekly0.5https://nowarp.io/tools/misti/docs/next/tools/DumpCfgweekly0.5https://nowarp.io/tools/misti/docs/next/tools/DumpConfigweekly0.5https://nowarp.io/tools/misti/docs/next/tutorial/blueprintweekly0.5https://nowarp.io/tools/misti/docs/next/tutorial/ci-cdweekly0.5https://nowarp.io/tools/misti/docs/next/tutorial/cliweekly0.5https://nowarp.io/tools/misti/docs/next/tutorial/configurationweekly0.5https://nowarp.io/tools/misti/docs/next/tutorial/getting-startedweekly0.5https://nowarp.io/tools/misti/docs/weekly0.5https://nowarp.io/tools/misti/docs/detectorsweekly0.5https://nowarp.io/tools/misti/docs/detectors/ArgCopyMutationweekly0.5https://nowarp.io/tools/misti/docs/detectors/AsmIsUsedweekly0.5https://nowarp.io/tools/misti/docs/detectors/BranchDuplicateweekly0.5https://nowarp.io/tools/misti/docs/detectors/ConstantAddressweekly0.5https://nowarp.io/tools/misti/docs/detectors/DivideBeforeMultiplyweekly0.5https://nowarp.io/tools/misti/docs/detectors/DumpIsUsedweekly0.5https://nowarp.io/tools/misti/docs/detectors/DuplicatedConditionweekly0.5https://nowarp.io/tools/misti/docs/detectors/EnsurePrgSeedweekly0.5https://nowarp.io/tools/misti/docs/detectors/FalseConditionweekly0.5https://nowarp.io/tools/misti/docs/detectors/FieldDoubleInitweekly0.5https://nowarp.io/tools/misti/docs/detectors/InheritedStateMutationweekly0.5https://nowarp.io/tools/misti/docs/detectors/NeverAccessedVariablesweekly0.5https://nowarp.io/tools/misti/docs/detectors/OptimalMathFunctionweekly0.5https://nowarp.io/tools/misti/docs/detectors/PreferAugmentedAssignweekly0.5https://nowarp.io/tools/misti/docs/detectors/PreferredStdlibApiweekly0.5https://nowarp.io/tools/misti/docs/detectors/ReadOnlyVariablesweekly0.5https://nowarp.io/tools/misti/docs/detectors/StringReceiversOverlapweekly0.5https://nowarp.io/tools/misti/docs/detectors/UnboundLoopsweekly0.5https://nowarp.io/tools/misti/docs/detectors/UnusedOptionalweekly0.5https://nowarp.io/tools/misti/docs/detectors/ZeroAddressweekly0.5https://nowarp.io/tools/misti/docs/hacking/contributingweekly0.5https://nowarp.io/tools/misti/docs/hacking/custom-detectorweekly0.5https://nowarp.io/tools/misti/docs/hacking/designweekly0.5https://nowarp.io/tools/misti/docs/hacking/developing-mistiweekly0.5https://nowarp.io/tools/misti/docs/hacking/souffleweekly0.5https://nowarp.io/tools/misti/docs/toolsweekly0.5https://nowarp.io/tools/misti/docs/tools/DumpAstweekly0.5https://nowarp.io/tools/misti/docs/tools/DumpCfgweekly0.5https://nowarp.io/tools/misti/docs/tools/DumpConfigweekly0.5https://nowarp.io/tools/misti/docs/tutorial/blueprintweekly0.5https://nowarp.io/tools/misti/docs/tutorial/ci-cdweekly0.5https://nowarp.io/tools/misti/docs/tutorial/cliweekly0.5https://nowarp.io/tools/misti/docs/tutorial/configurationweekly0.5https://nowarp.io/tools/misti/docs/tutorial/getting-startedweekly0.5https://nowarp.io/weekly0.5 \ No newline at end of file diff --git a/tools/misti/api/.nojekyll b/tools/misti/api/.nojekyll new file mode 100644 index 000000000..e2ac6616a --- /dev/null +++ b/tools/misti/api/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/tools/misti/api/assets/custom.css b/tools/misti/api/assets/custom.css new file mode 100644 index 000000000..bba952d7d --- /dev/null +++ b/tools/misti/api/assets/custom.css @@ -0,0 +1 @@ +.tsd-navigation,body{background-color:var(--background-color)}:root{--primary-color:#0a3d62;--secondary-color:#34b3f1;--accent-color:#00e6e6;--light-color:#d3d3d3;--background-color:#fff}body{color:var(--primary-color)}a{color:var(--secondary-color)}.tsd-page-title h1{color:var(--accent-color)}.tsd-kind-class,.tsd-kind-enum,.tsd-kind-interface,.tsd-kind-module{border-left:5px solid var(--primary-color)} \ No newline at end of file diff --git a/tools/misti/api/assets/highlight.css b/tools/misti/api/assets/highlight.css new file mode 100644 index 000000000..24ce58c02 --- /dev/null +++ b/tools/misti/api/assets/highlight.css @@ -0,0 +1 @@ +:root{--light-hl-0:#795e26;--dark-hl-0:#dcdcaa;--light-hl-1:#000;--dark-hl-1:#d4d4d4;--light-hl-2:#a31515;--dark-hl-2:#ce9178;--light-code-background:#fff;--dark-code-background:#1e1e1e}:root[data-theme=light]{--hl-0:var(--light-hl-0);--hl-1:var(--light-hl-1);--hl-2:var(--light-hl-2);--code-background:var(--light-code-background)}:root[data-theme=dark]{--hl-0:var(--dark-hl-0);--hl-1:var(--dark-hl-1);--hl-2:var(--dark-hl-2);--code-background:var(--dark-code-background)}.hl-0{color:var(--hl-0)}.hl-1{color:var(--hl-1)}.hl-2{color:var(--hl-2)}code,pre{background:var(--code-background)}@media (prefers-color-scheme:dark){:root{--hl-0:var(--dark-hl-0);--hl-1:var(--dark-hl-1);--hl-2:var(--dark-hl-2);--code-background:var(--dark-code-background)}}@media (prefers-color-scheme:light){:root{--hl-0:var(--light-hl-0);--hl-1:var(--light-hl-1);--hl-2:var(--light-hl-2);--code-background:var(--light-code-background)}} \ No newline at end of file diff --git a/tools/misti/api/assets/icons.js b/tools/misti/api/assets/icons.js new file mode 100644 index 000000000..006f19c20 --- /dev/null +++ b/tools/misti/api/assets/icons.js @@ -0,0 +1 @@ +!function t(){if("loading"===document.readyState)return document.addEventListener("DOMContentLoaded",t);const r=document.body.appendChild(document.createElementNS("http://www.w3.org/2000/svg","svg"));r.innerHTML='""',r.style.display="none","file:"===location.protocol&&document.querySelectorAll("use").forEach((t=>{t.getAttribute("href").includes("#icon-")&&t.setAttribute("href",t.getAttribute("href").replace(/.*#/,"#"))}))}(); \ No newline at end of file diff --git a/tools/misti/api/assets/icons.svg b/tools/misti/api/assets/icons.svg new file mode 100644 index 000000000..e371b8b5d --- /dev/null +++ b/tools/misti/api/assets/icons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tools/misti/api/assets/main.js b/tools/misti/api/assets/main.js new file mode 100644 index 000000000..1cc762ea3 --- /dev/null +++ b/tools/misti/api/assets/main.js @@ -0,0 +1,2 @@ +/*! For license information please see main.js.LICENSE.txt */ +"use strict";window.translations={copy:"Copy",copied:"Copied!",normally_hidden:"This member is normally hidden due to your filter settings."},(()=>{var e,t,r=Object.create,n=Object.defineProperty,i=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,o=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,l=(e=(e,t)=>{!function(){var r,n=function(e){var t=new n.Builder;return t.pipeline.add(n.trimmer,n.stopWordFilter,n.stemmer),t.searchPipeline.add(n.stemmer),e.call(t,t),t.build()};n.version="2.3.9",n.utils={},n.utils.warn=(r=this,function(e){r.console&&console.warn&&console.warn(e)}),n.utils.asString=function(e){return null==e?"":e.toString()},n.utils.clone=function(e){if(null==e)return e;for(var t=Object.create(null),r=Object.keys(e),n=0;n0){var u=n.utils.clone(t)||{};u.position=[a,l],u.index=s.length,s.push(new n.Token(r.slice(a,o),u))}a=o+1}}return s},n.tokenizer.separator=/[\s\-]+/,n.Pipeline=function(){this._stack=[]},n.Pipeline.registeredFunctions=Object.create(null),n.Pipeline.registerFunction=function(e,t){t in this.registeredFunctions&&n.utils.warn("Overwriting existing registered function: "+t),e.label=t,n.Pipeline.registeredFunctions[e.label]=e},n.Pipeline.warnIfFunctionNotRegistered=function(e){e.label&&e.label in this.registeredFunctions||n.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},n.Pipeline.load=function(e){var t=new n.Pipeline;return e.forEach((function(e){var r=n.Pipeline.registeredFunctions[e];if(!r)throw new Error("Cannot load unregistered function: "+e);t.add(r)})),t},n.Pipeline.prototype.add=function(){Array.prototype.slice.call(arguments).forEach((function(e){n.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)}),this)},n.Pipeline.prototype.after=function(e,t){n.Pipeline.warnIfFunctionNotRegistered(t);var r=this._stack.indexOf(e);if(-1==r)throw new Error("Cannot find existingFn");r+=1,this._stack.splice(r,0,t)},n.Pipeline.prototype.before=function(e,t){n.Pipeline.warnIfFunctionNotRegistered(t);var r=this._stack.indexOf(e);if(-1==r)throw new Error("Cannot find existingFn");this._stack.splice(r,0,t)},n.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);-1!=t&&this._stack.splice(t,1)},n.Pipeline.prototype.run=function(e){for(var t=this._stack.length,r=0;r1&&(se&&(r=i),s!=e);)n=r-t,i=t+Math.floor(n/2),s=this.elements[2*i];return s==e||s>e?2*i:sa?u+=2:o==a&&(t+=r[l+1]*n[u+1],l+=2,u+=2);return t},n.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},n.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,r=0;t0){var o,a=s.str.charAt(0);a in s.node.edges?o=s.node.edges[a]:(o=new n.TokenSet,s.node.edges[a]=o),1==s.str.length&&(o.final=!0),i.push({node:o,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(0!=s.editsRemaining){if("*"in s.node.edges)var l=s.node.edges["*"];else l=new n.TokenSet,s.node.edges["*"]=l;if(0==s.str.length&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),1==s.str.length&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var u=s.node.edges["*"];else u=new n.TokenSet,s.node.edges["*"]=u;1==s.str.length&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var c,d=s.str.charAt(0),h=s.str.charAt(1);h in s.node.edges?c=s.node.edges[h]:(c=new n.TokenSet,s.node.edges[h]=c),1==s.str.length&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:d+s.str.slice(2)})}}}return r},n.TokenSet.fromString=function(e){for(var t=new n.TokenSet,r=t,i=0,s=e.length;i=e;t--){var r=this.uncheckedNodes[t],n=r.child.toString();n in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[n]:(r.child._str=n,this.minimizedNodes[n]=r.child),this.uncheckedNodes.pop()}},n.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},n.Index.prototype.search=function(e){return this.query((function(t){new n.QueryParser(e,t).parse()}))},n.Index.prototype.query=function(e){for(var t=new n.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),l=0;l1?1:e},n.Builder.prototype.k1=function(e){this._k1=e},n.Builder.prototype.add=function(e,t){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=t||{},this.documentCount+=1;for(var s=0;s=this.length)return n.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},n.QueryLexer.prototype.width=function(){return this.pos-this.start},n.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},n.QueryLexer.prototype.backup=function(){this.pos-=1},n.QueryLexer.prototype.acceptDigitRun=function(){var e,t;do{t=(e=this.next()).charCodeAt(0)}while(t>47&&t<58);e!=n.QueryLexer.EOS&&this.backup()},n.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(n.QueryLexer.TERM)),e.ignore(),e.more())return n.QueryLexer.lexText},n.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(n.QueryLexer.EDIT_DISTANCE),n.QueryLexer.lexText},n.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(n.QueryLexer.BOOST),n.QueryLexer.lexText},n.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(n.QueryLexer.TERM)},n.QueryLexer.termSeparator=n.tokenizer.separator,n.QueryLexer.lexText=function(e){for(;;){var t=e.next();if(t==n.QueryLexer.EOS)return n.QueryLexer.lexEOS;if(92!=t.charCodeAt(0)){if(":"==t)return n.QueryLexer.lexField;if("~"==t)return e.backup(),e.width()>0&&e.emit(n.QueryLexer.TERM),n.QueryLexer.lexEditDistance;if("^"==t)return e.backup(),e.width()>0&&e.emit(n.QueryLexer.TERM),n.QueryLexer.lexBoost;if("+"==t&&1===e.width()||"-"==t&&1===e.width())return e.emit(n.QueryLexer.PRESENCE),n.QueryLexer.lexText;if(t.match(n.QueryLexer.termSeparator))return n.QueryLexer.lexTerm}else e.escapeCharacter()}},n.QueryParser=function(e,t){this.lexer=new n.QueryLexer(e),this.query=t,this.currentClause={},this.lexemeIdx=0},n.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=n.QueryParser.parseClause;e;)e=e(this);return this.query},n.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},n.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},n.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},n.QueryParser.parseClause=function(e){var t=e.peekLexeme();if(null!=t)switch(t.type){case n.QueryLexer.PRESENCE:return n.QueryParser.parsePresence;case n.QueryLexer.FIELD:return n.QueryParser.parseField;case n.QueryLexer.TERM:return n.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+t.type;throw t.str.length>=1&&(r+=" with value '"+t.str+"'"),new n.QueryParseError(r,t.start,t.end)}},n.QueryParser.parsePresence=function(e){var t=e.consumeLexeme();if(null!=t){switch(t.str){case"-":e.currentClause.presence=n.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=n.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+t.str+"'";throw new n.QueryParseError(r,t.start,t.end)}var i=e.peekLexeme();if(null==i)throw r="expecting term or field, found nothing",new n.QueryParseError(r,t.start,t.end);switch(i.type){case n.QueryLexer.FIELD:return n.QueryParser.parseField;case n.QueryLexer.TERM:return n.QueryParser.parseTerm;default:throw r="expecting term or field, found '"+i.type+"'",new n.QueryParseError(r,i.start,i.end)}}},n.QueryParser.parseField=function(e){var t=e.consumeLexeme();if(null!=t){if(-1==e.query.allFields.indexOf(t.str)){var r=e.query.allFields.map((function(e){return"'"+e+"'"})).join(", "),i="unrecognised field '"+t.str+"', possible fields: "+r;throw new n.QueryParseError(i,t.start,t.end)}e.currentClause.fields=[t.str];var s=e.peekLexeme();if(null==s)throw i="expecting term, found nothing",new n.QueryParseError(i,t.start,t.end);if(s.type===n.QueryLexer.TERM)return n.QueryParser.parseTerm;throw i="expecting term, found '"+s.type+"'",new n.QueryParseError(i,s.start,s.end)}},n.QueryParser.parseTerm=function(e){var t=e.consumeLexeme();if(null!=t){e.currentClause.term=t.str.toLowerCase(),-1!=t.str.indexOf("*")&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(null==r)return void e.nextClause();switch(r.type){case n.QueryLexer.TERM:return e.nextClause(),n.QueryParser.parseTerm;case n.QueryLexer.FIELD:return e.nextClause(),n.QueryParser.parseField;case n.QueryLexer.EDIT_DISTANCE:return n.QueryParser.parseEditDistance;case n.QueryLexer.BOOST:return n.QueryParser.parseBoost;case n.QueryLexer.PRESENCE:return e.nextClause(),n.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new n.QueryParseError(i,r.start,r.end)}}},n.QueryParser.parseEditDistance=function(e){var t=e.consumeLexeme();if(null!=t){var r=parseInt(t.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new n.QueryParseError(i,t.start,t.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(null==s)return void e.nextClause();switch(s.type){case n.QueryLexer.TERM:return e.nextClause(),n.QueryParser.parseTerm;case n.QueryLexer.FIELD:return e.nextClause(),n.QueryParser.parseField;case n.QueryLexer.EDIT_DISTANCE:return n.QueryParser.parseEditDistance;case n.QueryLexer.BOOST:return n.QueryParser.parseBoost;case n.QueryLexer.PRESENCE:return e.nextClause(),n.QueryParser.parsePresence;default:throw i="Unexpected lexeme type '"+s.type+"'",new n.QueryParseError(i,s.start,s.end)}}},n.QueryParser.parseBoost=function(e){var t=e.consumeLexeme();if(null!=t){var r=parseInt(t.str,10);if(isNaN(r)){var i="boost must be numeric";throw new n.QueryParseError(i,t.start,t.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(null==s)return void e.nextClause();switch(s.type){case n.QueryLexer.TERM:return e.nextClause(),n.QueryParser.parseTerm;case n.QueryLexer.FIELD:return e.nextClause(),n.QueryParser.parseField;case n.QueryLexer.EDIT_DISTANCE:return n.QueryParser.parseEditDistance;case n.QueryLexer.BOOST:return n.QueryParser.parseBoost;case n.QueryLexer.PRESENCE:return e.nextClause(),n.QueryParser.parsePresence;default:throw i="Unexpected lexeme type '"+s.type+"'",new n.QueryParseError(i,s.start,s.end)}}},function(r,n){"function"==typeof define&&define.amd?define(n):"object"==typeof e?t.exports=n():r.lunr=n()}(this,(function(){return n}))}()},()=>(t||e((t={exports:{}}).exports,t),t.exports)),u=[];function c(e,t){u.push({selector:t,constructor:e})}var d=(e,t=100)=>{let r;return()=>{clearTimeout(r),r=setTimeout((()=>e()),t)}},h=((e,t,l)=>(l=null!=e?r(o(e)):{},((e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let l of s(t))!a.call(e,l)&&l!==r&&n(e,l,{get:()=>t[l],enumerable:!(o=i(t,l))||o.enumerable});return e})(!t&&e&&e.__esModule?l:n(l,"default",{value:e,enumerable:!0}),e)))(l());async function p(e,t){if(!window.searchData)return;let r=await fetch(window.searchData),n=new Blob([await r.arrayBuffer()]).stream().pipeThrough(new DecompressionStream("gzip")),i=await new Response(n).json();e.data=i,e.index=h.Index.load(i.index),t.classList.remove("loading"),t.classList.add("ready")}function f(e){e.classList.remove("has-focus")}function m(e,t,r){let n=e.querySelector(".current");if(n){let e=n;if(1===r)do{e=e.nextElementSibling??void 0}while(e instanceof HTMLElement&&null==e.offsetParent);else do{e=e.previousElementSibling??void 0}while(e instanceof HTMLElement&&null==e.offsetParent);e?(n.classList.remove("current"),e.classList.add("current")):-1===r&&(n.classList.remove("current"),t.focus())}else n=e.querySelector(1==r?"li:first-child":"li:last-child"),n&&n.classList.add("current")}function y(e,t){if(""===t)return e;let r=e.toLocaleLowerCase(),n=t.toLocaleLowerCase(),i=[],s=0,o=r.indexOf(n);for(;-1!=o;)i.push(v(e.substring(s,o)),`${v(e.substring(o,o+n.length))}`),s=o+n.length,o=r.indexOf(n,s);return i.push(v(e.substring(s))),i.join("")}var g={"&":"&","<":"<",">":">","'":"'",'"':"""};function v(e){return e.replace(/[&<>"'"]/g,(e=>g[e]))}var x=class{constructor(e){this.el=e.el,this.app=e.app}},w="mousedown",E="mousemove",b="mouseup",L={x:0,y:0},k=!1,S=!1,Q=!1,T=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(T?"is-mobile":"not-mobile"),T&&"ontouchstart"in document.documentElement&&(w="touchstart",E="touchmove",b="touchend"),document.addEventListener(w,(e=>{S=!0,Q=!1;let t="touchstart"==w?e.targetTouches[0]:e;L.y=t.pageY||0,L.x=t.pageX||0})),document.addEventListener(E,(e=>{if(S&&!Q){let t="touchstart"==w?e.targetTouches[0]:e,r=L.x-(t.pageX||0),n=L.y-(t.pageY||0);Q=Math.sqrt(r*r+n*n)>10}})),document.addEventListener(b,(()=>{S=!1})),document.addEventListener("click",(e=>{k&&(e.preventDefault(),e.stopImmediatePropagation(),k=!1)}));var P;try{P=localStorage}catch{P={getItem:()=>null,setItem(){}}}var I=P,O=document.head.appendChild(document.createElement("style"));O.dataset.for="filters";var C;function R(e){document.documentElement.dataset.theme=e}async function F(){let e=document.getElementById("tsd-nav-container");if(!e||!window.navigationData)return;let t=await(await fetch(window.navigationData)).arrayBuffer(),r=new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip")),n=await new Response(r).json();(C=e.dataset.base).endsWith("/")||(C+="/"),e.innerHTML="";for(let i of n)D(i,e,[]);window.app.createComponents(e),window.app.showPage(),window.app.ensureActivePageVisible()}function D(e,t,r){let n=t.appendChild(document.createElement("li"));if(e.children){let t=[...r,e.text],i=n.appendChild(document.createElement("details"));i.className=e.class?`${e.class} tsd-accordion`:"tsd-accordion";let s=i.appendChild(document.createElement("summary"));s.className="tsd-accordion-summary",s.dataset.key=t.join("$"),s.innerHTML='',N(e,s);let o=i.appendChild(document.createElement("div"));o.className="tsd-accordion-details";let a=o.appendChild(document.createElement("ul"));a.className="tsd-nested-navigation";for(let r of e.children)D(r,a,t)}else N(e,n,e.class)}function N(e,t,r){if(e.path){let n=t.appendChild(document.createElement("a"));n.href=C+e.path,r&&(n.className=r),location.pathname===n.pathname&&n.classList.add("current"),e.kind&&(n.innerHTML=``),n.appendChild(document.createElement("span")).textContent=e.text}else t.appendChild(document.createElement("span")).textContent=e.text}c(class extends x{constructor(e){super(e),this.className=this.el.dataset.toggle||"",this.el.addEventListener(b,(e=>this.onPointerUp(e))),this.el.addEventListener("click",(e=>e.preventDefault())),document.addEventListener(w,(e=>this.onDocumentPointerDown(e))),document.addEventListener(b,(e=>this.onDocumentPointerUp(e)))}setActive(e){if(this.active==e)return;this.active=e,document.documentElement.classList.toggle("has-"+this.className,e),this.el.classList.toggle("active",e);let t=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(t),setTimeout((()=>document.documentElement.classList.remove(t)),500)}onPointerUp(e){Q||(this.setActive(!0),e.preventDefault())}onDocumentPointerDown(e){if(this.active){if(e.target.closest(".col-sidebar, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(e){if(!Q&&this.active&&e.target.closest(".col-sidebar")){let t=e.target.closest("a");if(t){let e=window.location.href;-1!=e.indexOf("#")&&(e=e.substring(0,e.indexOf("#"))),t.href.substring(0,e.length)==e&&setTimeout((()=>this.setActive(!1)),250)}}}},"a[data-toggle]"),c(class extends x{constructor(e){super(e),this.summary=this.el.querySelector(".tsd-accordion-summary"),this.icon=this.summary.querySelector("svg"),this.key=`tsd-accordion-${this.summary.dataset.key??this.summary.textContent.trim().replace(/\s+/g,"-").toLowerCase()}`;let t=I.getItem(this.key);this.el.open=t?"true"===t:this.el.open,this.el.addEventListener("toggle",(()=>this.update()));let r=this.summary.querySelector("a");r&&r.addEventListener("click",(()=>{location.assign(r.href)})),this.update()}update(){this.icon.style.transform=`rotate(${this.el.open?0:-90}deg)`,I.setItem(this.key,this.el.open.toString())}},".tsd-accordion"),c(class extends x{constructor(e){super(e),this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",(()=>{this.setLocalStorage(this.el.checked)})),this.setLocalStorage(this.fromLocalStorage()),O.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; }\n`,this.app.updateIndexVisibility()}fromLocalStorage(){let e=I.getItem(this.key);return e?"true"===e:this.el.checked}setLocalStorage(e){I.setItem(this.key,e.toString()),this.value=e,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),this.app.filterChanged(),this.app.updateIndexVisibility()}},".tsd-filter-item input[type=checkbox]");var j=document.getElementById("tsd-theme");j&&function(e){let t=I.getItem("tsd-theme")||"os";e.value=t,R(t),e.addEventListener("change",(()=>{I.setItem("tsd-theme",e.value),R(e.value)}))}(j);var _=new class{constructor(){this.alwaysVisibleMember=null,this.createComponents(document.body),this.ensureFocusedElementVisible(),this.listenForCodeCopies(),window.addEventListener("hashchange",(()=>this.ensureFocusedElementVisible())),document.body.style.display||(this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}createComponents(e){u.forEach((t=>{e.querySelectorAll(t.selector).forEach((e=>{e.dataset.hasInstance||(new t.constructor({el:e,app:this}),e.dataset.hasInstance=String(!0))}))}))}filterChanged(){this.ensureFocusedElementVisible()}showPage(){document.body.style.display&&(document.body.style.removeProperty("display"),this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}scrollToHash(){if(location.hash){let e=document.getElementById(location.hash.substring(1));if(!e)return;e.scrollIntoView({behavior:"instant",block:"start"})}}ensureActivePageVisible(){let e=document.querySelector(".tsd-navigation .current"),t=e?.parentElement;for(;t&&!t.classList.contains(".tsd-navigation");)t instanceof HTMLDetailsElement&&(t.open=!0),t=t.parentElement;if(e&&!function(e){let t=e.getBoundingClientRect(),r=Math.max(document.documentElement.clientHeight,window.innerHeight);return!(t.bottom<0||t.top-r>=0)}(e)){let t=e.getBoundingClientRect().top-document.documentElement.clientHeight/4;document.querySelector(".site-menu").scrollTop=t,document.querySelector(".col-sidebar").scrollTop=t}}updateIndexVisibility(){let e=document.querySelector(".tsd-index-content"),t=e?.open;e&&(e.open=!0),document.querySelectorAll(".tsd-index-section").forEach((e=>{e.style.display="block";let t=Array.from(e.querySelectorAll(".tsd-index-link")).every((e=>null==e.offsetParent));e.style.display=t?"none":"block"})),e&&(e.open=t)}ensureFocusedElementVisible(){if(this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null),!location.hash)return;let e=document.getElementById(location.hash.substring(1));if(!e)return;let t=e.parentElement;for(;t&&"SECTION"!==t.tagName;)t=t.parentElement;if(!t)return;let r=null==t.offsetParent,n=t;for(;n!==document.body;)n instanceof HTMLDetailsElement&&(n.open=!0),n=n.parentElement;if(null==t.offsetParent){this.alwaysVisibleMember=t,t.classList.add("always-visible");let e=document.createElement("p");e.classList.add("warning"),e.textContent=window.translations.normally_hidden,t.prepend(e)}r&&e.scrollIntoView()}listenForCodeCopies(){document.querySelectorAll("pre > button").forEach((e=>{let t;e.addEventListener("click",(()=>{e.previousElementSibling instanceof HTMLElement&&navigator.clipboard.writeText(e.previousElementSibling.innerText.trim()),e.textContent=window.translations.copied,e.classList.add("visible"),clearTimeout(t),t=setTimeout((()=>{e.classList.remove("visible"),t=setTimeout((()=>{e.textContent=window.translations.copy}),100)}),1e3)}))}))}};Object.defineProperty(window,"app",{value:_}),function(){let e=document.getElementById("tsd-search");if(!e)return;let t={base:e.dataset.base+"/"},r=document.getElementById("tsd-search-script");e.classList.add("loading"),r&&(r.addEventListener("error",(()=>{e.classList.remove("loading"),e.classList.add("failure")})),r.addEventListener("load",(()=>{p(t,e)})),p(t,e));let n=document.querySelector("#tsd-search input"),i=document.querySelector("#tsd-search .results");if(!n||!i)throw new Error("The input field or the result list wrapper was not found");i.addEventListener("mouseup",(()=>{f(e)})),n.addEventListener("focus",(()=>e.classList.add("has-focus"))),function(e,t,r,n){r.addEventListener("input",d((()=>{!function(e,t,r,n){if(!n.index||!n.data)return;t.textContent="";let i,s=r.value.trim();if(s){let e=s.split(" ").map((e=>e.length?`*${e}*`:"")).join(" ");i=n.index.search(e)}else i=[];for(let o=0;ot.score-e.score));for(let o=0,a=Math.min(10,i.length);o`,a=y(e.name,s);globalThis.DEBUG_SEARCH_WEIGHTS&&(a+=` (score: ${i[o].score.toFixed(2)})`),e.parent&&(a=`\n ${y(e.parent,s)}.${a}`);let l=document.createElement("li");l.classList.value=e.classes??"";let u=document.createElement("a");u.href=n.base+e.url,u.innerHTML=r+a,l.append(u),u.addEventListener("focus",(()=>{t.querySelector(".current")?.classList.remove("current"),l.classList.add("current")})),t.appendChild(l)}}(0,t,r,n)}),200)),r.addEventListener("keydown",(n=>{"Enter"==n.key?function(e,t){let r=e.querySelector(".current");if(r||(r=e.querySelector("li:first-child")),r){let e=r.querySelector("a");e&&(window.location.href=e.href),f(t)}}(t,e):"ArrowUp"==n.key?(m(t,r,-1),n.preventDefault()):"ArrowDown"===n.key&&(m(t,r,1),n.preventDefault())})),document.body.addEventListener("keypress",(e=>{e.altKey||e.ctrlKey||e.metaKey||!r.matches(":focus")&&"/"===e.key&&(e.preventDefault(),r.focus())})),document.body.addEventListener("keyup",(n=>{e.classList.contains("has-focus")&&("Escape"===n.key||!t.matches(":focus-within")&&!r.matches(":focus"))&&(r.blur(),f(e))}))}(e,i,n,t)}(),function(){let e=document.getElementById("tsd-nav-script");e&&(e.addEventListener("load",F),F())}()})(); \ No newline at end of file diff --git a/tools/misti/api/assets/main.js.LICENSE.txt b/tools/misti/api/assets/main.js.LICENSE.txt new file mode 100644 index 000000000..67510dae1 --- /dev/null +++ b/tools/misti/api/assets/main.js.LICENSE.txt @@ -0,0 +1,54 @@ +/*! Bundled license information: + +lunr/lunr.js: + (** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + *) + (*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + *) + (*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + *) +*/ diff --git a/tools/misti/api/assets/navigation.js b/tools/misti/api/assets/navigation.js new file mode 100644 index 000000000..7e5caca20 --- /dev/null +++ b/tools/misti/api/assets/navigation.js @@ -0,0 +1 @@ +window.navigationData="data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/tools/misti/api/assets/search.js b/tools/misti/api/assets/search.js new file mode 100644 index 000000000..172080700 --- /dev/null +++ b/tools/misti/api/assets/search.js @@ -0,0 +1 @@ +window.searchData="data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/tools/misti/api/assets/style.css b/tools/misti/api/assets/style.css new file mode 100644 index 000000000..589d16137 --- /dev/null +++ b/tools/misti/api/assets/style.css @@ -0,0 +1 @@ +.tsd-typography ol,.tsd-typography p,.tsd-typography ul,blockquote,dl,menu,ol,ul{margin:1em 0}.settings-label,.tsd-hierarchy .target,.tsd-page-toolbar a.title{font-weight:700}#tsd-search .field input,#tsd-search .title,.tsd-anchor,.tsd-member,pre{position:relative}#tsd-search .results li.current:not(.no-results),#tsd-search .results li:hover:not(.no-results),#tsd-search.has-focus,.tsd-widget.active{background-color:var(--color-accent)}:root{--light-color-background:#f2f4f8;--light-color-background-secondary:#eff0f1;--light-color-warning-text:#222;--light-color-background-warning:#e6e600;--light-color-icon-background:var(--light-color-background);--light-color-accent:#c5c7c9;--light-color-active-menu-item:var(--light-color-accent);--light-color-text:#222;--light-color-text-aside:#6e6e6e;--light-color-link:#1f70c2;--light-color-focus-outline:#3584e4;--light-color-ts-keyword:#056bd6;--light-color-ts-project:#b111c9;--light-color-ts-module:var(--light-color-ts-project);--light-color-ts-namespace:var(--light-color-ts-project);--light-color-ts-enum:#7e6f15;--light-color-ts-enum-member:var(--light-color-ts-enum);--light-color-ts-variable:#4760ec;--light-color-ts-function:#572be7;--light-color-ts-class:#1f70c2;--light-color-ts-interface:#108024;--light-color-ts-constructor:var(--light-color-ts-class);--light-color-ts-property:var(--light-color-ts-variable);--light-color-ts-method:var(--light-color-ts-function);--light-color-ts-call-signature:var(--light-color-ts-method);--light-color-ts-index-signature:var(--light-color-ts-property);--light-color-ts-constructor-signature:var(--light-color-ts-constructor);--light-color-ts-parameter:var(--light-color-ts-variable);--light-color-ts-type-parameter:#a55c0e;--light-color-ts-accessor:var(--light-color-ts-property);--light-color-ts-get-signature:var(--light-color-ts-accessor);--light-color-ts-set-signature:var(--light-color-ts-accessor);--light-color-ts-type-alias:#d51270;--light-color-document:#000;--light-external-icon:url("data:image/svg+xml;utf8,");--light-color-scheme:light;--dark-color-background:#2b2e33;--dark-color-background-secondary:#1e2024;--dark-color-background-warning:#bebe00;--dark-color-warning-text:#222;--dark-color-icon-background:var(--dark-color-background-secondary);--dark-color-accent:#9096a2;--dark-color-active-menu-item:#5d5d6a;--dark-color-text:#f5f5f5;--dark-color-text-aside:#ddd;--dark-color-link:#00aff4;--dark-color-focus-outline:#4c97f2;--dark-color-ts-keyword:#39f;--dark-color-ts-project:#e358ff;--dark-color-ts-module:var(--dark-color-ts-project);--dark-color-ts-namespace:var(--dark-color-ts-project);--dark-color-ts-enum:#f4d93e;--dark-color-ts-enum-member:var(--dark-color-ts-enum);--dark-color-ts-variable:#798dff;--dark-color-ts-function:#a280ff;--dark-color-ts-class:#8ac4ff;--dark-color-ts-interface:#6cff87;--dark-color-ts-constructor:var(--dark-color-ts-class);--dark-color-ts-property:var(--dark-color-ts-variable);--dark-color-ts-method:var(--dark-color-ts-function);--dark-color-ts-call-signature:var(--dark-color-ts-method);--dark-color-ts-index-signature:var(--dark-color-ts-property);--dark-color-ts-constructor-signature:var(--dark-color-ts-constructor);--dark-color-ts-parameter:var(--dark-color-ts-variable);--dark-color-ts-type-parameter:#e07d13;--dark-color-ts-accessor:var(--dark-color-ts-property);--dark-color-ts-get-signature:var(--dark-color-ts-accessor);--dark-color-ts-set-signature:var(--dark-color-ts-accessor);--dark-color-ts-type-alias:#ff6492;--dark-color-document:#fff;--dark-external-icon:url("data:image/svg+xml;utf8,");--dark-color-scheme:dark}html{color-scheme:var(--color-scheme)}.tsd-kind-icon~span,a.tsd-anchor-link,body{color:var(--color-text)}:root[data-theme=light]{--color-background:var(--light-color-background);--color-background-secondary:var(--light-color-background-secondary);--color-background-warning:var(--light-color-background-warning);--color-warning-text:var(--light-color-warning-text);--color-icon-background:var(--light-color-icon-background);--color-accent:var(--light-color-accent);--color-active-menu-item:var(--light-color-active-menu-item);--color-text:var(--light-color-text);--color-text-aside:var(--light-color-text-aside);--color-link:var(--light-color-link);--color-focus-outline:var(--light-color-focus-outline);--color-ts-keyword:var(--light-color-ts-keyword);--color-ts-module:var(--light-color-ts-module);--color-ts-namespace:var(--light-color-ts-namespace);--color-ts-enum:var(--light-color-ts-enum);--color-ts-enum-member:var(--light-color-ts-enum-member);--color-ts-variable:var(--light-color-ts-variable);--color-ts-function:var(--light-color-ts-function);--color-ts-class:var(--light-color-ts-class);--color-ts-interface:var(--light-color-ts-interface);--color-ts-constructor:var(--light-color-ts-constructor);--color-ts-property:var(--light-color-ts-property);--color-ts-method:var(--light-color-ts-method);--color-ts-call-signature:var(--light-color-ts-call-signature);--color-ts-index-signature:var(--light-color-ts-index-signature);--color-ts-constructor-signature:var(--light-color-ts-constructor-signature);--color-ts-parameter:var(--light-color-ts-parameter);--color-ts-type-parameter:var(--light-color-ts-type-parameter);--color-ts-accessor:var(--light-color-ts-accessor);--color-ts-get-signature:var(--light-color-ts-get-signature);--color-ts-set-signature:var(--light-color-ts-set-signature);--color-ts-type-alias:var(--light-color-ts-type-alias);--color-document:var(--light-color-document);--external-icon:var(--light-external-icon);--color-scheme:var(--light-color-scheme)}:root[data-theme=dark]{--color-background:var(--dark-color-background);--color-background-secondary:var(--dark-color-background-secondary);--color-background-warning:var(--dark-color-background-warning);--color-warning-text:var(--dark-color-warning-text);--color-icon-background:var(--dark-color-icon-background);--color-accent:var(--dark-color-accent);--color-active-menu-item:var(--dark-color-active-menu-item);--color-text:var(--dark-color-text);--color-text-aside:var(--dark-color-text-aside);--color-link:var(--dark-color-link);--color-focus-outline:var(--dark-color-focus-outline);--color-ts-keyword:var(--dark-color-ts-keyword);--color-ts-module:var(--dark-color-ts-module);--color-ts-namespace:var(--dark-color-ts-namespace);--color-ts-enum:var(--dark-color-ts-enum);--color-ts-enum-member:var(--dark-color-ts-enum-member);--color-ts-variable:var(--dark-color-ts-variable);--color-ts-function:var(--dark-color-ts-function);--color-ts-class:var(--dark-color-ts-class);--color-ts-interface:var(--dark-color-ts-interface);--color-ts-constructor:var(--dark-color-ts-constructor);--color-ts-property:var(--dark-color-ts-property);--color-ts-method:var(--dark-color-ts-method);--color-ts-call-signature:var(--dark-color-ts-call-signature);--color-ts-index-signature:var(--dark-color-ts-index-signature);--color-ts-constructor-signature:var(--dark-color-ts-constructor-signature);--color-ts-parameter:var(--dark-color-ts-parameter);--color-ts-type-parameter:var(--dark-color-ts-type-parameter);--color-ts-accessor:var(--dark-color-ts-accessor);--color-ts-get-signature:var(--dark-color-ts-get-signature);--color-ts-set-signature:var(--dark-color-ts-set-signature);--color-ts-type-alias:var(--dark-color-ts-type-alias);--color-document:var(--dark-color-document);--external-icon:var(--dark-external-icon);--color-scheme:var(--dark-color-scheme)}.tsd-accordion-summary:focus-visible svg,:focus-visible{outline:2px solid var(--color-focus-outline)}.always-visible,.always-visible .tsd-signatures{display:inherit!important}h1,h2,h3,h4,h5,h6{line-height:1.2}h1{font-size:1.875rem;margin:.67rem 0}h2{font-size:1.5rem;margin:.83rem 0}h3{font-size:1.25rem;margin:1rem 0}h4{font-size:1.05rem;margin:1.33rem 0}h5{font-size:1rem;margin:1.5rem 0}h6{font-size:.875rem;margin:2.33rem 0}dd{margin:0 0 0 40px}.container{max-width:1700px;padding:0 2rem}footer{border-top:1px solid var(--color-accent);max-height:3.5rem;padding-bottom:1rem;padding-top:1rem}footer>p{margin:0 1em}.container-main{margin:0 auto;min-height:calc(100vh - 97px - 4rem)}@keyframes a{0%{opacity:0}to{opacity:1}}@keyframes b{0%{opacity:1;visibility:visible}to{opacity:0}}@keyframes c{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes d{0%{transform:translate(0);visibility:visible}to{transform:translate(100%)}}body{margin:0;background:var(--color-background);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;font-size:16px}.tsd-signature,code,pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}a{color:var(--color-link);text-decoration:none}#tsd-toolbar-links a:hover,.tsd-breadcrumb a:hover,.tsd-navigation a:hover,.tsd-page-navigation a:hover,.tsd-page-toolbar a.title:hover,a:hover{text-decoration:underline}a.external[target=_blank]{background-image:var(--external-icon);background-position:top 3px right;background-repeat:no-repeat;padding-right:13px}code,pre{border-radius:.8em;font-size:.875rem;margin:0;padding:.2em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word;border:1px solid var(--color-accent);padding:10px}pre code{font-size:100%;padding:0}pre>button{box-sizing:border-box;opacity:0;position:absolute;right:10px;top:10px;transition:opacity .1s}pre:hover>button,pre>button.visible{opacity:1}blockquote{border-left:4px solid gray;padding-left:1em}.tsd-typography{line-height:1.333em}.tsd-typography ul{list-style:square;padding:0 0 0 20px}.tsd-index-panel .tsd-typography h3,.tsd-typography .tsd-index-panel h3,.tsd-typography h4,.tsd-typography h5,.tsd-typography h6{font-size:1em}.tsd-typography h5,.tsd-typography h6{font-weight:400}.tsd-typography table{border:none;border-collapse:collapse}.tsd-typography td,.tsd-typography th{border:1px solid var(--color-accent);padding:6px 13px}#tsd-search .results li:nth-child(2n),.tsd-typography thead,.tsd-typography tr:nth-child(2n){background-color:var(--color-background-secondary)}.tsd-breadcrumb{color:var(--color-text-aside);margin:0;padding:0}.tsd-breadcrumb a{color:var(--color-text-aside);text-decoration:none}.tsd-breadcrumb li{display:inline}.tsd-breadcrumb li:after{content:" / "}.tsd-comment-tags{display:flex;flex-direction:column}dl.tsd-comment-tag-group{align-items:center;display:flex;margin:.5em 0;overflow:hidden}dl.tsd-comment-tag-group dt{display:flex;font-size:.875em;font-weight:400;margin-right:.5em}.tsd-widget.no-caption:before,dl.tsd-comment-tag-group dd,dl.tsd-comment-tag-group p{margin:0}code.tsd-tag{border:.1em solid var(--color-accent);font-size:70%;margin-right:.25em;padding:.25em .4em}h1 code.tsd-tag:first-of-type{margin-left:.25em}dl.tsd-comment-tag-group dd:after,dl.tsd-comment-tag-group dd:before{content:" "}dl.tsd-comment-tag-group dd pre,dl.tsd-comment-tag-group dd:after{clear:both}.tsd-panel.tsd-comment .lead{font-size:1.1em;line-height:1.333em;margin-bottom:2em}#tsd-sidebar-links a:last-of-type,.tsd-panel.tsd-comment .lead:last-child{margin-bottom:0}.tsd-filter-visibility h4{font-size:1rem;margin:0;padding-bottom:.5rem;padding-top:.75rem}.tsd-filter-item:not(:last-child){margin-bottom:.5rem}.tsd-filter-input{align-items:center;cursor:pointer;display:flex;-webkit-user-select:none;user-select:none;width:-moz-fit-content;width:fit-content}.settings-label,.tsd-flag,.tsd-widget{display:inline-block}.tsd-filter-input input[type=checkbox]{cursor:pointer;height:1.5em;opacity:0;position:absolute;width:1.5em}.tsd-filter-input input[type=checkbox]:disabled{pointer-events:none}.tsd-filter-input svg{border-radius:.33em;cursor:pointer;height:1.5em;margin-right:.5em;opacity:.99;width:1.5em}.tsd-filter-input input[type=checkbox]:focus-visible+svg{outline:2px solid var(--color-focus-outline)}.tsd-checkbox-background{fill:var(--color-accent)}input[type=checkbox]:checked~svg .tsd-checkbox-checkmark{stroke:var(--color-text)}.tsd-filter-input input:disabled~svg>.tsd-checkbox-background{fill:var(--color-background);stroke:var(--color-accent);stroke-width:.25rem}.tsd-filter-input input:disabled~svg>.tsd-checkbox-checkmark{stroke:var(--color-accent)}.settings-label{text-transform:uppercase}.tsd-filter-visibility .settings-label{margin:.75rem 0 .5rem}.tsd-theme-toggle .settings-label{margin:.75rem .75rem 0 0}.tsd-hierarchy{list-style:square;margin:0}.tsd-full-hierarchy:not(:last-child){border-bottom:1px solid var(--color-accent);margin-bottom:1em;padding-bottom:1em}.tsd-full-hierarchy,.tsd-full-hierarchy ul{list-style:none;margin:0;padding:0}.tsd-full-hierarchy ul{padding-left:1.5rem}.tsd-full-hierarchy a{align-items:center;color:var(--color-text);display:inline-flex;font-size:1rem;padding:.25rem 0!important}.tsd-index-panel .tsd-index-list{column-gap:1rem;display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:auto;line-height:1.333em;list-style:none;margin:0;overflow:hidden;padding:.25rem 0 0}.tsd-index-panel .tsd-index-list li{-webkit-page-break-inside:avoid;-moz-page-break-inside:avoid;-ms-page-break-inside:avoid;-o-page-break-inside:avoid;page-break-inside:avoid}.tsd-flag{background-color:var(--color-comment-tag);border-radius:4px;color:var(--color-comment-tag-text);font-size:75%;font-weight:400;line-height:1;padding:.25em .4em;text-indent:0}.tsd-anchor{top:-100px}.tsd-member .tsd-anchor+h3{align-items:center;border-bottom:none;display:flex;margin-bottom:0;margin-top:0}.tsd-navigation.settings{margin:1rem 0}.tsd-navigation .tsd-accordion-summary,.tsd-navigation>a{align-items:center;display:flex;width:calc(100% - .25rem)}#tsd-search .results li.state,.tsd-navigation .tsd-nav-link,.tsd-panel:empty,.tsd-widget.menu,.tsd-widget.options{display:none}.tsd-navigation a,.tsd-navigation summary>span,.tsd-page-navigation a{align-items:center;box-sizing:border-box;color:var(--color-text);display:flex;padding:.25rem;text-decoration:none;width:calc(100% - .25rem)}.tsd-navigation a.current,.tsd-page-navigation a.current{background:var(--color-active-menu-item)}.tsd-navigation ul,.tsd-page-navigation ul{list-style:none;margin-bottom:0;margin-top:0;padding:0}.tsd-navigation li,.tsd-page-navigation li{max-width:100%;padding:0}.tsd-nested-navigation{margin-left:3rem}.tsd-nested-navigation>li>details,.tsd-small-nested-navigation>li>details{margin-left:-1.5rem}#tsd-toolbar-links a,.tsd-small-nested-navigation{margin-left:1.5rem}.tsd-page-navigation-section{margin-left:10px}.tsd-page-navigation-section>summary{padding:.25rem}.tsd-page-navigation-section>div{margin-left:20px}.tsd-page-navigation ul{padding-left:1.75rem}#tsd-sidebar-links a{line-height:1.25rem;margin-bottom:.5rem;margin-top:0}a.tsd-index-link{align-items:center;color:var(--color-text);display:inline-flex;font-size:1rem;line-height:1.25rem;padding:.25rem 0!important}.tsd-accordion-summary{list-style-type:none;outline:0}.tsd-accordion-summary::-webkit-details-marker{display:none}.tsd-accordion-summary,.tsd-accordion-summary a{cursor:pointer;-webkit-user-select:none;user-select:none}.tsd-accordion-summary a{width:calc(100% - 1.5rem)}.tsd-accordion-summary>*{margin-bottom:0;margin-top:0;padding-bottom:0;padding-top:0}.tsd-accordion .tsd-accordion-summary>svg{margin-left:.25rem;vertical-align:text-top}.tsd-index-content>:not(:first-child){margin-top:.75rem}.tsd-index-heading{margin-bottom:.75rem;margin-top:1.5rem}.tsd-kind-icon{height:1.25rem;margin-right:.5rem;min-height:1.25rem;min-width:1.25rem;width:1.25rem}.tsd-kind-icon path{transform:scale(1.1);transform-origin:center}.tsd-signature>.tsd-kind-icon{margin-right:.8rem}.tsd-panel{margin-bottom:2.5rem}.tsd-panel.tsd-member{margin-bottom:4rem}.tsd-panel>h1,.tsd-panel>h2,.tsd-panel>h3{margin:1.5rem -1.5rem .75rem;padding:0 1.5rem .75rem}.tsd-panel>h1.tsd-before-signature,.tsd-panel>h2.tsd-before-signature,.tsd-panel>h3.tsd-before-signature{border-bottom:none;margin-bottom:0}.tsd-panel-group,.tsd-panel-group.tsd-index-group,.tsd-panel-group.tsd-index-group details{margin:2rem 0}.tsd-panel-group>.tsd-accordion-summary{margin-bottom:1rem}#tsd-search{transition:background-color .2s}#tsd-search .title{z-index:2}#tsd-search .field{height:100%;left:0;position:absolute;right:2.5rem;top:0}#tsd-search .field input{background:#0000;border:0;box-sizing:border-box;color:var(--color-text);opacity:0;outline:0;padding:0 10px;top:-50px;width:100%;z-index:1}#tsd-search .field label{overflow:hidden;position:absolute;right:-40px}#tsd-search .field input,#tsd-search .title,#tsd-toolbar-links a{transition:opacity .2s}#tsd-search .results{box-shadow:0 0 4px #00000040;list-style:none;margin:0;padding:0;position:absolute;top:40px;visibility:hidden;width:100%}#tsd-search .results li{background-color:var(--color-background);line-height:normal;padding:4px}#tsd-search .results a{align-items:center;box-sizing:border-box;display:flex;padding:.25rem}#tsd-search .results a:before{top:10px}#tsd-search .results span.parent,.tsd-signature-symbol{color:var(--color-text-aside);font-weight:400}#tsd-search.has-focus .field input{opacity:1;top:0}#tsd-search.has-focus #tsd-toolbar-links a,#tsd-search.has-focus .title{opacity:0;z-index:0}#tsd-search.has-focus .results,.tsd-anchor-link:hover>.tsd-anchor-icon svg{visibility:visible}#tsd-search.failure .results li.state.failure,#tsd-search.loading .results li.state.loading{display:block}#tsd-toolbar-links{align-items:center;display:flex;height:100%;justify-content:flex-end;position:absolute;right:2rem;top:0}.tsd-signature{border:1px solid var(--color-accent);font-size:14px;margin:0 0 1rem;overflow-x:auto;padding:1rem .5rem}.tsd-signature-keyword{color:var(--color-ts-keyword);font-weight:400}.tsd-signature-type{font-style:italic;font-weight:400}.tsd-signatures{list-style-type:none;margin:0 0 1em;padding:0}.tsd-signatures .tsd-signature{border-color:var(--color-accent);border-width:1px 0;margin:0;transition:background-color .1s}.tsd-signatures .tsd-index-signature:not(:last-child){margin-bottom:1em}.tsd-description .tsd-signatures .tsd-signature,.tsd-signatures .tsd-index-signature .tsd-signature{border-width:1px}ul.tsd-parameter-list,ul.tsd-type-parameter-list{list-style:square;margin:0;padding-left:20px}ul.tsd-parameter-list>li.tsd-parameter-signature,ul.tsd-type-parameter-list>li.tsd-parameter-signature{list-style:none;margin-left:-20px}ul.tsd-parameter-list h5,ul.tsd-type-parameter-list h5{font-size:16px;margin:1em 0 .5em}.tsd-sources{font-size:.875em;margin-top:1rem}.tsd-sources a{color:var(--color-text-aside);text-decoration:underline}.tsd-sources ul{list-style:none;padding:0}.tsd-page-toolbar{background:var(--color-background-secondary);border-bottom:1px solid var(--color-accent);color:var(--color-text);left:0;position:sticky;top:0;transition:transform .3s ease-in-out;width:100%;z-index:1}.tsd-page-toolbar a{color:var(--color-text);text-decoration:none}.tsd-page-toolbar .tsd-toolbar-contents{display:flex;height:2.5rem;justify-content:space-between;margin:0 auto}.tsd-page-toolbar .table-cell{line-height:40px;position:relative;white-space:nowrap}.tsd-page-toolbar .table-cell:first-child{width:100%}.tsd-page-toolbar .tsd-toolbar-icon{box-sizing:border-box;line-height:0;padding:12px 0}.tsd-widget{cursor:pointer;height:40px;opacity:.8;overflow:hidden;transition:opacity .1s,background-color .2s;vertical-align:bottom}.tsd-widget:hover{opacity:.9}.tsd-widget.active{opacity:1}.tsd-widget.no-caption{width:40px}input[type=checkbox]+.tsd-widget:before{background-position:-120px 0}input[type=checkbox]:checked+.tsd-widget:before{background-position:-160px 0}img{max-width:100%}.tsd-anchor-icon{align-items:center;color:var(--color-text);display:inline-flex;margin-left:.5rem;vertical-align:middle}.tsd-anchor-icon svg{height:1em;visibility:hidden;width:1em}.deprecated{text-decoration:line-through!important}.warning{background:var(--color-background-warning);color:var(--color-warning-text);padding:1rem}.tsd-kind-project{color:var(--color-ts-project)}.tsd-kind-module{color:var(--color-ts-module)}.tsd-kind-namespace{color:var(--color-ts-namespace)}.tsd-kind-enum{color:var(--color-ts-enum)}.tsd-kind-enum-member{color:var(--color-ts-enum-member)}.tsd-kind-variable{color:var(--color-ts-variable)}.tsd-kind-function{color:var(--color-ts-function)}.tsd-kind-class{color:var(--color-ts-class)}.tsd-kind-interface{color:var(--color-ts-interface)}.tsd-kind-constructor{color:var(--color-ts-constructor)}.tsd-kind-property{color:var(--color-ts-property)}.tsd-kind-method{color:var(--color-ts-method)}.tsd-kind-call-signature{color:var(--color-ts-call-signature)}.tsd-kind-index-signature{color:var(--color-ts-index-signature)}.tsd-kind-constructor-signature{color:var(--color-ts-constructor-signature)}.tsd-kind-parameter{color:var(--color-ts-parameter)}.tsd-kind-type-literal{color:var(--color-ts-type-literal)}.tsd-kind-type-parameter{color:var(--color-ts-type-parameter)}.tsd-kind-accessor{color:var(--color-ts-accessor)}.tsd-kind-get-signature{color:var(--color-ts-get-signature)}.tsd-kind-set-signature{color:var(--color-ts-set-signature)}.tsd-kind-type-alias{color:var(--color-ts-type-alias)}*{scrollbar-color:var(--color-accent) var(--color-icon-background);scrollbar-width:thin}::-webkit-scrollbar{width:.75rem}::-webkit-scrollbar-track{background:var(--color-icon-background)}::-webkit-scrollbar-thumb{background-color:var(--color-accent);border:.25rem solid var(--color-icon-background);border-radius:999rem}@media (min-width:770px){.container-main{display:grid;grid-template-areas:"a b";grid-template-columns:minmax(0,1fr) minmax(0,2fr);margin:2rem auto}.col-sidebar{grid-area:a}.col-content{grid-area:b;padding:0 1rem}}@media (min-width:770px) and (max-width:1399px){.col-sidebar{max-height:calc(100vh - 2rem - 42px);overflow:auto;padding-top:1rem;position:sticky;top:42px}.site-menu{margin-top:1rem}}@media (min-width:1200px){.container-main{grid-template-areas:"a b c";grid-template-columns:minmax(0,1fr) minmax(0,2.5fr) minmax(0,20rem)}.col-sidebar{display:contents}.page-menu{grid-area:c;padding-left:1rem}.site-menu{grid-area:a;margin-top:1rem 0}.page-menu,.site-menu{max-height:calc(100vh - 2rem - 42px);overflow:auto;position:sticky;top:42px}}@media (max-width:1024px){.tsd-index-panel .tsd-index-list{grid-template-columns:repeat(2,1fr)}}@media (max-width:769px){.tsd-widget.menu,.tsd-widget.options{display:inline-block}.container-main,.tsd-navigation .tsd-nav-link{display:flex}html .col-content{float:none;max-width:100%;width:100%}html .col-sidebar{overflow-y:auto;position:fixed!important;-webkit-overflow-scrolling:touch;background-color:var(--color-background);bottom:0!important;left:auto!important;padding:1.5rem 1.5rem 0 0;right:0!important;top:0!important;transform:translate(100%);visibility:hidden;width:75vw;z-index:1024}html .col-sidebar>:last-child{padding-bottom:20px}html .overlay{background-color:#000000bf;bottom:0;content:"";display:block;left:0;position:fixed;right:0;top:0;visibility:hidden;z-index:1023}.to-has-menu .overlay{animation:.4s a}.to-has-menu .col-sidebar{animation:.4s c}.from-has-menu .overlay{animation:.4s b}.from-has-menu .col-sidebar{animation:.4s d}.has-menu body{overflow:hidden}.has-menu .overlay{visibility:visible}.has-menu .col-sidebar{display:flex;flex-direction:column;gap:1.5rem;max-height:100vh;padding:1rem 2rem;transform:translate(0);visibility:visible}.has-menu .tsd-navigation{max-height:100%}#tsd-toolbar-links{display:none}}@media (max-width:768px){.tsd-index-panel .tsd-index-list{grid-template-columns:repeat(1,1fr)}}@media (prefers-color-scheme:dark){:root{--color-background:var(--dark-color-background);--color-background-secondary:var(--dark-color-background-secondary);--color-background-warning:var(--dark-color-background-warning);--color-warning-text:var(--dark-color-warning-text);--color-icon-background:var(--dark-color-icon-background);--color-accent:var(--dark-color-accent);--color-active-menu-item:var(--dark-color-active-menu-item);--color-text:var(--dark-color-text);--color-text-aside:var(--dark-color-text-aside);--color-link:var(--dark-color-link);--color-focus-outline:var(--dark-color-focus-outline);--color-ts-keyword:var(--dark-color-ts-keyword);--color-ts-module:var(--dark-color-ts-module);--color-ts-namespace:var(--dark-color-ts-namespace);--color-ts-enum:var(--dark-color-ts-enum);--color-ts-enum-member:var(--dark-color-ts-enum-member);--color-ts-variable:var(--dark-color-ts-variable);--color-ts-function:var(--dark-color-ts-function);--color-ts-class:var(--dark-color-ts-class);--color-ts-interface:var(--dark-color-ts-interface);--color-ts-constructor:var(--dark-color-ts-constructor);--color-ts-property:var(--dark-color-ts-property);--color-ts-method:var(--dark-color-ts-method);--color-ts-call-signature:var(--dark-color-ts-call-signature);--color-ts-index-signature:var(--dark-color-ts-index-signature);--color-ts-constructor-signature:var(--dark-color-ts-constructor-signature);--color-ts-parameter:var(--dark-color-ts-parameter);--color-ts-type-parameter:var(--dark-color-ts-type-parameter);--color-ts-accessor:var(--dark-color-ts-accessor);--color-ts-get-signature:var(--dark-color-ts-get-signature);--color-ts-set-signature:var(--dark-color-ts-set-signature);--color-ts-type-alias:var(--dark-color-ts-type-alias);--color-document:var(--dark-color-document);--external-icon:var(--dark-external-icon);--color-scheme:var(--dark-color-scheme)}}@media (prefers-color-scheme:light){:root{--color-background:var(--light-color-background);--color-background-secondary:var(--light-color-background-secondary);--color-background-warning:var(--light-color-background-warning);--color-warning-text:var(--light-color-warning-text);--color-icon-background:var(--light-color-icon-background);--color-accent:var(--light-color-accent);--color-active-menu-item:var(--light-color-active-menu-item);--color-text:var(--light-color-text);--color-text-aside:var(--light-color-text-aside);--color-link:var(--light-color-link);--color-focus-outline:var(--light-color-focus-outline);--color-ts-keyword:var(--light-color-ts-keyword);--color-ts-module:var(--light-color-ts-module);--color-ts-namespace:var(--light-color-ts-namespace);--color-ts-enum:var(--light-color-ts-enum);--color-ts-enum-member:var(--light-color-ts-enum-member);--color-ts-variable:var(--light-color-ts-variable);--color-ts-function:var(--light-color-ts-function);--color-ts-class:var(--light-color-ts-class);--color-ts-interface:var(--light-color-ts-interface);--color-ts-constructor:var(--light-color-ts-constructor);--color-ts-property:var(--light-color-ts-property);--color-ts-method:var(--light-color-ts-method);--color-ts-call-signature:var(--light-color-ts-call-signature);--color-ts-index-signature:var(--light-color-ts-index-signature);--color-ts-constructor-signature:var(--light-color-ts-constructor-signature);--color-ts-parameter:var(--light-color-ts-parameter);--color-ts-type-parameter:var(--light-color-ts-type-parameter);--color-ts-accessor:var(--light-color-ts-accessor);--color-ts-get-signature:var(--light-color-ts-get-signature);--color-ts-set-signature:var(--light-color-ts-set-signature);--color-ts-type-alias:var(--light-color-ts-type-alias);--color-document:var(--light-color-document);--external-icon:var(--light-external-icon);--color-scheme:var(--light-color-scheme)}} \ No newline at end of file diff --git a/tools/misti/api/classes/cli_driver.Driver.html b/tools/misti/api/classes/cli_driver.Driver.html new file mode 100644 index 000000000..32ee144bb --- /dev/null +++ b/tools/misti/api/classes/cli_driver.Driver.html @@ -0,0 +1,24 @@ +Driver | Misti

Manages the initialization and execution of detectors for analyzing compilation units.

+

Properties

colorizeOutput: boolean
detectors: Detector[] = []
disabledDetectors: Set<string>
minSeverity: Severity

Minimum severity level to report warnings.

+
outputFormat: OutputFormat
outputPath: string
singleContractProjectManager: undefined | SingleContractProjectManager
tactConfigPath: undefined | string
tools: Tool<any>[] = []

Methods

  • Initializes all detectors specified in the configuration including external and built-in detectors.

    +

    Returns Promise<void>

    Error if a detector class cannot be found in the specified module or as a built-in.

    +
  • Initializes all built-in tools specified in the configuration.

    +

    Returns Promise<void>

    Error if a tool cannot be found or initialized.

    +
  • Asynchronously creates a driver initializing all detectors.

    +

    Parameters

    • tactPath: undefined | string

      Path to the Tact project configuration of to a single Tact contract.

      +
    • options: Partial<CLIOptions> = {}

    Returns Promise<Driver>

diff --git a/tools/misti/api/classes/cli_singleContract.SingleContractProjectManager.html b/tools/misti/api/classes/cli_singleContract.SingleContractProjectManager.html new file mode 100644 index 000000000..28e8ef634 --- /dev/null +++ b/tools/misti/api/classes/cli_singleContract.SingleContractProjectManager.html @@ -0,0 +1,11 @@ +SingleContractProjectManager | Misti

Class SingleContractProjectManager

Encapsulates logic of handling single Tact contracts without user-defined configuration.

+

Methods

  • Cleans up the created temporary directory structure. +This method should be called after using this class.

    +

    Returns void

  • Creates a temporary project directory containing the Tact configuration file and contract.

    +

    Parameters

    • copyAll: boolean = true

      If true, copies all .tact and .fc files to the temporary directory; +otherwise, copies only the main contract file.

      +

    Returns string

    Path to the created Tact project configuration.

    +
diff --git a/tools/misti/api/classes/detectors_builtin_argCopyMutation.ArgCopyMutation.html b/tools/misti/api/classes/detectors_builtin_argCopyMutation.ArgCopyMutation.html new file mode 100644 index 000000000..fec270245 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_argCopyMutation.ArgCopyMutation.html @@ -0,0 +1,61 @@ +ArgCopyMutation | Misti

A detector that highlights cases where function argument mutations are ineffective +due to call-by-value semantics in Tact.

+

In Tact, function arguments are passed by value, meaning that any mutations applied +to these arguments will only affect the local copy of the variable within the function. +Such mutations are unobservable outside the function, except for potentially +increasing gas consumption or causing exceptions.

+
fun addEntry(m: map) {
+  m.set(1, 10); // Bad: Mutating the copy
+}
+
+ +

Use instead:

+
fun addEntry() {
+  self.m.set(1, 10); // OK: Changing contract's state
+}
+
+ +

Alternatively, you could redesign the method:

+
fun generateNewValue(): Int {
+  // ... produce new value for the map
+  return self.nextValue + 1;
+}
+
+m.set(self.nextKey, self.generateNewValue()); // OK
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.HIGH

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_asmIsUsed.AsmIsUsed.html b/tools/misti/api/classes/detectors_builtin_asmIsUsed.AsmIsUsed.html new file mode 100644 index 000000000..082a396b9 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_asmIsUsed.AsmIsUsed.html @@ -0,0 +1,43 @@ +AsmIsUsed | Misti

An optional detector that highlights all the asm functions.

+

Using TVM Assembly is a potentially dangerous operation that requires additional +attention from an auditor. This optional detector will highlight all its uses to +assist in contract security audits.

+
// Highlighted: the asm function use should be audited
+asm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE }
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.INFO

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_branchDuplicate.BranchDuplicate.html b/tools/misti/api/classes/detectors_builtin_branchDuplicate.BranchDuplicate.html new file mode 100644 index 000000000..28505815b --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_branchDuplicate.BranchDuplicate.html @@ -0,0 +1,57 @@ +BranchDuplicate | Misti

Detector that reports duplicated code in conditional branches.

+

Duplicated code in branches is bad because it:

+
    +
  1. Reduces Readability: Repetition makes the code harder to understand.
  2. +
  3. Increases Maintenance: Changes must be made in multiple places, risking errors.
  4. +
  5. Signals Poor Design: It suggests missed opportunities for cleaner, more abstract code.
  6. +
+
if (a > 42) {
+  a = 43; // bad: duplicated code
+} else {
+  a = 43;
+}
+
+ +

Use instead:

+
if (a > 42) {
+  a = inc(b); // ok
+} else {
+  a = 43;
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.HIGH

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_cellOverflow.CellOverflow.html b/tools/misti/api/classes/detectors_builtin_cellOverflow.CellOverflow.html new file mode 100644 index 000000000..57a077371 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_cellOverflow.CellOverflow.html @@ -0,0 +1,69 @@ +CellOverflow | Misti

A detector that identifies cell overflow problems.

+

Cell overflow is an issue specific to the TON blockchain. TON stores data in +cells, which are low-level data structures used for serialization and deserialization.

+

The overflow issue occurs when the user attempts to store more data in a cell +than it supports. The current limitation is 1023 bits and 4 references to other +cells. When these limits are exceeded, the contract throws an error with the +exit code 8 during the compute phase.

+
// Bad: storeRef is used more than 4 times
+beginCell()
+  .storeRef(...)
+  .storeAddress(myAddress())
+  .storeRef(...)
+  .storeRef(...)
+  .storeRef(...)
+  .storeRef(...)
+  .endCell()
+
+ +

Use instead:

+
// OK: Fixed after the analyzer highlighted it
+beginCell()
+  .storeRef(...)
+  .storeAddress(myAddress())
+  .storeRef(...)
+  .storeRef(...)
+  .storeRef(...)
+  .endCell()
+
+ +
    +
  1. Cell & Bag of Cells (BoC) | TON Docs
  2. +
  3. TVM Exit codes | TON Docs
  4. +
  5. Cells, Builders and Slices | Tact Docs
  6. +
+

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.CRITICAL

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Executes the detector's logic to check for issues within the provided compilation unit.

    +

    Parameters

    Returns Promise<MistiTactWarning[]>

    List of warnings has highlighted by this detector.

    +
diff --git a/tools/misti/api/classes/detectors_builtin_constantAddress.ConstantAddress.html b/tools/misti/api/classes/detectors_builtin_constantAddress.ConstantAddress.html new file mode 100644 index 000000000..7f9d1a0a3 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_constantAddress.ConstantAddress.html @@ -0,0 +1,60 @@ +ConstantAddress | Misti

An optional detector that highlights all the constant addresses appearing in the source code.

+

Using hardcoded addresses can sometimes indicate poor contract design. +Some constant addresses may need to be set dynamically, e.g., using +contractAddress, or at least have a way to change them at runtime, for +example, when upgrading a contract.

+
contract Main {
+  proxy: Address;
+  init() {
+    // Bad: Constant address highlighted by the analyzer.
+    self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");
+  }
+}
+
+ +

Use instead:

+
contract Main {
+  proxy: Address;
+  init() {
+   let proxy: Proxy = initOf Proxy(myAddress());
+    // OK: Address depends on how the proxy contact has been deployed
+    self.proxy = contractAddress(proxy);
+  }
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.INFO

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_divideBeforeMultiply.DivideBeforeMultiply.html b/tools/misti/api/classes/detectors_builtin_divideBeforeMultiply.DivideBeforeMultiply.html new file mode 100644 index 000000000..316696da9 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_divideBeforeMultiply.DivideBeforeMultiply.html @@ -0,0 +1,66 @@ +DivideBeforeMultiply | Misti

A detector that identifies and corrects instances of division before multiplication to +ensure accurate mathematical operations.

+

Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:

+
    +
  • Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers.
  • +
  • Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations.
  • +
  • Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging.
  • +
+
let a: Int = 10;
+let b: Int = 3;
+let c: Int = 2;
+// Bad: Division before multiplication
+let result: Int = a / b * c;
+
+ +

Use instead:

+
let a: Int = 10;
+let b: Int = 3;
+let c: Int = 2;
+// Correct: Multiplication before division
+let result: Int = a * c / b;
+
+ +

Hierarchy (view full)

Constructors

Properties

severity: Severity = Severity.HIGH

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Creates a Soufflé context with unique name.

    +

    Parameters

    • cu: CompilationUnit
    • docstring: undefined | string | string[] = ...

      A comment introduced on the top of the generated program if ctx.config.souffleVerbose is set.

      +

      It should be used to avoid name clashes in the Soufflé directory when working with multiple projects.

      +

    Returns SouffleContext<SrcInfo>

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_dumpIsUsed.DumpIsUsed.html b/tools/misti/api/classes/detectors_builtin_dumpIsUsed.DumpIsUsed.html new file mode 100644 index 000000000..114ac8885 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_dumpIsUsed.DumpIsUsed.html @@ -0,0 +1,56 @@ +DumpIsUsed | Misti

An optional detector that highlights all the dump debug prints.

+

The dump function is a debug print that shouldn't be in the final code. +Even though the compiler removes it in production, its presence suggests the +developer was debugging something. This can flag areas where issues might exist, +so auditors should take a closer look at these parts of the code.

+
fun test(): Int {
+  // ... other computations
+  let combined: Int = (RANDOM_SEED >> half_shift) &
+                      (MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;
+  dump(combined); // Suspicious: Highlighted by the detector
+}
+
+ +

Use instead:

+
fun test(): Int {
+  // ... other computations
+  let combined: Int = this.seed ^ shift_mask
+  // OK: The code was reviewed and simplified; `dump` was removed
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.INFO

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_duplicatedCondition.DuplicatedCondition.html b/tools/misti/api/classes/detectors_builtin_duplicatedCondition.DuplicatedCondition.html new file mode 100644 index 000000000..3ccb1dfc8 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_duplicatedCondition.DuplicatedCondition.html @@ -0,0 +1,57 @@ +DuplicatedCondition | Misti

A detector that finds duplicated conditions appearing in conditional expressions.

+

Typically, these cases are developer errors caused by copy-pasting code, leading +to unreachable code.

+
fun test(a: Int): Int {
+  if (a < 1) { return 1; }
+  else if (a > 4) { return 2; }
+  // Bad: A developer copy-pasted the condition
+  else if (a > 4) { return 3; }
+  return 4;
+}
+
+ +

Use instead:

+
fun test(a: Int): Int {
+  if (a < 1) { return 1; }
+  else if (a > 4) { return 2; }
+  // OK: Fixed
+  else if (a < x) { return 3; }
+  return 4;
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.HIGH

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_ensurePrgSeed.EnsurePrgSeed.html b/tools/misti/api/classes/detectors_builtin_ensurePrgSeed.EnsurePrgSeed.html new file mode 100644 index 000000000..f6e938551 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_ensurePrgSeed.EnsurePrgSeed.html @@ -0,0 +1,58 @@ +EnsurePrgSeed | Misti

A detector that identifies all calls to nativeRandom and nativeRandomInterval +without a preceding PRG seed initialization.

+

Using nativeRandom or nativeRandomInterval without first initializing the PRG seed via +nativePrepareRandom, nativeRandomize, or nativeRandomizeLt may lead to unintended behavior +or weak random number generation. This detector ensures that PRG seed initialization +is always performed before any use of random functions, enhancing contract security.

+
// Bad: `nativeRandom` is used without prior PRG seed initialization
+fun generateRandomValue(): Int {
+  return nativeRandom()
+}
+
+ +

Use instead:

+
fun test(): Int {
+  nativePrepareRandom();
+}
+
+// OK: PRG has been initialized somewhere in the contract
+fun generateRandomValue(): Int {
+  return nativeRandom()
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.MEDIUM

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_falseCondition.FalseCondition.html b/tools/misti/api/classes/detectors_builtin_falseCondition.FalseCondition.html new file mode 100644 index 000000000..d893ec089 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_falseCondition.FalseCondition.html @@ -0,0 +1,53 @@ +FalseCondition | Misti

A detector that highlights conditions that evaluate to a constant true or false +in if, while, or until statements, and zero iterations in repeat statements.

+

Conditions that always evaluate to a constant true or false are likely the result of a typo +or logic error. Such conditions can lead to unintended behavior, dead code, or incorrect control flow. +This detector helps identify these cases so they can be corrected, improving the code's reliability.

+
const FALSE: Bool = false;
+// Bad: Always false because of operator precedence
+if ((param | value) & FALSE) {
+ // ... never executed
+}
+
+ +

Use instead:

+
const FALSE: Bool = false;
+// OK: Fixed after the analyzer highlighted this
+if (param) {}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.MEDIUM

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_fieldDoubleInit.FieldDoubleInit.html b/tools/misti/api/classes/detectors_builtin_fieldDoubleInit.FieldDoubleInit.html new file mode 100644 index 000000000..b13d3bce0 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_fieldDoubleInit.FieldDoubleInit.html @@ -0,0 +1,54 @@ +FieldDoubleInit | Misti

A detector that highlights cases where a field is initialized both in the +init function and at the point of definition.

+

Double initialization of fields can either be a programmer's mistake or simply +a waste of gas. It is always preferred to initialize values in the field declaration +if they have a compile-time evaluatable default value, or in the init function if +they must be initialized dynamically.

+
contract Test {
+    a: Int = 0; // Bad
+    init(x: Int) { self.a = x }
+}
+
+ +

Use instead:

+
contract Test {
+    a: Int; // Fixed
+    init(x: Int) { self.a = x }
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.MEDIUM

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_inheritedStateMutation.InheritedStateMutation.html b/tools/misti/api/classes/detectors_builtin_inheritedStateMutation.InheritedStateMutation.html new file mode 100644 index 000000000..1d46b604f --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_inheritedStateMutation.InheritedStateMutation.html @@ -0,0 +1,71 @@ +InheritedStateMutation | Misti

An optional detector that highlights all instances where inherited trait variables +are directly modified.

+

Traits should provide setter methods to ensure that invariants related to their +state are preserved. Directly modifying trait variables (e.g., self.traitVar = 42) +can violate these invariants, leading to potential bugs or security vulnerabilities. +This detector warns when such direct modifications occur, prompting further review +by auditors.

+
trait T {
+  balance: Int;
+}
+
+contract C with T {
+  balance: Int = 42;
+  fun updateBalance() {
+    self.balance = 100; // Suspicious: Highlighted by the detector
+  }
+}
+
+ +

Use instead:

+
trait T {
+  balance: Int;
+  fun setBalance(newBalance: Int) {
+    require(newBalance > 0, "balance cannot be negative"); // Invariant check
+    self.balance = newBalance;
+  }
+}
+
+contract C with T {
+  balance: Int = 42;
+  fun updateBalance() {
+    self.setBalance(100); // OK: Invariant preserved
+  }
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.LOW

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_neverAccessedVariables.NeverAccessedVariables.html b/tools/misti/api/classes/detectors_builtin_neverAccessedVariables.NeverAccessedVariables.html new file mode 100644 index 000000000..1b8d97e81 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_neverAccessedVariables.NeverAccessedVariables.html @@ -0,0 +1,67 @@ +NeverAccessedVariables | Misti

A detector that identifies write-only or unused variables, fields and constants.

+

These variables are either assigned but never used in any meaningful computation, +or they are declared and never used at all, which may indicate redundant code +or an incomplete implementation of the intended logic.

+
// Error: the developer forgot to use the constant
+const MAX_SUPPLY: Int = 1000;
+
+fun mint(to: Address, amount: Int) {
+  balances.set(to, balances.get(to)!! + amount);
+  totalSupply += amount;
+}
+
+ +

Use instead:

+
const MAX_SUPPLY: Int = 1000;
+
+fun mint(to: Address, amount: Int) {
+  // OK: Fixed after the analyzer highlighted this warning
+  require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");
+  balances.set(to, balances.get(to)!! + amount);
+  totalSupply += amount;
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

severity: Severity = Severity.MEDIUM

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

diff --git a/tools/misti/api/classes/detectors_builtin_optimalMathFunction.OptimalMathFunction.html b/tools/misti/api/classes/detectors_builtin_optimalMathFunction.OptimalMathFunction.html new file mode 100644 index 000000000..8def252d9 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_optimalMathFunction.OptimalMathFunction.html @@ -0,0 +1,44 @@ +OptimalMathFunction | Misti

A detector that highlights standard library math function calls that have more gas-efficient alternatives.

+

Tact supports log2/pow2 functions, which are more gas-efficient than log(x, 2)/pow(x, 2).

+
log(x, 2);
+
+ +

Use instead:

+
log2(x)
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.LOW

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_preferAugmentedAssign.PreferAugmentedAssign.html b/tools/misti/api/classes/detectors_builtin_preferAugmentedAssign.PreferAugmentedAssign.html new file mode 100644 index 000000000..36344b2ce --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_preferAugmentedAssign.PreferAugmentedAssign.html @@ -0,0 +1,47 @@ +PreferAugmentedAssign | Misti

Detects non-idiomatic statements that can be written using augmented assignment +operators like +=, -=, etc.

+

Using augmented assignment operations improves the readability of the source code +and reduces the risk of mistakes, such as those that occur during copy-pasting +and refactoring code.

+
msgValue = (msgValue - ctx.readForwardFee());
+
+ +

Use instead:

+
msgValue -= ctx.readForwardFee());
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.INFO

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_preferredStdlibApi.PreferredStdlibApi.html b/tools/misti/api/classes/detectors_builtin_preferredStdlibApi.PreferredStdlibApi.html new file mode 100644 index 000000000..338f184be --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_preferredStdlibApi.PreferredStdlibApi.html @@ -0,0 +1,59 @@ +PreferredStdlibApi | Misti

An optional detector that flags the use of advanced functions from the standard library.

+

Auditors should pay extra attention to these functions, as incorrect usage can +lead to subtle bugs. Safer stdlib alternatives should be preferred in the code.

+

Supported functions:

+ +
let pkg: Slice = msg.transfer;
+let _seqno: Int = pkg.loadInt(32);
+let mode: Int = pkg.loadInt(8);
+let body: Cell = pkg.loadRef();
+// Bad: prefer `send` to avoid low-level manipulation of Slice
+nativeSendMessage(body, mode);
+
+ +

Use instead:

+
// Safer: More explicit definition of the send operation
+send(SendParameters{ value: amount,
+                     to: self.owner,
+                     mode: mode,
+                     body: beginCell().endCell() });
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.INFO

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_readOnlyVariables.ReadOnlyVariables.html b/tools/misti/api/classes/detectors_builtin_readOnlyVariables.ReadOnlyVariables.html new file mode 100644 index 000000000..9b71f022e --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_readOnlyVariables.ReadOnlyVariables.html @@ -0,0 +1,70 @@ +ReadOnlyVariables | Misti

A detector that identifies read-only variables and fields.

+

These variables could typically be replaced with constants to optimize performance. +Alternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally.

+
fun calculateFinalPrice(price: Int): Int {
+  // Warning: the developer uses a read-only variable that could be a constant
+  let DISCOUNT_AMOUNT: Int = 10;
+  return price - DISCOUNT_AMOUNT;
+}
+
+ +

Use instead:

+
const DISCOUNT_AMOUNT: Int = 10;
+
+fun calculateFinalPrice(price: Int): Int {
+  // OK: Fixed after the analyzer highlighted this warning
+  return price - DISCOUNT_AMOUNT;
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

severity: Severity = Severity.MEDIUM

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Collects facts based on the IR to populate the Souffle program.

    +

    Parameters

    • cu: CompilationUnit

      The compilation unit containing the CFGs and AST information.

      +
    • ctx: SouffleContext<SrcInfo>

      The Souffle program to which the facts are added.

      +

    Returns void

  • Adds declarations to the Souffle program to represent the properties of variables.

    +

    Parameters

    • ctx: SouffleContext<SrcInfo>

      The Souffle program where the relations are to be added.

      +

    Returns void

  • Creates a Soufflé context with unique name.

    +

    Parameters

    • cu: CompilationUnit
    • docstring: undefined | string | string[] = ...

      A comment introduced on the top of the generated program if ctx.config.souffleVerbose is set.

      +

      It should be used to avoid name clashes in the Soufflé directory when working with multiple projects.

      +

    Returns SouffleContext<SrcInfo>

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_stringReceiversOverlap.StringReceiversOverlap.html b/tools/misti/api/classes/detectors_builtin_stringReceiversOverlap.StringReceiversOverlap.html new file mode 100644 index 000000000..ad25577d1 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_stringReceiversOverlap.StringReceiversOverlap.html @@ -0,0 +1,53 @@ +StringReceiversOverlap | Misti

A detector that finds overlapping messages between general string receivers and string receivers.

+

Constant string receivers and general string receivers can have overlapping messages +in which case the constant string receiver always takes precedence.

+
contract Test {
+  receive("foobar") { throw(1042) }
+  receive(msg: String) {
+    if (msg == "foobar") { throw(1043)  } // Bad: Dead code
+  }
+}
+
+ +

Use instead:

+
contract Test {
+  receive("foobar") { throw(1042) }
+  receive(msg: String) {}
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.HIGH

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

diff --git a/tools/misti/api/classes/detectors_builtin_unboundLoops.UnboundLoops.html b/tools/misti/api/classes/detectors_builtin_unboundLoops.UnboundLoops.html new file mode 100644 index 000000000..25cc41e7e --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_unboundLoops.UnboundLoops.html @@ -0,0 +1,65 @@ +UnboundLoops | Misti

A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.

+

An unbounded loop can be problematic for several reasons:

+
    +
  • Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult.
  • +
  • Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks.
  • +
  • DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability.
  • +
+
let x: Int = 10;
+while (x > 0) {
+  // Bad: x is not changed due looping
+  send(SendParameters{ to: sender(), ... });
+}
+
+ +

Use instead:

+
let x: Int = 10;
+while (x > 0) {
+  send(SendParameters{ to: sender(), ... });
+  x = x - 1;
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

severity: Severity = Severity.HIGH

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Creates a Soufflé context with unique name.

    +

    Parameters

    • cu: CompilationUnit
    • docstring: undefined | string | string[] = ...

      A comment introduced on the top of the generated program if ctx.config.souffleVerbose is set.

      +

      It should be used to avoid name clashes in the Soufflé directory when working with multiple projects.

      +

    Returns SouffleContext<SrcInfo>

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_unusedOptional.UnusedOptional.html b/tools/misti/api/classes/detectors_builtin_unusedOptional.UnusedOptional.html new file mode 100644 index 000000000..48b302846 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_unusedOptional.UnusedOptional.html @@ -0,0 +1,54 @@ +UnusedOptional | Misti

A detector variables and fields with unused optional modifier.

+

Optional is a nullable value that has a special null value indicating the absence +of a value. If a developer creates an optional variable or field, he should leverage +its functionality by accessing the null value somewhere in his code. Otherwise, +the optional type should be removed to simplify and optimize the code.

+
contract Test {
+  a: Int?; // Bad: null value is never accessed
+  init() { self.a = 42; }
+  get fun getA(): Int { return self.a!!; }
+}
+
+ +

Use instead:

+
contract Test {
+  a: Int = 42; // OK: Removed optional
+  get fun getA(): Int { return self.a; }
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.LOW

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_builtin_zeroAddress.ZeroAddress.html b/tools/misti/api/classes/detectors_builtin_zeroAddress.ZeroAddress.html new file mode 100644 index 000000000..eb42f3e94 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_zeroAddress.ZeroAddress.html @@ -0,0 +1,65 @@ +ZeroAddress | Misti

A detector that identifies uses of the zero address.

+

Using the zero address in smart contracts is typically problematic because it can be +exploited as a default or uninitialized address, leading to unintended transfers and +security vulnerabilities. Additionally, operations involving the zero address can +result in loss of funds or tokens, as there is no private key to access this address.

+
contract Proxy {
+  to: Address;
+  init() {
+    // Warning: Insecure usage of zero address as default value
+    self.to = newAddress(0, 0);
+  }
+  fun setAddress(to: Address) {
+    self.to = to
+  }
+}
+
+ +

Use instead:

+
contract Proxy {
+  to: Address;
+  init(to: Address) {
+    // Fixed: Using the input value on initialization.
+    self.to = to;
+  }
+  fun setAddress(to: Address) {
+    self.to = to
+  }
+}
+
+ +

Hierarchy (view full)

Constructors

Properties

Accessors

Methods

Constructors

Properties

severity: Severity = Severity.LOW

Gets the severity of the detector.

+

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_detector.ASTDetector.html b/tools/misti/api/classes/detectors_detector.ASTDetector.html new file mode 100644 index 000000000..1e638db77 --- /dev/null +++ b/tools/misti/api/classes/detectors_detector.ASTDetector.html @@ -0,0 +1,36 @@ +ASTDetector | Misti

Class ASTDetectorAbstract

Abstract class for detectors that identify specific patterns in the AST.

+

Hierarchy (view full)

Constructors

Properties

ctx +

Accessors

Methods

Constructors

Properties

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • A wrapper method that creates Misti warnings with additional context about +the detector generated it.

    +

    Parameters

    • description: string
    • loc: SrcInfo
    • data: Partial<{
          extraDescription: string;
          suggestion: string;
      }> = {}

    Returns MistiTactWarning

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_detector.DataflowDetector.html b/tools/misti/api/classes/detectors_detector.DataflowDetector.html new file mode 100644 index 000000000..8ced15ccf --- /dev/null +++ b/tools/misti/api/classes/detectors_detector.DataflowDetector.html @@ -0,0 +1,36 @@ +DataflowDetector | Misti

Class DataflowDetectorAbstract

Abstract class for dataflow detectors that leverage the Monotone framework and a worklist solver.

+

Hierarchy (view full)

Constructors

Properties

ctx +

Accessors

Methods

Constructors

Properties

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • A wrapper method that creates Misti warnings with additional context about +the detector generated it.

    +

    Parameters

    • description: string
    • loc: SrcInfo
    • data: Partial<{
          extraDescription: string;
          suggestion: string;
      }> = {}

    Returns MistiTactWarning

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_detector.Detector.html b/tools/misti/api/classes/detectors_detector.Detector.html new file mode 100644 index 000000000..b1a6c9076 --- /dev/null +++ b/tools/misti/api/classes/detectors_detector.Detector.html @@ -0,0 +1,36 @@ +Detector | Misti

Class DetectorAbstract

Abstract base class for a detector module, providing an interface for defining various types of detectors.

+

Hierarchy (view full)

Constructors

Properties

ctx +

Accessors

Methods

Constructors

Properties

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • A wrapper method that creates Misti warnings with additional context about +the detector generated it.

    +

    Parameters

    • description: string
    • loc: SrcInfo
    • data: Partial<{
          extraDescription: string;
          suggestion: string;
      }> = {}

    Returns MistiTactWarning

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/detectors_detector.SouffleDetector.html b/tools/misti/api/classes/detectors_detector.SouffleDetector.html new file mode 100644 index 000000000..b70154042 --- /dev/null +++ b/tools/misti/api/classes/detectors_detector.SouffleDetector.html @@ -0,0 +1,44 @@ +SouffleDetector | Misti

Class SouffleDetectorAbstract

Abstract class for Souffle-based detectors that implement Datalog-based analyses.

+

Hierarchy (view full)

Constructors

Properties

Accessors

  • get id(): string
  • Gets the short identifier of the detector, used in analyzer warnings.

    +

    Returns string

    The unique identifier of the detector.

    +
  • get shareImportedWarnings(): WarningsBehavior
  • Defines the behavior of warnings generated by this detector when working with +multiple projects within a single Tact configuration.

    +

    Here are the available options:

    +
      +
    1. "union" +Leave this value if you don't care about warnings generated in other projects.
    2. +
    3. "intersect" +If the warning is generated for some source location of the imported file, +it should be generated by each of the projects. Example: Constants from an +imported file should not be reported iff they are unused in all the projects, +so you need "intersect".
    4. +
    +

    Returns WarningsBehavior

  • get usesSouffle(): boolean
  • Checks whether this detector needs the Soufflé binary to be executed.

    +

    Returns boolean

Methods

  • Creates a Soufflé context with unique name.

    +

    Parameters

    • cu: CompilationUnit
    • docstring: undefined | string | string[] = ...

      A comment introduced on the top of the generated program if ctx.config.souffleVerbose is set.

      +

      It should be used to avoid name clashes in the Soufflé directory when working with multiple projects.

      +

    Returns SouffleContext<SrcInfo>

  • Executes Souffle program for this detector converting output facts to warnings.

    +

    Parameters

    • ctx: SouffleContext<SrcInfo>

      Souffle context with all the declarations, rules and facts added.

      +
    • callback: ((fact: SouffleFact<SrcInfo>) => undefined | MistiTactWarning)

      A function that creates warnings from output facts.

      +

    Returns Promise<MistiTactWarning[]>

  • A wrapper method that creates Misti warnings with additional context about +the detector generated it.

    +

    Parameters

    • description: string
    • loc: SrcInfo
    • data: Partial<{
          extraDescription: string;
          suggestion: string;
      }> = {}

    Returns MistiTactWarning

  • Returns true if the identifier with the given name should not be reported +by unused variables detectors.

    +

    Parameters

    • name: string

    Returns boolean

diff --git a/tools/misti/api/classes/internals_config.MistiConfig.html b/tools/misti/api/classes/internals_config.MistiConfig.html new file mode 100644 index 000000000..5a6078d8f --- /dev/null +++ b/tools/misti/api/classes/internals_config.MistiConfig.html @@ -0,0 +1,12 @@ +MistiConfig | Misti

Represents content of the Misti configuration file (misti.config.json).

+

Constructors

Properties

detectors: DetectorConfig[]
ignoredProjects: string[]
soufflePath: string = "/tmp/misti/souffle"
souffleVerbose?: boolean
suppressions: WarningSuppression[]
tactStdlibPath?: string
tools: ToolConfig[]
unusedPrefix: string
verbosity: "quiet" | "debug" | "default"
diff --git a/tools/misti/api/classes/internals_context.MistiContext.html b/tools/misti/api/classes/internals_context.MistiContext.html new file mode 100644 index 000000000..8641dc2a1 --- /dev/null +++ b/tools/misti/api/classes/internals_context.MistiContext.html @@ -0,0 +1,10 @@ +MistiContext | Misti

Represents the context for a Misti run.

+

Constructors

Properties

config: MistiConfig
logger: Logger
singleContractPath: undefined | string

Path to a single Tact contract if executed without project config.

+
souffleAvailable: boolean

Indicates whether a Souffle binary is available.

+
diff --git a/tools/misti/api/classes/internals_exceptions.ExecutionException.html b/tools/misti/api/classes/internals_exceptions.ExecutionException.html new file mode 100644 index 000000000..1b7e1b19b --- /dev/null +++ b/tools/misti/api/classes/internals_exceptions.ExecutionException.html @@ -0,0 +1,4 @@ +ExecutionException | Misti

An error caused by incorrect actions of the user, such as wrong configuration, +problems in the environment, wrong CLI options.

+

Methods

Methods

  • Parameters

    • msg: string
    • __namedParameters: Partial<{
          loc: SrcInfo;
          node: AstNode;
      }> = {}

    Returns Error

diff --git a/tools/misti/api/classes/internals_exceptions.InternalException.html b/tools/misti/api/classes/internals_exceptions.InternalException.html new file mode 100644 index 000000000..a6ecc3c4d --- /dev/null +++ b/tools/misti/api/classes/internals_exceptions.InternalException.html @@ -0,0 +1,3 @@ +InternalException | Misti

Internal error, typically caused by a bug in Misti or incorrect API usage.

+

Methods

Methods

  • Parameters

    • msg: string
    • __namedParameters: Partial<{
          generateReport: boolean;
          loc: SrcInfo;
          node: unknown;
      }> = {}

    Returns Error

diff --git a/tools/misti/api/classes/internals_exceptions.TactException.html b/tools/misti/api/classes/internals_exceptions.TactException.html new file mode 100644 index 000000000..d7763e58e --- /dev/null +++ b/tools/misti/api/classes/internals_exceptions.TactException.html @@ -0,0 +1,7 @@ +TactException | Misti

Represents all the errors coming from the Tact compiler API.

+

Methods

  • Returns true if stack represents a compilation error.

    +

    Parameters

    • stack: undefined | string

    Returns boolean

  • Returns true if stack represents a syntax error.

    +

    Parameters

    • stack: undefined | string

    Returns boolean

diff --git a/tools/misti/api/classes/internals_ir_astStore.TactASTStore.html b/tools/misti/api/classes/internals_ir_astStore.TactASTStore.html new file mode 100644 index 000000000..28303e33a --- /dev/null +++ b/tools/misti/api/classes/internals_ir_astStore.TactASTStore.html @@ -0,0 +1,116 @@ +TactASTStore | Misti

Provides access to AST elements defined within a single Tact project.

+

The generated AST entries includes all the dependent elements, including imported +code which is included in the project AST in C/C++ style.

+

Constructors

  • Constructs a TactASTStore with mappings to all major AST components accessible +by their unique AST identifiers.

    +

    Parameters

    • stdlibIds: Set<number> = ...

      Identifiers of AST elements defined in stdlib.

      +
    • contractConstants: Set<number> = ...

      Identifiers of constants defined within contracts.

      +
    • programEntries: Set<number>

      Identifiers of AST elements defined on the top-level.

      +
    • functions: Map<number, AstFunctionDef | AstContractInit | AstReceiver>

      Functions and methods including user-defined and special methods.

      +
    • constants: Map<number, AstConstantDef>

      Constants defined across the compilation unit.

      +
    • contracts: Map<number, AstContract>

      Contracts defined within the project.

      +
    • nativeFunctions: Map<number, AstNativeFunctionDecl>

      Functions defined natively (not in user's source code).

      +
    • asmFunctions: Map<number, AstAsmFunctionDef>

      Tact asm functions.

      +
    • primitives: Map<number, AstPrimitiveTypeDecl>

      Primitive types defined in the project.

      +
    • structs: Map<number, AstStructDecl>

      Structs defined in the project.

      +
    • messages: Map<number, AstMessageDecl>

      Messages defined in the project.

      +
    • traits: Map<number, AstTrait>

      Traits defined in the project.

      +
    • statements: Map<number, AstStatement>

      All executable statements within all functions of the project.

      +

    Returns TactASTStore

Methods

  • Retrieves an asm function by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the asm function.

      +

    Returns undefined | AstAsmFunctionDef

    The asm function if found, otherwise undefined.

    +
  • Retrieves a constant by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the constant.

      +

    Returns undefined | AstConstantDef

    The constant if found, otherwise undefined.

    +
  • Returns all the constants defined within the program, including top-level constants +and contract constants.

    +

    Parameters

    • params: Partial<{
          includeContract: boolean;
          includeStdlib: boolean;
      }> = {}

      Additional parameters:

      +
        +
      • includeStdlib: If true, includes constants defined in stdlib.
      • +
      • includeContract: If true, includes constants defined within a contract.
      • +
      +

    Returns IterableIterator<AstConstantDef>

  • Retrieves a contract by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the contract.

      +

    Returns undefined | AstContract

    The contract if found, otherwise undefined.

    +
  • Retrieves the IDs of constants associated with a specified contract.

    +

    Parameters

    • contractId: number

      The ID of the contract.

      +

    Returns undefined | number[]

    An array of constant IDs or undefined if no contract is found.

    +
  • Retrieves fields defined within a specified contract.

    +

    Parameters

    • contractId: number

      The ID of the contract.

      +

    Returns undefined | AstFieldDecl[]

    An array of AstFieldDecl or undefined if no contract is found.

    +
  • Retrieves a function or method by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the function or method.

      +

    Returns
        | undefined
        | AstFunctionDef
        | AstContractInit
        | AstReceiver

    The function or method if found, otherwise undefined.

    +
  • Returns all the functions and methods defined within the program.

    +

    Parameters

    • params: Partial<{
          includeStdlib: boolean;
      }> = {}

      Additional parameters:

      +
        +
      • includeStdlib: If true, includes functions defined in stdlib.
      • +
      +

    Returns IterableIterator<AstFunctionDef | AstContractInit | AstReceiver>

  • Retrieves fields defined in the traits the contract inherited.

    +

    Parameters

    • contractId: number

      The ID of the contract.

      +

    Returns undefined | AstFieldDecl[]

    An array of AstFieldDecl or undefined if no contract or one its trait are found.

    +
  • Retrieves the ID of the initialization function for a specified contract.

    +

    Parameters

    • contractId: number

      The ID of the contract.

      +

    Returns undefined | number

    The ID of the init function or undefined if the contract does not exist.

    +
  • Retrieves a message by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the message.

      +

    Returns undefined | AstMessageDecl

    The message if found, otherwise undefined.

    +
  • Retrieves the IDs of methods for a specified contract which have one of the following types: AstFunctionDef, AstReceiver, AstContractInit.

    +

    Parameters

    • contractId: number

      The ID of the contract.

      +

    Returns undefined | number[]

    An array of method IDs or undefined if no contract is found.

    +
  • Retrieves a native function by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the native function.

      +

    Returns undefined | AstNativeFunctionDecl

    The native function if found, otherwise undefined.

    +
  • Returns IterableIterator<AstNativeFunctionDecl>

  • Retrieves a primitive type by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the primitive type.

      +

    Returns undefined | AstPrimitiveTypeDecl

    The primitive type if found, otherwise undefined.

    +
  • Returns IterableIterator<AstPrimitiveTypeDecl>

  • Returns top-level program entries in order as they defined.

    +

    Parameters

    • includeStdlib: boolean = false

    Returns AstNode[]

  • Retrieves a statement by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the statement.

      +

    Returns undefined | AstStatement

    The statement if found, otherwise undefined.

    +
  • Returns all the statements defined within the program.

    +

    Returns IterableIterator<AstStatement>

  • Retrieves a struct by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the struct.

      +

    Returns undefined | AstStructDecl

    The struct if found, otherwise undefined.

    +
  • Retrieves a trait by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the trait.

      +

    Returns undefined | AstTrait

    The trait if found, otherwise undefined.

    +
diff --git a/tools/misti/api/classes/internals_ir_builders_tactIRBuilder.TactIRBuilder.html b/tools/misti/api/classes/internals_ir_builders_tactIRBuilder.TactIRBuilder.html new file mode 100644 index 000000000..82a00c5ca --- /dev/null +++ b/tools/misti/api/classes/internals_ir_builders_tactIRBuilder.TactIRBuilder.html @@ -0,0 +1,15 @@ +TactIRBuilder | Misti

Represents a stateful object which is responsible for constructing the IR of a Tact project.

+

It creates a one-statement-per-basic-block CFG.

+

Methods

  • Recursively processes an array of AST statements to generate nodes and edges for a CFG.

    +

    Parameters

    • statements: AstStatement[]

      The array of AstStatement objects.

      +
    • bbs: BasicBlock[] = []

      An optional array of basic blocks to which new nodes will be added.

      +
    • edges: Edge[] = []

      An optional array of Edge objects to which new edges will be added.

      +
    • lastBBIdxes: number[] = []

      An optional indices representing from which control flow enters the current sequence of statements.

      +

    Returns [BasicBlock[], Edge[]]

    A tuple containing the arrays of BasicBlock and Edge objects representing the CFG derived from the statements.

    +
diff --git a/tools/misti/api/classes/internals_ir_cfg.BasicBlock.html b/tools/misti/api/classes/internals_ir_cfg.BasicBlock.html new file mode 100644 index 000000000..297f32ece --- /dev/null +++ b/tools/misti/api/classes/internals_ir_cfg.BasicBlock.html @@ -0,0 +1,16 @@ +BasicBlock | Misti

Represents a basic block in a Control Flow Graph (CFG), corresponding to a single +statement in the source code. +Basic blocks are connected by edges that represent the flow of control between statements.

+

The unique identifier of the statement this block represents.

+

Kind of the basic block representing ways it behave.

+

A set of indices for edges incoming to this block, representing control flows leading into this statement.

+

A set of indices for edges outgoing from this block, representing potential control flows out of this statement.

+

Constructors

Properties

Methods

Constructors

Properties

dstEdges: Set<number> = ...
idx: number
srcEdges: Set<number> = ...
stmtID: number

Methods

  • Returns true iff this basic block terminates control flow.

    +

    Returns boolean

diff --git a/tools/misti/api/classes/internals_ir_cfg.CFG.html b/tools/misti/api/classes/internals_ir_cfg.CFG.html new file mode 100644 index 000000000..75c5e990e --- /dev/null +++ b/tools/misti/api/classes/internals_ir_cfg.CFG.html @@ -0,0 +1,53 @@ +CFG | Misti

Describes the intraprocedural control flow graph (CFG) that corresponds to a function or method within the project.

+

Constructors

  • Creates an instance of CFG.

    +

    Parameters

    • name: string

      The name of the function or method this CFG represents.

      +
    • id: number

      AST ID.

      +
    • kind: FunctionKind

      Indicates whether this CFG represents a standalone function or a method or a receive method belonging to a contract.

      +
    • origin: EntryOrigin

      Indicates whether the function was defined in users code or in standard library.

      +
    • nodes: BasicBlock[]

      Map of block indices to basic blocks in the CFG that come in the reverse order.

      +
    • edges: Edge[]

      Map of edge indices to edges in the CFG that come in the reverse order.

      +
    • ref: SrcInfo

      AST reference that corresponds to the function definition.

      +
    • idx: undefined | number = undefined

      An optional unique index. If not set, a new one will be chosen automatically.

      +

    Returns CFG

Properties

edges: Edge[]

Map of edge indices to edges in the CFG that come in the reverse order.

+
id: number

AST ID.

+
idx: number

The unique identifier of this CFG among the compilation unit it belongs to.

+

Indicates whether this CFG represents a standalone function or a method or a receive method belonging to a contract.

+
name: string

The name of the function or method this CFG represents.

+
nodes: BasicBlock[]

Map of block indices to basic blocks in the CFG that come in the reverse order.

+
origin: EntryOrigin

Indicates whether the function was defined in users code or in standard library.

+
ref: SrcInfo

AST reference that corresponds to the function definition.

+

Methods

  • Iterates over all basic blocks in a CFG, applying a callback to each node. +The callback can perform any operation, such as analyzing or transforming the basic block.

    +

    Parameters

    • astStore: TactASTStore

      The store containing the AST nodes.

      +
    • callback: ((stmt: AstStatement, cfgBB: BasicBlock) => void)

      The function to apply to each block.

      +
        • (stmt, cfgBB): void
        • Parameters

          Returns void

    Returns void

  • Iterates over all edges in a CFG, applying a callback to each edge.

    +

    Parameters

    • callback: ((cfgEdge: Edge) => void)

      The function to apply to each edge.

      +
        • (cfgEdge): void
        • Parameters

          Returns void

    Returns void

  • Retrieves a basic block from the CFG based on its unique index.

    +

    Parameters

    • idx: number

      The index of the basic block to retrieve.

      +

    Returns undefined | BasicBlock

    The basic block if found, otherwise undefined.

    +
  • Retrieves an Edge from the CFG based on its unique index.

    +

    Parameters

    • idx: number

      The index of the edge to retrieve.

      +

    Returns undefined | Edge

    The Edge if found, otherwise undefined.

    +
  • Returns predecessors for the given block.

    +

    Parameters

    • bbIdx: number

    Returns undefined | BasicBlock[]

    A list of predecessor blocks or undefined if any of the indices cannot be found in this CFG.

    +
  • Returns successors for the given block.

    +

    Parameters

    • bbIdx: number

    Returns undefined | BasicBlock[]

    A list of predecessor blocks or undefined if any of the indices cannot be found in this CFG.

    +
diff --git a/tools/misti/api/classes/internals_ir_cfg.Edge.html b/tools/misti/api/classes/internals_ir_cfg.Edge.html new file mode 100644 index 000000000..c14cd0f2d --- /dev/null +++ b/tools/misti/api/classes/internals_ir_cfg.Edge.html @@ -0,0 +1,9 @@ +Edge | Misti

Represents an edge in a Control Flow Graph (CFG), connecting two basic blocks. +Each edge signifies a potential flow of control from one statement to another.

+

The index of the source block from which the control flow originates.

+

The index of the destination block to which the control flow goes.

+

Constructors

Properties

dst +idx +src +

Constructors

Properties

dst: number
idx: number
src: number
diff --git a/tools/misti/api/classes/internals_ir_ir.CompilationUnit.html b/tools/misti/api/classes/internals_ir_ir.CompilationUnit.html new file mode 100644 index 000000000..7f86613fb --- /dev/null +++ b/tools/misti/api/classes/internals_ir_ir.CompilationUnit.html @@ -0,0 +1,40 @@ +CompilationUnit | Misti

Represents a Compilation Unit, encapsulating the information necessary for +analyzing a single Tact project.

+

Constructors

  • Creates an instance of CompilationUnit.

    +

    Parameters

    • projectName: string

      The name of the project this Compilation Unit belongs to.

      +
    • ast: TactASTStore

      The AST of the project.

      +
    • functions: Map<number, CFG>

      A mapping from unique IDs of free functions to their CFGs.

      +
    • contracts: Map<number, Contract>

      A mapping from unique IDs of contract entries to contracts.

      +

    Returns CompilationUnit

Properties

The AST of the project.

+
contracts: Map<number, Contract>

A mapping from unique IDs of contract entries to contracts.

+
functions: Map<number, CFG>

A mapping from unique IDs of free functions to their CFGs.

+
projectName: string

The name of the project this Compilation Unit belongs to.

+

Methods

  • Looks for a CFG with a specific index.

    +

    Parameters

    • idx: number

    Returns undefined | CFG

    Found CFG or undefined if not found.

    +
  • Looks for a CFG for a function node with a specific name.

    +

    Parameters

    • name: string

    Returns undefined | CFG

    Found CFG or undefined if not found.

    +
  • Looks for a CFG for a method node with a specific name.

    +

    Parameters

    • contractName: string
    • methodName: string

    Returns undefined | CFG

    Found CFG or undefined if not found.

    +
  • Performs a fold operation over all CFGs in the Compilation Unit.

    +

    Type Parameters

    • T

    Parameters

    • init: T

      The initial value of the accumulator.

      +
    • callback: ((acc: T, cfg: CFG) => T)

      A function that takes the current accumulator and a CFG, +and returns a new accumulator value.

      +
        • (acc, cfg): T
        • Parameters

          Returns T

    Returns T

    The final accumulated value.

    +
  • Iterates over all CFGs in a Compilation Unit, and applies a callback to each +basic block in every CFG.

    +

    Parameters

    • astStore: TactASTStore

      The store containing the AST nodes.

      +
    • callback: ((cfg: CFG, node: BasicBlock, stmt: AstStatement) => void)

      The function to apply to each BB within each CFG.

      +
        • (cfg, node, stmt): void
        • Parameters

          Returns void

    Returns void

  • Iterates over all CFGs in a Compilation Unit, and applies a callback to CFG.

    +

    Parameters

    • callback: ((cfg: CFG) => void)

      The function to apply to each CFG.

      +
        • (cfg): void
        • Parameters

          Returns void

    • __namedParameters: Partial<{
          includeStdlib: boolean;
      }> = {}

    Returns void

diff --git a/tools/misti/api/classes/internals_ir_ir.Contract.html b/tools/misti/api/classes/internals_ir_ir.Contract.html new file mode 100644 index 000000000..6bd6d4bc5 --- /dev/null +++ b/tools/misti/api/classes/internals_ir_ir.Contract.html @@ -0,0 +1,17 @@ +Contract | Misti

Represents an entry for a contract in the compilation unit which +encapsulates a collection of related methods and their configurations.

+

Constructors

Properties

Constructors

  • Creates an instance of Contract.

    +

    Parameters

    • name: string

      The unique name identifying this contract within the project.

      +
    • methods: Map<number, CFG>

      A mapping of method ids to their CFGs.

      +
    • ref: SrcInfo

      AST reference that corresponds to the contract definition.

      +
    • idx: undefined | number = undefined

      An optional unique index. If not set, a new one will be chosen automatically.

      +

    Returns Contract

Properties

idx: number

The unique identifier of this Contract among the compilation unit it belongs to.

+
methods: Map<number, CFG>

A mapping of method ids to their CFGs.

+
name: string

The unique name identifying this contract within the project.

+
ref: SrcInfo

AST reference that corresponds to the contract definition.

+
diff --git a/tools/misti/api/classes/internals_lattice.SetJoinSemilattice.html b/tools/misti/api/classes/internals_lattice.SetJoinSemilattice.html new file mode 100644 index 000000000..6bb55da71 --- /dev/null +++ b/tools/misti/api/classes/internals_lattice.SetJoinSemilattice.html @@ -0,0 +1,17 @@ +SetJoinSemilattice | Misti

Class SetJoinSemilattice<T>

Implementation of a join semilattice for sets, providing methods to establish a partial order relation.

+

Type Parameters

  • T

    The type of elements in the sets.

    +

Implements

Constructors

Methods

Constructors

Methods

  • Joins two elements of the semilattice, returning the least upper bound (lub) of the two elements.

    +

    Parameters

    • a: Set<T>

      First element to join.

      +
    • b: Set<T>

      Second element to join.

      +

    Returns Set<T>

    The joined value, representing the combination of a and b.

    +
  • Determines if one element in the semilattice is less than or equal to another element. +This is crucial for determining if the analysis has reached a fixpoint.

    +

    Parameters

    • a: Set<T>

      The element to be compared.

      +
    • b: Set<T>

      The element to compare against.

      +

    Returns boolean

    true if a is less than or equal to b, otherwise false.

    +
diff --git a/tools/misti/api/classes/internals_lattice.SetMeetSemilattice.html b/tools/misti/api/classes/internals_lattice.SetMeetSemilattice.html new file mode 100644 index 000000000..446c3df66 --- /dev/null +++ b/tools/misti/api/classes/internals_lattice.SetMeetSemilattice.html @@ -0,0 +1,17 @@ +SetMeetSemilattice | Misti

Class SetMeetSemilattice<T>

Implementation of a meet semilattice for sets, providing methods to establish a partial order relation.

+

Type Parameters

  • T

    The type of elements in the sets.

    +

Implements

Constructors

Methods

Constructors

Methods

  • Determines if one element in the semilattice is less than or equal to another element. +This is crucial for determining if the analysis has reached a fixpoint.

    +

    Parameters

    • a: Set<T>

      The element to be compared.

      +
    • b: Set<T>

      The element to compare against.

      +

    Returns boolean

    true if a is less than or equal to b, otherwise false.

    +
  • Meets two elements of the semilattice, returning the greatest lower bound (glb) of the two elements.

    +

    Parameters

    • a: Set<T>

      First element to meet.

      +
    • b: Set<T>

      Second element to meet.

      +

    Returns Set<T>

    The met value, representing the combination of a and b.

    +
diff --git a/tools/misti/api/classes/internals_logger.DebugLogger.html b/tools/misti/api/classes/internals_logger.DebugLogger.html new file mode 100644 index 000000000..5bb556f92 --- /dev/null +++ b/tools/misti/api/classes/internals_logger.DebugLogger.html @@ -0,0 +1,11 @@ +DebugLogger | Misti

Logger that enables debug level logging to stdin.

+

Hierarchy (view full)

Constructors

Methods

Constructors

Methods

  • Logs a message at the specified log level if a corresponding log function is defined.

    +

    Parameters

    • level: LogLevel

      The severity level of the log entry.

      +
    • msg: MessageType

      The content of the log message.

      +

    Returns void

diff --git a/tools/misti/api/classes/internals_logger.Logger.html b/tools/misti/api/classes/internals_logger.Logger.html new file mode 100644 index 000000000..4602c8e87 --- /dev/null +++ b/tools/misti/api/classes/internals_logger.Logger.html @@ -0,0 +1,13 @@ +Logger | Misti

Provides a customizable logging mechanism across different levels of verbosity.

+

Hierarchy (view full)

Implements

  • ILogger

Constructors

Methods

Constructors

  • Initializes logging functions for each log level, optionally overridden by provided mappings.

    +

    Parameters

    • OptionallogMapping: Partial<Record<LogLevel, undefined | LogFunction>>

      Optional mappings to override default log functions per level.

      +

    Returns Logger

Methods

  • Parameters

    • msg: MessageType

    Returns void

  • Parameters

    • msg: MessageType

    Returns void

  • Parameters

    • msg: MessageType

    Returns void

  • Logs a message at the specified log level if a corresponding log function is defined.

    +

    Parameters

    • level: LogLevel

      The severity level of the log entry.

      +
    • msg: MessageType

      The content of the log message.

      +

    Returns void

  • Parameters

    • msg: MessageType

    Returns void

diff --git a/tools/misti/api/classes/internals_logger.QuietLogger.html b/tools/misti/api/classes/internals_logger.QuietLogger.html new file mode 100644 index 000000000..de373de96 --- /dev/null +++ b/tools/misti/api/classes/internals_logger.QuietLogger.html @@ -0,0 +1,11 @@ +QuietLogger | Misti

Logger that silences all logs.

+

Hierarchy (view full)

Constructors

Methods

Constructors

Methods

  • Logs a message at the specified log level if a corresponding log function is defined.

    +

    Parameters

    • level: LogLevel

      The severity level of the log entry.

      +
    • msg: MessageType

      The content of the log message.

      +

    Returns void

diff --git a/tools/misti/api/classes/internals_logger.TraceLogger.html b/tools/misti/api/classes/internals_logger.TraceLogger.html new file mode 100644 index 000000000..4b248063a --- /dev/null +++ b/tools/misti/api/classes/internals_logger.TraceLogger.html @@ -0,0 +1,11 @@ +TraceLogger | Misti

Logger that adds backtraces to each log function.

+

Hierarchy (view full)

Constructors

Methods

Constructors

Methods

  • Logs a message at the specified log level if a corresponding log function is defined.

    +

    Parameters

    • level: LogLevel

      The severity level of the log entry.

      +
    • msg: MessageType

      The content of the log message.

      +

    Returns void

diff --git a/tools/misti/api/classes/internals_solver_results.SolverResults.html b/tools/misti/api/classes/internals_solver_results.SolverResults.html new file mode 100644 index 000000000..24ee7591a --- /dev/null +++ b/tools/misti/api/classes/internals_solver_results.SolverResults.html @@ -0,0 +1,7 @@ +SolverResults | Misti

Results of solving a generic dataflow problem.

+

Type Parameters

  • State

    The type representing the state in the dataflow analysis.

    +

Constructors

Methods

Constructors

Methods

diff --git a/tools/misti/api/classes/internals_solver_souffle.SouffleSolver.html b/tools/misti/api/classes/internals_solver_souffle.SouffleSolver.html new file mode 100644 index 000000000..b650569ce --- /dev/null +++ b/tools/misti/api/classes/internals_solver_souffle.SouffleSolver.html @@ -0,0 +1,8 @@ +SouffleSolver | Misti

Provides a framework for solving dataflow analysis problems using the Soufflé solver.

+

Type Parameters

  • State

Implements

Constructors

Methods

Constructors

Methods

diff --git a/tools/misti/api/classes/internals_solver_worklist.WorklistSolver.html b/tools/misti/api/classes/internals_solver_worklist.WorklistSolver.html new file mode 100644 index 000000000..bcd6f9b54 --- /dev/null +++ b/tools/misti/api/classes/internals_solver_worklist.WorklistSolver.html @@ -0,0 +1,11 @@ +WorklistSolver | Misti

Provides a framework for solving dataflow analysis problems by employing a worklist-based algorithm.

+

This class encapsulates the control flow graph (CFG), node state transformations, +and lattice properties necessary for the computation of fixpoints in dataflow equations.

+

Type Parameters

  • State

Implements

Constructors

Methods

Constructors

Methods

diff --git a/tools/misti/api/classes/internals_tact_util.SrcInfoSet.html b/tools/misti/api/classes/internals_tact_util.SrcInfoSet.html new file mode 100644 index 000000000..01a91dc07 --- /dev/null +++ b/tools/misti/api/classes/internals_tact_util.SrcInfoSet.html @@ -0,0 +1,8 @@ +SrcInfoSet | Misti

Set containing information about the locations with some additional information. +We need this, since SrcInfo objects cannot be trivially compared.

+

Type Parameters

  • T

Constructors

Methods

Constructors

Methods

diff --git a/tools/misti/api/classes/internals_warnings.MistiTactWarning.html b/tools/misti/api/classes/internals_warnings.MistiTactWarning.html new file mode 100644 index 000000000..336512cc6 --- /dev/null +++ b/tools/misti/api/classes/internals_warnings.MistiTactWarning.html @@ -0,0 +1,22 @@ +MistiTactWarning | Misti

Misti warning that highlights a specific place in a Tact contract.

+

Constructors

Properties

Methods

Constructors

Properties

detectorId: string

Unique identifier of the detector raised that warning.

+
loc: SrcInfo
msg: string
severity: Severity

Methods

  • Constructs a warning object with a description and the source code location.

    +

    Parameters

    • ctx: MistiContext
    • detectorId: string

      Unique identifier of the detector.

      +
    • description: string

      Descriptive text of the warning.

      +
    • severity: Severity

      Severity of the finding.

      +
    • loc: SrcInfo

      Reference to the source code that includes file information and position data.

      +
    • data: Partial<{
          docURL: string;
          extraDescription: string;
          suggestion: string;
      }> = {}

      Additional optional data for the warning, including:

      +
        +
      • extraDescription: More comprehensive description that clarifies the warning in greater detail.
      • +
      • docURL: URL to the detector documentation.
      • +
      • suggestion: Suggested change in the source code.
      • +
      +

    Returns MistiTactWarning

    A new MistiTactWarning containing the warning message and source code reference.

    +
diff --git a/tools/misti/api/classes/tools_dumpAst.DumpAst.html b/tools/misti/api/classes/tools_dumpAst.DumpAst.html new file mode 100644 index 000000000..6a08b7891 --- /dev/null +++ b/tools/misti/api/classes/tools_dumpAst.DumpAst.html @@ -0,0 +1,20 @@ +DumpAst | Misti

A tool that dumps the AST of the given compilation unit.

+

Hierarchy (view full)

  • Tool<DumpAstOptions>
    • DumpAst

Constructors

Properties

options: DumpAstOptions

User-defined options for the tool merged with the default options.

+

Accessors

  • get defaultOptions(): DumpAstOptions
  • The default options for the tool.

    +

    Returns DumpAstOptions

  • get id(): string
  • The unique identifier of the tool.

    +

    Returns string

Methods

  • Returns a map of option names to their descriptions.

    +

    Returns Record<keyof DumpAstOptions, string>

diff --git a/tools/misti/api/classes/tools_dumpCfg.DumpCfg.html b/tools/misti/api/classes/tools_dumpCfg.DumpCfg.html new file mode 100644 index 000000000..7964b5719 --- /dev/null +++ b/tools/misti/api/classes/tools_dumpCfg.DumpCfg.html @@ -0,0 +1,20 @@ +DumpCfg | Misti

A tool that dumps the CFG of the given compilation unit.

+

Hierarchy (view full)

  • Tool<DumpCfgOptions>
    • DumpCfg

Constructors

Properties

options: DumpCfgOptions

User-defined options for the tool merged with the default options.

+

Accessors

  • get defaultOptions(): DumpCfgOptions
  • The default options for the tool.

    +

    Returns DumpCfgOptions

  • get id(): string
  • The unique identifier of the tool.

    +

    Returns string

Methods

  • Returns a map of option names to their descriptions.

    +

    Returns Record<keyof DumpCfgOptions, string>

diff --git a/tools/misti/api/classes/tools_dumpConfig.DumpConfig.html b/tools/misti/api/classes/tools_dumpConfig.DumpConfig.html new file mode 100644 index 000000000..775ae87cb --- /dev/null +++ b/tools/misti/api/classes/tools_dumpConfig.DumpConfig.html @@ -0,0 +1,20 @@ +DumpConfig | Misti

A tool that dumps the Misti configuration file in use.

+

Hierarchy (view full)

  • Tool<DumpConfigOptions>
    • DumpConfig

Constructors

Properties

options: DumpConfigOptions

User-defined options for the tool merged with the default options.

+

Accessors

  • get defaultOptions(): DumpConfigOptions
  • The default options for the tool.

    +

    Returns DumpConfigOptions

  • get id(): string
  • The unique identifier of the tool.

    +

    Returns string

Methods

diff --git a/tools/misti/api/classes/tools_tool.Tool.html b/tools/misti/api/classes/tools_tool.Tool.html new file mode 100644 index 000000000..ff64ca107 --- /dev/null +++ b/tools/misti/api/classes/tools_tool.Tool.html @@ -0,0 +1,20 @@ +Tool | Misti

Class Tool<T>Abstract

A tool that can be used to extend the functionality of Misti.

+

Type Parameters

  • T extends Record<string, unknown>

Hierarchy (view full)

Constructors

Properties

options: T

User-defined options for the tool merged with the default options.

+

Accessors

  • get defaultOptions(): T
  • The default options for the tool.

    +

    Returns T

  • get id(): string
  • The unique identifier of the tool.

    +

    Returns string

Methods

  • Returns a description of the tool and its options.

    +

    Returns string

  • Returns a map of option names to their descriptions.

    +

    Returns Record<keyof T, string>

diff --git a/tools/misti/api/enums/cli_types.ExitCode.html b/tools/misti/api/enums/cli_types.ExitCode.html new file mode 100644 index 000000000..e5c9e4a45 --- /dev/null +++ b/tools/misti/api/enums/cli_types.ExitCode.html @@ -0,0 +1,8 @@ +ExitCode | Misti

Enumeration ExitCode

Exit codes after executing Misti.

+

Enumeration Members

Enumeration Members

EXECUTION_FAILURE: 2

Execution failed because of an error.

+
SUCCESS: 0

Successful execution. No warnings or errors reported.

+
WARNINGS: 1

Warnings were reported.

+
diff --git a/tools/misti/api/enums/internals_logger.LogLevel.html b/tools/misti/api/enums/internals_logger.LogLevel.html new file mode 100644 index 000000000..02bc81499 --- /dev/null +++ b/tools/misti/api/enums/internals_logger.LogLevel.html @@ -0,0 +1,5 @@ +LogLevel | Misti

Enumeration LogLevel

Enumeration Members

Enumeration Members

DEBUG: 0
ERROR: 3
INFO: 1
WARN: 2
diff --git a/tools/misti/api/enums/internals_warnings.Severity.html b/tools/misti/api/enums/internals_warnings.Severity.html new file mode 100644 index 000000000..fec081b3f --- /dev/null +++ b/tools/misti/api/enums/internals_warnings.Severity.html @@ -0,0 +1,7 @@ +Severity | Misti

Enumerates the levels of severity that can be assigned to detected findings.

+

Enumeration Members

Enumeration Members

CRITICAL: 5
HIGH: 4
INFO: 1
LOW: 2
MEDIUM: 3
diff --git a/tools/misti/api/functions/cli_cli.createMistiCommand.html b/tools/misti/api/functions/cli_cli.createMistiCommand.html new file mode 100644 index 000000000..1e8baf190 --- /dev/null +++ b/tools/misti/api/functions/cli_cli.createMistiCommand.html @@ -0,0 +1,3 @@ +createMistiCommand | Misti

Function createMistiCommand

  • Creates and configures the Misti CLI command.

    +

    Returns Command

    The configured commander Command instance.

    +
diff --git a/tools/misti/api/functions/cli_cli.executeMisti.html b/tools/misti/api/functions/cli_cli.executeMisti.html new file mode 100644 index 000000000..7e4d4d2ab --- /dev/null +++ b/tools/misti/api/functions/cli_cli.executeMisti.html @@ -0,0 +1,4 @@ +executeMisti | Misti

Function executeMisti

  • Executes Misti capturing the output and returning it as a string.

    +

    Parameters

    • args: string[]

      The list of arguments to pass to the CLI command.

      +

    Returns Promise<string>

    The output of the Misti command as a string.

    +
diff --git a/tools/misti/api/functions/cli_cli.handleMistiResult.html b/tools/misti/api/functions/cli_cli.handleMistiResult.html new file mode 100644 index 000000000..740fa7fca --- /dev/null +++ b/tools/misti/api/functions/cli_cli.handleMistiResult.html @@ -0,0 +1,2 @@ +handleMistiResult | Misti

Function handleMistiResult

  • Handles Misti execution result by either logging to console or saving to file.

    +

    Parameters

    Returns void

diff --git a/tools/misti/api/functions/cli_cli.runMistiCommand.html b/tools/misti/api/functions/cli_cli.runMistiCommand.html new file mode 100644 index 000000000..89191cc0f --- /dev/null +++ b/tools/misti/api/functions/cli_cli.runMistiCommand.html @@ -0,0 +1,4 @@ +runMistiCommand | Misti

Function runMistiCommand

  • Runs the Misti CLI command with the provided arguments.

    +

    Parameters

    • args: string[]

      The list of arguments to pass to the CLI command.

      +
    • command: Command = ...

    Returns Promise<[Driver, MistiResult]>

    The created Driver instance and the result of execution.

    +
diff --git a/tools/misti/api/functions/cli_result.resultToExitCode.html b/tools/misti/api/functions/cli_result.resultToExitCode.html new file mode 100644 index 000000000..999a96781 --- /dev/null +++ b/tools/misti/api/functions/cli_result.resultToExitCode.html @@ -0,0 +1 @@ +resultToExitCode | Misti

Function resultToExitCode

diff --git a/tools/misti/api/functions/cli_result.resultToString.html b/tools/misti/api/functions/cli_result.resultToString.html new file mode 100644 index 000000000..93ade7f00 --- /dev/null +++ b/tools/misti/api/functions/cli_result.resultToString.html @@ -0,0 +1,2 @@ +resultToString | Misti

Function resultToString

  • Converts a MistiResult object to a readable string based on its kind.

    +

    Parameters

    Returns string

diff --git a/tools/misti/api/functions/cli_result.saveResultToFiles.html b/tools/misti/api/functions/cli_result.saveResultToFiles.html new file mode 100644 index 000000000..9d2170efa --- /dev/null +++ b/tools/misti/api/functions/cli_result.saveResultToFiles.html @@ -0,0 +1,10 @@ +saveResultToFiles | Misti

Function saveResultToFiles

  • Saves the result of a Misti operation to files.

    +

    The names of the files follow the following format:

    +
      +
    • .warnings.out
    • +
    • ..out
    • +
    +

    Parameters

    • result: MistiResult

      The result of a Misti operation.

      +
    • outputPath: string

      The path to save the result to.

      +

    Returns ResultReport

    The report of the result.

    +
diff --git a/tools/misti/api/functions/createDetector.createDetector.html b/tools/misti/api/functions/createDetector.createDetector.html new file mode 100644 index 000000000..415e93b57 --- /dev/null +++ b/tools/misti/api/functions/createDetector.createDetector.html @@ -0,0 +1,5 @@ +createDetector | Misti

Function createDetector

  • Creates a new detector from TEMPLATE_PATH based on user's input.

    +

    Parameters

    • nameOrPath: string

      Either detector name (will create the detector in src/detector/detectorName.ts) +or the complete path to the target detector (e.g. /path/to/myDetector.ts).

      +

    Returns Promise<boolean>

    true if the detector was successfully created, false otherwise.

    +
diff --git a/tools/misti/api/functions/detectors_detector.findBuiltInDetector.html b/tools/misti/api/functions/detectors_detector.findBuiltInDetector.html new file mode 100644 index 000000000..b40895418 --- /dev/null +++ b/tools/misti/api/functions/detectors_detector.findBuiltInDetector.html @@ -0,0 +1,7 @@ +findBuiltInDetector | Misti

Function findBuiltInDetector

  • Asynchronously retrieves a built-in detector by its name. +If the detector is found in the BuiltInDetectors registry, it is loaded and returned; +otherwise, a warning is logged and undefined is returned.

    +

    Parameters

    • ctx: MistiContext

      Misti context.

      +
    • name: string

      The name of the detector to retrieve. This name must match a key in the BuiltInDetectors object.

      +

    Returns Promise<Detector | undefined>

    A Promise that resolves to a Detector instance or undefined if the detector cannot be found or fails to load.

    +
diff --git a/tools/misti/api/functions/detectors_detector.getAllDetectors.html b/tools/misti/api/functions/detectors_detector.getAllDetectors.html new file mode 100644 index 000000000..6ab1defc1 --- /dev/null +++ b/tools/misti/api/functions/detectors_detector.getAllDetectors.html @@ -0,0 +1,3 @@ +getAllDetectors | Misti
  • Returns a list of all the available built-in detectors.

    +

    Returns string[]

    An array of strings representing the names of detectors.

    +
diff --git a/tools/misti/api/functions/detectors_detector.getEnabledDetectors.html b/tools/misti/api/functions/detectors_detector.getEnabledDetectors.html new file mode 100644 index 000000000..391c1d135 --- /dev/null +++ b/tools/misti/api/functions/detectors_detector.getEnabledDetectors.html @@ -0,0 +1,3 @@ +getEnabledDetectors | Misti

Function getEnabledDetectors

  • Returns a list of detector names that are enabled by default.

    +

    Returns string[]

    An array of strings representing the names of enabled detectors.

    +
diff --git a/tools/misti/api/functions/detectors_detector.hasBuiltInDetector.html b/tools/misti/api/functions/detectors_detector.hasBuiltInDetector.html new file mode 100644 index 000000000..aabb3916d --- /dev/null +++ b/tools/misti/api/functions/detectors_detector.hasBuiltInDetector.html @@ -0,0 +1,2 @@ +hasBuiltInDetector | Misti
  • Parameters

    • name: string

    Returns boolean

    True if there is a built-in detector with the given name.

    +
diff --git a/tools/misti/api/functions/internals_exceptions.throwZodError.html b/tools/misti/api/functions/internals_exceptions.throwZodError.html new file mode 100644 index 000000000..810ff155f --- /dev/null +++ b/tools/misti/api/functions/internals_exceptions.throwZodError.html @@ -0,0 +1,3 @@ +throwZodError | Misti
  • Throws an ExecutionException with a human-readable ZodError message.

    +

    Parameters

    • err: unknown

      The ZodError to throw.

      +
    • __namedParameters: Partial<{
          help: string;
          msg: string;
      }> = {}

    Returns never

diff --git a/tools/misti/api/functions/internals_exceptions.tryMsg.html b/tools/misti/api/functions/internals_exceptions.tryMsg.html new file mode 100644 index 000000000..9c5de54fe --- /dev/null +++ b/tools/misti/api/functions/internals_exceptions.tryMsg.html @@ -0,0 +1,2 @@ +tryMsg | Misti
  • Wraps the try clause adding an extra context to the exception text.

    +

    Parameters

    • callback: (() => void)
        • (): void
        • Returns void

    • message: string

    Returns void

diff --git a/tools/misti/api/functions/internals_ir_builders_tactIRBuilder.createIR.html b/tools/misti/api/functions/internals_ir_builders_tactIRBuilder.createIR.html new file mode 100644 index 000000000..c06ef32b2 --- /dev/null +++ b/tools/misti/api/functions/internals_ir_builders_tactIRBuilder.createIR.html @@ -0,0 +1,3 @@ +createIR | Misti
diff --git a/tools/misti/api/functions/internals_ir_builders_tactIRBuilder.setTactStdlibPath.html b/tools/misti/api/functions/internals_ir_builders_tactIRBuilder.setTactStdlibPath.html new file mode 100644 index 000000000..c83ea5feb --- /dev/null +++ b/tools/misti/api/functions/internals_ir_builders_tactIRBuilder.setTactStdlibPath.html @@ -0,0 +1,3 @@ +setTactStdlibPath | Misti
  • Returns path to Tact stdlib defined in the node_modules.

    +

    This adjustment is needed to get an actual path to stdlib distributed within the tact package.

    +

    Parameters

    • nodeModulesPath: string = "../../../.."

    Returns string

diff --git a/tools/misti/api/functions/internals_ir_cfg.getPredecessors.html b/tools/misti/api/functions/internals_ir_cfg.getPredecessors.html new file mode 100644 index 000000000..c817e82fd --- /dev/null +++ b/tools/misti/api/functions/internals_ir_cfg.getPredecessors.html @@ -0,0 +1,2 @@ +getPredecessors | Misti

Function getPredecessors

diff --git a/tools/misti/api/functions/internals_ir_cfg.getSuccessors.html b/tools/misti/api/functions/internals_ir_cfg.getSuccessors.html new file mode 100644 index 000000000..6eee76237 --- /dev/null +++ b/tools/misti/api/functions/internals_ir_cfg.getSuccessors.html @@ -0,0 +1,2 @@ +getSuccessors | Misti
diff --git a/tools/misti/api/functions/internals_ir_indices.IdxGenerator.__reset.html b/tools/misti/api/functions/internals_ir_indices.IdxGenerator.__reset.html new file mode 100644 index 000000000..1f4253062 --- /dev/null +++ b/tools/misti/api/functions/internals_ir_indices.IdxGenerator.__reset.html @@ -0,0 +1,2 @@ +__reset | Misti
diff --git a/tools/misti/api/functions/internals_ir_indices.IdxGenerator.next.html b/tools/misti/api/functions/internals_ir_indices.IdxGenerator.next.html new file mode 100644 index 000000000..1fecd508b --- /dev/null +++ b/tools/misti/api/functions/internals_ir_indices.IdxGenerator.next.html @@ -0,0 +1 @@ +next | Misti
diff --git a/tools/misti/api/functions/internals_tact_constEval.evalExpr.html b/tools/misti/api/functions/internals_tact_constEval.evalExpr.html new file mode 100644 index 000000000..3723b542f --- /dev/null +++ b/tools/misti/api/functions/internals_tact_constEval.evalExpr.html @@ -0,0 +1,4 @@ +evalExpr | Misti
  • Evaluates a constant expression and returns its value.

    +

    Parameters

    • expr: AstExpression

      The AST expression to evaluate.

      +

    Returns Value | undefined

    The evaluated constant value, or undefined if evaluation fails.

    +
diff --git a/tools/misti/api/functions/internals_tact_constEval.evalToType.html b/tools/misti/api/functions/internals_tact_constEval.evalToType.html new file mode 100644 index 000000000..b6e09552b --- /dev/null +++ b/tools/misti/api/functions/internals_tact_constEval.evalToType.html @@ -0,0 +1,6 @@ +evalToType | Misti
  • Evaluates the given expression to a constant value and checks if it matches +the expected type.

    +

    Parameters

    • expr: AstExpression

      The expression to evaluate.

      +
    • expectedType: string

      The expected type name as a string.

      +

    Returns Value | undefined

    The evaluated value if it matches the expected type, undefined otherwise.

    +
diff --git a/tools/misti/api/functions/internals_tact_constEval.evalsToPredicate.html b/tools/misti/api/functions/internals_tact_constEval.evalsToPredicate.html new file mode 100644 index 000000000..9d91b96ef --- /dev/null +++ b/tools/misti/api/functions/internals_tact_constEval.evalsToPredicate.html @@ -0,0 +1,6 @@ +evalsToPredicate | Misti
  • Evaluates the given expression to a constant value and checks if it satisfies the predicate.

    +

    Parameters

    • expr: AstExpression

      The expression to evaluate.

      +
    • predicate: ((value: any) => boolean)

      The predicate to check.

      +
        • (value): boolean
        • Parameters

          • value: any

          Returns boolean

    Returns boolean

    True if the expression can be evaluated to a constant value that satisfies +the predicate, false otherwise.

    +
diff --git a/tools/misti/api/functions/internals_tact_constEval.evalsToValue.html b/tools/misti/api/functions/internals_tact_constEval.evalsToValue.html new file mode 100644 index 000000000..74f96b029 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_constEval.evalsToValue.html @@ -0,0 +1,8 @@ +evalsToValue | Misti
  • Evaluates the given expression to a constant value and checks if it matches +the expected type and value.

    +

    Parameters

    • expr: AstExpression

      The expression to evaluate.

      +
    • expectedType: string

      The expected type name as a string.

      +
    • expectedValue: Value

      The expected value.

      +

    Returns boolean

    True if the expression can be evaluated to a constant value that +matches the expected type and value, false otherwise.

    +
diff --git a/tools/misti/api/functions/internals_tact_iterators.extractPath.html b/tools/misti/api/functions/internals_tact_iterators.extractPath.html new file mode 100644 index 000000000..3a9942c71 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_iterators.extractPath.html @@ -0,0 +1 @@ +extractPath | Misti
diff --git a/tools/misti/api/functions/internals_tact_iterators.findInExpressions.html b/tools/misti/api/functions/internals_tact_iterators.findInExpressions.html new file mode 100644 index 000000000..d05d60040 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_iterators.findInExpressions.html @@ -0,0 +1,5 @@ +findInExpressions | Misti
  • Recursively searches for an expression in an ASTNode that satisfies the predicate.

    +

    Parameters

    • node: AstNode

      The node to traverse.

      +
    • predicate: ((expr: AstExpression) => boolean)

      The predicate function to test each expression.

      +
        • (expr): boolean
        • Parameters

          • expr: AstExpression

          Returns boolean

    Returns AstExpression | null

    The first expression that satisfies the predicate, or null if none found.

    +
diff --git a/tools/misti/api/functions/internals_tact_iterators.foldExpressions.html b/tools/misti/api/functions/internals_tact_iterators.foldExpressions.html new file mode 100644 index 000000000..e5732ab02 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_iterators.foldExpressions.html @@ -0,0 +1,6 @@ +foldExpressions | Misti
  • Recursively iterates over each expression in an ASTNode and applies a callback to each expression.

    +

    Type Parameters

    • T

    Parameters

    • node: AstNode

      The node to traverse.

      +
    • callback: ((acc: T, expr: AstExpression) => T)

      The callback function to apply to each expression.

      +
        • (acc, expr): T
        • Parameters

          • acc: T
          • expr: AstExpression

          Returns T

    • acc: T

      The initial value of the accumulator.

      +

    Returns T

    The final value of the accumulator after processing all expressions.

    +
diff --git a/tools/misti/api/functions/internals_tact_iterators.foldStatements.html b/tools/misti/api/functions/internals_tact_iterators.foldStatements.html new file mode 100644 index 000000000..8655e6042 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_iterators.foldStatements.html @@ -0,0 +1,8 @@ +foldStatements | Misti
  • Recursively iterates over each statement in an ASTNode and applies a callback to each statement.

    +

    Type Parameters

    • T

    Parameters

    • node: AstNode

      The node to traverse.

      +
    • callback: ((acc: T, stmt: AstStatement) => T)

      The callback function to apply to each statement, also passes the accumulator.

      +
        • (acc, stmt): T
        • Parameters

          • acc: T
          • stmt: AstStatement

          Returns T

    • acc: T

      The initial value of the accumulator.

      +
    • flatStmts: Partial<{
          flatStmts: boolean;
      }> = {}

      If true, only traverse statements at the current level without +going into nested statements.

      +

    Returns T

    The final value of the accumulator after processing all statements.

    +
diff --git a/tools/misti/api/functions/internals_tact_iterators.forEachExpression.html b/tools/misti/api/functions/internals_tact_iterators.forEachExpression.html new file mode 100644 index 000000000..edfc9eca2 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_iterators.forEachExpression.html @@ -0,0 +1,6 @@ +forEachExpression | Misti
  • Recursively iterates over each expression in an ASTNode and applies a callback to each expression.

    +

    Parameters

    • node: AstNode

      The node to traverse.

      +
    • callback: ((expr: AstExpression) => void)

      The callback function to apply to each expression.

      +
        • (expr): void
        • Parameters

          • expr: AstExpression

          Returns void

    • flatStmts: Partial<{
          flatStmts: boolean;
      }> = {}

      If true, only traverse statement expressions at the current +level without going into nested statements.

      +

    Returns void

diff --git a/tools/misti/api/functions/internals_tact_iterators.forEachStatement.html b/tools/misti/api/functions/internals_tact_iterators.forEachStatement.html new file mode 100644 index 000000000..1080a7c65 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_iterators.forEachStatement.html @@ -0,0 +1,4 @@ +forEachStatement | Misti
  • Recursively iterates over each statement in an ASTNode and applies a callback to each statement.

    +

    Parameters

    • node: AstNode

      The node to traverse.

      +
    • callback: ((stmt: AstStatement) => void)

      The callback function to apply to each statement.

      +
        • (stmt): void
        • Parameters

          • stmt: AstStatement

          Returns void

    Returns void

diff --git a/tools/misti/api/functions/internals_tact_iterators.hasInExpressions.html b/tools/misti/api/functions/internals_tact_iterators.hasInExpressions.html new file mode 100644 index 000000000..8dcee6dd2 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_iterators.hasInExpressions.html @@ -0,0 +1,5 @@ +hasInExpressions | Misti
  • Returns true if there are any nested expressions matching the given predicate.

    +

    Parameters

    • node: AstNode

      The node to traverse.

      +
    • predicate: ((expr: AstExpression) => boolean)

      The predicate function to test each expression.

      +
        • (expr): boolean
        • Parameters

          • expr: AstExpression

          Returns boolean

    Returns boolean

    The first expression that satisfies the predicate, or null if none found.

    +
diff --git a/tools/misti/api/functions/internals_tact_util.collectConditions.html b/tools/misti/api/functions/internals_tact_util.collectConditions.html new file mode 100644 index 000000000..7ec732f2d --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.collectConditions.html @@ -0,0 +1,2 @@ +collectConditions | Misti
  • Collects all the conditions from the conditional, including if and else if statements.

    +

    Parameters

    • node: AstCondition
    • __namedParameters: Partial<{
          nonEmpty: boolean;
      }> = {}

    Returns AstExpression[]

diff --git a/tools/misti/api/functions/internals_tact_util.collectFields.html b/tools/misti/api/functions/internals_tact_util.collectFields.html new file mode 100644 index 000000000..364acb434 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.collectFields.html @@ -0,0 +1,2 @@ +collectFields | Misti
  • Collects declarations of all the contract fields.

    +

    Parameters

    • contract: AstContract
    • __namedParameters: Partial<{
          initialized: boolean;
      }> = {}

    Returns Map<string, AstFieldDecl>

diff --git a/tools/misti/api/functions/internals_tact_util.collectMutations.html b/tools/misti/api/functions/internals_tact_util.collectMutations.html new file mode 100644 index 000000000..f861b311e --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.collectMutations.html @@ -0,0 +1,6 @@ +collectMutations | Misti
  • Collects mutations local or state mutations within the statements.

    +

    Parameters

    • stmt: AstStatement
    • flatStmts: Partial<{
          flatStmts: boolean;
      }> = {}

      If true, only traverse statements at the current level without +going into nested statements. It should be used when calling this function +inside one of the iterators.

      +

    Returns {
        mutatedFields: MutatedElement[];
        mutatedLocals: MutatedElement[];
    } | undefined

    Mutated fields and local identifiers, including nested fields of mutated structure instances

    +
diff --git a/tools/misti/api/functions/internals_tact_util.formatPosition.html b/tools/misti/api/functions/internals_tact_util.formatPosition.html new file mode 100644 index 000000000..3e41dcbb7 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.formatPosition.html @@ -0,0 +1,2 @@ +formatPosition | Misti
  • Creates a concise string representation of SrcInfo.

    +

    Parameters

    • Optionalref: SrcInfo

    Returns string

diff --git a/tools/misti/api/functions/internals_tact_util.funName.html b/tools/misti/api/functions/internals_tact_util.funName.html new file mode 100644 index 000000000..b6bad9193 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.funName.html @@ -0,0 +1,2 @@ +funName | Misti
  • Returns the human-readable name of the function.

    +

    Parameters

    • fun: AstFunctionDef | AstContractInit | AstReceiver

    Returns string

diff --git a/tools/misti/api/functions/internals_tact_util.isPrimitiveLiteral.html b/tools/misti/api/functions/internals_tact_util.isPrimitiveLiteral.html new file mode 100644 index 000000000..cf82ec106 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.isPrimitiveLiteral.html @@ -0,0 +1,2 @@ +isPrimitiveLiteral | Misti
  • Returns true iff the input expression represents a primitive literal.

    +

    Parameters

    • expr: AstExpression

    Returns boolean

diff --git a/tools/misti/api/functions/internals_tact_util.isSelf.html b/tools/misti/api/functions/internals_tact_util.isSelf.html new file mode 100644 index 000000000..e641b6661 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.isSelf.html @@ -0,0 +1,2 @@ +isSelf | Misti
  • Parameters

    • expr: AstExpression

    Returns boolean

    True for self identifiers: self.

    +
diff --git a/tools/misti/api/functions/internals_tact_util.isSelfAccess.html b/tools/misti/api/functions/internals_tact_util.isSelfAccess.html new file mode 100644 index 000000000..d95459d98 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.isSelfAccess.html @@ -0,0 +1,2 @@ +isSelfAccess | Misti
  • Parameters

    • expr: AstExpression

    Returns boolean

    True for self access expressions: self.a, self.a.b.

    +
diff --git a/tools/misti/api/functions/internals_tact_util.isStdlibMutationMethod.html b/tools/misti/api/functions/internals_tact_util.isStdlibMutationMethod.html new file mode 100644 index 000000000..3e486a075 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.isStdlibMutationMethod.html @@ -0,0 +1,2 @@ +isStdlibMutationMethod | Misti

Function isStdlibMutationMethod

  • Parameters

    • call: AstMethodCall

    Returns boolean

    True iff call is a stdlib method mutating its receiver.

    +
diff --git a/tools/misti/api/functions/internals_tact_util.mutationNames.html b/tools/misti/api/functions/internals_tact_util.mutationNames.html new file mode 100644 index 000000000..4c17eedf8 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.mutationNames.html @@ -0,0 +1,8 @@ +mutationNames | Misti
  • Collects names of the mutated elements.

    +

    For example:

    +
      +
    • a -> a
    • +
    • self.a -> a
    • +
    • self.object.f1 -> object
    • +
    +

    Parameters

    Returns string[]

diff --git a/tools/misti/api/functions/internals_tact_util.nodesAreEqual.html b/tools/misti/api/functions/internals_tact_util.nodesAreEqual.html new file mode 100644 index 000000000..72dedaca7 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.nodesAreEqual.html @@ -0,0 +1,2 @@ +nodesAreEqual | Misti
  • Checks if the AST of two nodes is equal using the Tact AST comparison API.

    +

    Parameters

    • node1: AstExpression | AstStatement
    • node2: AstExpression | AstStatement

    Returns boolean

diff --git a/tools/misti/api/functions/internals_tact_util.removeSelf.html b/tools/misti/api/functions/internals_tact_util.removeSelf.html new file mode 100644 index 000000000..8529e09fc --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.removeSelf.html @@ -0,0 +1,9 @@ +removeSelf | Misti
  • Returns the accessor name without the leading self. part.

    +

    For example:

    +
      +
    • self.a -> AstId(a)
    • +
    • self.a() -> AstMethodCall(a)
    • +
    • self.object.f1 -> AstFieldAccess(object.f1)
    • +
    • nonSelf.a -> undefined
    • +
    +

    Parameters

    • expr: AstExpression

    Returns AstId | AstFieldAccess | undefined

diff --git a/tools/misti/api/functions/internals_tact_util.statementsAreEqual.html b/tools/misti/api/functions/internals_tact_util.statementsAreEqual.html new file mode 100644 index 000000000..fb752a60d --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.statementsAreEqual.html @@ -0,0 +1,2 @@ +statementsAreEqual | Misti
  • Checks if the AST of two lists of statements is equal using the Tact AST comparison API.

    +

    Parameters

    • stmts1: AstStatement[]
    • stmts2: AstStatement[]

    Returns boolean

diff --git a/tools/misti/api/functions/internals_util.intersection.html b/tools/misti/api/functions/internals_util.intersection.html new file mode 100644 index 000000000..db2f31ef5 --- /dev/null +++ b/tools/misti/api/functions/internals_util.intersection.html @@ -0,0 +1,2 @@ +intersection | Misti

Function intersection

Intersection of two lists.

+
diff --git a/tools/misti/api/functions/internals_util.isListSubsetOf.html b/tools/misti/api/functions/internals_util.isListSubsetOf.html new file mode 100644 index 000000000..49cbf3b24 --- /dev/null +++ b/tools/misti/api/functions/internals_util.isListSubsetOf.html @@ -0,0 +1 @@ +isListSubsetOf | Misti

Function isListSubsetOf

  • Type Parameters

    • T

    Parameters

    • lhs: T[]
    • rhs: T[]

    Returns boolean

diff --git a/tools/misti/api/functions/internals_util.isMapSubsetOf.html b/tools/misti/api/functions/internals_util.isMapSubsetOf.html new file mode 100644 index 000000000..f8a64c1a3 --- /dev/null +++ b/tools/misti/api/functions/internals_util.isMapSubsetOf.html @@ -0,0 +1 @@ +isMapSubsetOf | Misti

Function isMapSubsetOf

  • Type Parameters

    • K
    • V

    Parameters

    • lhs: Map<K, V>
    • rhs: Map<K, V>

    Returns boolean

diff --git a/tools/misti/api/functions/internals_util.isSubsetOf.html b/tools/misti/api/functions/internals_util.isSubsetOf.html new file mode 100644 index 000000000..6d1116708 --- /dev/null +++ b/tools/misti/api/functions/internals_util.isSubsetOf.html @@ -0,0 +1 @@ +isSubsetOf | Misti
  • Type Parameters

    • T

    Parameters

    • lhs: Set<T>
    • rhs: Set<T>

    Returns boolean

diff --git a/tools/misti/api/functions/internals_util.mergeLists.html b/tools/misti/api/functions/internals_util.mergeLists.html new file mode 100644 index 000000000..b5da1cf75 --- /dev/null +++ b/tools/misti/api/functions/internals_util.mergeLists.html @@ -0,0 +1 @@ +mergeLists | Misti
diff --git a/tools/misti/api/functions/internals_util.mergeMaps.html b/tools/misti/api/functions/internals_util.mergeMaps.html new file mode 100644 index 000000000..f5dc272c8 --- /dev/null +++ b/tools/misti/api/functions/internals_util.mergeMaps.html @@ -0,0 +1 @@ +mergeMaps | Misti
diff --git a/tools/misti/api/functions/internals_util.mergeSets.html b/tools/misti/api/functions/internals_util.mergeSets.html new file mode 100644 index 000000000..256e642c3 --- /dev/null +++ b/tools/misti/api/functions/internals_util.mergeSets.html @@ -0,0 +1 @@ +mergeSets | Misti
diff --git a/tools/misti/api/functions/internals_util.unreachable.html b/tools/misti/api/functions/internals_util.unreachable.html new file mode 100644 index 000000000..4fbe0f139 --- /dev/null +++ b/tools/misti/api/functions/internals_util.unreachable.html @@ -0,0 +1,2 @@ +unreachable | Misti

Function unreachable

  • Unreachable case for exhaustive checking.

    +

    Parameters

    • value: never

    Returns never

diff --git a/tools/misti/api/functions/internals_warnings.makeDocURL.html b/tools/misti/api/functions/internals_warnings.makeDocURL.html new file mode 100644 index 000000000..fda9061d0 --- /dev/null +++ b/tools/misti/api/functions/internals_warnings.makeDocURL.html @@ -0,0 +1,2 @@ +makeDocURL | Misti
  • Creates a link to the documentation for built-in detectors.

    +

    Parameters

    • detectorName: string

    Returns string

diff --git a/tools/misti/api/functions/internals_warnings.parseSeverity.html b/tools/misti/api/functions/internals_warnings.parseSeverity.html new file mode 100644 index 000000000..1c0590f51 --- /dev/null +++ b/tools/misti/api/functions/internals_warnings.parseSeverity.html @@ -0,0 +1,2 @@ +parseSeverity | Misti
diff --git a/tools/misti/api/functions/internals_warnings.severityToString.html b/tools/misti/api/functions/internals_warnings.severityToString.html new file mode 100644 index 000000000..badd16f67 --- /dev/null +++ b/tools/misti/api/functions/internals_warnings.severityToString.html @@ -0,0 +1,3 @@ +severityToString | Misti
  • Returns string representation of Severity optionally wrapped in ANSI escape +sequences making them colorful for visual overload.

    +

    Parameters

    • s: Severity
    • __namedParameters: Partial<{
          brackets: boolean;
          colorize: boolean;
      }> = {}

    Returns string

diff --git a/tools/misti/api/functions/tools_tool.findBuiltInTool.html b/tools/misti/api/functions/tools_tool.findBuiltInTool.html new file mode 100644 index 000000000..48c640c38 --- /dev/null +++ b/tools/misti/api/functions/tools_tool.findBuiltInTool.html @@ -0,0 +1,8 @@ +findBuiltInTool | Misti

Function findBuiltInTool

  • Asynchronously retrieves a built-in tool by its name. +If the tool is found in the BuiltInTools registry, it is loaded and returned; +otherwise, a warning is logged and undefined is returned.

    +

    Type Parameters

    • T extends Record<string, unknown>

    Parameters

    • ctx: MistiContext

      Misti context.

      +
    • name: string

      The name of the tool to retrieve. This name must match a key in the BuiltInTools object.

      +
    • options: T

      The options to pass to the tool constructor.

      +

    Returns Promise<Tool<T> | undefined>

    A Promise that resolves to a Tool instance or undefined if the tool cannot be found or fails to load.

    +
diff --git a/tools/misti/api/functions/tools_tool.generateToolsHelpMessage.html b/tools/misti/api/functions/tools_tool.generateToolsHelpMessage.html new file mode 100644 index 000000000..02105d3ea --- /dev/null +++ b/tools/misti/api/functions/tools_tool.generateToolsHelpMessage.html @@ -0,0 +1,3 @@ +generateToolsHelpMessage | Misti

Function generateToolsHelpMessage

  • Generates a help message for all the available tools.

    +

    Returns Promise<string>

    A string containing the help message.

    +
diff --git a/tools/misti/api/functions/tools_tool.getAllTools.html b/tools/misti/api/functions/tools_tool.getAllTools.html new file mode 100644 index 000000000..8e28804ef --- /dev/null +++ b/tools/misti/api/functions/tools_tool.getAllTools.html @@ -0,0 +1,3 @@ +getAllTools | Misti

Function getAllTools

  • Returns a list of all the available built-in tools.

    +

    Returns string[]

    An array of strings representing the names of tools.

    +
diff --git a/tools/misti/api/functions/tools_tool.hasBuiltInTool.html b/tools/misti/api/functions/tools_tool.hasBuiltInTool.html new file mode 100644 index 000000000..f73d5da1e --- /dev/null +++ b/tools/misti/api/functions/tools_tool.hasBuiltInTool.html @@ -0,0 +1,2 @@ +hasBuiltInTool | Misti

Function hasBuiltInTool

  • Parameters

    • name: string

    Returns boolean

    True if there is a built-in tool with the given name.

    +
diff --git a/tools/misti/api/hierarchy.html b/tools/misti/api/hierarchy.html new file mode 100644 index 000000000..036ec5658 --- /dev/null +++ b/tools/misti/api/hierarchy.html @@ -0,0 +1 @@ +Misti
diff --git a/tools/misti/api/index.html b/tools/misti/api/index.html new file mode 100644 index 000000000..b2fb8d4a3 --- /dev/null +++ b/tools/misti/api/index.html @@ -0,0 +1,36 @@ +Misti

Misti

Misti Logo Misti

Misti is a static analysis tool designed for smart contracts on the TON blockchain.

+ +
    +
  • Detect Code Issues: Identify and fix potential security flaws and code problems early in the development cycle.
  • +
  • Streamline Development: +Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.
  • +
  • Custom Detectors: Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.
  • +
+
    +
  1. +

    Install Soufflé according to the official installation instruction.

    +
  2. +
  3. +

    Misti is distributed via npm and should be added to your Tact project in the same way as Tact itself:

    +
  4. +
+
yarn add @nowarp/misti
+
+ +
    +
  1. Run Misti by specifying a Tact project configuration:
  2. +
+
npx misti path/to/your/tact.config.json
+
+ +

See Misti Configuration for available options, or Developing Misti for advanced instructions. Blueprint users should refer to the appropriate documentation page.

+ +
diff --git a/tools/misti/api/interfaces/cli_options.CLIOptions.html b/tools/misti/api/interfaces/cli_options.CLIOptions.html new file mode 100644 index 000000000..50ec9805d --- /dev/null +++ b/tools/misti/api/interfaces/cli_options.CLIOptions.html @@ -0,0 +1,18 @@ +CLIOptions | Misti

Interface CLIOptions

interface CLIOptions {
    allDetectors: boolean;
    colors: boolean;
    config: undefined | string;
    disabledDetectors: undefined | string[];
    enabledDetectors: undefined | string[];
    listTools: boolean;
    minSeverity: Severity;
    newDetector: undefined | string;
    outputFormat: OutputFormat;
    outputPath: string;
    quiet: boolean;
    souffleBinary: string;
    soufflePath: string;
    souffleVerbose: boolean;
    tactStdlibPath: undefined | string;
    tools: undefined | ToolConfig[];
    verbose: boolean;
}

Properties

allDetectors: boolean
colors: boolean
config: undefined | string
disabledDetectors: undefined | string[]
enabledDetectors: undefined | string[]
listTools: boolean
minSeverity: Severity
newDetector: undefined | string
outputFormat: OutputFormat
outputPath: string
quiet: boolean
souffleBinary: string
soufflePath: string
souffleVerbose: boolean
tactStdlibPath: undefined | string
tools: undefined | ToolConfig[]
verbose: boolean
diff --git a/tools/misti/api/interfaces/cli_types.DetectorConfig.html b/tools/misti/api/interfaces/cli_types.DetectorConfig.html new file mode 100644 index 000000000..e48480f06 --- /dev/null +++ b/tools/misti/api/interfaces/cli_types.DetectorConfig.html @@ -0,0 +1,7 @@ +DetectorConfig | Misti

Interface DetectorConfig

Configuration for a detector.

+
interface DetectorConfig {
    className: string;
    modulePath?: string;
}

Properties

Properties

className: string

Name of the class that implements the detector.

+
modulePath?: string

Path to the module containing the detector. +Used only for custom out-of-tree detectors.

+
diff --git a/tools/misti/api/interfaces/cli_types.ToolConfig.html b/tools/misti/api/interfaces/cli_types.ToolConfig.html new file mode 100644 index 000000000..f182bea5d --- /dev/null +++ b/tools/misti/api/interfaces/cli_types.ToolConfig.html @@ -0,0 +1,6 @@ +ToolConfig | Misti

Interface ToolConfig

Configuration for a tool.

+
interface ToolConfig {
    className: string;
    options?: Record<string, unknown>;
}

Properties

Properties

className: string

Name of the class that implements the tool.

+
options?: Record<string, unknown>

Generic set of options for tools

+
diff --git a/tools/misti/api/interfaces/internals_lattice.JoinSemilattice.html b/tools/misti/api/interfaces/internals_lattice.JoinSemilattice.html new file mode 100644 index 000000000..06a458ce3 --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice.JoinSemilattice.html @@ -0,0 +1,16 @@ +JoinSemilattice | Misti

Interface JoinSemilattice<T>

Interface for a join semilattice that introduces the join operation.

+
interface JoinSemilattice<T> {
    bottom(): T;
    join(a: T, b: T): T;
    leq(a: T, b: T): boolean;
}

Type Parameters

  • T

    The type of elements in the semilattice.

    +

Hierarchy (view full)

Implemented by

Methods

Methods

  • Joins two elements of the semilattice, returning the least upper bound (lub) of the two elements.

    +

    Parameters

    • a: T

      First element to join.

      +
    • b: T

      Second element to join.

      +

    Returns T

    The joined value, representing the combination of a and b.

    +
  • Determines if one element in the semilattice is less than or equal to another element. +This is crucial for determining if the analysis has reached a fixpoint.

    +

    Parameters

    • a: T

      The element to be compared.

      +
    • b: T

      The element to compare against.

      +

    Returns boolean

    true if a is less than or equal to b, otherwise false.

    +
diff --git a/tools/misti/api/interfaces/internals_lattice.Lattice.html b/tools/misti/api/interfaces/internals_lattice.Lattice.html new file mode 100644 index 000000000..cbfa0eed8 --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice.Lattice.html @@ -0,0 +1,11 @@ +Lattice | Misti

Interface Lattice<T>

Interface for a lattice structure, providing methods for control flow analysis.

+
interface Lattice<T> {
    bottom(): T;
    leq(a: T, b: T): boolean;
}

Type Parameters

  • T

    The type of elements in the lattice.

    +

Hierarchy (view full)

Methods

Methods

  • Determines if one element in the semilattice is less than or equal to another element. +This is crucial for determining if the analysis has reached a fixpoint.

    +

    Parameters

    • a: T

      The element to be compared.

      +
    • b: T

      The element to compare against.

      +

    Returns boolean

    true if a is less than or equal to b, otherwise false.

    +
diff --git a/tools/misti/api/interfaces/internals_lattice.MeetSemilattice.html b/tools/misti/api/interfaces/internals_lattice.MeetSemilattice.html new file mode 100644 index 000000000..882fcbce0 --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice.MeetSemilattice.html @@ -0,0 +1,16 @@ +MeetSemilattice | Misti

Interface MeetSemilattice<T>

Interface for a meet semilattice that introduces the meet operation.

+
interface MeetSemilattice<T> {
    bottom(): T;
    leq(a: T, b: T): boolean;
    meet(a: T, b: T): T;
}

Type Parameters

  • T

    The type of elements in the semilattice.

    +

Hierarchy (view full)

Implemented by

Methods

Methods

  • Determines if one element in the semilattice is less than or equal to another element. +This is crucial for determining if the analysis has reached a fixpoint.

    +

    Parameters

    • a: T

      The element to be compared.

      +
    • b: T

      The element to compare against.

      +

    Returns boolean

    true if a is less than or equal to b, otherwise false.

    +
  • Meets two elements of the semilattice, returning the greatest lower bound (glb) of the two elements.

    +

    Parameters

    • a: T

      First element to meet.

      +
    • b: T

      Second element to meet.

      +

    Returns T

    The met value, representing the combination of a and b.

    +
diff --git a/tools/misti/api/interfaces/internals_solver_solver.Solver.html b/tools/misti/api/interfaces/internals_solver_solver.Solver.html new file mode 100644 index 000000000..45a99785e --- /dev/null +++ b/tools/misti/api/interfaces/internals_solver_solver.Solver.html @@ -0,0 +1,3 @@ +Solver | Misti

Interface Solver<State>

A generic interface that defines dataflow-equations solvers.

+
interface Solver<State> {
    solve(): SolverResults<State>;
}

Type Parameters

  • State

Implemented by

Methods

Methods

diff --git a/tools/misti/api/interfaces/internals_solver_souffle.SouffleMapper.html b/tools/misti/api/interfaces/internals_solver_souffle.SouffleMapper.html new file mode 100644 index 000000000..06f35d837 --- /dev/null +++ b/tools/misti/api/interfaces/internals_solver_souffle.SouffleMapper.html @@ -0,0 +1,25 @@ +SouffleMapper | Misti

An interface for a specific dataflow problem used to generate a Soufflé program.

+

It is used to express the dataflow problem and serves the same purpose as the transfer +function when using the worklist fixpoint algorithm. The join/meet semilattice +operations should be expressed implicitly in the Soufflé rules. Maintaining the +monotonicity property is a responsibility of the user, i.e. the designed rules +must ensure that the dataflow information only grows or remains the same.

+

When implementing definitions inside the functions of this interface, the user can refer +to some fields that have special meanings and are added by the Soufflé solver by default:

+
    +
  • bb${index} - Basic block with the given index
  • +
  • edge - Edge relations between two blocks
  • +
+
interface SouffleMapper {
    addConstraints(ctx: SouffleContext<SrcInfo>): void;
    addDecls(ctx: SouffleContext<SrcInfo>): void;
    addRules(ctx: SouffleContext<SrcInfo>): void;
}

Methods

  • Adds Souffle facts to describe constraints for the dataflow problem.

    +

    Example: +var_defined("bb4", "x"). - Variable x is defined within the basic block with index 4

    +

    Parameters

    • ctx: SouffleContext<SrcInfo>

    Returns void

  • Adds Souffle declarations specific for the dataflow problem.

    +

    Example: +.decl var_defined(bb: symbol, var: symbol) - Variables defined in dataflow

    +

    Parameters

    • ctx: SouffleContext<SrcInfo>

    Returns void

  • Adds Souffle rules specific for the dataflow problem.

    +

    Example: +out(bb, var) :- pred(bb, predBB), in(predBB, var). - Computes the out state based on the in state

    +

    Parameters

    • ctx: SouffleContext<SrcInfo>

    Returns void

diff --git a/tools/misti/api/interfaces/internals_transfer.Transfer.html b/tools/misti/api/interfaces/internals_transfer.Transfer.html new file mode 100644 index 000000000..a24e6dacb --- /dev/null +++ b/tools/misti/api/interfaces/internals_transfer.Transfer.html @@ -0,0 +1,11 @@ +Transfer | Misti

Interface Transfer<State>

Represents an interface for dataflow transfer functions.

+
interface Transfer<State> {
    transfer(inState: State, bb: BasicBlock, stmt: AstStatement): State;
}

Type Parameters

  • State

Methods

Methods

  • Transforms the input state based on the analysis of a CFG node.

    +

    This function updates the state of dataflow analysis as it processes +each basic block (e.g., statements, expressions) in a control flow graph, +reflecting changes due to program actions.

    +

    Parameters

    • inState: State

      The dataflow state prior to the execution of node.

      +
    • bb: BasicBlock

      The CFG construct being analyzed.

      +
    • stmt: AstStatement

      The statement defined within the node.

      +

    Returns State

    The updated dataflow state post node execution.

    +
diff --git a/tools/misti/api/media/misti.png b/tools/misti/api/media/misti.png new file mode 100644 index 0000000000000000000000000000000000000000..1b177ea53ac9b89585122ab91fec8f6bab6b5109 GIT binary patch literal 331022 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

f^zSsA4ZT> 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ⅇfU>nw1aA{IB0x_J>!{orNUZ*J!vS5ycB}T>MrE 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� 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⋘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 | Misti

Module cli

References

Re-exports CLIOptions
Re-exports DetectorConfig
Re-exports Driver
Re-exports ExitCode
Re-exports MistiResult
Re-exports MistiResultError
Re-exports MistiResultOK
Re-exports MistiResultTool
Re-exports MistiResultWarnings
Re-exports OutputFormat
Re-exports ResultReport
Re-exports STDOUT_PATH
Re-exports ToolConfig
Re-exports ToolOutput
Re-exports WarningOutput
Re-exports cliOptionDefaults
Re-exports cliOptions
Re-exports createMistiCommand
Re-exports executeMisti
Re-exports handleMistiResult
Re-exports resultToExitCode
Re-exports resultToString
Re-exports runMistiCommand
Re-exports saveResultToFiles
diff --git a/tools/misti/api/modules/cli_cli.html b/tools/misti/api/modules/cli_cli.html new file mode 100644 index 000000000..eca38a28c --- /dev/null +++ b/tools/misti/api/modules/cli_cli.html @@ -0,0 +1,5 @@ +cli/cli | Misti
diff --git a/tools/misti/api/modules/cli_driver.html b/tools/misti/api/modules/cli_driver.html new file mode 100644 index 000000000..b803bb25e --- /dev/null +++ b/tools/misti/api/modules/cli_driver.html @@ -0,0 +1,2 @@ +cli/driver | Misti

Module cli/driver

Index

Classes

diff --git a/tools/misti/api/modules/cli_options.html b/tools/misti/api/modules/cli_options.html new file mode 100644 index 000000000..9db542a4e --- /dev/null +++ b/tools/misti/api/modules/cli_options.html @@ -0,0 +1,5 @@ +cli/options | Misti

Module cli/options

Index

Interfaces

Variables

diff --git a/tools/misti/api/modules/cli_result.html b/tools/misti/api/modules/cli_result.html new file mode 100644 index 000000000..1f0a8a4a1 --- /dev/null +++ b/tools/misti/api/modules/cli_result.html @@ -0,0 +1,12 @@ +cli/result | Misti
diff --git a/tools/misti/api/modules/cli_singleContract.html b/tools/misti/api/modules/cli_singleContract.html new file mode 100644 index 000000000..cae142568 --- /dev/null +++ b/tools/misti/api/modules/cli_singleContract.html @@ -0,0 +1,2 @@ +cli/singleContract | Misti

Module cli/singleContract

Index

Classes

diff --git a/tools/misti/api/modules/cli_types.html b/tools/misti/api/modules/cli_types.html new file mode 100644 index 000000000..d27c411ca --- /dev/null +++ b/tools/misti/api/modules/cli_types.html @@ -0,0 +1,5 @@ +cli/types | Misti

Module cli/types

Index

Enumerations

Interfaces

Type Aliases

diff --git a/tools/misti/api/modules/createDetector.html b/tools/misti/api/modules/createDetector.html new file mode 100644 index 000000000..7adc9f68c --- /dev/null +++ b/tools/misti/api/modules/createDetector.html @@ -0,0 +1,3 @@ +createDetector | Misti

Module createDetector

An utility to create new custom detectors from the defined template.

+

Index

Functions

diff --git a/tools/misti/api/modules/detectors_builtin_argCopyMutation.html b/tools/misti/api/modules/detectors_builtin_argCopyMutation.html new file mode 100644 index 000000000..f5af2be7c --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_argCopyMutation.html @@ -0,0 +1,2 @@ +detectors/builtin/argCopyMutation | Misti

Module detectors/builtin/argCopyMutation

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_asmIsUsed.html b/tools/misti/api/modules/detectors_builtin_asmIsUsed.html new file mode 100644 index 000000000..fddbb1b38 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_asmIsUsed.html @@ -0,0 +1,2 @@ +detectors/builtin/asmIsUsed | Misti

Module detectors/builtin/asmIsUsed

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_branchDuplicate.html b/tools/misti/api/modules/detectors_builtin_branchDuplicate.html new file mode 100644 index 000000000..7e23b0c2d --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_branchDuplicate.html @@ -0,0 +1,2 @@ +detectors/builtin/branchDuplicate | Misti

Module detectors/builtin/branchDuplicate

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_cellOverflow.html b/tools/misti/api/modules/detectors_builtin_cellOverflow.html new file mode 100644 index 000000000..ee2ac1d69 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_cellOverflow.html @@ -0,0 +1,2 @@ +detectors/builtin/cellOverflow | Misti

Module detectors/builtin/cellOverflow

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_constantAddress.html b/tools/misti/api/modules/detectors_builtin_constantAddress.html new file mode 100644 index 000000000..5e22cc979 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_constantAddress.html @@ -0,0 +1,2 @@ +detectors/builtin/constantAddress | Misti

Module detectors/builtin/constantAddress

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_divideBeforeMultiply.html b/tools/misti/api/modules/detectors_builtin_divideBeforeMultiply.html new file mode 100644 index 000000000..36d591801 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_divideBeforeMultiply.html @@ -0,0 +1,2 @@ +detectors/builtin/divideBeforeMultiply | Misti
diff --git a/tools/misti/api/modules/detectors_builtin_dumpIsUsed.html b/tools/misti/api/modules/detectors_builtin_dumpIsUsed.html new file mode 100644 index 000000000..0b8fc5166 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_dumpIsUsed.html @@ -0,0 +1,2 @@ +detectors/builtin/dumpIsUsed | Misti

Module detectors/builtin/dumpIsUsed

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_duplicatedCondition.html b/tools/misti/api/modules/detectors_builtin_duplicatedCondition.html new file mode 100644 index 000000000..c3d926be7 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_duplicatedCondition.html @@ -0,0 +1,2 @@ +detectors/builtin/duplicatedCondition | Misti

Module detectors/builtin/duplicatedCondition

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_ensurePrgSeed.html b/tools/misti/api/modules/detectors_builtin_ensurePrgSeed.html new file mode 100644 index 000000000..042c48300 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_ensurePrgSeed.html @@ -0,0 +1,2 @@ +detectors/builtin/ensurePrgSeed | Misti

Module detectors/builtin/ensurePrgSeed

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_falseCondition.html b/tools/misti/api/modules/detectors_builtin_falseCondition.html new file mode 100644 index 000000000..833407c03 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_falseCondition.html @@ -0,0 +1,2 @@ +detectors/builtin/falseCondition | Misti

Module detectors/builtin/falseCondition

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_fieldDoubleInit.html b/tools/misti/api/modules/detectors_builtin_fieldDoubleInit.html new file mode 100644 index 000000000..fe4198bc7 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_fieldDoubleInit.html @@ -0,0 +1,2 @@ +detectors/builtin/fieldDoubleInit | Misti

Module detectors/builtin/fieldDoubleInit

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_inheritedStateMutation.html b/tools/misti/api/modules/detectors_builtin_inheritedStateMutation.html new file mode 100644 index 000000000..7614b558e --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_inheritedStateMutation.html @@ -0,0 +1,2 @@ +detectors/builtin/inheritedStateMutation | Misti
diff --git a/tools/misti/api/modules/detectors_builtin_neverAccessedVariables.html b/tools/misti/api/modules/detectors_builtin_neverAccessedVariables.html new file mode 100644 index 000000000..a4aa18e49 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_neverAccessedVariables.html @@ -0,0 +1,2 @@ +detectors/builtin/neverAccessedVariables | Misti
diff --git a/tools/misti/api/modules/detectors_builtin_optimalMathFunction.html b/tools/misti/api/modules/detectors_builtin_optimalMathFunction.html new file mode 100644 index 000000000..202f03386 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_optimalMathFunction.html @@ -0,0 +1,2 @@ +detectors/builtin/optimalMathFunction | Misti

Module detectors/builtin/optimalMathFunction

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_preferAugmentedAssign.html b/tools/misti/api/modules/detectors_builtin_preferAugmentedAssign.html new file mode 100644 index 000000000..b310d1bc8 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_preferAugmentedAssign.html @@ -0,0 +1,2 @@ +detectors/builtin/preferAugmentedAssign | Misti
diff --git a/tools/misti/api/modules/detectors_builtin_preferredStdlibApi.html b/tools/misti/api/modules/detectors_builtin_preferredStdlibApi.html new file mode 100644 index 000000000..57fc7eae2 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_preferredStdlibApi.html @@ -0,0 +1,2 @@ +detectors/builtin/preferredStdlibApi | Misti

Module detectors/builtin/preferredStdlibApi

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_readOnlyVariables.html b/tools/misti/api/modules/detectors_builtin_readOnlyVariables.html new file mode 100644 index 000000000..38f5b62fb --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_readOnlyVariables.html @@ -0,0 +1,2 @@ +detectors/builtin/readOnlyVariables | Misti

Module detectors/builtin/readOnlyVariables

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_stringReceiversOverlap.html b/tools/misti/api/modules/detectors_builtin_stringReceiversOverlap.html new file mode 100644 index 000000000..2c78736b4 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_stringReceiversOverlap.html @@ -0,0 +1,2 @@ +detectors/builtin/stringReceiversOverlap | Misti
diff --git a/tools/misti/api/modules/detectors_builtin_unboundLoops.html b/tools/misti/api/modules/detectors_builtin_unboundLoops.html new file mode 100644 index 000000000..20a983625 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_unboundLoops.html @@ -0,0 +1,2 @@ +detectors/builtin/unboundLoops | Misti

Module detectors/builtin/unboundLoops

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_unusedOptional.html b/tools/misti/api/modules/detectors_builtin_unusedOptional.html new file mode 100644 index 000000000..04ef0950e --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_unusedOptional.html @@ -0,0 +1,2 @@ +detectors/builtin/unusedOptional | Misti

Module detectors/builtin/unusedOptional

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_zeroAddress.html b/tools/misti/api/modules/detectors_builtin_zeroAddress.html new file mode 100644 index 000000000..90b7d146f --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_zeroAddress.html @@ -0,0 +1,2 @@ +detectors/builtin/zeroAddress | Misti

Module detectors/builtin/zeroAddress

Index

Classes

diff --git a/tools/misti/api/modules/detectors_detector.html b/tools/misti/api/modules/detectors_detector.html new file mode 100644 index 000000000..661adc386 --- /dev/null +++ b/tools/misti/api/modules/detectors_detector.html @@ -0,0 +1,20 @@ +detectors/detector | Misti

Module detectors/detector

Defines the base structure for Misti static analysis detectors, including AST, +dataflow, and Soufflé-based detectors.

+

Supports dynamic loading of built-in detectors, warning generation, and configurable +behavior for multi-project setups.

+

To add a new built-in detector, create its implementation in the ./builtin +directory and add information about it to BuiltInDetectors. No other changes +in the project are needed.

+

Index

Classes

Type Aliases

Variables

Functions

diff --git a/tools/misti/api/modules/index.html b/tools/misti/api/modules/index.html new file mode 100644 index 000000000..61ef591e0 --- /dev/null +++ b/tools/misti/api/modules/index.html @@ -0,0 +1,79 @@ +index | Misti

Module index

References

Re-exports ASTDetector
Re-exports BASE_DOC_URL
Re-exports BuiltInDetectors
Re-exports DataflowDetector
Re-exports DebugLogger
Re-exports Detector
Re-exports DetectorKind
Re-exports DetectorName
Re-exports DumpAst
Re-exports DumpCfg
Re-exports DumpConfig
Re-exports ExecutionException
Re-exports InternalException
Re-exports JoinSemilattice
Re-exports Lattice
Re-exports LogFunction
Re-exports LogLevel
Re-exports Logger
Re-exports MISTI_VERSION
Re-exports MeetSemilattice
Re-exports MistiConfig
Re-exports MistiContext
Re-exports MistiTactWarning
Re-exports MutatedElement
Re-exports QuietLogger
Re-exports SetJoinSemilattice
Re-exports SetMeetSemilattice
Re-exports Severity
Re-exports SouffleDetector
Re-exports SrcInfoSet
Re-exports TACT_VERSION
Re-exports TactException
Re-exports Tool
Re-exports ToolName
Re-exports TraceLogger
Re-exports Transfer
Re-exports WarningSuppression
Re-exports WarningsBehavior
Re-exports cli
Re-exports collectConditions
Re-exports collectFields
Re-exports collectMutations
Re-exports evalExpr
Re-exports evalToType
Re-exports evalsToPredicate
Re-exports evalsToValue
Re-exports extractPath
Re-exports findBuiltInDetector
Re-exports findBuiltInTool
Re-exports findInExpressions
Re-exports foldExpressions
Re-exports foldStatements
Re-exports forEachExpression
Re-exports forEachStatement
Re-exports formatPosition
Re-exports funName
Re-exports generateToolsHelpMessage
Re-exports getAllDetectors
Re-exports getAllTools
Re-exports getEnabledDetectors
Re-exports hasBuiltInDetector
Re-exports hasBuiltInTool
Re-exports hasInExpressions
Renames and re-exports internals/ir
Re-exports isPrimitiveLiteral
Re-exports isSelf
Re-exports isSelfAccess
Re-exports isStdlibMutationMethod
Re-exports makeDocURL
Re-exports mutationNames
Re-exports nodesAreEqual
Re-exports parseSeverity
Re-exports removeSelf
Re-exports severityToString
Renames and re-exports internals/solver
Re-exports statementsAreEqual
Re-exports throwZodError
Re-exports tryMsg
diff --git a/tools/misti/api/modules/internals_config.html b/tools/misti/api/modules/internals_config.html new file mode 100644 index 000000000..e43e2b481 --- /dev/null +++ b/tools/misti/api/modules/internals_config.html @@ -0,0 +1,3 @@ +internals/config | Misti

Module internals/config

Index

Classes

Type Aliases

diff --git a/tools/misti/api/modules/internals_context.html b/tools/misti/api/modules/internals_context.html new file mode 100644 index 000000000..abb72a55a --- /dev/null +++ b/tools/misti/api/modules/internals_context.html @@ -0,0 +1,2 @@ +internals/context | Misti

Module internals/context

Index

Classes

diff --git a/tools/misti/api/modules/internals_exceptions.html b/tools/misti/api/modules/internals_exceptions.html new file mode 100644 index 000000000..e9544762c --- /dev/null +++ b/tools/misti/api/modules/internals_exceptions.html @@ -0,0 +1,6 @@ +internals/exceptions | Misti
diff --git a/tools/misti/api/modules/internals_ir.html b/tools/misti/api/modules/internals_ir.html new file mode 100644 index 000000000..19428610d --- /dev/null +++ b/tools/misti/api/modules/internals_ir.html @@ -0,0 +1,25 @@ +internals/ir | Misti

Module internals/ir

References

Re-exports BasicBlock
Re-exports BasicBlockIdx
Re-exports BasicBlockKind
Re-exports CFG
Re-exports CFGIdx
Re-exports CompilationUnit
Re-exports Contract
Re-exports ContractIdx
Re-exports ContractName
Re-exports DEFAULT_STDLIB_PATH_ELEMENTS
Re-exports Edge
Re-exports EdgeIdx
Re-exports EntryOrigin
Re-exports FunctionKind
Re-exports FunctionName
Re-exports FunctionsMap
Re-exports MethodsMap
Re-exports ProjectName
Re-exports TactASTStore
Re-exports TactIRBuilder
Re-exports createIR
Re-exports getPredecessors
Re-exports getSuccessors
Re-exports setTactStdlibPath
diff --git a/tools/misti/api/modules/internals_ir_astStore.html b/tools/misti/api/modules/internals_ir_astStore.html new file mode 100644 index 000000000..8661c1c9c --- /dev/null +++ b/tools/misti/api/modules/internals_ir_astStore.html @@ -0,0 +1,2 @@ +internals/ir/astStore | Misti

Module internals/ir/astStore

Index

Classes

diff --git a/tools/misti/api/modules/internals_ir_builders_tactIRBuilder.html b/tools/misti/api/modules/internals_ir_builders_tactIRBuilder.html new file mode 100644 index 000000000..0504c062d --- /dev/null +++ b/tools/misti/api/modules/internals_ir_builders_tactIRBuilder.html @@ -0,0 +1,7 @@ +internals/ir/builders/tactIRBuilder | Misti
diff --git a/tools/misti/api/modules/internals_ir_cfg.html b/tools/misti/api/modules/internals_ir_cfg.html new file mode 100644 index 000000000..84e6e33d1 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_cfg.html @@ -0,0 +1,11 @@ +internals/ir/cfg | Misti

Module internals/ir/cfg

Contains definitions of the Control Flow Graph (CFG) for Tact and utility +functions to work with it.

+

Index

Classes

Type Aliases

Functions

diff --git a/tools/misti/api/modules/internals_ir_indices.IdxGenerator.html b/tools/misti/api/modules/internals_ir_indices.IdxGenerator.html new file mode 100644 index 000000000..bd798d2a7 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_indices.IdxGenerator.html @@ -0,0 +1,5 @@ +IdxGenerator | Misti

Generates unique indexes is used to assign unique identifiers to nodes and edges, +ensuring that each element within the CFG can be distinctly referenced.

+

Index

Functions

diff --git a/tools/misti/api/modules/internals_ir_indices.html b/tools/misti/api/modules/internals_ir_indices.html new file mode 100644 index 000000000..d0333fc87 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_indices.html @@ -0,0 +1,2 @@ +internals/ir/indices | Misti

Module internals/ir/indices

Index

Namespaces

diff --git a/tools/misti/api/modules/internals_ir_ir.html b/tools/misti/api/modules/internals_ir_ir.html new file mode 100644 index 000000000..d14734b34 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_ir.html @@ -0,0 +1,4 @@ +internals/ir/ir | Misti

Module internals/ir/ir

Defined the Intermediate Representation (IR) for Tact used in analysis.

+

Index

Classes

diff --git a/tools/misti/api/modules/internals_ir_types.html b/tools/misti/api/modules/internals_ir_types.html new file mode 100644 index 000000000..d74e413c4 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_types.html @@ -0,0 +1,8 @@ +internals/ir/types | Misti
diff --git a/tools/misti/api/modules/internals_lattice.html b/tools/misti/api/modules/internals_lattice.html new file mode 100644 index 000000000..df37297e0 --- /dev/null +++ b/tools/misti/api/modules/internals_lattice.html @@ -0,0 +1,6 @@ +internals/lattice | Misti
diff --git a/tools/misti/api/modules/internals_logger.html b/tools/misti/api/modules/internals_logger.html new file mode 100644 index 000000000..6c2f51822 --- /dev/null +++ b/tools/misti/api/modules/internals_logger.html @@ -0,0 +1,7 @@ +internals/logger | Misti

Module internals/logger

Index

Enumerations

Classes

Type Aliases

diff --git a/tools/misti/api/modules/internals_solver.html b/tools/misti/api/modules/internals_solver.html new file mode 100644 index 000000000..dfacecc68 --- /dev/null +++ b/tools/misti/api/modules/internals_solver.html @@ -0,0 +1,7 @@ +internals/solver | Misti

Module internals/solver

References

Re-exports AnalysisKind
Re-exports Solver
Re-exports SolverResults
Re-exports SouffleMapper
Re-exports SouffleSolver
Re-exports WorklistSolver
diff --git a/tools/misti/api/modules/internals_solver_results.html b/tools/misti/api/modules/internals_solver_results.html new file mode 100644 index 000000000..fbc9da160 --- /dev/null +++ b/tools/misti/api/modules/internals_solver_results.html @@ -0,0 +1,2 @@ +internals/solver/results | Misti

Module internals/solver/results

Index

Classes

diff --git a/tools/misti/api/modules/internals_solver_solver.html b/tools/misti/api/modules/internals_solver_solver.html new file mode 100644 index 000000000..324de16cd --- /dev/null +++ b/tools/misti/api/modules/internals_solver_solver.html @@ -0,0 +1,2 @@ +internals/solver/solver | Misti

Module internals/solver/solver

Index

Interfaces

diff --git a/tools/misti/api/modules/internals_solver_souffle.html b/tools/misti/api/modules/internals_solver_souffle.html new file mode 100644 index 000000000..d28537b36 --- /dev/null +++ b/tools/misti/api/modules/internals_solver_souffle.html @@ -0,0 +1,3 @@ +internals/solver/souffle | Misti

Module internals/solver/souffle

Index

Classes

Interfaces

diff --git a/tools/misti/api/modules/internals_solver_worklist.html b/tools/misti/api/modules/internals_solver_worklist.html new file mode 100644 index 000000000..95e7fb189 --- /dev/null +++ b/tools/misti/api/modules/internals_solver_worklist.html @@ -0,0 +1,3 @@ +internals/solver/worklist | Misti

Module internals/solver/worklist

Index

Classes

Type Aliases

diff --git a/tools/misti/api/modules/internals_tact.html b/tools/misti/api/modules/internals_tact.html new file mode 100644 index 000000000..dc815ea75 --- /dev/null +++ b/tools/misti/api/modules/internals_tact.html @@ -0,0 +1,27 @@ +internals/tact | Misti

Module internals/tact

References

Re-exports MutatedElement
Re-exports SrcInfoSet
Re-exports collectConditions
Re-exports collectFields
Re-exports collectMutations
Re-exports evalExpr
Re-exports evalToType
Re-exports evalsToPredicate
Re-exports evalsToValue
Re-exports extractPath
Re-exports findInExpressions
Re-exports foldExpressions
Re-exports foldStatements
Re-exports forEachExpression
Re-exports forEachStatement
Re-exports formatPosition
Re-exports funName
Re-exports hasInExpressions
Re-exports isPrimitiveLiteral
Re-exports isSelf
Re-exports isSelfAccess
Re-exports isStdlibMutationMethod
Re-exports mutationNames
Re-exports nodesAreEqual
Re-exports removeSelf
Re-exports statementsAreEqual
diff --git a/tools/misti/api/modules/internals_tact_constEval.html b/tools/misti/api/modules/internals_tact_constEval.html new file mode 100644 index 000000000..8d2e749bf --- /dev/null +++ b/tools/misti/api/modules/internals_tact_constEval.html @@ -0,0 +1,5 @@ +internals/tact/constEval | Misti

Module internals/tact/constEval

Index

Functions

diff --git a/tools/misti/api/modules/internals_tact_iterators.html b/tools/misti/api/modules/internals_tact_iterators.html new file mode 100644 index 000000000..510461558 --- /dev/null +++ b/tools/misti/api/modules/internals_tact_iterators.html @@ -0,0 +1,8 @@ +internals/tact/iterators | Misti
diff --git a/tools/misti/api/modules/internals_tact_util.html b/tools/misti/api/modules/internals_tact_util.html new file mode 100644 index 000000000..f52cd2f21 --- /dev/null +++ b/tools/misti/api/modules/internals_tact_util.html @@ -0,0 +1,16 @@ +internals/tact/util | Misti
diff --git a/tools/misti/api/modules/internals_transfer.html b/tools/misti/api/modules/internals_transfer.html new file mode 100644 index 000000000..02fc8fd40 --- /dev/null +++ b/tools/misti/api/modules/internals_transfer.html @@ -0,0 +1,2 @@ +internals/transfer | Misti

Module internals/transfer

Index

Interfaces

diff --git a/tools/misti/api/modules/internals_util.html b/tools/misti/api/modules/internals_util.html new file mode 100644 index 000000000..a7b0909dc --- /dev/null +++ b/tools/misti/api/modules/internals_util.html @@ -0,0 +1,10 @@ +internals/util | Misti

Module internals/util

Additional generic TypeScript functions used in the project.

+

Index

Functions

diff --git a/tools/misti/api/modules/internals_warnings.html b/tools/misti/api/modules/internals_warnings.html new file mode 100644 index 000000000..015935d89 --- /dev/null +++ b/tools/misti/api/modules/internals_warnings.html @@ -0,0 +1,7 @@ +internals/warnings | Misti

Module internals/warnings

Index

Enumerations

Classes

Variables

Functions

diff --git a/tools/misti/api/modules/main.html b/tools/misti/api/modules/main.html new file mode 100644 index 000000000..7ed35b6f3 --- /dev/null +++ b/tools/misti/api/modules/main.html @@ -0,0 +1 @@ +main | Misti

Module main

diff --git a/tools/misti/api/modules/tools.html b/tools/misti/api/modules/tools.html new file mode 100644 index 000000000..4814e0d90 --- /dev/null +++ b/tools/misti/api/modules/tools.html @@ -0,0 +1,10 @@ +tools | Misti

Module tools

References

Re-exports DumpAst
Re-exports DumpCfg
Re-exports DumpConfig
Re-exports Tool
Re-exports ToolName
Re-exports findBuiltInTool
Re-exports generateToolsHelpMessage
Re-exports getAllTools
Re-exports hasBuiltInTool
diff --git a/tools/misti/api/modules/tools_dumpAst.html b/tools/misti/api/modules/tools_dumpAst.html new file mode 100644 index 000000000..244c959fc --- /dev/null +++ b/tools/misti/api/modules/tools_dumpAst.html @@ -0,0 +1,2 @@ +tools/dumpAst | Misti

Module tools/dumpAst

Index

Classes

diff --git a/tools/misti/api/modules/tools_dumpCfg.html b/tools/misti/api/modules/tools_dumpCfg.html new file mode 100644 index 000000000..7dfa34292 --- /dev/null +++ b/tools/misti/api/modules/tools_dumpCfg.html @@ -0,0 +1,2 @@ +tools/dumpCfg | Misti

Module tools/dumpCfg

Index

Classes

diff --git a/tools/misti/api/modules/tools_dumpConfig.html b/tools/misti/api/modules/tools_dumpConfig.html new file mode 100644 index 000000000..f5539bd44 --- /dev/null +++ b/tools/misti/api/modules/tools_dumpConfig.html @@ -0,0 +1,2 @@ +tools/dumpConfig | Misti

Module tools/dumpConfig

Index

Classes

diff --git a/tools/misti/api/modules/tools_tool.html b/tools/misti/api/modules/tools_tool.html new file mode 100644 index 000000000..b345a02df --- /dev/null +++ b/tools/misti/api/modules/tools_tool.html @@ -0,0 +1,7 @@ +tools/tool | Misti

Module tools/tool

Index

Classes

Type Aliases

Functions

diff --git a/tools/misti/api/modules/version.html b/tools/misti/api/modules/version.html new file mode 100644 index 000000000..753bef012 --- /dev/null +++ b/tools/misti/api/modules/version.html @@ -0,0 +1,3 @@ +version | Misti

Module version

References

Re-exports MISTI_VERSION
Re-exports TACT_VERSION
diff --git a/tools/misti/api/modules/version_info.html b/tools/misti/api/modules/version_info.html new file mode 100644 index 000000000..786e90207 --- /dev/null +++ b/tools/misti/api/modules/version_info.html @@ -0,0 +1,3 @@ +version-info | Misti

Module version-info

Index

Variables

diff --git a/tools/misti/api/types/cli_result.MistiResult.html b/tools/misti/api/types/cli_result.MistiResult.html new file mode 100644 index 000000000..7a0b6f0a6 --- /dev/null +++ b/tools/misti/api/types/cli_result.MistiResult.html @@ -0,0 +1 @@ +MistiResult | Misti

Type Alias MistiResult

MistiResult:
    | MistiResultOK
    | MistiResultWarnings
    | MistiResultTool
    | MistiResultError
diff --git a/tools/misti/api/types/cli_result.MistiResultError.html b/tools/misti/api/types/cli_result.MistiResultError.html new file mode 100644 index 000000000..a1705f825 --- /dev/null +++ b/tools/misti/api/types/cli_result.MistiResultError.html @@ -0,0 +1,3 @@ +MistiResultError | Misti

Type Alias MistiResultError

MistiResultError: {
    error: string;
    kind: "error";
}

MistiResultError represents the result of a Misti operation that encountered an error.

+

Type declaration

  • error: string

    Error output when Misti cannot complete the requested operation.

    +
  • kind: "error"
diff --git a/tools/misti/api/types/cli_result.MistiResultOK.html b/tools/misti/api/types/cli_result.MistiResultOK.html new file mode 100644 index 000000000..55e32b683 --- /dev/null +++ b/tools/misti/api/types/cli_result.MistiResultOK.html @@ -0,0 +1,2 @@ +MistiResultOK | Misti

Type Alias MistiResultOK

MistiResultOK: {
    kind: "ok";
}

MistiResultOK represents the result of a Misti operation that did not find any warnings.

+
diff --git a/tools/misti/api/types/cli_result.MistiResultTool.html b/tools/misti/api/types/cli_result.MistiResultTool.html new file mode 100644 index 000000000..3bc2fb65f --- /dev/null +++ b/tools/misti/api/types/cli_result.MistiResultTool.html @@ -0,0 +1,2 @@ +MistiResultTool | Misti

Type Alias MistiResultTool

MistiResultTool: {
    kind: "tool";
    output: ToolOutput[];
}

MistiResultTool represents the result of a Misti operation that executed an internal tool.

+
diff --git a/tools/misti/api/types/cli_result.MistiResultWarnings.html b/tools/misti/api/types/cli_result.MistiResultWarnings.html new file mode 100644 index 000000000..115ae02cb --- /dev/null +++ b/tools/misti/api/types/cli_result.MistiResultWarnings.html @@ -0,0 +1,2 @@ +MistiResultWarnings | Misti

Type Alias MistiResultWarnings

MistiResultWarnings: {
    kind: "warnings";
    warnings: WarningOutput[];
}

MistiResultWarnings represents the result of a Misti operation that found warnings.

+
diff --git a/tools/misti/api/types/cli_result.ResultReport.html b/tools/misti/api/types/cli_result.ResultReport.html new file mode 100644 index 000000000..de48cab55 --- /dev/null +++ b/tools/misti/api/types/cli_result.ResultReport.html @@ -0,0 +1 @@ +ResultReport | Misti

Type Alias ResultReport

ResultReport: {
    kind: "ok";
} | {
    kind: "error";
    message: string;
} | null
diff --git a/tools/misti/api/types/cli_result.ToolOutput.html b/tools/misti/api/types/cli_result.ToolOutput.html new file mode 100644 index 000000000..7e592a675 --- /dev/null +++ b/tools/misti/api/types/cli_result.ToolOutput.html @@ -0,0 +1,3 @@ +ToolOutput | Misti

Type Alias ToolOutput

ToolOutput: {
    name: string;
    output: string;
    projectName: string;
}

Type declaration

  • name: string

    Name of the tool.

    +
  • output: string
  • projectName: string

    Project this tool was executed for.

    +
diff --git a/tools/misti/api/types/cli_result.WarningOutput.html b/tools/misti/api/types/cli_result.WarningOutput.html new file mode 100644 index 000000000..c52551540 --- /dev/null +++ b/tools/misti/api/types/cli_result.WarningOutput.html @@ -0,0 +1,3 @@ +WarningOutput | Misti

Type Alias WarningOutput

WarningOutput: {
    projectName: string;
    warnings: string[];
}

Type declaration

  • projectName: string

    Project that has been checked.

    +
  • warnings: string[]

    Warnings found by Misti.

    +
diff --git a/tools/misti/api/types/cli_types.OutputFormat.html b/tools/misti/api/types/cli_types.OutputFormat.html new file mode 100644 index 000000000..b31d3f731 --- /dev/null +++ b/tools/misti/api/types/cli_types.OutputFormat.html @@ -0,0 +1 @@ +OutputFormat | Misti

Type Alias OutputFormat

OutputFormat: "json" | "plain"
diff --git a/tools/misti/api/types/detectors_detector.DetectorKind.html b/tools/misti/api/types/detectors_detector.DetectorKind.html new file mode 100644 index 000000000..ff9dc48d8 --- /dev/null +++ b/tools/misti/api/types/detectors_detector.DetectorKind.html @@ -0,0 +1 @@ +DetectorKind | Misti
DetectorKind: "ast" | "dataflow" | "souffle"
diff --git a/tools/misti/api/types/detectors_detector.DetectorName.html b/tools/misti/api/types/detectors_detector.DetectorName.html new file mode 100644 index 000000000..0d8226eb3 --- /dev/null +++ b/tools/misti/api/types/detectors_detector.DetectorName.html @@ -0,0 +1 @@ +DetectorName | Misti
DetectorName: string
diff --git a/tools/misti/api/types/detectors_detector.WarningsBehavior.html b/tools/misti/api/types/detectors_detector.WarningsBehavior.html new file mode 100644 index 000000000..69ac48f48 --- /dev/null +++ b/tools/misti/api/types/detectors_detector.WarningsBehavior.html @@ -0,0 +1 @@ +WarningsBehavior | Misti

Type Alias WarningsBehavior

WarningsBehavior: "union" | "intersect"
diff --git a/tools/misti/api/types/internals_config.WarningSuppression.html b/tools/misti/api/types/internals_config.WarningSuppression.html new file mode 100644 index 000000000..8c8e44605 --- /dev/null +++ b/tools/misti/api/types/internals_config.WarningSuppression.html @@ -0,0 +1 @@ +WarningSuppression | Misti

Type Alias WarningSuppression

WarningSuppression: {
    col: number;
    detector: DetectorName;
    file: string;
    line: number;
}
diff --git a/tools/misti/api/types/internals_ir_builders_tactIRBuilder.FunctionsMap.html b/tools/misti/api/types/internals_ir_builders_tactIRBuilder.FunctionsMap.html new file mode 100644 index 000000000..44ce9478c --- /dev/null +++ b/tools/misti/api/types/internals_ir_builders_tactIRBuilder.FunctionsMap.html @@ -0,0 +1,2 @@ +FunctionsMap | Misti
FunctionsMap: Map<FunctionName, CFGIdx>

Maps each function name to its corresponding CFG index.

+
diff --git a/tools/misti/api/types/internals_ir_builders_tactIRBuilder.MethodsMap.html b/tools/misti/api/types/internals_ir_builders_tactIRBuilder.MethodsMap.html new file mode 100644 index 000000000..57709806b --- /dev/null +++ b/tools/misti/api/types/internals_ir_builders_tactIRBuilder.MethodsMap.html @@ -0,0 +1,2 @@ +MethodsMap | Misti
MethodsMap: Map<ContractName, FunctionsMap>

Maps each contract name to a map of its methods, where each method is mapped to its CFG index.

+
diff --git a/tools/misti/api/types/internals_ir_cfg.BasicBlockKind.html b/tools/misti/api/types/internals_ir_cfg.BasicBlockKind.html new file mode 100644 index 000000000..48a2b475c --- /dev/null +++ b/tools/misti/api/types/internals_ir_cfg.BasicBlockKind.html @@ -0,0 +1,8 @@ +BasicBlockKind | Misti

Type Alias BasicBlockKind

BasicBlockKind: {
    kind: "regular";
} | {
    callees: Set<CFGIdx>;
    kind: "call";
} | {
    kind: "exit";
}

Represents the kinds of basic blocks that can be present in a control flow graph (CFG).

+
  • {
        kind: "regular";
    }

    Represents a regular control flow node with no special control behavior.

    +
  • {
        callees: Set<CFGIdx>;
        kind: "call";
    }

    Represents a block that contains function calls in its expressions. +callees refers to unique indices of the callee within the CFG. +Functions which definitions are not available in the current +compilation unit are omitted.

    +
  • {
        kind: "exit";
    }

    Represents an exit node that effectively terminates the execution of the current control flow.

    +
diff --git a/tools/misti/api/types/internals_ir_cfg.EntryOrigin.html b/tools/misti/api/types/internals_ir_cfg.EntryOrigin.html new file mode 100644 index 000000000..64519a29f --- /dev/null +++ b/tools/misti/api/types/internals_ir_cfg.EntryOrigin.html @@ -0,0 +1 @@ +EntryOrigin | Misti

Type Alias EntryOrigin

EntryOrigin: "user" | "stdlib"
diff --git a/tools/misti/api/types/internals_ir_cfg.FunctionKind.html b/tools/misti/api/types/internals_ir_cfg.FunctionKind.html new file mode 100644 index 000000000..3acd00b71 --- /dev/null +++ b/tools/misti/api/types/internals_ir_cfg.FunctionKind.html @@ -0,0 +1,2 @@ +FunctionKind | Misti

Type Alias FunctionKind

FunctionKind: "function" | "method" | "receive"

Kind of a function that appear in CFG.

+
diff --git a/tools/misti/api/types/internals_ir_types.BasicBlockIdx.html b/tools/misti/api/types/internals_ir_types.BasicBlockIdx.html new file mode 100644 index 000000000..a67f923d4 --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.BasicBlockIdx.html @@ -0,0 +1 @@ +BasicBlockIdx | Misti

Type Alias BasicBlockIdx

BasicBlockIdx: number
diff --git a/tools/misti/api/types/internals_ir_types.CFGIdx.html b/tools/misti/api/types/internals_ir_types.CFGIdx.html new file mode 100644 index 000000000..146e2a71e --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.CFGIdx.html @@ -0,0 +1 @@ +CFGIdx | Misti
CFGIdx: number
diff --git a/tools/misti/api/types/internals_ir_types.ContractIdx.html b/tools/misti/api/types/internals_ir_types.ContractIdx.html new file mode 100644 index 000000000..c3deb12c0 --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.ContractIdx.html @@ -0,0 +1 @@ +ContractIdx | Misti
ContractIdx: number
diff --git a/tools/misti/api/types/internals_ir_types.ContractName.html b/tools/misti/api/types/internals_ir_types.ContractName.html new file mode 100644 index 000000000..6e7930224 --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.ContractName.html @@ -0,0 +1 @@ +ContractName | Misti
ContractName: string
diff --git a/tools/misti/api/types/internals_ir_types.EdgeIdx.html b/tools/misti/api/types/internals_ir_types.EdgeIdx.html new file mode 100644 index 000000000..569d76169 --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.EdgeIdx.html @@ -0,0 +1 @@ +EdgeIdx | Misti
EdgeIdx: number
diff --git a/tools/misti/api/types/internals_ir_types.FunctionName.html b/tools/misti/api/types/internals_ir_types.FunctionName.html new file mode 100644 index 000000000..863558b40 --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.FunctionName.html @@ -0,0 +1 @@ +FunctionName | Misti
FunctionName: string
diff --git a/tools/misti/api/types/internals_ir_types.ProjectName.html b/tools/misti/api/types/internals_ir_types.ProjectName.html new file mode 100644 index 000000000..1abff7104 --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.ProjectName.html @@ -0,0 +1 @@ +ProjectName | Misti
ProjectName: string
diff --git a/tools/misti/api/types/internals_logger.LogFunction.html b/tools/misti/api/types/internals_logger.LogFunction.html new file mode 100644 index 000000000..9e071a343 --- /dev/null +++ b/tools/misti/api/types/internals_logger.LogFunction.html @@ -0,0 +1 @@ +LogFunction | Misti

Type Alias LogFunction

LogFunction: ((message: string) => void)
diff --git a/tools/misti/api/types/internals_solver_worklist.AnalysisKind.html b/tools/misti/api/types/internals_solver_worklist.AnalysisKind.html new file mode 100644 index 000000000..57a926c42 --- /dev/null +++ b/tools/misti/api/types/internals_solver_worklist.AnalysisKind.html @@ -0,0 +1,9 @@ +AnalysisKind | Misti
AnalysisKind: "forward" | "backward"

Determines the kind of the dataflow analysis.

+

This type is used to specify the direction of the dataflow analysis being performed.

+
    +
  • forward: Represents a forward dataflow analysis, where information flows from the entry point of a program towards the exit.
  • +
  • backward: Represents a backward dataflow analysis, where information flows from the exit point of a program towards the entry.
  • +
+

Forward analysis is typically used for problems like reaching definitions, live variable analysis, and constant propagation. +Backward analysis is often used for problems such as liveness analysis and backwards slicing.

+
diff --git a/tools/misti/api/types/internals_tact_util.MutatedElement.html b/tools/misti/api/types/internals_tact_util.MutatedElement.html new file mode 100644 index 000000000..878a437b2 --- /dev/null +++ b/tools/misti/api/types/internals_tact_util.MutatedElement.html @@ -0,0 +1 @@ +MutatedElement | Misti
MutatedElement: AstId | AstFieldAccess
diff --git a/tools/misti/api/types/tools_tool.ToolName.html b/tools/misti/api/types/tools_tool.ToolName.html new file mode 100644 index 000000000..827370c8b --- /dev/null +++ b/tools/misti/api/types/tools_tool.ToolName.html @@ -0,0 +1 @@ +ToolName | Misti

Type Alias ToolName

ToolName: string
diff --git a/tools/misti/api/variables/cli_options.STDOUT_PATH.html b/tools/misti/api/variables/cli_options.STDOUT_PATH.html new file mode 100644 index 000000000..dc811bd7e --- /dev/null +++ b/tools/misti/api/variables/cli_options.STDOUT_PATH.html @@ -0,0 +1 @@ +STDOUT_PATH | Misti

Variable STDOUT_PATHConst

STDOUT_PATH: "-" = "-"
diff --git a/tools/misti/api/variables/cli_options.cliOptionDefaults.html b/tools/misti/api/variables/cli_options.cliOptionDefaults.html new file mode 100644 index 000000000..207823054 --- /dev/null +++ b/tools/misti/api/variables/cli_options.cliOptionDefaults.html @@ -0,0 +1 @@ +cliOptionDefaults | Misti

Variable cliOptionDefaultsConst

cliOptionDefaults: Required<CLIOptions> = ...
diff --git a/tools/misti/api/variables/cli_options.cliOptions-1.html b/tools/misti/api/variables/cli_options.cliOptions-1.html new file mode 100644 index 000000000..b64670faa --- /dev/null +++ b/tools/misti/api/variables/cli_options.cliOptions-1.html @@ -0,0 +1 @@ +cliOptions | Misti

Variable cliOptionsConst

cliOptions: Option[] = ...
diff --git a/tools/misti/api/variables/detectors_detector.BuiltInDetectors.html b/tools/misti/api/variables/detectors_detector.BuiltInDetectors.html new file mode 100644 index 000000000..54f32fd19 --- /dev/null +++ b/tools/misti/api/variables/detectors_detector.BuiltInDetectors.html @@ -0,0 +1,2 @@ +BuiltInDetectors | Misti

Variable BuiltInDetectorsConst

BuiltInDetectors: Record<string, DetectorEntry> = ...

A mapping of detector names to their respective loader functions and default enablement status.

+
diff --git a/tools/misti/api/variables/internals_ir_builders_tactIRBuilder.DEFAULT_STDLIB_PATH_ELEMENTS.html b/tools/misti/api/variables/internals_ir_builders_tactIRBuilder.DEFAULT_STDLIB_PATH_ELEMENTS.html new file mode 100644 index 000000000..d430ba689 --- /dev/null +++ b/tools/misti/api/variables/internals_ir_builders_tactIRBuilder.DEFAULT_STDLIB_PATH_ELEMENTS.html @@ -0,0 +1,2 @@ +DEFAULT_STDLIB_PATH_ELEMENTS | Misti
DEFAULT_STDLIB_PATH_ELEMENTS: string[] = ...

A mandatory part of the file path to stdlib if using the default path.

+
diff --git a/tools/misti/api/variables/internals_warnings.BASE_DOC_URL.html b/tools/misti/api/variables/internals_warnings.BASE_DOC_URL.html new file mode 100644 index 000000000..7028cf607 --- /dev/null +++ b/tools/misti/api/variables/internals_warnings.BASE_DOC_URL.html @@ -0,0 +1,2 @@ +BASE_DOC_URL | Misti

Variable BASE_DOC_URLConst

BASE_DOC_URL: "https://nowarp.io/tools/misti/docs/detectors" = "https://nowarp.io/tools/misti/docs/detectors"

Base URL to detectors documentation.

+
diff --git a/tools/misti/api/variables/version_info.MISTI_VERSION.html b/tools/misti/api/variables/version_info.MISTI_VERSION.html new file mode 100644 index 000000000..44c8ecc95 --- /dev/null +++ b/tools/misti/api/variables/version_info.MISTI_VERSION.html @@ -0,0 +1 @@ +MISTI_VERSION | Misti

Variable MISTI_VERSIONConst

MISTI_VERSION: "0.4.2-95c1bff" = '0.4.2-95c1bff'
diff --git a/tools/misti/api/variables/version_info.TACT_VERSION.html b/tools/misti/api/variables/version_info.TACT_VERSION.html new file mode 100644 index 000000000..ebb24f04f --- /dev/null +++ b/tools/misti/api/variables/version_info.TACT_VERSION.html @@ -0,0 +1 @@ +TACT_VERSION | Misti

Variable TACT_VERSIONConst

TACT_VERSION: "1.5.1" = '1.5.1'
diff --git a/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply/index.html b/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply/index.html new file mode 100644 index 000000000..043a4206f --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,34 @@ + + + + + +Divide before Multiply | Misti + + + + +
Version: 0.1.2

Divide before Multiply

+

A detector that identifies and corrects instances of division before multiplication to +ensure accurate mathematical operations.

+

Why is it bad?

+

Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:

+
    +
  • Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers.
  • +
  • Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations.
  • +
  • Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging.
  • +
+

Example

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Bad: Division before multiplication
let result: Int = a / b * c;
+

Use instead:

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Correct: Multiplication before division
let result: Int = a * c / b;
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables/index.html b/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables/index.html new file mode 100644 index 000000000..74b2b4c8c --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,30 @@ + + + + + +Never-accessed Variables | Misti + + + + +
Version: 0.1.2

Never-accessed Variables

+

A detector that identifies write-only or unused variables, fields and constants.

+

Why is it bad?

+

These variables are either assigned but never used in any meaningful computation, +or they are declared and never used at all, which may indicate redundant code +or an incomplete implementation of the intended logic.

+

Example

+
// Error: the developer forgot to use the constant
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+

Use instead:

+
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
// OK: Fixed after the linter highlighted this warning
require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables/index.html b/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables/index.html new file mode 100644 index 000000000..0624d7537 --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,29 @@ + + + + + +Read-only Variables | Misti + + + + +
Version: 0.1.2

Read-only Variables

+

A detector that identifies read-only variables and fields.

+

Why is it bad?

+

These variables could typically be replaced with constants to optimize performance. +Alternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally.

+

Example

+
fun calculateFinalPrice(price: Int): Int {
// Warning: the developer uses a read-only variable that could be a constant
let DISCOUNT_AMOUNT: Int = 10;
return price - DISCOUNT_AMOUNT;
}
+

Use instead:

+
const DISCOUNT_AMOUNT: Int = 10;

fun calculateFinalPrice(price: Int): Int {
// OK: Fixed after the linter highlighted this warning
return price - DISCOUNT_AMOUNT;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/detectors/UnboundLoops/index.html b/tools/misti/docs/0.1.2/detectors/UnboundLoops/index.html new file mode 100644 index 000000000..3c9b2c004 --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/UnboundLoops/index.html @@ -0,0 +1,33 @@ + + + + + +Unbound Loops | Misti + + + + +
Version: 0.1.2

Unbound Loops

+

A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.

+

Why is it bad?

+

An unbounded loop can be problematic for several reasons:

+
    +
  • Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult.
  • +
  • Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks.
  • +
  • DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability.
  • +
+

Example

+
let x: Int = 10;
while (x > 0) {
// Bad: x is not changed due looping
send(SendParameters{ to: sender(), ... });
}
+

Use instead:

+
let x: Int = 10;
while (x > 0) {
send(SendParameters{ to: sender(), ... });
x = x - 1;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/detectors/ZeroAddress/index.html b/tools/misti/docs/0.1.2/detectors/ZeroAddress/index.html new file mode 100644 index 000000000..b8ccc02bf --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/ZeroAddress/index.html @@ -0,0 +1,31 @@ + + + + + +Zero Address | Misti + + + + +
Version: 0.1.2

Zero Address

+

A detector that identifies uses of the zero address.

+

Why is it bad?

+

Using the zero address in smart contracts is typically problematic because it can be +exploited as a default or uninitialized address, leading to unintended transfers and +security vulnerabilities. Additionally, operations involving the zero address can +result in loss of funds or tokens, as there is no private key to access this address.

+

Example

+
contract Proxy {
to: Address;
init() {
// Warning: Insecure usage of zero address as default value
self.to = newAddress(0, 0);
}
fun setAddress(to: Address) {
self.to = to
}
}
+

Use instead:

+
contract Proxy {
to: Address;
init(to: Address) {
// Fixed: Using the input value on initializaiton.
self.to = to;
}
fun setAddress(to: Address) {
self.to = to
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/hacking/CHANGELOG/index.html b/tools/misti/docs/0.1.2/hacking/CHANGELOG/index.html new file mode 100644 index 000000000..73edf188b --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/CHANGELOG/index.html @@ -0,0 +1,43 @@ + + + + + +Changelog | Misti + + + + +
Version: 0.1.2

Changelog

+

All notable changes to this project are documented in this file.

+

The format is based on Keep a Changelog, +and this project adheres to Semantic Versioning.

+

[0.1.2] - 2024-08-06

+

Added

+

Changed

+

Fixed

+
    +
  • Set the actual documentation URL in warnings.
  • +
+

[0.1.1] - 2024-08-06

+

Added

+

Changed

+

Fixed

+
    +
  • The npm postinstall script tries to build a contract project after running yarn add @nowarp/misti.
  • +
+

[0.1.0] - 2024-08-06

+

Added

+
    +
  • Initial release
  • +
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/hacking/contributing/index.html b/tools/misti/docs/0.1.2/hacking/contributing/index.html new file mode 100644 index 000000000..14f6d0c4c --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/contributing/index.html @@ -0,0 +1,66 @@ + + + + + +Contributing Guide | Misti + + + + +
Version: 0.1.2

Contributing Guide

+

Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.

+

Issues reporting

+

When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:

+
The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.
Please help us by publishing it and the input sources at:
https://github.com/nowarp/misti/issues/new.
+

We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users.

+

Documentation contribution

+

We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: nowarp.github.io Issues. Additionally, many documentation pages have an Edit button that allows you to make direct contributions easily.

+

Code contribution

+
    +
  1. +

    Navigate Issues and Find Tasks

    +
      +
    • Browse the issues here. Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues.
    • +
    • Choose an issue suitable for you and mention in the issue that you're working on it.
    • +
    +
  2. +
  3. +

    Implement Your Changes

    +
      +
    • Implement your changes. Feel free to ask questions in the issue if needed.
    • +
    +
  4. +
  5. +

    Ensure Tests Pass

    +
      +
    • Before creating a PR, make sure all tests and CI checks are passing by running: +
      yarn test-all
      +
    • +
    +
  6. +
  7. +

    Create a PR

    +
      +
    • Submit your pull request here
    • +
    +
  8. +
  9. +

    Add a CHANGELOG entry

    +
      +
    • Describe your changes in the CHANGELOG.md file according to the existing structure.
    • +
    +
  10. +
+

All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to HACKING.md.

+

Thank you for your contributions!

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/hacking/custom-detector/index.html b/tools/misti/docs/0.1.2/hacking/custom-detector/index.html new file mode 100644 index 000000000..393724e60 --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/custom-detector/index.html @@ -0,0 +1,32 @@ + + + + + +Custom Detector Guide | Misti + + + + +
Version: 0.1.2

Custom Detector Guide

+

Introduction

+

Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: Misti API Reference.

+

Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the Detector interface.

+

Writing a Detector

+

To write a custom detector, create a TypeScript file using the Misti API. Here's an example of how to implement a custom detector:

+
import { Detector } from "../../src/detectors/detector";
import { MistiContext } from "../../src/internals/context";
import { CompilationUnit } from "../../src/internals/ir";
import {
createError,
MistiTactError,
Severity,
} from "../../src/internals/errors";

/**
* An example of a custom detector that showcases the usage of the detector API.
*
* It reports all the contracts that don't have an explicit implementation of the init function.
*/
export class ImplicitInit extends Detector {
check(ctx: MistiContext, cu: CompilationUnit): MistiTactError[] {
return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {
if (!cu.findMethodCFGByName(contract.name, "init")) {
const err = createError(
ctx,
`contract ${contract.name} doesn't define an init function`,
Severity.INFO,
contract.ref,
);
foundErrors.push(err);
}
return foundErrors;
}, [] as MistiTactError[]);
}
}
+

After creating a detector, you need to specify it in your configuration. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:

+
{
"detectors": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },

{ "className": "ImplicitInit", "modulePath": "/path/to/implicitInit.ts" }
],
"ignored_projects": [],
"verbosity": "default"
}

+

After this, you could run the created detector specifying a path to it: --config path/to/mistiConfig.json test/projects/simple/tactConfig.json.

+

Example Detectors

+

The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the examples directory in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/hacking/design/index.html b/tools/misti/docs/0.1.2/hacking/design/index.html new file mode 100644 index 000000000..5f6394e1c --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/design/index.html @@ -0,0 +1,34 @@ + + + + + +Design Overview | Misti + + + + +
Version: 0.1.2

Design Overview

+

Static Analysis

+

Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues.

+

Souffle Datalog Solver

+

Misti leverages the Souffle Datalog solver, an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases.

+

Dataflow Analysis in Misti

+

Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code.

+

References

+

For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:

+ +

These resources provide a solid foundation in the theory and practice of static and dataflow analysis.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/hacking/souffle/index.html b/tools/misti/docs/0.1.2/hacking/souffle/index.html new file mode 100644 index 000000000..2733f5fc4 --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/souffle/index.html @@ -0,0 +1,38 @@ + + + + + +Soufflé Integration Guide | Misti + + + + +
Version: 0.1.2

Soufflé Integration Guide

+

What is Soufflé?

+

Soufflé is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Soufflé, Misti can perform deep and scalable analyses of smart contracts.

+

Benefits of Using Soufflé for Static Analysis

+

Soufflé allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Soufflé program might be more straightforward then implementing a complex transfer function in for a classic monotone framework.

+

Soufflé Integration in Misti

+

The API for interacting with Soufflé in Misti is detailed here.

+

Creating Soufflé Programs

+

To create a Soufflé program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:

+
addDecls(ctx: Context<SrcInfo>) {
ctx.add(
Relation.from(
"varDecl",
[
["var", FactType.Symbol],
["func", FactType.Symbol],
],
undefined,
),
);
// other declarations
}
+
addRules(ctx: Context<SrcInfo>) {
// readOnly(var, func) :-
// varDecl(var, func),
// !varAssign(var, func),
// !varUse(var, func).
ctx.add(
Rule.from(
[makeAtom("readOnly", ["var", "func"])],
makeRuleBody(makeAtom("varDecl", ["var", "func"])),
makeRuleBody(makeAtom("varAssign", ["var", "func"]), {
negated: true,
}),
makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),
),
);
}
+

Generating Facts and Executing Soufflé

+

After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Soufflé executor to run the analysis:

+
const executor = ctx.config.soufflePath
? new Executor<SrcInfo>({
inputDir: ctx.config.soufflePath,
outputDir: ctx.config.soufflePath,
})
: new Executor<SrcInfo>();

const result = executor.executeSync(program);

if (!result.success) {
throw new Error(
`Error executing Soufflé for ${this.id}:\n${result.stderr}`,
);
}

const warnings = Array.from(result.results.entries.values()).map((fact) => {
// raise warnings
});
+

Learning from Existing Code

+

We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Soufflé with Misti. This will help you understand the intricacies of generating IR and executing Soufflé programs effectively.

+

Further Reading

+

For a deeper understanding of static analysis using Soufflé, refer to the textbook Program Analysis: An Appetizer by Flemming Nielson and Hanne Riis Nielson. It discusses Soufflé-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/hacking/tools/index.html b/tools/misti/docs/0.1.2/hacking/tools/index.html new file mode 100644 index 000000000..a340a5887 --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/tools/index.html @@ -0,0 +1,51 @@ + + + + + +Tools Guide | Misti + + + + +
Version: 0.1.2

Tools Guide

+

This page describes the internal analyzer tools available in Misti to aid in development and debugging.

+

CFG Dump

+

Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts.

+

Usage

+

To dump the CFG in JSON format, use the following command:

+
npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in DOT format, use the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Converting DOT to SVG

+

To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use Graphviz with the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot
dot -Tsvg output.dot -o output.svg
+

Viewing the SVG

+

To view the SVG file in Firefox, use the following command:

+
firefox output.svg
+

For example, for the following contract:

+
fun test(): Int {
let sum: Int = 0;
let i: Int = 0;
repeat (10) {
i = i + 1;
sum = sum + i;
}
return sum;
}
+

The following CFG will be generated:

+

CFG Example

+

VS Code Plugin

+

For real-time visualization of DOT files, you can use one of the available Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer.

    +
  • +
  • +

    DOT Dumps: These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/index.html b/tools/misti/docs/0.1.2/index.html new file mode 100644 index 000000000..771ba6734 --- /dev/null +++ b/tools/misti/docs/0.1.2/index.html @@ -0,0 +1,37 @@ + + + + + +Introduction | Misti + + + + +
Version: 0.1.2

Introduction

Misti is a static analysis tool designed for smart contracts on the TON blockchain.

+

Language Support:

+ +

Use Cases

+

Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:

+
    +
  • Detect Vulnerabilities: Identify and fix potential security flaws early in the development cycle.
  • +
  • Improve Code Quality: Maintain high standards by catching bugs and enforcing best practices automatically.
  • +
  • Streamline Development: Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.
  • +
  • Custom Detectors: Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.
  • +
+

Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow.

+

Funding

+

Misti has been funded by TON Foundation. This support has enabled us to develop and maintain the tool.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/tutorial/configuration/index.html b/tools/misti/docs/0.1.2/tutorial/configuration/index.html new file mode 100644 index 000000000..36186744a --- /dev/null +++ b/tools/misti/docs/0.1.2/tutorial/configuration/index.html @@ -0,0 +1,54 @@ + + + + + +Configuration | Misti + + + + +
Version: 0.1.2

Configuration

+

This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.

+

Configuration Options

+
    +
  • +

    detectors: List of detectors to run. Each detector can be specified with a className and optionally a modulePath if it’s a custom detector.

    +
      +
    • className (string, required): The class name of the detector.
    • +
    • modulePath (string, optional): The file path of the detector module.
    • +
    +
  • +
  • +

    ignored_projects (array of strings, optional): List of Tact projects to ignore during analysis.

    +
  • +
  • +

    soufflePath (string, optional): Directory to save generated Soufflé files which is helpful for debugging purposes. If not set, a temporary directory will be used.

    +
  • +
  • +

    verbosity (string, optional): Verbosity level of the logs. Possible values are quiet, debug, and default.

    +
  • +
+

Running Misti with Configuration

+

To run Misti with the specified configuration file, use the following command:

+
npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json
+

This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration.

+

Default Configuration File

+

By default, Misti enables all built-in detectors. Below is an example of the default configuration file:

+
{
"detectors": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" }
],
"ignored_projects": [],
"verbosity": "default"
}
+

All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: configSchema.json.

+

You can always dump the Misti configuration file in use by passing the --dump-config option in the CLI:

+
npx misti --dump-config test/projects/simple/tactConfig.json
+

If there is no Misti config in the simple directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors.

+

Getting Help

+

If you need assistance or encounter any issues, please create an issue on GitHub at nowarp/misti or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.1.2/tutorial/getting-started/index.html b/tools/misti/docs/0.1.2/tutorial/getting-started/index.html new file mode 100644 index 000000000..231d5aad6 --- /dev/null +++ b/tools/misti/docs/0.1.2/tutorial/getting-started/index.html @@ -0,0 +1,39 @@ + + + + + +Getting started | Misti + + + + +
Version: 0.1.2

Getting started

+

This guide will walk you through the steps to install and set up the Misti static analyzer.

+

Prerequisites

+

Before you begin, ensure you have the following software installed on your system:

+ +

Installation

+

Misti is distributed via npm and should be added to your Tact project in the same way as Tact itself:

+
yarn add @nowarp/misti
+

Running the analysis

+

Run Misti by specifying a Tact project configuration:

+
npx misti test/projects/simple/tactConfig.json
+

This will highlight any warnings the analyzer found.

+

Troubleshooting

+

If you encounter any issues during the installation process, feel free to create an issue or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/BranchDuplicate/index.html b/tools/misti/docs/0.2.0/detectors/BranchDuplicate/index.html new file mode 100644 index 000000000..54fc9feee --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/BranchDuplicate/index.html @@ -0,0 +1,33 @@ + + + + + +Branch Duplicate | Misti + + + + +
Version: 0.2.0

Branch Duplicate

+

Detector that reports duplicated code in conditional branches.

+

Why is it bad?

+

Duplicated code in branches is bad because it:

+
    +
  1. Reduces Readability: Repetition makes the code harder to understand.
  2. +
  3. Increases Maintenance: Changes must be made in multiple places, risking errors.
  4. +
  5. Signals Poor Design: It suggests missed opportunities for cleaner, more abstract code.
  6. +
+

Example

+
if (a > 42) {
a = 43; // bad: duplicated code
} else {
a = 43;
}
+

Use instead:

+
if (a > 42) {
a = inc(b); // ok
} else {
a = 43;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/ConstantAddress/index.html b/tools/misti/docs/0.2.0/detectors/ConstantAddress/index.html new file mode 100644 index 000000000..2f8721b4d --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/ConstantAddress/index.html @@ -0,0 +1,31 @@ + + + + + +Constant Address | Misti + + + + +
Version: 0.2.0

Constant Address

+

An optional detector that highlights all the constant addresses appearing in the source code.

+

Why is it bad?

+

Using hardcoded addresses can sometimes indicate poor contract design. +Some constant addresses may need to be set dynamically, e.g., using +contractAddress, or at least have a way to change them at runtime, for +example, when upgrading a contract.

+

Example

+
contract Main {
proxy: Address;
init() {
// Bad: Constant address highlighted by the analyzer.
self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");
}
}
+

Use instead:

+
contract Main {
proxy: Address;
init() {
let proxy: Proxy = initOf Proxy(myAddress());
// OK: Address depends on how the proxy contact has been deployed
self.proxy = contractAddress(proxy);
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply/index.html b/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply/index.html new file mode 100644 index 000000000..134ac7c91 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,34 @@ + + + + + +Divide before Multiply | Misti + + + + +
Version: 0.2.0

Divide before Multiply

+

A detector that identifies and corrects instances of division before multiplication to +ensure accurate mathematical operations.

+

Why is it bad?

+

Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:

+
    +
  • Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers.
  • +
  • Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations.
  • +
  • Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging.
  • +
+

Example

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Bad: Division before multiplication
let result: Int = a / b * c;
+

Use instead:

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Correct: Multiplication before division
let result: Int = a * c / b;
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/DumpIsUsed/index.html b/tools/misti/docs/0.2.0/detectors/DumpIsUsed/index.html new file mode 100644 index 000000000..59748d6c8 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/DumpIsUsed/index.html @@ -0,0 +1,28 @@ + + + + + +dump Is Used | Misti + + + + +
Version: 0.2.0

dump Is Used

+

An optional detector that highlights all the dump function calls.

+

Why is it bad?

+

The dump function is a debug print that shouldn't be in the final code. Even though the compiler removes it in production, its presence suggests the developer was debugging something. This can flag areas where issues might exist, so auditors should take a closer look at these parts of the code.

+

Example

+
fun test(): Int {
// ... other computations
let combined: Int = (RANDOM_SEED >> half_shift) &
(MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;
dump(combined); // Suspicious: Highlighted by the detector
}
+

Use instead:

+
fun test(): Int {
// ... other computations
let combined: Int = this.seed ^ shift_mask
// OK: The code was reviewed and simplified; `dump` was removed
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/FieldDoubleInit/index.html b/tools/misti/docs/0.2.0/detectors/FieldDoubleInit/index.html new file mode 100644 index 000000000..6bc8f70f2 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/FieldDoubleInit/index.html @@ -0,0 +1,28 @@ + + + + + +Field Initialized Twice | Misti + + + + +
Version: 0.2.0

Field Initialized Twice

+

A detector that highlights cases where a field is initialized both in the init function and at the point of definition.

+

Why is it bad?

+

Double initialization of fields can either be a programmer's mistake or simply a waste of gas. It is always preferred to initialize values in the field declaration if they have a compile-time evaluatable default value, or in the init function if they must be initialized dynamically.

+

Example

+
contract Test {
a: Int = 0; // Bad
init(x: Int) { self.a = x }
}
+

Use instead:

+
contract Test {
a: Int; // Fixed
init(x: Int) { self.a = x }
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables/index.html b/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables/index.html new file mode 100644 index 000000000..e223cdef9 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,30 @@ + + + + + +Never-accessed Variables | Misti + + + + +
Version: 0.2.0

Never-accessed Variables

+

A detector that identifies write-only or unused variables, fields and constants.

+

Why is it bad?

+

These variables are either assigned but never used in any meaningful computation, +or they are declared and never used at all, which may indicate redundant code +or an incomplete implementation of the intended logic.

+

Example

+
// Error: the developer forgot to use the constant
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+

Use instead:

+
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
// OK: Fixed after the linter highlighted this warning
require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign/index.html b/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign/index.html new file mode 100644 index 000000000..1cc007495 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,28 @@ + + + + + +Prefer Augmented Assignment | Misti + + + + +
Version: 0.2.0

Prefer Augmented Assignment

+

Detects non-idiomatic statements that can be written using augmented assignment operators like +=, -=, etc.

+

Why is it bad?

+

Using augmented assignment operations improves the readability of the source code and reduces the risk of mistakes, such as those that occur during copy-pasting and refactoring code.

+

Example

+
msgValue = (msgValue - ctx.readForwardFee());
+

Use instead:

+
msgValue -= ctx.readForwardFee());
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables/index.html b/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables/index.html new file mode 100644 index 000000000..bdf0dd7a3 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,29 @@ + + + + + +Read-only Variables | Misti + + + + +
Version: 0.2.0

Read-only Variables

+

A detector that identifies read-only variables and fields.

+

Why is it bad?

+

These variables could typically be replaced with constants to optimize performance. +Alternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally.

+

Example

+
fun calculateFinalPrice(price: Int): Int {
// Warning: the developer uses a read-only variable that could be a constant
let DISCOUNT_AMOUNT: Int = 10;
return price - DISCOUNT_AMOUNT;
}
+

Use instead:

+
const DISCOUNT_AMOUNT: Int = 10;

fun calculateFinalPrice(price: Int): Int {
// OK: Fixed after the linter highlighted this warning
return price - DISCOUNT_AMOUNT;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/UnboundLoops/index.html b/tools/misti/docs/0.2.0/detectors/UnboundLoops/index.html new file mode 100644 index 000000000..c9f09395d --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/UnboundLoops/index.html @@ -0,0 +1,33 @@ + + + + + +Unbound Loops | Misti + + + + +
Version: 0.2.0

Unbound Loops

+

A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.

+

Why is it bad?

+

An unbounded loop can be problematic for several reasons:

+
    +
  • Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult.
  • +
  • Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks.
  • +
  • DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability.
  • +
+

Example

+
let x: Int = 10;
while (x > 0) {
// Bad: x is not changed due looping
send(SendParameters{ to: sender(), ... });
}
+

Use instead:

+
let x: Int = 10;
while (x > 0) {
send(SendParameters{ to: sender(), ... });
x = x - 1;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/ZeroAddress/index.html b/tools/misti/docs/0.2.0/detectors/ZeroAddress/index.html new file mode 100644 index 000000000..90f77d295 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/ZeroAddress/index.html @@ -0,0 +1,31 @@ + + + + + +Zero Address | Misti + + + + +
Version: 0.2.0

Zero Address

+

A detector that identifies uses of the zero address.

+

Why is it bad?

+

Using the zero address in smart contracts is typically problematic because it can be +exploited as a default or uninitialized address, leading to unintended transfers and +security vulnerabilities. Additionally, operations involving the zero address can +result in loss of funds or tokens, as there is no private key to access this address.

+

Example

+
contract Proxy {
to: Address;
init() {
// Warning: Insecure usage of zero address as default value
self.to = newAddress(0, 0);
}
fun setAddress(to: Address) {
self.to = to
}
}
+

Use instead:

+
contract Proxy {
to: Address;
init(to: Address) {
// Fixed: Using the input value on initializaiton.
self.to = to;
}
fun setAddress(to: Address) {
self.to = to
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/detectors/index.html b/tools/misti/docs/0.2.0/detectors/index.html new file mode 100644 index 000000000..19e0a66af --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/index.html @@ -0,0 +1,35 @@ + + + + + +Detectors Overview | Misti + + + + +
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/hacking/contributing/index.html b/tools/misti/docs/0.2.0/hacking/contributing/index.html new file mode 100644 index 000000000..d2a51f49f --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/contributing/index.html @@ -0,0 +1,66 @@ + + + + + +Contributing Guide | Misti + + + + +
Version: 0.2.0

Contributing Guide

+

Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.

+

Issues reporting

+

When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:

+
The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.
Please help us by publishing it and the input sources at:
https://github.com/nowarp/misti/issues/new.
+

We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users.

+

Documentation contribution

+

We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: nowarp.github.io Issues. Additionally, many documentation pages have an Edit button that allows you to make direct contributions easily.

+

Code contribution

+
    +
  1. +

    Navigate Issues and Find Tasks

    +
      +
    • Browse the issues here. Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues.
    • +
    • Choose an issue suitable for you and mention in the issue that you're working on it.
    • +
    +
  2. +
  3. +

    Implement Your Changes

    +
      +
    • Implement your changes. Feel free to ask questions in the issue if needed.
    • +
    +
  4. +
  5. +

    Ensure Tests Pass

    +
      +
    • Before creating a PR, make sure all tests and CI checks are passing by running: +
      yarn test-all
      +
    • +
    +
  6. +
  7. +

    Create a PR

    +
      +
    • Submit your pull request here
    • +
    +
  8. +
  9. +

    Add a CHANGELOG entry

    +
      +
    • Describe your changes in the CHANGELOG.md file according to the existing structure.
    • +
    +
  10. +
+

All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to HACKING.md.

+

Thank you for your contributions!

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/hacking/custom-detector/index.html b/tools/misti/docs/0.2.0/hacking/custom-detector/index.html new file mode 100644 index 000000000..e04302494 --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/custom-detector/index.html @@ -0,0 +1,32 @@ + + + + + +Custom Detector Guide | Misti + + + + +
Version: 0.2.0

Custom Detector Guide

+

Introduction

+

Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: Misti API Reference.

+

Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the Detector interface.

+

Writing a Detector

+

To write a custom detector, create a TypeScript file using the Misti API. Here's an example of how to implement a custom detector:

+
import { Detector } from "../../src/detectors/detector";
import { MistiContext } from "../../src/internals/context";
import { CompilationUnit } from "../../src/internals/ir";
import {
createError,
MistiTactError,
Severity,
} from "../../src/internals/errors";

/**
* An example of a custom detector that showcases the usage of the detector API.
*
* It reports all the contracts that don't have an explicit implementation of the init function.
*/
export class ImplicitInit extends Detector {
check(ctx: MistiContext, cu: CompilationUnit): MistiTactError[] {
return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {
if (!cu.findMethodCFGByName(contract.name, "init")) {
const err = createError(
ctx,
`contract ${contract.name} doesn't define an init function`,
Severity.INFO,
contract.ref,
);
foundErrors.push(err);
}
return foundErrors;
}, [] as MistiTactError[]);
}
}
+

After creating a detector, you need to specify it in your configuration. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:

+
{
"detectors": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },

{ "className": "ImplicitInit", "modulePath": "/path/to/implicitInit.ts" }
],
"ignored_projects": [],
"verbosity": "default"
}

+

After this, you could run the created detector specifying a path to it: --config path/to/mistiConfig.json test/projects/simple/tactConfig.json.

+

Example Detectors

+

The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the examples directory in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/hacking/design/index.html b/tools/misti/docs/0.2.0/hacking/design/index.html new file mode 100644 index 000000000..26f42cbec --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/design/index.html @@ -0,0 +1,34 @@ + + + + + +Design Overview | Misti + + + + +
Version: 0.2.0

Design Overview

+

Static Analysis

+

Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues.

+

Souffle Datalog Solver

+

Misti leverages the Souffle Datalog solver, an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases.

+

Dataflow Analysis in Misti

+

Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code.

+

References

+

For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:

+ +

These resources provide a solid foundation in the theory and practice of static and dataflow analysis.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/hacking/souffle/index.html b/tools/misti/docs/0.2.0/hacking/souffle/index.html new file mode 100644 index 000000000..5c067c2d3 --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/souffle/index.html @@ -0,0 +1,38 @@ + + + + + +Soufflé Integration Guide | Misti + + + + +
Version: 0.2.0

Soufflé Integration Guide

+

What is Soufflé?

+

Soufflé is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Soufflé, Misti can perform deep and scalable analyses of smart contracts.

+

Benefits of Using Soufflé for Static Analysis

+

Soufflé allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Soufflé program might be more straightforward then implementing a complex transfer function in for a classic monotone framework.

+

Soufflé Integration in Misti

+

The API for interacting with Soufflé in Misti is detailed here.

+

Creating Soufflé Programs

+

To create a Soufflé program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:

+
addDecls(ctx: Context<SrcInfo>) {
ctx.add(
Relation.from(
"varDecl",
[
["var", FactType.Symbol],
["func", FactType.Symbol],
],
undefined,
),
);
// other declarations
}
+
addRules(ctx: Context<SrcInfo>) {
// readOnly(var, func) :-
// varDecl(var, func),
// !varAssign(var, func),
// !varUse(var, func).
ctx.add(
Rule.from(
[makeAtom("readOnly", ["var", "func"])],
makeRuleBody(makeAtom("varDecl", ["var", "func"])),
makeRuleBody(makeAtom("varAssign", ["var", "func"]), {
negated: true,
}),
makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),
),
);
}
+

Generating Facts and Executing Soufflé

+

After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Soufflé executor to run the analysis:

+
const executor = ctx.config.soufflePath
? new Executor<SrcInfo>({
inputDir: ctx.config.soufflePath,
outputDir: ctx.config.soufflePath,
})
: new Executor<SrcInfo>();

const result = executor.executeSync(program);

if (!result.success) {
throw new Error(
`Error executing Soufflé for ${this.id}:\n${result.stderr}`,
);
}

const warnings = Array.from(result.results.entries.values()).map((fact) => {
// raise warnings
});
+

Learning from Existing Code

+

We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Soufflé with Misti. This will help you understand the intricacies of generating IR and executing Soufflé programs effectively.

+

Further Reading

+

For a deeper understanding of static analysis using Soufflé, refer to the textbook Program Analysis: An Appetizer by Flemming Nielson and Hanne Riis Nielson. It discusses Soufflé-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/hacking/tools/index.html b/tools/misti/docs/0.2.0/hacking/tools/index.html new file mode 100644 index 000000000..b3bb8a73a --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/tools/index.html @@ -0,0 +1,51 @@ + + + + + +Tools Guide | Misti + + + + +
Version: 0.2.0

Tools Guide

+

This page describes the internal analyzer tools available in Misti to aid in development and debugging.

+

CFG Dump

+

Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts.

+

Usage

+

To dump the CFG in JSON format, use the following command:

+
npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in DOT format, use the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Converting DOT to SVG

+

To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use Graphviz with the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot
dot -Tsvg output.dot -o output.svg
+

Viewing the SVG

+

To view the SVG file in Firefox, use the following command:

+
firefox output.svg
+

For example, for the following contract:

+
fun test(): Int {
let sum: Int = 0;
let i: Int = 0;
repeat (10) {
i = i + 1;
sum = sum + i;
}
return sum;
}
+

The following CFG will be generated:

+

CFG Example

+

VS Code Plugin

+

For real-time visualization of DOT files, you can use one of the available Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer.

    +
  • +
  • +

    DOT Dumps: These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/index.html b/tools/misti/docs/0.2.0/index.html new file mode 100644 index 000000000..ba3dcc045 --- /dev/null +++ b/tools/misti/docs/0.2.0/index.html @@ -0,0 +1,37 @@ + + + + + +Introduction | Misti + + + + +
Version: 0.2.0

Introduction

Misti is a static analysis tool designed for smart contracts on the TON blockchain.

+

Language Support:

+ +

Use Cases

+

Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:

+
    +
  • Detect Vulnerabilities: Identify and fix potential security flaws early in the development cycle.
  • +
  • Improve Code Quality: Maintain high standards by catching bugs and enforcing best practices automatically.
  • +
  • Streamline Development: Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.
  • +
  • Custom Detectors: Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.
  • +
+

Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow.

+

Funding

+

Misti has been funded by TON Foundation. This support has enabled us to develop and maintain the tool.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/tutorial/ci-cd/index.html b/tools/misti/docs/0.2.0/tutorial/ci-cd/index.html new file mode 100644 index 000000000..6d1f656f0 --- /dev/null +++ b/tools/misti/docs/0.2.0/tutorial/ci-cd/index.html @@ -0,0 +1,33 @@ + + + + + +Integrating Misti into CI/CD | Misti + + + + +
Version: 0.2.0

Integrating Misti into CI/CD

+

Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.

+

GitHub Actions

+

To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:

+

1. Open your GitHub repository

+

2. Create or edit the GitHub Actions workflow YAML file

+

It could be located at e.g., .github/workflows/main.yml.

+

3. Add the step to run Misti to your YAML file

+

For example:

+
name: Run Misti
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install dependencies
run: npm install

- name: Run Misti
run: npx misti /path/to/your/tact.config.json
+

The npx misti /path/to/your/tact.config.json command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail.

+

4. Adjusting the Misti Configuration

+

If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the Configuration section for more details on how to customize your settings.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/tutorial/configuration/index.html b/tools/misti/docs/0.2.0/tutorial/configuration/index.html new file mode 100644 index 000000000..f7440fb2c --- /dev/null +++ b/tools/misti/docs/0.2.0/tutorial/configuration/index.html @@ -0,0 +1,60 @@ + + + + + +Configuration | Misti + + + + +
Version: 0.2.0

Configuration

+

This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.

+

Configuration Options

+
    +
  • +

    detectors: List of detectors to run. Each detector can be specified with a className and optionally a modulePath if it’s a custom detector.

    +
      +
    • className (string, required): The class name of the detector.
    • +
    • modulePath (string, optional): The file path of the detector module.
    • +
    +
  • +
  • +

    ignored_projects (array of strings, optional): List of Tact projects to ignore during analysis.

    +
  • +
  • +

    soufflePath (string, optional): Directory to save generated Soufflé files which is helpful for debugging purposes. If not set, a temporary directory will be used.

    +
  • +
  • +

    tactStdlibPath (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used.

    +
  • +
  • +

    unusedPrefix (string, default: "_"): Identifiers starting with this prefix won't be reported as unused by built-in detectors.

    +
  • +
  • +

    verbosity (string, optional): Verbosity level of the logs. Possible values are quiet, debug, and default.

    +
  • +
+

Running Misti with Configuration

+

To run Misti with the specified configuration file, use the following command:

+
npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json
+

This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration.

+

Default Configuration File

+

By default, Misti enables all built-in detectors. Below is an example of the default configuration file:

+
{
"detectorsEnabled": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },
{ "className": "BranchDuplicate" },
{ "className": "FieldDoubleInit" },
{ "className": "PreferAugmentedAssign" }
],
"ignoredProjects": [],
"unusedPrefix": "_",
"verbosity": "default"
}
+

All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: configSchema.json.

+

You can always dump the Misti configuration file in use by passing the --dump-config option in the CLI:

+
npx misti --dump-config test/projects/simple/tactConfig.json
+

If there is no Misti config in the simple directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors.

+

Getting Help

+

If you need assistance or encounter any issues, please create an issue on GitHub at nowarp/misti or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.0/tutorial/getting-started/index.html b/tools/misti/docs/0.2.0/tutorial/getting-started/index.html new file mode 100644 index 000000000..960ca1126 --- /dev/null +++ b/tools/misti/docs/0.2.0/tutorial/getting-started/index.html @@ -0,0 +1,49 @@ + + + + + +Getting started | Misti + + + + +
Version: 0.2.0

Getting started

+

This guide will walk you through the steps to install and set up the Misti static analyzer.

+

Prerequisites

+

Before you begin, ensure you have the following software installed on your system:

+ +

Installation

+

Misti is distributed via npm and should be added to your Tact project in the same way as Tact itself:

+
yarn add @nowarp/misti
+

Using Development Version

+

The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis.

+

To install the latest development version you should:

+
    +
  1. Clone Misti: git clone https://github.com/nowarp/misti
  2. +
  3. Build it: cd misti && yarn install && yarn build
  4. +
  5. Use it in your Tact project: cd /path/to/tact/project && yarn add file:/path/to/misti
  6. +
+

Running the analysis

+

Run Misti by specifying a Tact project configuration:

+
npx misti test/projects/simple/tactConfig.json
+

This will highlight any warnings the analyzer found.

+

You can also add a script to your package.json to simplify running the linting process:

+
{
"scripts": {
"lint": "npx misti test/projects/simple/tactConfig.json"
}
}
+

Troubleshooting

+

If you encounter any issues during the installation process, feel free to create an issue or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/BranchDuplicate/index.html b/tools/misti/docs/0.2.1/detectors/BranchDuplicate/index.html new file mode 100644 index 000000000..0ca2c2595 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/BranchDuplicate/index.html @@ -0,0 +1,33 @@ + + + + + +Branch Duplicate | Misti + + + + +
Version: 0.2.1

Branch Duplicate

+

Detector that reports duplicated code in conditional branches.

+

Why is it bad?

+

Duplicated code in branches is bad because it:

+
    +
  1. Reduces Readability: Repetition makes the code harder to understand.
  2. +
  3. Increases Maintenance: Changes must be made in multiple places, risking errors.
  4. +
  5. Signals Poor Design: It suggests missed opportunities for cleaner, more abstract code.
  6. +
+

Example

+
if (a > 42) {
a = 43; // bad: duplicated code
} else {
a = 43;
}
+

Use instead:

+
if (a > 42) {
a = inc(b); // ok
} else {
a = 43;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/ConstantAddress/index.html b/tools/misti/docs/0.2.1/detectors/ConstantAddress/index.html new file mode 100644 index 000000000..bec382fde --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/ConstantAddress/index.html @@ -0,0 +1,31 @@ + + + + + +Constant Address | Misti + + + + +
Version: 0.2.1

Constant Address

+

An optional detector that highlights all the constant addresses appearing in the source code.

+

Why is it bad?

+

Using hardcoded addresses can sometimes indicate poor contract design. +Some constant addresses may need to be set dynamically, e.g., using +contractAddress, or at least have a way to change them at runtime, for +example, when upgrading a contract.

+

Example

+
contract Main {
proxy: Address;
init() {
// Bad: Constant address highlighted by the analyzer.
self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");
}
}
+

Use instead:

+
contract Main {
proxy: Address;
init() {
let proxy: Proxy = initOf Proxy(myAddress());
// OK: Address depends on how the proxy contact has been deployed
self.proxy = contractAddress(proxy);
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply/index.html b/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply/index.html new file mode 100644 index 000000000..010416674 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,34 @@ + + + + + +Divide before Multiply | Misti + + + + +
Version: 0.2.1

Divide before Multiply

+

A detector that identifies and corrects instances of division before multiplication to +ensure accurate mathematical operations.

+

Why is it bad?

+

Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:

+
    +
  • Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers.
  • +
  • Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations.
  • +
  • Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging.
  • +
+

Example

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Bad: Division before multiplication
let result: Int = a / b * c;
+

Use instead:

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Correct: Multiplication before division
let result: Int = a * c / b;
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/DumpIsUsed/index.html b/tools/misti/docs/0.2.1/detectors/DumpIsUsed/index.html new file mode 100644 index 000000000..7bd3851b8 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/DumpIsUsed/index.html @@ -0,0 +1,28 @@ + + + + + +dump Is Used | Misti + + + + +
Version: 0.2.1

dump Is Used

+

An optional detector that highlights all the dump function calls.

+

Why is it bad?

+

The dump function is a debug print that shouldn't be in the final code. Even though the compiler removes it in production, its presence suggests the developer was debugging something. This can flag areas where issues might exist, so auditors should take a closer look at these parts of the code.

+

Example

+
fun test(): Int {
// ... other computations
let combined: Int = (RANDOM_SEED >> half_shift) &
(MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;
dump(combined); // Suspicious: Highlighted by the detector
}
+

Use instead:

+
fun test(): Int {
// ... other computations
let combined: Int = this.seed ^ shift_mask
// OK: The code was reviewed and simplified; `dump` was removed
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/FieldDoubleInit/index.html b/tools/misti/docs/0.2.1/detectors/FieldDoubleInit/index.html new file mode 100644 index 000000000..2aa826e00 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/FieldDoubleInit/index.html @@ -0,0 +1,28 @@ + + + + + +Field Initialized Twice | Misti + + + + +
Version: 0.2.1

Field Initialized Twice

+

A detector that highlights cases where a field is initialized both in the init function and at the point of definition.

+

Why is it bad?

+

Double initialization of fields can either be a programmer's mistake or simply a waste of gas. It is always preferred to initialize values in the field declaration if they have a compile-time evaluatable default value, or in the init function if they must be initialized dynamically.

+

Example

+
contract Test {
a: Int = 0; // Bad
init(x: Int) { self.a = x }
}
+

Use instead:

+
contract Test {
a: Int; // Fixed
init(x: Int) { self.a = x }
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables/index.html b/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables/index.html new file mode 100644 index 000000000..e76c1b0de --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,30 @@ + + + + + +Never-accessed Variables | Misti + + + + +
Version: 0.2.1

Never-accessed Variables

+

A detector that identifies write-only or unused variables, fields and constants.

+

Why is it bad?

+

These variables are either assigned but never used in any meaningful computation, +or they are declared and never used at all, which may indicate redundant code +or an incomplete implementation of the intended logic.

+

Example

+
// Error: the developer forgot to use the constant
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+

Use instead:

+
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
// OK: Fixed after the linter highlighted this warning
require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign/index.html b/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign/index.html new file mode 100644 index 000000000..f55914310 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,28 @@ + + + + + +Prefer Augmented Assignment | Misti + + + + +
Version: 0.2.1

Prefer Augmented Assignment

+

Detects non-idiomatic statements that can be written using augmented assignment operators like +=, -=, etc.

+

Why is it bad?

+

Using augmented assignment operations improves the readability of the source code and reduces the risk of mistakes, such as those that occur during copy-pasting and refactoring code.

+

Example

+
msgValue = (msgValue - ctx.readForwardFee());
+

Use instead:

+
msgValue -= ctx.readForwardFee());
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables/index.html b/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables/index.html new file mode 100644 index 000000000..a80979ad2 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,29 @@ + + + + + +Read-only Variables | Misti + + + + +
Version: 0.2.1

Read-only Variables

+

A detector that identifies read-only variables and fields.

+

Why is it bad?

+

These variables could typically be replaced with constants to optimize performance. +Alternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally.

+

Example

+
fun calculateFinalPrice(price: Int): Int {
// Warning: the developer uses a read-only variable that could be a constant
let DISCOUNT_AMOUNT: Int = 10;
return price - DISCOUNT_AMOUNT;
}
+

Use instead:

+
const DISCOUNT_AMOUNT: Int = 10;

fun calculateFinalPrice(price: Int): Int {
// OK: Fixed after the linter highlighted this warning
return price - DISCOUNT_AMOUNT;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/UnboundLoops/index.html b/tools/misti/docs/0.2.1/detectors/UnboundLoops/index.html new file mode 100644 index 000000000..d7c8c22bc --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/UnboundLoops/index.html @@ -0,0 +1,33 @@ + + + + + +Unbound Loops | Misti + + + + +
Version: 0.2.1

Unbound Loops

+

A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.

+

Why is it bad?

+

An unbounded loop can be problematic for several reasons:

+
    +
  • Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult.
  • +
  • Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks.
  • +
  • DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability.
  • +
+

Example

+
let x: Int = 10;
while (x > 0) {
// Bad: x is not changed due looping
send(SendParameters{ to: sender(), ... });
}
+

Use instead:

+
let x: Int = 10;
while (x > 0) {
send(SendParameters{ to: sender(), ... });
x = x - 1;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/ZeroAddress/index.html b/tools/misti/docs/0.2.1/detectors/ZeroAddress/index.html new file mode 100644 index 000000000..dfa062780 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/ZeroAddress/index.html @@ -0,0 +1,31 @@ + + + + + +Zero Address | Misti + + + + +
Version: 0.2.1

Zero Address

+

A detector that identifies uses of the zero address.

+

Why is it bad?

+

Using the zero address in smart contracts is typically problematic because it can be +exploited as a default or uninitialized address, leading to unintended transfers and +security vulnerabilities. Additionally, operations involving the zero address can +result in loss of funds or tokens, as there is no private key to access this address.

+

Example

+
contract Proxy {
to: Address;
init() {
// Warning: Insecure usage of zero address as default value
self.to = newAddress(0, 0);
}
fun setAddress(to: Address) {
self.to = to
}
}
+

Use instead:

+
contract Proxy {
to: Address;
init(to: Address) {
// Fixed: Using the input value on initializaiton.
self.to = to;
}
fun setAddress(to: Address) {
self.to = to
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/detectors/index.html b/tools/misti/docs/0.2.1/detectors/index.html new file mode 100644 index 000000000..872eaa3e0 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/index.html @@ -0,0 +1,35 @@ + + + + + +Detectors Overview | Misti + + + + +
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/hacking/contributing/index.html b/tools/misti/docs/0.2.1/hacking/contributing/index.html new file mode 100644 index 000000000..c1e3209a0 --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/contributing/index.html @@ -0,0 +1,66 @@ + + + + + +Contributing Guide | Misti + + + + +
Version: 0.2.1

Contributing Guide

+

Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.

+

Issues reporting

+

When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:

+
The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.
Please help us by publishing it and the input sources at:
https://github.com/nowarp/misti/issues/new.
+

We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users.

+

Documentation contribution

+

We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: nowarp.github.io Issues. Additionally, many documentation pages have an Edit button that allows you to make direct contributions easily.

+

Code contribution

+
    +
  1. +

    Navigate Issues and Find Tasks

    +
      +
    • Browse the issues here. Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues.
    • +
    • Choose an issue suitable for you and mention in the issue that you're working on it.
    • +
    +
  2. +
  3. +

    Implement Your Changes

    +
      +
    • Implement your changes. Feel free to ask questions in the issue if needed.
    • +
    +
  4. +
  5. +

    Ensure Tests Pass

    +
      +
    • Before creating a PR, make sure all tests and CI checks are passing by running: +
      yarn test-all
      +
    • +
    +
  6. +
  7. +

    Create a PR

    +
      +
    • Submit your pull request here
    • +
    +
  8. +
  9. +

    Add a CHANGELOG entry

    +
      +
    • Describe your changes in the CHANGELOG.md file according to the existing structure.
    • +
    +
  10. +
+

All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to HACKING.md.

+

Thank you for your contributions!

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/hacking/custom-detector/index.html b/tools/misti/docs/0.2.1/hacking/custom-detector/index.html new file mode 100644 index 000000000..9d5cd8de5 --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/custom-detector/index.html @@ -0,0 +1,32 @@ + + + + + +Custom Detector Guide | Misti + + + + +
Version: 0.2.1

Custom Detector Guide

+

Introduction

+

Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: Misti API Reference.

+

Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the Detector interface.

+

Writing a Detector

+

To write a custom detector, create a TypeScript file using the Misti API. Here's an example of how to implement a custom detector:

+
import { Detector } from "../../src/detectors/detector";
import { MistiContext } from "../../src/internals/context";
import { CompilationUnit } from "../../src/internals/ir";
import {
createError,
MistiTactError,
Severity,
} from "../../src/internals/errors";

/**
* An example of a custom detector that showcases the usage of the detector API.
*
* It reports all the contracts that don't have an explicit implementation of the init function.
*/
export class ImplicitInit extends Detector {
check(ctx: MistiContext, cu: CompilationUnit): MistiTactError[] {
return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {
if (!cu.findMethodCFGByName(contract.name, "init")) {
const err = createError(
ctx,
`contract ${contract.name} doesn't define an init function`,
Severity.INFO,
contract.ref,
);
foundErrors.push(err);
}
return foundErrors;
}, [] as MistiTactError[]);
}
}
+

After creating a detector, you need to specify it in your configuration. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:

+
{
"detectors": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },

{ "className": "ImplicitInit", "modulePath": "/path/to/implicitInit.ts" }
],
"ignored_projects": [],
"verbosity": "default"
}

+

After this, you could run the created detector specifying a path to it: --config path/to/mistiConfig.json test/projects/simple/tactConfig.json.

+

Example Detectors

+

The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the examples directory in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/hacking/design/index.html b/tools/misti/docs/0.2.1/hacking/design/index.html new file mode 100644 index 000000000..204cdfdc4 --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/design/index.html @@ -0,0 +1,34 @@ + + + + + +Design Overview | Misti + + + + +
Version: 0.2.1

Design Overview

+

Static Analysis

+

Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues.

+

Souffle Datalog Solver

+

Misti leverages the Souffle Datalog solver, an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases.

+

Dataflow Analysis in Misti

+

Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code.

+

References

+

For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:

+ +

These resources provide a solid foundation in the theory and practice of static and dataflow analysis.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/hacking/souffle/index.html b/tools/misti/docs/0.2.1/hacking/souffle/index.html new file mode 100644 index 000000000..9259ed4e5 --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/souffle/index.html @@ -0,0 +1,38 @@ + + + + + +Soufflé Integration Guide | Misti + + + + +
Version: 0.2.1

Soufflé Integration Guide

+

What is Soufflé?

+

Soufflé is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Soufflé, Misti can perform deep and scalable analyses of smart contracts.

+

Benefits of Using Soufflé for Static Analysis

+

Soufflé allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Soufflé program might be more straightforward then implementing a complex transfer function in for a classic monotone framework.

+

Soufflé Integration in Misti

+

The API for interacting with Soufflé in Misti is detailed here.

+

Creating Soufflé Programs

+

To create a Soufflé program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:

+
addDecls(ctx: Context<SrcInfo>) {
ctx.add(
Relation.from(
"varDecl",
[
["var", FactType.Symbol],
["func", FactType.Symbol],
],
undefined,
),
);
// other declarations
}
+
addRules(ctx: Context<SrcInfo>) {
// readOnly(var, func) :-
// varDecl(var, func),
// !varAssign(var, func),
// !varUse(var, func).
ctx.add(
Rule.from(
[makeAtom("readOnly", ["var", "func"])],
makeRuleBody(makeAtom("varDecl", ["var", "func"])),
makeRuleBody(makeAtom("varAssign", ["var", "func"]), {
negated: true,
}),
makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),
),
);
}
+

Generating Facts and Executing Soufflé

+

After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Soufflé executor to run the analysis:

+
const executor = ctx.config.soufflePath
? new Executor<SrcInfo>({
inputDir: ctx.config.soufflePath,
outputDir: ctx.config.soufflePath,
})
: new Executor<SrcInfo>();

const result = executor.executeSync(program);

if (!result.success) {
throw new Error(
`Error executing Soufflé for ${this.id}:\n${result.stderr}`,
);
}

const warnings = Array.from(result.results.entries.values()).map((fact) => {
// raise warnings
});
+

Learning from Existing Code

+

We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Soufflé with Misti. This will help you understand the intricacies of generating IR and executing Soufflé programs effectively.

+

Further Reading

+

For a deeper understanding of static analysis using Soufflé, refer to the textbook Program Analysis: An Appetizer by Flemming Nielson and Hanne Riis Nielson. It discusses Soufflé-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/hacking/tools/index.html b/tools/misti/docs/0.2.1/hacking/tools/index.html new file mode 100644 index 000000000..a30579eb5 --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/tools/index.html @@ -0,0 +1,51 @@ + + + + + +Tools Guide | Misti + + + + +
Version: 0.2.1

Tools Guide

+

This page describes the internal analyzer tools available in Misti to aid in development and debugging.

+

CFG Dump

+

Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts.

+

Usage

+

To dump the CFG in JSON format, use the following command:

+
npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in DOT format, use the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Converting DOT to SVG

+

To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use Graphviz with the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot
dot -Tsvg output.dot -o output.svg
+

Viewing the SVG

+

To view the SVG file in Firefox, use the following command:

+
firefox output.svg
+

For example, for the following contract:

+
fun test(): Int {
let sum: Int = 0;
let i: Int = 0;
repeat (10) {
i = i + 1;
sum = sum + i;
}
return sum;
}
+

The following CFG will be generated:

+

CFG Example

+

VS Code Plugin

+

For real-time visualization of DOT files, you can use one of the available Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer.

    +
  • +
  • +

    DOT Dumps: These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/index.html b/tools/misti/docs/0.2.1/index.html new file mode 100644 index 000000000..5e76de153 --- /dev/null +++ b/tools/misti/docs/0.2.1/index.html @@ -0,0 +1,37 @@ + + + + + +Introduction | Misti + + + + +
Version: 0.2.1

Introduction

Misti is a static analysis tool designed for smart contracts on the TON blockchain.

+

Language Support:

+ +

Use Cases

+

Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:

+
    +
  • Detect Vulnerabilities: Identify and fix potential security flaws early in the development cycle.
  • +
  • Improve Code Quality: Maintain high standards by catching bugs and enforcing best practices automatically.
  • +
  • Streamline Development: Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.
  • +
  • Custom Detectors: Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.
  • +
+

Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow.

+

Funding

+

Misti has been funded by TON Foundation. This support has enabled us to develop and maintain the tool.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/tutorial/ci-cd/index.html b/tools/misti/docs/0.2.1/tutorial/ci-cd/index.html new file mode 100644 index 000000000..dcef1bf4e --- /dev/null +++ b/tools/misti/docs/0.2.1/tutorial/ci-cd/index.html @@ -0,0 +1,33 @@ + + + + + +Integrating Misti into CI/CD | Misti + + + + +
Version: 0.2.1

Integrating Misti into CI/CD

+

Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.

+

GitHub Actions

+

To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:

+

1. Open your GitHub repository

+

2. Create or edit the GitHub Actions workflow YAML file

+

It could be located at e.g., .github/workflows/main.yml.

+

3. Add the step to run Misti to your YAML file

+

For example:

+
name: Run Misti
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install dependencies
run: npm install

- name: Run Misti
run: npx misti /path/to/your/tact.config.json
+

The npx misti /path/to/your/tact.config.json command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail.

+

4. Adjusting the Misti Configuration

+

If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the Configuration section for more details on how to customize your settings.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/tutorial/configuration/index.html b/tools/misti/docs/0.2.1/tutorial/configuration/index.html new file mode 100644 index 000000000..e830f0cde --- /dev/null +++ b/tools/misti/docs/0.2.1/tutorial/configuration/index.html @@ -0,0 +1,60 @@ + + + + + +Configuration | Misti + + + + +
Version: 0.2.1

Configuration

+

This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.

+

Configuration Options

+
    +
  • +

    detectors: List of detectors to run. Each detector can be specified with a className and optionally a modulePath if it’s a custom detector.

    +
      +
    • className (string, required): The class name of the detector.
    • +
    • modulePath (string, optional): The file path of the detector module.
    • +
    +
  • +
  • +

    ignored_projects (array of strings, optional): List of Tact projects to ignore during analysis.

    +
  • +
  • +

    soufflePath (string, optional): Directory to save generated Soufflé files which is helpful for debugging purposes. If not set, a temporary directory will be used.

    +
  • +
  • +

    tactStdlibPath (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used.

    +
  • +
  • +

    unusedPrefix (string, default: "_"): Identifiers starting with this prefix won't be reported as unused by built-in detectors.

    +
  • +
  • +

    verbosity (string, optional): Verbosity level of the logs. Possible values are quiet, debug, and default.

    +
  • +
+

Running Misti with Configuration

+

To run Misti with the specified configuration file, use the following command:

+
npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json
+

This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration.

+

Default Configuration File

+

By default, Misti enables all built-in detectors. Below is an example of the default configuration file:

+
{
"detectorsEnabled": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },
{ "className": "BranchDuplicate" },
{ "className": "FieldDoubleInit" },
{ "className": "PreferAugmentedAssign" }
],
"ignoredProjects": [],
"unusedPrefix": "_",
"verbosity": "default"
}
+

All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: configSchema.json.

+

You can always dump the Misti configuration file in use by passing the --dump-config option in the CLI:

+
npx misti --dump-config test/projects/simple/tactConfig.json
+

If there is no Misti config in the simple directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors.

+

Getting Help

+

If you need assistance or encounter any issues, please create an issue on GitHub at nowarp/misti or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.1/tutorial/getting-started/index.html b/tools/misti/docs/0.2.1/tutorial/getting-started/index.html new file mode 100644 index 000000000..59f7d096f --- /dev/null +++ b/tools/misti/docs/0.2.1/tutorial/getting-started/index.html @@ -0,0 +1,49 @@ + + + + + +Getting started | Misti + + + + +
Version: 0.2.1

Getting started

+

This guide will walk you through the steps to install and set up the Misti static analyzer.

+

Prerequisites

+

Before you begin, ensure you have the following software installed on your system:

+ +

Installation

+

Misti is distributed via npm and should be added to your Tact project in the same way as Tact itself:

+
yarn add @nowarp/misti
+

Using Development Version

+

The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis.

+

To install the latest development version you should:

+
    +
  1. Clone Misti: git clone https://github.com/nowarp/misti
  2. +
  3. Build it: cd misti && yarn install && yarn build
  4. +
  5. Use it in your Tact project: cd /path/to/tact/project && yarn add file:/path/to/misti
  6. +
+

Running the analysis

+

Run Misti by specifying a Tact project configuration:

+
npx misti test/projects/simple/tactConfig.json
+

This will highlight any warnings the analyzer found.

+

You can also add a script to your package.json to simplify running the linting process:

+
{
"scripts": {
"lint": "npx misti test/projects/simple/tactConfig.json"
}
}
+

Troubleshooting

+

If you encounter any issues during the installation process, feel free to create an issue or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/BranchDuplicate/index.html b/tools/misti/docs/0.2.2/detectors/BranchDuplicate/index.html new file mode 100644 index 000000000..95a0dab82 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/BranchDuplicate/index.html @@ -0,0 +1,33 @@ + + + + + +Branch Duplicate | Misti + + + + +
Version: 0.2.2

Branch Duplicate

+

Detector that reports duplicated code in conditional branches.

+

Why is it bad?

+

Duplicated code in branches is bad because it:

+
    +
  1. Reduces Readability: Repetition makes the code harder to understand.
  2. +
  3. Increases Maintenance: Changes must be made in multiple places, risking errors.
  4. +
  5. Signals Poor Design: It suggests missed opportunities for cleaner, more abstract code.
  6. +
+

Example

+
if (a > 42) {
a = 43; // bad: duplicated code
} else {
a = 43;
}
+

Use instead:

+
if (a > 42) {
a = inc(b); // ok
} else {
a = 43;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/ConstantAddress/index.html b/tools/misti/docs/0.2.2/detectors/ConstantAddress/index.html new file mode 100644 index 000000000..0e6909978 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/ConstantAddress/index.html @@ -0,0 +1,31 @@ + + + + + +Constant Address | Misti + + + + +
Version: 0.2.2

Constant Address

+

An optional detector that highlights all the constant addresses appearing in the source code.

+

Why is it bad?

+

Using hardcoded addresses can sometimes indicate poor contract design. +Some constant addresses may need to be set dynamically, e.g., using +contractAddress, or at least have a way to change them at runtime, for +example, when upgrading a contract.

+

Example

+
contract Main {
proxy: Address;
init() {
// Bad: Constant address highlighted by the analyzer.
self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");
}
}
+

Use instead:

+
contract Main {
proxy: Address;
init() {
let proxy: Proxy = initOf Proxy(myAddress());
// OK: Address depends on how the proxy contact has been deployed
self.proxy = contractAddress(proxy);
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply/index.html b/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply/index.html new file mode 100644 index 000000000..424150279 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,34 @@ + + + + + +Divide before Multiply | Misti + + + + +
Version: 0.2.2

Divide before Multiply

+

A detector that identifies and corrects instances of division before multiplication to +ensure accurate mathematical operations.

+

Why is it bad?

+

Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:

+
    +
  • Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers.
  • +
  • Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations.
  • +
  • Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging.
  • +
+

Example

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Bad: Division before multiplication
let result: Int = a / b * c;
+

Use instead:

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Correct: Multiplication before division
let result: Int = a * c / b;
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/DumpIsUsed/index.html b/tools/misti/docs/0.2.2/detectors/DumpIsUsed/index.html new file mode 100644 index 000000000..9c89e5d03 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/DumpIsUsed/index.html @@ -0,0 +1,28 @@ + + + + + +dump Is Used | Misti + + + + +
Version: 0.2.2

dump Is Used

+

An optional detector that highlights all the dump function calls.

+

Why is it bad?

+

The dump function is a debug print that shouldn't be in the final code. Even though the compiler removes it in production, its presence suggests the developer was debugging something. This can flag areas where issues might exist, so auditors should take a closer look at these parts of the code.

+

Example

+
fun test(): Int {
// ... other computations
let combined: Int = (RANDOM_SEED >> half_shift) &
(MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;
dump(combined); // Suspicious: Highlighted by the detector
}
+

Use instead:

+
fun test(): Int {
// ... other computations
let combined: Int = this.seed ^ shift_mask
// OK: The code was reviewed and simplified; `dump` was removed
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/FieldDoubleInit/index.html b/tools/misti/docs/0.2.2/detectors/FieldDoubleInit/index.html new file mode 100644 index 000000000..3434d71ee --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/FieldDoubleInit/index.html @@ -0,0 +1,28 @@ + + + + + +Field Initialized Twice | Misti + + + + +
Version: 0.2.2

Field Initialized Twice

+

A detector that highlights cases where a field is initialized both in the init function and at the point of definition.

+

Why is it bad?

+

Double initialization of fields can either be a programmer's mistake or simply a waste of gas. It is always preferred to initialize values in the field declaration if they have a compile-time evaluatable default value, or in the init function if they must be initialized dynamically.

+

Example

+
contract Test {
a: Int = 0; // Bad
init(x: Int) { self.a = x }
}
+

Use instead:

+
contract Test {
a: Int; // Fixed
init(x: Int) { self.a = x }
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables/index.html b/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables/index.html new file mode 100644 index 000000000..793281bdd --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,30 @@ + + + + + +Never-accessed Variables | Misti + + + + +
Version: 0.2.2

Never-accessed Variables

+

A detector that identifies write-only or unused variables, fields and constants.

+

Why is it bad?

+

These variables are either assigned but never used in any meaningful computation, +or they are declared and never used at all, which may indicate redundant code +or an incomplete implementation of the intended logic.

+

Example

+
// Error: the developer forgot to use the constant
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+

Use instead:

+
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
// OK: Fixed after the linter highlighted this warning
require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign/index.html b/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign/index.html new file mode 100644 index 000000000..f7e616348 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,28 @@ + + + + + +Prefer Augmented Assignment | Misti + + + + +
Version: 0.2.2

Prefer Augmented Assignment

+

Detects non-idiomatic statements that can be written using augmented assignment operators like +=, -=, etc.

+

Why is it bad?

+

Using augmented assignment operations improves the readability of the source code and reduces the risk of mistakes, such as those that occur during copy-pasting and refactoring code.

+

Example

+
msgValue = (msgValue - ctx.readForwardFee());
+

Use instead:

+
msgValue -= ctx.readForwardFee());
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables/index.html b/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables/index.html new file mode 100644 index 000000000..746d61886 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,29 @@ + + + + + +Read-only Variables | Misti + + + + +
Version: 0.2.2

Read-only Variables

+

A detector that identifies read-only variables and fields.

+

Why is it bad?

+

These variables could typically be replaced with constants to optimize performance. +Alternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally.

+

Example

+
fun calculateFinalPrice(price: Int): Int {
// Warning: the developer uses a read-only variable that could be a constant
let DISCOUNT_AMOUNT: Int = 10;
return price - DISCOUNT_AMOUNT;
}
+

Use instead:

+
const DISCOUNT_AMOUNT: Int = 10;

fun calculateFinalPrice(price: Int): Int {
// OK: Fixed after the linter highlighted this warning
return price - DISCOUNT_AMOUNT;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/UnboundLoops/index.html b/tools/misti/docs/0.2.2/detectors/UnboundLoops/index.html new file mode 100644 index 000000000..7c3942923 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/UnboundLoops/index.html @@ -0,0 +1,33 @@ + + + + + +Unbound Loops | Misti + + + + +
Version: 0.2.2

Unbound Loops

+

A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.

+

Why is it bad?

+

An unbounded loop can be problematic for several reasons:

+
    +
  • Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult.
  • +
  • Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks.
  • +
  • DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability.
  • +
+

Example

+
let x: Int = 10;
while (x > 0) {
// Bad: x is not changed due looping
send(SendParameters{ to: sender(), ... });
}
+

Use instead:

+
let x: Int = 10;
while (x > 0) {
send(SendParameters{ to: sender(), ... });
x = x - 1;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/ZeroAddress/index.html b/tools/misti/docs/0.2.2/detectors/ZeroAddress/index.html new file mode 100644 index 000000000..f806bbe41 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/ZeroAddress/index.html @@ -0,0 +1,31 @@ + + + + + +Zero Address | Misti + + + + +
Version: 0.2.2

Zero Address

+

A detector that identifies uses of the zero address.

+

Why is it bad?

+

Using the zero address in smart contracts is typically problematic because it can be +exploited as a default or uninitialized address, leading to unintended transfers and +security vulnerabilities. Additionally, operations involving the zero address can +result in loss of funds or tokens, as there is no private key to access this address.

+

Example

+
contract Proxy {
to: Address;
init() {
// Warning: Insecure usage of zero address as default value
self.to = newAddress(0, 0);
}
fun setAddress(to: Address) {
self.to = to
}
}
+

Use instead:

+
contract Proxy {
to: Address;
init(to: Address) {
// Fixed: Using the input value on initializaiton.
self.to = to;
}
fun setAddress(to: Address) {
self.to = to
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/detectors/index.html b/tools/misti/docs/0.2.2/detectors/index.html new file mode 100644 index 000000000..b225eab84 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/index.html @@ -0,0 +1,35 @@ + + + + + +Detectors Overview | Misti + + + + +
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/hacking/contributing/index.html b/tools/misti/docs/0.2.2/hacking/contributing/index.html new file mode 100644 index 000000000..bb5349c33 --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/contributing/index.html @@ -0,0 +1,66 @@ + + + + + +Contributing Guide | Misti + + + + +
Version: 0.2.2

Contributing Guide

+

Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.

+

Issues reporting

+

When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:

+
The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.
Please help us by publishing it and the input sources at:
https://github.com/nowarp/misti/issues/new.
+

We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users.

+

Documentation contribution

+

We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: nowarp.github.io Issues. Additionally, many documentation pages have an Edit button that allows you to make direct contributions easily.

+

Code contribution

+
    +
  1. +

    Navigate Issues and Find Tasks

    +
      +
    • Browse the issues here. Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues.
    • +
    • Choose an issue suitable for you and mention in the issue that you're working on it.
    • +
    +
  2. +
  3. +

    Implement Your Changes

    +
      +
    • Implement your changes. Feel free to ask questions in the issue if needed.
    • +
    +
  4. +
  5. +

    Ensure Tests Pass

    +
      +
    • Before creating a PR, make sure all tests and CI checks are passing by running: +
      yarn test-all
      +
    • +
    +
  6. +
  7. +

    Create a PR

    +
      +
    • Submit your pull request here
    • +
    +
  8. +
  9. +

    Add a CHANGELOG entry

    +
      +
    • Describe your changes in the CHANGELOG.md file according to the existing structure.
    • +
    +
  10. +
+

All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to HACKING.md.

+

Thank you for your contributions!

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/hacking/custom-detector/index.html b/tools/misti/docs/0.2.2/hacking/custom-detector/index.html new file mode 100644 index 000000000..a8308ab6b --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/custom-detector/index.html @@ -0,0 +1,32 @@ + + + + + +Custom Detector Guide | Misti + + + + +
Version: 0.2.2

Custom Detector Guide

+

Introduction

+

Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: Misti API Reference.

+

Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the Detector interface.

+

Writing a Detector

+

To write a custom detector, create a TypeScript file using the Misti API. Here's an example of how to implement a custom detector:

+
import { Detector } from "../../src/detectors/detector";
import { MistiContext } from "../../src/internals/context";
import { CompilationUnit } from "../../src/internals/ir";
import {
createError,
MistiTactError,
Severity,
} from "../../src/internals/errors";

/**
* An example of a custom detector that showcases the usage of the detector API.
*
* It reports all the contracts that don't have an explicit implementation of the init function.
*/
export class ImplicitInit extends Detector {
check(ctx: MistiContext, cu: CompilationUnit): MistiTactError[] {
return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {
if (!cu.findMethodCFGByName(contract.name, "init")) {
const err = createError(
ctx,
`contract ${contract.name} doesn't define an init function`,
Severity.INFO,
contract.ref,
);
foundErrors.push(err);
}
return foundErrors;
}, [] as MistiTactError[]);
}
}
+

After creating a detector, you need to specify it in your configuration. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:

+
{
"detectors": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },

{ "className": "ImplicitInit", "modulePath": "/path/to/implicitInit.ts" }
],
"ignored_projects": [],
"verbosity": "default"
}

+

After this, you could run the created detector specifying a path to it: --config path/to/mistiConfig.json test/projects/simple/tactConfig.json.

+

Example Detectors

+

The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the examples directory in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/hacking/design/index.html b/tools/misti/docs/0.2.2/hacking/design/index.html new file mode 100644 index 000000000..bb0214c67 --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/design/index.html @@ -0,0 +1,34 @@ + + + + + +Design Overview | Misti + + + + +
Version: 0.2.2

Design Overview

+

Static Analysis

+

Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues.

+

Souffle Datalog Solver

+

Misti leverages the Souffle Datalog solver, an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases.

+

Dataflow Analysis in Misti

+

Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code.

+

References

+

For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:

+ +

These resources provide a solid foundation in the theory and practice of static and dataflow analysis.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/hacking/souffle/index.html b/tools/misti/docs/0.2.2/hacking/souffle/index.html new file mode 100644 index 000000000..42b59967e --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/souffle/index.html @@ -0,0 +1,38 @@ + + + + + +Soufflé Integration Guide | Misti + + + + +
Version: 0.2.2

Soufflé Integration Guide

+

What is Soufflé?

+

Soufflé is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Soufflé, Misti can perform deep and scalable analyses of smart contracts.

+

Benefits of Using Soufflé for Static Analysis

+

Soufflé allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Soufflé program might be more straightforward then implementing a complex transfer function in for a classic monotone framework.

+

Soufflé Integration in Misti

+

The API for interacting with Soufflé in Misti is detailed here.

+

Creating Soufflé Programs

+

To create a Soufflé program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:

+
addDecls(ctx: Context<SrcInfo>) {
ctx.add(
Relation.from(
"varDecl",
[
["var", FactType.Symbol],
["func", FactType.Symbol],
],
undefined,
),
);
// other declarations
}
+
addRules(ctx: Context<SrcInfo>) {
// readOnly(var, func) :-
// varDecl(var, func),
// !varAssign(var, func),
// !varUse(var, func).
ctx.add(
Rule.from(
[makeAtom("readOnly", ["var", "func"])],
makeRuleBody(makeAtom("varDecl", ["var", "func"])),
makeRuleBody(makeAtom("varAssign", ["var", "func"]), {
negated: true,
}),
makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),
),
);
}
+

Generating Facts and Executing Soufflé

+

After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Soufflé executor to run the analysis:

+
const executor = ctx.config.soufflePath
? new Executor<SrcInfo>({
inputDir: ctx.config.soufflePath,
outputDir: ctx.config.soufflePath,
})
: new Executor<SrcInfo>();

const result = executor.executeSync(program);

if (!result.success) {
throw new Error(
`Error executing Soufflé for ${this.id}:\n${result.stderr}`,
);
}

const warnings = Array.from(result.results.entries.values()).map((fact) => {
// raise warnings
});
+

Learning from Existing Code

+

We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Soufflé with Misti. This will help you understand the intricacies of generating IR and executing Soufflé programs effectively.

+

Further Reading

+

For a deeper understanding of static analysis using Soufflé, refer to the textbook Program Analysis: An Appetizer by Flemming Nielson and Hanne Riis Nielson. It discusses Soufflé-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/hacking/tools/index.html b/tools/misti/docs/0.2.2/hacking/tools/index.html new file mode 100644 index 000000000..74a16cf88 --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/tools/index.html @@ -0,0 +1,51 @@ + + + + + +Tools Guide | Misti + + + + +
Version: 0.2.2

Tools Guide

+

This page describes the internal analyzer tools available in Misti to aid in development and debugging.

+

CFG Dump

+

Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts.

+

Usage

+

To dump the CFG in JSON format, use the following command:

+
npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in DOT format, use the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Converting DOT to SVG

+

To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use Graphviz with the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot
dot -Tsvg output.dot -o output.svg
+

Viewing the SVG

+

To view the SVG file in Firefox, use the following command:

+
firefox output.svg
+

For example, for the following contract:

+
fun test(): Int {
let sum: Int = 0;
let i: Int = 0;
repeat (10) {
i = i + 1;
sum = sum + i;
}
return sum;
}
+

The following CFG will be generated:

+

CFG Example

+

VS Code Plugin

+

For real-time visualization of DOT files, you can use one of the available Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer.

    +
  • +
  • +

    DOT Dumps: These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/index.html b/tools/misti/docs/0.2.2/index.html new file mode 100644 index 000000000..a7fa5ea3a --- /dev/null +++ b/tools/misti/docs/0.2.2/index.html @@ -0,0 +1,37 @@ + + + + + +Introduction | Misti + + + + +
Version: 0.2.2

Introduction

Misti is a static analysis tool designed for smart contracts on the TON blockchain.

+

Language Support:

+ +

Use Cases

+

Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:

+
    +
  • Detect Vulnerabilities: Identify and fix potential security flaws early in the development cycle.
  • +
  • Improve Code Quality: Maintain high standards by catching bugs and enforcing best practices automatically.
  • +
  • Streamline Development: Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.
  • +
  • Custom Detectors: Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.
  • +
+

Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow.

+

Funding

+

Misti has been funded by TON Foundation. This support has enabled us to develop and maintain the tool.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/tutorial/blueprint/index.html b/tools/misti/docs/0.2.2/tutorial/blueprint/index.html new file mode 100644 index 000000000..67e78e8dd --- /dev/null +++ b/tools/misti/docs/0.2.2/tutorial/blueprint/index.html @@ -0,0 +1,32 @@ + + + + + +Using Misti with Blueprint | Misti + + + + +
Version: 0.2.2

Using Misti with Blueprint

+

Blueprint is a development environment for writing, testing, and deploying TON smart contracts.

+

Misti can be used in Blueprint projects by leveraging the blueprint-misti plugin.

+

Getting started

+

Add the plugin and the recent version of Tact to the package.json of your Blueprint project by running:

+
yarn add @tact-lang/compiler
yarn add @nowarp/blueprint-misti
+

Then, add this configuration to blueprint.config.ts:

+
import { MistiPlugin } from '@nowarp/blueprint-misti';
export const config = {
plugins: [
new MistiPlugin(),
],
};
+

Now, try to run Misti:

+
yarn blueprint misti ./path/to/tact.config.json
+

Resources

+

For more information, please refer to the README of the blueprint-misti project. If you have any problems, feel free to reach out to us in the Misti discussion group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/tutorial/ci-cd/index.html b/tools/misti/docs/0.2.2/tutorial/ci-cd/index.html new file mode 100644 index 000000000..6ea10f949 --- /dev/null +++ b/tools/misti/docs/0.2.2/tutorial/ci-cd/index.html @@ -0,0 +1,33 @@ + + + + + +Integrating Misti into CI/CD | Misti + + + + +
Version: 0.2.2

Integrating Misti into CI/CD

+

Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.

+

GitHub Actions

+

To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:

+

1. Open your GitHub repository

+

2. Create or edit the GitHub Actions workflow YAML file

+

It could be located at e.g., .github/workflows/main.yml.

+

3. Add the step to run Misti to your YAML file

+

For example:

+
name: Run Misti
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install dependencies
run: npm install

- name: Run Misti
run: npx misti /path/to/your/tact.config.json
+

The npx misti /path/to/your/tact.config.json command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail.

+

4. Adjusting the Misti Configuration

+

If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the Configuration section for more details on how to customize your settings.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/tutorial/configuration/index.html b/tools/misti/docs/0.2.2/tutorial/configuration/index.html new file mode 100644 index 000000000..7c821d46e --- /dev/null +++ b/tools/misti/docs/0.2.2/tutorial/configuration/index.html @@ -0,0 +1,60 @@ + + + + + +Configuration | Misti + + + + +
Version: 0.2.2

Configuration

+

This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.

+

Configuration Options

+
    +
  • +

    detectors: List of detectors to run. Each detector can be specified with a className and optionally a modulePath if it’s a custom detector.

    +
      +
    • className (string, required): The class name of the detector.
    • +
    • modulePath (string, optional): The file path of the detector module.
    • +
    +
  • +
  • +

    ignored_projects (array of strings, optional): List of Tact projects to ignore during analysis.

    +
  • +
  • +

    soufflePath (string, optional): Directory to save generated Soufflé files which is helpful for debugging purposes. If not set, a temporary directory will be used.

    +
  • +
  • +

    tactStdlibPath (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used.

    +
  • +
  • +

    unusedPrefix (string, default: "_"): Identifiers starting with this prefix won't be reported as unused by built-in detectors.

    +
  • +
  • +

    verbosity (string, optional): Verbosity level of the logs. Possible values are quiet, debug, and default.

    +
  • +
+

Running Misti with Configuration

+

To run Misti with the specified configuration file, use the following command:

+
npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json
+

This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration.

+

Default Configuration File

+

By default, Misti enables all built-in detectors. Below is an example of the default configuration file:

+
{
"detectorsEnabled": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },
{ "className": "BranchDuplicate" },
{ "className": "FieldDoubleInit" },
{ "className": "PreferAugmentedAssign" }
],
"ignoredProjects": [],
"unusedPrefix": "_",
"verbosity": "default"
}
+

All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: configSchema.json.

+

You can always dump the Misti configuration file in use by passing the --dump-config option in the CLI:

+
npx misti --dump-config test/projects/simple/tactConfig.json
+

If there is no Misti config in the simple directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors.

+

Getting Help

+

If you need assistance or encounter any issues, please create an issue on GitHub at nowarp/misti or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.2.2/tutorial/getting-started/index.html b/tools/misti/docs/0.2.2/tutorial/getting-started/index.html new file mode 100644 index 000000000..416a88557 --- /dev/null +++ b/tools/misti/docs/0.2.2/tutorial/getting-started/index.html @@ -0,0 +1,49 @@ + + + + + +Getting started | Misti + + + + +
Version: 0.2.2

Getting started

+

This guide will walk you through the steps to install and set up the Misti static analyzer.

+

Prerequisites

+

Before you begin, ensure you have the following software installed on your system:

+ +

Installation

+

Misti is distributed via npm and should be added to your Tact project in the same way as Tact itself:

+
yarn add @nowarp/misti
+

Using Development Version

+

The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis.

+

To install the latest development version you should:

+
    +
  1. Clone Misti: git clone https://github.com/nowarp/misti
  2. +
  3. Build it: cd misti && yarn install && yarn build
  4. +
  5. Use it in your Tact project: cd /path/to/tact/project && yarn add file:/path/to/misti
  6. +
+

Running the analysis

+

Run Misti by specifying a Tact project configuration:

+
npx misti test/projects/simple/tactConfig.json
+

This will highlight any warnings the analyzer found.

+

You can also add a script to your package.json to simplify running the linting process:

+
{
"scripts": {
"lint": "npx misti test/projects/simple/tactConfig.json"
}
}
+

Troubleshooting

+

If you encounter any issues during the installation process, feel free to create an issue or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/ArgCopyMutation/index.html b/tools/misti/docs/0.3.0/detectors/ArgCopyMutation/index.html new file mode 100644 index 000000000..2b3fe00dc --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/ArgCopyMutation/index.html @@ -0,0 +1,34 @@ + + + + + +ArgCopyMutation | Misti + + + + +
Version: 0.3.0

ArgCopyMutation

+

A detector that highlights cases where function argument mutations are ineffective +due to call-by-value semantics in Tact.

+

Why is it bad?

+

In Tact, function arguments are passed by value, meaning that any mutations applied +to these arguments will only affect the local copy of the variable within the function. +Such mutations are unobservable outside the function, except for potentially +increasing gas consumption or causing exceptions.

+

Example

+
fun addEntry(m: map<Int,Int>) {
m.set(1, 10); // Bad: Mutating the copy
}
+

Use instead:

+
fun addEntry() {
self.m.set(1, 10); // OK: Changing contract's state
}
+

Alternatively, you could redesign the method:

+
fun generateNewValue(): Int {
// ... produce new value for the map
return self.nextValue + 1;
}

m.set(self.nextKey, self.generateNewValue()); // OK
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/AsmIsUsed/index.html b/tools/misti/docs/0.3.0/detectors/AsmIsUsed/index.html new file mode 100644 index 000000000..b19e28a97 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/AsmIsUsed/index.html @@ -0,0 +1,28 @@ + + + + + +AsmIsUsed | Misti + + + + +
Version: 0.3.0

AsmIsUsed

+

An optional detector that highlights all the asm functions.

+

Why is it bad?

+

Using TVM Assembly is a potentially dangerous operation that requires additional +attention from an auditor. This optional detector will highlight all its uses to +assist in contract security audits.

+

Example

+
// Highlighted: the asm function use should be audited
asm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE }
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/BranchDuplicate/index.html b/tools/misti/docs/0.3.0/detectors/BranchDuplicate/index.html new file mode 100644 index 000000000..37091829f --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/BranchDuplicate/index.html @@ -0,0 +1,33 @@ + + + + + +BranchDuplicate | Misti + + + + +
Version: 0.3.0

BranchDuplicate

+

Detector that reports duplicated code in conditional branches.

+

Why is it bad?

+

Duplicated code in branches is bad because it:

+
    +
  1. Reduces Readability: Repetition makes the code harder to understand.
  2. +
  3. Increases Maintenance: Changes must be made in multiple places, risking errors.
  4. +
  5. Signals Poor Design: It suggests missed opportunities for cleaner, more abstract code.
  6. +
+

Example

+
if (a > 42) {
a = 43; // bad: duplicated code
} else {
a = 43;
}
+

Use instead:

+
if (a > 42) {
a = inc(b); // ok
} else {
a = 43;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/ConstantAddress/index.html b/tools/misti/docs/0.3.0/detectors/ConstantAddress/index.html new file mode 100644 index 000000000..736197797 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/ConstantAddress/index.html @@ -0,0 +1,31 @@ + + + + + +ConstantAddress | Misti + + + + +
Version: 0.3.0

ConstantAddress

+

An optional detector that highlights all the constant addresses appearing in the source code.

+

Why is it bad?

+

Using hardcoded addresses can sometimes indicate poor contract design. +Some constant addresses may need to be set dynamically, e.g., using +contractAddress, or at least have a way to change them at runtime, for +example, when upgrading a contract.

+

Example

+
contract Main {
proxy: Address;
init() {
// Bad: Constant address highlighted by the analyzer.
self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");
}
}
+

Use instead:

+
contract Main {
proxy: Address;
init() {
let proxy: Proxy = initOf Proxy(myAddress());
// OK: Address depends on how the proxy contact has been deployed
self.proxy = contractAddress(proxy);
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply/index.html b/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply/index.html new file mode 100644 index 000000000..8b93122a9 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,34 @@ + + + + + +DivideBeforeMultiply | Misti + + + + +
Version: 0.3.0

DivideBeforeMultiply

+

A detector that identifies and corrects instances of division before multiplication to +ensure accurate mathematical operations.

+

Why is it bad?

+

Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:

+
    +
  • Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers.
  • +
  • Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations.
  • +
  • Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging.
  • +
+

Example

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Bad: Division before multiplication
let result: Int = a / b * c;
+

Use instead:

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Correct: Multiplication before division
let result: Int = a * c / b;
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/DumpIsUsed/index.html b/tools/misti/docs/0.3.0/detectors/DumpIsUsed/index.html new file mode 100644 index 000000000..eec571a4c --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/DumpIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +DumpIsUsed | Misti + + + + +
Version: 0.3.0

DumpIsUsed

+

An optional detector that highlights all the dump function calls.

+

Why is it bad?

+

The dump function is a debug print that shouldn't be in the final code. +Even though the compiler removes it in production, its presence suggests the +developer was debugging something. This can flag areas where issues might exist, +so auditors should take a closer look at these parts of the code.

+

Example

+
fun test(): Int {
// ... other computations
let combined: Int = (RANDOM_SEED >> half_shift) &
(MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;
dump(combined); // Suspicious: Highlighted by the detector
}
+

Use instead:

+
fun test(): Int {
// ... other computations
let combined: Int = this.seed ^ shift_mask
// OK: The code was reviewed and simplified; `dump` was removed
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/FieldDoubleInit/index.html b/tools/misti/docs/0.3.0/detectors/FieldDoubleInit/index.html new file mode 100644 index 000000000..4549ca381 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/FieldDoubleInit/index.html @@ -0,0 +1,32 @@ + + + + + +FieldDoubleInit | Misti + + + + +
Version: 0.3.0

FieldDoubleInit

+

A detector that highlights cases where a field is initialized both in the +init function and at the point of definition.

+

Why is it bad?

+

Double initialization of fields can either be a programmer's mistake or simply +a waste of gas. It is always preferred to initialize values in the field declaration +if they have a compile-time evaluatable default value, or in the init function if +they must be initialized dynamically.

+

Example

+
contract Test {
a: Int = 0; // Bad
init(x: Int) { self.a = x }
}
+

Use instead:

+
contract Test {
a: Int; // Fixed
init(x: Int) { self.a = x }
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/InheritedStateMutation/index.html b/tools/misti/docs/0.3.0/detectors/InheritedStateMutation/index.html new file mode 100644 index 000000000..7222efd58 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/InheritedStateMutation/index.html @@ -0,0 +1,33 @@ + + + + + +InheritedStateMutation | Misti + + + + +
Version: 0.3.0

InheritedStateMutation

+

An optional detector that highlights all instances where inherited trait variables +are directly modified.

+

Why is it bad?

+

Traits should provide setter methods to ensure that invariants related to their +state are preserved. Directly modifying trait variables (e.g., self.traitVar = 42) +can violate these invariants, leading to potential bugs or security vulnerabilities. +This detector warns when such direct modifications occur, prompting further review +by auditors.

+

Example

+
trait T {
balance: Int;
}

contract C with T {
balance: Int = 42;
fun updateBalance() {
self.balance = 100; // Suspicious: Highlighted by the detector
}
}
+

Use instead:

+
trait T {
balance: Int;
fun setBalance(newBalance: Int) {
require(newBalance > 0, "balance cannot be negative"); // Invariant check
self.balance = newBalance;
}
}

contract C with T {
balance: Int = 42;
fun updateBalance() {
self.setBalance(100); // OK: Invariant preserved
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables/index.html b/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables/index.html new file mode 100644 index 000000000..f0b509370 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,30 @@ + + + + + +NeverAccessedVariables | Misti + + + + +
Version: 0.3.0

NeverAccessedVariables

+

A detector that identifies write-only or unused variables, fields and constants.

+

Why is it bad?

+

These variables are either assigned but never used in any meaningful computation, +or they are declared and never used at all, which may indicate redundant code +or an incomplete implementation of the intended logic.

+

Example

+
// Error: the developer forgot to use the constant
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+

Use instead:

+
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
// OK: Fixed after the analyzer highlighted this warning
require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign/index.html b/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign/index.html new file mode 100644 index 000000000..abe547b47 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,31 @@ + + + + + +PreferAugmentedAssign | Misti + + + + +
Version: 0.3.0

PreferAugmentedAssign

+

Detects non-idiomatic statements that can be written using augmented assignment +operators like +=, -=, etc.

+

Why is it bad?

+

Using augmented assignment operations improves the readability of the source code +and reduces the risk of mistakes, such as those that occur during copy-pasting +and refactoring code.

+

Example

+
msgValue = (msgValue - ctx.readForwardFee());
+

Use instead:

+
msgValue -= ctx.readForwardFee());
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi/index.html b/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi/index.html new file mode 100644 index 000000000..3439bd2a7 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi/index.html @@ -0,0 +1,34 @@ + + + + + +PreferredStdlibApi | Misti + + + + +
Version: 0.3.0

PreferredStdlibApi

+

An optional detector that flags the use of advanced functions from the standard library.

+

Why is it bad?

+

Auditors should pay extra attention to these functions, as incorrect usage can +lead to subtle bugs. Safer stdlib alternatives should be preferred in the code.

+

Supported functions:

+ +

Example

+
let pkg: Slice = msg.transfer;
let _seqno: Int = pkg.loadInt(32);
let mode: Int = pkg.loadInt(8);
let body: Cell = pkg.loadRef();
// Bad: prefer `send` to avoid low-level manipulation of Slice
nativeSendMessage(body, mode);
+

Use instead:

+
// Safer: More explicit definition of the send operation
send(SendParameters{ value: amount,
to: self.owner,
mode: mode,
body: beginCell().endCell() });
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables/index.html b/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables/index.html new file mode 100644 index 000000000..350dccbba --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,29 @@ + + + + + +ReadOnlyVariables | Misti + + + + +
Version: 0.3.0

ReadOnlyVariables

+

A detector that identifies read-only variables and fields.

+

Why is it bad?

+

These variables could typically be replaced with constants to optimize performance. +Alternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally.

+

Example

+
fun calculateFinalPrice(price: Int): Int {
// Warning: the developer uses a read-only variable that could be a constant
let DISCOUNT_AMOUNT: Int = 10;
return price - DISCOUNT_AMOUNT;
}
+

Use instead:

+
const DISCOUNT_AMOUNT: Int = 10;

fun calculateFinalPrice(price: Int): Int {
// OK: Fixed after the analyzer highlighted this warning
return price - DISCOUNT_AMOUNT;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap/index.html b/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap/index.html new file mode 100644 index 000000000..b80303e5a --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap/index.html @@ -0,0 +1,29 @@ + + + + + +StringReceiversOverlap | Misti + + + + +
Version: 0.3.0

StringReceiversOverlap

+

A detector that finds overlapping messages between general string receivers and string receivers.

+

Why is it bad?

+

Constant string receivers and general string receivers can have overlapping messages +in which case the constant string receiver always takes precedence.

+

Example

+
contract Test {
receive("foobar") { throw(1042) }
receive(msg: String) {
if (msg == "foobar") { throw(1043) } // Bad: Dead code
}
}
+

Use instead:

+
contract Test {
receive("foobar") { throw(1042) }
receive(msg: String) {}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/UnboundLoops/index.html b/tools/misti/docs/0.3.0/detectors/UnboundLoops/index.html new file mode 100644 index 000000000..d15cdaa09 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/UnboundLoops/index.html @@ -0,0 +1,33 @@ + + + + + +UnboundLoops | Misti + + + + +
Version: 0.3.0

UnboundLoops

+

A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.

+

Why is it bad?

+

An unbounded loop can be problematic for several reasons:

+
    +
  • Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult.
  • +
  • Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks.
  • +
  • DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability.
  • +
+

Example

+
let x: Int = 10;
while (x > 0) {
// Bad: x is not changed due looping
send(SendParameters{ to: sender(), ... });
}
+

Use instead:

+
let x: Int = 10;
while (x > 0) {
send(SendParameters{ to: sender(), ... });
x = x - 1;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/ZeroAddress/index.html b/tools/misti/docs/0.3.0/detectors/ZeroAddress/index.html new file mode 100644 index 000000000..82b6dab63 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/ZeroAddress/index.html @@ -0,0 +1,31 @@ + + + + + +ZeroAddress | Misti + + + + +
Version: 0.3.0

ZeroAddress

+

A detector that identifies uses of the zero address.

+

Why is it bad?

+

Using the zero address in smart contracts is typically problematic because it can be +exploited as a default or uninitialized address, leading to unintended transfers and +security vulnerabilities. Additionally, operations involving the zero address can +result in loss of funds or tokens, as there is no private key to access this address.

+

Example

+
contract Proxy {
to: Address;
init() {
// Warning: Insecure usage of zero address as default value
self.to = newAddress(0, 0);
}
fun setAddress(to: Address) {
self.to = to
}
}
+

Use instead:

+
contract Proxy {
to: Address;
init(to: Address) {
// Fixed: Using the input value on initialization.
self.to = to;
}
fun setAddress(to: Address) {
self.to = to
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/detectors/index.html b/tools/misti/docs/0.3.0/detectors/index.html new file mode 100644 index 000000000..1ebabbd58 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/index.html @@ -0,0 +1,26 @@ + + + + + +Detectors Overview | Misti + + + + +
Version: 0.3.0

Detectors Overview

+

Misti currently supports 15 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:

+
#DetectorRequires SouffléEnabled by default
1ArgCopyMutation
2AsmIsUsed
3BranchDuplicate
4ConstantAddress
5DivideBeforeMultiply
6DumpIsUsed
7FieldDoubleInit
8InheritedStateMutation
9NeverAccessedVariables
10PreferAugmentedAssign
11PreferredStdlibApi
12ReadOnlyVariables
13StringReceiversOverlap
14UnboundLoops
15ZeroAddress
+

Some of the detectors require Soufflé to be installed. If no Soufflé installation is found, these detectors won't be executed.

+

A few detectors are optional and aimed at auditors to help uncover subtle issues in the source code. To enable all detectors, use the --all-detectors option. You can find a full list of configuration options on the configuration page.

+

Each detector targets a specific type of problem in your code. Click on the detector name to learn more.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/hacking/contributing/index.html b/tools/misti/docs/0.3.0/hacking/contributing/index.html new file mode 100644 index 000000000..b895bd40b --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/contributing/index.html @@ -0,0 +1,66 @@ + + + + + +Contributing Guide | Misti + + + + +
Version: 0.3.0

Contributing Guide

+

Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.

+

Issues reporting

+

When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:

+
The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.
Please help us by publishing it and the input sources at:
https://github.com/nowarp/misti/issues/new.
+

We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users.

+

Documentation contribution

+

We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: nowarp.github.io Issues. Additionally, many documentation pages have an Edit button that allows you to make direct contributions easily.

+

Code contribution

+
    +
  1. +

    Navigate Issues and Find Tasks

    +
      +
    • Browse the issues here. Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues.
    • +
    • Choose an issue suitable for you and mention in the issue that you're working on it.
    • +
    +
  2. +
  3. +

    Implement Your Changes

    +
      +
    • Implement your changes. Feel free to ask questions in the issue if needed.
    • +
    +
  4. +
  5. +

    Ensure Tests Pass

    +
      +
    • Before creating a PR, make sure all tests and CI checks are passing by running: +
      yarn test-all
      +
    • +
    +
  6. +
  7. +

    Create a PR

    +
      +
    • Submit your pull request here
    • +
    +
  8. +
  9. +

    Add a CHANGELOG entry

    +
      +
    • Describe your changes in the CHANGELOG.md file according to the existing structure.
    • +
    +
  10. +
+

All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to HACKING.md.

+

Thank you for your contributions!

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/hacking/custom-detector/index.html b/tools/misti/docs/0.3.0/hacking/custom-detector/index.html new file mode 100644 index 000000000..a852d7aa5 --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/custom-detector/index.html @@ -0,0 +1,38 @@ + + + + + +Custom Detector Guide | Misti + + + + +
Version: 0.3.0

Custom Detector Guide

+

Introduction

+

Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: Misti API Reference.

+

Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the Detector interface.

+

Creating a Detector

+

You can create a new custom detector by executing Misti with the --new-detector option: npx misti --new-detector implicitInit.

+

This will create the implicitInit.ts file, which contains the template code for writing your own custom detector logic leveraging the Misti API.

+

Here's an example of how to implement a custom detector using Misti API:

+
import { Detector } from "@nowarp/misti/dist/detectors/detector";
import { CompilationUnit } from "@nowarp/misti/dist/internals/ir";
import {
MistiTactWarning,
Severity,
} from "@nowarp/misti/dist/internals/errors";

/**
* An example of a custom detector that showcases the usage of the detector API.
*
* It reports all the contracts that doesn't have an explicit implementation of the init function.
*/
export class ImplicitInit extends Detector {
async check(cu: CompilationUnit): Promise<MistiTactWarning[]> {
return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {
if (!cu.findMethodCFGByName(contract.name, "init")) {
const err = this.makeError(
`Contract ${contract.name} doesn't define an init function`,
Severity.INFO,
contract.ref,
);
foundErrors.push(err);
}
return foundErrors;
}, [] as MistiTactWarning[]);
}
}
+

Testing the detector

+

To run Misti with only your new detector, use the --detectors option, specifying the path to the detector and the Detector class name: npx misti path/to/your/tact.config.json --detectors path/to/implicitInit.ts:ImplicitInit.

+

That's a good way to test the detector on the first run. You could also use the --verbose CLI option and set the environment variable MISTI_TRACE=1 to facilitate debugging.

+

Saving the configuration

+

After testing the detector, you can specify it in your configuration to enable it in future runs. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:

+
{
"detectors": [
// Other detectors...
{ "className": "ImplicitInit", "modulePath": "ImplicitInit.ts" }
],
}
+

After this, you could run Misti specifying a path to a custom configuration npx misti --config path/to/misti.config.json path/to/your/tact.config.json.

+

Example Detectors

+

The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the examples directory in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/hacking/design/index.html b/tools/misti/docs/0.3.0/hacking/design/index.html new file mode 100644 index 000000000..942ad9012 --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/design/index.html @@ -0,0 +1,34 @@ + + + + + +Design Overview | Misti + + + + +
Version: 0.3.0

Design Overview

+

Static Analysis

+

Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues.

+

Souffle Datalog Solver

+

Misti leverages the Souffle Datalog solver, an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases.

+

Dataflow Analysis in Misti

+

Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code.

+

References

+

For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:

+ +

These resources provide a solid foundation in the theory and practice of static and dataflow analysis.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/hacking/souffle/index.html b/tools/misti/docs/0.3.0/hacking/souffle/index.html new file mode 100644 index 000000000..af3a781a3 --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/souffle/index.html @@ -0,0 +1,38 @@ + + + + + +Soufflé Integration Guide | Misti + + + + +
Version: 0.3.0

Soufflé Integration Guide

+

What is Soufflé?

+

Soufflé is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Soufflé, Misti can perform deep and scalable analyses of smart contracts.

+

Benefits of Using Soufflé for Static Analysis

+

Soufflé allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Soufflé program might be more straightforward then implementing a complex transfer function in for a classic monotone framework.

+

Soufflé Integration in Misti

+

The API for interacting with Soufflé in Misti is implemented in the Souffle.js library. See the Souffle.js API reference for more detailed information.

+

Creating Soufflé Programs

+

To create a Soufflé program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:

+
addDecls(ctx: Context<SrcInfo>) {
ctx.add(
Relation.from(
"varDecl",
[
["var", FactType.Symbol],
["func", FactType.Symbol],
],
undefined,
),
);
// other declarations
}
+
addRules(ctx: Context<SrcInfo>) {
// readOnly(var, func) :-
// varDecl(var, func),
// !varAssign(var, func),
// !varUse(var, func).
ctx.add(
Rule.from(
[makeAtom("readOnly", ["var", "func"])],
makeRuleBody(makeAtom("varDecl", ["var", "func"])),
makeRuleBody(makeAtom("varAssign", ["var", "func"]), {
negated: true,
}),
makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),
),
);
}
+

Generating Facts and Executing Soufflé

+

After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Soufflé executor to run the analysis:

+
const executor = ctx.config.soufflePath
? new Executor<SrcInfo>({
inputDir: ctx.config.soufflePath,
outputDir: ctx.config.soufflePath,
})
: new Executor<SrcInfo>();

const result = executor.executeSync(program);

if (!result.success) {
throw new Error(
`Error executing Soufflé for ${this.id}:\n${result.stderr}`,
);
}

const warnings = Array.from(result.results.entries.values()).map((fact) => {
// raise warnings
});
+

Learning from Existing Code

+

We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Soufflé with Misti. This will help you understand the intricacies of generating IR and executing Soufflé programs effectively.

+

Further Reading

+

For a deeper understanding of static analysis using Soufflé, refer to the textbook Program Analysis: An Appetizer by Flemming Nielson and Hanne Riis Nielson. It discusses Soufflé-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/hacking/tools/index.html b/tools/misti/docs/0.3.0/hacking/tools/index.html new file mode 100644 index 000000000..424d4e70f --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/tools/index.html @@ -0,0 +1,51 @@ + + + + + +Tools Guide | Misti + + + + +
Version: 0.3.0

Tools Guide

+

This page describes the internal analyzer tools available in Misti to aid in development and debugging.

+

CFG Dump

+

Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts.

+

Usage

+

To dump the CFG in JSON format, use the following command:

+
npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in DOT format, use the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Converting DOT to SVG

+

To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use Graphviz with the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot
dot -Tsvg output.dot -o output.svg
+

Viewing the SVG

+

To view the SVG file in Firefox, use the following command:

+
firefox output.svg
+

For example, for the following contract:

+
fun test(): Int {
let sum: Int = 0;
let i: Int = 0;
repeat (10) {
i = i + 1;
sum = sum + i;
}
return sum;
}
+

The following CFG will be generated:

+

CFG Example

+

VS Code Plugin

+

For real-time visualization of DOT files, you can use one of the available Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer.

    +
  • +
  • +

    DOT Dumps: These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/index.html b/tools/misti/docs/0.3.0/index.html new file mode 100644 index 000000000..f1adc8d56 --- /dev/null +++ b/tools/misti/docs/0.3.0/index.html @@ -0,0 +1,39 @@ + + + + + +Introduction | Misti + + + + +
Version: 0.3.0

Introduction

Misti is a static analysis tool designed for smart contracts on the TON blockchain.

+

Language Support:

+ +

Use Cases

+

Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:

+
    +
  • Detect Vulnerabilities: Identify and fix potential security flaws early in the development cycle.
  • +
  • Improve Code Quality: Maintain high standards by catching bugs and enforcing best practices automatically.
  • +
  • Streamline Development: Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.
  • +
  • Custom Detectors: Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.
  • +
+

Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow.

+

Name Origin

+

The name "Misti" comes from the Misti volcano in Peru. It was chosen because it's catchy and easy to remember.

+

Funding

+

Misti has been funded by TON Foundation. This support has enabled us to develop and maintain the tool.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/tutorial/blueprint/index.html b/tools/misti/docs/0.3.0/tutorial/blueprint/index.html new file mode 100644 index 000000000..3b2888062 --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/blueprint/index.html @@ -0,0 +1,32 @@ + + + + + +Using Misti with Blueprint | Misti + + + + +
Version: 0.3.0

Using Misti with Blueprint

+

Blueprint is a development environment for writing, testing, and deploying TON smart contracts.

+

Misti can be used in Blueprint projects by leveraging the blueprint-misti plugin.

+

Getting started

+

Add the plugin and the recent version of Tact to the package.json of your Blueprint project by running:

+
yarn add @tact-lang/compiler
yarn add @nowarp/blueprint-misti
+

Then, add this configuration to blueprint.config.ts:

+
import { MistiPlugin } from '@nowarp/blueprint-misti';
export const config = {
plugins: [
new MistiPlugin(),
],
};
+

Now, try to run Misti:

+
yarn blueprint misti ./path/to/tact.config.json
+

Resources

+

For more information, please refer to the README of the blueprint-misti project. If you have any problems, feel free to reach out to us in the Misti discussion group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/tutorial/ci-cd/index.html b/tools/misti/docs/0.3.0/tutorial/ci-cd/index.html new file mode 100644 index 000000000..c5d26887d --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/ci-cd/index.html @@ -0,0 +1,33 @@ + + + + + +Integrating Misti into CI/CD | Misti + + + + +
Version: 0.3.0

Integrating Misti into CI/CD

+

Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.

+

GitHub Actions

+

To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:

+

1. Open your GitHub repository

+

2. Create or edit the GitHub Actions workflow YAML file

+

It could be located at e.g., .github/workflows/main.yml.

+

3. Add the step to run Misti to your YAML file

+

For example:

+
name: Run Misti
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install dependencies
run: npm install

- name: Run Misti
run: npx misti /path/to/your/tact.config.json
+

The npx misti /path/to/your/tact.config.json command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail.

+

4. Adjusting the Misti Configuration

+

If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the Configuration section for more details on how to customize your settings.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/tutorial/cli/index.html b/tools/misti/docs/0.3.0/tutorial/cli/index.html new file mode 100644 index 000000000..5c8bc1c1c --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/cli/index.html @@ -0,0 +1,102 @@ + + + + + +Command-Line Interface | Misti + + + + +
Version: 0.3.0

Command-Line Interface

+

Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.

+

--dump-cfg <json|dot>

+
    +
  • Description: Dumps the Control Flow Graph (CFG) in the requested format: JSON or Graphviz Dot.
  • +
  • Default: undefined
  • +
+

--dump-ast

+
    +
  • Description: Dumps the Abstract Syntax Tree (AST) in JSON format.
  • +
  • Default: false
  • +
+

--dump-output <PATH>

+
    +
  • Description: Specifies the directory to save the AST/CFG dump. If <PATH> is -, then the output is sent to stdout.
  • +
  • Default: Value of DUMP_STDOUT_PATH
  • +
+

--dump-include-stdlib

+
    +
  • Description: Includes standard library components in the AST/CFG dump.
  • +
  • Default: false
  • +
+

--dump-config

+
    +
  • Description: Dumps the Misti JSON configuration file in use.
  • +
  • Default: false
  • +
+

--souffle-binary <PATH>

+
    +
  • Description: Path to the Soufflé binary.
  • +
  • Default: "souffle"
  • +
+

--souffle-path <PATH>

+
    +
  • Description: Directory to save the generated Soufflé files.
  • +
  • Default: "/tmp/misti/souffle"
  • +
+

--souffle-verbose

+
    +
  • Description: Generates human-readable, but more verbose, Soufflé files.
  • +
  • Default: false
  • +
+

--tact-stdlib-path <PATH>

+
    +
  • Description: Path to the Tact standard library.
  • +
+

--verbose

+
    +
  • Description: Enables verbose output.
  • +
  • Default: false
  • +
+

--quiet

+
    +
  • Description: Suppresses all output.
  • +
  • Default: false
  • +
+

--detectors <name|path:name>

+
    +
  • Description: A comma-separated list of detectors to enable.
  • +
  • Argument Validation: Requires a non-empty list of detector names.
  • +
  • Default: undefined
  • +
+

--suppress <names>

+
    +
  • Description: A comma-separated list of detector names to suppress.
  • +
  • Argument Validation: Requires a non-empty list of detector names.
  • +
  • Default: undefined
  • +
+

--all-detectors

+
    +
  • Description: Enables all the available built-in detectors.
  • +
  • Default: false
  • +
+

--config <PATH>

+
    +
  • Description: Path to the Misti configuration file.
  • +
+

--new-detector <PATH>

+
    +
  • Description: Creates a new custom detector at the specified path.
  • +
  • Default: undefined
  • +
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/tutorial/configuration/index.html b/tools/misti/docs/0.3.0/tutorial/configuration/index.html new file mode 100644 index 000000000..a36825f62 --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/configuration/index.html @@ -0,0 +1,63 @@ + + + + + +Configuration | Misti + + + + +
Version: 0.3.0

Configuration

+

This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.

+

Configuration Options

+
    +
  • +

    detectors: List of detectors to run. Each detector can be specified with a className and optionally a modulePath if it’s a custom detector.

    +
      +
    • className (string, required): The class name of the detector.
    • +
    • modulePath (string, optional): The file path of the detector module.
    • +
    +
  • +
  • +

    ignoredProjects (array of strings, optional): List of Tact projects to ignore during analysis.

    +
  • +
  • +

    soufflePath (string, optional): Directory to save generated Soufflé files which is helpful for debugging purposes. If not set, a temporary directory will be used.

    +
  • +
  • +

    souffleVerbose (boolean, optional): If set, generates more readable Soufflé files instead of making the result source code smaller.

    +
  • +
  • +

    tactStdlibPath (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used.

    +
  • +
  • +

    unusedPrefix (string, default: "_"): Identifiers starting with this prefix won't be reported as unused by built-in detectors.

    +
  • +
  • +

    verbosity (string, optional): Verbosity level of the logs. Possible values are quiet, debug, and default.

    +
  • +
+

Running Misti with Configuration

+

To run Misti with the specified configuration file, use the following command:

+
npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json
+

This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration.

+

Default Configuration File

+

By default, Misti enables all built-in detectors. Below is an example of the default configuration file:

+
{
"detectors": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },
{ "className": "BranchDuplicate" },
{ "className": "FieldDoubleInit" },
{ "className": "PreferAugmentedAssign" },
{ "className": "StringReceiversOverlap" },
{ "className": "ArgCopyMutation" }
],
"ignoredProjects": [],
"soufflePath": "/tmp/misti/souffle",
"souffleVerbose": false,
"unusedPrefix": "_",
"verbosity": "default"
}
+

All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: configSchema.json.

+

You can always dump the Misti configuration file in use by passing the --dump-config option in the CLI:

+
npx misti --dump-config test/projects/simple/tactConfig.json
+

If there is no Misti config in the simple directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors.

+

Getting Help

+

If you need assistance or encounter any issues, please create an issue on GitHub at nowarp/misti or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.0/tutorial/getting-started/index.html b/tools/misti/docs/0.3.0/tutorial/getting-started/index.html new file mode 100644 index 000000000..578cec56f --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/getting-started/index.html @@ -0,0 +1,62 @@ + + + + + +Getting started | Misti + + + + +
Version: 0.3.0

Getting started

+

This guide will walk you through the steps to install and set up the Misti static analyzer.

+

Prerequisites

+

Before you begin, ensure you have the following software installed on your system:

+
    +
  • Git
  • +
  • Yarn
  • +
  • Node.js version 22 or higher
  • +
  • Soufflé
  • +
+

Installation

+

Misti is distributed via npm and should be added to your Tact project in the same way as Tact itself:

+
yarn add @nowarp/misti
+

Using Development Version

+

The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis.

+

To install the latest development version you should:

+
    +
  1. Clone Misti: git clone https://github.com/nowarp/misti
  2. +
  3. Build it: cd misti && yarn install && yarn build
  4. +
  5. Use it in your Tact project: cd /path/to/tact/project && yarn add file:/path/to/misti
  6. +
+

Running the analysis

+

Run Misti by specifying a Tact project configuration:

+
npx misti path/to/tact.config.json
+

This will highlight any warnings the analyzer found.

+

You can also add a script to your package.json to simplify running the linting process:

+
{
"scripts": {
"lint": "npx misti path/to/tact.config.json"
}
}
+

More usage examples

+

Below are a few usage examples for common scenarios when using the misti CLI.

+

Suppressing Specific Detectors

+

To run misti while suppressing specific detectors, such as ReadOnlyVariables:

+
npx misti --suppress ReadOnlyVariables path/to/tact.config.json
+

Enabling All Detectors

+

Running misti with all available built-in detectors enabled:

+
npx misti --all-detectors path/to/tact.config.json
+

It is recommended to do that when auditing the project.

+

Running in Quiet Mode

+

To suppress all output while running misti getting just a return code:

+
npx misti --quiet path/to/tact.config.json
+

This might be useful in scripts and CI/CD.

+

Troubleshooting

+

If you encounter any issues during the installation process, feel free to create an issue or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/ArgCopyMutation/index.html b/tools/misti/docs/0.3.1/detectors/ArgCopyMutation/index.html new file mode 100644 index 000000000..7a901bc41 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/ArgCopyMutation/index.html @@ -0,0 +1,34 @@ + + + + + +ArgCopyMutation | Misti + + + + +
Version: 0.3.1

ArgCopyMutation

+

A detector that highlights cases where function argument mutations are ineffective +due to call-by-value semantics in Tact.

+

Why is it bad?

+

In Tact, function arguments are passed by value, meaning that any mutations applied +to these arguments will only affect the local copy of the variable within the function. +Such mutations are unobservable outside the function, except for potentially +increasing gas consumption or causing exceptions.

+

Example

+
fun addEntry(m: map<Int,Int>) {
m.set(1, 10); // Bad: Mutating the copy
}
+

Use instead:

+
fun addEntry() {
self.m.set(1, 10); // OK: Changing contract's state
}
+

Alternatively, you could redesign the method:

+
fun generateNewValue(): Int {
// ... produce new value for the map
return self.nextValue + 1;
}

m.set(self.nextKey, self.generateNewValue()); // OK
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/AsmIsUsed/index.html b/tools/misti/docs/0.3.1/detectors/AsmIsUsed/index.html new file mode 100644 index 000000000..7ae3e27f7 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/AsmIsUsed/index.html @@ -0,0 +1,28 @@ + + + + + +AsmIsUsed | Misti + + + + +
Version: 0.3.1

AsmIsUsed

+

An optional detector that highlights all the asm functions.

+

Why is it bad?

+

Using TVM Assembly is a potentially dangerous operation that requires additional +attention from an auditor. This optional detector will highlight all its uses to +assist in contract security audits.

+

Example

+
// Highlighted: the asm function use should be audited
asm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE }
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/BranchDuplicate/index.html b/tools/misti/docs/0.3.1/detectors/BranchDuplicate/index.html new file mode 100644 index 000000000..b2d0b1cf9 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/BranchDuplicate/index.html @@ -0,0 +1,33 @@ + + + + + +BranchDuplicate | Misti + + + + +
Version: 0.3.1

BranchDuplicate

+

Detector that reports duplicated code in conditional branches.

+

Why is it bad?

+

Duplicated code in branches is bad because it:

+
    +
  1. Reduces Readability: Repetition makes the code harder to understand.
  2. +
  3. Increases Maintenance: Changes must be made in multiple places, risking errors.
  4. +
  5. Signals Poor Design: It suggests missed opportunities for cleaner, more abstract code.
  6. +
+

Example

+
if (a > 42) {
a = 43; // bad: duplicated code
} else {
a = 43;
}
+

Use instead:

+
if (a > 42) {
a = inc(b); // ok
} else {
a = 43;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/ConstantAddress/index.html b/tools/misti/docs/0.3.1/detectors/ConstantAddress/index.html new file mode 100644 index 000000000..ce7f8cf72 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/ConstantAddress/index.html @@ -0,0 +1,31 @@ + + + + + +ConstantAddress | Misti + + + + +
Version: 0.3.1

ConstantAddress

+

An optional detector that highlights all the constant addresses appearing in the source code.

+

Why is it bad?

+

Using hardcoded addresses can sometimes indicate poor contract design. +Some constant addresses may need to be set dynamically, e.g., using +contractAddress, or at least have a way to change them at runtime, for +example, when upgrading a contract.

+

Example

+
contract Main {
proxy: Address;
init() {
// Bad: Constant address highlighted by the analyzer.
self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");
}
}
+

Use instead:

+
contract Main {
proxy: Address;
init() {
let proxy: Proxy = initOf Proxy(myAddress());
// OK: Address depends on how the proxy contact has been deployed
self.proxy = contractAddress(proxy);
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply/index.html b/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply/index.html new file mode 100644 index 000000000..4e3106515 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,34 @@ + + + + + +DivideBeforeMultiply | Misti + + + + +
Version: 0.3.1

DivideBeforeMultiply

+

A detector that identifies and corrects instances of division before multiplication to +ensure accurate mathematical operations.

+

Why is it bad?

+

Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:

+
    +
  • Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers.
  • +
  • Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations.
  • +
  • Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging.
  • +
+

Example

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Bad: Division before multiplication
let result: Int = a / b * c;
+

Use instead:

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Correct: Multiplication before division
let result: Int = a * c / b;
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/DumpIsUsed/index.html b/tools/misti/docs/0.3.1/detectors/DumpIsUsed/index.html new file mode 100644 index 000000000..afea67da6 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/DumpIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +DumpIsUsed | Misti + + + + +
Version: 0.3.1

DumpIsUsed

+

An optional detector that highlights all the dump function calls.

+

Why is it bad?

+

The dump function is a debug print that shouldn't be in the final code. +Even though the compiler removes it in production, its presence suggests the +developer was debugging something. This can flag areas where issues might exist, +so auditors should take a closer look at these parts of the code.

+

Example

+
fun test(): Int {
// ... other computations
let combined: Int = (RANDOM_SEED >> half_shift) &
(MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;
dump(combined); // Suspicious: Highlighted by the detector
}
+

Use instead:

+
fun test(): Int {
// ... other computations
let combined: Int = this.seed ^ shift_mask
// OK: The code was reviewed and simplified; `dump` was removed
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/FieldDoubleInit/index.html b/tools/misti/docs/0.3.1/detectors/FieldDoubleInit/index.html new file mode 100644 index 000000000..bcb7df8c2 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/FieldDoubleInit/index.html @@ -0,0 +1,32 @@ + + + + + +FieldDoubleInit | Misti + + + + +
Version: 0.3.1

FieldDoubleInit

+

A detector that highlights cases where a field is initialized both in the +init function and at the point of definition.

+

Why is it bad?

+

Double initialization of fields can either be a programmer's mistake or simply +a waste of gas. It is always preferred to initialize values in the field declaration +if they have a compile-time evaluatable default value, or in the init function if +they must be initialized dynamically.

+

Example

+
contract Test {
a: Int = 0; // Bad
init(x: Int) { self.a = x }
}
+

Use instead:

+
contract Test {
a: Int; // Fixed
init(x: Int) { self.a = x }
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/InheritedStateMutation/index.html b/tools/misti/docs/0.3.1/detectors/InheritedStateMutation/index.html new file mode 100644 index 000000000..16ed6db2b --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/InheritedStateMutation/index.html @@ -0,0 +1,33 @@ + + + + + +InheritedStateMutation | Misti + + + + +
Version: 0.3.1

InheritedStateMutation

+

An optional detector that highlights all instances where inherited trait variables +are directly modified.

+

Why is it bad?

+

Traits should provide setter methods to ensure that invariants related to their +state are preserved. Directly modifying trait variables (e.g., self.traitVar = 42) +can violate these invariants, leading to potential bugs or security vulnerabilities. +This detector warns when such direct modifications occur, prompting further review +by auditors.

+

Example

+
trait T {
balance: Int;
}

contract C with T {
balance: Int = 42;
fun updateBalance() {
self.balance = 100; // Suspicious: Highlighted by the detector
}
}
+

Use instead:

+
trait T {
balance: Int;
fun setBalance(newBalance: Int) {
require(newBalance > 0, "balance cannot be negative"); // Invariant check
self.balance = newBalance;
}
}

contract C with T {
balance: Int = 42;
fun updateBalance() {
self.setBalance(100); // OK: Invariant preserved
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables/index.html b/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables/index.html new file mode 100644 index 000000000..02bee2bab --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,30 @@ + + + + + +NeverAccessedVariables | Misti + + + + +
Version: 0.3.1

NeverAccessedVariables

+

A detector that identifies write-only or unused variables, fields and constants.

+

Why is it bad?

+

These variables are either assigned but never used in any meaningful computation, +or they are declared and never used at all, which may indicate redundant code +or an incomplete implementation of the intended logic.

+

Example

+
// Error: the developer forgot to use the constant
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+

Use instead:

+
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
// OK: Fixed after the analyzer highlighted this warning
require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign/index.html b/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign/index.html new file mode 100644 index 000000000..519964324 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,31 @@ + + + + + +PreferAugmentedAssign | Misti + + + + +
Version: 0.3.1

PreferAugmentedAssign

+

Detects non-idiomatic statements that can be written using augmented assignment +operators like +=, -=, etc.

+

Why is it bad?

+

Using augmented assignment operations improves the readability of the source code +and reduces the risk of mistakes, such as those that occur during copy-pasting +and refactoring code.

+

Example

+
msgValue = (msgValue - ctx.readForwardFee());
+

Use instead:

+
msgValue -= ctx.readForwardFee());
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi/index.html b/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi/index.html new file mode 100644 index 000000000..34fe055ce --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi/index.html @@ -0,0 +1,34 @@ + + + + + +PreferredStdlibApi | Misti + + + + +
Version: 0.3.1

PreferredStdlibApi

+

An optional detector that flags the use of advanced functions from the standard library.

+

Why is it bad?

+

Auditors should pay extra attention to these functions, as incorrect usage can +lead to subtle bugs. Safer stdlib alternatives should be preferred in the code.

+

Supported functions:

+ +

Example

+
let pkg: Slice = msg.transfer;
let _seqno: Int = pkg.loadInt(32);
let mode: Int = pkg.loadInt(8);
let body: Cell = pkg.loadRef();
// Bad: prefer `send` to avoid low-level manipulation of Slice
nativeSendMessage(body, mode);
+

Use instead:

+
// Safer: More explicit definition of the send operation
send(SendParameters{ value: amount,
to: self.owner,
mode: mode,
body: beginCell().endCell() });
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables/index.html b/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables/index.html new file mode 100644 index 000000000..b47f01ed7 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,29 @@ + + + + + +ReadOnlyVariables | Misti + + + + +
Version: 0.3.1

ReadOnlyVariables

+

A detector that identifies read-only variables and fields.

+

Why is it bad?

+

These variables could typically be replaced with constants to optimize performance. +Alternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally.

+

Example

+
fun calculateFinalPrice(price: Int): Int {
// Warning: the developer uses a read-only variable that could be a constant
let DISCOUNT_AMOUNT: Int = 10;
return price - DISCOUNT_AMOUNT;
}
+

Use instead:

+
const DISCOUNT_AMOUNT: Int = 10;

fun calculateFinalPrice(price: Int): Int {
// OK: Fixed after the analyzer highlighted this warning
return price - DISCOUNT_AMOUNT;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap/index.html b/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap/index.html new file mode 100644 index 000000000..d067ffe49 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap/index.html @@ -0,0 +1,29 @@ + + + + + +StringReceiversOverlap | Misti + + + + +
Version: 0.3.1

StringReceiversOverlap

+

A detector that finds overlapping messages between general string receivers and string receivers.

+

Why is it bad?

+

Constant string receivers and general string receivers can have overlapping messages +in which case the constant string receiver always takes precedence.

+

Example

+
contract Test {
receive("foobar") { throw(1042) }
receive(msg: String) {
if (msg == "foobar") { throw(1043) } // Bad: Dead code
}
}
+

Use instead:

+
contract Test {
receive("foobar") { throw(1042) }
receive(msg: String) {}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/UnboundLoops/index.html b/tools/misti/docs/0.3.1/detectors/UnboundLoops/index.html new file mode 100644 index 000000000..2cc5709a5 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/UnboundLoops/index.html @@ -0,0 +1,33 @@ + + + + + +UnboundLoops | Misti + + + + +
Version: 0.3.1

UnboundLoops

+

A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.

+

Why is it bad?

+

An unbounded loop can be problematic for several reasons:

+
    +
  • Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult.
  • +
  • Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks.
  • +
  • DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability.
  • +
+

Example

+
let x: Int = 10;
while (x > 0) {
// Bad: x is not changed due looping
send(SendParameters{ to: sender(), ... });
}
+

Use instead:

+
let x: Int = 10;
while (x > 0) {
send(SendParameters{ to: sender(), ... });
x = x - 1;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/ZeroAddress/index.html b/tools/misti/docs/0.3.1/detectors/ZeroAddress/index.html new file mode 100644 index 000000000..31c493eee --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/ZeroAddress/index.html @@ -0,0 +1,31 @@ + + + + + +ZeroAddress | Misti + + + + +
Version: 0.3.1

ZeroAddress

+

A detector that identifies uses of the zero address.

+

Why is it bad?

+

Using the zero address in smart contracts is typically problematic because it can be +exploited as a default or uninitialized address, leading to unintended transfers and +security vulnerabilities. Additionally, operations involving the zero address can +result in loss of funds or tokens, as there is no private key to access this address.

+

Example

+
contract Proxy {
to: Address;
init() {
// Warning: Insecure usage of zero address as default value
self.to = newAddress(0, 0);
}
fun setAddress(to: Address) {
self.to = to
}
}
+

Use instead:

+
contract Proxy {
to: Address;
init(to: Address) {
// Fixed: Using the input value on initialization.
self.to = to;
}
fun setAddress(to: Address) {
self.to = to
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/detectors/index.html b/tools/misti/docs/0.3.1/detectors/index.html new file mode 100644 index 000000000..d9ffbb355 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/index.html @@ -0,0 +1,26 @@ + + + + + +Detectors Overview | Misti + + + + +
Version: 0.3.1

Detectors Overview

+

Misti currently supports 15 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:

+
#DetectorRequires SouffléEnabled by default
1ArgCopyMutation
2AsmIsUsed
3BranchDuplicate
4ConstantAddress
5DivideBeforeMultiply
6DumpIsUsed
7FieldDoubleInit
8InheritedStateMutation
9NeverAccessedVariables
10PreferAugmentedAssign
11PreferredStdlibApi
12ReadOnlyVariables
13StringReceiversOverlap
14UnboundLoops
15ZeroAddress
+

Some of the detectors require Soufflé to be installed. If no Soufflé installation is found, these detectors won't be executed.

+

A few detectors are optional and aimed at auditors to help uncover subtle issues in the source code. To enable all detectors, use the --all-detectors option. You can find a full list of configuration options on the configuration page.

+

Each detector targets a specific type of problem in your code. Click on the detector name to learn more.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/hacking/contributing/index.html b/tools/misti/docs/0.3.1/hacking/contributing/index.html new file mode 100644 index 000000000..fd1c07039 --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/contributing/index.html @@ -0,0 +1,66 @@ + + + + + +Contributing Guide | Misti + + + + +
Version: 0.3.1

Contributing Guide

+

Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.

+

Issues reporting

+

When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:

+
The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.
Please help us by publishing it and the input sources at:
https://github.com/nowarp/misti/issues/new.
+

We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users.

+

Documentation contribution

+

We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: nowarp.github.io Issues. Additionally, many documentation pages have an Edit button that allows you to make direct contributions easily.

+

Code contribution

+
    +
  1. +

    Navigate Issues and Find Tasks

    +
      +
    • Browse the issues here. Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues.
    • +
    • Choose an issue suitable for you and mention in the issue that you're working on it.
    • +
    +
  2. +
  3. +

    Implement Your Changes

    +
      +
    • Implement your changes. Feel free to ask questions in the issue if needed.
    • +
    +
  4. +
  5. +

    Ensure Tests Pass

    +
      +
    • Before creating a PR, make sure all tests and CI checks are passing by running: +
      yarn test-all
      +
    • +
    +
  6. +
  7. +

    Create a PR

    +
      +
    • Submit your pull request here
    • +
    +
  8. +
  9. +

    Add a CHANGELOG entry

    +
      +
    • Describe your changes in the CHANGELOG.md file according to the existing structure.
    • +
    +
  10. +
+

All guidelines and additional hacking tips are available in the repo. For low-level details not present in the docs, refer to HACKING.md.

+

Thank you for your contributions!

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/hacking/custom-detector/index.html b/tools/misti/docs/0.3.1/hacking/custom-detector/index.html new file mode 100644 index 000000000..591376171 --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/custom-detector/index.html @@ -0,0 +1,38 @@ + + + + + +Custom Detector Guide | Misti + + + + +
Version: 0.3.1

Custom Detector Guide

+

Introduction

+

Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: Misti API Reference.

+

Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the Detector interface.

+

Creating a Detector

+

You can create a new custom detector by executing Misti with the --new-detector option: npx misti --new-detector implicitInit.

+

This will create the implicitInit.ts file, which contains the template code for writing your own custom detector logic leveraging the Misti API.

+

Here's an example of how to implement a custom detector using Misti API:

+
import { Detector } from "@nowarp/misti/dist/detectors/detector";
import { CompilationUnit } from "@nowarp/misti/dist/internals/ir";
import {
MistiTactWarning,
Severity,
} from "@nowarp/misti/dist/internals/errors";

/**
* An example of a custom detector that showcases the usage of the detector API.
*
* It reports all the contracts that doesn't have an explicit implementation of the init function.
*/
export class ImplicitInit extends Detector {
async check(cu: CompilationUnit): Promise<MistiTactWarning[]> {
return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {
if (!cu.findMethodCFGByName(contract.name, "init")) {
const err = this.makeError(
`Contract ${contract.name} doesn't define an init function`,
Severity.INFO,
contract.ref,
);
foundErrors.push(err);
}
return foundErrors;
}, [] as MistiTactWarning[]);
}
}
+

Testing the detector

+

To run Misti with only your new detector, use the --detectors option, specifying the path to the detector and the Detector class name: npx misti path/to/your/tact.config.json --detectors path/to/implicitInit.ts:ImplicitInit.

+

That's a good way to test the detector on the first run. You could also use the --verbose CLI option and set the environment variable MISTI_TRACE=1 to facilitate debugging.

+

Saving the configuration

+

After testing the detector, you can specify it in your configuration to enable it in future runs. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:

+
{
"detectors": [
// Other detectors...
{ "className": "ImplicitInit", "modulePath": "ImplicitInit.ts" }
],
}
+

After this, you could run Misti specifying a path to a custom configuration npx misti --config path/to/misti.config.json path/to/your/tact.config.json.

+

Example Detectors

+

The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the examples directory in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/hacking/design/index.html b/tools/misti/docs/0.3.1/hacking/design/index.html new file mode 100644 index 000000000..298099fc0 --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/design/index.html @@ -0,0 +1,34 @@ + + + + + +Design Overview | Misti + + + + +
Version: 0.3.1

Design Overview

+

Static Analysis

+

Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues.

+

Souffle Datalog Solver

+

Misti leverages the Souffle Datalog solver, an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases.

+

Dataflow Analysis in Misti

+

Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code.

+

References

+

For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:

+ +

These resources provide a solid foundation in the theory and practice of static and dataflow analysis.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/hacking/souffle/index.html b/tools/misti/docs/0.3.1/hacking/souffle/index.html new file mode 100644 index 000000000..1bfe157f4 --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/souffle/index.html @@ -0,0 +1,38 @@ + + + + + +Soufflé Integration Guide | Misti + + + + +
Version: 0.3.1

Soufflé Integration Guide

+

What is Soufflé?

+

Soufflé is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Soufflé, Misti can perform deep and scalable analyses of smart contracts.

+

Benefits of Using Soufflé for Static Analysis

+

Soufflé allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Soufflé program might be more straightforward then implementing a complex transfer function in for a classic monotone framework.

+

Soufflé Integration in Misti

+

The API for interacting with Soufflé in Misti is implemented in the Souffle.js library. See the Souffle.js API reference for more detailed information.

+

Creating Soufflé Programs

+

To create a Soufflé program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:

+
addDecls(ctx: Context<SrcInfo>) {
ctx.add(
Relation.from(
"varDecl",
[
["var", FactType.Symbol],
["func", FactType.Symbol],
],
undefined,
),
);
// other declarations
}
+
addRules(ctx: Context<SrcInfo>) {
// readOnly(var, func) :-
// varDecl(var, func),
// !varAssign(var, func),
// !varUse(var, func).
ctx.add(
Rule.from(
[makeAtom("readOnly", ["var", "func"])],
makeRuleBody(makeAtom("varDecl", ["var", "func"])),
makeRuleBody(makeAtom("varAssign", ["var", "func"]), {
negated: true,
}),
makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),
),
);
}
+

Generating Facts and Executing Soufflé

+

After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Soufflé executor to run the analysis:

+
const executor = ctx.config.soufflePath
? new Executor<SrcInfo>({
inputDir: ctx.config.soufflePath,
outputDir: ctx.config.soufflePath,
})
: new Executor<SrcInfo>();

const result = executor.executeSync(program);

if (!result.success) {
throw new Error(
`Error executing Soufflé for ${this.id}:\n${result.stderr}`,
);
}

const warnings = Array.from(result.results.entries.values()).map((fact) => {
// raise warnings
});
+

Learning from Existing Code

+

We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Soufflé with Misti. This will help you understand the intricacies of generating IR and executing Soufflé programs effectively.

+

Further Reading

+

For a deeper understanding of static analysis using Soufflé, refer to the textbook Program Analysis: An Appetizer by Flemming Nielson and Hanne Riis Nielson. It discusses Soufflé-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/hacking/tools/index.html b/tools/misti/docs/0.3.1/hacking/tools/index.html new file mode 100644 index 000000000..6808ec2b1 --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/tools/index.html @@ -0,0 +1,51 @@ + + + + + +Tools Guide | Misti + + + + +
Version: 0.3.1

Tools Guide

+

This page describes the internal analyzer tools available in Misti to aid in development and debugging.

+

CFG Dump

+

Misti provides a feature to dump the Control Flow Graph (CFG) in both JSON and DOT formats. This is essential for understanding the internal representation (IR) of the code and analyzing the control flow within contracts.

+

Usage

+

To dump the CFG in JSON format, use the following command:

+
npx misti --dump-cfg="json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in DOT format, use the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Converting DOT to SVG

+

To convert the resulting DOT file to an SVG for visualization, you can save the generated DOT dump to a file and use Graphviz with the following command:

+
npx misti --dump-cfg="dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot
dot -Tsvg output.dot -o output.svg
+

Viewing the SVG

+

To view the SVG file in Firefox, use the following command:

+
firefox output.svg
+

For example, for the following contract:

+
fun test(): Int {
let sum: Int = 0;
let i: Int = 0;
repeat (10) {
i = i + 1;
sum = sum + i;
}
return sum;
}
+

The following CFG will be generated:

+

CFG Example

+

VS Code Plugin

+

For real-time visualization of DOT files, you can use one of the available Graphviz plugins for Visual Studio Code. These plugins allows you to view DOT diagrams directly within the editor, facilitating easier debugging and development.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer.

    +
  • +
  • +

    DOT Dumps: These provide a visual representation of the contract's control flow. They are particularly useful for gaining a better understanding of the control flow within contracts, making it easier to identify issues and optimize the code.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/index.html b/tools/misti/docs/0.3.1/index.html new file mode 100644 index 000000000..cbc924d81 --- /dev/null +++ b/tools/misti/docs/0.3.1/index.html @@ -0,0 +1,39 @@ + + + + + +Introduction | Misti + + + + +
Version: 0.3.1

Introduction

Misti is a static analysis tool designed for smart contracts on the TON blockchain.

+

Language Support:

+ +

Use Cases

+

Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:

+
    +
  • Detect Vulnerabilities: Identify and fix potential security flaws early in the development cycle.
  • +
  • Improve Code Quality: Maintain high standards by catching bugs and enforcing best practices automatically.
  • +
  • Streamline Development: Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.
  • +
  • Custom Detectors: Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.
  • +
+

Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow.

+

Name Origin

+

The name "Misti" comes from the Misti volcano in Peru. It was chosen because it's catchy and easy to remember.

+

Funding

+

Misti has been funded by TON Foundation. This support has enabled us to develop and maintain the tool.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/tutorial/blueprint/index.html b/tools/misti/docs/0.3.1/tutorial/blueprint/index.html new file mode 100644 index 000000000..34e0da726 --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/blueprint/index.html @@ -0,0 +1,32 @@ + + + + + +Using Misti with Blueprint | Misti + + + + +
Version: 0.3.1

Using Misti with Blueprint

+

Blueprint is a development environment for writing, testing, and deploying TON smart contracts.

+

Misti can be used in Blueprint projects by leveraging the blueprint-misti plugin.

+

Getting started

+

Add the plugin and the recent version of Tact to the package.json of your Blueprint project by running:

+
yarn add @tact-lang/compiler
yarn add @nowarp/blueprint-misti
+

Then, add this configuration to blueprint.config.ts:

+
import { MistiPlugin } from '@nowarp/blueprint-misti';
export const config = {
plugins: [
new MistiPlugin(),
],
};
+

Now, try to run Misti:

+
yarn blueprint misti ./path/to/tact.config.json
+

Resources

+

For more information, please refer to the README of the blueprint-misti project. If you have any problems, feel free to reach out to us in the Misti discussion group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/tutorial/ci-cd/index.html b/tools/misti/docs/0.3.1/tutorial/ci-cd/index.html new file mode 100644 index 000000000..710ca1b23 --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/ci-cd/index.html @@ -0,0 +1,33 @@ + + + + + +Integrating Misti into CI/CD | Misti + + + + +
Version: 0.3.1

Integrating Misti into CI/CD

+

Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.

+

GitHub Actions

+

To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:

+

1. Open your GitHub repository

+

2. Create or edit the GitHub Actions workflow YAML file

+

It could be located at e.g., .github/workflows/main.yml.

+

3. Add the step to run Misti to your YAML file

+

For example:

+
name: Run Misti
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install dependencies
run: npm install

- name: Run Misti
run: npx misti /path/to/your/tact.config.json
+

The npx misti /path/to/your/tact.config.json command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail.

+

4. Adjusting the Misti Configuration

+

If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the Configuration section for more details on how to customize your settings.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/tutorial/cli/index.html b/tools/misti/docs/0.3.1/tutorial/cli/index.html new file mode 100644 index 000000000..915ba33ac --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/cli/index.html @@ -0,0 +1,102 @@ + + + + + +Command-Line Interface | Misti + + + + +
Version: 0.3.1

Command-Line Interface

+

Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.

+

--dump-cfg <json|dot>

+
    +
  • Description: Dumps the Control Flow Graph (CFG) in the requested format: JSON or Graphviz Dot.
  • +
  • Default: undefined
  • +
+

--dump-ast

+
    +
  • Description: Dumps the Abstract Syntax Tree (AST) in JSON format.
  • +
  • Default: false
  • +
+

--dump-output <PATH>

+
    +
  • Description: Specifies the directory to save the AST/CFG dump. If <PATH> is -, then the output is sent to stdout.
  • +
  • Default: Value of DUMP_STDOUT_PATH
  • +
+

--dump-include-stdlib

+
    +
  • Description: Includes standard library components in the AST/CFG dump.
  • +
  • Default: false
  • +
+

--dump-config

+
    +
  • Description: Dumps the Misti JSON configuration file in use.
  • +
  • Default: false
  • +
+

--souffle-binary <PATH>

+
    +
  • Description: Path to the Soufflé binary.
  • +
  • Default: "souffle"
  • +
+

--souffle-path <PATH>

+
    +
  • Description: Directory to save the generated Soufflé files.
  • +
  • Default: "/tmp/misti/souffle"
  • +
+

--souffle-verbose

+
    +
  • Description: Generates human-readable, but more verbose, Soufflé files.
  • +
  • Default: false
  • +
+

--tact-stdlib-path <PATH>

+
    +
  • Description: Path to the Tact standard library.
  • +
+

--verbose

+
    +
  • Description: Enables verbose output.
  • +
  • Default: false
  • +
+

--quiet

+
    +
  • Description: Suppresses all output.
  • +
  • Default: false
  • +
+

--detectors <name|path:name>

+
    +
  • Description: A comma-separated list of detectors to enable.
  • +
  • Argument Validation: Requires a non-empty list of detector names.
  • +
  • Default: undefined
  • +
+

--suppress <names>

+
    +
  • Description: A comma-separated list of detector names to suppress.
  • +
  • Argument Validation: Requires a non-empty list of detector names.
  • +
  • Default: undefined
  • +
+

--all-detectors

+
    +
  • Description: Enables all the available built-in detectors.
  • +
  • Default: false
  • +
+

--config <PATH>

+
    +
  • Description: Path to the Misti configuration file.
  • +
+

--new-detector <PATH>

+
    +
  • Description: Creates a new custom detector at the specified path.
  • +
  • Default: undefined
  • +
+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/tutorial/configuration/index.html b/tools/misti/docs/0.3.1/tutorial/configuration/index.html new file mode 100644 index 000000000..2a2b4aed4 --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/configuration/index.html @@ -0,0 +1,63 @@ + + + + + +Configuration | Misti + + + + +
Version: 0.3.1

Configuration

+

This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.

+

Configuration Options

+
    +
  • +

    detectors: List of detectors to run. Each detector can be specified with a className and optionally a modulePath if it’s a custom detector.

    +
      +
    • className (string, required): The class name of the detector.
    • +
    • modulePath (string, optional): The file path of the detector module.
    • +
    +
  • +
  • +

    ignoredProjects (array of strings, optional): List of Tact projects to ignore during analysis.

    +
  • +
  • +

    soufflePath (string, optional): Directory to save generated Soufflé files which is helpful for debugging purposes. If not set, a temporary directory will be used.

    +
  • +
  • +

    souffleVerbose (boolean, optional): If set, generates more readable Soufflé files instead of making the result source code smaller.

    +
  • +
  • +

    tactStdlibPath (string, optional): Path to Tact standard library. If not set, the default stdlib from the actual Tact setup will be used.

    +
  • +
  • +

    unusedPrefix (string, default: "_"): Identifiers starting with this prefix won't be reported as unused by built-in detectors.

    +
  • +
  • +

    verbosity (string, optional): Verbosity level of the logs. Possible values are quiet, debug, and default.

    +
  • +
+

Running Misti with Configuration

+

To run Misti with the specified configuration file, use the following command:

+
npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json
+

This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration.

+

Default Configuration File

+

By default, Misti enables all built-in detectors. Below is an example of the default configuration file:

+
{
"detectors": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },
{ "className": "BranchDuplicate" },
{ "className": "FieldDoubleInit" },
{ "className": "PreferAugmentedAssign" },
{ "className": "StringReceiversOverlap" },
{ "className": "ArgCopyMutation" }
],
"ignoredProjects": [],
"soufflePath": "/tmp/misti/souffle",
"souffleVerbose": false,
"unusedPrefix": "_",
"verbosity": "default"
}
+

All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: configSchema.json.

+

You can always dump the Misti configuration file in use by passing the --dump-config option in the CLI:

+
npx misti --dump-config test/projects/simple/tactConfig.json
+

If there is no Misti config in the simple directory, Misti dumps the default config. This can be used to adjust it, e.g., adding or suppressing some detectors.

+

Getting Help

+

If you need assistance or encounter any issues, please create an issue on GitHub at nowarp/misti or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/0.3.1/tutorial/getting-started/index.html b/tools/misti/docs/0.3.1/tutorial/getting-started/index.html new file mode 100644 index 000000000..4bf7d18c1 --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/getting-started/index.html @@ -0,0 +1,62 @@ + + + + + +Getting started | Misti + + + + +
Version: 0.3.1

Getting started

+

This guide will walk you through the steps to install and set up the Misti static analyzer.

+

Prerequisites

+

Before you begin, ensure you have the following software installed on your system:

+
    +
  • Git
  • +
  • Yarn
  • +
  • Node.js version 22 or higher
  • +
  • Soufflé
  • +
+

Installation

+

Misti is distributed via npm and should be added to your Tact project in the same way as Tact itself:

+
yarn add @nowarp/misti
+

Using Development Version

+

The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis.

+

To install the latest development version you should:

+
    +
  1. Clone Misti: git clone https://github.com/nowarp/misti
  2. +
  3. Build it: cd misti && yarn install && yarn build
  4. +
  5. Use it in your Tact project: cd /path/to/tact/project && yarn add file:/path/to/misti
  6. +
+

Running the analysis

+

Run Misti by specifying a Tact project configuration:

+
npx misti path/to/tact.config.json
+

This will highlight any warnings the analyzer found.

+

You can also add a script to your package.json to simplify running the linting process:

+
{
"scripts": {
"lint": "npx misti path/to/tact.config.json"
}
}
+

More usage examples

+

Below are a few usage examples for common scenarios when using the misti CLI.

+

Suppressing Specific Detectors

+

To run misti while suppressing specific detectors, such as ReadOnlyVariables:

+
npx misti --suppress ReadOnlyVariables path/to/tact.config.json
+

Enabling All Detectors

+

Running misti with all available built-in detectors enabled:

+
npx misti --all-detectors path/to/tact.config.json
+

It is recommended to do that when auditing the project.

+

Running in Quiet Mode

+

To suppress all output while running misti getting just a return code:

+
npx misti --quiet path/to/tact.config.json
+

This might be useful in scripts and CI/CD.

+

Troubleshooting

+

If you encounter any issues during the installation process, feel free to create an issue or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/ArgCopyMutation/index.html b/tools/misti/docs/detectors/ArgCopyMutation/index.html new file mode 100644 index 000000000..392014b6f --- /dev/null +++ b/tools/misti/docs/detectors/ArgCopyMutation/index.html @@ -0,0 +1,34 @@ + + + + + +ArgCopyMutation | Misti + + + + +
Version: 0.4.0

ArgCopyMutation

+

A detector that highlights cases where function argument mutations are ineffective +due to call-by-value semantics in Tact.

+

Why is it bad?

+

In Tact, function arguments are passed by value, meaning that any mutations applied +to these arguments will only affect the local copy of the variable within the function. +Such mutations are unobservable outside the function, except for potentially +increasing gas consumption or causing exceptions.

+

Example

+
fun addEntry(m: map<Int,Int>) {
m.set(1, 10); // Bad: Mutating the copy
}
+

Use instead:

+
fun addEntry() {
self.m.set(1, 10); // OK: Changing contract's state
}
+

Alternatively, you could redesign the method:

+
fun generateNewValue(): Int {
// ... produce new value for the map
return self.nextValue + 1;
}

m.set(self.nextKey, self.generateNewValue()); // OK
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/AsmIsUsed/index.html b/tools/misti/docs/detectors/AsmIsUsed/index.html new file mode 100644 index 000000000..241c71c84 --- /dev/null +++ b/tools/misti/docs/detectors/AsmIsUsed/index.html @@ -0,0 +1,28 @@ + + + + + +AsmIsUsed | Misti + + + + +
Version: 0.4.0

AsmIsUsed

+

An optional detector that highlights all the asm functions.

+

Why is it bad?

+

Using TVM Assembly is a potentially dangerous operation that requires additional +attention from an auditor. This optional detector will highlight all its uses to +assist in contract security audits.

+

Example

+
// Highlighted: the asm function use should be audited
asm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE }
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/BranchDuplicate/index.html b/tools/misti/docs/detectors/BranchDuplicate/index.html new file mode 100644 index 000000000..dded3457f --- /dev/null +++ b/tools/misti/docs/detectors/BranchDuplicate/index.html @@ -0,0 +1,33 @@ + + + + + +BranchDuplicate | Misti + + + + +
Version: 0.4.0

BranchDuplicate

+

Detector that reports duplicated code in conditional branches.

+

Why is it bad?

+

Duplicated code in branches is bad because it:

+
    +
  1. Reduces Readability: Repetition makes the code harder to understand.
  2. +
  3. Increases Maintenance: Changes must be made in multiple places, risking errors.
  4. +
  5. Signals Poor Design: It suggests missed opportunities for cleaner, more abstract code.
  6. +
+

Example

+
if (a > 42) {
a = 43; // bad: duplicated code
} else {
a = 43;
}
+

Use instead:

+
if (a > 42) {
a = inc(b); // ok
} else {
a = 43;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/ConstantAddress/index.html b/tools/misti/docs/detectors/ConstantAddress/index.html new file mode 100644 index 000000000..51b3c265f --- /dev/null +++ b/tools/misti/docs/detectors/ConstantAddress/index.html @@ -0,0 +1,31 @@ + + + + + +ConstantAddress | Misti + + + + +
Version: 0.4.0

ConstantAddress

+

An optional detector that highlights all the constant addresses appearing in the source code.

+

Why is it bad?

+

Using hardcoded addresses can sometimes indicate poor contract design. +Some constant addresses may need to be set dynamically, e.g., using +contractAddress, or at least have a way to change them at runtime, for +example, when upgrading a contract.

+

Example

+
contract Main {
proxy: Address;
init() {
// Bad: Constant address highlighted by the analyzer.
self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");
}
}
+

Use instead:

+
contract Main {
proxy: Address;
init() {
let proxy: Proxy = initOf Proxy(myAddress());
// OK: Address depends on how the proxy contact has been deployed
self.proxy = contractAddress(proxy);
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/DivideBeforeMultiply/index.html b/tools/misti/docs/detectors/DivideBeforeMultiply/index.html new file mode 100644 index 000000000..f96ebe8a5 --- /dev/null +++ b/tools/misti/docs/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,34 @@ + + + + + +DivideBeforeMultiply | Misti + + + + +
Version: 0.4.0

DivideBeforeMultiply

+

A detector that identifies and corrects instances of division before multiplication to +ensure accurate mathematical operations.

+

Why is it bad?

+

Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:

+
    +
  • Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers.
  • +
  • Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations.
  • +
  • Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging.
  • +
+

Example

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Bad: Division before multiplication
let result: Int = a / b * c;
+

Use instead:

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Correct: Multiplication before division
let result: Int = a * c / b;
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/DumpIsUsed/index.html b/tools/misti/docs/detectors/DumpIsUsed/index.html new file mode 100644 index 000000000..ced70f7ba --- /dev/null +++ b/tools/misti/docs/detectors/DumpIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +DumpIsUsed | Misti + + + + +
Version: 0.4.0

DumpIsUsed

+

An optional detector that highlights all the dump debug prints.

+

Why is it bad?

+

The dump function is a debug print that shouldn't be in the final code. +Even though the compiler removes it in production, its presence suggests the +developer was debugging something. This can flag areas where issues might exist, +so auditors should take a closer look at these parts of the code.

+

Example

+
fun test(): Int {
// ... other computations
let combined: Int = (RANDOM_SEED >> half_shift) &
(MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;
dump(combined); // Suspicious: Highlighted by the detector
}
+

Use instead:

+
fun test(): Int {
// ... other computations
let combined: Int = this.seed ^ shift_mask
// OK: The code was reviewed and simplified; `dump` was removed
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/DuplicatedCondition/index.html b/tools/misti/docs/detectors/DuplicatedCondition/index.html new file mode 100644 index 000000000..438fd8e08 --- /dev/null +++ b/tools/misti/docs/detectors/DuplicatedCondition/index.html @@ -0,0 +1,29 @@ + + + + + +DuplicatedCondition | Misti + + + + +
Version: 0.4.0

DuplicatedCondition

+

A detector that finds duplicated conditions appearing in conditional expressions.

+

Why is it bad?

+

Typically, these cases are developer errors caused by copy-pasting code, leading +to unreachable code.

+

Example

+
fun test(a: Int): Int {
if (a < 1) { return 1; }
else if (a > 4) { return 2; }
// Bad: A developer copy-pasted the condition
else if (a > 4) { return 3; }
return 4;
}
+

Use instead:

+
fun test(a: Int): Int {
if (a < 1) { return 1; }
else if (a > 4) { return 2; }
// OK: Fixed
else if (a < x) { return 3; }
return 4;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/EnsurePrgSeed/index.html b/tools/misti/docs/detectors/EnsurePrgSeed/index.html new file mode 100644 index 000000000..e0fddb972 --- /dev/null +++ b/tools/misti/docs/detectors/EnsurePrgSeed/index.html @@ -0,0 +1,32 @@ + + + + + +EnsurePrgSeed | Misti + + + + +
Version: 0.4.0

EnsurePrgSeed

+

A detector that identifies all calls to nativeRandom and nativeRandomInterval +without a preceding PRG seed initialization.

+

Why is it bad?

+

Using nativeRandom or nativeRandomInterval without first initializing the PRG seed via +nativePrepareRandom, nativeRandomize, or nativeRandomizeLt may lead to unintended behavior +or weak random number generation. This detector ensures that PRG seed initialization +is always performed before any use of random functions, enhancing contract security.

+

Example

+
// Bad: `nativeRandom` is used without prior PRG seed initialization
fun generateRandomValue(): Int {
return nativeRandom()
}
+

Use instead:

+
fun test(): Int {
nativePrepareRandom();
}

// OK: PRG has been initialized somewhere in the contract
fun generateRandomValue(): Int {
return nativeRandom()
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/FalseCondition/index.html b/tools/misti/docs/detectors/FalseCondition/index.html new file mode 100644 index 000000000..9eaeafb8b --- /dev/null +++ b/tools/misti/docs/detectors/FalseCondition/index.html @@ -0,0 +1,31 @@ + + + + + +FalseCondition | Misti + + + + +
Version: 0.4.0

FalseCondition

+

A detector that highlights conditions that evaluate to a constant true or false +in if, while, or until statements, and zero iterations in repeat statements.

+

Why is it bad?

+

Conditions that always evaluate to a constant true or false are likely the result of a typo +or logic error. Such conditions can lead to unintended behavior, dead code, or incorrect control flow. +This detector helps identify these cases so they can be corrected, improving the code's reliability.

+

Example

+
const FALSE: Bool = false;
// Bad: Always false because of operator precedence
if ((param | value) & FALSE) {
// ... never executed
}
+

Use instead:

+
const FALSE: Bool = false;
// OK: Fixed after the analyzer highlighted this
if (param) {}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/FieldDoubleInit/index.html b/tools/misti/docs/detectors/FieldDoubleInit/index.html new file mode 100644 index 000000000..4806710c0 --- /dev/null +++ b/tools/misti/docs/detectors/FieldDoubleInit/index.html @@ -0,0 +1,32 @@ + + + + + +FieldDoubleInit | Misti + + + + +
Version: 0.4.0

FieldDoubleInit

+

A detector that highlights cases where a field is initialized both in the +init function and at the point of definition.

+

Why is it bad?

+

Double initialization of fields can either be a programmer's mistake or simply +a waste of gas. It is always preferred to initialize values in the field declaration +if they have a compile-time evaluatable default value, or in the init function if +they must be initialized dynamically.

+

Example

+
contract Test {
a: Int = 0; // Bad
init(x: Int) { self.a = x }
}
+

Use instead:

+
contract Test {
a: Int; // Fixed
init(x: Int) { self.a = x }
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/InheritedStateMutation/index.html b/tools/misti/docs/detectors/InheritedStateMutation/index.html new file mode 100644 index 000000000..4b0cf59c6 --- /dev/null +++ b/tools/misti/docs/detectors/InheritedStateMutation/index.html @@ -0,0 +1,33 @@ + + + + + +InheritedStateMutation | Misti + + + + +
Version: 0.4.0

InheritedStateMutation

+

An optional detector that highlights all instances where inherited trait variables +are directly modified.

+

Why is it bad?

+

Traits should provide setter methods to ensure that invariants related to their +state are preserved. Directly modifying trait variables (e.g., self.traitVar = 42) +can violate these invariants, leading to potential bugs or security vulnerabilities. +This detector warns when such direct modifications occur, prompting further review +by auditors.

+

Example

+
trait T {
balance: Int;
}

contract C with T {
balance: Int = 42;
fun updateBalance() {
self.balance = 100; // Suspicious: Highlighted by the detector
}
}
+

Use instead:

+
trait T {
balance: Int;
fun setBalance(newBalance: Int) {
require(newBalance > 0, "balance cannot be negative"); // Invariant check
self.balance = newBalance;
}
}

contract C with T {
balance: Int = 42;
fun updateBalance() {
self.setBalance(100); // OK: Invariant preserved
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/NeverAccessedVariables/index.html b/tools/misti/docs/detectors/NeverAccessedVariables/index.html new file mode 100644 index 000000000..edc264fbb --- /dev/null +++ b/tools/misti/docs/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,30 @@ + + + + + +NeverAccessedVariables | Misti + + + + +
Version: 0.4.0

NeverAccessedVariables

+

A detector that identifies write-only or unused variables, fields and constants.

+

Why is it bad?

+

These variables are either assigned but never used in any meaningful computation, +or they are declared and never used at all, which may indicate redundant code +or an incomplete implementation of the intended logic.

+

Example

+
// Error: the developer forgot to use the constant
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+

Use instead:

+
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
// OK: Fixed after the analyzer highlighted this warning
require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/OptimalMathFunction/index.html b/tools/misti/docs/detectors/OptimalMathFunction/index.html new file mode 100644 index 000000000..964642523 --- /dev/null +++ b/tools/misti/docs/detectors/OptimalMathFunction/index.html @@ -0,0 +1,28 @@ + + + + + +OptimalMathFunction | Misti + + + + + + + \ No newline at end of file diff --git a/tools/misti/docs/detectors/PreferAugmentedAssign/index.html b/tools/misti/docs/detectors/PreferAugmentedAssign/index.html new file mode 100644 index 000000000..124df2c31 --- /dev/null +++ b/tools/misti/docs/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,31 @@ + + + + + +PreferAugmentedAssign | Misti + + + + +
Version: 0.4.0

PreferAugmentedAssign

+

Detects non-idiomatic statements that can be written using augmented assignment +operators like +=, -=, etc.

+

Why is it bad?

+

Using augmented assignment operations improves the readability of the source code +and reduces the risk of mistakes, such as those that occur during copy-pasting +and refactoring code.

+

Example

+
msgValue = (msgValue - ctx.readForwardFee());
+

Use instead:

+
msgValue -= ctx.readForwardFee());
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/PreferredStdlibApi/index.html b/tools/misti/docs/detectors/PreferredStdlibApi/index.html new file mode 100644 index 000000000..6deea5dac --- /dev/null +++ b/tools/misti/docs/detectors/PreferredStdlibApi/index.html @@ -0,0 +1,34 @@ + + + + + +PreferredStdlibApi | Misti + + + + +
Version: 0.4.0

PreferredStdlibApi

+

An optional detector that flags the use of advanced functions from the standard library.

+

Why is it bad?

+

Auditors should pay extra attention to these functions, as incorrect usage can +lead to subtle bugs. Safer stdlib alternatives should be preferred in the code.

+

Supported functions:

+ +

Example

+
let pkg: Slice = msg.transfer;
let _seqno: Int = pkg.loadInt(32);
let mode: Int = pkg.loadInt(8);
let body: Cell = pkg.loadRef();
// Bad: prefer `send` to avoid low-level manipulation of Slice
nativeSendMessage(body, mode);
+

Use instead:

+
// Safer: More explicit definition of the send operation
send(SendParameters{ value: amount,
to: self.owner,
mode: mode,
body: beginCell().endCell() });
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/ReadOnlyVariables/index.html b/tools/misti/docs/detectors/ReadOnlyVariables/index.html new file mode 100644 index 000000000..70555ef8f --- /dev/null +++ b/tools/misti/docs/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,29 @@ + + + + + +ReadOnlyVariables | Misti + + + + +
Version: 0.4.0

ReadOnlyVariables

+

A detector that identifies read-only variables and fields.

+

Why is it bad?

+

These variables could typically be replaced with constants to optimize performance. +Alternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally.

+

Example

+
fun calculateFinalPrice(price: Int): Int {
// Warning: the developer uses a read-only variable that could be a constant
let DISCOUNT_AMOUNT: Int = 10;
return price - DISCOUNT_AMOUNT;
}
+

Use instead:

+
const DISCOUNT_AMOUNT: Int = 10;

fun calculateFinalPrice(price: Int): Int {
// OK: Fixed after the analyzer highlighted this warning
return price - DISCOUNT_AMOUNT;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/StringReceiversOverlap/index.html b/tools/misti/docs/detectors/StringReceiversOverlap/index.html new file mode 100644 index 000000000..e67237be6 --- /dev/null +++ b/tools/misti/docs/detectors/StringReceiversOverlap/index.html @@ -0,0 +1,29 @@ + + + + + +StringReceiversOverlap | Misti + + + + +
Version: 0.4.0

StringReceiversOverlap

+

A detector that finds overlapping messages between general string receivers and string receivers.

+

Why is it bad?

+

Constant string receivers and general string receivers can have overlapping messages +in which case the constant string receiver always takes precedence.

+

Example

+
contract Test {
receive("foobar") { throw(1042) }
receive(msg: String) {
if (msg == "foobar") { throw(1043) } // Bad: Dead code
}
}
+

Use instead:

+
contract Test {
receive("foobar") { throw(1042) }
receive(msg: String) {}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/UnboundLoops/index.html b/tools/misti/docs/detectors/UnboundLoops/index.html new file mode 100644 index 000000000..ef0974010 --- /dev/null +++ b/tools/misti/docs/detectors/UnboundLoops/index.html @@ -0,0 +1,33 @@ + + + + + +UnboundLoops | Misti + + + + +
Version: 0.4.0

UnboundLoops

+

A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.

+

Why is it bad?

+

An unbounded loop can be problematic for several reasons:

+
    +
  • Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult.
  • +
  • Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks.
  • +
  • DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability.
  • +
+

Example

+
let x: Int = 10;
while (x > 0) {
// Bad: x is not changed due looping
send(SendParameters{ to: sender(), ... });
}
+

Use instead:

+
let x: Int = 10;
while (x > 0) {
send(SendParameters{ to: sender(), ... });
x = x - 1;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/UnusedOptional/index.html b/tools/misti/docs/detectors/UnusedOptional/index.html new file mode 100644 index 000000000..71b021c21 --- /dev/null +++ b/tools/misti/docs/detectors/UnusedOptional/index.html @@ -0,0 +1,31 @@ + + + + + +UnusedOptional | Misti + + + + +
Version: 0.4.0

UnusedOptional

+

A detector variables and fields with unused optional modifier.

+

Why is it bad?

+

Optional is a nullable value that has a special null value indicating the absence +of a value. If a developer creates an optional variable or field, he should leverage +its functionality by accessing the null value somewhere in his code. Otherwise, +the optional type should be removed to simplify and optimize the code.

+

Example

+
contract Test {
a: Int?; // Bad: null value is never accessed
init() { self.a = 42; }
get fun getA(): Int { return self.a!!; }
}
+

Use instead:

+
contract Test {
a: Int = 42; // OK: Removed optional
get fun getA(): Int { return self.a; }
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/ZeroAddress/index.html b/tools/misti/docs/detectors/ZeroAddress/index.html new file mode 100644 index 000000000..122678181 --- /dev/null +++ b/tools/misti/docs/detectors/ZeroAddress/index.html @@ -0,0 +1,31 @@ + + + + + +ZeroAddress | Misti + + + + +
Version: 0.4.0

ZeroAddress

+

A detector that identifies uses of the zero address.

+

Why is it bad?

+

Using the zero address in smart contracts is typically problematic because it can be +exploited as a default or uninitialized address, leading to unintended transfers and +security vulnerabilities. Additionally, operations involving the zero address can +result in loss of funds or tokens, as there is no private key to access this address.

+

Example

+
contract Proxy {
to: Address;
init() {
// Warning: Insecure usage of zero address as default value
self.to = newAddress(0, 0);
}
fun setAddress(to: Address) {
self.to = to
}
}
+

Use instead:

+
contract Proxy {
to: Address;
init(to: Address) {
// Fixed: Using the input value on initialization.
self.to = to;
}
fun setAddress(to: Address) {
self.to = to
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/index.html b/tools/misti/docs/detectors/index.html new file mode 100644 index 000000000..8d3e0d592 --- /dev/null +++ b/tools/misti/docs/detectors/index.html @@ -0,0 +1,26 @@ + + + + + +Detectors Overview | Misti + + + + +
Version: 0.4.0

Detectors Overview

+

Misti currently supports 20 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices:

+
#DetectorSeverityRequires SouffléEnabled by default
1ArgCopyMutationHigh
2AsmIsUsedInfo
3BranchDuplicateHigh
4ConstantAddressInfo
5DivideBeforeMultiplyHigh
6DumpIsUsedInfo
7DuplicatedConditionHigh
8EnsurePrgSeedMedium
9FalseConditionMedium
10FieldDoubleInitMedium
11InheritedStateMutationLow
12NeverAccessedVariablesMedium
13OptimalMathFunctionLow
14PreferAugmentedAssignInfo
15PreferredStdlibApiInfo
16ReadOnlyVariablesMedium
17StringReceiversOverlapHigh
18UnboundLoopsHigh
19UnusedOptionalLow
20ZeroAddressLow
+

Some of the detectors require Soufflé to be installed. If no Soufflé installation is found, these detectors won't be executed.

+

A few detectors are optional and aimed at auditors to help uncover subtle issues in the source code. To enable all detectors, use the --all-detectors option. You can find a full list of configuration options on the configuration page.

+

Each detector targets a specific type of problem in your code. Click on the detector name to learn more.

+ + \ No newline at end of file diff --git a/tools/misti/docs/hacking/contributing/index.html b/tools/misti/docs/hacking/contributing/index.html new file mode 100644 index 000000000..10614616f --- /dev/null +++ b/tools/misti/docs/hacking/contributing/index.html @@ -0,0 +1,66 @@ + + + + + +Contributing Guide | Misti + + + + +
Version: 0.4.0

Contributing Guide

+

Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.

+

Issues reporting

+

When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:

+
The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.
Please help us by publishing it and the input sources at:
https://github.com/nowarp/misti/issues/new.
+

We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users.

+

Documentation contribution

+

We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: nowarp.github.io Issues. Additionally, many documentation pages have an Edit button that allows you to make direct contributions easily.

+

Code contribution

+
    +
  1. +

    Navigate Issues and Find Tasks

    +
      +
    • Browse the issues here. Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues.
    • +
    • Choose an issue suitable for you and mention in the issue that you're working on it.
    • +
    +
  2. +
  3. +

    Implement Your Changes

    +
      +
    • Implement your changes. Feel free to ask questions in the issue if needed.
    • +
    +
  4. +
  5. +

    Ensure Tests Pass

    +
      +
    • Before creating a PR, make sure all tests and CI checks are passing by running: +
      yarn test-all
      +
    • +
    +
  6. +
  7. +

    Create a PR

    +
      +
    • Submit your pull request here
    • +
    +
  8. +
  9. +

    Add a CHANGELOG entry

    +
      +
    • Describe your changes in the CHANGELOG.md file according to the existing structure.
    • +
    +
  10. +
+

See Developing Misti for information about initializing the environment and additional hacking tips.

+

Thank you for your contributions!

+ + \ No newline at end of file diff --git a/tools/misti/docs/hacking/custom-detector/index.html b/tools/misti/docs/hacking/custom-detector/index.html new file mode 100644 index 000000000..922627ccf --- /dev/null +++ b/tools/misti/docs/hacking/custom-detector/index.html @@ -0,0 +1,38 @@ + + + + + +Custom Detector Guide | Misti + + + + +
Version: 0.4.0

Custom Detector Guide

+

Introduction

+

Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: Misti API Reference.

+

Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the Detector interface.

+

Creating a Detector

+

You can create a new custom detector by executing Misti with the --new-detector option: npx misti --new-detector implicitInit.

+

This will create the implicitInit.ts file, which contains the template code for writing your own custom detector logic leveraging the Misti API.

+

Here's an example of how to implement a custom detector using Misti API:

+
import { ASTDetector } from "@nowarp/misti/dist/detectors/detector";
import { CompilationUnit } from "@nowarp/misti/dist/internals/ir";
import {
MistiTactWarning,
Severity,
} from "@nowarp/misti/dist/internals/errors";

/**
* An example of a custom detector that showcases the usage of the detector API.
*
* It reports all the contracts that doesn't have an explicit implementation of the init function.
*/
export class ImplicitInit extends ASTDetector {
severity = Severity.INFO;

async check(cu: CompilationUnit): Promise<MistiTactWarning[]> {
return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {
if (!cu.findMethodCFGByName(contract.name, "init")) {
const err = this.makeWarning(
`Contract ${contract.name} doesn't define an init function`,
contract.ref,
);
foundErrors.push(err);
}
return foundErrors;
}, [] as MistiTactWarning[]);
}
}

+

Testing the detector

+

To run Misti with only your new detector, use the --detectors option, specifying the path to the detector and the Detector class name: npx misti path/to/your/tact.config.json --detectors path/to/implicitInit.ts:ImplicitInit.

+

That's a good way to test the detector on the first run. You could also use the --verbose CLI option and set the environment variable MISTI_TRACE=1 to facilitate debugging.

+

Saving the configuration

+

After testing the detector, you can specify it in your configuration to enable it in future runs. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:

+
{
"detectors": [
// Other detectors...
{ "className": "ImplicitInit", "modulePath": "ImplicitInit.ts" }
],
}
+

After this, you could run Misti specifying a path to a custom configuration npx misti --config path/to/misti.config.json path/to/your/tact.config.json.

+

Example Detectors

+

The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the examples directory in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/hacking/design/index.html b/tools/misti/docs/hacking/design/index.html new file mode 100644 index 000000000..236f469fe --- /dev/null +++ b/tools/misti/docs/hacking/design/index.html @@ -0,0 +1,34 @@ + + + + + +Design Overview | Misti + + + + +
Version: 0.4.0

Design Overview

+

Static Analysis

+

Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues.

+

Souffle Datalog Solver

+

Misti leverages the Souffle Datalog solver, an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases.

+

Dataflow Analysis in Misti

+

Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code.

+

References

+

For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:

+ +

These resources provide a solid foundation in the theory and practice of static and dataflow analysis.

+ + \ No newline at end of file diff --git a/tools/misti/docs/hacking/developing-misti/index.html b/tools/misti/docs/hacking/developing-misti/index.html new file mode 100644 index 000000000..c88cb4ee0 --- /dev/null +++ b/tools/misti/docs/hacking/developing-misti/index.html @@ -0,0 +1,44 @@ + + + + + +Developing Misti | Misti + + + + +
Version: 0.4.0

Developing Misti

+

Prerequisites

+

Before you begin, please refer to the Getting Started documentation for the required system dependencies.

+

Cloning the Repository

+

Clone the Misti repository:

+
git clone 'https://github.com/nowarp/misti'
+

Building the Project

+

Navigate to the project directory, install dependencies, generate necessary files, and build the project:

+
cd misti && yarn install && yarn gen && yarn build
+

Running the Analyzer

+

During development, you can run the analyzer using:

+
yarn misti
+

For example, to run it for tests:

+
yarn misti test/good/never-accessed.tact
+

Adding Backtraces to the Logger

+

To add debug traces to all log messages, set the MISTI_TRACE environment variable to 1:

+
export MISTI_TRACE=1
+

Updating Expected Outputs of Tests

+

To update the expected outputs of tests, set the BLESS environment variable and run the tests:

+
BLESS=1 yarn test
+

You can also run a single test or update its expected output when working with a specific test file:

+
BLESS=1 yarn test test/tactIR.spec.ts tests/good/never-accessed.tact
+

And for another specific test:

+
BLESS=1 yarn test test/builtinDetectors.spec.ts test/good/branch-duplicate.tact
+ + \ No newline at end of file diff --git a/tools/misti/docs/hacking/souffle/index.html b/tools/misti/docs/hacking/souffle/index.html new file mode 100644 index 000000000..45a7ba9dc --- /dev/null +++ b/tools/misti/docs/hacking/souffle/index.html @@ -0,0 +1,38 @@ + + + + + +Soufflé Integration Guide | Misti + + + + +
Version: 0.4.0

Soufflé Integration Guide

+

What is Soufflé?

+

Soufflé is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Soufflé, Misti can perform deep and scalable analyses of smart contracts.

+

Benefits of Using Soufflé for Static Analysis

+

Soufflé allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Soufflé program might be more straightforward then implementing a complex transfer function in for a classic monotone framework.

+

Soufflé Integration in Misti

+

The API for interacting with Soufflé in Misti is implemented in the Souffle.js library. See the Souffle.js API reference for more detailed information.

+

Creating Soufflé Programs

+

To create a Soufflé program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:

+
addDecls(ctx: Context<SrcInfo>) {
ctx.add(
Relation.from(
"varDecl",
[
["var", FactType.Symbol],
["func", FactType.Symbol],
],
undefined,
),
);
// other declarations
}
+
addRules(ctx: Context<SrcInfo>) {
// readOnly(var, func) :-
// varDecl(var, func),
// !varAssign(var, func),
// !varUse(var, func).
ctx.add(
Rule.from(
[makeAtom("readOnly", ["var", "func"])],
makeRuleBody(makeAtom("varDecl", ["var", "func"])),
makeRuleBody(makeAtom("varAssign", ["var", "func"]), {
negated: true,
}),
makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),
),
);
}
+

Generating Facts and Executing Soufflé

+

After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Soufflé executor to run the analysis:

+
const executor = ctx.config.soufflePath
? new Executor<SrcInfo>({
inputDir: ctx.config.soufflePath,
outputDir: ctx.config.soufflePath,
})
: new Executor<SrcInfo>();

const result = executor.executeSync(program);

if (!result.success) {
throw new Error(
`Error executing Soufflé for ${this.id}:\n${result.stderr}`,
);
}

const warnings = Array.from(result.results.entries.values()).map((fact) => {
// raise warnings
});
+

Learning from Existing Code

+

We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Soufflé with Misti. This will help you understand the intricacies of generating IR and executing Soufflé programs effectively.

+

Further Reading

+

For a deeper understanding of static analysis using Soufflé, refer to the textbook Program Analysis: An Appetizer by Flemming Nielson and Hanne Riis Nielson. It discusses Soufflé-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field.

+ + \ No newline at end of file diff --git a/tools/misti/docs/index.html b/tools/misti/docs/index.html new file mode 100644 index 000000000..94e26e554 --- /dev/null +++ b/tools/misti/docs/index.html @@ -0,0 +1,44 @@ + + + + + +Introduction | Misti + + + + +
Version: 0.4.0

Introduction

Misti is a static analysis tool designed for smart contracts on the TON blockchain.

+

Language Support:

+ +

Use Cases

+

Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:

+
    +
  • Detect Vulnerabilities: Identify and fix potential security flaws early in the development cycle.
  • +
  • Improve Code Quality: Maintain high standards by catching bugs and enforcing best practices automatically.
  • +
  • Streamline Development: Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.
  • +
  • Custom Detectors: Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.
  • +
+

Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow.

+

Name Origin

+

The name "Misti" comes from the Misti volcano in Peru. It was chosen because it's catchy and easy to remember.

+

Funding

+

Misti has been funded by the following TON Foundation grants:

+ +

This support has enabled us to develop and maintain the tool.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/ArgCopyMutation/index.html b/tools/misti/docs/next/detectors/ArgCopyMutation/index.html new file mode 100644 index 000000000..bb6cd143e --- /dev/null +++ b/tools/misti/docs/next/detectors/ArgCopyMutation/index.html @@ -0,0 +1,34 @@ + + + + + +ArgCopyMutation | Misti + + + + +
Version: Next

ArgCopyMutation

+

A detector that highlights cases where function argument mutations are ineffective +due to call-by-value semantics in Tact.

+

Why is it bad?

+

In Tact, function arguments are passed by value, meaning that any mutations applied +to these arguments will only affect the local copy of the variable within the function. +Such mutations are unobservable outside the function, except for potentially +increasing gas consumption or causing exceptions.

+

Example

+
fun addEntry(m: map<Int,Int>) {
m.set(1, 10); // Bad: Mutating the copy
}
+

Use instead:

+
fun addEntry() {
self.m.set(1, 10); // OK: Changing contract's state
}
+

Alternatively, you could redesign the method:

+
fun generateNewValue(): Int {
// ... produce new value for the map
return self.nextValue + 1;
}

m.set(self.nextKey, self.generateNewValue()); // OK
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/AsmIsUsed/index.html b/tools/misti/docs/next/detectors/AsmIsUsed/index.html new file mode 100644 index 000000000..e8bbc919b --- /dev/null +++ b/tools/misti/docs/next/detectors/AsmIsUsed/index.html @@ -0,0 +1,28 @@ + + + + + +AsmIsUsed | Misti + + + + +
Version: Next

AsmIsUsed

+

An optional detector that highlights all the asm functions.

+

Why is it bad?

+

Using TVM Assembly is a potentially dangerous operation that requires additional +attention from an auditor. This optional detector will highlight all its uses to +assist in contract security audits.

+

Example

+
// Highlighted: the asm function use should be audited
asm fun getStorageFee(cells: Int, bits: Int, seconds: Int, is_masterchain: Bool): Int { GETSTORAGEFEE }
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/BranchDuplicate/index.html b/tools/misti/docs/next/detectors/BranchDuplicate/index.html new file mode 100644 index 000000000..1a08ea36d --- /dev/null +++ b/tools/misti/docs/next/detectors/BranchDuplicate/index.html @@ -0,0 +1,33 @@ + + + + + +BranchDuplicate | Misti + + + + +
Version: Next

BranchDuplicate

+

Detector that reports duplicated code in conditional branches.

+

Why is it bad?

+

Duplicated code in branches is bad because it:

+
    +
  1. Reduces Readability: Repetition makes the code harder to understand.
  2. +
  3. Increases Maintenance: Changes must be made in multiple places, risking errors.
  4. +
  5. Signals Poor Design: It suggests missed opportunities for cleaner, more abstract code.
  6. +
+

Example

+
if (a > 42) {
a = 43; // bad: duplicated code
} else {
a = 43;
}
+

Use instead:

+
if (a > 42) {
a = inc(b); // ok
} else {
a = 43;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/ConstantAddress/index.html b/tools/misti/docs/next/detectors/ConstantAddress/index.html new file mode 100644 index 000000000..510bbe9de --- /dev/null +++ b/tools/misti/docs/next/detectors/ConstantAddress/index.html @@ -0,0 +1,31 @@ + + + + + +ConstantAddress | Misti + + + + +
Version: Next

ConstantAddress

+

An optional detector that highlights all the constant addresses appearing in the source code.

+

Why is it bad?

+

Using hardcoded addresses can sometimes indicate poor contract design. +Some constant addresses may need to be set dynamically, e.g., using +contractAddress, or at least have a way to change them at runtime, for +example, when upgrading a contract.

+

Example

+
contract Main {
proxy: Address;
init() {
// Bad: Constant address highlighted by the analyzer.
self.proxy = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");
}
}
+

Use instead:

+
contract Main {
proxy: Address;
init() {
let proxy: Proxy = initOf Proxy(myAddress());
// OK: Address depends on how the proxy contact has been deployed
self.proxy = contractAddress(proxy);
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/DivideBeforeMultiply/index.html b/tools/misti/docs/next/detectors/DivideBeforeMultiply/index.html new file mode 100644 index 000000000..f84bb8435 --- /dev/null +++ b/tools/misti/docs/next/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,34 @@ + + + + + +DivideBeforeMultiply | Misti + + + + +
Version: Next

DivideBeforeMultiply

+

A detector that identifies and corrects instances of division before multiplication to +ensure accurate mathematical operations.

+

Why is it bad?

+

Performing division before multiplication can lead to unexpected results due to precision loss and rounding errors:

+
    +
  • Precision Loss: Dividing first can result in significant precision loss, especially when dealing with integers or fixed-point numbers.
  • +
  • Rounding Errors: Early division might cause rounding errors that propagate through subsequent calculations.
  • +
  • Unexpected Behavior: Incorrectly ordered operations can lead to incorrect outcomes, making debugging and maintenance more challenging.
  • +
+

Example

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Bad: Division before multiplication
let result: Int = a / b * c;
+

Use instead:

+
let a: Int = 10;
let b: Int = 3;
let c: Int = 2;
// Correct: Multiplication before division
let result: Int = a * c / b;
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/DumpIsUsed/index.html b/tools/misti/docs/next/detectors/DumpIsUsed/index.html new file mode 100644 index 000000000..8e3a9d443 --- /dev/null +++ b/tools/misti/docs/next/detectors/DumpIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +DumpIsUsed | Misti + + + + +
Version: Next

DumpIsUsed

+

An optional detector that highlights all the dump debug prints.

+

Why is it bad?

+

The dump function is a debug print that shouldn't be in the final code. +Even though the compiler removes it in production, its presence suggests the +developer was debugging something. This can flag areas where issues might exist, +so auditors should take a closer look at these parts of the code.

+

Example

+
fun test(): Int {
// ... other computations
let combined: Int = (RANDOM_SEED >> half_shift) &
(MAGIC_CONSTANT << DIVIDE_BY_TWO) ^ shift_mask;
dump(combined); // Suspicious: Highlighted by the detector
}
+

Use instead:

+
fun test(): Int {
// ... other computations
let combined: Int = this.seed ^ shift_mask
// OK: The code was reviewed and simplified; `dump` was removed
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/DuplicatedCondition/index.html b/tools/misti/docs/next/detectors/DuplicatedCondition/index.html new file mode 100644 index 000000000..aaaa0d6f9 --- /dev/null +++ b/tools/misti/docs/next/detectors/DuplicatedCondition/index.html @@ -0,0 +1,29 @@ + + + + + +DuplicatedCondition | Misti + + + + +
Version: Next

DuplicatedCondition

+

A detector that finds duplicated conditions appearing in conditional expressions.

+

Why is it bad?

+

Typically, these cases are developer errors caused by copy-pasting code, leading +to unreachable code.

+

Example

+
fun test(a: Int): Int {
if (a < 1) { return 1; }
else if (a > 4) { return 2; }
// Bad: A developer copy-pasted the condition
else if (a > 4) { return 3; }
return 4;
}
+

Use instead:

+
fun test(a: Int): Int {
if (a < 1) { return 1; }
else if (a > 4) { return 2; }
// OK: Fixed
else if (a < x) { return 3; }
return 4;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/EnsurePrgSeed/index.html b/tools/misti/docs/next/detectors/EnsurePrgSeed/index.html new file mode 100644 index 000000000..90a880bf8 --- /dev/null +++ b/tools/misti/docs/next/detectors/EnsurePrgSeed/index.html @@ -0,0 +1,32 @@ + + + + + +EnsurePrgSeed | Misti + + + + +
Version: Next

EnsurePrgSeed

+

A detector that identifies all calls to nativeRandom and nativeRandomInterval +without a preceding PRG seed initialization.

+

Why is it bad?

+

Using nativeRandom or nativeRandomInterval without first initializing the PRG seed via +nativePrepareRandom, nativeRandomize, or nativeRandomizeLt may lead to unintended behavior +or weak random number generation. This detector ensures that PRG seed initialization +is always performed before any use of random functions, enhancing contract security.

+

Example

+
// Bad: `nativeRandom` is used without prior PRG seed initialization
fun generateRandomValue(): Int {
return nativeRandom()
}
+

Use instead:

+
fun test(): Int {
nativePrepareRandom();
}

// OK: PRG has been initialized somewhere in the contract
fun generateRandomValue(): Int {
return nativeRandom()
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/FalseCondition/index.html b/tools/misti/docs/next/detectors/FalseCondition/index.html new file mode 100644 index 000000000..ccd8f2ef8 --- /dev/null +++ b/tools/misti/docs/next/detectors/FalseCondition/index.html @@ -0,0 +1,31 @@ + + + + + +FalseCondition | Misti + + + + +
Version: Next

FalseCondition

+

A detector that highlights conditions that evaluate to a constant true or false +in if, while, or until statements, and zero iterations in repeat statements.

+

Why is it bad?

+

Conditions that always evaluate to a constant true or false are likely the result of a typo +or logic error. Such conditions can lead to unintended behavior, dead code, or incorrect control flow. +This detector helps identify these cases so they can be corrected, improving the code's reliability.

+

Example

+
const FALSE: Bool = false;
// Bad: Always false because of operator precedence
if ((param | value) & FALSE) {
// ... never executed
}
+

Use instead:

+
const FALSE: Bool = false;
// OK: Fixed after the analyzer highlighted this
if (param) {}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/FieldDoubleInit/index.html b/tools/misti/docs/next/detectors/FieldDoubleInit/index.html new file mode 100644 index 000000000..ede5e2b3c --- /dev/null +++ b/tools/misti/docs/next/detectors/FieldDoubleInit/index.html @@ -0,0 +1,32 @@ + + + + + +FieldDoubleInit | Misti + + + + +
Version: Next

FieldDoubleInit

+

A detector that highlights cases where a field is initialized both in the +init function and at the point of definition.

+

Why is it bad?

+

Double initialization of fields can either be a programmer's mistake or simply +a waste of gas. It is always preferred to initialize values in the field declaration +if they have a compile-time evaluatable default value, or in the init function if +they must be initialized dynamically.

+

Example

+
contract Test {
a: Int = 0; // Bad
init(x: Int) { self.a = x }
}
+

Use instead:

+
contract Test {
a: Int; // Fixed
init(x: Int) { self.a = x }
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/InheritedStateMutation/index.html b/tools/misti/docs/next/detectors/InheritedStateMutation/index.html new file mode 100644 index 000000000..a36609060 --- /dev/null +++ b/tools/misti/docs/next/detectors/InheritedStateMutation/index.html @@ -0,0 +1,33 @@ + + + + + +InheritedStateMutation | Misti + + + + +
Version: Next

InheritedStateMutation

+

An optional detector that highlights all instances where inherited trait variables +are directly modified.

+

Why is it bad?

+

Traits should provide setter methods to ensure that invariants related to their +state are preserved. Directly modifying trait variables (e.g., self.traitVar = 42) +can violate these invariants, leading to potential bugs or security vulnerabilities. +This detector warns when such direct modifications occur, prompting further review +by auditors.

+

Example

+
trait T {
balance: Int;
}

contract C with T {
balance: Int = 42;
fun updateBalance() {
self.balance = 100; // Suspicious: Highlighted by the detector
}
}
+

Use instead:

+
trait T {
balance: Int;
fun setBalance(newBalance: Int) {
require(newBalance > 0, "balance cannot be negative"); // Invariant check
self.balance = newBalance;
}
}

contract C with T {
balance: Int = 42;
fun updateBalance() {
self.setBalance(100); // OK: Invariant preserved
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/NeverAccessedVariables/index.html b/tools/misti/docs/next/detectors/NeverAccessedVariables/index.html new file mode 100644 index 000000000..c0d64ba0b --- /dev/null +++ b/tools/misti/docs/next/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,30 @@ + + + + + +NeverAccessedVariables | Misti + + + + +
Version: Next

NeverAccessedVariables

+

A detector that identifies write-only or unused variables, fields and constants.

+

Why is it bad?

+

These variables are either assigned but never used in any meaningful computation, +or they are declared and never used at all, which may indicate redundant code +or an incomplete implementation of the intended logic.

+

Example

+
// Error: the developer forgot to use the constant
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+

Use instead:

+
const MAX_SUPPLY: Int = 1000;

fun mint(to: Address, amount: Int) {
// OK: Fixed after the analyzer highlighted this warning
require(totalSupply + amount <= MAX_SUPPLY, "Exceeds max supply");
balances.set(to, balances.get(to)!! + amount);
totalSupply += amount;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/OptimalMathFunction/index.html b/tools/misti/docs/next/detectors/OptimalMathFunction/index.html new file mode 100644 index 000000000..f321588f6 --- /dev/null +++ b/tools/misti/docs/next/detectors/OptimalMathFunction/index.html @@ -0,0 +1,28 @@ + + + + + +OptimalMathFunction | Misti + + + + +
Version: Next

OptimalMathFunction

+

A detector that highlights standard library math function calls that have more gas-efficient alternatives.

+

Why is it bad?

+

Tact supports log2/pow2 functions, which are more gas-efficient than log(x, 2)/pow(x, 2).

+

Example

+
log(x, 2);
+

Use instead:

+
log2(x)
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/PreferAugmentedAssign/index.html b/tools/misti/docs/next/detectors/PreferAugmentedAssign/index.html new file mode 100644 index 000000000..5c8fb3bac --- /dev/null +++ b/tools/misti/docs/next/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,31 @@ + + + + + +PreferAugmentedAssign | Misti + + + + +
Version: Next

PreferAugmentedAssign

+

Detects non-idiomatic statements that can be written using augmented assignment +operators like +=, -=, etc.

+

Why is it bad?

+

Using augmented assignment operations improves the readability of the source code +and reduces the risk of mistakes, such as those that occur during copy-pasting +and refactoring code.

+

Example

+
msgValue = (msgValue - ctx.readForwardFee());
+

Use instead:

+
msgValue -= ctx.readForwardFee());
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/PreferredStdlibApi/index.html b/tools/misti/docs/next/detectors/PreferredStdlibApi/index.html new file mode 100644 index 000000000..98713ca11 --- /dev/null +++ b/tools/misti/docs/next/detectors/PreferredStdlibApi/index.html @@ -0,0 +1,34 @@ + + + + + +PreferredStdlibApi | Misti + + + + +
Version: Next

PreferredStdlibApi

+

An optional detector that flags the use of advanced functions from the standard library.

+

Why is it bad?

+

Auditors should pay extra attention to these functions, as incorrect usage can +lead to subtle bugs. Safer stdlib alternatives should be preferred in the code.

+

Supported functions:

+ +

Example

+
let pkg: Slice = msg.transfer;
let _seqno: Int = pkg.loadInt(32);
let mode: Int = pkg.loadInt(8);
let body: Cell = pkg.loadRef();
// Bad: prefer `send` to avoid low-level manipulation of Slice
nativeSendMessage(body, mode);
+

Use instead:

+
// Safer: More explicit definition of the send operation
send(SendParameters{ value: amount,
to: self.owner,
mode: mode,
body: beginCell().endCell() });
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/ReadOnlyVariables/index.html b/tools/misti/docs/next/detectors/ReadOnlyVariables/index.html new file mode 100644 index 000000000..6f6206d40 --- /dev/null +++ b/tools/misti/docs/next/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,29 @@ + + + + + +ReadOnlyVariables | Misti + + + + +
Version: Next

ReadOnlyVariables

+

A detector that identifies read-only variables and fields.

+

Why is it bad?

+

These variables could typically be replaced with constants to optimize performance. +Alternatively, identifying read-only variables may reveal issues where unused values are being replaced unintentionally.

+

Example

+
fun calculateFinalPrice(price: Int): Int {
// Warning: the developer uses a read-only variable that could be a constant
let DISCOUNT_AMOUNT: Int = 10;
return price - DISCOUNT_AMOUNT;
}
+

Use instead:

+
const DISCOUNT_AMOUNT: Int = 10;

fun calculateFinalPrice(price: Int): Int {
// OK: Fixed after the analyzer highlighted this warning
return price - DISCOUNT_AMOUNT;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/StringReceiversOverlap/index.html b/tools/misti/docs/next/detectors/StringReceiversOverlap/index.html new file mode 100644 index 000000000..a1105ada1 --- /dev/null +++ b/tools/misti/docs/next/detectors/StringReceiversOverlap/index.html @@ -0,0 +1,29 @@ + + + + + +StringReceiversOverlap | Misti + + + + +
Version: Next

StringReceiversOverlap

+

A detector that finds overlapping messages between general string receivers and string receivers.

+

Why is it bad?

+

Constant string receivers and general string receivers can have overlapping messages +in which case the constant string receiver always takes precedence.

+

Example

+
contract Test {
receive("foobar") { throw(1042) }
receive(msg: String) {
if (msg == "foobar") { throw(1043) } // Bad: Dead code
}
}
+

Use instead:

+
contract Test {
receive("foobar") { throw(1042) }
receive(msg: String) {}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/UnboundLoops/index.html b/tools/misti/docs/next/detectors/UnboundLoops/index.html new file mode 100644 index 000000000..7ba6abc0d --- /dev/null +++ b/tools/misti/docs/next/detectors/UnboundLoops/index.html @@ -0,0 +1,33 @@ + + + + + +UnboundLoops | Misti + + + + +
Version: Next

UnboundLoops

+

A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.

+

Why is it bad?

+

An unbounded loop can be problematic for several reasons:

+
    +
  • Unexpected Behavior: Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult.
  • +
  • Out-of-gas Attacks: Continuous looping without termination can lead to out-of-gas attacks.
  • +
  • DoS Attacks: Malicious actors can exploit unbounded loops to create denial-of-service attacks, impacting contract's availability.
  • +
+

Example

+
let x: Int = 10;
while (x > 0) {
// Bad: x is not changed due looping
send(SendParameters{ to: sender(), ... });
}
+

Use instead:

+
let x: Int = 10;
while (x > 0) {
send(SendParameters{ to: sender(), ... });
x = x - 1;
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/UnusedOptional/index.html b/tools/misti/docs/next/detectors/UnusedOptional/index.html new file mode 100644 index 000000000..a65d9249d --- /dev/null +++ b/tools/misti/docs/next/detectors/UnusedOptional/index.html @@ -0,0 +1,31 @@ + + + + + +UnusedOptional | Misti + + + + +
Version: Next

UnusedOptional

+

A detector variables and fields with unused optional modifier.

+

Why is it bad?

+

Optional is a nullable value that has a special null value indicating the absence +of a value. If a developer creates an optional variable or field, he should leverage +its functionality by accessing the null value somewhere in his code. Otherwise, +the optional type should be removed to simplify and optimize the code.

+

Example

+
contract Test {
a: Int?; // Bad: null value is never accessed
init() { self.a = 42; }
get fun getA(): Int { return self.a!!; }
}
+

Use instead:

+
contract Test {
a: Int = 42; // OK: Removed optional
get fun getA(): Int { return self.a; }
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/ZeroAddress/index.html b/tools/misti/docs/next/detectors/ZeroAddress/index.html new file mode 100644 index 000000000..b64ada9de --- /dev/null +++ b/tools/misti/docs/next/detectors/ZeroAddress/index.html @@ -0,0 +1,31 @@ + + + + + +ZeroAddress | Misti + + + + +
Version: Next

ZeroAddress

+

A detector that identifies uses of the zero address.

+

Why is it bad?

+

Using the zero address in smart contracts is typically problematic because it can be +exploited as a default or uninitialized address, leading to unintended transfers and +security vulnerabilities. Additionally, operations involving the zero address can +result in loss of funds or tokens, as there is no private key to access this address.

+

Example

+
contract Proxy {
to: Address;
init() {
// Warning: Insecure usage of zero address as default value
self.to = newAddress(0, 0);
}
fun setAddress(to: Address) {
self.to = to
}
}
+

Use instead:

+
contract Proxy {
to: Address;
init(to: Address) {
// Fixed: Using the input value on initialization.
self.to = to;
}
fun setAddress(to: Address) {
self.to = to
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/index.html b/tools/misti/docs/next/detectors/index.html new file mode 100644 index 000000000..331459087 --- /dev/null +++ b/tools/misti/docs/next/detectors/index.html @@ -0,0 +1,61 @@ + + + + + +Detectors Overview | Misti + + + + +
Version: Next

Detectors Overview

+

Misti currently supports 21 detectors designed to identify specific code issues, detect vulnerabilities, and enforce best practices.

+

Solved Problems

+

TON and Tact Specific

+

There are language-specific patterns in TON and Tact that may lead to unintended behavior if not handled correctly.

+

Example detectors:

+ +

DoS Attacks

+

Denial of Service (DoS) and out-of-gas attacks can disrupt the execution of contracts, making them inaccessible or non-functional.

+

Example detectors:

+
    +
  • SendInLoop
  • +
+

Arithmetic Errors

+

Arithmetic errors in blockchain code can lead to incorrect calculations, potentially causing serious issues such as overflows or underflows.

+

Example detectors:

+ +

Optimization

+

Misti provides various detectors aimed at optimizing code. While these may not identify security vulnerabilities, they help improve project quality by optimizing gas usage and enhancing code readability. These detectors are typically available when running Misti with the --all-detectors flag.

+

Example detectors:

+ +

Suspicious Patterns

+

There are numerous suspicious patterns in source code that auditors should pay attention to. These detectors are generally disabled by default but can be enabled during audits to provide deeper insights into the code structure and highlight areas for manual review.

+

Example detectors:

+ +

List of Built-in detectors

+
#DetectorSeverityRequires SouffléEnabled by default
1ArgCopyMutationHigh
2AsmIsUsedInfo
3BranchDuplicateHigh
4ConstantAddressInfo
5DivideBeforeMultiplyHigh
6DumpIsUsedInfo
7DuplicatedConditionHigh
8EnsurePrgSeedMedium
9FalseConditionMedium
10FieldDoubleInitMedium
11InheritedStateMutationLow
12NeverAccessedVariablesMedium
13OptimalMathFunctionLow
14PreferAugmentedAssignInfo
15PreferredStdlibApiInfo
16ReadOnlyVariablesMedium
17StringReceiversOverlapHigh
18UnboundLoopsHigh
19UnusedOptionalLow
20ZeroAddressLow
+

Some of the detectors require Soufflé to be installed. If no Soufflé installation is found, these detectors won't be executed.

+

A few detectors are optional and aimed at auditors to help uncover subtle issues in the source code. To enable all detectors, use the --all-detectors option. You can find a full list of configuration options on the configuration page.

+

Each detector targets a specific type of problem in your code. Click on the detector name to learn more.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/hacking/contributing/index.html b/tools/misti/docs/next/hacking/contributing/index.html new file mode 100644 index 000000000..f65802e75 --- /dev/null +++ b/tools/misti/docs/next/hacking/contributing/index.html @@ -0,0 +1,66 @@ + + + + + +Contributing Guide | Misti + + + + +
Version: Next

Contributing Guide

+

Thank you for your interest in contributing to Misti. This guide provides the information you need to start, from reporting issues to coding and documentation. Your participation makes this project better.

+

Issues reporting

+

When Misti encounters an error and crashes, it generates a report and saves it to a file, displaying a message similar to the following:

+
The error report was saved to the file: /tmp/misti/reports/2024-07-29T08-48-59-308Z.txt.
Please help us by publishing it and the input sources at:
https://github.com/nowarp/misti/issues/new.
+

We encourage you to report these issues as it helps improve the project and enhances the tool's reliability for everyone. Sharing these reports ensures that we can address and fix problems promptly, benefiting all users.

+

Documentation contribution

+

We welcome contributions to our documentation. If you find areas that need improvement or clarification, feel free to edit, add, or suggest changes. You can create new issues related to documentation in our docs repository: nowarp.github.io Issues. Additionally, many documentation pages have an Edit button that allows you to make direct contributions easily.

+

Code contribution

+
    +
  1. +

    Navigate Issues and Find Tasks

    +
      +
    • Browse the issues here. Sometimes, it can be beneficial to find TODOs in the source code and tests for easy issues.
    • +
    • Choose an issue suitable for you and mention in the issue that you're working on it.
    • +
    +
  2. +
  3. +

    Implement Your Changes

    +
      +
    • Implement your changes. Feel free to ask questions in the issue if needed.
    • +
    +
  4. +
  5. +

    Ensure Tests Pass

    +
      +
    • Before creating a PR, make sure all tests and CI checks are passing by running: +
      yarn test-all
      +
    • +
    +
  6. +
  7. +

    Create a PR

    +
      +
    • Submit your pull request here
    • +
    +
  8. +
  9. +

    Add a CHANGELOG entry

    +
      +
    • Describe your changes in the CHANGELOG.md file according to the existing structure.
    • +
    +
  10. +
+

See Developing Misti for information about initializing the environment and additional hacking tips.

+

Thank you for your contributions!

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/hacking/custom-detector/index.html b/tools/misti/docs/next/hacking/custom-detector/index.html new file mode 100644 index 000000000..5c736a81e --- /dev/null +++ b/tools/misti/docs/next/hacking/custom-detector/index.html @@ -0,0 +1,38 @@ + + + + + +Custom Detector Guide | Misti + + + + +
Version: Next

Custom Detector Guide

+

Introduction

+

Misti provides an API to write custom detectors, allowing you to implement your own linting rules. These custom detectors enable you to identify specific issues in your codebase, much like other static analysis tools. The API reference can be found here: Misti API Reference.

+

Detectors are designed to be dynamically loaded by the Misti driver, and they are present by TypeScript classes that implement the Detector interface.

+

Creating a Detector

+

You can create a new custom detector by executing Misti with the --new-detector option: npx misti --new-detector implicitInit.

+

This will create the implicitInit.ts file, which contains the template code for writing your own custom detector logic leveraging the Misti API.

+

Here's an example of how to implement a custom detector using Misti API:

+
import { ASTDetector } from "@nowarp/misti/dist/detectors/detector";
import { CompilationUnit } from "@nowarp/misti/dist/internals/ir";
import {
MistiTactWarning,
Severity,
} from "@nowarp/misti/dist/internals/errors";

/**
* An example of a custom detector that showcases the usage of the detector API.
*
* It reports all the contracts that doesn't have an explicit implementation of the init function.
*/
export class ImplicitInit extends ASTDetector {
severity = Severity.INFO;

async check(cu: CompilationUnit): Promise<MistiTactWarning[]> {
return Array.from(cu.contracts).reduce((foundErrors, [_, contract]) => {
if (!cu.findMethodCFGByName(contract.name, "init")) {
const err = this.makeWarning(
`Contract ${contract.name} doesn't define an init function`,
contract.ref,
);
foundErrors.push(err);
}
return foundErrors;
}, [] as MistiTactWarning[]);
}
}

+

Testing the detector

+

To run Misti with only your new detector, use the --detectors option, specifying the path to the detector and the Detector class name: npx misti path/to/your/tact.config.json --detectors path/to/implicitInit.ts:ImplicitInit.

+

That's a good way to test the detector on the first run. You could also use the --verbose CLI option and set the environment variable MISTI_TRACE=1 to facilitate debugging.

+

Saving the configuration

+

After testing the detector, you can specify it in your configuration to enable it in future runs. Update your Misti configuration file to include the path to your custom detector implementation, e.g.:

+
{
"detectors": [
// Other detectors...
{ "className": "ImplicitInit", "modulePath": "ImplicitInit.ts" }
],
}
+

After this, you could run Misti specifying a path to a custom configuration npx misti --config path/to/misti.config.json path/to/your/tact.config.json.

+

Example Detectors

+

The best way to examine how to use the Misti API is to look at the example detectors. Navigate to the examples directory in the Misti repository to see how various detectors are implemented. Additionally, the built-in detectors are present in the project and are well-documented, providing further insight into writing effective custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/hacking/design/index.html b/tools/misti/docs/next/hacking/design/index.html new file mode 100644 index 000000000..5807ce77d --- /dev/null +++ b/tools/misti/docs/next/hacking/design/index.html @@ -0,0 +1,34 @@ + + + + + +Design Overview | Misti + + + + +
Version: Next

Design Overview

+

Static Analysis

+

Misti is a static analyzer, a tool that examines code without executing it, identifying potential errors, security vulnerabilities, and code quality issues.

+

Souffle Datalog Solver

+

Misti leverages the Souffle Datalog solver, an industry-grade and highly efficient Datalog solver designed specifically for program analysis. Souffle provides native parallel execution and is extremely fast, making it an ideal choice for analyzing complex codebases.

+

Dataflow Analysis in Misti

+

Misti offers an interface to describe classic dataflow problems. It includes a lattice interface and provides a mechanism to solve these problems using the worklist algorithm. This allows for efficient and accurate analysis of data flow within the code.

+

References

+

For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:

+ +

These resources provide a solid foundation in the theory and practice of static and dataflow analysis.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/hacking/developing-misti/index.html b/tools/misti/docs/next/hacking/developing-misti/index.html new file mode 100644 index 000000000..8aeb17326 --- /dev/null +++ b/tools/misti/docs/next/hacking/developing-misti/index.html @@ -0,0 +1,44 @@ + + + + + +Developing Misti | Misti + + + + +
Version: Next

Developing Misti

+

Prerequisites

+

Before you begin, please refer to the Getting Started documentation for the required system dependencies.

+

Cloning the Repository

+

Clone the Misti repository:

+
git clone 'https://github.com/nowarp/misti'
+

Building the Project

+

Navigate to the project directory, install dependencies, generate necessary files, and build the project:

+
cd misti && yarn install && yarn gen && yarn build
+

Running the Analyzer

+

During development, you can run the analyzer using:

+
yarn misti
+

For example, to run it for tests:

+
yarn misti test/good/never-accessed.tact
+

Adding Backtraces to the Logger

+

To add debug traces to all log messages, set the MISTI_TRACE environment variable to 1:

+
export MISTI_TRACE=1
+

Updating Expected Outputs of Tests

+

To update the expected outputs of tests, set the BLESS environment variable and run the tests:

+
BLESS=1 yarn test
+

You can also run a single test or update its expected output when working with a specific test file:

+
BLESS=1 yarn test test/tactIR.spec.ts tests/good/never-accessed.tact
+

And for another specific test:

+
BLESS=1 yarn test test/builtinDetectors.spec.ts test/good/branch-duplicate.tact
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/hacking/souffle/index.html b/tools/misti/docs/next/hacking/souffle/index.html new file mode 100644 index 000000000..6c955474d --- /dev/null +++ b/tools/misti/docs/next/hacking/souffle/index.html @@ -0,0 +1,38 @@ + + + + + +Soufflé Integration Guide | Misti + + + + +
Version: Next

Soufflé Integration Guide

+

What is Soufflé?

+

Soufflé is a highly efficient Datalog solver designed specifically for program analysis. It offers native parallel execution, making it incredibly fast and suitable for handling complex static analysis tasks. By leveraging Soufflé, Misti can perform deep and scalable analyses of smart contracts.

+

Benefits of Using Soufflé for Static Analysis

+

Soufflé allows to express static analysis problems declaratively, making it easier to define and solve complex queries over the code's intermediate representation (IR). In some cases writing a Soufflé program might be more straightforward then implementing a complex transfer function in for a classic monotone framework.

+

Soufflé Integration in Misti

+

The API for interacting with Soufflé in Misti is implemented in the Souffle.js library. See the Souffle.js API reference for more detailed information.

+

Creating Soufflé Programs

+

To create a Soufflé program within Misti, you need to declare relations, rules and generate facts based on the IR. Here is an example from the built-in "readonly variables" detector:

+
addDecls(ctx: Context<SrcInfo>) {
ctx.add(
Relation.from(
"varDecl",
[
["var", FactType.Symbol],
["func", FactType.Symbol],
],
undefined,
),
);
// other declarations
}
+
addRules(ctx: Context<SrcInfo>) {
// readOnly(var, func) :-
// varDecl(var, func),
// !varAssign(var, func),
// !varUse(var, func).
ctx.add(
Rule.from(
[makeAtom("readOnly", ["var", "func"])],
makeRuleBody(makeAtom("varDecl", ["var", "func"])),
makeRuleBody(makeAtom("varAssign", ["var", "func"]), {
negated: true,
}),
makeRuleBody(makeAtom("varUse", ["var", "func"]), { negated: true }),
),
);
}
+

Generating Facts and Executing Soufflé

+

After declaring the necessary relations, you need to iterate over the IR to generate facts for these declarations. Then, use the built-in Soufflé executor to run the analysis:

+
const executor = ctx.config.soufflePath
? new Executor<SrcInfo>({
inputDir: ctx.config.soufflePath,
outputDir: ctx.config.soufflePath,
})
: new Executor<SrcInfo>();

const result = executor.executeSync(program);

if (!result.success) {
throw new Error(
`Error executing Soufflé for ${this.id}:\n${result.stderr}`,
);
}

const warnings = Array.from(result.results.entries.values()).map((fact) => {
// raise warnings
});
+

Learning from Existing Code

+

We recommend studying the existing codebase, as it is well-documented and provides a comprehensive overview of integrating Soufflé with Misti. This will help you understand the intricacies of generating IR and executing Soufflé programs effectively.

+

Further Reading

+

For a deeper understanding of static analysis using Soufflé, refer to the textbook Program Analysis: An Appetizer by Flemming Nielson and Hanne Riis Nielson. It discusses Soufflé-based analysis in greater detail and is an excellent resource for both beginners and experienced developers in the field.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/index.html b/tools/misti/docs/next/index.html new file mode 100644 index 000000000..5b6d93e31 --- /dev/null +++ b/tools/misti/docs/next/index.html @@ -0,0 +1,44 @@ + + + + + +Introduction | Misti + + + + +
Version: Next

Introduction

Misti is a static analysis tool designed for smart contracts on the TON blockchain.

+

Language Support:

+ +

Use Cases

+

Misti is designed to detect issues in smart contracts efficiently, making it ideal for integration into development tools and CI/CD pipelines. By incorporating Misti, you can:

+
    +
  • Detect Vulnerabilities: Identify and fix potential security flaws early in the development cycle.
  • +
  • Improve Code Quality: Maintain high standards by catching bugs and enforcing best practices automatically.
  • +
  • Streamline Development: Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.
  • +
  • Custom Detectors: Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.
  • +
+

Go ahead and read more about the tool, including its design, to fully leverage its capabilities and integrate it effectively into your workflow.

+

Name Origin

+

The name "Misti" comes from the Misti volcano in Peru. It was chosen because it's catchy and easy to remember.

+

Funding

+

Misti has been funded by the following TON Foundation grants:

+ +

This support has enabled us to develop and maintain the tool.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/tools/DumpAst/index.html b/tools/misti/docs/next/tools/DumpAst/index.html new file mode 100644 index 000000000..7756bddf9 --- /dev/null +++ b/tools/misti/docs/next/tools/DumpAst/index.html @@ -0,0 +1,30 @@ + + + + + +DumpAst | Misti + + + + +
Version: Next

DumpAst

+

The DumpAst tool in Misti enables users to output the Abstract Syntax Tree (AST) of project modules in JSON format. This is particularly useful when writing custom detectors, as it helps understand the structure and components of the code.

+

Usage

+

To dump the AST in JSON format, use the following command:

+
npx misti -t "DumpAst" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

If you wish to include the standard library in the dump, set dumpStdlib to true:

+
npx misti -t "DumpAst:dumpStdlib=true" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Understanding the Dumps

+

The AST provides a detailed breakdown of code components, offering insights into its structure. This is essential when creating or debugging custom detectors, as it allows a deeper understanding of how code is represented internally by the analyzer.

+

By leveraging the DumpAst tool, developers can more effectively navigate and interpret the project's syntax, supporting the development of accurate and efficient detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/tools/DumpCfg/index.html b/tools/misti/docs/next/tools/DumpCfg/index.html new file mode 100644 index 000000000..5505c0cca --- /dev/null +++ b/tools/misti/docs/next/tools/DumpCfg/index.html @@ -0,0 +1,62 @@ + + + + + +DumpCfg | Misti + + + + +
Version: Next

DumpCfg

+

Misti provides a feature to dump the Control Flow Graph (CFG) in JSON, DOT, and Mermaid formats. This is essential for understanding the Internal Representation (IR) of the code and analyzing the control flow within contracts.

+

Usage

+

To dump the CFG in Mermaid format, use the following command:

+
npx misti -t "DumpCfg:format=mmd" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in Graphviz DOT format, use the following command:

+
npx misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in JSON format, use the following command:

+
npx misti -t "DumpCfg:format=json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

You could also include Tact standard library functions to the dump adding dumpStdlib=true to the DumpCfg options.

+

Working with Mermaid

+

Mermaid is a JavaScript-based diagramming and charting tool that allows you to create dynamic visualizations, such as flowcharts and sequence diagrams, using a simple syntax. It is integrated into various platforms, including Visual Studio Code.

+

To view Mermaid diagrams in Visual Studio Code, you can use the Markdown Preview Mermaid Support extension. You can also use the Mermaid Live Editor to preview your diagrams online.

+

To dump the CFG in Mermaid format using Misti, run the following command:

+
npx misti -t "DumpCfg:format=mermaid" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

The output can be viewed directly in the VS Code plugin or the online editor.

+

Working with Graphviz

+

Converting DOT to SVG

+

To convert the resulting DOT file to an SVG for visualization, save the generated DOT dump to a file and use Graphviz with the following command:

+
npx misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot
dot -Tsvg output.dot -o output.svg
+

Viewing the SVG

+

To view the SVG file in Firefox, use the following command:

+
firefox output.svg
+

For example, for the following contract:

+
fun test(): Int {
let sum: Int = 0;
let i: Int = 0;
repeat (10) {
i = i + 1;
sum = sum + i;
}
return sum;
}
+

The following CFG will be generated:

+

CFG Example

+

VS Code Plugin

+

For real-time visualization of DOT files, you can use one of the available Graphviz plugins for Visual Studio Code. These plugins allow you to view DOT diagrams directly within the editor, facilitating easier debugging and development.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer.

    +
  • +
  • +

    DOT Dumps: These provide a visual representation of the contract's control flow. They are particularly useful for understanding the control flow within contracts, making it easier to identify issues and optimize the code.

    +
  • +
  • +

    Mermaid Dumps: The Mermaid format allows you to generate flowcharts that are easy to read and share. They offer a convenient way to visualize the CFG without requiring additional tools, as they can be directly embedded in markdown files or viewed in the Mermaid Live Editor.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/tools/DumpConfig/index.html b/tools/misti/docs/next/tools/DumpConfig/index.html new file mode 100644 index 000000000..2171c9ffe --- /dev/null +++ b/tools/misti/docs/next/tools/DumpConfig/index.html @@ -0,0 +1,27 @@ + + + + + +DumpConfig | Misti + + + + +
Version: Next

DumpConfig

+

The DumpConfig tool in Misti allows you to print the current configuration file used by the analyzer. This is useful for obtaining the default configuration to use as a starting point for your custom setup or to inspect and understand the existing configuration in use.

+

Usage

+

To dump the configuration file, use the following command:

+
npx misti -t "DumpConfig" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Understanding the Output

+

The output provides an overview of all the configurations and settings applied to your project. This can help you quickly identify the default settings, make adjustments to fit your specific needs, and ensure that your custom detectors are running under the correct configurations.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/tools/index.html b/tools/misti/docs/next/tools/index.html new file mode 100644 index 000000000..1e1f15a2d --- /dev/null +++ b/tools/misti/docs/next/tools/index.html @@ -0,0 +1,36 @@ + + + + + +Tools Overview | Misti + + + + +
Version: Next

Tools Overview

+

Misti Tools are additional modules designed to work alongside detectors, enabling various tasks beyond code analysis.

+

These tools are particularly useful for auditors, providing additional functionalities to assist in manual code reviews.

+

Usage

+

List available tools and their options:

+
npx misti --list-tools
+

To invoke a specific tool, use the following command format:

+
npx misti -t "ToolName:option=value,option=value" /path/to/tact.config.json
+

Usage Examples

+

Dump the AST of the project:

+
npx misti -t "DumpAst" my-example.tact
+

Dump the CFGs of the project in Mermaid format to the file /tmp/my-example.DumpCfg.out:

+
npx misti --output-path "/tmp" -t "DumpCfg:format=mermaid" my-example.tact
+

Available Tools

+

Below is the complete list of built-in tools. Click on any of them to learn more.

+
#ToolDescription
1DumpAstDumps the AST of project modules
2DumpCfgDumps the CFG of project modules
3DumpConfigDumps the Misti configuration file in use
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/tutorial/blueprint/index.html b/tools/misti/docs/next/tutorial/blueprint/index.html new file mode 100644 index 000000000..6cb09f566 --- /dev/null +++ b/tools/misti/docs/next/tutorial/blueprint/index.html @@ -0,0 +1,48 @@ + + + + + +Using Misti with Blueprint | Misti + + + + +
Version: Next

Using Misti with Blueprint

+

Blueprint is a platform to compile, test, and deploy contracts on the TON blockchain. It is quite similar to Hardhat and Truffle for Ethereum.

+

There is a blueprint-misti plugin that can be added to a Blueprint configuration. It adds the blueprint misti command, which runs the static analyzer over the selected Blueprint project.

+

This page describes how to use it.

+

Getting Started

+
    +
  1. +

    Install Soufflé to use all detectors provided by Misti.

    +
  2. +
  3. +

    Add this plugin as a dependency of your Blueprint project:

    +
  4. +
+
yarn add @nowarp/blueprint-misti
+
    +
  1. Add this configuration to blueprint.config.ts:
  2. +
+
import { MistiPlugin } from '@nowarp/blueprint-misti';
export const config = {
plugins: [
new MistiPlugin(),
],
};
+

Usage

+

Run the following command:

+
yarn blueprint misti
+

It will run the analysis of the available project, if there is one, or show an interactive window to select a project:

+

img

+

You could also pass the supported CLI options for Misti, for example:

+
yarn blueprint misti --all-detectors
+

Or you can even pass the path to the contract directly:

+
yarn blueprint misti path/to/my/contract.tact
+

If you have any problems, feel free to reach out to us in the Misti discussion group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/tutorial/ci-cd/index.html b/tools/misti/docs/next/tutorial/ci-cd/index.html new file mode 100644 index 000000000..595d2513e --- /dev/null +++ b/tools/misti/docs/next/tutorial/ci-cd/index.html @@ -0,0 +1,42 @@ + + + + + +Integrating Misti into CI/CD | Misti + + + + +
Version: Next

Integrating Misti into CI/CD

+

Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.

+

Using Tact Template

+

tact-template is a template project for Tact. If you started your project from this template, Misti is already installed in the CI. You also have the yarn lint command available in your package.json.

+

GitHub Actions

+

To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:

+

1. Open your GitHub repository

+

2. Create or edit the GitHub Actions workflow YAML file

+

It could be located at e.g., .github/workflows/ci.yml.

+

3. Add the step to run Misti to your YAML file

+

For example:

+
name: CI

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:

jobs:
test:
strategy:
fail-fast: false
matrix:
node-version: [22]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install Soufflé on Ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
sudo wget https://souffle-lang.github.io/ppa/souffle-key.public -O /usr/share/keyrings/souffle-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/souffle-archive-keyring.gpg] https://souffle-lang.github.io/ppa/ubuntu/ stable main" | sudo tee /etc/apt/sources.list.d/souffle.list
sudo apt update
sudo apt install souffle

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: yarn install

- name: Run Misti
run: yarn misti --min-severity medium /path/to/your/tact.config.json
+

The yarn misti --min-severity medium /path/to/your/tact.config.json command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail.

+

The --min-severity medium will filter out low-priority warnings. You can always run Misti with all the detectors enabled locally in order to get the most comprehensive warnings output: yarn misti --all-detectors /path/to/your/tact.config.json

+

4. Adjusting the Misti Configuration

+

If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the Configuration section for more details on how to customize your settings.

+

Integration with Blueprint Projects

+

To add Misti to the CI for your Blueprint project, follow these steps:

+
    +
  1. Install blueprint-misti.
  2. +
  3. Follow the steps to set up the GitHub action above, but replace the yarn misti command with npx blueprint misti --blueprint-project <PROJECT_NAME>, where <PROJECT_NAME> is the name of the project displayed when you run npx blueprint build.
  4. +
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/tutorial/cli/index.html b/tools/misti/docs/next/tutorial/cli/index.html new file mode 100644 index 000000000..922a4df21 --- /dev/null +++ b/tools/misti/docs/next/tutorial/cli/index.html @@ -0,0 +1,105 @@ + + + + + +Command-Line Interface | Misti + + + + +
Version: Next

Command-Line Interface

+

Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.

+

-t, --tools <className[:key=value...]>

+
    +
  • Description: Specifies a tool to enable with optional configuration. This option can be used multiple times.
  • +
  • Example: -t "DumpCfg:format=dot"
  • +
+

--output-path <PATH>

+
    +
  • Description: Specifies the directory to save warnings or output generated by tools. If <PATH> is -, then the output is sent to stdout.
  • +
  • Default: -
  • +
+

--list-tools

+
    +
  • Description: Lists available tools and their configuration options.
  • +
  • Default: false
  • +
+

-o, --output-format <json|plain>

+
    +
  • Description: Sets the output format for all tools and warnings (either JSON or plain text).
  • +
  • Default: plain
  • +
+

-C, --no-colors

+
    +
  • Description: Disables ANSI colors in the output.
  • +
  • Default: false
  • +
+

--souffle-binary <PATH>

+
    +
  • Description: Specifies the path to the Soufflé binary.
  • +
  • Default: "souffle"
  • +
+

--souffle-path <PATH>

+
    +
  • Description: Specifies the directory to save generated Soufflé files.
  • +
  • Default: "/tmp/misti/souffle"
  • +
+

--souffle-verbose

+
    +
  • Description: Generates human-readable, more verbose Soufflé files.
  • +
  • Default: false
  • +
+

--tact-stdlib-path <PATH>

+
    +
  • Description: Specifies the path to the Tact standard library.
  • +
+

-v, --verbose

+
    +
  • Description: Enables verbose output.
  • +
  • Default: false
  • +
+

-q, --quiet

+
    +
  • Description: Suppresses all output.
  • +
  • Default: false
  • +
+

-m, --min-severity <info|low|medium|high|critical>

+
    +
  • Description: Sets the minimum level of severity to report.
  • +
  • Default: info
  • +
+

-de, --enabled-detectors <name|path:name>

+
    +
  • Description: A comma-separated list of detectors to enable.
  • +
  • Argument Validation: Requires a non-empty list of detector names.
  • +
+

-dd, --disabled-detectors <names>

+
    +
  • Description: A comma-separated list of detector names to disable.
  • +
  • Argument Validation: Requires a non-empty list of detector names.
  • +
+

-A, --all-detectors

+
    +
  • Description: Enables all available built-in detectors.
  • +
  • Default: false
  • +
+

-c, --config <PATH>

+
    +
  • Description: Specifies the path to the Misti configuration file.
  • +
+

--new-detector <PATH>

+
    +
  • Description: Creates a new custom detector at the specified path.
  • +
  • Default: undefined
  • +
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/tutorial/configuration/index.html b/tools/misti/docs/next/tutorial/configuration/index.html new file mode 100644 index 000000000..f62307da3 --- /dev/null +++ b/tools/misti/docs/next/tutorial/configuration/index.html @@ -0,0 +1,77 @@ + + + + + +Configuration | Misti + + + + +
Version: Next

Configuration

+

This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.

+

Configuration Options

+
    +
  • +

    detectors (array of objects, optional): List of detectors to run. Each detector can be specified with a className and optionally a modulePath if it’s a custom detector.

    +
      +
    • className (string, required): The class name of the detector.
    • +
    • modulePath (string, optional): The file path of the detector module if it's a custom implementation.
    • +
    +
  • +
  • +

    tools (array of objects, optional): List of tools to enable, each with its own configuration.

    +
      +
    • className (string, required): The class name of the tool.
    • +
    • options (object, optional): Key-value configuration options for the tool.
    • +
    +
  • +
  • +

    suppressions (array of objects, optional): A list of suppressions for warnings.

    +
      +
    • detector (string, required): The detector to suppress warnings for.
    • +
    • position (string, required): The position in the code where the warning should be suppressed.
    • +
    +
  • +
  • +

    ignoredProjects (array of strings, optional): List of Tact projects to ignore during analysis.

    +
  • +
  • +

    soufflePath (string, optional): Directory to save generated Soufflé files, useful for debugging purposes. If not set, a temporary directory will be used.

    +
  • +
  • +

    souffleVerbose (boolean, optional): If set, generates more readable Soufflé files instead of optimizing the output for size.

    +
  • +
  • +

    tactStdlibPath (string, optional): Path to the Tact standard library. If not set, the default standard library from the active Tact setup will be used.

    +
  • +
  • +

    unusedPrefix (string, default: "_"): Identifiers starting with this prefix won't be reported as unused by the built-in detectors.

    +
  • +
  • +

    verbosity (string, optional, default: "default"): Verbosity level of the logs. Possible values are quiet, debug, and default.

    +
  • +
+

Running Misti with Configuration

+

To run Misti with the specified configuration file, use the following command:

+
npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json
+

This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration.

+

Default Configuration File

+

By default, Misti enables all built-in detectors. Below is an example of the default configuration file:

+
{
"detectors": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },
{ "className": "BranchDuplicate" },
{ "className": "FieldDoubleInit" },
{ "className": "PreferAugmentedAssign" },
{ "className": "StringReceiversOverlap" },
{ "className": "ArgCopyMutation" }
],
"ignoredProjects": [],
"soufflePath": "/tmp/misti/souffle",
"souffleVerbose": false,
"unusedPrefix": "_",
"verbosity": "default"
}
+

All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: configSchema.json.

+

You can always dump the Misti configuration file in use by passing the --dump-config option in the CLI:

+
npx misti --dump-config path/to/your/tact.config.json
+

If there is no Misti config in the directory, Misti dumps the default config. This can be used to adjust it, such as adding or suppressing some detectors.

+

Getting Help

+

If you need assistance or encounter any issues, please create an issue on GitHub at nowarp/misti or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/next/tutorial/getting-started/index.html b/tools/misti/docs/next/tutorial/getting-started/index.html new file mode 100644 index 000000000..f07029dec --- /dev/null +++ b/tools/misti/docs/next/tutorial/getting-started/index.html @@ -0,0 +1,62 @@ + + + + + +Getting started | Misti + + + + +
Version: Next

Getting started

+

This guide will walk you through the steps to install and set up the Misti static analyzer.

+

Prerequisites

+

Before you begin, ensure you have the following software installed on your system:

+
    +
  • Git
  • +
  • Yarn
  • +
  • Node.js version 22 or higher
  • +
  • Soufflé
  • +
+

Installation

+

Misti is distributed via npm and should be added to your Tact project in the same way as Tact itself:

+
yarn add @nowarp/misti
+

Using Development Version

+

The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis.

+

To install the latest development version you should:

+
    +
  1. Clone Misti: git clone https://github.com/nowarp/misti
  2. +
  3. Build it: cd misti && yarn install && yarn build
  4. +
  5. Use it in your Tact project: cd /path/to/tact/project && yarn add file:/path/to/misti
  6. +
+

Running the analysis

+

Run Misti by specifying a Tact project configuration:

+
npx misti path/to/tact.config.json
+

This will highlight any warnings the analyzer found.

+

You can also add a script to your package.json to simplify running the linting process:

+
{
"scripts": {
"lint": "npx misti path/to/tact.config.json"
}
}
+

More usage examples

+

Below are a few usage examples for common scenarios when using the misti CLI.

+

Suppressing Specific Detectors

+

To run misti while suppressing specific detectors, such as ReadOnlyVariables:

+
npx misti --suppress ReadOnlyVariables path/to/tact.config.json
+

Enabling All Detectors

+

Running misti with all available built-in detectors enabled:

+
npx misti --all-detectors path/to/tact.config.json
+

It is recommended to do that when auditing the project.

+

Running in Quiet Mode

+

To suppress all output while running misti getting just a return code:

+
npx misti --quiet path/to/tact.config.json
+

This might be useful in scripts and CI/CD.

+

Troubleshooting

+

If you encounter any issues during the installation process, feel free to create an issue or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/tools/DumpAst/index.html b/tools/misti/docs/tools/DumpAst/index.html new file mode 100644 index 000000000..157ae8edd --- /dev/null +++ b/tools/misti/docs/tools/DumpAst/index.html @@ -0,0 +1,30 @@ + + + + + +DumpAst | Misti + + + + +
Version: 0.4.0

DumpAst

+

The DumpAst tool in Misti enables users to output the Abstract Syntax Tree (AST) of project modules in JSON format. This is particularly useful when writing custom detectors, as it helps understand the structure and components of the code.

+

Usage

+

To dump the AST in JSON format, use the following command:

+
npx misti -t "DumpAst" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

If you wish to include the standard library in the dump, set dumpStdlib to true:

+
npx misti -t "DumpAst:dumpStdlib=true" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Understanding the Dumps

+

The AST provides a detailed breakdown of code components, offering insights into its structure. This is essential when creating or debugging custom detectors, as it allows a deeper understanding of how code is represented internally by the analyzer.

+

By leveraging the DumpAst tool, developers can more effectively navigate and interpret the project's syntax, supporting the development of accurate and efficient detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/tools/DumpCfg/index.html b/tools/misti/docs/tools/DumpCfg/index.html new file mode 100644 index 000000000..85f5e2b7c --- /dev/null +++ b/tools/misti/docs/tools/DumpCfg/index.html @@ -0,0 +1,62 @@ + + + + + +DumpCfg | Misti + + + + +
Version: 0.4.0

DumpCfg

+

Misti provides a feature to dump the Control Flow Graph (CFG) in JSON, DOT, and Mermaid formats. This is essential for understanding the Internal Representation (IR) of the code and analyzing the control flow within contracts.

+

Usage

+

To dump the CFG in Mermaid format, use the following command:

+
npx misti -t "DumpCfg:format=mmd" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in Graphviz DOT format, use the following command:

+
npx misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in JSON format, use the following command:

+
npx misti -t "DumpCfg:format=json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

You could also include Tact standard library functions to the dump adding dumpStdlib=true to the DumpCfg options.

+

Working with Mermaid

+

Mermaid is a JavaScript-based diagramming and charting tool that allows you to create dynamic visualizations, such as flowcharts and sequence diagrams, using a simple syntax. It is integrated into various platforms, including Visual Studio Code.

+

To view Mermaid diagrams in Visual Studio Code, you can use the Markdown Preview Mermaid Support extension. You can also use the Mermaid Live Editor to preview your diagrams online.

+

To dump the CFG in Mermaid format using Misti, run the following command:

+
npx misti -t "DumpCfg:format=mermaid" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

The output can be viewed directly in the VS Code plugin or the online editor.

+

Working with Graphviz

+

Converting DOT to SVG

+

To convert the resulting DOT file to an SVG for visualization, save the generated DOT dump to a file and use Graphviz with the following command:

+
npx misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH> > output.dot
dot -Tsvg output.dot -o output.svg
+

Viewing the SVG

+

To view the SVG file in Firefox, use the following command:

+
firefox output.svg
+

For example, for the following contract:

+
fun test(): Int {
let sum: Int = 0;
let i: Int = 0;
repeat (10) {
i = i + 1;
sum = sum + i;
}
return sum;
}
+

The following CFG will be generated:

+

CFG Example

+

VS Code Plugin

+

For real-time visualization of DOT files, you can use one of the available Graphviz plugins for Visual Studio Code. These plugins allow you to view DOT diagrams directly within the editor, facilitating easier debugging and development.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: These are mostly helpful for understanding low-level details on how the IR is generated. They provide a comprehensive representation of the internal structures used by the analyzer.

    +
  • +
  • +

    DOT Dumps: These provide a visual representation of the contract's control flow. They are particularly useful for understanding the control flow within contracts, making it easier to identify issues and optimize the code.

    +
  • +
  • +

    Mermaid Dumps: The Mermaid format allows you to generate flowcharts that are easy to read and share. They offer a convenient way to visualize the CFG without requiring additional tools, as they can be directly embedded in markdown files or viewed in the Mermaid Live Editor.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the workings of the static analyzer and effectively debug and enhance their custom detectors.

+ + \ No newline at end of file diff --git a/tools/misti/docs/tools/DumpConfig/index.html b/tools/misti/docs/tools/DumpConfig/index.html new file mode 100644 index 000000000..ac1a7ae94 --- /dev/null +++ b/tools/misti/docs/tools/DumpConfig/index.html @@ -0,0 +1,27 @@ + + + + + +DumpConfig | Misti + + + + +
Version: 0.4.0

DumpConfig

+

The DumpConfig tool in Misti allows you to print the current configuration file used by the analyzer. This is useful for obtaining the default configuration to use as a starting point for your custom setup or to inspect and understand the existing configuration in use.

+

Usage

+

To dump the configuration file, use the following command:

+
npx misti -t "DumpConfig" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Understanding the Output

+

The output provides an overview of all the configurations and settings applied to your project. This can help you quickly identify the default settings, make adjustments to fit your specific needs, and ensure that your custom detectors are running under the correct configurations.

+ + \ No newline at end of file diff --git a/tools/misti/docs/tools/index.html b/tools/misti/docs/tools/index.html new file mode 100644 index 000000000..252cdcf12 --- /dev/null +++ b/tools/misti/docs/tools/index.html @@ -0,0 +1,36 @@ + + + + + +Tools Overview | Misti + + + + +
Version: 0.4.0

Tools Overview

+

Misti Tools are additional modules designed to work alongside detectors, enabling various tasks beyond code analysis.

+

These tools are particularly useful for auditors, providing additional functionalities to assist in manual code reviews.

+

Usage

+

List available tools and their options:

+
npx misti --list-tools
+

To invoke a specific tool, use the following command format:

+
npx misti -t "ToolName:option=value,option=value" /path/to/tact.config.json
+

Usage Examples

+

Dump the AST of the project:

+
npx misti -t "DumpAst" my-example.tact
+

Dump the CFGs of the project in Mermaid format to the file /tmp/my-example.DumpCfg.out:

+
npx misti --output-path "/tmp" -t "DumpCfg:format=mermaid" my-example.tact
+

Available Tools

+

Below is the complete list of built-in tools. Click on any of them to learn more.

+
#ToolDescription
1DumpAstDumps the AST of project modules
2DumpCfgDumps the CFG of project modules
3DumpConfigDumps the Misti configuration file in use
+ + \ No newline at end of file diff --git a/tools/misti/docs/tutorial/blueprint/index.html b/tools/misti/docs/tutorial/blueprint/index.html new file mode 100644 index 000000000..01c135f21 --- /dev/null +++ b/tools/misti/docs/tutorial/blueprint/index.html @@ -0,0 +1,48 @@ + + + + + +Using Misti with Blueprint | Misti + + + + +
Version: 0.4.0

Using Misti with Blueprint

+

Blueprint is a platform to compile, test, and deploy contracts on the TON blockchain. It is quite similar to Hardhat and Truffle for Ethereum.

+

There is a blueprint-misti plugin that can be added to a Blueprint configuration. It adds the blueprint misti command, which runs the static analyzer over the selected Blueprint project.

+

This page describes how to use it.

+

Getting Started

+
    +
  1. +

    Install Soufflé to use all detectors provided by Misti.

    +
  2. +
  3. +

    Add this plugin as a dependency of your Blueprint project:

    +
  4. +
+
yarn add @tact-lang/compiler
yarn add @nowarp/blueprint-misti
+
    +
  1. Add this configuration to blueprint.config.ts:
  2. +
+
import { MistiPlugin } from '@nowarp/blueprint-misti';
export const config = {
plugins: [
new MistiPlugin(),
],
};
+

Usage

+

Run the following command:

+
yarn blueprint misti
+

It will run the analysis of the available project, if there is one, or show an interactive window to select a project:

+

img

+

You could also pass the supported CLI options for Misti, for example:

+
yarn blueprint misti --all-detectors
+

Or you can even pass the path to the contract directly:

+
yarn blueprint misti path/to/my/contract.tact
+

If you have any problems, feel free to reach out to us in the Misti discussion group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/tutorial/ci-cd/index.html b/tools/misti/docs/tutorial/ci-cd/index.html new file mode 100644 index 000000000..67409c5b2 --- /dev/null +++ b/tools/misti/docs/tutorial/ci-cd/index.html @@ -0,0 +1,42 @@ + + + + + +Integrating Misti into CI/CD | Misti + + + + +
Version: 0.4.0

Integrating Misti into CI/CD

+

Integrating Misti into your CI/CD pipeline ensures continuous code quality checks, catching issues early in the development cycle.

+

Using Tact Template

+

tact-template is a template project for Tact. If you started your project from this template, Misti is already installed in the CI. You also have the yarn lint command available in your package.json.

+

GitHub Actions

+

To integrate Misti into your GitHub Actions workflow, you need to add a command that runs Misti as part of your CI process. Here's how you can do it:

+

1. Open your GitHub repository

+

2. Create or edit the GitHub Actions workflow YAML file

+

It could be located at e.g., .github/workflows/ci.yml.

+

3. Add the step to run Misti to your YAML file

+

For example:

+
name: CI

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:

jobs:
test:
strategy:
fail-fast: false
matrix:
node-version: [22]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install Soufflé on Ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
sudo wget https://souffle-lang.github.io/ppa/souffle-key.public -O /usr/share/keyrings/souffle-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/souffle-archive-keyring.gpg] https://souffle-lang.github.io/ppa/ubuntu/ stable main" | sudo tee /etc/apt/sources.list.d/souffle.list
sudo apt update
sudo apt install souffle

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: yarn install

- name: Run Misti
run: yarn misti --min-severity medium /path/to/your/tact.config.json
+

The yarn misti --min-severity medium /path/to/your/tact.config.json command will run Misti against your project. If Misti detects any issues that are not suppressed by your configuration, it will return a non-zero exit code, causing the CI pipeline to fail.

+

The --min-severity medium will filter out low-priority warnings. You can always run Misti with all the detectors enabled locally in order to get the most comprehensive warnings output: yarn misti --all-detectors /path/to/your/tact.config.json

+

4. Adjusting the Misti Configuration

+

If you find that Misti is too noisy (e.g., detecting issues that are not relevant to your project), you can adjust your Misti configuration file to suppress those warnings. Refer to the Configuration section for more details on how to customize your settings.

+

Integration with Blueprint Projects

+

To add Misti to the CI for your Blueprint project, follow these steps:

+
    +
  1. Install blueprint-misti.
  2. +
  3. Follow the steps to set up the GitHub action above, but replace the yarn misti command with npx blueprint misti --blueprint-project <PROJECT_NAME>, where <PROJECT_NAME> is the name of the project displayed when you run npx blueprint build.
  4. +
+ + \ No newline at end of file diff --git a/tools/misti/docs/tutorial/cli/index.html b/tools/misti/docs/tutorial/cli/index.html new file mode 100644 index 000000000..5503c4cfe --- /dev/null +++ b/tools/misti/docs/tutorial/cli/index.html @@ -0,0 +1,105 @@ + + + + + +Command-Line Interface | Misti + + + + +
Version: 0.4.0

Command-Line Interface

+

Below is a list of all available CLI (Command-Line Interface) options for the project, with a brief explanation of each.

+

-t, --tools <className[:key=value...]>

+
    +
  • Description: Specifies a tool to enable with optional configuration. This option can be used multiple times.
  • +
  • Example: -t "DumpCfg:format=dot"
  • +
+

--output-path <PATH>

+
    +
  • Description: Specifies the directory to save warnings or output generated by tools. If <PATH> is -, then the output is sent to stdout.
  • +
  • Default: -
  • +
+

--list-tools

+
    +
  • Description: Lists available tools and their configuration options.
  • +
  • Default: false
  • +
+

-o, --output-format <json|plain>

+
    +
  • Description: Sets the output format for all tools and warnings (either JSON or plain text).
  • +
  • Default: plain
  • +
+

-C, --no-colors

+
    +
  • Description: Disables ANSI colors in the output.
  • +
  • Default: false
  • +
+

--souffle-binary <PATH>

+
    +
  • Description: Specifies the path to the Soufflé binary.
  • +
  • Default: "souffle"
  • +
+

--souffle-path <PATH>

+
    +
  • Description: Specifies the directory to save generated Soufflé files.
  • +
  • Default: "/tmp/misti/souffle"
  • +
+

--souffle-verbose

+
    +
  • Description: Generates human-readable, more verbose Soufflé files.
  • +
  • Default: false
  • +
+

--tact-stdlib-path <PATH>

+
    +
  • Description: Specifies the path to the Tact standard library.
  • +
+

-v, --verbose

+
    +
  • Description: Enables verbose output.
  • +
  • Default: false
  • +
+

-q, --quiet

+
    +
  • Description: Suppresses all output.
  • +
  • Default: false
  • +
+

-m, --min-severity <info|low|medium|high|critical>

+
    +
  • Description: Sets the minimum level of severity to report.
  • +
  • Default: info
  • +
+

-de, --enabled-detectors <name|path:name>

+
    +
  • Description: A comma-separated list of detectors to enable.
  • +
  • Argument Validation: Requires a non-empty list of detector names.
  • +
+

-dd, --disabled-detectors <names>

+
    +
  • Description: A comma-separated list of detector names to disable.
  • +
  • Argument Validation: Requires a non-empty list of detector names.
  • +
+

-A, --all-detectors

+
    +
  • Description: Enables all available built-in detectors.
  • +
  • Default: false
  • +
+

-c, --config <PATH>

+
    +
  • Description: Specifies the path to the Misti configuration file.
  • +
+

--new-detector <PATH>

+
    +
  • Description: Creates a new custom detector at the specified path.
  • +
  • Default: undefined
  • +
+ + \ No newline at end of file diff --git a/tools/misti/docs/tutorial/configuration/index.html b/tools/misti/docs/tutorial/configuration/index.html new file mode 100644 index 000000000..39d9c00d2 --- /dev/null +++ b/tools/misti/docs/tutorial/configuration/index.html @@ -0,0 +1,77 @@ + + + + + +Configuration | Misti + + + + +
Version: 0.4.0

Configuration

+

This guide provides an example of the JSON configuration file for Misti, detailing the possible options you can set.

+

Configuration Options

+
    +
  • +

    detectors (array of objects, optional): List of detectors to run. Each detector can be specified with a className and optionally a modulePath if it’s a custom detector.

    +
      +
    • className (string, required): The class name of the detector.
    • +
    • modulePath (string, optional): The file path of the detector module if it's a custom implementation.
    • +
    +
  • +
  • +

    tools (array of objects, optional): List of tools to enable, each with its own configuration.

    +
      +
    • className (string, required): The class name of the tool.
    • +
    • options (object, optional): Key-value configuration options for the tool.
    • +
    +
  • +
  • +

    suppressions (array of objects, optional): A list of suppressions for warnings.

    +
      +
    • detector (string, required): The detector to suppress warnings for.
    • +
    • position (string, required): The position in the code where the warning should be suppressed.
    • +
    +
  • +
  • +

    ignoredProjects (array of strings, optional): List of Tact projects to ignore during analysis.

    +
  • +
  • +

    soufflePath (string, optional): Directory to save generated Soufflé files, useful for debugging purposes. If not set, a temporary directory will be used.

    +
  • +
  • +

    souffleVerbose (boolean, optional): If set, generates more readable Soufflé files instead of optimizing the output for size.

    +
  • +
  • +

    tactStdlibPath (string, optional): Path to the Tact standard library. If not set, the default standard library from the active Tact setup will be used.

    +
  • +
  • +

    unusedPrefix (string, default: "_"): Identifiers starting with this prefix won't be reported as unused by the built-in detectors.

    +
  • +
  • +

    verbosity (string, optional, default: "default"): Verbosity level of the logs. Possible values are quiet, debug, and default.

    +
  • +
+

Running Misti with Configuration

+

To run Misti with the specified configuration file, use the following command:

+
npx misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json
+

This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration.

+

Default Configuration File

+

By default, Misti enables all built-in detectors. Below is an example of the default configuration file:

+
{
"detectors": [
{ "className": "DivideBeforeMultiply" },
{ "className": "ReadOnlyVariables" },
{ "className": "NeverAccessedVariables" },
{ "className": "UnboundLoops" },
{ "className": "ZeroAddress" },
{ "className": "BranchDuplicate" },
{ "className": "FieldDoubleInit" },
{ "className": "PreferAugmentedAssign" },
{ "className": "StringReceiversOverlap" },
{ "className": "ArgCopyMutation" }
],
"ignoredProjects": [],
"soufflePath": "/tmp/misti/souffle",
"souffleVerbose": false,
"unusedPrefix": "_",
"verbosity": "default"
}
+

All the built-in detectors are enabled by default. You can find the complete configuration schema and default configuration file on GitHub: configSchema.json.

+

You can always dump the Misti configuration file in use by passing the --dump-config option in the CLI:

+
npx misti --dump-config path/to/your/tact.config.json
+

If there is no Misti config in the directory, Misti dumps the default config. This can be used to adjust it, such as adding or suppressing some detectors.

+

Getting Help

+

If you need assistance or encounter any issues, please create an issue on GitHub at nowarp/misti or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/docs/tutorial/getting-started/index.html b/tools/misti/docs/tutorial/getting-started/index.html new file mode 100644 index 000000000..6f32aafee --- /dev/null +++ b/tools/misti/docs/tutorial/getting-started/index.html @@ -0,0 +1,62 @@ + + + + + +Getting started | Misti + + + + +
Version: 0.4.0

Getting started

+

This guide will walk you through the steps to install and set up the Misti static analyzer.

+

Prerequisites

+

Before you begin, ensure you have the following software installed on your system:

+
    +
  • Git
  • +
  • Yarn
  • +
  • Node.js version 22 or higher
  • +
  • Soufflé
  • +
+

Installation

+

Misti is distributed via npm and should be added to your Tact project in the same way as Tact itself:

+
yarn add @nowarp/misti
+

Using Development Version

+

The latest development version may be unstable, yet it includes all the recently added detectors and therefore can provide a more comprehensive analysis.

+

To install the latest development version you should:

+
    +
  1. Clone Misti: git clone https://github.com/nowarp/misti
  2. +
  3. Build it: cd misti && yarn install && yarn build
  4. +
  5. Use it in your Tact project: cd /path/to/tact/project && yarn add file:/path/to/misti
  6. +
+

Running the analysis

+

Run Misti by specifying a Tact project configuration:

+
npx misti path/to/tact.config.json
+

This will highlight any warnings the analyzer found.

+

You can also add a script to your package.json to simplify running the linting process:

+
{
"scripts": {
"lint": "npx misti path/to/tact.config.json"
}
}
+

More usage examples

+

Below are a few usage examples for common scenarios when using the misti CLI.

+

Suppressing Specific Detectors

+

To run misti while suppressing specific detectors, such as ReadOnlyVariables:

+
npx misti --suppress ReadOnlyVariables path/to/tact.config.json
+

Enabling All Detectors

+

Running misti with all available built-in detectors enabled:

+
npx misti --all-detectors path/to/tact.config.json
+

It is recommended to do that when auditing the project.

+

Running in Quiet Mode

+

To suppress all output while running misti getting just a return code:

+
npx misti --quiet path/to/tact.config.json
+

This might be useful in scripts and CI/CD.

+

Troubleshooting

+

If you encounter any issues during the installation process, feel free to create an issue or ask in the Misti Telegram group.

+ + \ No newline at end of file diff --git a/tools/misti/index.html b/tools/misti/index.html new file mode 100644 index 000000000..945cf3be7 --- /dev/null +++ b/tools/misti/index.html @@ -0,0 +1,21 @@ + + + + + +Welcome to Misti | Misti + + + + +

Welcome to Misti

The tool for static analysis in the TON ecosystem.

🔒 Detect Code Issues

Identify and fix potential security flaws and code problems early in the development cycle.

⚙️ Streamline Development

Integrate Misti into your CI/CD pipeline to ensure continuous code quality checks.

🛠️ Custom Detectors

Create custom detectors to solve specific problems in your code or to provide a thorough security review if you are an auditor.

💬 Need more? Reach me out: @jubnzv

+ + \ No newline at end of file

9&EVJilgSa#GDmV-Q? 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%0ADW@Kibvr+0my6QU(r*@ZPjpTCyBeCl}0 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 + + + + +Misti + + + + +