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..b09a3dc7d --- /dev/null +++ b/404.html @@ -0,0 +1,24 @@ + + + + + +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.f7007ee9.css b/assets/css/styles.f7007ee9.css new file mode 100644 index 000000000..cb9984e9a --- /dev/null +++ b/assets/css/styles.f7007ee9.css @@ -0,0 +1 @@ +@import url(https://fonts.googleapis.com/css2?family=Nunito:wght@600&display=swap);.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)}.heroBanner_hAhw,.row--align-top{align-items:flex-start}.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-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}.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)}.heroTitle_zNcP,.navbar__brand{font-family:Nunito,sans-serif;text-transform:lowercase}.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}.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)}.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}.navbar__brand,a.table-of-contents__link--active{font-weight:700}.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}.sidebars-separator{border:none!important;border-top:.5px solid #ccc!important;box-sizing:initial!important;height:0!important;margin:5px 0!important}.hero{height:100vh;padding:20px 0}.hero__title{font-size:2.5rem}.hero__subtitle{font-size:1.2rem}.button--primary{margin-top:15px}.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}.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{min-height:100%}#__docusaurus,.heroBanner_hAhw{display:flex;flex-direction:column}.heroBanner_hAhw{background-image:url(/assets/images/background-823d579360ac24c08932eedcefbc1dc0.svg);background-position:50%;background-size:cover;color:#072341;height:100vh;justify-content:center;margin:0;overflow:hidden;padding:0 2rem;text-align:left}.heroTitle_zNcP{font-size:4rem;margin-bottom:.5rem;text-shadow:1px 1px 5px #0000004d}.heroSubtitle_NX3L{font-size:1.5rem;margin-bottom:.5rem}.heroSubtitleSmall_wW8f{font-size:1.1rem;margin-bottom:.5rem}.textContainer_y9OC{align-items:flex-start;-webkit-backdrop-filter:blur(15px);backdrop-filter:blur(15px);background:#ffffff59;border-radius:10px;box-shadow:0 4px 20px #0003;display:flex;flex-direction:column;max-width:600px;padding:2rem}.buttons_YgGx{align-items:center;display:flex;gap:1rem;justify-content:flex-start}.sectionPadding_JTui{padding-bottom:2rem;padding-top:2rem}.featureBox_C4l2{border-radius:8px;box-shadow:0 4px 15px #00000026;display:flex;flex-direction:column;height:100%;padding:1.5rem}.rowWithMargin_rNqB{margin-bottom:2rem}.centerButton_N5e1{display:flex;justify-content:center}.featuresTitle_elEa{color:var(--ifm-color-primary-darkest);font-size:1.75rem;font-weight:600;margin-bottom:1rem;padding-left:1.5rem;text-align:left}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.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);text-transform:uppercase}.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:768px){.heroBanner_hAhw{padding:0 4rem}}@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:1024px){.heroBanner_hAhw{padding:0 6rem}}@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 (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/background-823d579360ac24c08932eedcefbc1dc0.svg b/assets/images/background-823d579360ac24c08932eedcefbc1dc0.svg new file mode 100644 index 000000000..400e6725a --- /dev/null +++ b/assets/images/background-823d579360ac24c08932eedcefbc1dc0.svg @@ -0,0 +1,2110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 000000000..fbc35d186 Binary files /dev/null and b/assets/images/blueprint-select-project-b8656fa4266c0c7923d6b67c7f5950e6.png differ diff --git a/assets/images/dump-imports-mmd-455299aa0e63b065a70b166ab0597814.png b/assets/images/dump-imports-mmd-455299aa0e63b065a70b166ab0597814.png new file mode 100644 index 000000000..b900b2ca4 Binary files /dev/null and b/assets/images/dump-imports-mmd-455299aa0e63b065a70b166ab0597814.png differ diff --git a/assets/js/012e8e66.8c957f95.js b/assets/js/012e8e66.8c957f95.js new file mode 100644 index 000000000..70f4e1dc7 --- /dev/null +++ b/assets/js/012e8e66.8c957f95.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8700],{7337:(t,e,n)=>{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:"DumpImports",permalink:"/tools/misti/docs/next/tools/DumpImports"}},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:'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/03b4256a.f5655242.js b/assets/js/03b4256a.f5655242.js new file mode 100644 index 000000000..246b3dab0 --- /dev/null +++ b/assets/js/03b4256a.f5655242.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7354],{2682:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"0.4.0","label":"0.4.0","banner":"unmaintained","badge":true,"noIndex":false,"className":"docs-version-0.4.0","isLast":false,"docsSidebars":{"sidebar":[{"type":"link","label":"Introduction","href":"/tools/misti/docs/0.4.0/","docId":"intro","unlisted":false},{"type":"category","label":"Tutorial","items":[{"type":"link","label":"Getting Started","href":"/tools/misti/docs/0.4.0/tutorial/getting-started","docId":"tutorial/getting-started","unlisted":false},{"type":"link","label":"CI/CD Integration","href":"/tools/misti/docs/0.4.0/tutorial/ci-cd","docId":"tutorial/ci-cd","unlisted":false},{"type":"link","label":"Command-Line Interface","href":"/tools/misti/docs/0.4.0/tutorial/cli","docId":"tutorial/cli","unlisted":false},{"type":"link","label":"Configuration","href":"/tools/misti/docs/0.4.0/tutorial/configuration","docId":"tutorial/configuration","unlisted":false},{"type":"link","label":"Using with Blueprint","href":"/tools/misti/docs/0.4.0/tutorial/blueprint","docId":"tutorial/blueprint","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Detectors Overview","href":"/tools/misti/docs/0.4.0/detectors","docId":"detectors","unlisted":false},{"type":"category","label":"Detectors","items":[{"type":"link","label":"ArgCopyMutation","href":"/tools/misti/docs/0.4.0/detectors/ArgCopyMutation","docId":"detectors/ArgCopyMutation","unlisted":false},{"type":"link","label":"AsmIsUsed","href":"/tools/misti/docs/0.4.0/detectors/AsmIsUsed","docId":"detectors/AsmIsUsed","unlisted":false},{"type":"link","label":"BranchDuplicate","href":"/tools/misti/docs/0.4.0/detectors/BranchDuplicate","docId":"detectors/BranchDuplicate","unlisted":false},{"type":"link","label":"ConstantAddress","href":"/tools/misti/docs/0.4.0/detectors/ConstantAddress","docId":"detectors/ConstantAddress","unlisted":false},{"type":"link","label":"DivideBeforeMultiply","href":"/tools/misti/docs/0.4.0/detectors/DivideBeforeMultiply","docId":"detectors/DivideBeforeMultiply","unlisted":false},{"type":"link","label":"DumpIsUsed","href":"/tools/misti/docs/0.4.0/detectors/DumpIsUsed","docId":"detectors/DumpIsUsed","unlisted":false},{"type":"link","label":"DuplicatedCondition","href":"/tools/misti/docs/0.4.0/detectors/DuplicatedCondition","docId":"detectors/DuplicatedCondition","unlisted":false},{"type":"link","label":"EnsurePrgSeed","href":"/tools/misti/docs/0.4.0/detectors/EnsurePrgSeed","docId":"detectors/EnsurePrgSeed","unlisted":false},{"type":"link","label":"FalseCondition","href":"/tools/misti/docs/0.4.0/detectors/FalseCondition","docId":"detectors/FalseCondition","unlisted":false},{"type":"link","label":"FieldDoubleInit","href":"/tools/misti/docs/0.4.0/detectors/FieldDoubleInit","docId":"detectors/FieldDoubleInit","unlisted":false},{"type":"link","label":"InheritedStateMutation","href":"/tools/misti/docs/0.4.0/detectors/InheritedStateMutation","docId":"detectors/InheritedStateMutation","unlisted":false},{"type":"link","label":"NeverAccessedVariables","href":"/tools/misti/docs/0.4.0/detectors/NeverAccessedVariables","docId":"detectors/NeverAccessedVariables","unlisted":false},{"type":"link","label":"OptimalMathFunction","href":"/tools/misti/docs/0.4.0/detectors/OptimalMathFunction","docId":"detectors/OptimalMathFunction","unlisted":false},{"type":"link","label":"PreferAugmentedAssign","href":"/tools/misti/docs/0.4.0/detectors/PreferAugmentedAssign","docId":"detectors/PreferAugmentedAssign","unlisted":false},{"type":"link","label":"PreferredStdlibApi","href":"/tools/misti/docs/0.4.0/detectors/PreferredStdlibApi","docId":"detectors/PreferredStdlibApi","unlisted":false},{"type":"link","label":"ReadOnlyVariables","href":"/tools/misti/docs/0.4.0/detectors/ReadOnlyVariables","docId":"detectors/ReadOnlyVariables","unlisted":false},{"type":"link","label":"StringReceiversOverlap","href":"/tools/misti/docs/0.4.0/detectors/StringReceiversOverlap","docId":"detectors/StringReceiversOverlap","unlisted":false},{"type":"link","label":"UnboundLoops","href":"/tools/misti/docs/0.4.0/detectors/UnboundLoops","docId":"detectors/UnboundLoops","unlisted":false},{"type":"link","label":"UnusedOptional","href":"/tools/misti/docs/0.4.0/detectors/UnusedOptional","docId":"detectors/UnusedOptional","unlisted":false},{"type":"link","label":"ZeroAddress","href":"/tools/misti/docs/0.4.0/detectors/ZeroAddress","docId":"detectors/ZeroAddress","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"link","label":"Tools Overview","href":"/tools/misti/docs/0.4.0/tools","docId":"tools","unlisted":false},{"type":"category","label":"Tools","items":[{"type":"link","label":"DumpAst","href":"/tools/misti/docs/0.4.0/tools/DumpAst","docId":"tools/DumpAst","unlisted":false},{"type":"link","label":"DumpCfg","href":"/tools/misti/docs/0.4.0/tools/DumpCfg","docId":"tools/DumpCfg","unlisted":false},{"type":"link","label":"DumpConfig","href":"/tools/misti/docs/0.4.0/tools/DumpConfig","docId":"tools/DumpConfig","unlisted":false}],"collapsed":true,"collapsible":true},{"type":"category","label":"Hacking","items":[{"type":"link","label":"Contributing","href":"/tools/misti/docs/0.4.0/hacking/contributing","docId":"hacking/contributing","unlisted":false},{"type":"link","label":"Developing Misti","href":"/tools/misti/docs/0.4.0/hacking/developing-misti","docId":"hacking/developing-misti","unlisted":false},{"type":"link","label":"Design Overview","href":"/tools/misti/docs/0.4.0/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/0.4.0/hacking/souffle","docId":"hacking/souffle","unlisted":false},{"type":"link","label":"Custom Detectors","href":"/tools/misti/docs/0.4.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 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/0600087e.2097de6c.js b/assets/js/0600087e.2097de6c.js new file mode 100644 index 000000000..726a4ba85 --- /dev/null +++ b/assets/js/0600087e.2097de6c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9713],{8078:(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.5/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.5/detectors/ZeroAddress.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"UnusedOptional",permalink:"/tools/misti/docs/detectors/UnusedOptional"},next:{title:"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/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.90b7d615.js b/assets/js/0c390d31.90b7d615.js new file mode 100644 index 000000000..6d3894555 --- /dev/null +++ b/assets/js/0c390d31.90b7d615.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/0.4.0/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/0.4.0/tutorial/ci-cd"},next:{title:"Configuration",permalink:"/tools/misti/docs/0.4.0/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.9f8c235e.js b/assets/js/0e4e7ef7.9f8c235e.js new file mode 100644 index 000000000..b5ba2fbba --- /dev/null +++ b/assets/js/0e4e7ef7.9f8c235e.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/0.4.0/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/0.4.0/tutorial/cli"},next:{title:"Using with Blueprint",permalink:"/tools/misti/docs/0.4.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 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.19df6688.js b/assets/js/0f37fc5e.19df6688.js new file mode 100644 index 000000000..55fd50858 --- /dev/null +++ b/assets/js/0f37fc5e.19df6688.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:"ShortCircuitCondition",permalink:"/tools/misti/docs/next/detectors/ShortCircuitCondition"},next:{title:"SuspiciousMessageMode",permalink:"/tools/misti/docs/next/detectors/SuspiciousMessageMode"}},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/110db9ee.e741188f.js b/assets/js/110db9ee.e741188f.js new file mode 100644 index 000000000..25497ae73 --- /dev/null +++ b/assets/js/110db9ee.e741188f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8164],{5547:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>u,frontMatter:()=>a,metadata:()=>i,toc:()=>c});var o=t(4848),s=t(8453);const a={},r="UnboundMap",i={id:"detectors/UnboundMap",title:"UnboundMap",description:"An optional detector that highlights cases where a map field allows inserting",source:"@site/versioned_docs/version-0.5/detectors/UnboundMap.md",sourceDirName:"detectors",slug:"/detectors/UnboundMap",permalink:"/tools/misti/docs/detectors/UnboundMap",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.5/detectors/UnboundMap.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"UnboundLoop",permalink:"/tools/misti/docs/detectors/UnboundLoop"},next:{title:"UnusedExpressionResult",permalink:"/tools/misti/docs/detectors/UnusedExpressionResult"}},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,s.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"unboundmap",children:"UnboundMap"}),"\n",(0,o.jsxs)(n.p,{children:["An optional detector that highlights cases where a map field allows inserting\nvalues (e.g., via ",(0,o.jsx)(n.code,{children:".set"}),") but lacks functionality for removing entries (e.g., via ",(0,o.jsx)(n.code,{children:".del"}),")."]}),"\n",(0,o.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsx)(n.p,{children:"A map without a method to remove elements can lead to storage overflow, particularly\nin long-term contract usage. Failing to provide a way to clear or delete entries\ncan result in uncontrolled storage growth, which not only wastes resources but\nmay also increase the cost of contract execution and maintenance over time."}),"\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:"contract Test {\n map: Map;\n\n setEntry(key: Int, value: String) {\n self.map.set(key, value); // Bad\n }\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:"contract Test {\n map: Map;\n\n setEntry(key: Int, value: String) {\n self.map.set(key, value);\n }\n\n delEntry(key: Int) {\n self.map.del(key); // Fixed: Added a new API method\n }\n}\n"})})]})}function u(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:()=>i});var o=t(6540);const s={},a=o.createContext(s);function r(e){const n=o.useContext(a);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(a.Provider,{value:n},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/129b217c.9e750dae.js b/assets/js/129b217c.9e750dae.js new file mode 100644 index 000000000..8eb9fab51 --- /dev/null +++ b/assets/js/129b217c.9e750dae.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5422],{4558:(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.5/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.5/detectors/AsmIsUsed.md",tags:[],version:"0.5",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/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.ba7446c4.js b/assets/js/150b97d9.ba7446c4.js new file mode 100644 index 000000000..6796a08ac --- /dev/null +++ b/assets/js/150b97d9.ba7446c4.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/0.4.0/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/0.4.0/detectors/ZeroAddress"},next:{title:"DumpAst",permalink:"/tools/misti/docs/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/1a2cd3da.0974c124.js b/assets/js/1a2cd3da.0974c124.js new file mode 100644 index 000000000..f2d5ea774 --- /dev/null +++ b/assets/js/1a2cd3da.0974c124.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4006],{3020:(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.5/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.5/detectors/ConstantAddress.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"CellOverflow",permalink:"/tools/misti/docs/detectors/CellOverflow"},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/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.26ab9acc.js b/assets/js/1a8310a1.26ab9acc.js new file mode 100644 index 000000000..813777357 --- /dev/null +++ b/assets/js/1a8310a1.26ab9acc.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/0.4.0/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/0.4.0/tools/DumpConfig"},next:{title:"Developing Misti",permalink:"/tools/misti/docs/0.4.0/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/0.4.0/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.e34de4aa.js b/assets/js/1b960128.e34de4aa.js new file mode 100644 index 000000000..89bdd8da4 --- /dev/null +++ b/assets/js/1b960128.e34de4aa.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/0.4.0/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/0.4.0/tools/DumpCfg"},next:{title:"Contributing",permalink:"/tools/misti/docs/0.4.0/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/230b3a10.f8054203.js b/assets/js/230b3a10.f8054203.js new file mode 100644 index 000000000..54c9131c3 --- /dev/null +++ b/assets/js/230b3a10.f8054203.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3031],{3940:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>d});var r=s(4848),n=s(8453);const o={},l="CellOverflow",i={id:"detectors/CellOverflow",title:"CellOverflow",description:"A detector that identifies cell overflow problems.",source:"@site/versioned_docs/version-0.5/detectors/CellOverflow.md",sourceDirName:"detectors",slug:"/detectors/CellOverflow",permalink:"/tools/misti/docs/detectors/CellOverflow",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.5/detectors/CellOverflow.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"BranchDuplicate",permalink:"/tools/misti/docs/detectors/BranchDuplicate"},next:{title:"ConstantAddress",permalink:"/tools/misti/docs/detectors/ConstantAddress"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2},{value:"Resources",id:"resources",level:2}];function a(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",...(0,n.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"celloverflow",children:"CellOverflow"}),"\n",(0,r.jsx)(t.p,{children:"A detector that identifies cell overflow problems."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"Cell overflow is an issue specific to the TON blockchain. TON stores data in\ncells, which are low-level data structures used for serialization and deserialization."}),"\n",(0,r.jsxs)(t.p,{children:["The overflow issue occurs when the user attempts to store more data in a cell\nthan it supports. The current limitation is 1023 bits and 4 references to other\ncells. When these limits are exceeded, the contract throws an error with the\nexit code ",(0,r.jsx)(t.code,{children:"8"})," during the compute phase."]}),"\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:"// Bad: storeRef is used more than 4 times\nbeginCell()\n .storeRef(...)\n .storeAddress(myAddress())\n .storeRef(...)\n .storeRef(...)\n .storeRef(...)\n .storeRef(...)\n .endCell()\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:"// OK: Fixed after the analyzer highlighted it\nbeginCell()\n .storeRef(...)\n .storeAddress(myAddress())\n .storeRef(...)\n .storeRef(...)\n .storeRef(...)\n .endCell()\n"})}),"\n",(0,r.jsx)(t.h2,{id:"resources",children:"Resources"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://docs.ton.org/develop/data-formats/cell-boc",children:"Cell & Bag of Cells (BoC) | TON Docs"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://docs.ton.org/learn/tvm-instructions/tvm-exit-codes",children:"TVM Exit codes | TON Docs"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-cells/",children:"Cells, Builders and Slices | Tact Docs"})}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,n.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>l,x:()=>i});var r=s(6540);const n={},o=r.createContext(n);function l(e){const t=r.useContext(o);return r.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(n):e.components||n:l(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/23b0c962.2fa9fd96.js b/assets/js/23b0c962.2fa9fd96.js new file mode 100644 index 000000000..c9f0e8c09 --- /dev/null +++ b/assets/js/23b0c962.2fa9fd96.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:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>l,metadata:()=>r,toc:()=>c});var s=i(4848),t=i(8453);const l={},o="Command-Line Interface",r={id:"tutorial/cli",title:"Command-Line Interface",description:"CLI Options",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"}},d={},c=[{value:"CLI Options",id:"cli-options",level:2},{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},{value:"Exit Codes",id:"exit-codes",level:2}];function a(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",strong:"strong",ul:"ul",...(0,t.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.h2,{id:"cli-options",children:"CLI Options"}),"\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"]}),"\n",(0,s.jsx)(n.h2,{id:"exit-codes",children:"Exit Codes"}),"\n",(0,s.jsx)(n.p,{children:"Misti returns different exit codes depending on the execution result:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"0"}),": Successful execution with no warnings or errors."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"1"}),": Warnings were reported."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"2"}),": Execution failed due to an internal or execution error."]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.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 t={},l=s.createContext(t);function o(e){const n=s.useContext(l);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(t):e.components||t:o(e.components),s.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/24ab0ec7.697f91e1.js b/assets/js/24ab0ec7.697f91e1.js new file mode 100644 index 000000000..a89c659ff --- /dev/null +++ b/assets/js/24ab0ec7.697f91e1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9439],{2592:(e,s,n)=>{n.r(s),n.d(s,{assets:()=>a,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>d});var t=n(4848),i=n(8453);const o={},r="SuspiciousMessageMode",c={id:"detectors/SuspiciousMessageMode",title:"SuspiciousMessageMode",description:"Detects suspicious usage of the mode field in SendParameters struct instances.",source:"@site/docs/detectors/SuspiciousMessageMode.md",sourceDirName:"detectors",slug:"/detectors/SuspiciousMessageMode",permalink:"/tools/misti/docs/next/detectors/SuspiciousMessageMode",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/SuspiciousMessageMode.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/next/detectors/StringReceiversOverlap"},next:{title:"UnboundLoop",permalink:"/tools/misti/docs/next/detectors/UnboundLoop"}},a={},d=[{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",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.h1,{id:"suspiciousmessagemode",children:"SuspiciousMessageMode"}),"\n",(0,t.jsxs)(s.p,{children:["Detects suspicious usage of the ",(0,t.jsx)(s.code,{children:"mode"})," field in ",(0,t.jsx)(s.code,{children:"SendParameters"})," struct instances."]}),"\n",(0,t.jsx)(s.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,t.jsxs)(s.p,{children:["Incorrect usage of the ",(0,t.jsx)(s.code,{children:"mode"})," field in ",(0,t.jsx)(s.code,{children:"SendParameters"})," can lead to unintended behavior when sending messages,\nsuch as incorrect flags being set, which can cause security vulnerabilities or unexpected contract behavior."]}),"\n",(0,t.jsx)(s.p,{children:(0,t.jsx)(s.strong,{children:"What it checks:"})}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:["Ensures that the ",(0,t.jsx)(s.code,{children:"mode"})," expression only uses the bitwise OR operator ",(0,t.jsx)(s.code,{children:"|"}),"."]}),"\n",(0,t.jsx)(s.li,{children:"Warns if integer literals are used instead of symbolic constants."}),"\n",(0,t.jsxs)(s.li,{children:["Warns if the same flag is used multiple times in the ",(0,t.jsx)(s.code,{children:"mode"})," expression."]}),"\n"]}),"\n",(0,t.jsx)(s.h2,{id:"example",children:"Example"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-tact",children:"// Suspicious usage:\nsend(SendParameters{\n to: recipient,\n value: amount,\n mode: SendRemainingBalance | SendRemainingBalance // Bad: Duplicate flag\n});\n\n// Correct usage:\nsend(SendParameters{\n to: recipient,\n value: amount,\n mode: SendRemainingBalance | SendDestroyIfZero // Ok\n});\n"})})]})}function u(e={}){const{wrapper:s}={...(0,i.R)(),...e.components};return s?(0,t.jsx)(s,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,s,n)=>{n.d(s,{R:()=>r,x:()=>c});var t=n(6540);const i={},o=t.createContext(i);function r(e){const s=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function c(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),t.createElement(o.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/25eb63f7.0fec67f5.js b/assets/js/25eb63f7.0fec67f5.js new file mode 100644 index 000000000..cab1bbf08 --- /dev/null +++ b/assets/js/25eb63f7.0fec67f5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6941],{2637:(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.5/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.5/detectors/DumpIsUsed.md",tags:[],version:"0.5",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/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/26b19808.395ffe9a.js b/assets/js/26b19808.395ffe9a.js new file mode 100644 index 000000000..5b7740acb --- /dev/null +++ b/assets/js/26b19808.395ffe9a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3339],{8267:(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.5/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.5/detectors/FieldDoubleInit.md",tags:[],version:"0.5",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/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/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.54dbde22.js b/assets/js/2b785902.54dbde22.js new file mode 100644 index 000000000..5b6e81be7 --- /dev/null +++ b/assets/js/2b785902.54dbde22.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:"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:'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:'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:'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"})]}),(0,o.jsxs)(t.tr,{children:[(0,o.jsx)(t.td,{children:"4"}),(0,o.jsx)(t.td,{children:(0,o.jsx)(t.a,{href:"/tools/misti/docs/next/tools/DumpImports",children:"DumpImports"})}),(0,o.jsx)(t.td,{children:"Dumps the graph of imports"})]})]})]})]})}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/2c038e81.5a3ae8ee.js b/assets/js/2c038e81.5a3ae8ee.js new file mode 100644 index 000000000..7f037ea53 --- /dev/null +++ b/assets/js/2c038e81.5a3ae8ee.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7393],{3268:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>a,metadata:()=>i,toc:()=>d});var o=t(4848),s=t(8453);const a={},r="UnboundMap",i={id:"detectors/UnboundMap",title:"UnboundMap",description:"An optional detector that highlights cases where a map field allows inserting",source:"@site/docs/detectors/UnboundMap.md",sourceDirName:"detectors",slug:"/detectors/UnboundMap",permalink:"/tools/misti/docs/next/detectors/UnboundMap",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/UnboundMap.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"UnboundLoop",permalink:"/tools/misti/docs/next/detectors/UnboundLoop"},next:{title:"UnusedExpressionResult",permalink:"/tools/misti/docs/next/detectors/UnusedExpressionResult"}},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",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"unboundmap",children:"UnboundMap"}),"\n",(0,o.jsxs)(n.p,{children:["An optional detector that highlights cases where a map field allows inserting\nvalues (e.g., via ",(0,o.jsx)(n.code,{children:".set"}),") but lacks functionality for removing entries (e.g., via ",(0,o.jsx)(n.code,{children:".del"}),")."]}),"\n",(0,o.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsx)(n.p,{children:"A map without a method to remove elements can lead to storage overflow, particularly\nin long-term contract usage. Failing to provide a way to clear or delete entries\ncan result in uncontrolled storage growth, which not only wastes resources but\nmay also increase the cost of contract execution and maintenance over time."}),"\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:"contract Test {\n map: Map;\n\n setEntry(key: Int, value: String) {\n self.map.set(key, value); // Bad\n }\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:"contract Test {\n map: Map;\n\n setEntry(key: Int, value: String) {\n self.map.set(key, value);\n }\n\n delEntry(key: Int) {\n self.map.del(key); // Fixed: Added a new API method\n }\n}\n"})})]})}function u(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:()=>i});var o=t(6540);const s={},a=o.createContext(s);function r(e){const n=o.useContext(a);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/2c17c501.a6c5c68e.js b/assets/js/2c17c501.a6c5c68e.js new file mode 100644 index 000000000..9a83e2424 --- /dev/null +++ b/assets/js/2c17c501.a6c5c68e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[23],{2458:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=n(4848),a=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/versioned_docs/version-0.5/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.5/detectors/ArgCopyMutation.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"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,a.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) {\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,a.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:()=>o,x:()=>r});var s=n(6540);const a={},i=s.createContext(a);function o(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(a):e.components||a:o(e.components),s.createElement(i.Provider,{value:t},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/2fbff8b1.84b0cc23.js b/assets/js/2fbff8b1.84b0cc23.js new file mode 100644 index 000000000..93ec7d20c --- /dev/null +++ b/assets/js/2fbff8b1.84b0cc23.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1330],{3832:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>o,default:()=>h,frontMatter:()=>s,metadata:()=>d,toc:()=>l});var i=t(4848),r=t(8453);const s={},o="DumpImports",d={id:"tools/DumpImports",title:"DumpImports",description:"Misti provides a feature to dump the Import Graph of your Tact code in JSON, DOT, and Mermaid formats. This tool helps you understand the dependencies between different files and modules in your project, including how contracts import each other and use the standard library.",source:"@site/versioned_docs/version-0.5/tools/DumpImports.md",sourceDirName:"tools",slug:"/tools/DumpImports",permalink:"/tools/misti/docs/tools/DumpImports",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.5/tools/DumpImports.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpConfig",permalink:"/tools/misti/docs/tools/DumpConfig"},next:{title:"Design Overview",permalink:"/tools/misti/docs/hacking/design"}},a={},l=[{value:"Usage",id:"usage",level:2},{value:"Working with Mermaid and Graphviz",id:"working-with-mermaid-and-graphviz",level:2},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2},{value:"Including Standard Library Imports",id:"including-standard-library-imports",level:2},{value:"Example",id:"example",level:2},{value:"Interpreting the Import Graph",id:"interpreting-the-import-graph",level:2},{value:"Conclusion",id:"conclusion",level:2}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"dumpimports",children:"DumpImports"}),"\n",(0,i.jsxs)(n.p,{children:["Misti provides a feature to dump the ",(0,i.jsx)(n.strong,{children:"Import Graph"})," of your Tact code in JSON, DOT, and Mermaid formats. This tool helps you understand the dependencies between different files and modules in your project, including how contracts import each other and use the standard library."]}),"\n",(0,i.jsx)(n.h2,{id:"usage",children:"Usage"}),"\n",(0,i.jsx)(n.p,{children:"To dump the Import Graph in Mermaid format, use the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=mmd" \n'})}),"\n",(0,i.jsx)(n.p,{children:"To dump the Import Graph in Graphviz DOT format, use the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=dot" \n'})}),"\n",(0,i.jsx)(n.p,{children:"To dump the Import Graph in JSON format, use the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=json" \n'})}),"\n",(0,i.jsxs)(n.p,{children:["You can also include Tact standard library imports in the dump by adding ",(0,i.jsx)(n.code,{children:"dumpStdlib=true"})," to the ",(0,i.jsx)(n.code,{children:"DumpImports"})," options:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=dot,dumpStdlib=true" \n'})}),"\n",(0,i.jsx)(n.h2,{id:"working-with-mermaid-and-graphviz",children:"Working with Mermaid and Graphviz"}),"\n",(0,i.jsxs)(n.p,{children:["For guidance on how to work with Mermaid diagrams, Graphviz DOT files, and viewing them in Visual Studio Code, please refer to the ",(0,i.jsx)(n.a,{href:"/tools/misti/docs/tools/DumpCfg#working-with-mermaid",children:"DumpCfg documentation"})," and the ",(0,i.jsx)(n.a,{href:"/tools/misti/docs/tools/DumpCfg#working-with-graphviz",children:"Graphviz section"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"JSON Dumps"}),": Provide a detailed representation of the Import Graph in JSON format, including nodes and edges with their properties. Useful for programmatic analysis or custom tooling."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"DOT Dumps"}),": Offer a visual representation of the project's import dependencies. Useful for understanding how files and contracts depend on each other."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Mermaid Dumps"}),": Similar to DOT dumps but using Mermaid syntax, which can be easier to work with in certain environments, especially when using markdown files or online editors."]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"By utilizing these tools, developers can gain deeper insights into the dependency structure of their Tact projects, facilitating better project organization, dependency management, and code optimization."}),"\n",(0,i.jsx)(n.h2,{id:"including-standard-library-imports",children:"Including Standard Library Imports"}),"\n",(0,i.jsxs)(n.p,{children:["By default, the Import Graph excludes imports from the standard library. If you want to include standard library imports in your graph, add ",(0,i.jsx)(n.code,{children:"dumpStdlib=true"})," to the command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=mmd,dumpStdlib=true" contracts/main.tact\n'})}),"\n",(0,i.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(n.p,{children:"Consider a project with the following structure:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"main.tact"})}),":"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:'import "./constants.tact";\nimport "./messages.tact";\nimport "@stdlib/ownable";\ncontract C{}\n'})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"constants.tact"})}),":"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"const SOMETHING: Int = 123;\n"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"messages.tact"})}),":"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:'import "./constants.tact";\nmessage Msg { a: Bool }\n'})}),"\n",(0,i.jsx)(n.p,{children:"To dump the Import Graph in Mermaid format, run:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=mmd:dumpStdlib=true" contracts/main.tact\n'})}),"\n",(0,i.jsx)(n.p,{children:"The output will look like:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-mermaid",children:'graph TD\n node_1["main"]:::contractNode\n node_2["constants"]\n node_3["messages"]\n node_4["@stdlib/ownable.tact"]:::stdlibNode\n node_1 --\x3e node_2\n node_3 --\x3e node_2\n node_1 --\x3e node_3\n node_1 --\x3e node_4\n classDef contractNode fill:#90EE90,stroke:#333,stroke-width:2px;\n classDef stdlibNode fill:#FFFF80,stroke:#333,stroke-width:2px;\n'})}),"\n",(0,i.jsx)(n.p,{children:"Which will be rendered as:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Mermaid Output",src:t(2479).A+"",width:"656",height:"414"})}),"\n",(0,i.jsx)(n.p,{children:"In this diagram:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Nodes"})," representing files that contain contracts are filled with green."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Edges"})," represent import relationships between files."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"You can paste this Mermaid code into the Mermaid Live Editor or view it directly in VS Code with the appropriate extension."}),"\n",(0,i.jsx)(n.h2,{id:"interpreting-the-import-graph",children:"Interpreting the Import Graph"}),"\n",(0,i.jsx)(n.p,{children:"The Import Graph shows how files in your project are interconnected through import statements. Each node represents a file, and each edge represents an import from one file to another."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Nodes"}),":","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Files containing contracts are highlighted (green in the examples)."}),"\n",(0,i.jsx)(n.li,{children:"Standard library files are highlighted differently (yellow) when included."}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Edges"}),":","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Directed edges show the import relationship (",(0,i.jsx)(n.code,{children:"A --\x3e B"})," means ",(0,i.jsx)(n.code,{children:"A"})," imports ",(0,i.jsx)(n.code,{children:"B"}),")."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Understanding the Import Graph can help you:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Identify unnecessary dependencies."}),"\n",(0,i.jsx)(n.li,{children:"Visualize the structure of your project."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"conclusion",children:"Conclusion"}),"\n",(0,i.jsxs)(n.p,{children:["By utilizing the ",(0,i.jsx)(n.code,{children:"DumpImports"})," tool, developers can gain deeper insights into the dependency structure of their Tact projects, facilitating better project organization, dependency management, and code optimization."]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},2479:(e,n,t)=>{t.d(n,{A:()=>i});const i=t.p+"assets/images/dump-imports-mmd-455299aa0e63b065a70b166ab0597814.png"},8453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>d});var i=t(6540);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},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/30835b52.63e9b2c4.js b/assets/js/30835b52.63e9b2c4.js new file mode 100644 index 000000000..f8bdc959a --- /dev/null +++ b/assets/js/30835b52.63e9b2c4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6269],{3116:(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.5/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.5/detectors/DivideBeforeMultiply.md",tags:[],version:"0.5",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/322eba7d.15fc9303.js b/assets/js/322eba7d.15fc9303.js new file mode 100644 index 000000000..fdb44a109 --- /dev/null +++ b/assets/js/322eba7d.15fc9303.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[1193],{1535:(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"},n="Detectors Overview",c={id:"detectors",title:"Detectors Overview",description:"Built-in Detectors",source:"@site/versioned_docs/version-0.5/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.5/detectors.md",tags:[],version:"0.5",frontMatter:{id:"detectors",title:"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=[{value:"Built-in Detectors",id:"built-in-detectors",level:2}];function h(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",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.h2,{id:"built-in-detectors",children:"Built-in Detectors"}),"\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/CellOverflow",children:"CellOverflow"})}),(0,d.jsx)(t.td,{children:"Critical"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(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/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:"6"}),(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:"7"}),(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:"8"}),(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:"9"}),(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:"10"}),(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:"11"}),(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:"12"}),(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:"13"}),(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:"14"}),(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:"15"}),(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:"16"}),(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:"17"}),(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:"18"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/SendInLoop",children:"SendInLoop"})}),(0,d.jsx)(t.td,{children:"Medium"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{})]}),(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/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:"20"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/SuspiciousMessageMode",children:"SuspiciousMessageMode"})}),(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:"21"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/UnboundLoop",children:"UnboundLoop"})}),(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:"22"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/UnboundMap",children:"UnboundMap"})}),(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:"23"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/detectors/UnusedExpressionResult",children:"UnusedExpressionResult"})}),(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:"24"}),(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:"25"}),(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/35d1ab0d.32926c20.js b/assets/js/35d1ab0d.32926c20.js new file mode 100644 index 000000000..1c261332f --- /dev/null +++ b/assets/js/35d1ab0d.32926c20.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4787],{1322:(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.5/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.5/tools/DumpAst.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"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:'misti -t "DumpAst" \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:'misti -t "DumpAst:dumpStdlib=true" \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/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.bf621ae4.js b/assets/js/3b3a1a75.bf621ae4.js new file mode 100644 index 000000000..ad9722d13 --- /dev/null +++ b/assets/js/3b3a1a75.bf621ae4.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/0.4.0/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/0.4.0/detectors"},next:{title:"AsmIsUsed",permalink:"/tools/misti/docs/0.4.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={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.10b20c3b.js b/assets/js/3bfe497f.10b20c3b.js new file mode 100644 index 000000000..19a7062e0 --- /dev/null +++ b/assets/js/3bfe497f.10b20c3b.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/0.4.0/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/0.4.0/detectors/ConstantAddress"},next:{title:"DumpIsUsed",permalink:"/tools/misti/docs/0.4.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",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/3c9b1461.4a5fe7e2.js b/assets/js/3c9b1461.4a5fe7e2.js new file mode 100644 index 000000000..f8f747342 --- /dev/null +++ b/assets/js/3c9b1461.4a5fe7e2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3988],{849:(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.5/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.5/detectors/PreferAugmentedAssign.md",tags:[],version:"0.5",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/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/40440f59.e19073b4.js b/assets/js/40440f59.e19073b4.js new file mode 100644 index 000000000..53036f164 --- /dev/null +++ b/assets/js/40440f59.e19073b4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5671],{8246:(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.5/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.5/hacking/contributing.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"Souffl\xe9",permalink:"/tools/misti/docs/hacking/souffle"},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/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.835e2f8a.js b/assets/js/42510f93.835e2f8a.js new file mode 100644 index 000000000..0593bb056 --- /dev/null +++ b/assets/js/42510f93.835e2f8a.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/0.4.0/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/0.4.0/hacking/contributing"},next:{title:"Design Overview",permalink:"/tools/misti/docs/0.4.0/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.d823b28c.js b/assets/js/432cb5a5.d823b28c.js new file mode 100644 index 000000000..d17dfa682 --- /dev/null +++ b/assets/js/432cb5a5.d823b28c.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/0.4.0/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/0.4.0/hacking/developing-misti"},next:{title:"Souffl\xe9",permalink:"/tools/misti/docs/0.4.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,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/4624921c.a36b4fff.js b/assets/js/4624921c.a36b4fff.js new file mode 100644 index 000000000..62d7860f5 --- /dev/null +++ b/assets/js/4624921c.a36b4fff.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9510],{9567:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>s,default:()=>p,frontMatter:()=>a,metadata:()=>l,toc:()=>d});var i=t(4848),r=t(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.5/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.5/detectors/ReadOnlyVariables.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/detectors/PreferredStdlibApi"},next:{title:"SendInLoop",permalink:"/tools/misti/docs/detectors/SendInLoop"}},o={},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,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"readonlyvariables",children:"ReadOnlyVariables"}),"\n",(0,i.jsx)(n.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,i.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.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,i.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.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,i.jsx)(n.p,{children:"Use instead:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.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:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>l});var i=t(6540);const r={},a=i.createContext(r);function s(e){const n=i.useContext(a);return i.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(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/46947df5.86adfe22.js b/assets/js/46947df5.86adfe22.js new file mode 100644 index 000000000..787c1dd41 --- /dev/null +++ b/assets/js/46947df5.86adfe22.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4992],{1904:(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.5/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.5/detectors/EnsurePrgSeed.md",tags:[],version:"0.5",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/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.35b4841f.js b/assets/js/4ab26116.35b4841f.js new file mode 100644 index 000000000..f601f891b --- /dev/null +++ b/assets/js/4ab26116.35b4841f.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/0.4.0/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/0.4.0/detectors/BranchDuplicate"},next:{title:"DivideBeforeMultiply",permalink:"/tools/misti/docs/0.4.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/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.efba011c.js b/assets/js/51fe41a6.efba011c.js new file mode 100644 index 000000000..a274a7062 --- /dev/null +++ b/assets/js/51fe41a6.efba011c.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/0.4.0/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/0.4.0/detectors/InheritedStateMutation"},next:{title:"OptimalMathFunction",permalink:"/tools/misti/docs/0.4.0/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/53023ca8.611e95e8.js b/assets/js/53023ca8.611e95e8.js new file mode 100644 index 000000000..99273eb42 --- /dev/null +++ b/assets/js/53023ca8.611e95e8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2712],{4228:(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.5/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.5/detectors/NeverAccessedVariables.md",tags:[],version:"0.5",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/54df6b9c.ab93266a.js b/assets/js/54df6b9c.ab93266a.js new file mode 100644 index 000000000..bf3d59452 --- /dev/null +++ b/assets/js/54df6b9c.ab93266a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8962],{7852:(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.5/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.5/detectors/DuplicatedCondition.md",tags:[],version:"0.5",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/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/5604.07bdff8a.js b/assets/js/5604.07bdff8a.js new file mode 100644 index 000000000..2bb23b69a --- /dev/null +++ b/assets/js/5604.07bdff8a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5604],{5604:(t,e,r)=>{r.d(e,{zyo:()=>v});var n=r(6540),o={color:void 0,size:void 0,className:void 0,style:void 0,attr:void 0},i=n.createContext&&n.createContext(o),c=["attr","size","title"];function a(t,e){if(null==t)return{};var r,n,o=function(t,e){if(null==t)return{};var r={};for(var n in t)if(Object.prototype.hasOwnProperty.call(t,n)){if(e.indexOf(n)>=0)continue;r[n]=t[n]}return r}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(n=0;n<i.length;n++)r=i[n],e.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(t,r)&&(o[r]=t[r])}return o}function l(){return l=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t},l.apply(this,arguments)}function u(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,n)}return r}function s(t){for(var e=1;e<arguments.length;e++){var r=null!=arguments[e]?arguments[e]:{};e%2?u(Object(r),!0).forEach((function(e){f(t,e,r[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):u(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}function f(t,e,r){var n;return(e="symbol"==typeof(n=function(t,e){if("object"!=typeof t||!t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var n=r.call(t,e||"default");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}(e,"string"))?n:n+"")in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function p(t){return t&&t.map(((t,e)=>n.createElement(t.tag,s({key:e},t.attr),p(t.child))))}function b(t){return e=>n.createElement(y,l({attr:s({},t.attr)},e),p(t.child))}function y(t){var e=e=>{var r,{attr:o,size:i,title:u}=t,f=a(t,c),p=i||e.size||"1em";return e.className&&(r=e.className),t.className&&(r=(r?r+" ":"")+t.className),n.createElement("svg",l({stroke:"currentColor",fill:"currentColor",strokeWidth:"0"},e.attr,o,f,{className:r,style:s(s({color:t.color||e.color},e.style),t.style),height:p,width:p,xmlns:"http://www.w3.org/2000/svg"}),u&&n.createElement("title",null,u),t.children)};return void 0!==i?n.createElement(i.Consumer,null,(t=>e(t))):e(o)}function v(t){return b({tag:"svg",attr:{viewBox:"0 0 448 512"},child:[{tag:"path",attr:{d:"M446.7 98.6l-67.6 318.8c-5.1 22.5-18.4 28.1-37.3 17.5l-103-75.9-49.7 47.8c-5.5 5.5-10.1 10.1-20.7 10.1l7.4-104.9 190.9-172.5c8.3-7.4-1.8-11.5-12.9-4.1L117.8 284 16.2 252.2c-22.1-6.9-22.5-22.1 4.6-32.7L418.2 66.4c18.4-6.9 34.5 4.1 28.5 32.2z"},child:[]}]})(t)}}}]); \ 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.8f602791.js b/assets/js/59016342.8f602791.js new file mode 100644 index 000000000..fcd8d0764 --- /dev/null +++ b/assets/js/59016342.8f602791.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/0.4.0/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/0.4.0/detectors/UnboundLoops"},next:{title:"ZeroAddress",permalink:"/tools/misti/docs/0.4.0/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/5c07db7d.dbb32bd9.js b/assets/js/5c07db7d.dbb32bd9.js new file mode 100644 index 000000000..e8b854c60 --- /dev/null +++ b/assets/js/5c07db7d.dbb32bd9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4575],{342:(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.5/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.5/detectors/InheritedStateMutation.md",tags:[],version:"0.5",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/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.e34a6ec9.js b/assets/js/602c5d84.e34a6ec9.js new file mode 100644 index 000000000..db395cdb5 --- /dev/null +++ b/assets/js/602c5d84.e34a6ec9.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/0.4.0/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/0.4.0/detectors/FalseCondition"},next:{title:"InheritedStateMutation",permalink:"/tools/misti/docs/0.4.0/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.fb178849.js b/assets/js/6362ac9f.fb178849.js new file mode 100644 index 000000000..4c24e1e70 --- /dev/null +++ b/assets/js/6362ac9f.fb178849.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/0.4.0/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/0.4.0/tutorial/configuration"},next:{title:"Detectors Overview",permalink:"/tools/misti/docs/0.4.0/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/0.4.0/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.d93af67f.js b/assets/js/63bb535a.d93af67f.js new file mode 100644 index 000000000..4675c9dff --- /dev/null +++ b/assets/js/63bb535a.d93af67f.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/0.4.0/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/0.4.0/detectors/PreferAugmentedAssign"},next:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/0.4.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/6696f09b.57cd0d6b.js b/assets/js/6696f09b.57cd0d6b.js new file mode 100644 index 000000000..2f7b7493f --- /dev/null +++ b/assets/js/6696f09b.57cd0d6b.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/0.4.0/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/0.4.0/tools/DumpAst"},next:{title:"DumpConfig",permalink:"/tools/misti/docs/0.4.0/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/6afbdc7c.8a6b1736.js b/assets/js/6afbdc7c.8a6b1736.js new file mode 100644 index 000000000..2ca92d475 --- /dev/null +++ b/assets/js/6afbdc7c.8a6b1736.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4701],{6400:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>a,contentTitle:()=>s,default:()=>l,frontMatter:()=>r,metadata:()=>c,toc:()=>d});var n=i(4848),o=i(8453);const r={},s="Custom Detector Guide",c={id:"hacking/custom-detector",title:"Custom Detector Guide",description:"Introduction",source:"@site/versioned_docs/version-0.5/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.5/hacking/custom-detector.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"Developing Misti",permalink:"/tools/misti/docs/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(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"custom-detector-guide",children:"Custom Detector Guide"}),"\n",(0,n.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,n.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,n.jsx)(t.a,{href:"https://nowarp.io/tools/misti/api/",children:"Misti API Reference"}),"."]}),"\n",(0,n.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,n.jsx)(t.a,{href:"https://nowarp.io/tools/misti/api/classes/detectors_detector.Detector.html",children:(0,n.jsx)(t.code,{children:"Detector"})})," interface."]}),"\n",(0,n.jsx)(t.h2,{id:"creating-a-detector",children:"Creating a Detector"}),"\n",(0,n.jsxs)(t.p,{children:["You can create a new custom detector by executing Misti with the ",(0,n.jsx)(t.code,{children:"--new-detector"})," option: ",(0,n.jsx)(t.code,{children:"misti --new-detector implicitInit"}),"."]}),"\n",(0,n.jsxs)(t.p,{children:["This will create the ",(0,n.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,n.jsx)(t.p,{children:"Here's an example of how to implement a custom detector using Misti API:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.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,n.jsx)(t.h3,{id:"testing-the-detector",children:"Testing the detector"}),"\n",(0,n.jsxs)(t.p,{children:["To run Misti with only your new detector, use the ",(0,n.jsx)(t.code,{children:"--detectors"})," option, specifying the path to the detector and the Detector class name: ",(0,n.jsx)(t.code,{children:"misti path/to/your/tact.config.json --detectors path/to/implicitInit.ts:ImplicitInit"}),"."]}),"\n",(0,n.jsxs)(t.p,{children:["That's a good way to test the detector on the first run. You could also use the ",(0,n.jsx)(t.code,{children:"--verbose"})," CLI option and set the environment variable ",(0,n.jsx)(t.code,{children:"MISTI_TRACE=1"})," to facilitate debugging."]}),"\n",(0,n.jsx)(t.h3,{id:"saving-the-configuration",children:"Saving the configuration"}),"\n",(0,n.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,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:'{\n "detectors": [\n // Other detectors...\n { "className": "ImplicitInit", "modulePath": "ImplicitInit.ts" }\n ],\n}\n'})}),"\n",(0,n.jsxs)(t.p,{children:["After this, you could run Misti specifying a path to a custom configuration ",(0,n.jsx)(t.code,{children:"misti --config path/to/misti.config.json path/to/your/tact.config.json"}),"."]}),"\n",(0,n.jsx)(t.h2,{id:"example-detectors",children:"Example Detectors"}),"\n",(0,n.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,n.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,n.jsx)(t,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}},8453:(e,t,i)=>{i.d(t,{R:()=>s,x:()=>c});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 c(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/6bb9ad58.94c990fe.js b/assets/js/6bb9ad58.94c990fe.js new file mode 100644 index 000000000..51f337ced --- /dev/null +++ b/assets/js/6bb9ad58.94c990fe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9448],{693:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>c});var s=i(4848),l=i(8453);const t={},o="Command-Line Interface",r={id:"tutorial/cli",title:"Command-Line Interface",description:"CLI Options",source:"@site/versioned_docs/version-0.5/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.5/tutorial/cli.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"CI/CD Integration",permalink:"/tools/misti/docs/tutorial/ci-cd"},next:{title:"Configuration",permalink:"/tools/misti/docs/tutorial/configuration"}},d={},c=[{value:"CLI Options",id:"cli-options",level:2},{value:"<code>-t, --tools <className[:key=value...]></code>",id:"-t---tools-classnamekeyvalue",level:3},{value:"<code>--output-path <PATH></code>",id:"--output-path-path",level:3},{value:"<code>--list-tools</code>",id:"--list-tools",level:3},{value:"<code>-o, --output-format <json|plain></code>",id:"-o---output-format-jsonplain",level:3},{value:"<code>-C, --no-colors</code>",id:"-c---no-colors",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>-v, --verbose</code>",id:"-v---verbose",level:3},{value:"<code>-q, --quiet</code>",id:"-q---quiet",level:3},{value:"<code>-m, --min-severity <info|low|medium|high|critical></code>",id:"-m---min-severity-infolowmediumhighcritical",level:3},{value:"<code>-de, --enabled-detectors <name|path:name></code>",id:"-de---enabled-detectors-namepathname",level:3},{value:"<code>-dd, --disabled-detectors <names></code>",id:"-dd---disabled-detectors-names",level:3},{value:"<code>-A, --all-detectors</code>",id:"-a---all-detectors",level:3},{value:"<code>-c, --config <PATH></code>",id:"-c---config-path",level:3},{value:"<code>--new-detector <PATH></code>",id:"--new-detector-path",level:3},{value:"Exit Codes",id:"exit-codes",level:2}];function a(e){const n={code:"code",h1:"h1",h2:"h2",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.h2,{id:"cli-options",children:"CLI Options"}),"\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 <className[:key=value...]>"})}),"\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 <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:"<PATH>"})," 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 <json|plain>"})}),"\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 <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 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 <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 <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 <info|low|medium|high|critical>"})}),"\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 <name|path:name>"})}),"\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 <names>"})}),"\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 <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 Misti configuration file."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"--new-detector-path",children:(0,s.jsx)(n.code,{children:"--new-detector <PATH>"})}),"\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"]}),"\n",(0,s.jsx)(n.h2,{id:"exit-codes",children:"Exit Codes"}),"\n",(0,s.jsx)(n.p,{children:"Misti returns different exit codes depending on the execution result:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"0"}),": Successful execution with no warnings or errors."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"1"}),": Warnings were reported."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"2"}),": Execution failed due to an internal or execution error."]}),"\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/6bfbb660.67f004b0.js b/assets/js/6bfbb660.67f004b0.js new file mode 100644 index 000000000..d634815ee --- /dev/null +++ b/assets/js/6bfbb660.67f004b0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5173],{2963:(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.5/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.5/tutorial/ci-cd.md",tags:[],version:"0.5",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/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.46b8f441.js b/assets/js/719e5d48.46b8f441.js new file mode 100644 index 000000000..3d653748e --- /dev/null +++ b/assets/js/719e5d48.46b8f441.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/0.4.0/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/0.4.0/detectors/PreferredStdlibApi"},next:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/0.4.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/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/740c342d.44a80203.js b/assets/js/740c342d.44a80203.js new file mode 100644 index 000000000..9ae50a7a0 --- /dev/null +++ b/assets/js/740c342d.44a80203.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4910],{8670:(t,e,n)=>{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/versioned_docs/version-0.5/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.5/tools/DumpConfig.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpCfg",permalink:"/tools/misti/docs/tools/DumpCfg"},next:{title:"DumpImports",permalink:"/tools/misti/docs/tools/DumpImports"}},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:'misti -t "DumpConfig" <TACT_CONFIG_PATH|TACT_FILE_PATH>\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/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.591c6669.js b/assets/js/7499c02a.591c6669.js new file mode 100644 index 000000000..b6ba23ffa --- /dev/null +++ b/assets/js/7499c02a.591c6669.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3150],{4019:(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/0.4.0/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/0.4.0/detectors/AsmIsUsed"},next:{title:"ConstantAddress",permalink:"/tools/misti/docs/0.4.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/754ccd45.c7633e79.js b/assets/js/754ccd45.c7633e79.js new file mode 100644 index 000000000..558f29610 --- /dev/null +++ b/assets/js/754ccd45.c7633e79.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:()=>a,contentTitle:()=>c,default:()=>h,frontMatter:()=>r,metadata:()=>o,toc:()=>l});var s=n(4848),i=n(8453);const r={},c="Developing Misti",o={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"}},a={},l=[{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 d(e){const t={a:"a",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:"developing-misti",children:"Developing Misti"}),"\n",(0,s.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,s.jsxs)(t.p,{children:["Before you begin, please refer to the ",(0,s.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,s.jsx)(t.h2,{id:"cloning-the-repository",children:"Cloning the Repository"}),"\n",(0,s.jsx)(t.p,{children:"Clone the Misti repository:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"git clone 'https://github.com/nowarp/misti'\n"})}),"\n",(0,s.jsx)(t.h2,{id:"building-the-project",children:"Building the Project"}),"\n",(0,s.jsx)(t.p,{children:"Navigate to the project directory, install dependencies, generate necessary files, and build the project:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"cd misti && yarn install && yarn gen && yarn build\n"})}),"\n",(0,s.jsx)(t.h2,{id:"running-the-analyzer",children:"Running the Analyzer"}),"\n",(0,s.jsx)(t.p,{children:"During development, you can run the analyzer using:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"yarn misti\n"})}),"\n",(0,s.jsx)(t.p,{children:"For example, to run it for tests:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"yarn misti test/detectors/NeverAccessedVariables.tact\n"})}),"\n",(0,s.jsx)(t.h2,{id:"adding-backtraces-to-the-logger",children:"Adding Backtraces to the Logger"}),"\n",(0,s.jsxs)(t.p,{children:["To add debug traces to all log messages, set the ",(0,s.jsx)(t.code,{children:"MISTI_TRACE"})," environment variable to ",(0,s.jsx)(t.code,{children:"1"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"MISTI_TRACE=1 yarn misti test/detectors/NeverAccessedVariables.tact\n"})}),"\n",(0,s.jsx)(t.h2,{id:"updating-expected-outputs-of-tests",children:"Updating Expected Outputs of Tests"}),"\n",(0,s.jsxs)(t.p,{children:["To update the expected outputs of tests, set the ",(0,s.jsx)(t.code,{children:"BLESS"})," environment variable and run the tests:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test\n"})}),"\n",(0,s.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,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test test/tactIR.spec.ts tests/detectors/NeverAccessedVariables.tact\n"})}),"\n",(0,s.jsx)(t.p,{children:"And for another specific test:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test test/builtinDetectors.spec.ts test/detectors/BranchDuplicate.tact\n"})})]})}function h(e={}){const{wrapper:t}={...(0,i.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:()=>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/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/770027e6.28c96dd7.js b/assets/js/770027e6.28c96dd7.js new file mode 100644 index 000000000..26dcc9898 --- /dev/null +++ b/assets/js/770027e6.28c96dd7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7709],{4951:(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="UnusedExpressionResult",d={id:"detectors/UnusedExpressionResult",title:"UnusedExpressionResult",description:"A detector that identifies expression statements whose result is unused.",source:"@site/versioned_docs/version-0.5/detectors/UnusedExpressionResult.md",sourceDirName:"detectors",slug:"/detectors/UnusedExpressionResult",permalink:"/tools/misti/docs/detectors/UnusedExpressionResult",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.5/detectors/UnusedExpressionResult.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"UnboundMap",permalink:"/tools/misti/docs/detectors/UnboundMap"},next:{title:"UnusedOptional",permalink:"/tools/misti/docs/detectors/UnusedOptional"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function u(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:"unusedexpressionresult",children:"UnusedExpressionResult"}),"\n",(0,n.jsx)(t.p,{children:"A detector that identifies expression statements whose result is unused."}),"\n",(0,n.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,n.jsx)(t.p,{children:"Expression statements that don't alter the contract's state and whose results are not used\ncan lead to inefficiency, dead code, and potential confusion. They add unnecessary complexity\nwithout contributing to the logic or state of the contract."}),"\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:"self.foo == 3; // Warning: unused boolean expression\ninc(a); // Warning: unused return value\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:"self.foo = 3; // Fixed: corrected assignment\nnewValue = inc(a); // OK: result is now used\nlet _ = inc(a); // OK: explicitly ignored\n"})})]})}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/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/8078ad78.72d8805b.js b/assets/js/8078ad78.72d8805b.js new file mode 100644 index 000000000..bba14e859 --- /dev/null +++ b/assets/js/8078ad78.72d8805b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6208],{210:(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.5/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.5/detectors/FalseCondition.md",tags:[],version:"0.5",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/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.0e912fc3.js b/assets/js/8306354c.0e912fc3.js new file mode 100644 index 000000000..6f591d1df --- /dev/null +++ b/assets/js/8306354c.0e912fc3.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/0.4.0/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/0.4.0/detectors/OptimalMathFunction"},next:{title:"PreferredStdlibApi",permalink:"/tools/misti/docs/0.4.0/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/8685a76e.8943dfe3.js b/assets/js/8685a76e.8943dfe3.js new file mode 100644 index 000000000..19c695218 --- /dev/null +++ b/assets/js/8685a76e.8943dfe3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3583],{3950:(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.5/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.5/hacking/souffle.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"Design Overview",permalink:"/tools/misti/docs/hacking/design"},next:{title:"Contributing",permalink:"/tools/misti/docs/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<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/86d22c3d.7c8fbb6b.js b/assets/js/86d22c3d.7c8fbb6b.js new file mode 100644 index 000000000..d290eb76c --- /dev/null +++ b/assets/js/86d22c3d.7c8fbb6b.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.5","label":"0.5","banner":null,"badge":true,"noIndex":false,"className":"docs-version-0.5","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":"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/detectors","docId":"detectors","unlisted":false},{"type":"category","label":"Built-in 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":"CellOverflow","href":"/tools/misti/docs/detectors/CellOverflow","docId":"detectors/CellOverflow","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":"SendInLoop","href":"/tools/misti/docs/detectors/SendInLoop","docId":"detectors/SendInLoop","unlisted":false},{"type":"link","label":"StringReceiversOverlap","href":"/tools/misti/docs/detectors/StringReceiversOverlap","docId":"detectors/StringReceiversOverlap","unlisted":false},{"type":"link","label":"SuspiciousMessageMode","href":"/tools/misti/docs/detectors/SuspiciousMessageMode","docId":"detectors/SuspiciousMessageMode","unlisted":false},{"type":"link","label":"UnboundLoop","href":"/tools/misti/docs/detectors/UnboundLoop","docId":"detectors/UnboundLoop","unlisted":false},{"type":"link","label":"UnboundMap","href":"/tools/misti/docs/detectors/UnboundMap","docId":"detectors/UnboundMap","unlisted":false},{"type":"link","label":"UnusedExpressionResult","href":"/tools/misti/docs/detectors/UnusedExpressionResult","docId":"detectors/UnusedExpressionResult","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":"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/tools","docId":"tools","unlisted":false},{"type":"category","label":"Built-in 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},{"type":"link","label":"DumpImports","href":"/tools/misti/docs/tools/DumpImports","docId":"tools/DumpImports","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/hacking/design","docId":"hacking/design","unlisted":false},{"type":"link","label":"Souffl\xe9","href":"/tools/misti/docs/hacking/souffle","docId":"hacking/souffle","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}],"collapsed":true,"collapsible":true},{"type":"link","label":"Writing Custom Detectors","href":"/tools/misti/docs/hacking/custom-detector","docId":"hacking/custom-detector","unlisted":false}]},"docs":{"detectors":{"id":"detectors","title":"Detectors Overview","description":"Built-in Detectors","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/CellOverflow":{"id":"detectors/CellOverflow","title":"CellOverflow","description":"A detector that identifies cell overflow problems.","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/SendInLoop":{"id":"detectors/SendInLoop","title":"SendInLoop","description":"An optional detector that identifies send functions being called inside loops.","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/SuspiciousMessageMode":{"id":"detectors/SuspiciousMessageMode","title":"SuspiciousMessageMode","description":"Detects suspicious usage of the mode field in SendParameters struct instances.","sidebar":"sidebar"},"detectors/UnboundLoop":{"id":"detectors/UnboundLoop","title":"UnboundLoop","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/UnboundMap":{"id":"detectors/UnboundMap","title":"UnboundMap","description":"An optional detector that highlights cases where a map field allows inserting","sidebar":"sidebar"},"detectors/UnusedExpressionResult":{"id":"detectors/UnusedExpressionResult","title":"UnusedExpressionResult","description":"A detector that identifies expression statements whose result is unused.","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"},"tools/DumpImports":{"id":"tools/DumpImports","title":"DumpImports","description":"Misti provides a feature to dump the Import Graph of your Tact code in JSON, DOT, and Mermaid formats. This tool helps you understand the dependencies between different files and modules in your project, including how contracts import each other and use the standard library.","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":"CLI Options","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/888071ca.8652ec85.js b/assets/js/888071ca.8652ec85.js new file mode 100644 index 000000000..3b017ad60 --- /dev/null +++ b/assets/js/888071ca.8652ec85.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9187],{903:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>r,default:()=>p,frontMatter:()=>s,metadata:()=>c,toc:()=>d});var i=n(4848),o=n(8453);const s={},r="ShortCircuitCondition",c={id:"detectors/ShortCircuitCondition",title:"ShortCircuitCondition",description:"A detector that suggests optimizing boolean expressions to leverage short-circuit evaluation.",source:"@site/docs/detectors/ShortCircuitCondition.md",sourceDirName:"detectors",slug:"/detectors/ShortCircuitCondition",permalink:"/tools/misti/docs/next/detectors/ShortCircuitCondition",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/ShortCircuitCondition.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"SendInLoop",permalink:"/tools/misti/docs/next/detectors/SendInLoop"},next:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/next/detectors/StringReceiversOverlap"}},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,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h1,{id:"shortcircuitcondition",children:"ShortCircuitCondition"}),"\n",(0,i.jsx)(t.p,{children:"A detector that suggests optimizing boolean expressions to leverage short-circuit evaluation."}),"\n",(0,i.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,i.jsxs)(t.p,{children:["TVM supports short-circuit operations. When using logical AND (",(0,i.jsx)(t.code,{children:"&&"}),") or logical OR (",(0,i.jsx)(t.code,{children:"||"}),") operations,\nplacing constant or cheaper conditions first can prevent unnecessary execution\nof expensive operations when the result is already determined."]}),"\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:"// Bad: Expensive operation is always executed\nif (expensive_function() && constant_false) {\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:"// Good: Expensive operation is skipped when constant_false is false\nif (constant_false && expensive_function()) {\n // ...\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:()=>c});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 c(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/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.f6ea35a1.js b/assets/js/8e426e62.f6ea35a1.js new file mode 100644 index 000000000..7cdd95dd7 --- /dev/null +++ b/assets/js/8e426e62.f6ea35a1.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/0.4.0/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/0.4.0/detectors/DivideBeforeMultiply"},next:{title:"DuplicatedCondition",permalink:"/tools/misti/docs/0.4.0/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/9016a10e.f412061d.js b/assets/js/9016a10e.f412061d.js new file mode 100644 index 000000000..8ee2e58a3 --- /dev/null +++ b/assets/js/9016a10e.f412061d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2906],{7216:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>r,default:()=>l,frontMatter:()=>i,metadata:()=>d,toc:()=>c});var s=n(4848),o=n(8453);const i={},r="UnusedExpressionResult",d={id:"detectors/UnusedExpressionResult",title:"UnusedExpressionResult",description:"A detector that identifies expression statements whose result is unused.",source:"@site/docs/detectors/UnusedExpressionResult.md",sourceDirName:"detectors",slug:"/detectors/UnusedExpressionResult",permalink:"/tools/misti/docs/next/detectors/UnusedExpressionResult",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/UnusedExpressionResult.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"UnboundMap",permalink:"/tools/misti/docs/next/detectors/UnboundMap"},next:{title:"UnusedOptional",permalink:"/tools/misti/docs/next/detectors/UnusedOptional"}},a={},c=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2}];function u(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:"unusedexpressionresult",children:"UnusedExpressionResult"}),"\n",(0,s.jsx)(t.p,{children:"A detector that identifies expression statements whose result is unused."}),"\n",(0,s.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,s.jsx)(t.p,{children:"Expression statements that don't alter the contract's state and whose results are not used\ncan lead to inefficiency, dead code, and potential confusion. They add unnecessary complexity\nwithout contributing to the logic or state of the 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:"self.foo == 3; // Warning: unused boolean expression\ninc(a); // Warning: unused return value\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:"self.foo = 3; // Fixed: corrected assignment\nnewValue = inc(a); // OK: result is now used\nlet _ = inc(a); // OK: explicitly ignored\n"})})]})}function l(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(u,{...e})}):u(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>d});var s=n(6540);const o={},i=s.createContext(o);function r(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(o):e.components||o:r(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9081c3e5.771bfadf.js b/assets/js/9081c3e5.771bfadf.js new file mode 100644 index 000000000..354bf47b8 --- /dev/null +++ b/assets/js/9081c3e5.771bfadf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6805],{1445:(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.5/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.5/detectors/PreferredStdlibApi.md",tags:[],version:"0.5",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/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.e9b6829a.js b/assets/js/91acf703.e9b6829a.js new file mode 100644 index 000000000..d84c339c8 --- /dev/null +++ b/assets/js/91acf703.e9b6829a.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/0.4.0/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/0.4.0/detectors/UnusedOptional"},next:{title:"Tools Overview",permalink:"/tools/misti/docs/0.4.0/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/926d5e8d.9358cd7a.js b/assets/js/926d5e8d.9358cd7a.js new file mode 100644 index 000000000..7a9cd697e --- /dev/null +++ b/assets/js/926d5e8d.9358cd7a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2526],{2737:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>d,default:()=>p,frontMatter:()=>i,metadata:()=>r,toc:()=>a});var o=t(4848),s=t(8453);const i={},d="SendInLoop",r={id:"detectors/SendInLoop",title:"SendInLoop",description:"An optional detector that identifies send functions being called inside loops.",source:"@site/versioned_docs/version-0.5/detectors/SendInLoop.md",sourceDirName:"detectors",slug:"/detectors/SendInLoop",permalink:"/tools/misti/docs/detectors/SendInLoop",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.5/detectors/SendInLoop.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/detectors/ReadOnlyVariables"},next:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/detectors/StringReceiversOverlap"}},c={},a=[{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,s.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"sendinloop",children:"SendInLoop"}),"\n",(0,o.jsx)(n.p,{children:"An optional detector that identifies send functions being called inside loops."}),"\n",(0,o.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsx)(n.p,{children:"Calling send functions inside loops can lead to unintended consequences, such as\nexcessive message sending, increased gas consumption, and potential race conditions.\nLoops with send calls should be refactored to avoid these issues. This detector helps\nflag such code, prompting the developer to reconsider the design."}),"\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:"fun exampleWhileLoop(limit: Int, owner: Address) {\n let i = 0;\n while (i < limit) {\n send(SendParameters{ // Highlighted: An auditor should review the loop\n to: owner,\n value: 0,\n bounce: false,\n body: Msg{ a: i }.toCell()\n });\n i += 1;\n }\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:()=>d,x:()=>r});var o=t(6540);const s={},i=o.createContext(s);function d(e){const n=o.useContext(i);return o.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:d(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/94d07e36.7f27f910.js b/assets/js/94d07e36.7f27f910.js new file mode 100644 index 000000000..6db9b0258 --- /dev/null +++ b/assets/js/94d07e36.7f27f910.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/0.4.0/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/0.4.0/detectors/DuplicatedCondition"},next:{title:"FalseCondition",permalink:"/tools/misti/docs/0.4.0/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/9983337e.ea12e3f1.js b/assets/js/9983337e.ea12e3f1.js new file mode 100644 index 000000000..e0575f1aa --- /dev/null +++ b/assets/js/9983337e.ea12e3f1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[3320],{1337:(e,s,n)=>{n.r(s),n.d(s,{assets:()=>d,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>a});var t=n(4848),i=n(8453);const o={},r="SuspiciousMessageMode",c={id:"detectors/SuspiciousMessageMode",title:"SuspiciousMessageMode",description:"Detects suspicious usage of the mode field in SendParameters struct instances.",source:"@site/versioned_docs/version-0.5/detectors/SuspiciousMessageMode.md",sourceDirName:"detectors",slug:"/detectors/SuspiciousMessageMode",permalink:"/tools/misti/docs/detectors/SuspiciousMessageMode",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.5/detectors/SuspiciousMessageMode.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"StringReceiversOverlap",permalink:"/tools/misti/docs/detectors/StringReceiversOverlap"},next:{title:"UnboundLoop",permalink:"/tools/misti/docs/detectors/UnboundLoop"}},d={},a=[{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",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(s.h1,{id:"suspiciousmessagemode",children:"SuspiciousMessageMode"}),"\n",(0,t.jsxs)(s.p,{children:["Detects suspicious usage of the ",(0,t.jsx)(s.code,{children:"mode"})," field in ",(0,t.jsx)(s.code,{children:"SendParameters"})," struct instances."]}),"\n",(0,t.jsx)(s.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,t.jsxs)(s.p,{children:["Incorrect usage of the ",(0,t.jsx)(s.code,{children:"mode"})," field in ",(0,t.jsx)(s.code,{children:"SendParameters"})," can lead to unintended behavior when sending messages,\nsuch as incorrect flags being set, which can cause security vulnerabilities or unexpected contract behavior."]}),"\n",(0,t.jsx)(s.p,{children:(0,t.jsx)(s.strong,{children:"What it checks:"})}),"\n",(0,t.jsxs)(s.ul,{children:["\n",(0,t.jsxs)(s.li,{children:["Ensures that the ",(0,t.jsx)(s.code,{children:"mode"})," expression only uses the bitwise OR operator ",(0,t.jsx)(s.code,{children:"|"}),"."]}),"\n",(0,t.jsx)(s.li,{children:"Warns if integer literals are used instead of symbolic constants."}),"\n",(0,t.jsxs)(s.li,{children:["Warns if the same flag is used multiple times in the ",(0,t.jsx)(s.code,{children:"mode"})," expression."]}),"\n"]}),"\n",(0,t.jsx)(s.h2,{id:"example",children:"Example"}),"\n",(0,t.jsx)(s.pre,{children:(0,t.jsx)(s.code,{className:"language-tact",children:"// Suspicious usage:\nsend(SendParameters{\n to: recipient,\n value: amount,\n mode: SendRemainingBalance | SendRemainingBalance // Bad: Duplicate flag\n});\n\n// Correct usage:\nsend(SendParameters{\n to: recipient,\n value: amount,\n mode: SendRemainingBalance | SendDestroyIfZero // Ok\n});\n"})})]})}function u(e={}){const{wrapper:s}={...(0,i.R)(),...e.components};return s?(0,t.jsx)(s,{...e,children:(0,t.jsx)(l,{...e})}):l(e)}},8453:(e,s,n)=>{n.d(s,{R:()=>r,x:()=>c});var t=n(6540);const i={},o=t.createContext(i);function r(e){const s=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function c(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),t.createElement(o.Provider,{value:s},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.f1235972.js b/assets/js/a291c19d.f1235972.js new file mode 100644 index 000000000..49d81f028 --- /dev/null +++ b/assets/js/a291c19d.f1235972.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/0.4.0/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/0.4.0/detectors/FieldDoubleInit"},next:{title:"NeverAccessedVariables",permalink:"/tools/misti/docs/0.4.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/a2e1ac23.ed8d2af3.js b/assets/js/a2e1ac23.ed8d2af3.js new file mode 100644 index 000000000..bd3af6552 --- /dev/null +++ b/assets/js/a2e1ac23.ed8d2af3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9977],{1682:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>u,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var o=t(4848),s=t(8453);const i={},r="UnboundLoop",a={id:"detectors/UnboundLoop",title:"UnboundLoop",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/docs/detectors/UnboundLoop.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoop",permalink:"/tools/misti/docs/next/detectors/UnboundLoop",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/UnboundLoop.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"SuspiciousMessageMode",permalink:"/tools/misti/docs/next/detectors/SuspiciousMessageMode"},next:{title:"UnboundMap",permalink:"/tools/misti/docs/next/detectors/UnboundMap"}},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:"unboundloop",children:"UnboundLoop"}),"\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 u(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/a3df6930.3fd81736.js b/assets/js/a3df6930.3fd81736.js new file mode 100644 index 000000000..33d36ea75 --- /dev/null +++ b/assets/js/a3df6930.3fd81736.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/0.4.0/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/0.4.0/"},next:{title:"CI/CD Integration",permalink:"/tools/misti/docs/0.4.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.4.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/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.d691b43f.js b/assets/js/a5055d90.d691b43f.js new file mode 100644 index 000000000..0f8483250 --- /dev/null +++ b/assets/js/a5055d90.d691b43f.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:"DumpImports",permalink:"/tools/misti/docs/next/tools/DumpImports"},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/ab64460a.f029dca5.js b/assets/js/ab64460a.f029dca5.js new file mode 100644 index 000000000..8ee47c194 --- /dev/null +++ b/assets/js/ab64460a.f029dca5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[2467],{6083:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>u,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var t=o(4848),s=o(8453);const i={},r="UnboundLoop",a={id:"detectors/UnboundLoop",title:"UnboundLoop",description:"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.",source:"@site/versioned_docs/version-0.5/detectors/UnboundLoop.md",sourceDirName:"detectors",slug:"/detectors/UnboundLoop",permalink:"/tools/misti/docs/detectors/UnboundLoop",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/versioned_docs/version-0.5/detectors/UnboundLoop.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"SuspiciousMessageMode",permalink:"/tools/misti/docs/detectors/SuspiciousMessageMode"},next:{title:"UnboundMap",permalink:"/tools/misti/docs/detectors/UnboundMap"}},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,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"unboundloop",children:"UnboundLoop"}),"\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.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Unexpected Behavior:"})," Without a defined termination, loops can lead to unpredictable contract behavior and make debugging difficult."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Out-of-gas Attacks:"})," Continuous looping without termination can lead to out-of-gas attacks."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.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,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 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,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/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.034e2877.js b/assets/js/aee0b8cc.034e2877.js new file mode 100644 index 000000000..a83a0f1dc --- /dev/null +++ b/assets/js/aee0b8cc.034e2877.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/0.4.0/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/0.4.0/tools"},next:{title:"DumpCfg",permalink:"/tools/misti/docs/0.4.0/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/0.4.0/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/b2b6aa30.3aa9416e.js b/assets/js/b2b6aa30.3aa9416e.js new file mode 100644 index 000000000..ffb7819c2 --- /dev/null +++ b/assets/js/b2b6aa30.3aa9416e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6216],{7828:(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.5/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.5/detectors/OptimalMathFunction.md",tags:[],version:"0.5",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/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.f5677375.js b/assets/js/b64540ae.f5677375.js new file mode 100644 index 000000000..0e288ff2a --- /dev/null +++ b/assets/js/b64540ae.f5677375.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6412],{8560:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var i=s(4848),t=s(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 Warnings",id:"suppressing-warnings",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,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,i.jsx)(n.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,i.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsx)(n.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Git"}),"\n",(0,i.jsx)(n.li,{children:"Yarn"}),"\n",(0,i.jsx)(n.li,{children:"Node.js version 22 or higher"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"npm install -g @nowarp/misti\n"})}),"\n",(0,i.jsx)(n.h3,{id:"using-development-version",children:"Using Development Version"}),"\n",(0,i.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,i.jsx)(n.p,{children:"To install the latest development version you should:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["Clone Misti: ",(0,i.jsx)(n.code,{children:"git clone https://github.com/nowarp/misti"})]}),"\n",(0,i.jsxs)(n.li,{children:["Build it: ",(0,i.jsx)(n.code,{children:"cd misti && yarn install && yarn build"})]}),"\n",(0,i.jsxs)(n.li,{children:["Use it in your Tact project: ",(0,i.jsx)(n.code,{children:"cd /path/to/tact/project && yarn add file:/path/to/misti"})]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,i.jsx)(n.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"misti path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(n.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,i.jsxs)(n.p,{children:["You can also add a script to your ",(0,i.jsx)(n.code,{children:"package.json"})," to simplify running the linting process:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-json",children:'{\n "scripts": {\n "lint": "misti path/to/tact.config.json"\n }\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"more-usage-examples",children:"More usage examples"}),"\n",(0,i.jsxs)(n.p,{children:["Below are a few usage examples for common scenarios when using ",(0,i.jsxs)(n.a,{href:"/tools/misti/docs/next/tutorial/cli",children:["the ",(0,i.jsx)(n.code,{children:"misti"})," CLI"]}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"suppressing-warnings",children:"Suppressing Warnings"}),"\n",(0,i.jsxs)(n.p,{children:["If you want to suppress some warnings in specific places of source code, you should use the ",(0,i.jsx)(n.code,{children:"@misti:suppress"})," annotations in the comment on the previous line, for example:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"fun test(): Int {\n // @misti:suppress NeverAccessedVariables\n let sum: Int = 0; // OK: The warning will be suppressed\n return 52;\n}\n"})}),"\n",(0,i.jsx)(n.p,{children:"This syntax also enables you to list a few detectors to be suppressed, including the custom ones, for example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"// @misti:suppress NeverAccessedVariables,MyCustomDetector,ReadOnlyVariables\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Alternatively, you could run ",(0,i.jsx)(n.code,{children:"misti"})," while entirely suppressing specific detectors:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"misti --suppress ReadOnlyVariables path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(n.h3,{id:"enabling-all-detectors",children:"Enabling All Detectors"}),"\n",(0,i.jsxs)(n.p,{children:["Running ",(0,i.jsx)(n.code,{children:"misti"})," with all available built-in detectors enabled:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"misti --all-detectors path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(n.p,{children:"It is recommended to do that when auditing the project."}),"\n",(0,i.jsx)(n.h3,{id:"running-in-quiet-mode",children:"Running in Quiet Mode"}),"\n",(0,i.jsxs)(n.p,{children:["To suppress all output while running ",(0,i.jsx)(n.code,{children:"misti"})," getting just a return code:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"misti --quiet path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(n.p,{children:"This might be useful in scripts and CI/CD."}),"\n",(0,i.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsxs)(n.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,i.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,i.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,n,s)=>{s.d(n,{R:()=>r,x:()=>o});var i=s(6540);const t={},l=i.createContext(t);function r(e){const n=i.useContext(l);return i.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(t):e.components||t:r(e.components),i.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/b64aaedd.0b438287.js b/assets/js/b64aaedd.0b438287.js new file mode 100644 index 000000000..5844a13c7 --- /dev/null +++ b/assets/js/b64aaedd.0b438287.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/0.4.0/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/0.4.0/detectors/EnsurePrgSeed"},next:{title:"FieldDoubleInit",permalink:"/tools/misti/docs/0.4.0/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/b9de2907.1fc2ebe1.js b/assets/js/b9de2907.1fc2ebe1.js new file mode 100644 index 000000000..8feb97e21 --- /dev/null +++ b/assets/js/b9de2907.1fc2ebe1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[4913],{5144:(e,t,i)=>{i.r(t),i.d(t,{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.5/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.5/tutorial/blueprint.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/tools/misti/docs/tutorial/configuration"},next:{title:"Overview",permalink:"/tools/misti/docs/detectors"}},a={},c=[{value:"Getting Started",id:"getting-started",level:2},{value:"Usage",id:"usage",level:2}];function d(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h1,{id:"using-misti-with-blueprint",children:"Using Misti with Blueprint"}),"\n",(0,n.jsxs)(t.p,{children:[(0,n.jsx)(t.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)(t.p,{children:["There is a ",(0,n.jsx)(t.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)(t.code,{children:"blueprint misti"})," command, which runs the static analyzer over the selected Blueprint project."]}),"\n",(0,n.jsx)(t.p,{children:"This page describes how to use it."}),"\n",(0,n.jsx)(t.h2,{id:"getting-started",children:"Getting Started"}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsxs)(t.p,{children:[(0,n.jsx)(t.a,{href:"https://souffle-lang.github.io/install",children:"Install Souffl\xe9"})," to use all detectors provided by Misti."]}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Add this plugin as a dependency of your Blueprint project:"}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"yarn add @nowarp/blueprint-misti\n"})}),"\n",(0,n.jsxs)(t.ol,{start:"3",children:["\n",(0,n.jsxs)(t.li,{children:["Add this configuration to ",(0,n.jsx)(t.code,{children:"blueprint.config.ts"}),":"]}),"\n"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.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)(t.h2,{id:"usage",children:"Usage"}),"\n",(0,n.jsx)(t.p,{children:"Run the following command:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"yarn blueprint misti\n"})}),"\n",(0,n.jsx)(t.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)(t.p,{children:(0,n.jsx)(t.img,{alt:"img",src:i(1547).A+"",width:"493",height:"96"})}),"\n",(0,n.jsxs)(t.p,{children:["You could also pass the ",(0,n.jsx)(t.a,{href:"/tools/misti/docs/tutorial/cli",children:"supported CLI options"})," for Misti, for example:"]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"yarn blueprint misti --all-detectors\n"})}),"\n",(0,n.jsx)(t.p,{children:"Or you can even pass the path to the contract directly:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-bash",children:"yarn blueprint misti path/to/my/contract.tact\n"})}),"\n",(0,n.jsxs)(t.p,{children:["If you have any problems, feel free to reach out to us in the ",(0,n.jsx)(t.a,{href:"https://t.me/misti_dev",children:"Misti discussion group"}),"."]})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},1547:(e,t,i)=>{i.d(t,{A:()=>n});const n=i.p+"assets/images/blueprint-select-project-b8656fa4266c0c7923d6b67c7f5950e6.png"},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/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/be04c9f2.c6a1b800.js b/assets/js/be04c9f2.c6a1b800.js new file mode 100644 index 000000000..389718122 --- /dev/null +++ b/assets/js/be04c9f2.c6a1b800.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[44],{2322:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>d,default:()=>p,frontMatter:()=>s,metadata:()=>r,toc:()=>a});var o=t(4848),i=t(8453);const s={},d="SendInLoop",r={id:"detectors/SendInLoop",title:"SendInLoop",description:"An optional detector that identifies send functions being called inside loops.",source:"@site/docs/detectors/SendInLoop.md",sourceDirName:"detectors",slug:"/detectors/SendInLoop",permalink:"/tools/misti/docs/next/detectors/SendInLoop",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/SendInLoop.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"ReadOnlyVariables",permalink:"/tools/misti/docs/next/detectors/ReadOnlyVariables"},next:{title:"ShortCircuitCondition",permalink:"/tools/misti/docs/next/detectors/ShortCircuitCondition"}},c={},a=[{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,i.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"sendinloop",children:"SendInLoop"}),"\n",(0,o.jsx)(n.p,{children:"An optional detector that identifies send functions being called inside loops."}),"\n",(0,o.jsx)(n.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,o.jsx)(n.p,{children:"Calling send functions inside loops can lead to unintended consequences, such as\nexcessive message sending, increased gas consumption, and potential race conditions.\nLoops with send calls should be refactored to avoid these issues. This detector helps\nflag such code, prompting the developer to reconsider the design."}),"\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:"fun exampleWhileLoop(limit: Int, owner: Address) {\n let i = 0;\n while (i < limit) {\n send(SendParameters{ // Highlighted: An auditor should review the loop\n to: owner,\n value: 0,\n bounce: false,\n body: Msg{ a: i }.toCell()\n });\n i += 1;\n }\n}\n"})})]})}function p(e={}){const{wrapper:n}={...(0,i.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:()=>d,x:()=>r});var o=t(6540);const i={},s=o.createContext(i);function d(e){const n=o.useContext(s);return o.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(i):e.components||i:d(e.components),o.createElement(s.Provider,{value:n},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/c2845dc0.24f1aeb0.js b/assets/js/c2845dc0.24f1aeb0.js new file mode 100644 index 000000000..eda412e49 --- /dev/null +++ b/assets/js/c2845dc0.24f1aeb0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5378],{830:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>a,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>c,toc:()=>d});var n=r(4848),s=r(8453);const i={},o="StringReceiversOverlap",c={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.5/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.5/detectors/StringReceiversOverlap.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"SendInLoop",permalink:"/tools/misti/docs/detectors/SendInLoop"},next:{title:"SuspiciousMessageMode",permalink:"/tools/misti/docs/detectors/SuspiciousMessageMode"}},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:()=>o,x:()=>c});var n=r(6540);const s={},i=n.createContext(s);function o(e){const t=n.useContext(i);return n.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(s):e.components||s:o(e.components),n.createElement(i.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/c734b99d.c559e4ef.js b/assets/js/c734b99d.c559e4ef.js new file mode 100644 index 000000000..2c099cd8c --- /dev/null +++ b/assets/js/c734b99d.c559e4ef.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[872],{8956:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>u,frontMatter:()=>o,metadata:()=>r,toc:()=>l});var s=n(4848),i=n(8453);const o={},a="UnusedOptional",r={id:"detectors/UnusedOptional",title:"UnusedOptional",description:"A detector variables and fields with unused optional modifier.",source:"@site/versioned_docs/version-0.5/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.5/detectors/UnusedOptional.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"UnusedExpressionResult",permalink:"/tools/misti/docs/detectors/UnusedExpressionResult"},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 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:"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,i.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 i={},o=s.createContext(i);function a(e){const t=s.useContext(o);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(i):e.components||i:a(e.components),s.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c7ee6afe.d82db54e.js b/assets/js/c7ee6afe.d82db54e.js new file mode 100644 index 000000000..13c2384fe --- /dev/null +++ b/assets/js/c7ee6afe.d82db54e.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/0.4.0/",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/0.4.0/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.388e1126.js b/assets/js/c82192ae.388e1126.js new file mode 100644 index 000000000..82d252f93 --- /dev/null +++ b/assets/js/c82192ae.388e1126.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/0.4.0/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/0.4.0/tutorial/blueprint"},next:{title:"ArgCopyMutation",permalink:"/tools/misti/docs/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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/0.4.0/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.7b0b1178.js b/assets/js/cf2c24d9.7b0b1178.js new file mode 100644 index 000000000..3948125ce --- /dev/null +++ b/assets/js/cf2c24d9.7b0b1178.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/0.4.0/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/0.4.0/detectors/StringReceiversOverlap"},next:{title:"UnusedOptional",permalink:"/tools/misti/docs/0.4.0/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.9f26dd12.js b/assets/js/d2f295f4.9f26dd12.js new file mode 100644 index 000000000..237f62e8c --- /dev/null +++ b/assets/js/d2f295f4.9f26dd12.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:'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:'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:'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:'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:'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.2fcfc32a.js b/assets/js/d3996cd7.2fcfc32a.js new file mode 100644 index 000000000..e2d52cd68 --- /dev/null +++ b/assets/js/d3996cd7.2fcfc32a.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:'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:'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.2f60268c.js b/assets/js/d7c99f30.2f60268c.js new file mode 100644 index 000000000..2f721f3bb --- /dev/null +++ b/assets/js/d7c99f30.2f60268c.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/0.4.0/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/0.4.0/detectors/NeverAccessedVariables"},next:{title:"PreferAugmentedAssign",permalink:"/tools/misti/docs/0.4.0/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/d7ebd85b.81f998f6.js b/assets/js/d7ebd85b.81f998f6.js new file mode 100644 index 000000000..bf5d92ed2 --- /dev/null +++ b/assets/js/d7ebd85b.81f998f6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5308],{6659:(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"},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.5/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.5/tools.md",tags:[],version:"0.5",frontMatter:{id:"tools",title:"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:"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:'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:'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:'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"})]}),(0,o.jsxs)(s.tr,{children:[(0,o.jsx)(s.td,{children:"4"}),(0,o.jsx)(s.td,{children:(0,o.jsx)(s.a,{href:"/tools/misti/docs/tools/DumpImports",children:"DumpImports"})}),(0,o.jsx)(s.td,{children:"Dumps the graph of imports"})]})]})]})]})}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/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/d9941f94.b1fb5e38.js b/assets/js/d9941f94.b1fb5e38.js new file mode 100644 index 000000000..84dcca808 --- /dev/null +++ b/assets/js/d9941f94.b1fb5e38.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8183],{7084:(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.5/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.5/tools/DumpCfg.md",tags:[],version:"0.5",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:'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:'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:'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:'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:'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/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.ffc63748.js b/assets/js/dd8730c9.ffc63748.js new file mode 100644 index 000000000..44b0ea848 --- /dev/null +++ b/assets/js/dd8730c9.ffc63748.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":"CellOverflow","href":"/tools/misti/docs/next/detectors/CellOverflow","docId":"detectors/CellOverflow","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":"SendInLoop","href":"/tools/misti/docs/next/detectors/SendInLoop","docId":"detectors/SendInLoop","unlisted":false},{"type":"link","label":"ShortCircuitCondition","href":"/tools/misti/docs/next/detectors/ShortCircuitCondition","docId":"detectors/ShortCircuitCondition","unlisted":false},{"type":"link","label":"StringReceiversOverlap","href":"/tools/misti/docs/next/detectors/StringReceiversOverlap","docId":"detectors/StringReceiversOverlap","unlisted":false},{"type":"link","label":"SuspiciousMessageMode","href":"/tools/misti/docs/next/detectors/SuspiciousMessageMode","docId":"detectors/SuspiciousMessageMode","unlisted":false},{"type":"link","label":"UnboundLoop","href":"/tools/misti/docs/next/detectors/UnboundLoop","docId":"detectors/UnboundLoop","unlisted":false},{"type":"link","label":"UnboundMap","href":"/tools/misti/docs/next/detectors/UnboundMap","docId":"detectors/UnboundMap","unlisted":false},{"type":"link","label":"UnusedExpressionResult","href":"/tools/misti/docs/next/detectors/UnusedExpressionResult","docId":"detectors/UnusedExpressionResult","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},{"type":"link","label":"DumpImports","href":"/tools/misti/docs/next/tools/DumpImports","docId":"tools/DumpImports","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":"Built-in Detectors","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/CellOverflow":{"id":"detectors/CellOverflow","title":"CellOverflow","description":"A detector that identifies cell overflow problems.","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/SendInLoop":{"id":"detectors/SendInLoop","title":"SendInLoop","description":"An optional detector that identifies send functions being called inside loops.","sidebar":"sidebar"},"detectors/ShortCircuitCondition":{"id":"detectors/ShortCircuitCondition","title":"ShortCircuitCondition","description":"A detector that suggests optimizing boolean expressions to leverage short-circuit evaluation.","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/SuspiciousMessageMode":{"id":"detectors/SuspiciousMessageMode","title":"SuspiciousMessageMode","description":"Detects suspicious usage of the mode field in SendParameters struct instances.","sidebar":"sidebar"},"detectors/UnboundLoop":{"id":"detectors/UnboundLoop","title":"UnboundLoop","description":"A detector that analyzes loop conditions and control flow to ensure loops have proper termination criteria.","sidebar":"sidebar"},"detectors/UnboundMap":{"id":"detectors/UnboundMap","title":"UnboundMap","description":"An optional detector that highlights cases where a map field allows inserting","sidebar":"sidebar"},"detectors/UnusedExpressionResult":{"id":"detectors/UnusedExpressionResult","title":"UnusedExpressionResult","description":"A detector that identifies expression statements whose result is unused.","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"},"tools/DumpImports":{"id":"tools/DumpImports","title":"DumpImports","description":"Misti provides a feature to dump the Import Graph of your Tact code in JSON, DOT, and Mermaid formats. This tool helps you understand the dependencies between different files and modules in your project, including how contracts import each other and use the standard library.","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":"CLI Options","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/dda96275.6e542222.js b/assets/js/dda96275.6e542222.js new file mode 100644 index 000000000..d054349cf --- /dev/null +++ b/assets/js/dda96275.6e542222.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[7193],{6924:(e,i,s)=>{s.r(i),s.d(i,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var n=s(4848),t=s(8453);const a={},o="Design Overview",l={id:"hacking/design",title:"Design Overview",description:"Static Analysis",source:"@site/versioned_docs/version-0.5/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.5/hacking/design.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpImports",permalink:"/tools/misti/docs/tools/DumpImports"},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,t.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(i.h1,{id:"design-overview",children:"Design Overview"}),"\n",(0,n.jsx)(i.h2,{id:"static-analysis",children:"Static Analysis"}),"\n",(0,n.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,n.jsx)(i.h2,{id:"souffle-datalog-solver",children:"Souffle Datalog Solver"}),"\n",(0,n.jsxs)(i.p,{children:["Misti leverages the ",(0,n.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,n.jsx)(i.h2,{id:"dataflow-analysis-in-misti",children:"Dataflow Analysis in Misti"}),"\n",(0,n.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,n.jsx)(i.h2,{id:"references",children:"References"}),"\n",(0,n.jsx)(i.p,{children:"For those interested in learning more about static analysis and dataflow analysis, the following books are recommended:"}),"\n",(0,n.jsxs)(i.ul,{children:["\n",(0,n.jsx)(i.li,{children:(0,n.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,n.jsx)(i.li,{children:"Uday Khedker et al. \u2013 Data Flow Analysis: Theory and Practice"}),"\n"]}),"\n",(0,n.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,n.jsx)(i,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},8453:(e,i,s)=>{s.d(i,{R:()=>o,x:()=>l});var n=s(6540);const t={},a=n.createContext(t);function o(e){const i=n.useContext(a);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(t):e.components||t:o(e.components),n.createElement(a.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/de7c269b.f7040048.js b/assets/js/de7c269b.f7040048.js new file mode 100644 index 000000000..5f7585c42 --- /dev/null +++ b/assets/js/de7c269b.f7040048.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6309],{5275:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>d});var r=s(4848),n=s(8453);const o={},l="CellOverflow",i={id:"detectors/CellOverflow",title:"CellOverflow",description:"A detector that identifies cell overflow problems.",source:"@site/docs/detectors/CellOverflow.md",sourceDirName:"detectors",slug:"/detectors/CellOverflow",permalink:"/tools/misti/docs/next/detectors/CellOverflow",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/detectors/CellOverflow.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"BranchDuplicate",permalink:"/tools/misti/docs/next/detectors/BranchDuplicate"},next:{title:"ConstantAddress",permalink:"/tools/misti/docs/next/detectors/ConstantAddress"}},c={},d=[{value:"Why is it bad?",id:"why-is-it-bad",level:2},{value:"Example",id:"example",level:2},{value:"Resources",id:"resources",level:2}];function a(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",...(0,n.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.h1,{id:"celloverflow",children:"CellOverflow"}),"\n",(0,r.jsx)(t.p,{children:"A detector that identifies cell overflow problems."}),"\n",(0,r.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,r.jsx)(t.p,{children:"Cell overflow is an issue specific to the TON blockchain. TON stores data in\ncells, which are low-level data structures used for serialization and deserialization."}),"\n",(0,r.jsxs)(t.p,{children:["The overflow issue occurs when the user attempts to store more data in a cell\nthan it supports. The current limitation is 1023 bits and 4 references to other\ncells. When these limits are exceeded, the contract throws an error with the\nexit code ",(0,r.jsx)(t.code,{children:"8"})," during the compute phase."]}),"\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:"// Bad: storeRef is used more than 4 times\nbeginCell()\n .storeRef(...)\n .storeAddress(myAddress())\n .storeRef(...)\n .storeRef(...)\n .storeRef(...)\n .storeRef(...)\n .endCell()\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:"// OK: Fixed after the analyzer highlighted it\nbeginCell()\n .storeRef(...)\n .storeAddress(myAddress())\n .storeRef(...)\n .storeRef(...)\n .storeRef(...)\n .endCell()\n"})}),"\n",(0,r.jsx)(t.h2,{id:"resources",children:"Resources"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://docs.ton.org/develop/data-formats/cell-boc",children:"Cell & Bag of Cells (BoC) | TON Docs"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://docs.ton.org/learn/tvm-instructions/tvm-exit-codes",children:"TVM Exit codes | TON Docs"})}),"\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://docs.tact-lang.org/ref/core-cells/",children:"Cells, Builders and Slices | Tact Docs"})}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,n.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>l,x:()=>i});var r=s(6540);const n={},o=r.createContext(n);function l(e){const t=r.useContext(o);return r.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(n):e.components||n:l(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/df3f8a78.19c23fa7.js b/assets/js/df3f8a78.19c23fa7.js new file mode 100644 index 000000000..a0e45ed08 --- /dev/null +++ b/assets/js/df3f8a78.19c23fa7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[6474],{9633:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var s=i(4848),t=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.5/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.5/tutorial/configuration.md",tags:[],version:"0.5",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:"Environment Variables",id:"environment-variables",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const n={a:"a",br:"br",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"configuration",children:"Configuration"}),"\n",(0,s.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,s.jsx)(n.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"detectors"})," (array of objects, optional): List of detectors to run. Each detector can be specified with a ",(0,s.jsx)(n.code,{children:"className"})," and optionally a ",(0,s.jsx)(n.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"modulePath"})," (string, optional): The file path of the detector module if it's a custom implementation."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"tools"})," (array of objects, optional): List of tools to enable, each with its own configuration."]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"className"})," (string, required): The class name of the tool."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"options"})," (object, optional): Key-value configuration options for the tool."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"suppressions"})," (array of objects, optional): A list of suppressions for warnings."]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"detector"})," (string, required): The detector to suppress warnings for."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"position"})," (string, required): The position in the code where the warning should be suppressed."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"ignoredProjects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.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,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.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,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.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,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.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,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"verbosity"}),' (string, optional, default: "default"): Verbosity level of the logs. Possible values are ',(0,s.jsx)(n.code,{children:"quiet"}),", ",(0,s.jsx)(n.code,{children:"debug"}),", and ",(0,s.jsx)(n.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,s.jsx)(n.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,s.jsx)(n.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,s.jsx)(n.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,s.jsx)(n.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.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,s.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,s.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,s.jsx)(n.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"misti --dump-config path/to/your/tact.config.json\n"})}),"\n",(0,s.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,s.jsx)(n.h2,{id:"environment-variables",children:"Environment Variables"}),"\n",(0,s.jsx)(n.p,{children:"Misti offers advanced configuration through environment variables to control specific options."}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:(0,s.jsx)(n.code,{children:"MISTI_TIMEOUT"})}),(0,s.jsx)(n.br,{}),"\n","Sets the timeout for detector execution in milliseconds.",(0,s.jsx)(n.br,{}),"\n",(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"15000"}),(0,s.jsx)(n.br,{}),"\n",(0,s.jsx)(n.strong,{children:"Example"}),":","\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"export MISTI_TIMEOUT=20000\n"})}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:(0,s.jsx)(n.code,{children:"MISTI_TRACE"})}),(0,s.jsx)(n.br,{}),"\n","Enables tracing of the execution. Set to ",(0,s.jsx)(n.code,{children:"1"})," to enable tracing, otherwise it is disabled.",(0,s.jsx)(n.br,{}),"\n",(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"false"}),(0,s.jsx)(n.br,{}),"\n",(0,s.jsx)(n.strong,{children:"Example"}),":","\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"export MISTI_TRACE=1\n"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,s.jsxs)(n.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,s.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,s.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>l});var s=i(6540);const t={},o=s.createContext(t);function r(e){const n=s.useContext(o);return s.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(t):e.components||t:r(e.components),s.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e0636556.3ece1612.js b/assets/js/e0636556.3ece1612.js new file mode 100644 index 000000000..053558dd2 --- /dev/null +++ b/assets/js/e0636556.3ece1612.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8047],{3944:(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.5/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.5/index.md",tags:[],version:"0.5",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/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.f50ac3b9.js b/assets/js/e3b47995.f50ac3b9.js new file mode 100644 index 000000000..ce57749e4 --- /dev/null +++ b/assets/js/e3b47995.f50ac3b9.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:()=>l});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:"CellOverflow",permalink:"/tools/misti/docs/next/detectors/CellOverflow"}},o={},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",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)(d,{...e})}):d(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.190cf370.js b/assets/js/e4a43c7d.190cf370.js new file mode 100644 index 000000000..357b23580 --- /dev/null +++ b/assets/js/e4a43c7d.190cf370.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",heroTitle:"heroTitle_zNcP",heroSubtitle:"heroSubtitle_NX3L",heroSubtitleSmall:"heroSubtitleSmall_wW8f",textContainer:"textContainer_y9OC",buttons:"buttons_YgGx",sectionPadding:"sectionPadding_JTui",featureBox:"featureBox_C4l2",rowWithMargin:"rowWithMargin_rNqB",centerButton:"centerButton_N5e1",featuresTitle:"featuresTitle_elEa"};var c=t(5604),a=t(4848);function o(){return(0,a.jsxs)(i.A,{title:"Welcome to Misti",description:"The TON Static Analyzer",children:[(0,a.jsx)("header",{className:r.heroBanner,children:(0,a.jsxs)("div",{className:r.textContainer,children:[(0,a.jsx)("h1",{className:r.heroTitle,children:"Misti"}),(0,a.jsx)("p",{className:r.heroSubtitle,children:"TON Security Tool"}),(0,a.jsx)("p",{className:r.heroSubtitleSmall,children:"Detect security issues in TON smart contracts before they reach production"}),(0,a.jsx)("div",{className:r.buttons,children:(0,a.jsx)("a",{className:"button button--primary button--lg",href:"/tools/misti/docs/",children:"Get Started"})})]})}),(0,a.jsxs)("main",{children:[(0,a.jsx)("section",{className:`${r.features} ${r.sectionPadding}`,children:(0,a.jsxs)("div",{className:"container",children:[(0,a.jsx)("h2",{className:r.featuresTitle,children:"Misti Overview"}),(0,a.jsx)("p",{className:r.featuresSummary,children:"Misti is a comprehensive security tool designed to identify and prevent vulnerabilities in TON smart contracts. By streamlining the development process and integrating security checks early, Misti ensures your code remains robust and secure."}),(0,a.jsxs)("div",{className:`${r.rowWithMargin} row`,children:[(0,a.jsx)("div",{className:"col col--4",children:(0,a.jsxs)("div",{className:r.featureBox,children:[(0,a.jsx)("h3",{children:"\ud83d\udd12 Code Analysis"}),(0,a.jsxs)("p",{children:["Identify and fix potential"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors",children:"security flaws and code problems"})," ","early in the development cycle."]})]})}),(0,a.jsx)("div",{className:"col col--4",children:(0,a.jsxs)("div",{className:r.featureBox,children:[(0,a.jsx)("h3",{children:"\u2699\ufe0f CI/CD Integration"}),(0,a.jsxs)("p",{children:[(0,a.jsx)("a",{href:"/tools/misti/docs/tutorial/ci-cd",children:"Integrate"})," Misti into your CI/CD pipeline to ensure continuous code quality checks."]})]})}),(0,a.jsx)("div",{className:"col col--4",children:(0,a.jsxs)("div",{className:r.featureBox,children:[(0,a.jsx)("h3",{children:"\ud83d\udee0\ufe0f Custom Detectors"}),(0,a.jsxs)("p",{children:["Create"," ",(0,a.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,a.jsx)("div",{className:`${r.buttons} ${r.centerButton}`,children:(0,a.jsx)("a",{className:"button button--primary button--lg",href:"/tools/misti/docs/",children:"Read Documentation"})})]})}),(0,a.jsx)("section",{className:`${r.features} ${r.sectionPadding} ${r.alternateBackground}`,children:(0,a.jsxs)("div",{className:"container",children:[(0,a.jsx)("h2",{className:r.featuresTitle,children:"Discover Detectors"}),(0,a.jsx)("p",{className:r.featuresSummary,children:"Misti supports 26 specialized detectors designed to identify code issues, detect vulnerabilities, and enforce best practices."}),(0,a.jsxs)("div",{className:`${r.rowWithMargin} row`,children:[(0,a.jsx)("div",{className:"col col--4",children:(0,a.jsxs)("div",{className:r.featureBox,children:[(0,a.jsx)("h3",{children:"\ud83c\udf10 TON & Tact Specific"}),(0,a.jsxs)("p",{children:["Detect patterns unique to TON and Tact that could lead to unintended behavior, such as"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/CellOverflow",children:"CellOverflow"})," or"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/StringReceiversOverlap",children:"StringReceiversOverlap"}),"."]})]})}),(0,a.jsx)("div",{className:"col col--4",children:(0,a.jsxs)("div",{className:r.featureBox,children:[(0,a.jsx)("h3",{children:"\ud83d\udeab DoS Prevention"}),(0,a.jsxs)("p",{children:["Identify vulnerabilities that could lead to Denial of Service attacks, like"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/SendInLoop",children:"SendInLoop"})," or"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/UnboundMap",children:"UnboundMap"}),"."]})]})}),(0,a.jsx)("div",{className:"col col--4",children:(0,a.jsxs)("div",{className:r.featureBox,children:[(0,a.jsx)("h3",{children:"\u2797 Arithmetic Accuracy"}),(0,a.jsxs)("p",{children:["Avoid critical calculation errors with detectors like"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/DivideBeforeMultiply",children:"DivideBeforeMultiply"}),"."]})]})})]}),(0,a.jsxs)("div",{className:`${r.rowWithMargin} row`,children:[(0,a.jsx)("div",{className:"col col--4",children:(0,a.jsxs)("div",{className:r.featureBox,children:[(0,a.jsx)("h3",{children:"\ud83d\udd10 Access Control"}),(0,a.jsxs)("p",{children:["Ensure only authorized entities perform actions, preventing unauthorized access with detectors like"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/SuspiciousMessageMode",children:"SuspiciousMessageMode"}),"."]})]})}),(0,a.jsx)("div",{className:"col col--4",children:(0,a.jsxs)("div",{className:r.featureBox,children:[(0,a.jsx)("h3",{children:"\u26a1 Code Optimization"}),(0,a.jsxs)("p",{children:["Enhance code efficiency and readability with detectors like"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/OptimalMathFunction",children:"OptimalMathFunction"})," and"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/PreferAugmentedAssign",children:"PreferAugmentedAssign"}),"."]})]})}),(0,a.jsx)("div",{className:"col col--4",children:(0,a.jsxs)("div",{className:r.featureBox,children:[(0,a.jsx)("h3",{children:"\ud83d\udd75\ufe0f Suspicious Patterns"}),(0,a.jsxs)("p",{children:["Uncover subtle issues in your code with detectors such as"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/ZeroAddress",children:"ZeroAddress"})," and"," ",(0,a.jsx)("a",{href:"/tools/misti/docs/detectors/InheritedStateMutation",children:"InheritedStateMutation"}),"."]})]})})]}),(0,a.jsx)("div",{className:`${r.buttons} ${r.centerButton}`,children:(0,a.jsx)("a",{className:"button button--primary button--lg",href:"/tools/misti/docs/detectors",children:"View All Detectors"})})]})}),(0,a.jsx)("section",{className:`${r.features} ${r.sectionPadding}`,children:(0,a.jsxs)("div",{className:"container",children:[(0,a.jsx)("h2",{className:r.featuresTitle,children:"Request an Audit"}),(0,a.jsxs)("p",{className:r.featuresSummary,children:["Certain types of bugs cannot be caught by automated tools as they demand a deep understanding of the underlying system.",(0,a.jsx)("br",{}),"We offer audit services for TON smart contracts, backed by deep security expertise, as our availability allows. If you are interested, reach out to us."]}),(0,a.jsx)("div",{className:`${r.buttons} ${r.centerButton}`,children:(0,a.jsxs)("a",{className:"button button--primary button--lg",href:"https://t.me/jubnzv",children:[(0,a.jsx)(c.zyo,{style:{marginRight:"8px",verticalAlign:"middle"}}),"Contact Us"]})})]})})]})]})}}}]); \ No newline at end of file diff --git a/assets/js/e530f65e.a3814a9a.js b/assets/js/e530f65e.a3814a9a.js new file mode 100644 index 000000000..a75b96a3e --- /dev/null +++ b/assets/js/e530f65e.a3814a9a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[738],{425:(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.5/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.5/detectors/BranchDuplicate.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"AsmIsUsed",permalink:"/tools/misti/docs/detectors/AsmIsUsed"},next:{title:"CellOverflow",permalink:"/tools/misti/docs/detectors/CellOverflow"}},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/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.18abdbcd.js b/assets/js/e6ef21e7.18abdbcd.js new file mode 100644 index 000000000..6e062f5b7 --- /dev/null +++ b/assets/js/e6ef21e7.18abdbcd.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/0.4.0/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/0.4.0/detectors/DumpIsUsed"},next:{title:"EnsurePrgSeed",permalink:"/tools/misti/docs/0.4.0/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.a5aaaeb2.js b/assets/js/ea064c97.a5aaaeb2.js new file mode 100644 index 000000000..a05e7fa0e --- /dev/null +++ b/assets/js/ea064c97.a5aaaeb2.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/0.4.0/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/0.4.0/detectors/ArgCopyMutation"},next:{title:"BranchDuplicate",permalink:"/tools/misti/docs/0.4.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/ea8d0df0.3be72894.js b/assets/js/ea8d0df0.3be72894.js new file mode 100644 index 000000000..a5aaf2468 --- /dev/null +++ b/assets/js/ea8d0df0.3be72894.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:"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:"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:"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/eb1a8185.161f6a09.js b/assets/js/eb1a8185.161f6a09.js new file mode 100644 index 000000000..4bd89ae50 --- /dev/null +++ b/assets/js/eb1a8185.161f6a09.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[5656],{3872:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>d});var s=n(4848),i=n(8453);const r={},o="Developing Misti",a={id:"hacking/developing-misti",title:"Developing Misti",description:"Prerequisites",source:"@site/versioned_docs/version-0.5/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.5/hacking/developing-misti.md",tags:[],version:"0.5",frontMatter:{},sidebar:"sidebar",previous:{title:"Contributing",permalink:"/tools/misti/docs/hacking/contributing"},next:{title:"Writing Custom Detectors",permalink:"/tools/misti/docs/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,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"developing-misti",children:"Developing Misti"}),"\n",(0,s.jsx)(t.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,s.jsxs)(t.p,{children:["Before you begin, please refer to the ",(0,s.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,s.jsx)(t.h2,{id:"cloning-the-repository",children:"Cloning the Repository"}),"\n",(0,s.jsx)(t.p,{children:"Clone the Misti repository:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"git clone 'https://github.com/nowarp/misti'\n"})}),"\n",(0,s.jsx)(t.h2,{id:"building-the-project",children:"Building the Project"}),"\n",(0,s.jsx)(t.p,{children:"Navigate to the project directory, install dependencies, generate necessary files, and build the project:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"cd misti && yarn install && yarn gen && yarn build\n"})}),"\n",(0,s.jsx)(t.h2,{id:"running-the-analyzer",children:"Running the Analyzer"}),"\n",(0,s.jsx)(t.p,{children:"During development, you can run the analyzer using:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"yarn misti\n"})}),"\n",(0,s.jsx)(t.p,{children:"For example, to run it for tests:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"yarn misti test/detectors/NeverAccessedVariables.tact\n"})}),"\n",(0,s.jsx)(t.h2,{id:"adding-backtraces-to-the-logger",children:"Adding Backtraces to the Logger"}),"\n",(0,s.jsxs)(t.p,{children:["To add debug traces to all log messages, set the ",(0,s.jsx)(t.code,{children:"MISTI_TRACE"})," environment variable to ",(0,s.jsx)(t.code,{children:"1"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"MISTI_TRACE=1 yarn misti test/detectors/NeverAccessedVariables.tact\n"})}),"\n",(0,s.jsx)(t.h2,{id:"updating-expected-outputs-of-tests",children:"Updating Expected Outputs of Tests"}),"\n",(0,s.jsxs)(t.p,{children:["To update the expected outputs of tests, set the ",(0,s.jsx)(t.code,{children:"BLESS"})," environment variable and run the tests:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test\n"})}),"\n",(0,s.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,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test test/tactIR.spec.ts tests/detectors/NeverAccessedVariables.tact\n"})}),"\n",(0,s.jsx)(t.p,{children:"And for another specific test:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-bash",children:"BLESS=1 yarn test test/builtinDetectors.spec.ts test/detectors/BranchDuplicate.tact\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:()=>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/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.2d114ae2.js b/assets/js/ed2e6971.2d114ae2.js new file mode 100644 index 000000000..3a104acac --- /dev/null +++ b/assets/js/ed2e6971.2d114ae2.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:()=>o,metadata:()=>r,toc:()=>l});var s=n(4848),i=n(8453);const o={},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:"UnusedExpressionResult",permalink:"/tools/misti/docs/next/detectors/UnusedExpressionResult"},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,i.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,i.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 i={},o=s.createContext(i);function a(e){const t=s.useContext(o);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(i):e.components||i:a(e.components),s.createElement(o.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/ef43b7e4.3a22e7e4.js b/assets/js/ef43b7e4.3a22e7e4.js new file mode 100644 index 000000000..d5bc6b7b6 --- /dev/null +++ b/assets/js/ef43b7e4.3a22e7e4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[9623],{3467:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>a,contentTitle:()=>r,default:()=>h,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var i=s(4848),t=s(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.5/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.5/tutorial/getting-started.md",tags:[],version:"0.5",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 Warnings",id:"suppressing-warnings",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,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"getting-started",children:"Getting started"}),"\n",(0,i.jsx)(n.p,{children:"This guide will walk you through the steps to install and set up the Misti static analyzer."}),"\n",(0,i.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsx)(n.p,{children:"Before you begin, ensure you have the following software installed on your system:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Git"}),"\n",(0,i.jsx)(n.li,{children:"Yarn"}),"\n",(0,i.jsx)(n.li,{children:"Node.js version 22 or higher"}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://souffle-lang.github.io/install",children:"Souffl\xe9"})}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"installation",children:"Installation"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"npm install -g @nowarp/misti\n"})}),"\n",(0,i.jsx)(n.h3,{id:"using-development-version",children:"Using Development Version"}),"\n",(0,i.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,i.jsx)(n.p,{children:"To install the latest development version you should:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["Clone Misti: ",(0,i.jsx)(n.code,{children:"git clone https://github.com/nowarp/misti"})]}),"\n",(0,i.jsxs)(n.li,{children:["Build it: ",(0,i.jsx)(n.code,{children:"cd misti && yarn install && yarn build"})]}),"\n",(0,i.jsxs)(n.li,{children:["Use it in your Tact project: ",(0,i.jsx)(n.code,{children:"cd /path/to/tact/project && yarn add file:/path/to/misti"})]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"running-the-analysis",children:"Running the analysis"}),"\n",(0,i.jsx)(n.p,{children:"Run Misti by specifying a Tact project configuration:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"misti path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(n.p,{children:"This will highlight any warnings the analyzer found."}),"\n",(0,i.jsxs)(n.p,{children:["You can also add a script to your ",(0,i.jsx)(n.code,{children:"package.json"})," to simplify running the linting process:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-json",children:'{\n "scripts": {\n "lint": "misti path/to/tact.config.json"\n }\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"more-usage-examples",children:"More usage examples"}),"\n",(0,i.jsxs)(n.p,{children:["Below are a few usage examples for common scenarios when using ",(0,i.jsxs)(n.a,{href:"/tools/misti/docs/tutorial/cli",children:["the ",(0,i.jsx)(n.code,{children:"misti"})," CLI"]}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"suppressing-warnings",children:"Suppressing Warnings"}),"\n",(0,i.jsxs)(n.p,{children:["If you want to suppress some warnings in specific places of source code, you should use the ",(0,i.jsx)(n.code,{children:"@misti:suppress"})," annotations in the comment on the previous line, for example:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"fun test(): Int {\n // @misti:suppress NeverAccessedVariables\n let sum: Int = 0; // OK: The warning will be suppressed\n return 52;\n}\n"})}),"\n",(0,i.jsx)(n.p,{children:"This syntax also enables you to list a few detectors to be suppressed, including the custom ones, for example:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"// @misti:suppress NeverAccessedVariables,MyCustomDetector,ReadOnlyVariables\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Alternatively, you could run ",(0,i.jsx)(n.code,{children:"misti"})," while entirely suppressing specific detectors:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"misti --suppress ReadOnlyVariables path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(n.h3,{id:"enabling-all-detectors",children:"Enabling All Detectors"}),"\n",(0,i.jsxs)(n.p,{children:["Running ",(0,i.jsx)(n.code,{children:"misti"})," with all available built-in detectors enabled:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"misti --all-detectors path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(n.p,{children:"It is recommended to do that when auditing the project."}),"\n",(0,i.jsx)(n.h3,{id:"running-in-quiet-mode",children:"Running in Quiet Mode"}),"\n",(0,i.jsxs)(n.p,{children:["To suppress all output while running ",(0,i.jsx)(n.code,{children:"misti"})," getting just a return code:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"misti --quiet path/to/tact.config.json\n"})}),"\n",(0,i.jsx)(n.p,{children:"This might be useful in scripts and CI/CD."}),"\n",(0,i.jsx)(n.h2,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,i.jsxs)(n.p,{children:["If you encounter any issues during the installation process, feel free to ",(0,i.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues/new",children:"create an issue"})," or ask in the ",(0,i.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453:(e,n,s)=>{s.d(n,{R:()=>r,x:()=>o});var i=s(6540);const t={},l=i.createContext(t);function r(e){const n=i.useContext(l);return i.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(t):e.components||t:r(e.components),i.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/effcc73a.c554b68a.js b/assets/js/effcc73a.c554b68a.js new file mode 100644 index 000000000..4ecc0093f --- /dev/null +++ b/assets/js/effcc73a.c554b68a.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/0.4.0/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/0.4.0/hacking/design"},next:{title:"Custom Detectors",permalink:"/tools/misti/docs/0.4.0/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.c88faef0.js b/assets/js/f3297ff5.c88faef0.js new file mode 100644 index 000000000..64c8ec45a --- /dev/null +++ b/assets/js/f3297ff5.c88faef0.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:()=>o,contentTitle:()=>s,default:()=>p,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var a=n(4848),r=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:"SendInLoop",permalink:"/tools/misti/docs/next/detectors/SendInLoop"}},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,r.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.h1,{id:"readonlyvariables",children:"ReadOnlyVariables"}),"\n",(0,a.jsx)(t.p,{children:"A detector that identifies read-only variables and fields."}),"\n",(0,a.jsx)(t.h2,{id:"why-is-it-bad",children:"Why is it bad?"}),"\n",(0,a.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,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 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)(t.p,{children:"Use instead:"}),"\n",(0,a.jsx)(t.pre,{children:(0,a.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,r.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>s,x:()=>l});var a=n(6540);const r={},i=a.createContext(r);function s(e){const t=a.useContext(i);return a.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),a.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.4bde77ae.js b/assets/js/f553073e.4bde77ae.js new file mode 100644 index 000000000..b3f9e0336 --- /dev/null +++ b/assets/js/f553073e.4bde77ae.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/0.4.0/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/0.4.0/detectors/ReadOnlyVariables"},next:{title:"UnboundLoops",permalink:"/tools/misti/docs/0.4.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/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.14b05cf2.js b/assets/js/f58fcc43.14b05cf2.js new file mode 100644 index 000000000..ec63b30cd --- /dev/null +++ b/assets/js/f58fcc43.14b05cf2.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/0.4.0/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/0.4.0/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.1f995ffc.js b/assets/js/f752d1db.1f995ffc.js new file mode 100644 index 000000000..b19201fed --- /dev/null +++ b/assets/js/f752d1db.1f995ffc.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/0.4.0/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/0.4.0/tutorial/getting-started"},next:{title:"Command-Line Interface",permalink:"/tools/misti/docs/0.4.0/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/0.4.0/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.388d1a86.js b/assets/js/f97c3fca.388d1a86.js new file mode 100644 index 000000000..e9a0d1a55 --- /dev/null +++ b/assets/js/f97c3fca.388d1a86.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:"CellOverflow",permalink:"/tools/misti/docs/next/detectors/CellOverflow"},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/f99bae31.0a506efe.js b/assets/js/f99bae31.0a506efe.js new file mode 100644 index 000000000..08b0537a6 --- /dev/null +++ b/assets/js/f99bae31.0a506efe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[]).push([[8927],{8721:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>o,default:()=>h,frontMatter:()=>s,metadata:()=>d,toc:()=>l});var i=t(4848),r=t(8453);const s={},o="DumpImports",d={id:"tools/DumpImports",title:"DumpImports",description:"Misti provides a feature to dump the Import Graph of your Tact code in JSON, DOT, and Mermaid formats. This tool helps you understand the dependencies between different files and modules in your project, including how contracts import each other and use the standard library.",source:"@site/docs/tools/DumpImports.md",sourceDirName:"tools",slug:"/tools/DumpImports",permalink:"/tools/misti/docs/next/tools/DumpImports",draft:!1,unlisted:!1,editUrl:"https://github.com/nowarp/nowarp.github.io/tree/master/docs/tools/DumpImports.md",tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"DumpConfig",permalink:"/tools/misti/docs/next/tools/DumpConfig"},next:{title:"Design Overview",permalink:"/tools/misti/docs/next/hacking/design"}},a={},l=[{value:"Usage",id:"usage",level:2},{value:"Working with Mermaid and Graphviz",id:"working-with-mermaid-and-graphviz",level:2},{value:"Understanding the Dumps",id:"understanding-the-dumps",level:2},{value:"Including Standard Library Imports",id:"including-standard-library-imports",level:2},{value:"Example",id:"example",level:2},{value:"Interpreting the Import Graph",id:"interpreting-the-import-graph",level:2},{value:"Conclusion",id:"conclusion",level:2}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"dumpimports",children:"DumpImports"}),"\n",(0,i.jsxs)(n.p,{children:["Misti provides a feature to dump the ",(0,i.jsx)(n.strong,{children:"Import Graph"})," of your Tact code in JSON, DOT, and Mermaid formats. This tool helps you understand the dependencies between different files and modules in your project, including how contracts import each other and use the standard library."]}),"\n",(0,i.jsx)(n.h2,{id:"usage",children:"Usage"}),"\n",(0,i.jsx)(n.p,{children:"To dump the Import Graph in Mermaid format, use the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=mmd" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,i.jsx)(n.p,{children:"To dump the Import Graph in Graphviz DOT format, use the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,i.jsx)(n.p,{children:"To dump the Import Graph in JSON format, use the following command:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=json" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,i.jsxs)(n.p,{children:["You can also include Tact standard library imports in the dump by adding ",(0,i.jsx)(n.code,{children:"dumpStdlib=true"})," to the ",(0,i.jsx)(n.code,{children:"DumpImports"})," options:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=dot,dumpStdlib=true" <TACT_CONFIG_PATH|TACT_FILE_PATH>\n'})}),"\n",(0,i.jsx)(n.h2,{id:"working-with-mermaid-and-graphviz",children:"Working with Mermaid and Graphviz"}),"\n",(0,i.jsxs)(n.p,{children:["For guidance on how to work with Mermaid diagrams, Graphviz DOT files, and viewing them in Visual Studio Code, please refer to the ",(0,i.jsx)(n.a,{href:"/tools/misti/docs/next/tools/DumpCfg#working-with-mermaid",children:"DumpCfg documentation"})," and the ",(0,i.jsx)(n.a,{href:"/tools/misti/docs/next/tools/DumpCfg#working-with-graphviz",children:"Graphviz section"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"understanding-the-dumps",children:"Understanding the Dumps"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"JSON Dumps"}),": Provide a detailed representation of the Import Graph in JSON format, including nodes and edges with their properties. Useful for programmatic analysis or custom tooling."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"DOT Dumps"}),": Offer a visual representation of the project's import dependencies. Useful for understanding how files and contracts depend on each other."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Mermaid Dumps"}),": Similar to DOT dumps but using Mermaid syntax, which can be easier to work with in certain environments, especially when using markdown files or online editors."]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"By utilizing these tools, developers can gain deeper insights into the dependency structure of their Tact projects, facilitating better project organization, dependency management, and code optimization."}),"\n",(0,i.jsx)(n.h2,{id:"including-standard-library-imports",children:"Including Standard Library Imports"}),"\n",(0,i.jsxs)(n.p,{children:["By default, the Import Graph excludes imports from the standard library. If you want to include standard library imports in your graph, add ",(0,i.jsx)(n.code,{children:"dumpStdlib=true"})," to the command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=mmd,dumpStdlib=true" contracts/main.tact\n'})}),"\n",(0,i.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,i.jsx)(n.p,{children:"Consider a project with the following structure:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"main.tact"})}),":"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:'import "./constants.tact";\nimport "./messages.tact";\nimport "@stdlib/ownable";\ncontract C{}\n'})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"constants.tact"})}),":"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:"const SOMETHING: Int = 123;\n"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:(0,i.jsx)(n.code,{children:"messages.tact"})}),":"]}),"\n"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tact",children:'import "./constants.tact";\nmessage Msg { a: Bool }\n'})}),"\n",(0,i.jsx)(n.p,{children:"To dump the Import Graph in Mermaid format, run:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'misti -t "DumpImports:format=mmd:dumpStdlib=true" contracts/main.tact\n'})}),"\n",(0,i.jsx)(n.p,{children:"The output will look like:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-mermaid",children:'graph TD\n node_1["main"]:::contractNode\n node_2["constants"]\n node_3["messages"]\n node_4["@stdlib/ownable.tact"]:::stdlibNode\n node_1 --\x3e node_2\n node_3 --\x3e node_2\n node_1 --\x3e node_3\n node_1 --\x3e node_4\n classDef contractNode fill:#90EE90,stroke:#333,stroke-width:2px;\n classDef stdlibNode fill:#FFFF80,stroke:#333,stroke-width:2px;\n'})}),"\n",(0,i.jsx)(n.p,{children:"Which will be rendered as:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Mermaid Output",src:t(2479).A+"",width:"656",height:"414"})}),"\n",(0,i.jsx)(n.p,{children:"In this diagram:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Nodes"})," representing files that contain contracts are filled with green."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Edges"})," represent import relationships between files."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"You can paste this Mermaid code into the Mermaid Live Editor or view it directly in VS Code with the appropriate extension."}),"\n",(0,i.jsx)(n.h2,{id:"interpreting-the-import-graph",children:"Interpreting the Import Graph"}),"\n",(0,i.jsx)(n.p,{children:"The Import Graph shows how files in your project are interconnected through import statements. Each node represents a file, and each edge represents an import from one file to another."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Nodes"}),":","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Files containing contracts are highlighted (green in the examples)."}),"\n",(0,i.jsx)(n.li,{children:"Standard library files are highlighted differently (yellow) when included."}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Edges"}),":","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Directed edges show the import relationship (",(0,i.jsx)(n.code,{children:"A --\x3e B"})," means ",(0,i.jsx)(n.code,{children:"A"})," imports ",(0,i.jsx)(n.code,{children:"B"}),")."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Understanding the Import Graph can help you:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Identify unnecessary dependencies."}),"\n",(0,i.jsx)(n.li,{children:"Visualize the structure of your project."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"conclusion",children:"Conclusion"}),"\n",(0,i.jsxs)(n.p,{children:["By utilizing the ",(0,i.jsx)(n.code,{children:"DumpImports"})," tool, developers can gain deeper insights into the dependency structure of their Tact projects, facilitating better project organization, dependency management, and code optimization."]})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},2479:(e,n,t)=>{t.d(n,{A:()=>i});const i=t.p+"assets/images/dump-imports-mmd-455299aa0e63b065a70b166ab0597814.png"},8453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>d});var i=t(6540);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/faae61e5.0c385acd.js b/assets/js/faae61e5.0c385acd.js new file mode 100644 index 000000000..e55177a7f --- /dev/null +++ b/assets/js/faae61e5.0c385acd.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:()=>x,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var d=s(4848),r=s(8453);const i={id:"detectors",title:"Detectors Overview"},n="Detectors Overview",c={id:"detectors",title:"Detectors Overview",description:"Built-in Detectors",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:"Built-in Detectors",id:"built-in-detectors",level:2}];function h(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",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.h2,{id:"built-in-detectors",children:"Built-in Detectors"}),"\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/next/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/next/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/next/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/next/detectors/CellOverflow",children:"CellOverflow"})}),(0,d.jsx)(t.td,{children:"Critical"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{children:"\u2714"})]}),(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/next/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:"6"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"7"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"8"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"9"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"10"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"11"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"12"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"13"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"14"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"15"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"16"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"17"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"18"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/SendInLoop",children:"SendInLoop"})}),(0,d.jsx)(t.td,{children:"Medium"}),(0,d.jsx)(t.td,{}),(0,d.jsx)(t.td,{})]}),(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/next/detectors/ShortCircuitCondition",children:"ShortCircuitCondition"})}),(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/next/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:"21"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/SuspiciousMessageMode",children:"SuspiciousMessageMode"})}),(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:"22"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/UnboundLoop",children:"UnboundLoop"})}),(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:"23"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/UnboundMap",children:"UnboundMap"})}),(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:"24"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/detectors/UnusedExpressionResult",children:"UnusedExpressionResult"})}),(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:"25"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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:"26"}),(0,d.jsx)(t.td,{children:(0,d.jsx)(t.a,{href:"/tools/misti/docs/next/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/next/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/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.0abc4220.js b/assets/js/fbbe250b.0abc4220.js new file mode 100644 index 000000000..1c0d36f96 --- /dev/null +++ b/assets/js/fbbe250b.0abc4220.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:()=>h,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var s=i(4848),t=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:"Environment Variables",id:"environment-variables",level:2},{value:"Getting Help",id:"getting-help",level:2}];function d(e){const n={a:"a",br:"br",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"configuration",children:"Configuration"}),"\n",(0,s.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,s.jsx)(n.h3,{id:"configuration-options",children:"Configuration Options"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"detectors"})," (array of objects, optional): List of detectors to run. Each detector can be specified with a ",(0,s.jsx)(n.code,{children:"className"})," and optionally a ",(0,s.jsx)(n.code,{children:"modulePath"})," if it\u2019s a custom detector."]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"className"})," (string, required): The class name of the detector."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"modulePath"})," (string, optional): The file path of the detector module if it's a custom implementation."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"tools"})," (array of objects, optional): List of tools to enable, each with its own configuration."]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"className"})," (string, required): The class name of the tool."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"options"})," (object, optional): Key-value configuration options for the tool."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"suppressions"})," (array of objects, optional): A list of suppressions for warnings."]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"detector"})," (string, required): The detector to suppress warnings for."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"position"})," (string, required): The position in the code where the warning should be suppressed."]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"ignoredProjects"})," (array of strings, optional): List of Tact projects to ignore during analysis."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.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,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.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,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.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,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.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,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"verbosity"}),' (string, optional, default: "default"): Verbosity level of the logs. Possible values are ',(0,s.jsx)(n.code,{children:"quiet"}),", ",(0,s.jsx)(n.code,{children:"debug"}),", and ",(0,s.jsx)(n.code,{children:"default"}),"."]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"running-misti-with-configuration",children:"Running Misti with Configuration"}),"\n",(0,s.jsx)(n.p,{children:"To run Misti with the specified configuration file, use the following command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"misti --config path/to/mistiConfig.json test/projects/simple/tactConfig.json\n"})}),"\n",(0,s.jsx)(n.p,{children:"This command tells Misti to use the provided configuration file to analyze the specified Tact project configuration."}),"\n",(0,s.jsx)(n.h2,{id:"default-configuration-file",children:"Default Configuration File"}),"\n",(0,s.jsx)(n.p,{children:"By default, Misti enables all built-in detectors. Below is an example of the default configuration file:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.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,s.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,s.jsx)(n.a,{href:"https://github.com/nowarp/misti/blob/master/configSchema.json",children:"configSchema.json"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["You can always dump the Misti configuration file in use by passing the ",(0,s.jsx)(n.code,{children:"--dump-config"})," option in the CLI:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"misti --dump-config path/to/your/tact.config.json\n"})}),"\n",(0,s.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,s.jsx)(n.h2,{id:"environment-variables",children:"Environment Variables"}),"\n",(0,s.jsx)(n.p,{children:"Misti offers advanced configuration through environment variables to control specific options."}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:(0,s.jsx)(n.code,{children:"MISTI_TIMEOUT"})}),(0,s.jsx)(n.br,{}),"\n","Sets the timeout for detector execution in milliseconds.",(0,s.jsx)(n.br,{}),"\n",(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"15000"}),(0,s.jsx)(n.br,{}),"\n",(0,s.jsx)(n.strong,{children:"Example"}),":","\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"export MISTI_TIMEOUT=20000\n"})}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:(0,s.jsx)(n.code,{children:"MISTI_TRACE"})}),(0,s.jsx)(n.br,{}),"\n","Enables tracing of the execution. Set to ",(0,s.jsx)(n.code,{children:"1"})," to enable tracing, otherwise it is disabled.",(0,s.jsx)(n.br,{}),"\n",(0,s.jsx)(n.strong,{children:"Default"}),": ",(0,s.jsx)(n.code,{children:"false"}),(0,s.jsx)(n.br,{}),"\n",(0,s.jsx)(n.strong,{children:"Example"}),":","\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"export MISTI_TRACE=1\n"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"getting-help",children:"Getting Help"}),"\n",(0,s.jsxs)(n.p,{children:["If you need assistance or encounter any issues, please create an issue on GitHub at ",(0,s.jsx)(n.a,{href:"https://github.com/nowarp/misti/issues",children:"nowarp/misti"})," or ask in the ",(0,s.jsx)(n.a,{href:"https://t.me/misti_dev",children:"Misti Telegram group"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>l});var s=i(6540);const t={},o=s.createContext(t);function r(e){const n=s.useContext(o);return s.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(t):e.components||t:r(e.components),s.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.ebcc6cf7.js b/assets/js/main.ebcc6cf7.js new file mode 100644 index 000000000..883c88eac --- /dev/null +++ b/assets/js/main.ebcc6cf7.js @@ -0,0 +1,2 @@ +/*! For license information please see main.ebcc6cf7.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],"03b4256a":[()=>n.e(7354).then(n.t.bind(n,2682,19)),"@generated/docusaurus-plugin-content-docs/default/p/tools-misti-docs-0-4-0-43f.json",2682],"0600087e":[()=>n.e(9713).then(n.bind(n,8078)),"@site/versioned_docs/version-0.5/detectors/ZeroAddress.md",8078],"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],"110db9ee":[()=>n.e(8164).then(n.bind(n,5547)),"@site/versioned_docs/version-0.5/detectors/UnboundMap.md",5547],"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],"129b217c":[()=>n.e(5422).then(n.bind(n,4558)),"@site/versioned_docs/version-0.5/detectors/AsmIsUsed.md",4558],"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],"1a2cd3da":[()=>n.e(4006).then(n.bind(n,3020)),"@site/versioned_docs/version-0.5/detectors/ConstantAddress.md",3020],"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],"230b3a10":[()=>n.e(3031).then(n.bind(n,3940)),"@site/versioned_docs/version-0.5/detectors/CellOverflow.md",3940],"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],"24ab0ec7":[()=>n.e(9439).then(n.bind(n,2592)),"@site/docs/detectors/SuspiciousMessageMode.md",2592],"25eb63f7":[()=>n.e(6941).then(n.bind(n,2637)),"@site/versioned_docs/version-0.5/detectors/DumpIsUsed.md",2637],"26592ea2":[()=>n.e(3543).then(n.bind(n,3178)),"@site/docs/detectors/FieldDoubleInit.md",3178],"26b19808":[()=>n.e(3339).then(n.bind(n,8267)),"@site/versioned_docs/version-0.5/detectors/FieldDoubleInit.md",8267],"273168fb":[()=>n.e(1492).then(n.bind(n,7079)),"@site/versioned_docs/version-0.1.2/tutorial/getting-started.md",7079],"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],"2c038e81":[()=>n.e(7393).then(n.bind(n,3268)),"@site/docs/detectors/UnboundMap.md",3268],"2c17c501":[()=>n.e(23).then(n.bind(n,2458)),"@site/versioned_docs/version-0.5/detectors/ArgCopyMutation.md",2458],"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],"2fbff8b1":[()=>n.e(1330).then(n.bind(n,3832)),"@site/versioned_docs/version-0.5/tools/DumpImports.md",3832],"304edb56":[()=>n.e(4088).then(n.bind(n,8271)),"@site/docs/detectors/ArgCopyMutation.md",8271],"30835b52":[()=>n.e(6269).then(n.bind(n,3116)),"@site/versioned_docs/version-0.5/detectors/DivideBeforeMultiply.md",3116],"322eba7d":[()=>n.e(1193).then(n.bind(n,1535)),"@site/versioned_docs/version-0.5/detectors.md",1535],"35d1ab0d":[()=>n.e(4787).then(n.bind(n,1322)),"@site/versioned_docs/version-0.5/tools/DumpAst.md",1322],"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],"3c9b1461":[()=>n.e(3988).then(n.bind(n,849)),"@site/versioned_docs/version-0.5/detectors/PreferAugmentedAssign.md",849],"3db5102b":[()=>n.e(6774).then(n.bind(n,6931)),"@site/versioned_docs/version-0.2.1/tutorial/ci-cd.md",6931],"40440f59":[()=>n.e(5671).then(n.bind(n,8246)),"@site/versioned_docs/version-0.5/hacking/contributing.md",8246],"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],"4624921c":[()=>n.e(9510).then(n.bind(n,9567)),"@site/versioned_docs/version-0.5/detectors/ReadOnlyVariables.md",9567],"46947df5":[()=>n.e(4992).then(n.bind(n,1904)),"@site/versioned_docs/version-0.5/detectors/EnsurePrgSeed.md",1904],"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],"53023ca8":[()=>n.e(2712).then(n.bind(n,4228)),"@site/versioned_docs/version-0.5/detectors/NeverAccessedVariables.md",4228],"54df6b9c":[()=>n.e(8962).then(n.bind(n,7852)),"@site/versioned_docs/version-0.5/detectors/DuplicatedCondition.md",7852],"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],"5c07db7d":[()=>n.e(4575).then(n.bind(n,342)),"@site/versioned_docs/version-0.5/detectors/InheritedStateMutation.md",342],"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],"6afbdc7c":[()=>n.e(4701).then(n.bind(n,6400)),"@site/versioned_docs/version-0.5/hacking/custom-detector.md",6400],"6bb9ad58":[()=>n.e(9448).then(n.bind(n,693)),"@site/versioned_docs/version-0.5/tutorial/cli.md",693],"6bfbb660":[()=>n.e(5173).then(n.bind(n,2963)),"@site/versioned_docs/version-0.5/tutorial/ci-cd.md",2963],"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],"740c342d":[()=>n.e(4910).then(n.bind(n,8670)),"@site/versioned_docs/version-0.5/tools/DumpConfig.md",8670],"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,4019)),"@site/versioned_docs/version-0.4.0/detectors/BranchDuplicate.md",4019],"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],"770027e6":[()=>n.e(7709).then(n.bind(n,4951)),"@site/versioned_docs/version-0.5/detectors/UnusedExpressionResult.md",4951],"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],"8078ad78":[()=>n.e(6208).then(n.bind(n,210)),"@site/versioned_docs/version-0.5/detectors/FalseCondition.md",210],"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],"8685a76e":[()=>n.e(3583).then(n.bind(n,3950)),"@site/versioned_docs/version-0.5/hacking/souffle.md",3950],"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],"888071ca":[()=>n.e(9187).then(n.bind(n,903)),"@site/docs/detectors/ShortCircuitCondition.md",903],"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],"9016a10e":[()=>n.e(2906).then(n.bind(n,7216)),"@site/docs/detectors/UnusedExpressionResult.md",7216],"9081c3e5":[()=>n.e(6805).then(n.bind(n,1445)),"@site/versioned_docs/version-0.5/detectors/PreferredStdlibApi.md",1445],"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],"926d5e8d":[()=>n.e(2526).then(n.bind(n,2737)),"@site/versioned_docs/version-0.5/detectors/SendInLoop.md",2737],"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],"9983337e":[()=>n.e(3320).then(n.bind(n,1337)),"@site/versioned_docs/version-0.5/detectors/SuspiciousMessageMode.md",1337],"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],a2e1ac23:[()=>n.e(9977).then(n.bind(n,1682)),"@site/docs/detectors/UnboundLoop.md",1682],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],ab64460a:[()=>n.e(2467).then(n.bind(n,6083)),"@site/versioned_docs/version-0.5/detectors/UnboundLoop.md",6083],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],b2b6aa30:[()=>n.e(6216).then(n.bind(n,7828)),"@site/versioned_docs/version-0.5/detectors/OptimalMathFunction.md",7828],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],b9de2907:[()=>n.e(4913).then(n.bind(n,5144)),"@site/versioned_docs/version-0.5/tutorial/blueprint.md",5144],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],be04c9f2:[()=>n.e(44).then(n.bind(n,2322)),"@site/docs/detectors/SendInLoop.md",2322],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],c2845dc0:[()=>n.e(5378).then(n.bind(n,830)),"@site/versioned_docs/version-0.5/detectors/StringReceiversOverlap.md",830],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],c734b99d:[()=>n.e(872).then(n.bind(n,8956)),"@site/versioned_docs/version-0.5/detectors/UnusedOptional.md",8956],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],d7ebd85b:[()=>n.e(5308).then(n.bind(n,6659)),"@site/versioned_docs/version-0.5/tools.md",6659],d9542fcf:[()=>n.e(3590).then(n.bind(n,2866)),"@site/versioned_docs/version-0.2.0/detectors/BranchDuplicate.md",2866],d9941f94:[()=>n.e(8183).then(n.bind(n,7084)),"@site/versioned_docs/version-0.5/tools/DumpCfg.md",7084],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],dda96275:[()=>n.e(7193).then(n.bind(n,6924)),"@site/versioned_docs/version-0.5/hacking/design.md",6924],de7c269b:[()=>n.e(6309).then(n.bind(n,5275)),"@site/docs/detectors/CellOverflow.md",5275],df3f8a78:[()=>n.e(6474).then(n.bind(n,9633)),"@site/versioned_docs/version-0.5/tutorial/configuration.md",9633],e0636556:[()=>n.e(8047).then(n.bind(n,3944)),"@site/versioned_docs/version-0.5/index.md",3944],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(5604),n.e(7348)]).then(n.bind(n,3888)),"@site/src/pages/tools/misti/index.tsx",3888],e530f65e:[()=>n.e(738).then(n.bind(n,425)),"@site/versioned_docs/version-0.5/detectors/BranchDuplicate.md",425],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],eb1a8185:[()=>n.e(5656).then(n.bind(n,3872)),"@site/versioned_docs/version-0.5/hacking/developing-misti.md",3872],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],ef43b7e4:[()=>n.e(9623).then(n.bind(n,3467)),"@site/versioned_docs/version-0.5/tutorial/getting-started.md",3467],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],f99bae31:[()=>n.e(8927).then(n.bind(n,8721)),"@site/docs/tools/DumpImports.md",8721],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","063"),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/0.4.0",component:u("/tools/misti/docs/0.4.0","e81"),routes:[{path:"/tools/misti/docs/0.4.0",component:u("/tools/misti/docs/0.4.0","bc8"),routes:[{path:"/tools/misti/docs/0.4.0/",component:u("/tools/misti/docs/0.4.0/","6f1"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors",component:u("/tools/misti/docs/0.4.0/detectors","df6"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/ArgCopyMutation",component:u("/tools/misti/docs/0.4.0/detectors/ArgCopyMutation","761"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/AsmIsUsed",component:u("/tools/misti/docs/0.4.0/detectors/AsmIsUsed","6ef"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/BranchDuplicate",component:u("/tools/misti/docs/0.4.0/detectors/BranchDuplicate","051"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/ConstantAddress",component:u("/tools/misti/docs/0.4.0/detectors/ConstantAddress","1fb"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/0.4.0/detectors/DivideBeforeMultiply","33e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/DumpIsUsed",component:u("/tools/misti/docs/0.4.0/detectors/DumpIsUsed","b24"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/DuplicatedCondition",component:u("/tools/misti/docs/0.4.0/detectors/DuplicatedCondition","477"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/EnsurePrgSeed",component:u("/tools/misti/docs/0.4.0/detectors/EnsurePrgSeed","a2b"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/FalseCondition",component:u("/tools/misti/docs/0.4.0/detectors/FalseCondition","f06"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/FieldDoubleInit",component:u("/tools/misti/docs/0.4.0/detectors/FieldDoubleInit","cc7"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/InheritedStateMutation",component:u("/tools/misti/docs/0.4.0/detectors/InheritedStateMutation","d7f"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/0.4.0/detectors/NeverAccessedVariables","e94"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/OptimalMathFunction",component:u("/tools/misti/docs/0.4.0/detectors/OptimalMathFunction","849"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/PreferAugmentedAssign",component:u("/tools/misti/docs/0.4.0/detectors/PreferAugmentedAssign","127"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/PreferredStdlibApi",component:u("/tools/misti/docs/0.4.0/detectors/PreferredStdlibApi","d75"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/0.4.0/detectors/ReadOnlyVariables","4b9"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/StringReceiversOverlap",component:u("/tools/misti/docs/0.4.0/detectors/StringReceiversOverlap","c8e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/UnboundLoops",component:u("/tools/misti/docs/0.4.0/detectors/UnboundLoops","813"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/UnusedOptional",component:u("/tools/misti/docs/0.4.0/detectors/UnusedOptional","492"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/detectors/ZeroAddress",component:u("/tools/misti/docs/0.4.0/detectors/ZeroAddress","b6d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/hacking/contributing",component:u("/tools/misti/docs/0.4.0/hacking/contributing","39d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/hacking/custom-detector",component:u("/tools/misti/docs/0.4.0/hacking/custom-detector","45e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/hacking/design",component:u("/tools/misti/docs/0.4.0/hacking/design","ed4"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/hacking/developing-misti",component:u("/tools/misti/docs/0.4.0/hacking/developing-misti","172"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/hacking/souffle",component:u("/tools/misti/docs/0.4.0/hacking/souffle","144"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/tools",component:u("/tools/misti/docs/0.4.0/tools","28d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/tools/DumpAst",component:u("/tools/misti/docs/0.4.0/tools/DumpAst","2aa"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/tools/DumpCfg",component:u("/tools/misti/docs/0.4.0/tools/DumpCfg","d27"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/tools/DumpConfig",component:u("/tools/misti/docs/0.4.0/tools/DumpConfig","7b4"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/tutorial/blueprint",component:u("/tools/misti/docs/0.4.0/tutorial/blueprint","d90"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/tutorial/ci-cd",component:u("/tools/misti/docs/0.4.0/tutorial/ci-cd","096"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/tutorial/cli",component:u("/tools/misti/docs/0.4.0/tutorial/cli","179"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/tutorial/configuration",component:u("/tools/misti/docs/0.4.0/tutorial/configuration","e42"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/0.4.0/tutorial/getting-started",component:u("/tools/misti/docs/0.4.0/tutorial/getting-started","0f1"),exact:!0,sidebar:"sidebar"}]}]},{path:"/tools/misti/docs/next",component:u("/tools/misti/docs/next","13c"),routes:[{path:"/tools/misti/docs/next",component:u("/tools/misti/docs/next","46d"),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/CellOverflow",component:u("/tools/misti/docs/next/detectors/CellOverflow","347"),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/SendInLoop",component:u("/tools/misti/docs/next/detectors/SendInLoop","d81"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/ShortCircuitCondition",component:u("/tools/misti/docs/next/detectors/ShortCircuitCondition","96a"),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/SuspiciousMessageMode",component:u("/tools/misti/docs/next/detectors/SuspiciousMessageMode","7ac"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/UnboundLoop",component:u("/tools/misti/docs/next/detectors/UnboundLoop","e09"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/UnboundMap",component:u("/tools/misti/docs/next/detectors/UnboundMap","8d3"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/next/detectors/UnusedExpressionResult",component:u("/tools/misti/docs/next/detectors/UnusedExpressionResult","4c9"),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/tools/DumpImports",component:u("/tools/misti/docs/next/tools/DumpImports","bfa"),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","018"),routes:[{path:"/tools/misti/docs",component:u("/tools/misti/docs","fc9"),routes:[{path:"/tools/misti/docs/",component:u("/tools/misti/docs/","40c"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors",component:u("/tools/misti/docs/detectors","946"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/ArgCopyMutation",component:u("/tools/misti/docs/detectors/ArgCopyMutation","5be"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/AsmIsUsed",component:u("/tools/misti/docs/detectors/AsmIsUsed","a1e"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/BranchDuplicate",component:u("/tools/misti/docs/detectors/BranchDuplicate","dcd"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/CellOverflow",component:u("/tools/misti/docs/detectors/CellOverflow","0e4"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/ConstantAddress",component:u("/tools/misti/docs/detectors/ConstantAddress","ca0"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/DivideBeforeMultiply",component:u("/tools/misti/docs/detectors/DivideBeforeMultiply","e18"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/DumpIsUsed",component:u("/tools/misti/docs/detectors/DumpIsUsed","d93"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/DuplicatedCondition",component:u("/tools/misti/docs/detectors/DuplicatedCondition","636"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/EnsurePrgSeed",component:u("/tools/misti/docs/detectors/EnsurePrgSeed","cf1"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/FalseCondition",component:u("/tools/misti/docs/detectors/FalseCondition","b70"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/FieldDoubleInit",component:u("/tools/misti/docs/detectors/FieldDoubleInit","24a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/InheritedStateMutation",component:u("/tools/misti/docs/detectors/InheritedStateMutation","7a0"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/NeverAccessedVariables",component:u("/tools/misti/docs/detectors/NeverAccessedVariables","517"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/OptimalMathFunction",component:u("/tools/misti/docs/detectors/OptimalMathFunction","19d"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/PreferAugmentedAssign",component:u("/tools/misti/docs/detectors/PreferAugmentedAssign","6e1"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/PreferredStdlibApi",component:u("/tools/misti/docs/detectors/PreferredStdlibApi","b23"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/ReadOnlyVariables",component:u("/tools/misti/docs/detectors/ReadOnlyVariables","972"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/SendInLoop",component:u("/tools/misti/docs/detectors/SendInLoop","499"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/StringReceiversOverlap",component:u("/tools/misti/docs/detectors/StringReceiversOverlap","6d4"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/SuspiciousMessageMode",component:u("/tools/misti/docs/detectors/SuspiciousMessageMode","7bd"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/UnboundLoop",component:u("/tools/misti/docs/detectors/UnboundLoop","9ae"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/UnboundMap",component:u("/tools/misti/docs/detectors/UnboundMap","f1a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/UnusedExpressionResult",component:u("/tools/misti/docs/detectors/UnusedExpressionResult","b7c"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/UnusedOptional",component:u("/tools/misti/docs/detectors/UnusedOptional","d35"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/detectors/ZeroAddress",component:u("/tools/misti/docs/detectors/ZeroAddress","d48"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/contributing",component:u("/tools/misti/docs/hacking/contributing","768"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/custom-detector",component:u("/tools/misti/docs/hacking/custom-detector","dd3"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/design",component:u("/tools/misti/docs/hacking/design","43a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/developing-misti",component:u("/tools/misti/docs/hacking/developing-misti","fe7"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/hacking/souffle",component:u("/tools/misti/docs/hacking/souffle","f46"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tools",component:u("/tools/misti/docs/tools","5d4"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tools/DumpAst",component:u("/tools/misti/docs/tools/DumpAst","ade"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tools/DumpCfg",component:u("/tools/misti/docs/tools/DumpCfg","280"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tools/DumpConfig",component:u("/tools/misti/docs/tools/DumpConfig","511"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tools/DumpImports",component:u("/tools/misti/docs/tools/DumpImports","513"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/blueprint",component:u("/tools/misti/docs/tutorial/blueprint","6cf"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/ci-cd",component:u("/tools/misti/docs/tutorial/ci-cd","a83"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/cli",component:u("/tools/misti/docs/tutorial/cli","edd"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/configuration",component:u("/tools/misti/docs/tutorial/configuration","a4a"),exact:!0,sidebar:"sidebar"},{path:"/tools/misti/docs/tutorial/getting-started",component:u("/tools/misti/docs/tutorial/getting-started","7a0"),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),n(1911)];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),b=n(4586),g=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,b.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,b.A)(),o=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,b.A)(),{pathname:o}=(0,u.zy)();return e+(0,_.applyTrailingSlash)((0,g.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,b.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 D=new Map;var T=n(6125),R=n(6988),L=n(205);function O(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 P=function(e){let{children:t,location:n,previousLocation:o}=e;return(0,L.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}),O("onRouteDidUpdate",{previousLocation:o,location:n}))}),[o,n]),t};function N(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 I extends o.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.A.canUseDOM?O("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=O("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),N(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)(P,{previousLocation:this.previousLocation,location:t,children:(0,f.jsx)(u.qh,{location:t,render:()=>e})})}}const j=I,M="__docusaurus-base-url-issue-banner-container",F="__docusaurus-base-url-issue-banner",U="__docusaurus-base-url-issue-banner-suggestion-container";function B(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="${U}" 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('${U}');\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,b.A)();return(0,f.jsx)(f.Fragment,{children:!l.A.canUseDOM&&(0,f.jsx)(h.A,{children:(0,f.jsx)("script",{children:B(e)})})})}function $(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,b.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,b.A)(),i=(0,g.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(D.has(e.pathname))return{...e,pathname:D.get(e.pathname)};if((0,p.u)(d.A,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return D.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return D.set(e.pathname,t),{...e,pathname:t}}((0,u.zy)());return(0,f.jsx)(j,{location:e,children:W})}function Q(){return(0,f.jsx)(q.A,{children:(0,f.jsx)(R.l,{children:(0,f.jsxs)(T.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),N(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}};N(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/CellOverflow","path":"/tools/misti/docs/next/detectors/CellOverflow","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/SendInLoop","path":"/tools/misti/docs/next/detectors/SendInLoop","sidebar":"sidebar"},{"id":"detectors/ShortCircuitCondition","path":"/tools/misti/docs/next/detectors/ShortCircuitCondition","sidebar":"sidebar"},{"id":"detectors/StringReceiversOverlap","path":"/tools/misti/docs/next/detectors/StringReceiversOverlap","sidebar":"sidebar"},{"id":"detectors/SuspiciousMessageMode","path":"/tools/misti/docs/next/detectors/SuspiciousMessageMode","sidebar":"sidebar"},{"id":"detectors/UnboundLoop","path":"/tools/misti/docs/next/detectors/UnboundLoop","sidebar":"sidebar"},{"id":"detectors/UnboundMap","path":"/tools/misti/docs/next/detectors/UnboundMap","sidebar":"sidebar"},{"id":"detectors/UnusedExpressionResult","path":"/tools/misti/docs/next/detectors/UnusedExpressionResult","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":"tools/DumpImports","path":"/tools/misti/docs/next/tools/DumpImports","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.5","label":"0.5","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/CellOverflow","path":"/tools/misti/docs/detectors/CellOverflow","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/SendInLoop","path":"/tools/misti/docs/detectors/SendInLoop","sidebar":"sidebar"},{"id":"detectors/StringReceiversOverlap","path":"/tools/misti/docs/detectors/StringReceiversOverlap","sidebar":"sidebar"},{"id":"detectors/SuspiciousMessageMode","path":"/tools/misti/docs/detectors/SuspiciousMessageMode","sidebar":"sidebar"},{"id":"detectors/UnboundLoop","path":"/tools/misti/docs/detectors/UnboundLoop","sidebar":"sidebar"},{"id":"detectors/UnboundMap","path":"/tools/misti/docs/detectors/UnboundMap","sidebar":"sidebar"},{"id":"detectors/UnusedExpressionResult","path":"/tools/misti/docs/detectors/UnusedExpressionResult","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":"tools/DumpImports","path":"/tools/misti/docs/tools/DumpImports","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.4.0","label":"0.4.0","isLast":false,"path":"/tools/misti/docs/0.4.0","mainDocId":"intro","docs":[{"id":"detectors","path":"/tools/misti/docs/0.4.0/detectors","sidebar":"sidebar"},{"id":"detectors/ArgCopyMutation","path":"/tools/misti/docs/0.4.0/detectors/ArgCopyMutation","sidebar":"sidebar"},{"id":"detectors/AsmIsUsed","path":"/tools/misti/docs/0.4.0/detectors/AsmIsUsed","sidebar":"sidebar"},{"id":"detectors/BranchDuplicate","path":"/tools/misti/docs/0.4.0/detectors/BranchDuplicate","sidebar":"sidebar"},{"id":"detectors/ConstantAddress","path":"/tools/misti/docs/0.4.0/detectors/ConstantAddress","sidebar":"sidebar"},{"id":"detectors/DivideBeforeMultiply","path":"/tools/misti/docs/0.4.0/detectors/DivideBeforeMultiply","sidebar":"sidebar"},{"id":"detectors/DumpIsUsed","path":"/tools/misti/docs/0.4.0/detectors/DumpIsUsed","sidebar":"sidebar"},{"id":"detectors/DuplicatedCondition","path":"/tools/misti/docs/0.4.0/detectors/DuplicatedCondition","sidebar":"sidebar"},{"id":"detectors/EnsurePrgSeed","path":"/tools/misti/docs/0.4.0/detectors/EnsurePrgSeed","sidebar":"sidebar"},{"id":"detectors/FalseCondition","path":"/tools/misti/docs/0.4.0/detectors/FalseCondition","sidebar":"sidebar"},{"id":"detectors/FieldDoubleInit","path":"/tools/misti/docs/0.4.0/detectors/FieldDoubleInit","sidebar":"sidebar"},{"id":"detectors/InheritedStateMutation","path":"/tools/misti/docs/0.4.0/detectors/InheritedStateMutation","sidebar":"sidebar"},{"id":"detectors/NeverAccessedVariables","path":"/tools/misti/docs/0.4.0/detectors/NeverAccessedVariables","sidebar":"sidebar"},{"id":"detectors/OptimalMathFunction","path":"/tools/misti/docs/0.4.0/detectors/OptimalMathFunction","sidebar":"sidebar"},{"id":"detectors/PreferAugmentedAssign","path":"/tools/misti/docs/0.4.0/detectors/PreferAugmentedAssign","sidebar":"sidebar"},{"id":"detectors/PreferredStdlibApi","path":"/tools/misti/docs/0.4.0/detectors/PreferredStdlibApi","sidebar":"sidebar"},{"id":"detectors/ReadOnlyVariables","path":"/tools/misti/docs/0.4.0/detectors/ReadOnlyVariables","sidebar":"sidebar"},{"id":"detectors/StringReceiversOverlap","path":"/tools/misti/docs/0.4.0/detectors/StringReceiversOverlap","sidebar":"sidebar"},{"id":"detectors/UnboundLoops","path":"/tools/misti/docs/0.4.0/detectors/UnboundLoops","sidebar":"sidebar"},{"id":"detectors/UnusedOptional","path":"/tools/misti/docs/0.4.0/detectors/UnusedOptional","sidebar":"sidebar"},{"id":"detectors/ZeroAddress","path":"/tools/misti/docs/0.4.0/detectors/ZeroAddress","sidebar":"sidebar"},{"id":"hacking/contributing","path":"/tools/misti/docs/0.4.0/hacking/contributing","sidebar":"sidebar"},{"id":"hacking/custom-detector","path":"/tools/misti/docs/0.4.0/hacking/custom-detector","sidebar":"sidebar"},{"id":"hacking/design","path":"/tools/misti/docs/0.4.0/hacking/design","sidebar":"sidebar"},{"id":"hacking/developing-misti","path":"/tools/misti/docs/0.4.0/hacking/developing-misti","sidebar":"sidebar"},{"id":"hacking/souffle","path":"/tools/misti/docs/0.4.0/hacking/souffle","sidebar":"sidebar"},{"id":"intro","path":"/tools/misti/docs/0.4.0/","sidebar":"sidebar"},{"id":"tools","path":"/tools/misti/docs/0.4.0/tools","sidebar":"sidebar"},{"id":"tools/DumpAst","path":"/tools/misti/docs/0.4.0/tools/DumpAst","sidebar":"sidebar"},{"id":"tools/DumpCfg","path":"/tools/misti/docs/0.4.0/tools/DumpCfg","sidebar":"sidebar"},{"id":"tools/DumpConfig","path":"/tools/misti/docs/0.4.0/tools/DumpConfig","sidebar":"sidebar"},{"id":"tutorial/blueprint","path":"/tools/misti/docs/0.4.0/tutorial/blueprint","sidebar":"sidebar"},{"id":"tutorial/ci-cd","path":"/tools/misti/docs/0.4.0/tutorial/ci-cd","sidebar":"sidebar"},{"id":"tutorial/cli","path":"/tools/misti/docs/0.4.0/tutorial/cli","sidebar":"sidebar"},{"id":"tutorial/configuration","path":"/tools/misti/docs/0.4.0/tutorial/configuration","sidebar":"sidebar"},{"id":"tutorial/getting-started","path":"/tools/misti/docs/0.4.0/tutorial/getting-started","sidebar":"sidebar"}],"draftIds":[],"sidebars":{"sidebar":{"link":{"path":"/tools/misti/docs/0.4.0/","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}},"docusaurus-plugin-google-gtag":{"default":{"trackingID":["G-8VLF6VGHH5"],"anonymizeIP":true,"id":"default"}}}'),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"},"docusaurus-plugin-google-gtag":{"type":"package","name":"@docusaurus/plugin-google-gtag","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":b,autoAddBaseUrl:g=!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),D=C?.replace("pathname://","");let T=void 0!==D?(R=D,g&&(e=>e.startsWith("/"))(R)?_(R):R):void 0;var R;"hash"===x&&T?.startsWith("./")&&(T=T?.slice(1)),T&&E&&(T=(0,i.applyTrailingSlash)(T,{trailingSlash:w,baseUrl:k}));const L=(0,o.useRef)(!1),O=n?r.k2:r.N_,P=l.A.canUseIntersectionObserver,N=(0,o.useRef)(),I=()=>{L.current||null==T||(window.docusaurus.preload(T),L.current=!0)};(0,o.useEffect)((()=>(!P&&E&&null!=T&&window.docusaurus.prefetch(T),()=>{P&&N.current&&N.current.disconnect()})),[N,T,P,E]);const j=T?.startsWith("#")??!1,M=!v.target||"_self"===v.target,F=!T||!E||!M;return b||!j&&F||S.collectLink(T),v.id&&S.collectAnchor(v.id),F?(0,u.jsx)("a",{ref:A,href:T,...C&&!E&&{target:"_blank",rel:"noopener noreferrer"},...v}):(0,u.jsx)(O,{...v,onMouseEnter:I,onTouchStart:I,innerRef:e=>{A.current=e,P&&e&&E&&(N.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(N.current.unobserve(e),N.current.disconnect(),null!=T&&window.docusaurus.prefetch(T))}))})),N.current.observe(e))},to:T,...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:()=>b,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 b(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)}},1911:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});const o={onRouteDidUpdate(e){let{location:t,previousLocation:n}=e;!n||t.pathname===n.pathname&&t.search===n.search&&t.hash===n.hash||setTimeout((()=>{window.gtag("set","page_path",t.pathname+t.search+t.hash),window.gtag("event","page_view")}))}}},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 b=n(7559),g=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 D(){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 T=n(9876),R=n(3104);var L=n(9532),O=n(5600);const P=o.createContext(null);function N(e){let{children:t}=e;const n=function(){const e=(0,T.M)(),t=(0,O.YL)(),[n,r]=(0,o.useState)(!1),i=null!==t.component,s=(0,L.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)(P.Provider,{value:n,children:t})}function I(e){if(e.component){const t=e.component;return(0,d.jsx)(t,{...e.props})}}function j(){const e=(0,o.useContext)(P);if(!e)throw new L.dV("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,r=(0,o.useCallback)((()=>n(!1)),[n]),i=(0,O.YL)();return(0,o.useMemo)((()=>({shown:t,hide:r,content:I(i)})),[r,i,t])}function M(e){let{header:t,primaryMenu:n,secondaryMenu:o}=e;const{shown:i}=j();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),U=n(2303);function B(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,U.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)(B,{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,T.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 be="iconLanguage_nlXk";var ge=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],b=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:be}),b]}),items:h})},search:function(e){let{mobile:t,className:n}=e;return t?null:(0,d.jsx)(ye,{className:n,children:(0,d.jsx)(ge.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],b=(0,ke.Vd)(n)[0],g=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"}):b.label,v=t&&h.length>1?void 0:_e(b).path;return h.length<=1?(0,d.jsx)(ie,{...s,mobile:t,label:g,to:v,isActive:o?()=>!1:void 0}):(0,d.jsx)(fe,{...s,mobile:t,label:g,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,T.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 De(){const e=0===(0,w.p)().navbar.items.length,t=j();return(0,d.jsxs)(d.Fragment,{children:[!e&&(0,d.jsx)(Ee,{onClick:()=>t.hide()}),t.content]})}function Te(){const e=(0,T.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)(De,{})}):null}const Re={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Le(e){return(0,d.jsx)("div",{role:"presentation",...e,className:(0,r.A)("navbar-sidebar__backdrop",e.className)})}function Oe(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:i}}=(0,w.p)(),s=(0,T.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,R.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&&[Re.navbarHideable,!u&&Re.navbarHidden],{"navbar--dark":"dark"===i,"navbar--primary":"primary"===i,"navbar-sidebar--show":s.shown}),children:[t,(0,d.jsx)(Le,{onClick:s.toggle}),(0,d.jsx)(Te,{})]})}var Pe=n(440);const Ne={errorBoundaryError:"errorBoundaryError_a6uf",errorBoundaryFallback:"errorBoundaryFallback_VBag"};function Ie(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 je(e){let{error:t}=e;const n=(0,Pe.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,d.jsx)("p",{className:Ne.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 Ue(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 Be(){const{toggle:e,shown:t}=(0,T.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)(Ue,{})})}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,T.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)(Be,{}),(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)(ge.A,{})})]})})}function He(){return(0,d.jsx)(Oe,{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,L.fM)([F.a,k.o,R.Tv,xe.VQ,s.Jx,function(e){let{children:t}=e;return(0,d.jsx)(O.y_,{children:(0,d.jsx)(T.e,{children:(0,d.jsx)(N,{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)(Ie,{onClick:n,className:"button button--primary shadow--lw"})}),(0,d.jsx)("hr",{}),(0,d.jsx)("div",{className:"margin-vert--md",children:(0,d.jsx)(je,{error:t})})]})})})}const pt={mainWrapper:"mainWrapper_z2l0"};function ft(e){const{children:t,noFooter:n,wrapperClassName:o,title:a,description:l}=e;return(0,g.J)(),(0,d.jsxs)(ct,{children:[(0,d.jsx)(s.be,{title:a,description:l}),(0,d.jsx)(y,{}),(0,d.jsx)(D,{}),(0,d.jsx)(He,{}),(0,d.jsx)("div",{id:u,className:(0,r.A)(b.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:()=>g,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 b(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 g(e){let{lazy:t,...n}=e;const o=t?b: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:()=>g,a:()=>b});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 b(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 g(){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:()=>g,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 b(e){let{children:t}=e;const n=h();return(0,d.jsx)(m.Provider,{value:n,children:t})}function g(e){let{children:t}=e;return a.C5?(0,d.jsx)(b,{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:()=>b,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=>b(e,t)));function b(e,t){return"link"===e.type?m(e.href,t):"category"===e.type&&(m(e.href,t)||h(e.items,t))}function g(e,t){switch(e.type){case"category":return b(e,t)||e.items.some((e=>g(e,t)));case"link":return!e.unlisted||b(e,t);default:return!0}}function v(e,t){return(0,o.useMemo)((()=>e.filter((e=>g(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:()=>D,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 b(e,t){t(window.confirm(e))}var g="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?b: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 D=m();function T(e){(0,o.A)(z,e),z.length=n.length,D.notifyListeners(z.location,z.action)}function R(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||P(C(e.state))}function L(){P(C(y()))}var O=!1;function P(e){if(O)O=!1,T();else{D.confirmTransitionTo(e,"POP",x,(function(t){t?T({action:"POP",location:e}):function(e){var t=z.location,n=I.indexOf(t.key);-1===n&&(n=0);var o=I.indexOf(e.key);-1===o&&(o=0);var r=n-o;r&&(O=!0,M(r))}(e)}))}}var N=C(y()),I=[N.key];function j(e){return A+p(e)}function M(e){n.go(e)}var F=0;function U(e){1===(F+=e)&&1===e?(window.addEventListener(g,R),i&&window.addEventListener(v,L)):0===F&&(window.removeEventListener(g,R),i&&window.removeEventListener(v,L))}var B=!1;var z={length:n.length,action:"POP",location:N,createHref:j,push:function(e,t){var o="PUSH",i=f(e,t,E(),z.location);D.confirmTransitionTo(i,o,x,(function(e){if(e){var t=j(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=I.indexOf(z.location.key),c=I.slice(0,l+1);c.push(i.key),I=c,T({action:o,location:i})}else window.location.href=t}}))},replace:function(e,t){var o="REPLACE",i=f(e,t,E(),z.location);D.confirmTransitionTo(i,o,x,(function(e){if(e){var t=j(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=I.indexOf(z.location.key);-1!==l&&(I[l]=i.key),T({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=D.setPrompt(e);return B||(U(1),B=!0),function(){return B&&(B=!1,U(-1)),t()}},listen:function(e){var t=D.appendListener(e);return U(1),function(){U(-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?b:r,s=n.hashType,c=void 0===s?"slash":s,g=e.basename?u(l(e.basename)):"",v=x[c],y=v.encodePath,w=v.decodePath;function C(){var e=w(S());return g&&(e=d(e,g)),f(e)}var E=m();function D(e){(0,o.A)(B,e),B.length=t.length,E.notifyListeners(B.location,B.action)}var T=!1,R=null;function L(){var e,t,n=S(),o=y(n);if(n!==o)A(o);else{var r=C(),s=B.location;if(!T&&(t=r,(e=s).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(R===p(r))return;R=null,function(e){if(T)T=!1,D();else{var t="POP";E.confirmTransitionTo(e,t,i,(function(n){n?D({action:t,location:e}):function(e){var t=B.location,n=I.lastIndexOf(p(t));-1===n&&(n=0);var o=I.lastIndexOf(p(e));-1===o&&(o=0);var r=n-o;r&&(T=!0,j(r))}(e)}))}}(r)}}var O=S(),P=y(O);O!==P&&A(P);var N=C(),I=[p(N)];function j(e){t.go(e)}var M=0;function F(e){1===(M+=e)&&1===e?window.addEventListener(k,L):0===M&&window.removeEventListener(k,L)}var U=!1;var B={length:t.length,action:"POP",location:N,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=_(window.location.href)),n+"#"+y(g+p(e))},push:function(e,t){var n="PUSH",o=f(e,void 0,void 0,B.location);E.confirmTransitionTo(o,n,i,(function(e){if(e){var t=p(o),r=y(g+t);if(S()!==r){R=t,function(e){window.location.hash=e}(r);var i=I.lastIndexOf(p(B.location)),s=I.slice(0,i+1);s.push(t),I=s,D({action:n,location:o})}else D()}}))},replace:function(e,t){var n="REPLACE",o=f(e,void 0,void 0,B.location);E.confirmTransitionTo(o,n,i,(function(e){if(e){var t=p(o),r=y(g+t);S()!==r&&(R=t,A(r));var i=I.indexOf(p(B.location));-1!==i&&(I[i]=t),D({action:n,location:o})}}))},go:j,goBack:function(){j(-1)},goForward:function(){j(1)},block:function(e){void 0===e&&(e=!1);var t=E.setPrompt(e);return U||(F(1),U=!0),function(){return U&&(U=!1,F(-1)),t()}},listen:function(e){var t=E.appendListener(e);return F(1),function(){F(-1),t()}}};return B}function E(e,t,n){return Math.min(Math.max(e,t),n)}function D(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 b=E(a,0,i.length-1),g=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:g.length,action:"POP",location:g[b],index:b,entries:g,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),b=0;b<s.length;++b){var g=s[b];if(!(i[g]||o&&o[g]||h&&h[g]||a&&a[g])){var v=p(n,g);try{c(t,g,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 b=l[h];t(b&&b.modify,(function(e){e in u&&(p[e]=!0)}))}for(var g in u)if(!(g in d))for(var v in f(g))if(v in d){p[g]=!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 b={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){b[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];b[t]=new h(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){b[e]=new h(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){b[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){b[e]=new h(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){b[e]=new h(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){b[e]=new h(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){b[e]=new h(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){b[e]=new h(e,5,!1,e.toLowerCase(),null,!1,!1)}));var g=/[\-:]([a-z])/g;function v(e){return e[1].toUpperCase()}function y(e,t,n,o){var r=b.hasOwnProperty(t)?b[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(g,v);b[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(g,v);b[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(g,v);b[t]=new h(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){b[e]=new h(e,1,!1,e.toLowerCase(),null,!1,!1)})),b.xlinkHref=new h("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){b[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"),D=Symbol.for("react.forward_ref"),T=Symbol.for("react.suspense"),R=Symbol.for("react.suspense_list"),L=Symbol.for("react.memo"),O=Symbol.for("react.lazy");Symbol.for("react.scope"),Symbol.for("react.debug_trace_mode");var P=Symbol.for("react.offscreen");Symbol.for("react.legacy_hidden"),Symbol.for("react.cache"),Symbol.for("react.tracing_marker");var N=Symbol.iterator;function I(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=N&&e[N]||e["@@iterator"])?e:null}var j,M=Object.assign;function F(e){if(void 0===j)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);j=t&&t[1]||""}return"\n"+j+e}var U=!1;function B(e,t){if(!e||U)return"";U=!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{U=!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=B(e.type,!1);case 11:return e=B(e.type.render,!1);case 1:return e=B(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 T:return"Suspense";case R: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 D:var t=e.render;return(e=e.displayName)||(e=""!==(e=t.displayName||t.name||"")?"ForwardRef("+e+")":"ForwardRef"),e;case L:return null!==(t=e.displayName||null)?t:$(e.type)||"Memo";case O: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 be(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 ge=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(ge[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 De(e,t){return e(t)}function Te(){}var Re=!1;function Le(e,t,n){if(Re)return e(t,n);Re=!0;try{return De(e,t,n)}finally{Re=!1,(null!==_e||null!==Se)&&(Te(),Ee())}}function Oe(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 Pe=!1;if(d)try{var Ne={};Object.defineProperty(Ne,"passive",{get:function(){Pe=!0}}),window.addEventListener("test",Ne,Ne),window.removeEventListener("test",Ne,Ne)}catch(de){Pe=!1}function Ie(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 je=!1,Me=null,Fe=!1,Ue=null,Be={onError:function(e){je=!0,Me=e}};function ze(e,t,n,o,r,i,s,a,l){je=!1,Me=null,Ie.apply(Be,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 bt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function gt(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=[],Dt=null,Tt=null,Rt=null,Lt=new Map,Ot=new Map,Pt=[],Nt="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 It(e,t){switch(e){case"focusin":case"focusout":Dt=null;break;case"dragenter":case"dragleave":Tt=null;break;case"mouseover":case"mouseout":Rt=null;break;case"pointerover":case"pointerout":Lt.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":Ot.delete(t.pointerId)}}function jt(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 Ut(e,t,n){Ft(e)&&n.delete(t)}function Bt(){Ct=!1,null!==Dt&&Ft(Dt)&&(Dt=null),null!==Tt&&Ft(Tt)&&(Tt=null),null!==Rt&&Ft(Rt)&&(Rt=null),Lt.forEach(Ut),Ot.forEach(Ut)}function zt(e,t){e.blockedOn===t&&(e.blockedOn=null,Ct||(Ct=!0,r.unstable_scheduleCallback(r.unstable_NormalPriority,Bt)))}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!==Dt&&zt(Dt,e),null!==Tt&&zt(Tt,e),null!==Rt&&zt(Rt,e),Lt.forEach(t),Ot.forEach(t),n=0;n<Pt.length;n++)(o=Pt[n]).blockedOn===e&&(o.blockedOn=null);for(;0<Pt.length&&null===(n=Pt[0]).blockedOn;)Mt(n),null===n.blockedOn&&Pt.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),It(e,o);else if(function(e,t,n,o,r){switch(t){case"focusin":return Dt=jt(Dt,e,t,n,o,r),!0;case"dragenter":return Tt=jt(Tt,e,t,n,o,r),!0;case"mouseover":return Rt=jt(Rt,e,t,n,o,r),!0;case"pointerover":var i=r.pointerId;return Lt.set(i,jt(Lt.get(i)||null,e,t,n,o,r)),!0;case"gotpointercapture":return i=r.pointerId,Ot.set(i,jt(Ot.get(i)||null,e,t,n,o,r)),!0}return!1}(r,e,t,n,o))o.stopPropagation();else if(It(e,o),4&t&&-1<Nt.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})),bn=rn(M({},un,{relatedTarget:0})),gn=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),Dn=rn(M({},fn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),Tn=rn(M({},un,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:An})),Rn=rn(M({},cn,{propertyName:0,elapsedTime:0,pseudoElement:0})),Ln=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}),On=rn(Ln),Pn=[9,13,27,32],Nn=d&&"CompositionEvent"in window,In=null;d&&"documentMode"in document&&(In=document.documentMode);var jn=d&&"TextEvent"in window&&!In,Mn=d&&(!Nn||In&&8<In&&11>=In),Fn=String.fromCharCode(32),Un=!1;function Bn(e,t){switch(e){case"keyup":return-1!==Pn.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){Uo(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)),Le(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 bo=d&&"documentMode"in document&&11>=document.documentMode,go=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==go||go!==Z(o)||("selectionStart"in(o=go)&&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=go)))}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"),Do=Co("animationiteration"),To=Co("animationstart"),Ro=Co("transitionend"),Lo=new Map,Oo="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 Po(e,t){Lo.set(e,t),l(t,[e])}for(var No=0;No<Oo.length;No++){var Io=Oo[No];Po(Io.toLowerCase(),"on"+(Io[0].toUpperCase()+Io.slice(1)))}Po(Eo,"onAnimationEnd"),Po(Do,"onAnimationIteration"),Po(To,"onAnimationStart"),Po("dblclick","onDoubleClick"),Po("focusin","onFocus"),Po("focusout","onBlur"),Po(Ro,"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 jo="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(jo));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),je){if(!je)throw Error(i(198));var d=Me;je=!1,Me=null,Fe||(Fe=!0,Ue=d)}}(o,t,void 0,e),e.currentTarget=null}function Uo(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=Ue,Fe=!1,Ue=null,e}function Bo(e,t){var n=t[br];void 0===n&&(n=t[br]=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,!Pe||"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}Le((function(){var o=i,r=ke(n),s=[];e:{var a=Lo.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=bn;break;case"focusout":c="blur",l=bn;break;case"beforeblur":case"afterblur":l=bn;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=Tn;break;case Eo:case Do:case To:l=gn;break;case Ro:l=Rn;break;case"scroll":l=pn;break;case"wheel":l=On;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=Dn}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=Oe(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=Dn,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 b=Kn;else if(qn(a))if(Yn)b=so;else{b=ro;var g=oo}else(l=a.nodeName)&&"input"===l.toLowerCase()&&("checkbox"===a.type||"radio"===a.type)&&(b=io);switch(b&&(b=b(e,o))?Hn(s,b,n,r):(g&&g(e,a,o),"focusout"===e&&(g=a._wrapperState)&&g.controlled&&"number"===a.type&&ee(a,"number",a.value)),g=o?kr(o):window,e){case"focusin":(qn(g)||"true"===g.contentEditable)&&(go=g,vo=o,yo=null);break;case"focusout":yo=vo=go=null;break;case"mousedown":wo=!0;break;case"contextmenu":case"mouseup":case"dragend":wo=!1,ko(s,n,r);break;case"selectionchange":if(bo)break;case"keydown":case"keyup":ko(s,n,r)}var v;if(Nn)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?Bn(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<(g=Wo(o,y)).length&&(y=new wn(y,e,null,n,r),s.push({event:y,listeners:g}),v?y.data=v:null!==(v=zn(n))&&(y.data=v))),(v=jn?function(e,t){switch(e){case"compositionend":return zn(t);case"keypress":return 32!==t.which?null:(Un=!0,Fn);case"textInput":return(e=t.data)===Fn&&Un?null:e;default:return null}}(e,n):function(e,t){if($n)return"compositionend"===e||!Nn&&Bn(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))}Uo(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=Oe(e,n))&&o.unshift(Go(e,i,r)),null!=(i=Oe(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=Oe(n,i))&&s.unshift(Go(n,l,a)):r||null!=(l=Oe(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,br="__reactEvents$"+pr,gr="__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 Dr={},Tr=Ar(Dr),Rr=Ar(!1),Lr=Dr;function Or(e,t){var n=e.type.contextTypes;if(!n)return Dr;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 Pr(e){return null!=(e=e.childContextTypes)}function Nr(){Cr(Rr),Cr(Tr)}function Ir(e,t,n){if(Tr.current!==Dr)throw Error(i(168));Er(Tr,t),Er(Rr,n)}function jr(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||Dr,Lr=Tr.current,Er(Tr,e),Er(Rr,Rr.current),!0}function Fr(e,t,n){var o=e.stateNode;if(!o)throw Error(i(169));n?(e=jr(e,t,Lr),o.__reactInternalMemoizedMergedChildContext=e,Cr(Rr),Cr(Tr),Er(Tr,e)):Cr(Rr),Er(Rr,n)}var Ur=null,Br=!1,zr=!1;function $r(e){null===Ur?Ur=[e]:Ur.push(e)}function Vr(){if(!zr&&null!==Ur){zr=!0;var e=0,t=yt;try{var n=Ur;for(yt=1;e<n.length;e++){var o=n[e];do{o=o(!0)}while(null!==o)}Ur=null,Br=!1}catch(r){throw null!==Ur&&(Ur=Ur.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=Lc(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=Lc(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 bi=w.ReactCurrentBatchConfig;function gi(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=Pc(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===O&&yi(i)===t.type)?((o=r(t,n.props)).ref=gi(e,t,n),o.return=e,o):((o=Nc(n.type,n.key,n.props,null,e.mode,o)).ref=gi(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=Ic(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=Nc(t.type,t.key,t.props,null,e.mode,n)).ref=gi(e,null,t),n.return=e,n;case x:return(t=Fc(t,e.mode,n)).return=e,t;case O:return p(e,(0,t._init)(t._payload),n)}if(te(t)||I(t))return(t=Ic(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 O:return f(e,t,(r=n._init)(n._payload),o)}if(te(n)||I(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 O:return m(e,t,n,(0,o._init)(o._payload),r)}if(te(o)||I(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,b=null;null!==u&&h<a.length;h++){u.index>h?(b=u,u=null):b=u.sibling;var g=f(r,u,a[h],l);if(null===g){null===u&&(u=b);break}e&&u&&null===g.alternate&&t(r,u),i=s(g,i,h),null===d?c=g:d.sibling=g,d=g,u=b}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!==(b=m(u,r,h,a[h],l))&&(e&&null!==b.alternate&&u.delete(null===b.key?h:b.key),i=s(b,i,h),null===d?c=b:d.sibling=b,d=b);return e&&u.forEach((function(e){return t(r,e)})),ii&&Jr(r,h),c}function b(r,a,l,c){var d=I(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,b=a=0,g=null,v=l.next();null!==h&&!v.done;b++,v=l.next()){h.index>b?(g=h,h=null):g=h.sibling;var y=f(r,h,v.value,c);if(null===y){null===h&&(h=g);break}e&&h&&null===y.alternate&&t(r,h),a=s(y,a,b),null===u?d=y:u.sibling=y,u=y,h=g}if(v.done)return n(r,h),ii&&Jr(r,b),d;if(null===h){for(;!v.done;b++,v=l.next())null!==(v=p(r,v.value,c))&&(a=s(v,a,b),null===u?d=v:u.sibling=v,u=v);return ii&&Jr(r,b),d}for(h=o(r,h);!v.done;b++,v=l.next())null!==(v=m(h,r,b,v.value,c))&&(e&&null!==v.alternate&&h.delete(null===v.key?b:v.key),a=s(v,a,b),null===u?d=v:u.sibling=v,u=v);return e&&h.forEach((function(e){return t(r,e)})),ii&&Jr(r,b),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===O&&yi(c)===d.type){n(o,d.sibling),(i=r(d,s.props)).ref=gi(o,d,s),i.return=o,o=i;break e}n(o,d);break}t(o,d),d=d.sibling}s.type===_?((i=Ic(s.props.children,o.mode,l,s.key)).return=o,o=i):((l=Nc(s.type,s.key,s.props,null,o.mode,l)).ref=gi(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 O:return e(o,i,(d=s._init)(s._payload),l)}if(te(s))return h(o,i,s,l);if(I(s))return b(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 Di(e){var t=_i.current;Cr(_i),e._currentValue=t}function Ti(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 Ri(e,t){Si=e,Ci=Ai=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(!!(e.lanes&t)&&(ya=!0),e.firstContext=null)}function Li(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 Oi=null;function Pi(e){null===Oi?Oi=[e]:Oi.push(e)}function Ni(e,t,n,o){var r=t.interleaved;return null===r?(n.next=n,Pi(t)):(n.next=r.next,r.next=n),t.interleaved=n,Ii(e,o)}function Ii(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 ji=!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 Ui(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function Bi(e,t,n){var o=e.updateQueue;if(null===o)return null;if(o=o.shared,2&Dl){var r=o.pending;return null===r?t.next=t:(t.next=r.next,r.next=t),o.pending=t,Ii(e,n)}return null===(r=o.interleaved)?(t.next=t,Pi(o)):(t.next=r.next,r.next=t),o.interleaved=t,Ii(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;ji=!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:ji=!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);jl|=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 bs(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 gs(){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,jl|=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,jl|=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,js(Es.bind(null,n,o,e),[e]),o.getSnapshot!==t||s||null!==cs&&1&cs.memoizedState.tag){if(n.flags|=2048,Ls(9,Cs.bind(null,n,o,r,t),void 0,null),null===Tl)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,Ds(t)&&Ts(e)}function Es(e,t,n){return n((function(){Ds(t)&&Ts(e)}))}function Ds(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!ao(e,n)}catch(o){return!0}}function Ts(e){var t=Ii(e,1);null!==t&&nc(t,e,1,-1)}function Rs(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 Ls(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 Os(){return ys().memoizedState}function Ps(e,t,n,o){var r=vs();as.flags|=e,r.memoizedState=Ls(1|t,n,void 0,void 0===o?null:o)}function Ns(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=Ls(t,n,i,o))}as.flags|=e,r.memoizedState=Ls(1|t,n,i,o)}function Is(e,t){return Ps(8390656,8,e,t)}function js(e,t){return Ns(2048,8,e,t)}function Ms(e,t){return Ns(4,2,e,t)}function Fs(e,t){return Ns(4,4,e,t)}function Us(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 Bs(e,t,n){return n=null!=n?n.concat([e]):null,Ns(4,4,Us.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,jl|=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=Ni(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,Pi(t)):(r.next=l.next,l.next=r),void(t.interleaved=r)}}catch(c){}null!==(n=Ni(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:Li,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:Li,useCallback:function(e,t){return vs().memoizedState=[e,void 0===t?null:t],e},useContext:Li,useEffect:Is,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,Ps(4194308,4,Us.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Ps(4194308,4,e,t)},useInsertionEffect:function(e,t){return Ps(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:Rs,useDebugValue:zs,useDeferredValue:function(e){return vs().memoizedState=e},useTransition:function(){var e=Rs(!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===Tl)throw Error(i(349));30&ss||As(o,t,n)}r.memoizedState=n;var s={value:n,getSnapshot:t};return r.queue=s,Is(Es.bind(null,o,s,e),[e]),o.flags|=2048,Ls(9,Cs.bind(null,o,s,n,t),void 0,null),n},useId:function(){var e=vs(),t=Tl.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:Li,useCallback:$s,useContext:Li,useEffect:js,useImperativeHandle:Bs,useInsertionEffect:Ms,useLayoutEffect:Fs,useMemo:Vs,useReducer:ks,useRef:Os,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:Li,useCallback:$s,useContext:Li,useEffect:js,useImperativeHandle:Bs,useInsertionEffect:Ms,useLayoutEffect:Fs,useMemo:Vs,useReducer:xs,useRef:Os,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=Ui(o,r);i.payload=t,null!=n&&(i.callback=n),null!==(t=Bi(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=Ui(o,r);i.tag=1,i.payload=t,null!=n&&(i.callback=n),null!==(t=Bi(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=Ui(n,o);r.tag=2,null!=t&&(r.callback=t),null!==(t=Bi(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=Dr,i=t.contextType;return"object"==typeof i&&null!==i?i=Li(i):(r=Pr(t)?Lr:Tr.current,i=(o=null!=(o=t.contextTypes))?Or(e,r):Dr),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=Li(i):(i=Pr(t)?Lr:Tr.current,r.context=Or(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=Ui(-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=Ui(-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 ba(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 ga(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=Ui(-1,1)).tag=2,Bi(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 Ri(t,r),o=bs(e,t,n,o,i,r),n=gs(),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||Oc(i)||void 0!==i.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Nc(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=Pc(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(Pl,Ol),Ol|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},o=null!==i?i.baseLanes:n,Er(Pl,Ol),Ol|=o}else t.memoizedState={baseLanes:0,cachePool:null,transitions:null},Er(Pl,Ol),Ol|=n;else null!==i?(o=i.baseLanes|n,t.memoizedState=null):o=n,Er(Pl,Ol),Ol|=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=Pr(n)?Lr:Tr.current;return i=Or(t,i),Ri(t,r),n=bs(e,t,n,o,i,r),o=gs(),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(Pr(n)){var i=!0;Mr(t)}else i=!1;if(Ri(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=Li(c):c=Or(t,c=Pr(n)?Lr:Tr.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),ji=!1;var p=t.memoizedState;s.state=p,Vi(t,o,s,r),l=t.memoizedState,a!==o||p!==l||Rr.current||ji?("function"==typeof d&&(oa(t,n,d,o),l=t.memoizedState),(a=ji||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=Li(l):l=Or(t,l=Pr(n)?Lr:Tr.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),ji=!1,p=t.memoizedState,s.state=p,Vi(t,o,s,r);var m=t.memoizedState;a!==u||p!==m||Rr.current||ji?("function"==typeof f&&(oa(t,n,f,o),m=t.memoizedState),(c=ji||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 Da(e,t,n,o,i,r)}function Da(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 Ta(e){var t=e.stateNode;t.pendingContext?Ir(0,t.pendingContext,t.pendingContext!==t.context):t.context&&Ir(0,t.context,!1),Ki(e,t.containerInfo)}function Ra(e,t,n,o,r){return mi(),hi(r),t.flags|=256,wa(e,t,n,o),t.child}var La,Oa,Pa,Na,Ia={dehydrated:null,treeContext:null,retryLane:0};function ja(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=jc(l,r,0,null):(a.childLanes=0,a.pendingProps=l),e=Ic(e,r,n,null),a.return=t,e.return=t,a.sibling=e,t.child=a,t.child.memoizedState=ja(n),t.memoizedState=Ia,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,Ua(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=jc({mode:"visible",children:o.children},r,0,null),(s=Ic(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=ja(a),t.memoizedState=Ia,s);if(!(1&t.mode))return Ua(e,t,a,null);if("$!"===r.data){if(o=r.nextSibling&&r.nextSibling.dataset)var l=o.dgst;return o=l,Ua(e,t,a,o=da(s=Error(i(419)),o,void 0))}if(l=!!(a&e.childLanes),ya||l){if(null!==(o=Tl)){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,Ii(e,r),nc(o,e,r,-1))}return hc(),Ua(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=Pc(s,c)).subtreeFlags=14680064&s.subtreeFlags:((r=t.child).childLanes=0,r.pendingProps=c,t.deletions=null),null!==o?a=Pc(o,a):(a=Ic(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)?ja(n):{baseLanes:l.baseLanes|n,cachePool:null,transitions:l.transitions},a.memoizedState=l,a.childLanes=e.childLanes&~n,t.memoizedState=Ia,r}return e=(a=e.child).sibling,r=Pc(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=jc({mode:"visible",children:t},e.mode,0,null)).return=e,e.child=t}function Ua(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 Ba(e,t,n){e.lanes|=t;var o=e.alternate;null!==o&&(o.lanes|=t),Ti(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&&Ba(e,n,t);else if(19===e.tag)Ba(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),jl|=t.lanes,!(n&t.childLanes))return null;if(null!==e&&t.child!==e.child)throw Error(i(153));if(null!==t.child){for(n=Pc(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Pc(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 Pr(t.type)&&Nr(),Ga(t),null;case 3:return o=t.stateNode,Yi(),Cr(Rr),Cr(Tr),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))),Oa(e,t),Ga(t),null;case 5:Ji(t);var r=Qi(Zi.current);if(n=t.type,null!==e&&null!=t.stateNode)Pa(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":Bo("cancel",o),Bo("close",o);break;case"iframe":case"object":case"embed":Bo("load",o);break;case"video":case"audio":for(r=0;r<jo.length;r++)Bo(jo[r],o);break;case"source":Bo("error",o);break;case"img":case"image":case"link":Bo("error",o),Bo("load",o);break;case"details":Bo("toggle",o);break;case"input":K(o,s),Bo("invalid",o);break;case"select":o._wrapperState={wasMultiple:!!s.multiple},Bo("invalid",o);break;case"textarea":re(o,s),Bo("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&&Bo("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,La(e,t,!1,!1),t.stateNode=e;e:{switch(l=ye(n,o),n){case"dialog":Bo("cancel",e),Bo("close",e),r=o;break;case"iframe":case"object":case"embed":Bo("load",e),r=o;break;case"video":case"audio":for(r=0;r<jo.length;r++)Bo(jo[r],e);r=o;break;case"source":Bo("error",e),r=o;break;case"img":case"image":case"link":Bo("error",e),Bo("load",e),r=o;break;case"details":Bo("toggle",e),r=o;break;case"input":K(e,o),r=Q(e,o),Bo("invalid",e);break;case"option":default:r=o;break;case"select":e._wrapperState={wasMultiple:!!o.multiple},r=M({},o,{value:void 0}),Bo("invalid",e);break;case"textarea":re(e,o),r=oe(e,o),Bo("invalid",e)}for(s in ve(n,r),c=r)if(c.hasOwnProperty(s)){var d=c[s];"style"===s?be(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&&Bo("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)Na(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===Nl&&(Nl=3):hc())),null!==t.updateQueue&&(t.flags|=4),Ga(t),null);case 4:return Yi(),Oa(e,t),null===e&&Vo(t.stateNode.containerInfo),Ga(t),null;case 10:return Di(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!==Nl||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&Ol)&&(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 Pr(t.type)&&Nr(),65536&(e=t.flags)?(t.flags=-65537&e|128,t):null;case 3:return Yi(),Cr(Rr),Cr(Tr),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 Di(t.type._context),null;case 22:case 23:return uc(),null;default:return null}}La=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}},Oa=function(){},Pa=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&&Bo("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)}},Na=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[br],delete t[gr],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=Dc.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;)bl(t,e),t=t.sibling}function bl(e,t){var n=e.alternate,o=e.flags;switch(e.tag){case 0:case 11:case 14:case 15:if(hl(t,e),gl(e),4&o){try{nl(3,e,e.return),ol(3,e)}catch(b){Sc(e,e.return,b)}try{nl(5,e,e.return)}catch(b){Sc(e,e.return,b)}}break;case 1:hl(t,e),gl(e),512&o&&null!==n&&Ja(n,n.return);break;case 5:if(hl(t,e),gl(e),512&o&&null!==n&&Ja(n,n.return),32&e.flags){var r=e.stateNode;try{pe(r,"")}catch(b){Sc(e,e.return,b)}}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?be(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(b){Sc(e,e.return,b)}}break;case 6:if(hl(t,e),gl(e),4&o){if(null===e.stateNode)throw Error(i(162));r=e.stateNode,s=e.memoizedProps;try{r.nodeValue=s}catch(b){Sc(e,e.return,b)}}break;case 3:if(hl(t,e),gl(e),4&o&&null!==n&&n.memoizedState.isDehydrated)try{$t(t.containerInfo)}catch(b){Sc(e,e.return,b)}break;case 4:default:hl(t,e),gl(e);break;case 13:hl(t,e),gl(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),gl(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(b){Sc(o,n,b)}}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(b){Sc(e,e.return,b)}}}else if(6===p.tag){if(null===u)try{p.stateNode.nodeValue=d?"":p.memoizedProps}catch(b){Sc(e,e.return,b)}}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),gl(e),4&o&&ml(e);case 21:}}function gl(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,Dl=0,Tl=null,Rl=null,Ll=0,Ol=0,Pl=Ar(0),Nl=0,Il=null,jl=0,Ml=0,Fl=0,Ul=null,Bl=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&Dl?Ye():-1!==Xl?Xl:Xl=Ye()}function tc(e){return 1&e.mode?2&Dl&&0!==Ll?Ll&-Ll:null!==bi.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));gt(e,n,o),2&Dl&&e===Tl||(e===Tl&&(!(2&Dl)&&(Ml|=n),4===Nl&&ac(e,Ll)),oc(e,o),1===n&&0===Dl&&!(1&t.mode)&&($l=Ye()+500,Br&&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===Tl?Ll: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){Br=!0,$r(e)}(lc.bind(null,e)):$r(lc.bind(null,e)),ar((function(){!(6&Dl)&&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=Tc(n,rc.bind(null,e))}e.callbackPriority=t,e.callbackNode=n}}function rc(e,t){if(Xl=-1,Jl=0,6&Dl)throw Error(i(327));var n=e.callbackNode;if(xc()&&e.callbackNode!==n)return null;var o=pt(e,e===Tl?Ll:0);if(0===o)return null;if(30&o||o&e.expiredLanes||t)t=bc(e,o);else{t=o;var r=Dl;Dl|=2;var s=mc();for(Tl===e&&Ll===t||(Vl=null,$l=Ye()+500,pc(e,t));;)try{vc();break}catch(l){fc(e,l)}Ei(),Al.current=s,Dl=r,null!==Rl?t=0:(Tl=null,Ll=0,t=Nl)}if(0!==t){if(2===t&&(0!==(r=mt(e))&&(o=r,t=ic(e,r))),1===t)throw n=Il,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=bc(e,o),2===t&&(s=mt(e),0!==s&&(o=s,t=ic(e,s))),1!==t)))throw n=Il,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,Bl,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,Bl,Vl),t);break}kc(e,Bl,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,Bl,Vl),o);break}kc(e,Bl,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=Ul;return e.current.memoizedState.isDehydrated&&(pc(e,t).flags|=256),2!==(e=bc(e,t))&&(t=Bl,Bl=n,null!==t&&sc(t)),e}function sc(e){null===Bl?Bl=e:Bl.push.apply(Bl,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&Dl)throw Error(i(327));xc();var t=pt(e,0);if(!(1&t))return oc(e,Ye()),null;var n=bc(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=Il,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,Bl,Vl),oc(e,Ye()),null}function cc(e,t){var n=Dl;Dl|=1;try{return e(t)}finally{0===(Dl=n)&&($l=Ye()+500,Br&&Vr())}}function dc(e){null!==Zl&&0===Zl.tag&&!(6&Dl)&&xc();var t=Dl;Dl|=1;var n=El.transition,o=yt;try{if(El.transition=null,yt=1,e)return e()}finally{yt=o,El.transition=n,!(6&(Dl=t))&&Vr()}}function uc(){Ol=Pl.current,Cr(Pl)}function pc(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,ir(n)),null!==Rl)for(n=Rl.return;null!==n;){var o=n;switch(ni(o),o.tag){case 1:null!=(o=o.type.childContextTypes)&&Nr();break;case 3:Yi(),Cr(Rr),Cr(Tr),os();break;case 5:Ji(o);break;case 4:Yi();break;case 13:case 19:Cr(es);break;case 10:Di(o.type._context);break;case 22:case 23:uc()}n=n.return}if(Tl=e,Rl=e=Pc(e.current,null),Ll=Ol=t,Nl=0,Il=null,Fl=Ml=jl=0,Bl=Ul=null,null!==Oi){for(t=0;t<Oi.length;t++)if(null!==(o=(n=Oi[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}Oi=null}return e}function fc(e,t){for(;;){var n=Rl;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){Nl=1,Il=t,Rl=null;break}e:{var s=e,a=n.return,l=n,c=t;if(t=Ll,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=ba(a);if(null!==m){m.flags&=-257,ga(m,a,l,0,t),1&m.mode&&ha(s,d,t),c=d;var h=(t=m).updateQueue;if(null===h){var b=new Set;b.add(c),t.updateQueue=b}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 g=ba(a);if(null!==g){!(65536&g.flags)&&(g.flags|=256),ga(g,a,l,0,t),hi(ca(c,l));break e}}s=c=ca(c,l),4!==Nl&&(Nl=2),null===Ul?Ul=[s]:Ul.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,Rl===n&&null!==n&&(Rl=n=n.return);continue}break}}function mc(){var e=Al.current;return Al.current=Xs,null===e?Xs:e}function hc(){0!==Nl&&3!==Nl&&2!==Nl||(Nl=4),null===Tl||!(268435455&jl)&&!(268435455&Ml)||ac(Tl,Ll)}function bc(e,t){var n=Dl;Dl|=2;var o=mc();for(Tl===e&&Ll===t||(Vl=null,pc(e,t));;)try{gc();break}catch(r){fc(e,r)}if(Ei(),Dl=n,Al.current=o,null!==Rl)throw Error(i(261));return Tl=null,Ll=0,Nl}function gc(){for(;null!==Rl;)yc(Rl)}function vc(){for(;null!==Rl&&!Qe();)yc(Rl)}function yc(e){var t=_l(e.alternate,e,Ol);e.memoizedProps=e.pendingProps,null===t?wc(e):Rl=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(Rl=n);if(null===e)return Nl=6,void(Rl=null);e.flags|=32768,e.subtreeFlags=0,e.deletions=null}else if(null!==(n=Wa(n,t,Ol)))return void(Rl=n);if(null!==(t=t.sibling))return void(Rl=t);Rl=t=e}while(null!==t);0===Nl&&(Nl=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&Dl)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===Tl&&(Rl=Tl=null,Ll=0),!(2064&n.subtreeFlags)&&!(2064&n.flags)||Wl||(Wl=!0,Tc(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=Dl;Dl|=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 b=h.memoizedProps,g=h.memoizedState,v=t.stateNode,y=v.getSnapshotBeforeUpdate(t.elementType===t.type?b:na(t.type,b),g);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),bl(n,e),ho(nr),qt=!!tr,nr=tr=null,e.current=n,vl(n,e,r),Ke(),Dl=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&Dl)throw Error(i(331));var r=Dl;for(Dl|=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 b=h.child;if(null!==b){h.child=null;do{var g=b.sibling;b.sibling=null,b=g}while(null!==b)}}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(Dl=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=Bi(e,t=fa(0,t=ca(n,t),1),1),t=ec(),null!==e&&(gt(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=Bi(t,e=ma(t,e=ca(n,e),1),1),e=ec(),null!==t&&(gt(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,Tl===e&&(Ll&n)===n&&(4===Nl||3===Nl&&(130023424&Ll)===Ll&&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=Ii(e,t))&&(gt(e,t,n),oc(e,n))}function Ec(e){var t=e.memoizedState,n=0;null!==t&&(n=t.retryLane),Cc(e,n)}function Dc(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 Tc(e,t){return We(e,t)}function Rc(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 Lc(e,t,n,o){return new Rc(e,t,n,o)}function Oc(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Pc(e,t){var n=e.alternate;return null===n?((n=Lc(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 Nc(e,t,n,o,r,s){var a=2;if(o=e,"function"==typeof e)Oc(e)&&(a=1);else if("string"==typeof e)a=5;else e:switch(e){case _:return Ic(n.children,r,s,t);case S:a=8,r|=8;break;case A:return(e=Lc(12,n,t,2|r)).elementType=A,e.lanes=s,e;case T:return(e=Lc(13,n,t,r)).elementType=T,e.lanes=s,e;case R:return(e=Lc(19,n,t,r)).elementType=R,e.lanes=s,e;case P:return jc(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 D:a=11;break e;case L:a=14;break e;case O:a=16,o=null;break e}throw Error(i(130,null==e?e:typeof e,""))}return(t=Lc(a,n,t,r)).elementType=e,t.type=o,t.lanes=s,t}function Ic(e,t,n,o){return(e=Lc(7,e,o,t)).lanes=n,e}function jc(e,t,n,o){return(e=Lc(22,e,o,t)).elementType=P,e.lanes=n,e.stateNode={isHidden:!1},e}function Mc(e,t,n){return(e=Lc(6,e,null,t)).lanes=n,e}function Fc(e,t,n){return(t=Lc(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Uc(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=bt(0),this.expirationTimes=bt(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=bt(0),this.identifierPrefix=o,this.onRecoverableError=r,this.mutableSourceEagerHydrationData=null}function Bc(e,t,n,o,r,i,s,a,l){return e=new Uc(e,t,n,a,l),1===t?(t=1,!0===i&&(t|=8)):t=0,i=Lc(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 Dr;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(Pr(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(Pr(n))return jr(e,n,t)}return t}function $c(e,t,n,o,r,i,s,a,l){return(e=Bc(n,o,!0,e,0,i,0,a,l)).context=zc(null),n=e.current,(i=Ui(o=ec(),r=tc(n))).callback=null!=t?t:null,Bi(n,i,r),e.current.lanes=r,gt(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=Ui(i,s)).payload={element:e},null!==(o=void 0===o?null:o)&&(t.callback=o),null!==(e=Bi(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||Rr.current)ya=!0;else{if(!(e.lanes&n||128&t.flags))return ya=!1,function(e,t,n){switch(t.tag){case 3:Ta(t),mi();break;case 5:Xi(t);break;case 1:Pr(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=Or(t,Tr.current);Ri(t,n),r=bs(null,t,o,e,r,n);var s=gs();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,Pr(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=Da(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 Oc(e)?1:0;if(null!=e){if((e=e.$$typeof)===D)return 11;if(e===L)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(Ta(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=Ra(e,t,o,n,r=ca(Error(i(423)),t));break e}if(o!==r){t=Ra(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&&!Rr.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=Ui(-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),Ti(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),Ti(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,Ri(t,n),o=o(r=Li(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,Pr(o)?(e=!0,Mr(t)):e=!1,Ri(t,n),sa(t,o,r),la(t,o,r,n),Da(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=Bc(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<Pt.length&&0!==t&&t<Pt[n].priority;n++);Pt.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&Dl)&&($l=Ye()+500,Vr()))}break;case 13:dc((function(){var t=Ii(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=Ii(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=Ii(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)}},De=cc,Te=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=Bc(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 b={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},g={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(b).map((function(e){return b[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,b.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[b.BASE]})).map((function(e){return e[b.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}),[])},D=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()},T=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},R=function(e){return Array.isArray(e)?e.join(""):e},L=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}},O=function(e,t){var n;return p({},e,((n={})[t]=void 0,n))},P=[b.NOSCRIPT,b.SCRIPT,b.STYLE],N=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,"'")},I=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}),"")},j=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 b.TITLE:return{toComponent:function(){return n=t.titleAttributes,(r={key:e=t.title})["data-rh"]=!0,i=j(n,r),[o.createElement(b.TITLE,i,e)];var e,n,r,i},toString:function(){return function(e,t,n,o){var r=I(n),i=R(t);return r?"<"+e+' data-rh="true" '+r+">"+N(i,o)+"</"+e+">":"<"+e+' data-rh="true">'+N(i,o)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return j(t)},toString:function(){return I(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+'="'+N(o[t],n)+'"';return e?e+" "+r:r}),""),i=o.innerHTML||o.cssText||"",s=-1===P.indexOf(e);return t+"<"+e+' data-rh="true" '+r+(s?"/>":">"+i+"</"+e+">")}),"")}(e,t,n)}}}},U=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=L(e.metaTags,y),i=L(t,g),s=L(n,v);return{priorityMethods:{toComponent:function(){return[].concat(M(b.META,r.priority),M(b.LINK,i.priority),M(b.SCRIPT,s.priority))},toString:function(){return F(b.META,r.priority,o)+" "+F(b.LINK,i.priority,o)+" "+F(b.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(b.BASE,t,o),bodyAttributes:F("bodyAttributes",n,o),htmlAttributes:F("htmlAttributes",r,o),link:F(b.LINK,d,o),meta:F(b.META,u,o),noscript:F(b.NOSCRIPT,i,o),script:F(b.SCRIPT,p,o),style:F(b.STYLE,s,o),title:F(b.TITLE,{title:l,titleAttributes:c},o)}},B=[],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?B:n.instances},add:function(e){(n.canUseDOM?B:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?B:n.instances).indexOf(e);(n.canUseDOM?B:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=U({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(b.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(b.BODY,e.bodyAttributes),W(b.HTML,o),function(e,t){void 0!==e&&document.title!==e&&(document.title=R(e)),W(b.TITLE,t)}(d,u);var p={baseTag:G(b.BASE,n),linkTags:G(b.LINK,r),metaTags:G(b.META,i),noscriptTags:G(b.NOSCRIPT,s),scriptTags:G(b.SCRIPT,l),styleTags:G(b.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:D(b.LINK,["rel","href"],e),metaTags:D(b.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:D(b.NOSCRIPT,["innerHTML"],e),onChangeClientState:A(e),scriptTags:D(b.SCRIPT,["src","innerHTML"],e),styleTags:D(b.STYLE,["cssText"],e),title:S(e),titleAttributes:C("titleAttributes",e),prioritizeSeoTags:T(e,"prioritizeSeoTags")});H.canUseDOM?(t=i,Q&&cancelAnimationFrame(Q),t.defer?Q=requestAnimationFrame((function(){Z(t,(function(){Q=null}))})):(Z(t),Q=null)):U&&(r=U(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()(O(this.props,"helmetData"),O(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case b.SCRIPT:case b.NOSCRIPT:return{innerHTML:t};case b.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 b.TITLE:return p({},r,((t={})[o.type]=s,t.titleAttributes=p({},i),t));case b.BODY:return p({},r,{bodyAttributes:p({},i)});case b.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 b.FRAGMENT:t=n.mapChildrenToProps(i,t);break;case b.LINK:case b.META:case b.NOSCRIPT:case b.SCRIPT:case b.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,b=n?Symbol.for("react.lazy"):60116,g=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 b: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=b,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)===b},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===b||e.$$typeof===h||e.$$typeof===l||e.$$typeof===c||e.$$typeof===p||e.$$typeof===v||e.$$typeof===y||e.$$typeof===w||e.$$typeof===g)},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 b(){return h||(h=e(m.loader)),h.promise}return l.push(b),"function"==typeof m.webpack&&c.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return b()})),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()})),b(),o.state={error:h.error,pastDelay:!1,timedOut:!1,loading:h.loading,loaded:h.loaded},o}o(n,t),n.preload=function(){return b()};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 b=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 g(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return g(e)}))}h.Capture=b,h.preloadAll=function(){return new Promise((function(e,t){g(l).then(e,t)}))},h.preloadReady=function(){return new Promise((function(e,t){g(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_:()=>g,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 b=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 g=h((function(e,t){var n=e.component,r=void 0===n?b:n,d=e.replace,u=e.to,g=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):"",b=(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?b.ref=t||g:b.innerRef=g,i.createElement(r,b)}))})),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,b=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"),D=E?(0,o.B6)(n.pathname,{path:E,exact:h,sensitive:k,strict:x}):null,T=!!(b?b(D,n):D),R="function"==typeof m?m(T):m,L="function"==typeof _?_(T):_;T&&(R=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(" ")}(R,d),L=(0,a.A)({},L,u));var O=(0,a.A)({"aria-current":T&&r||null,className:R,style:L,to:s},C);return v!==y?O.ref=t||A:O.innerRef=A,i.createElement(g,O)}))}))},6347:(e,t,n)=>{"use strict";n.d(t,{B6:()=>_,Ix:()=>y,W6:()=>O,XZ:()=>v,dO:()=>R,qh:()=>S,zy:()=>P});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}},b=function(e){var t=h();return t.displayName=e,t},g=b("Router-History"),v=b("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(g.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 D(e){return function(){(0,l.A)(!1)}}function T(){}r.Component;var R=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 L=r.useContext;function O(){return L(g)}function P(){return L(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],b=n[3],g=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=g||v;o.push({name:b||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,b={};function g(e,t,n){this.props=e,this.context=t,this.refs=b,this.updater=n||m}function v(){}function y(e,t,n){this.props=e,this.context=t,this.refs=b,this.updater=n||m}g.prototype.isReactComponent={},g.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")},g.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},v.prototype=g.prototype;var w=y.prototype=new v;w.constructor=y,h(w,g.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 D(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 T(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?"."+D(l,0):i,k(s)?(r="",null!=e&&(r=e.replace(E,"$&/")+"/"),T(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+D(a=e[c],c);l+=T(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+=T(a=a.value,t,r,d=i+D(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 R(e,t,n){if(null==e)return e;var o=[],r=0;return T(e,o,"","",(function(e){return t.call(n,e,r++)})),o}function L(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 O={current:null},P={transition:null},N={ReactCurrentDispatcher:O,ReactCurrentBatchConfig:P,ReactCurrentOwner:_};function I(){throw Error("act(...) is not supported in production builds of React.")}t.Children={map:R,forEach:function(e,t,n){R(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return R(e,(function(){t++})),t},toArray:function(e){return R(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=g,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=N,t.act=I,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:L}},t.memo=function(e,t){return{$$typeof:u,type:e,compare:void 0===t?null:t}},t.startTransition=function(e){var t=P.transition;P.transition={};try{e()}finally{P.transition=t}},t.unstable_act=I,t.useCallback=function(e,t){return O.current.useCallback(e,t)},t.useContext=function(e){return O.current.useContext(e)},t.useDebugValue=function(){},t.useDeferredValue=function(e){return O.current.useDeferredValue(e)},t.useEffect=function(e,t){return O.current.useEffect(e,t)},t.useId=function(){return O.current.useId()},t.useImperativeHandle=function(e,t,n){return O.current.useImperativeHandle(e,t,n)},t.useInsertionEffect=function(e,t){return O.current.useInsertionEffect(e,t)},t.useLayoutEffect=function(e,t){return O.current.useLayoutEffect(e,t)},t.useMemo=function(e,t){return O.current.useMemo(e,t)},t.useReducer=function(e,t,n){return O.current.useReducer(e,t,n)},t.useRef=function(e){return O.current.useRef(e)},t.useState=function(e){return O.current.useState(e)},t.useSyncExternalStore=function(e,t,n){return O.current.useSyncExternalStore(e,t,n)},t.useTransition=function(){return O.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,b=!1,g="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(b=!1,w(e),!h)if(null!==o(c))h=!0,P(x);else{var t=o(d);null!==t&&N(k,t.startTime-e)}}function x(e,n){h=!1,b&&(b=!1,v(C),C=-1),m=!0;var i=f;try{for(w(n),p=o(c);null!==p&&(!(p.expirationTime>n)||e&&!T());){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&&N(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,D=-1;function T(){return!(t.unstable_now()-D<E)}function R(){if(null!==A){var e=t.unstable_now();D=e;var n=!0;try{n=A(!0,e)}finally{n?_():(S=!1,A=null)}}else S=!1}if("function"==typeof y)_=function(){y(R)};else if("undefined"!=typeof MessageChannel){var L=new MessageChannel,O=L.port2;L.port1.onmessage=R,_=function(){O.postMessage(null)}}else _=function(){g(R,0)};function P(e){A=e,S||(S=!0,_())}function N(e,n){C=g((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,P(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)&&(b?(v(C),C=-1):b=!0,N(k,i-s))):(e.sortIndex=a,n(c,e),h||m||(h=!0,P(x))),e},t.unstable_shouldYield=T,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/misti.svg",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"}}]],plugins:[["@docusaurus/plugin-google-gtag",{trackingID:"G-8VLF6VGHH5",anonymizeIP:!0}]],themeConfig:{navbar:{title:"Misti",logo:{alt:"Misti Logo",src:"img/misti.svg"},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:{},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,b=Object.getOwnPropertyDescriptors,g=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,b(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],b=h.inside,g=!!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,g))||A.index>=e.length)break;var E=A.index,D=A.index+A[0].length,T=_;for(T+=x.value.length;E>=T;)T+=(x=x.next).value.length;if(_=T-=x.value.length,x.value instanceof r)continue;for(var R=x;R!==t.tail&&(T<D||"string"==typeof R.value);R=R.next)C++,T+=R.value.length;C--,S=e.slice(_,T),A.index-=_}else if(!(A=i(k,0,S,g)))continue;E=A.index;var L=A[0],O=S.slice(0,E),P=S.slice(E+L.length),N=_+S.length;u&&N>u.reach&&(u.reach=N);var I=x.prev;if(O&&(I=l(t,I,O),_+=O.length),c(t,I,C),x=l(t,I,new r(p,b?o.tokenize(L,b):L,y,L)),P&&l(t,x,P),C>1){var j={cause:p+","+m,reach:N};s(e,t,n,x.prev,_,j),u&&j.reach>u.reach&&(u.reach=j.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[g(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 g(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,b,g=n[i];"string"==typeof g||"string"==typeof g.content?(s=u[c],-1!==(b=(h="string"==typeof g?g:g.content).indexOf(s))&&(++c,l=h.substring(0,b),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(b+s.length),m=[],l&&m.push(l),m.push(p),f&&(t(h=[f]),m.push.apply(m,h)),"string"==typeof g?(n.splice.apply(n,[i,1].concat(m)),i+=m.length-1):g.content=m)):(b=g.content,Array.isArray(b)?t(b):t([b]))}}(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:()=>D,duotoneDark:()=>T,duotoneLight:()=>R,github:()=>L,jettwaveDark:()=>q,jettwaveLight:()=>H,nightOwl:()=>O,nightOwlLight:()=>P,oceanicNext:()=>j,okaidia:()=>M,oneDark:()=>G,oneLight:()=>W,palenight:()=>F,shadesOfPurple:()=>U,synthwave84:()=>B,ultramin:()=>z,vsDark:()=>$,vsLight:()=>V});var D={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)"}}]},T={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"}}]},R={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"}}]},L={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"}}]},O={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)"}}]},P={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)"}}]},N="#c5a5c5",I="#8dc891",j={plain:{backgroundColor:"#282c34",color:"#ffffff"},styles:[{types:["attr-name"],style:{color:N}},{types:["attr-value"],style:{color:I}},{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:I}},{types:["punctuation"],style:{color:I}},{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:N}},{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)"}}]},U={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)"}}]},B={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-063":{"__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/0.4.0-e81":{"__comp":"a7bd4aaa","__props":"03b4256a"},"/tools/misti/docs/0.4.0-bc8":{"__comp":"a94703ab"},"/tools/misti/docs/0.4.0/-6f1":{"__comp":"17896441","content":"c7ee6afe"},"/tools/misti/docs/0.4.0/detectors-df6":{"__comp":"17896441","content":"c82192ae"},"/tools/misti/docs/0.4.0/detectors/ArgCopyMutation-761":{"__comp":"17896441","content":"3b3a1a75"},"/tools/misti/docs/0.4.0/detectors/AsmIsUsed-6ef":{"__comp":"17896441","content":"ea064c97"},"/tools/misti/docs/0.4.0/detectors/BranchDuplicate-051":{"__comp":"17896441","content":"7499c02a"},"/tools/misti/docs/0.4.0/detectors/ConstantAddress-1fb":{"__comp":"17896441","content":"4ab26116"},"/tools/misti/docs/0.4.0/detectors/DivideBeforeMultiply-33e":{"__comp":"17896441","content":"3bfe497f"},"/tools/misti/docs/0.4.0/detectors/DumpIsUsed-b24":{"__comp":"17896441","content":"8e426e62"},"/tools/misti/docs/0.4.0/detectors/DuplicatedCondition-477":{"__comp":"17896441","content":"e6ef21e7"},"/tools/misti/docs/0.4.0/detectors/EnsurePrgSeed-a2b":{"__comp":"17896441","content":"94d07e36"},"/tools/misti/docs/0.4.0/detectors/FalseCondition-f06":{"__comp":"17896441","content":"b64aaedd"},"/tools/misti/docs/0.4.0/detectors/FieldDoubleInit-cc7":{"__comp":"17896441","content":"602c5d84"},"/tools/misti/docs/0.4.0/detectors/InheritedStateMutation-d7f":{"__comp":"17896441","content":"a291c19d"},"/tools/misti/docs/0.4.0/detectors/NeverAccessedVariables-e94":{"__comp":"17896441","content":"51fe41a6"},"/tools/misti/docs/0.4.0/detectors/OptimalMathFunction-849":{"__comp":"17896441","content":"d7c99f30"},"/tools/misti/docs/0.4.0/detectors/PreferAugmentedAssign-127":{"__comp":"17896441","content":"8306354c"},"/tools/misti/docs/0.4.0/detectors/PreferredStdlibApi-d75":{"__comp":"17896441","content":"63bb535a"},"/tools/misti/docs/0.4.0/detectors/ReadOnlyVariables-4b9":{"__comp":"17896441","content":"719e5d48"},"/tools/misti/docs/0.4.0/detectors/StringReceiversOverlap-c8e":{"__comp":"17896441","content":"f553073e"},"/tools/misti/docs/0.4.0/detectors/UnboundLoops-813":{"__comp":"17896441","content":"cf2c24d9"},"/tools/misti/docs/0.4.0/detectors/UnusedOptional-492":{"__comp":"17896441","content":"59016342"},"/tools/misti/docs/0.4.0/detectors/ZeroAddress-b6d":{"__comp":"17896441","content":"91acf703"},"/tools/misti/docs/0.4.0/hacking/contributing-39d":{"__comp":"17896441","content":"1a8310a1"},"/tools/misti/docs/0.4.0/hacking/custom-detector-45e":{"__comp":"17896441","content":"f58fcc43"},"/tools/misti/docs/0.4.0/hacking/design-ed4":{"__comp":"17896441","content":"432cb5a5"},"/tools/misti/docs/0.4.0/hacking/developing-misti-172":{"__comp":"17896441","content":"42510f93"},"/tools/misti/docs/0.4.0/hacking/souffle-144":{"__comp":"17896441","content":"effcc73a"},"/tools/misti/docs/0.4.0/tools-28d":{"__comp":"17896441","content":"150b97d9"},"/tools/misti/docs/0.4.0/tools/DumpAst-2aa":{"__comp":"17896441","content":"aee0b8cc"},"/tools/misti/docs/0.4.0/tools/DumpCfg-d27":{"__comp":"17896441","content":"6696f09b"},"/tools/misti/docs/0.4.0/tools/DumpConfig-7b4":{"__comp":"17896441","content":"1b960128"},"/tools/misti/docs/0.4.0/tutorial/blueprint-d90":{"__comp":"17896441","content":"6362ac9f"},"/tools/misti/docs/0.4.0/tutorial/ci-cd-096":{"__comp":"17896441","content":"f752d1db"},"/tools/misti/docs/0.4.0/tutorial/cli-179":{"__comp":"17896441","content":"0c390d31"},"/tools/misti/docs/0.4.0/tutorial/configuration-e42":{"__comp":"17896441","content":"0e4e7ef7"},"/tools/misti/docs/0.4.0/tutorial/getting-started-0f1":{"__comp":"17896441","content":"a3df6930"},"/tools/misti/docs/next-13c":{"__comp":"a7bd4aaa","__props":"dd8730c9"},"/tools/misti/docs/next-46d":{"__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/CellOverflow-347":{"__comp":"17896441","content":"de7c269b"},"/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/SendInLoop-d81":{"__comp":"17896441","content":"be04c9f2"},"/tools/misti/docs/next/detectors/ShortCircuitCondition-96a":{"__comp":"17896441","content":"888071ca"},"/tools/misti/docs/next/detectors/StringReceiversOverlap-992":{"__comp":"17896441","content":"0f37fc5e"},"/tools/misti/docs/next/detectors/SuspiciousMessageMode-7ac":{"__comp":"17896441","content":"24ab0ec7"},"/tools/misti/docs/next/detectors/UnboundLoop-e09":{"__comp":"17896441","content":"a2e1ac23"},"/tools/misti/docs/next/detectors/UnboundMap-8d3":{"__comp":"17896441","content":"2c038e81"},"/tools/misti/docs/next/detectors/UnusedExpressionResult-4c9":{"__comp":"17896441","content":"9016a10e"},"/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/tools/DumpImports-bfa":{"__comp":"17896441","content":"f99bae31"},"/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-018":{"__comp":"a7bd4aaa","__props":"86d22c3d"},"/tools/misti/docs-fc9":{"__comp":"a94703ab"},"/tools/misti/docs/-40c":{"__comp":"17896441","content":"e0636556"},"/tools/misti/docs/detectors-946":{"__comp":"17896441","content":"322eba7d"},"/tools/misti/docs/detectors/ArgCopyMutation-5be":{"__comp":"17896441","content":"2c17c501"},"/tools/misti/docs/detectors/AsmIsUsed-a1e":{"__comp":"17896441","content":"129b217c"},"/tools/misti/docs/detectors/BranchDuplicate-dcd":{"__comp":"17896441","content":"e530f65e"},"/tools/misti/docs/detectors/CellOverflow-0e4":{"__comp":"17896441","content":"230b3a10"},"/tools/misti/docs/detectors/ConstantAddress-ca0":{"__comp":"17896441","content":"1a2cd3da"},"/tools/misti/docs/detectors/DivideBeforeMultiply-e18":{"__comp":"17896441","content":"30835b52"},"/tools/misti/docs/detectors/DumpIsUsed-d93":{"__comp":"17896441","content":"25eb63f7"},"/tools/misti/docs/detectors/DuplicatedCondition-636":{"__comp":"17896441","content":"54df6b9c"},"/tools/misti/docs/detectors/EnsurePrgSeed-cf1":{"__comp":"17896441","content":"46947df5"},"/tools/misti/docs/detectors/FalseCondition-b70":{"__comp":"17896441","content":"8078ad78"},"/tools/misti/docs/detectors/FieldDoubleInit-24a":{"__comp":"17896441","content":"26b19808"},"/tools/misti/docs/detectors/InheritedStateMutation-7a0":{"__comp":"17896441","content":"5c07db7d"},"/tools/misti/docs/detectors/NeverAccessedVariables-517":{"__comp":"17896441","content":"53023ca8"},"/tools/misti/docs/detectors/OptimalMathFunction-19d":{"__comp":"17896441","content":"b2b6aa30"},"/tools/misti/docs/detectors/PreferAugmentedAssign-6e1":{"__comp":"17896441","content":"3c9b1461"},"/tools/misti/docs/detectors/PreferredStdlibApi-b23":{"__comp":"17896441","content":"9081c3e5"},"/tools/misti/docs/detectors/ReadOnlyVariables-972":{"__comp":"17896441","content":"4624921c"},"/tools/misti/docs/detectors/SendInLoop-499":{"__comp":"17896441","content":"926d5e8d"},"/tools/misti/docs/detectors/StringReceiversOverlap-6d4":{"__comp":"17896441","content":"c2845dc0"},"/tools/misti/docs/detectors/SuspiciousMessageMode-7bd":{"__comp":"17896441","content":"9983337e"},"/tools/misti/docs/detectors/UnboundLoop-9ae":{"__comp":"17896441","content":"ab64460a"},"/tools/misti/docs/detectors/UnboundMap-f1a":{"__comp":"17896441","content":"110db9ee"},"/tools/misti/docs/detectors/UnusedExpressionResult-b7c":{"__comp":"17896441","content":"770027e6"},"/tools/misti/docs/detectors/UnusedOptional-d35":{"__comp":"17896441","content":"c734b99d"},"/tools/misti/docs/detectors/ZeroAddress-d48":{"__comp":"17896441","content":"0600087e"},"/tools/misti/docs/hacking/contributing-768":{"__comp":"17896441","content":"40440f59"},"/tools/misti/docs/hacking/custom-detector-dd3":{"__comp":"17896441","content":"6afbdc7c"},"/tools/misti/docs/hacking/design-43a":{"__comp":"17896441","content":"dda96275"},"/tools/misti/docs/hacking/developing-misti-fe7":{"__comp":"17896441","content":"eb1a8185"},"/tools/misti/docs/hacking/souffle-f46":{"__comp":"17896441","content":"8685a76e"},"/tools/misti/docs/tools-5d4":{"__comp":"17896441","content":"d7ebd85b"},"/tools/misti/docs/tools/DumpAst-ade":{"__comp":"17896441","content":"35d1ab0d"},"/tools/misti/docs/tools/DumpCfg-280":{"__comp":"17896441","content":"d9941f94"},"/tools/misti/docs/tools/DumpConfig-511":{"__comp":"17896441","content":"740c342d"},"/tools/misti/docs/tools/DumpImports-513":{"__comp":"17896441","content":"2fbff8b1"},"/tools/misti/docs/tutorial/blueprint-6cf":{"__comp":"17896441","content":"b9de2907"},"/tools/misti/docs/tutorial/ci-cd-a83":{"__comp":"17896441","content":"6bfbb660"},"/tools/misti/docs/tutorial/cli-edd":{"__comp":"17896441","content":"6bb9ad58"},"/tools/misti/docs/tutorial/configuration-a4a":{"__comp":"17896441","content":"df3f8a78"},"/tools/misti/docs/tutorial/getting-started-7a0":{"__comp":"17896441","content":"ef43b7e4"},"/-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.ebcc6cf7.js.LICENSE.txt b/assets/js/main.ebcc6cf7.js.LICENSE.txt new file mode 100644 index 000000000..72c943689 --- /dev/null +++ b/assets/js/main.ebcc6cf7.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.e41f8c8b.js b/assets/js/runtime~main.e41f8c8b.js new file mode 100644 index 000000000..ca8eec08a --- /dev/null +++ b/assets/js/runtime~main.e41f8c8b.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,d,c,a,b,f={},t={};function r(e){var d=t[e];if(void 0!==d)return d.exports;var c=t[e]={id:e,loaded:!1,exports:{}};return f[e].call(c.exports,c,c.exports,r),c.loaded=!0,c.exports}r.m=f,r.c=t,e=[],r.O=(d,c,a,b)=>{if(!c){var f=1/0;for(i=0;i<e.length;i++){c=e[i][0],a=e[i][1],b=e[i][2];for(var t=!0,o=0;o<c.length;o++)(!1&b||f>=b)&&Object.keys(r.O).every((e=>r.O[e](c[o])))?c.splice(o--,1):(t=!1,b<f&&(f=b));if(t){e.splice(i--,1);var n=a();void 0!==n&&(d=n)}}return d}b=b||0;for(var i=e.length;i>0&&e[i-1][2]>b;i--)e[i]=e[i-1];e[i]=[c,a,b]},r.n=e=>{var d=e&&e.__esModule?()=>e.default:()=>e;return r.d(d,{a:d}),d},c=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 b=Object.create(null);r.r(b);var f={};d=d||[null,c({}),c([]),c(c)];for(var t=2&a&&e;"object"==typeof t&&!~d.indexOf(t);t=c(t))Object.getOwnPropertyNames(t).forEach((d=>f[d]=()=>e[d]));return f.default=()=>e,r.d(b,f),b},r.d=(e,d)=>{for(var c in d)r.o(d,c)&&!r.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:d[c]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((d,c)=>(r.f[c](e,d),d)),[])),r.u=e=>"assets/js/"+({23:"2c17c501",25:"122f6b32",44:"be04c9f2",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",738:"e530f65e",767:"a3df6930",804:"06bf7bd2",872:"c734b99d",877:"f97c3fca",906:"c00ee666",1006:"c49af6bd",1070:"0e4e7ef7",1084:"2b6a80d0",1114:"bd72ef9b",1171:"e3b47995",1179:"972c9666",1193:"322eba7d",1200:"0c390d31",1204:"693ffdbc",1235:"a7456010",1258:"150b97d9",1299:"43c93918",1318:"987a8a5d",1330:"2fbff8b1",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",2467:"ab64460a",2478:"3b3a1a75",2526:"926d5e8d",2537:"d2d53d04",2712:"53023ca8",2734:"49256311",2798:"c252c345",2819:"f503d00c",2903:"0b705376",2906:"9016a10e",2913:"42510f93",2991:"8e426e62",3031:"230b3a10",3150:"7499c02a",3175:"6934ebe4",3196:"2aa59687",3291:"91acf703",3304:"754ccd45",3320:"9983337e",3339:"26b19808",3361:"c377a04b",3388:"9fedf60a",3420:"1b73222b",3434:"edf1e52e",3448:"377c4f81",3462:"07f2fad9",3543:"26592ea2",3583:"8685a76e",3590:"d9542fcf",3684:"63bb535a",3750:"cc6d1ce2",3754:"f7ab1f3a",3812:"86d70222",3840:"432cb5a5",3884:"15d13f14",3890:"563af34e",3988:"3c9b1461",4006:"1a2cd3da",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",4575:"5c07db7d",4583:"1df93b7f",4701:"6afbdc7c",4719:"602c5d84",4787:"35d1ab0d",4806:"2b785902",4861:"6f60ccd2",4875:"0c3de8e2",4903:"a291c19d",4910:"740c342d",4913:"b9de2907",4984:"e6ef21e7",4992:"46947df5",5097:"2d07d137",5122:"63a541b5",5173:"6bfbb660",5200:"ce7f72c2",5308:"d7ebd85b",5316:"844f22a2",5321:"c82192ae",5345:"2cebbb1e",5378:"c2845dc0",5381:"3bfe497f",5422:"129b217c",5459:"c7ee6afe",5484:"a5055d90",5508:"ea064c97",5588:"b64aaedd",5602:"1c26cb06",5622:"aee0b8cc",5656:"eb1a8185",5664:"d3996cd7",5671:"40440f59",5742:"aba21aa0",5794:"61c19607",5859:"faae61e5",5900:"f752d1db",5922:"96e77fcb",5945:"e2ad9c7a",5983:"0fb6ae9c",6061:"1f391b9e",6156:"4f2bb7ce",6208:"8078ad78",6216:"b2b6aa30",6269:"30835b52",6274:"8cf7c613",6286:"8c9dd45b",6309:"de7c269b",6340:"6f277b0e",6387:"ebcc9167",6406:"d15cc687",6412:"b64540ae",6474:"df3f8a78",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",6805:"9081c3e5",6854:"fe7c01fc",6869:"81087c81",6941:"25eb63f7",6948:"4fd06f05",6974:"866ed13d",6999:"1a50d306",7003:"cf5f971a",7005:"76268162",7083:"c55f1521",7098:"a7bd4aaa",7151:"776efca7",7173:"fbbe250b",7193:"dda96275",7238:"883df8cc",7242:"d2f295f4",7348:"e4a43c7d",7354:"03b4256a",7378:"f4d075b1",7393:"2c038e81",7406:"24652b08",7495:"87ce9660",7677:"2018b81b",7682:"b78952d0",7702:"0ac52da9",7709:"770027e6",7743:"1a8310a1",7787:"36ebdf3e",7837:"c5c1850c",7839:"8c0243db",7877:"8306354c",7965:"d147047e",8031:"b3799bec",8047:"e0636556",8072:"d46ee8ed",8137:"dd8730c9",8164:"110db9ee",8183:"d9941f94",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",8927:"f99bae31",8962:"54df6b9c",9048:"a94703ab",9076:"d7d99e1d",9108:"1869ccd1",9187:"888071ca",9198:"8c74c05e",9276:"4ab26116",9304:"a8c496ca",9337:"f34cb5e0",9359:"b12d76e5",9415:"a4516edb",9417:"6696f09b",9428:"e3c4fe0a",9431:"6362ac9f",9439:"24ab0ec7",9448:"6bb9ad58",9510:"4624921c",9601:"b91dc83b",9623:"ef43b7e4",9641:"e63578c3",9647:"5e95c892",9692:"0f37fc5e",9708:"5ec2195c",9713:"0600087e",9758:"988b076a",9802:"4d74b396",9924:"8e8fe4d7",9959:"f18c7db7",9977:"a2e1ac23"}[e]||e)+"."+{23:"a6c5c68e",25:"f6ee1737",44:"c6a1b800",106:"46b8f441",121:"ba311b0c",186:"36349d47",219:"14b05cf2",223:"4bde77ae",243:"3b9a5601",278:"b2bd9e44",301:"5a9830a2",321:"11a0dcc1",335:"3be72894",338:"7b0b1178",420:"88efacf6",485:"c554b68a",488:"26b5c812",494:"93ad2656",559:"6c981ca5",607:"c0afaf27",684:"6b5bbfc3",738:"a3814a9a",767:"3fd81736",804:"93cfb521",872:"c559e4ef",877:"388d1a86",906:"951c69ba",1006:"85a90098",1070:"9f8c235e",1084:"3d7eb50f",1114:"45e20252",1171:"f50ac3b9",1179:"e5b493f7",1193:"15fc9303",1200:"90b7d615",1204:"20a90ba4",1235:"c6eb9a57",1258:"ba7446c4",1299:"b3c5c4ff",1318:"bdfcfd74",1330:"84b0cc23",1332:"c39f76e5",1407:"7c8fbb6b",1417:"08c83086",1468:"ccd7a032",1492:"26adb4b1",1519:"578334fd",1529:"d9a84b38",1537:"c88faef0",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",2467:"f029dca5",2478:"bf621ae4",2526:"9358cd7a",2537:"404d4960",2712:"611e95e8",2734:"be5c404d",2798:"a3cf3637",2819:"e7655ff6",2903:"0f6bdf25",2906:"f412061d",2913:"835e2f8a",2991:"f6ea35a1",3031:"f8054203",3150:"591c6669",3175:"7bcf9574",3196:"16070803",3291:"e9b6829a",3304:"c7633e79",3320:"ea12e3f1",3339:"395ffe9a",3361:"8c30a29b",3388:"5a24888e",3420:"c47a22da",3434:"7e8e467f",3448:"79a338ae",3462:"76f75bf4",3543:"2dd4e9ca",3583:"8943dfe3",3590:"bbcb88d0",3658:"8fe69683",3684:"d93af67f",3750:"2f552c48",3754:"096a7a59",3812:"91cb640f",3840:"d823b28c",3884:"3309e304",3890:"29a0e834",3988:"4a5fe7e2",4006:"0974c124",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",4575:"dbb32bd9",4583:"4689c496",4701:"8a6b1736",4719:"e34a6ec9",4787:"32926c20",4806:"54dbde22",4861:"91c6f358",4875:"454cb0da",4903:"f1235972",4910:"44a80203",4913:"1fc2ebe1",4984:"18abdbcd",4992:"86adfe22",5097:"1711bd45",5122:"cf91b4ad",5173:"67f004b0",5200:"19df7abf",5308:"81f998f6",5316:"2f80fdcf",5321:"388e1126",5345:"1c80f755",5378:"24f1aeb0",5381:"10b20c3b",5422:"9e750dae",5459:"d82db54e",5484:"d691b43f",5508:"a5aaaeb2",5588:"0b438287",5602:"972f1ca6",5604:"07bdff8a",5622:"034e2877",5656:"161f6a09",5664:"2fcfc32a",5671:"e19073b4",5742:"d087865c",5794:"94c232da",5859:"0c385acd",5900:"1f995ffc",5922:"3fb77893",5945:"573d9426",5983:"e2818ac1",6061:"d1d4beb6",6156:"0a476d8d",6208:"72d8805b",6216:"3aa9416e",6269:"63e9b2c4",6274:"47582d2c",6286:"c7a96e3d",6309:"f7040048",6340:"89006761",6387:"b433e15d",6406:"df08049f",6412:"f5677375",6474:"19c23fa7",6544:"b9ef0cc5",6551:"942257c5",6584:"f4a8e3dd",6602:"be7d2a62",6612:"90aa7fd2",6633:"35abe5aa",6670:"c54dcfb2",6695:"61be676d",6701:"ed43e771",6751:"8f602791",6752:"e1395157",6757:"4c34ff27",6769:"efdf0920",6774:"08380390",6784:"2fa9fd96",6805:"771bfadf",6854:"f82580ba",6869:"7da41d03",6941:"0fec67f5",6948:"45b0f688",6974:"d4edfa4a",6999:"ff71f994",7003:"651efe6f",7005:"332975fc",7083:"cb9c8e4f",7098:"1b32332e",7151:"78ead050",7173:"0abc4220",7193:"6e542222",7238:"ec17e966",7242:"9f26dd12",7348:"190cf370",7354:"f5655242",7378:"8ca57b63",7393:"5a3ae8ee",7406:"91ed48d5",7495:"55512f80",7677:"63a7c757",7682:"efed39b1",7702:"865948a5",7709:"28c96dd7",7743:"26ab9acc",7787:"c81514b8",7837:"d97c4482",7839:"7de6da6a",7877:"0e912fc3",7965:"c3db349f",8031:"86c01a35",8047:"3ece1612",8072:"7ed1c3f4",8137:"ffc63748",8164:"e741188f",8183:"b1fb5e38",8221:"924539a3",8235:"7f27f910",8262:"90a54648",8290:"efba011c",8300:"2d114ae2",8342:"a34207ca",8401:"dc05340c",8422:"f5805772",8513:"759681c0",8546:"1af0a38f",8607:"a81bd6a1",8677:"1dfb4d97",8692:"46a0cb1c",8700:"8c957f95",8708:"06ff38aa",8771:"30e3ae68",8836:"256a666a",8904:"2f60268c",8917:"6eb86b98",8920:"e34de4aa",8927:"0a506efe",8962:"ab93266a",9048:"9f24e801",9076:"67e2d007",9108:"5d76a4bd",9187:"8652ec85",9198:"09164805",9276:"35b4841f",9304:"06cbb22b",9337:"b26c4fc7",9359:"d3ad221e",9415:"19e6546c",9417:"57cd0d6b",9428:"bf2b73e2",9431:"fb178849",9439:"697f91e1",9448:"94c990fe",9510:"a36b4fff",9601:"a57e29d3",9623:"3a22e7e4",9641:"6cc338fe",9647:"0afa16e4",9692:"19df6688",9708:"a723ab4e",9713:"2097de6c",9758:"3beed1a8",9802:"8aebea31",9924:"7a82fd74",9959:"502a736a",9977:"ed8d2af3"}[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,d)=>Object.prototype.hasOwnProperty.call(e,d),a={},b="nowarp-github-io:",r.l=(e,d,c,f)=>{if(a[e])a[e].push(d);else{var t,o;if(void 0!==c)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")==b+c){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",b+c),t.src=e),a[e]=[d];var l=(d,c)=>{t.onerror=t.onload=null,clearTimeout(s);var b=a[e];if(delete a[e],t.parentNode&&t.parentNode.removeChild(t),b&&b.forEach((e=>e(c))),d)return d(c)},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","2c17c501":"23","122f6b32":"25",be04c9f2:"44","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",e530f65e:"738",a3df6930:"767","06bf7bd2":"804",c734b99d:"872",f97c3fca:"877",c00ee666:"906",c49af6bd:"1006","0e4e7ef7":"1070","2b6a80d0":"1084",bd72ef9b:"1114",e3b47995:"1171","972c9666":"1179","322eba7d":"1193","0c390d31":"1200","693ffdbc":"1204",a7456010:"1235","150b97d9":"1258","43c93918":"1299","987a8a5d":"1318","2fbff8b1":"1330",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",ab64460a:"2467","3b3a1a75":"2478","926d5e8d":"2526",d2d53d04:"2537","53023ca8":"2712",c252c345:"2798",f503d00c:"2819","0b705376":"2903","9016a10e":"2906","42510f93":"2913","8e426e62":"2991","230b3a10":"3031","7499c02a":"3150","6934ebe4":"3175","2aa59687":"3196","91acf703":"3291","754ccd45":"3304","9983337e":"3320","26b19808":"3339",c377a04b:"3361","9fedf60a":"3388","1b73222b":"3420",edf1e52e:"3434","377c4f81":"3448","07f2fad9":"3462","26592ea2":"3543","8685a76e":"3583",d9542fcf:"3590","63bb535a":"3684",cc6d1ce2:"3750",f7ab1f3a:"3754","86d70222":"3812","432cb5a5":"3840","15d13f14":"3884","563af34e":"3890","3c9b1461":"3988","1a2cd3da":"4006","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","5c07db7d":"4575","1df93b7f":"4583","6afbdc7c":"4701","602c5d84":"4719","35d1ab0d":"4787","2b785902":"4806","6f60ccd2":"4861","0c3de8e2":"4875",a291c19d:"4903","740c342d":"4910",b9de2907:"4913",e6ef21e7:"4984","46947df5":"4992","2d07d137":"5097","63a541b5":"5122","6bfbb660":"5173",ce7f72c2:"5200",d7ebd85b:"5308","844f22a2":"5316",c82192ae:"5321","2cebbb1e":"5345",c2845dc0:"5378","3bfe497f":"5381","129b217c":"5422",c7ee6afe:"5459",a5055d90:"5484",ea064c97:"5508",b64aaedd:"5588","1c26cb06":"5602",aee0b8cc:"5622",eb1a8185:"5656",d3996cd7:"5664","40440f59":"5671",aba21aa0:"5742","61c19607":"5794",faae61e5:"5859",f752d1db:"5900","96e77fcb":"5922",e2ad9c7a:"5945","0fb6ae9c":"5983","1f391b9e":"6061","4f2bb7ce":"6156","8078ad78":"6208",b2b6aa30:"6216","30835b52":"6269","8cf7c613":"6274","8c9dd45b":"6286",de7c269b:"6309","6f277b0e":"6340",ebcc9167:"6387",d15cc687:"6406",b64540ae:"6412",df3f8a78:"6474","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","9081c3e5":"6805",fe7c01fc:"6854","81087c81":"6869","25eb63f7":"6941","4fd06f05":"6948","866ed13d":"6974","1a50d306":"6999",cf5f971a:"7003",c55f1521:"7083",a7bd4aaa:"7098","776efca7":"7151",fbbe250b:"7173",dda96275:"7193","883df8cc":"7238",d2f295f4:"7242",e4a43c7d:"7348","03b4256a":"7354",f4d075b1:"7378","2c038e81":"7393","24652b08":"7406","87ce9660":"7495","2018b81b":"7677",b78952d0:"7682","0ac52da9":"7702","770027e6":"7709","1a8310a1":"7743","36ebdf3e":"7787",c5c1850c:"7837","8c0243db":"7839","8306354c":"7877",d147047e:"7965",b3799bec:"8031",e0636556:"8047",d46ee8ed:"8072",dd8730c9:"8137","110db9ee":"8164",d9941f94:"8183",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",f99bae31:"8927","54df6b9c":"8962",a94703ab:"9048",d7d99e1d:"9076","1869ccd1":"9108","888071ca":"9187","8c74c05e":"9198","4ab26116":"9276",a8c496ca:"9304",f34cb5e0:"9337",b12d76e5:"9359",a4516edb:"9415","6696f09b":"9417",e3c4fe0a:"9428","6362ac9f":"9431","24ab0ec7":"9439","6bb9ad58":"9448","4624921c":"9510",b91dc83b:"9601",ef43b7e4:"9623",e63578c3:"9641","5e95c892":"9647","0f37fc5e":"9692","5ec2195c":"9708","0600087e":"9713","988b076a":"9758","4d74b396":"9802","8e8fe4d7":"9924",f18c7db7:"9959",a2e1ac23:"9977"}[e]||e,r.p+r.u(e)},(()=>{var e={5354:0,1869:0};r.f.j=(d,c)=>{var a=r.o(e,d)?e[d]:void 0;if(0!==a)if(a)c.push(a[2]);else if(/^(1869|5354)$/.test(d))e[d]=0;else{var b=new Promise(((c,b)=>a=e[d]=[c,b]));c.push(a[2]=b);var f=r.p+r.u(d),t=new Error;r.l(f,(c=>{if(r.o(e,d)&&(0!==(a=e[d])&&(e[d]=void 0),a)){var b=c&&("load"===c.type?"missing":c.type),f=c&&c.target&&c.target.src;t.message="Loading chunk "+d+" failed.\n("+b+": "+f+")",t.name="ChunkLoadError",t.type=b,t.request=f,a[1](t)}}),"chunk-"+d,d)}},r.O.j=d=>0===e[d];var d=(d,c)=>{var a,b,f=c[0],t=c[1],o=c[2],n=0;if(f.some((d=>0!==e[d]))){for(a in t)r.o(t,a)&&(r.m[a]=t[a]);if(o)var i=o(r)}for(d&&d(c);n<f.length;n++)b=f[n],r.o(e,b)&&e[b]&&e[b][0](),e[b]=0;return r.O(i)},c=self.webpackChunknowarp_github_io=self.webpackChunknowarp_github_io||[];c.forEach(d.bind(null,0)),c.push=d.bind(null,c.push.bind(c))})()})(); \ No newline at end of file diff --git a/img/background.svg b/img/background.svg new file mode 100644 index 000000000..400e6725a --- /dev/null +++ b/img/background.svg @@ -0,0 +1,2110 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="https://svgstorm.com" +viewBox = "0 0 1024 1024" +width="1024" +height="1024"> +<g fill="None" fill-opacity="0.0" stroke="#4CACDF" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 0.00 749.00 +C 9.72 745.71 21.22 749.92 27.00 739.00 +C 26.40 742.33 24.37 745.31 25.00 749.00 +C 30.12 747.14 30.99 743.38 31.00 739.00 +C 41.66 747.19 49.76 720.90 53.00 714.00 +C 62.10 720.09 58.77 731.84 59.00 740.00 +C 60.63 738.25 62.18 735.66 62.00 733.00 +C 71.84 732.80 77.06 722.35 75.00 714.00 +C 77.39 715.40 78.40 718.44 79.00 721.00 +C 84.24 718.78 79.91 707.82 76.00 713.00 +C 77.69 707.33 82.99 701.48 83.00 696.00 +C 85.33 697.42 84.66 699.80 84.00 702.00 +C 87.90 703.67 92.84 706.94 92.00 712.00 +C 87.42 708.91 88.67 709.92 87.00 715.00 +C 84.96 714.19 84.03 711.73 82.00 711.00 +C 84.25 715.35 88.89 721.19 94.00 722.00 +C 96.28 717.64 95.27 713.29 100.00 711.00 +C 98.61 714.94 98.36 718.22 96.00 722.00 +C 99.70 721.86 99.47 714.18 104.00 717.00 +C 103.09 712.80 106.14 710.14 110.00 710.00 +C 101.39 737.59 64.54 740.99 56.00 768.00 +C 88.53 746.59 124.01 729.89 157.00 709.00 +C 157.53 711.46 156.42 714.13 154.00 715.00 +C 155.04 719.45 159.38 723.96 156.00 729.00 +C 157.28 729.28 159.50 728.24 160.00 730.00 +C 163.91 729.85 167.36 730.11 171.00 729.00 +C 179.74 716.41 153.36 714.35 171.00 700.00 +C 167.78 701.65 151.03 706.59 154.00 701.00 +C 150.01 706.33 149.39 699.86 146.00 704.00 +C 183.88 650.82 275.80 649.86 311.92 589.92 C 348.04 529.97 421.28 508.19 454.00 449.00 +C 429.76 477.35 397.93 496.08 369.00 517.00 +C 365.80 517.64 369.47 513.27 366.00 513.00 +C 367.07 520.08 362.30 513.87 360.00 515.00 +C 394.32 445.88 488.63 431.80 511.00 354.00 +C 488.53 367.28 458.85 374.54 454.00 403.00 +C 457.36 405.17 444.12 423.38 432.77 425.77 C 421.42 428.16 408.87 442.58 400.00 446.00 +C 402.38 442.20 406.68 439.76 409.00 436.00 +C 403.63 436.19 399.56 444.65 395.00 444.00 +C 391.61 448.03 394.80 445.51 398.00 445.00 +C 396.00 448.89 398.54 448.25 401.00 449.00 +C 388.63 454.67 380.81 465.87 367.00 469.00 +C 364.25 479.31 353.26 487.24 346.00 494.00 +C 350.92 484.30 356.64 475.53 362.00 467.00 +C 352.25 479.98 329.53 484.58 321.00 501.00 +C 337.05 477.66 336.72 446.74 353.00 424.00 +C 370.79 406.21 398.13 389.45 409.25 366.25 C 420.36 343.04 451.13 327.69 461.00 304.00 +C 463.39 298.27 466.17 294.12 471.00 290.00 +C 486.71 270.88 497.83 246.40 515.00 229.00 +C 518.78 239.27 528.26 246.40 535.00 255.00 +C 544.63 263.91 557.87 268.39 564.00 281.00 +C 566.40 282.13 566.28 275.65 567.00 280.00 +C 568.37 279.23 567.39 277.54 569.00 277.00 +C 581.03 290.67 579.29 309.52 590.31 323.70 C 601.32 337.87 601.85 360.74 605.93 377.07 C 610.00 393.41 617.92 413.55 622.92 428.08 C 627.93 442.60 635.74 469.08 647.00 463.00 +C 664.45 489.96 698.50 501.71 714.00 529.00 +C 717.79 529.81 720.88 528.32 724.00 527.00 +C 739.59 541.50 750.51 560.48 772.00 569.00 +C 783.12 559.93 786.58 586.25 797.00 589.00 +C 797.53 585.98 798.78 581.23 803.00 582.00 +C 802.30 585.52 804.01 588.40 806.00 591.00 +C 808.42 589.70 810.04 587.43 811.00 585.00 +C 815.00 586.54 819.64 585.87 824.00 586.00 +C 825.54 592.62 838.11 604.83 844.00 598.00 +C 859.71 609.33 873.20 623.65 892.08 610.08 C 910.95 596.50 919.82 631.70 932.25 638.75 C 944.67 645.80 965.07 671.46 977.00 657.00 +C 982.19 661.87 988.68 657.53 994.00 662.00 +C 994.63 676.75 1015.94 667.43 1023.00 676.00 +C 1023.14 676.22 1024.00 676.00 1024.00 676.00 +L 1024.00 675.00 +C 1021.67 450.91 1023.67 224.85 1023.00 0.00 +L 0.00 0.00 +L 0.00 749.00 +M 265.00 572.00 +C 250.09 571.50 239.48 593.51 226.00 595.00 +C 228.73 592.11 226.96 591.92 224.00 593.00 +C 225.37 589.20 227.11 585.61 229.00 582.00 +C 239.24 582.55 251.01 563.44 260.00 559.00 +C 261.96 555.41 262.86 551.52 265.00 548.00 +C 268.00 548.50 270.54 547.43 273.00 546.00 +C 270.36 529.36 301.16 539.12 289.25 548.25 C 277.34 557.38 272.91 559.67 265.00 572.00 +M 224.00 594.00 +C 221.54 600.60 217.03 607.50 211.00 612.00 +C 215.37 606.29 217.91 598.52 224.00 594.00 +M 207.00 612.00 +C 202.42 621.69 199.26 634.37 202.00 645.00 +C 204.20 642.45 205.17 638.82 208.00 637.00 +C 206.66 644.15 200.45 648.92 197.00 655.00 +C 191.85 648.20 196.54 640.67 197.00 633.00 +C 204.04 636.37 194.39 613.84 207.00 612.00 +M 184.00 620.00 +C 187.61 626.45 183.09 634.76 185.00 642.00 +C 182.76 645.00 181.17 642.43 179.00 641.00 +C 186.87 647.94 183.07 655.01 175.00 646.00 +C 174.64 649.06 178.53 651.37 177.00 654.00 +C 172.89 651.60 174.60 645.14 170.00 643.00 +C 175.57 638.51 166.23 630.69 170.00 623.00 +C 176.12 626.75 177.33 615.60 184.00 620.00 +M 192.00 641.00 +C 191.09 634.55 185.18 627.50 189.00 621.00 +C 193.62 625.74 196.31 635.41 192.00 641.00 +M 165.00 646.00 +C 163.83 643.75 162.82 640.68 162.00 638.00 +C 159.97 640.45 165.02 648.92 158.00 648.00 +C 158.67 645.06 156.91 642.82 157.00 640.00 +C 158.64 627.21 173.76 636.34 165.00 646.00 +M 137.00 643.00 +C 140.12 648.46 125.19 663.18 138.00 658.00 +C 138.38 665.15 132.96 678.38 141.00 668.00 +C 141.14 672.29 140.00 676.31 138.00 680.00 +C 149.04 678.69 159.56 651.32 165.32 663.68 C 171.08 676.04 147.88 694.23 147.00 688.00 +C 144.96 695.93 137.97 702.41 129.00 703.00 +C 132.65 697.50 138.06 677.69 128.00 681.00 +C 132.51 676.99 133.29 665.97 125.00 671.00 +C 127.61 667.87 124.23 662.11 129.00 661.00 +C 127.38 663.91 128.51 667.09 131.00 669.00 +C 133.13 662.66 128.46 657.74 128.00 651.00 +C 131.19 648.65 131.88 642.86 137.00 643.00 +M 105.00 669.00 +C 108.57 680.78 117.12 691.02 112.00 704.00 +C 109.05 701.08 108.18 712.83 101.00 712.00 +C 102.85 709.25 99.41 707.98 100.00 705.00 +C 107.24 705.37 101.75 690.16 102.00 684.00 +C 94.43 690.55 104.12 667.00 96.00 661.00 +C 99.78 663.03 99.53 669.25 105.00 669.00 +M 94.00 664.00 +C 94.50 667.68 97.93 670.12 98.00 674.00 +C 92.40 678.22 91.94 684.61 89.00 690.00 +C 85.45 684.44 89.60 678.11 88.00 673.00 +C 81.83 681.09 81.49 693.99 75.00 701.00 +C 72.13 696.18 78.12 692.55 72.00 690.00 +C 76.54 682.43 86.91 677.03 87.00 667.00 +C 90.01 667.58 92.40 666.02 94.00 664.00 +M 72.00 686.00 +C 56.70 693.62 83.42 716.36 64.00 715.00 +C 62.45 710.08 70.26 698.23 61.00 701.00 +C 64.72 696.41 64.95 686.80 72.00 686.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#77C7EF" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 1024.00 675.00 +L 1024.00 0.00 +L 1023.00 0.00 +C 1023.67 224.85 1021.67 450.91 1024.00 675.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#95DCFB" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 471.00 290.00 +C 489.61 274.10 501.06 259.89 513.00 240.00 +C 515.38 242.23 516.29 246.20 520.00 247.00 +C 519.74 244.56 518.24 242.48 518.00 240.00 +C 524.38 242.68 529.11 253.30 535.00 255.00 +C 528.26 246.40 518.78 239.27 515.00 229.00 +C 497.83 246.40 486.71 270.88 471.00 290.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#6FC9FC" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 471.00 290.00 +C 466.17 294.12 463.39 298.27 461.00 304.00 +C 475.43 290.39 502.42 289.18 520.00 288.00 +C 509.31 293.11 503.84 302.80 494.00 309.00 +C 507.42 314.37 482.79 319.72 481.00 328.00 +C 483.46 331.88 456.22 345.06 448.75 359.75 C 441.28 374.44 416.12 379.82 403.31 390.30 C 390.49 400.79 369.99 411.33 363.00 422.00 +C 359.78 422.17 355.44 425.02 353.00 424.00 +C 336.72 446.74 337.05 477.66 321.00 501.00 +C 329.53 484.58 352.25 479.98 362.00 467.00 +C 363.22 465.10 364.67 463.55 364.00 461.00 +C 378.44 457.11 388.84 441.21 401.00 431.00 +C 402.91 435.94 400.24 440.65 395.00 444.00 +C 399.56 444.65 403.63 436.19 409.00 436.00 +C 406.68 439.76 402.38 442.20 400.00 446.00 +C 408.87 442.58 421.42 428.16 432.77 425.77 C 444.12 423.38 457.36 405.17 454.00 403.00 +C 458.85 374.54 488.53 367.28 511.00 354.00 +C 488.63 431.80 394.32 445.88 360.00 515.00 +C 362.30 513.87 367.07 520.08 366.00 513.00 +C 369.47 513.27 365.80 517.64 369.00 517.00 +C 397.93 496.08 429.76 477.35 454.00 449.00 +C 421.28 508.19 348.04 529.97 311.92 589.92 C 275.80 649.86 183.88 650.82 146.00 704.00 +C 149.39 699.86 150.01 706.33 154.00 701.00 +C 151.03 706.59 167.78 701.65 171.00 700.00 +C 174.50 697.15 178.46 694.74 182.00 692.00 +C 205.43 673.87 235.00 667.82 259.00 651.00 +C 255.53 650.06 253.36 653.46 250.00 653.00 +C 298.45 628.66 353.20 606.04 392.25 565.25 C 431.30 524.46 458.11 482.52 501.00 444.00 +C 501.32 443.80 501.91 443.35 502.00 443.00 +C 504.56 432.56 516.41 423.84 521.77 413.77 C 527.13 403.70 530.54 390.24 536.00 381.00 +C 536.07 379.40 533.69 381.66 533.00 381.00 +C 534.15 377.82 537.14 375.47 539.00 373.00 +C 544.81 349.22 578.72 334.56 572.00 303.00 +C 561.22 301.13 569.21 287.55 567.00 280.00 +C 566.28 275.65 566.40 282.13 564.00 281.00 +C 557.87 268.39 544.63 263.91 535.00 255.00 +C 529.11 253.30 524.38 242.68 518.00 240.00 +C 518.24 242.48 519.74 244.56 520.00 247.00 +C 516.29 246.20 515.38 242.23 513.00 240.00 +C 501.06 259.89 489.61 274.10 471.00 290.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#1C71C4" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 567.00 280.00 +C 569.21 287.55 561.22 301.13 572.00 303.00 +C 578.72 334.56 544.81 349.22 539.00 373.00 +C 538.20 376.27 537.45 378.54 536.00 381.00 +C 530.54 390.24 527.13 403.70 521.77 413.77 C 516.41 423.84 504.56 432.56 502.00 443.00 +C 502.43 442.36 503.18 441.36 504.00 441.00 +C 506.03 447.71 502.54 457.36 509.00 461.00 +C 506.98 457.91 509.54 455.55 513.00 456.00 +C 515.40 464.73 521.33 472.37 524.00 481.00 +C 521.96 480.19 521.03 477.73 519.00 477.00 +C 519.16 482.81 524.46 481.54 519.00 486.00 +C 521.01 487.90 522.84 484.63 524.00 486.00 +C 525.25 491.46 528.18 496.40 529.00 502.00 +C 532.96 497.36 524.41 488.32 527.00 483.00 +C 532.84 492.99 534.18 505.00 540.00 515.00 +C 538.03 517.88 537.51 511.50 536.00 514.00 +C 537.10 516.25 537.31 519.96 541.00 519.00 +C 541.65 514.66 539.07 502.65 546.00 498.00 +C 551.97 508.64 566.44 521.57 574.00 534.00 +C 565.71 520.76 557.27 505.71 548.00 494.00 +C 549.75 492.92 552.22 491.89 552.00 489.00 +C 561.49 497.29 572.43 505.03 582.00 514.00 +C 576.80 500.26 566.17 485.82 568.00 471.00 +C 569.96 472.02 566.48 475.45 570.00 476.00 +C 570.35 472.85 570.46 468.70 566.00 470.00 +C 567.36 465.22 560.52 462.44 565.00 457.00 +C 553.43 446.61 554.85 427.06 546.00 414.00 +C 548.10 414.07 549.70 417.01 550.00 419.00 +C 552.44 413.88 556.33 423.14 558.00 419.00 +C 572.51 445.12 586.60 475.25 605.00 495.00 +C 613.13 510.19 616.00 527.75 622.00 544.00 +C 619.70 525.63 614.55 504.95 610.00 486.00 +C 616.24 487.62 619.72 494.53 625.00 498.00 +C 620.06 473.87 598.78 457.86 588.00 437.00 +C 593.84 441.96 596.92 450.69 602.00 455.00 +C 601.89 450.76 607.23 442.28 614.00 444.00 +C 611.63 441.30 610.69 436.13 606.00 437.00 +C 608.91 436.18 607.48 433.05 610.00 433.00 +C 615.00 443.57 625.25 453.78 631.00 461.00 +C 628.88 467.43 632.83 471.09 634.00 477.00 +C 630.38 477.23 631.67 470.77 628.00 471.00 +C 625.86 478.00 625.30 487.15 627.00 495.00 +C 629.87 493.29 630.25 496.24 633.00 497.00 +C 636.42 494.66 634.72 495.48 635.00 492.00 +C 638.75 496.77 636.55 501.98 638.00 509.00 +C 643.43 506.95 635.12 496.33 643.00 497.00 +C 640.56 496.19 636.98 493.78 642.00 495.00 +C 638.81 492.75 641.02 486.71 637.00 486.00 +C 639.08 481.97 641.10 480.12 646.00 480.00 +C 653.93 492.80 668.45 505.06 665.00 522.00 +C 668.20 522.23 672.40 529.24 673.00 523.00 +C 674.79 526.91 676.70 528.28 681.00 527.00 +C 684.78 540.79 694.03 554.88 710.00 558.00 +C 706.71 554.28 703.91 550.14 704.00 545.00 +C 706.70 546.89 707.28 548.92 709.00 548.00 +C 705.27 546.16 710.19 534.53 716.00 541.00 +C 715.38 536.59 714.78 533.03 714.00 529.00 +C 698.50 501.71 664.45 489.96 647.00 463.00 +C 635.74 469.08 627.93 442.60 622.92 428.08 C 617.92 413.55 610.00 393.41 605.93 377.07 C 601.85 360.74 601.32 337.87 590.31 323.70 C 579.29 309.52 581.03 290.67 569.00 277.00 +C 567.39 277.54 568.37 279.23 567.00 280.00 +M 589.00 375.00 +C 589.75 372.09 589.10 370.10 589.00 367.00 +C 591.08 381.38 600.61 394.48 603.00 409.00 +C 595.88 403.12 590.84 391.87 586.00 383.00 +C 592.57 384.32 576.88 369.52 577.00 363.00 +C 581.89 366.09 583.90 372.11 589.00 375.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#93DAFD" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 461.00 304.00 +C 451.13 327.69 420.36 343.04 409.25 366.25 C 398.13 389.45 370.79 406.21 353.00 424.00 +C 355.44 425.02 359.78 422.17 363.00 422.00 +C 369.99 411.33 390.49 400.79 403.31 390.30 C 416.12 379.82 441.28 374.44 448.75 359.75 C 456.22 345.06 483.46 331.88 481.00 328.00 +C 482.79 319.72 507.42 314.37 494.00 309.00 +C 503.84 302.80 509.31 293.11 520.00 288.00 +C 502.42 289.18 475.43 290.39 461.00 304.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2B87DA" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 589.00 375.00 +C 583.90 372.11 581.89 366.09 577.00 363.00 +C 576.88 369.52 592.57 384.32 586.00 383.00 +C 590.84 391.87 595.88 403.12 603.00 409.00 +C 600.61 394.48 591.08 381.38 589.00 367.00 +C 589.10 370.10 589.75 372.09 589.00 375.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#4699D2" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 536.00 381.00 +C 537.45 378.54 538.20 376.27 539.00 373.00 +C 537.14 375.47 534.15 377.82 533.00 381.00 +C 533.69 381.66 536.07 379.40 536.00 381.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#135CAC" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 502.00 443.00 +C 501.91 443.35 501.32 443.80 501.00 444.00 +C 492.91 454.38 491.24 470.08 489.00 483.00 +C 484.27 493.14 460.26 512.37 465.00 521.00 +C 462.50 522.47 460.34 524.34 458.00 526.00 +C 462.42 547.29 474.88 564.78 463.00 584.00 +C 470.14 569.60 487.26 569.53 501.00 568.00 +C 497.88 575.01 491.78 581.98 485.00 586.00 +C 494.49 587.74 503.86 594.11 511.00 601.00 +C 494.95 591.99 479.22 587.51 465.00 595.00 +C 463.56 598.66 460.50 601.75 461.00 606.00 +C 463.13 613.40 477.33 617.94 479.00 626.00 +C 476.81 626.76 475.68 624.70 474.00 624.00 +C 475.27 625.66 469.71 638.60 473.00 643.00 +C 469.53 639.36 466.14 637.96 466.00 643.00 +C 463.41 638.63 463.97 633.45 462.00 629.00 +C 458.52 633.42 455.97 641.63 451.00 646.00 +C 452.55 648.46 455.14 642.94 455.00 647.00 +C 450.97 648.48 456.91 650.04 456.00 653.00 +C 451.93 649.89 444.01 646.96 444.00 655.00 +C 446.96 654.72 446.90 650.80 450.00 651.00 +C 449.40 654.26 450.83 656.91 451.00 660.00 +C 448.79 655.45 439.92 655.30 444.00 662.00 +C 425.86 667.71 433.55 645.36 444.00 641.00 +C 441.02 638.81 440.48 630.48 436.00 635.00 +C 436.17 631.69 438.00 627.95 433.00 628.00 +C 432.86 616.20 423.88 606.38 418.00 597.00 +C 418.54 601.25 422.72 604.36 422.00 609.00 +C 418.41 608.82 415.39 621.32 418.00 624.00 +C 420.06 619.98 417.81 613.72 425.00 614.00 +C 424.75 616.36 423.31 619.00 421.00 620.00 +C 423.38 623.73 421.01 630.56 416.00 628.00 +C 419.24 636.53 391.49 648.68 418.00 641.00 +C 418.44 643.96 415.05 644.47 415.00 647.00 +C 422.38 647.42 425.18 634.60 433.00 639.00 +C 432.39 643.66 429.94 648.23 426.00 651.00 +C 424.49 648.55 429.74 646.62 427.00 645.00 +C 424.07 646.42 423.79 650.05 424.00 653.00 +C 420.94 650.56 420.72 656.16 422.00 657.00 +C 420.51 658.77 417.41 655.99 415.00 657.00 +C 414.36 662.13 418.30 666.34 421.00 670.00 +C 419.93 671.87 416.62 671.57 416.00 674.00 +C 418.22 676.25 420.48 673.54 423.00 674.00 +C 425.69 677.05 429.06 681.00 427.00 685.00 +C 424.35 683.11 424.57 680.56 424.00 678.00 +C 420.77 678.66 418.29 680.76 415.00 681.00 +C 414.78 678.05 413.09 675.07 415.00 672.00 +C 412.69 670.20 410.32 668.22 408.00 671.00 +C 404.63 665.32 404.74 658.67 405.00 652.00 +C 398.75 663.17 404.21 630.62 395.00 643.00 +C 392.75 637.67 388.46 632.90 386.00 628.00 +C 387.61 640.96 407.52 652.04 395.00 657.00 +C 396.83 660.99 396.12 663.84 402.00 664.00 +C 399.31 672.92 414.92 674.84 406.00 683.00 +C 403.65 682.28 398.99 678.97 401.00 684.00 +C 391.42 676.69 396.09 657.58 390.00 650.00 +C 386.43 656.48 391.49 661.18 393.00 667.00 +C 387.40 667.64 382.66 664.57 384.00 659.00 +C 382.68 661.09 380.71 662.60 380.00 665.00 +C 384.72 666.41 388.84 669.44 391.00 674.00 +C 385.40 673.48 379.44 660.44 375.00 671.00 +C 369.65 661.51 378.63 651.91 385.00 646.00 +C 382.24 641.18 383.99 634.40 385.00 629.00 +C 381.51 630.32 381.83 636.25 376.00 634.00 +C 381.02 640.23 371.87 644.25 371.00 650.00 +C 363.86 643.50 362.92 654.97 363.00 660.00 +C 366.20 657.73 364.10 652.38 367.00 650.00 +C 373.72 656.45 361.77 660.90 361.00 667.00 +C 364.48 665.35 366.08 660.49 370.00 660.00 +C 368.48 664.73 368.08 665.56 370.00 669.00 +C 363.83 669.44 363.37 676.56 358.00 678.00 +C 358.81 675.96 361.27 675.03 362.00 673.00 +C 357.68 670.38 357.98 663.45 362.00 661.00 +C 357.66 657.92 354.79 661.26 350.00 661.00 +C 352.58 666.92 359.17 672.67 356.00 679.00 +C 352.09 675.65 354.22 668.97 348.00 669.00 +C 349.00 672.24 351.63 674.31 350.00 678.00 +C 346.34 674.90 344.02 666.74 340.00 673.00 +C 339.37 670.28 342.07 668.59 342.00 666.00 +C 336.80 666.89 334.12 673.59 337.00 678.00 +C 332.40 675.57 332.04 675.20 330.00 681.00 +C 327.78 675.87 335.14 668.32 332.00 663.00 +C 329.72 665.58 328.56 669.05 325.00 670.00 +C 325.77 673.62 326.87 678.71 323.00 681.00 +C 322.35 678.56 323.10 674.81 321.00 672.00 +C 327.18 667.29 335.09 651.76 342.00 658.00 +C 337.29 644.67 353.96 646.83 357.00 638.00 +C 354.66 638.06 350.70 643.11 353.00 638.00 +C 341.30 645.78 329.94 655.00 321.00 666.00 +C 310.61 661.55 304.77 678.12 296.00 683.00 +C 294.86 684.59 292.44 692.82 299.00 691.00 +C 297.28 695.39 298.14 702.99 292.00 704.00 +C 292.57 699.37 294.83 692.69 291.00 689.00 +C 290.30 691.62 285.92 699.75 291.00 695.00 +C 291.72 698.10 290.06 700.75 287.00 699.00 +C 285.28 702.04 287.19 704.69 287.00 708.00 +C 282.22 708.94 283.37 703.92 281.00 701.00 +C 278.35 703.47 282.03 707.03 282.00 710.00 +C 276.54 711.21 279.35 704.42 276.00 703.00 +C 273.93 706.17 278.26 710.15 276.00 714.00 +C 278.13 710.06 279.75 714.03 279.00 717.00 +C 270.62 714.31 270.29 702.08 275.00 696.00 +C 270.72 702.48 264.10 710.13 258.00 716.00 +C 267.10 712.42 254.24 717.99 256.00 721.00 +C 252.29 719.29 252.58 720.92 249.00 720.00 +C 249.45 722.52 249.88 724.60 249.00 727.00 +C 252.47 727.69 253.42 722.89 257.00 723.00 +C 254.94 726.69 258.10 734.87 252.00 734.00 +C 253.07 731.69 254.55 729.36 252.00 728.00 +C 248.63 733.19 247.60 727.28 247.00 724.00 +C 246.22 729.01 240.99 731.28 237.00 734.00 +C 236.42 727.92 240.22 723.49 241.00 718.00 +C 238.71 723.49 236.55 719.46 232.00 722.00 +C 233.05 724.82 235.11 725.03 237.00 723.00 +C 235.93 729.57 224.19 735.30 230.00 742.00 +C 226.98 742.61 227.43 738.51 225.00 738.00 +C 220.79 738.67 219.64 745.46 217.00 749.00 +C 215.49 745.25 212.20 746.40 209.00 747.00 +C 217.25 747.11 216.81 757.19 209.00 758.00 +C 210.29 755.07 212.56 752.49 212.00 749.00 +C 185.47 761.13 160.88 785.19 138.00 805.00 +C 154.91 779.70 183.62 766.99 202.00 744.00 +C 203.74 741.69 223.64 718.63 235.00 708.00 +C 234.54 705.49 225.22 705.06 223.00 705.00 +C 213.54 707.31 206.29 707.37 198.00 713.00 +C 190.19 718.30 180.09 726.24 171.00 729.00 +C 167.36 730.11 163.91 729.85 160.00 730.00 +C 127.94 731.22 115.22 767.23 85.30 776.30 C 55.39 785.38 28.85 801.93 0.00 808.00 +L 0.00 898.00 +C 40.28 878.62 96.14 887.60 131.23 854.23 C 166.32 820.86 206.42 812.84 246.00 848.00 +C 271.02 854.94 299.22 872.68 327.00 854.00 +C 325.57 854.09 322.01 852.69 321.00 852.00 +C 323.32 850.73 326.99 849.32 329.00 852.00 +C 329.47 848.89 327.72 846.95 332.00 850.00 +C 329.62 844.15 337.92 849.26 342.00 843.00 +C 337.64 839.06 345.57 839.47 340.00 836.00 +C 344.34 835.65 344.93 832.12 347.00 830.00 +C 342.90 829.99 342.00 830.88 341.00 826.00 +C 338.95 827.61 342.20 830.30 339.00 831.00 +C 339.12 827.44 334.80 830.51 333.00 831.00 +C 333.93 826.96 339.91 826.33 342.00 823.00 +C 333.91 825.24 327.52 832.31 319.00 833.00 +C 332.11 821.12 339.06 801.58 358.00 797.00 +C 357.34 791.35 378.68 778.93 381.00 781.00 +C 383.36 769.62 393.39 760.85 400.00 753.00 +C 401.45 755.02 401.40 754.55 403.00 753.00 +C 404.94 741.66 415.75 728.69 423.00 724.00 +C 414.21 715.64 429.11 700.85 434.00 692.00 +C 441.13 685.40 452.63 678.26 460.00 673.00 +C 464.02 669.10 467.95 663.96 472.00 660.00 +C 473.76 656.20 473.55 654.74 474.00 651.00 +C 474.59 646.17 477.19 643.30 482.00 643.00 +C 482.31 641.14 480.85 637.70 485.00 637.00 +C 487.39 639.27 486.35 643.16 487.00 645.00 +C 491.62 642.51 495.44 638.38 501.00 638.00 +C 505.29 647.03 515.09 645.48 523.00 647.00 +C 537.72 638.88 554.64 644.18 569.01 634.01 C 583.37 623.83 600.85 635.03 616.00 632.00 +C 616.62 631.63 617.66 630.77 618.00 630.00 +C 605.01 623.52 590.12 618.36 579.00 607.00 +C 565.99 597.82 547.48 589.04 536.00 577.00 +C 532.79 589.31 547.52 597.67 559.00 608.00 +C 533.40 596.54 523.86 568.32 506.00 549.00 +C 499.77 539.35 482.51 534.21 478.00 522.00 +C 498.53 541.10 526.57 543.34 548.00 560.00 +C 565.33 568.20 579.29 585.61 594.00 597.00 +C 607.55 602.85 629.20 621.39 644.00 622.00 +C 653.44 618.47 662.51 616.00 673.00 616.00 +C 681.07 616.00 689.27 616.42 697.00 615.00 +C 639.64 668.97 576.85 718.91 516.00 769.00 +C 508.24 777.48 495.47 780.17 487.00 788.00 +C 484.57 790.25 481.68 792.22 479.00 794.00 +C 512.40 801.92 547.54 801.07 579.00 787.00 +C 576.29 793.35 574.93 802.26 567.00 805.00 +C 571.94 805.98 574.91 801.15 579.00 800.00 +C 583.76 807.36 600.33 788.00 612.08 778.08 C 623.84 768.16 639.94 757.24 656.07 753.07 C 672.21 748.90 695.25 747.74 709.70 737.70 C 724.14 727.65 737.00 717.08 753.00 711.00 +C 726.21 711.49 712.29 697.74 694.00 681.00 +C 696.41 671.52 700.90 662.75 705.00 654.00 +C 696.95 658.66 706.47 637.64 709.00 633.00 +C 705.69 626.95 712.43 622.07 712.00 616.00 +C 709.91 604.37 734.01 619.66 744.25 628.75 C 754.49 637.84 773.63 643.70 785.25 653.75 C 796.87 663.81 807.32 677.34 823.23 680.77 C 839.14 684.20 856.45 690.36 871.25 698.75 C 886.05 707.14 914.66 692.53 929.00 699.00 +C 942.86 702.44 963.73 733.16 976.00 723.00 +C 980.32 727.43 977.17 725.28 982.00 725.00 +C 980.59 722.11 979.33 720.16 978.00 717.00 +C 991.66 724.00 1006.68 728.33 1023.00 727.00 +C 1021.56 710.91 1021.55 692.09 1023.00 676.00 +C 1015.94 667.43 994.63 676.75 994.00 662.00 +C 988.68 657.53 982.19 661.87 977.00 657.00 +C 965.07 671.46 944.67 645.80 932.25 638.75 C 919.82 631.70 910.95 596.50 892.08 610.08 C 873.20 623.65 859.71 609.33 844.00 598.00 +C 838.11 604.83 825.54 592.62 824.00 586.00 +C 819.64 585.87 815.00 586.54 811.00 585.00 +C 810.04 587.43 808.42 589.70 806.00 591.00 +C 804.01 588.40 802.30 585.52 803.00 582.00 +C 798.78 581.23 797.53 585.98 797.00 589.00 +C 786.58 586.25 783.12 559.93 772.00 569.00 +C 750.51 560.48 739.59 541.50 724.00 527.00 +C 720.88 528.32 717.79 529.81 714.00 529.00 +C 714.78 533.03 715.38 536.59 716.00 541.00 +C 710.19 534.53 705.27 546.16 709.00 548.00 +C 707.28 548.92 706.70 546.89 704.00 545.00 +C 703.91 550.14 706.71 554.28 710.00 558.00 +C 694.03 554.88 684.78 540.79 681.00 527.00 +C 676.70 528.28 674.79 526.91 673.00 523.00 +C 672.40 529.24 668.20 522.23 665.00 522.00 +C 668.45 505.06 653.93 492.80 646.00 480.00 +C 641.10 480.12 639.08 481.97 637.00 486.00 +C 641.02 486.71 638.81 492.75 642.00 495.00 +C 636.98 493.78 640.56 496.19 643.00 497.00 +C 635.12 496.33 643.43 506.95 638.00 509.00 +C 636.55 501.98 638.75 496.77 635.00 492.00 +C 634.72 495.48 636.42 494.66 633.00 497.00 +C 630.25 496.24 629.87 493.29 627.00 495.00 +C 625.30 487.15 625.86 478.00 628.00 471.00 +C 631.67 470.77 630.38 477.23 634.00 477.00 +C 632.83 471.09 628.88 467.43 631.00 461.00 +C 625.25 453.78 615.00 443.57 610.00 433.00 +C 607.48 433.05 608.91 436.18 606.00 437.00 +C 610.69 436.13 611.63 441.30 614.00 444.00 +C 607.23 442.28 601.89 450.76 602.00 455.00 +C 596.92 450.69 593.84 441.96 588.00 437.00 +C 598.78 457.86 620.06 473.87 625.00 498.00 +C 619.72 494.53 616.24 487.62 610.00 486.00 +C 614.55 504.95 619.70 525.63 622.00 544.00 +C 616.00 527.75 613.13 510.19 605.00 495.00 +C 586.60 475.25 572.51 445.12 558.00 419.00 +C 556.33 423.14 552.44 413.88 550.00 419.00 +C 549.70 417.01 548.10 414.07 546.00 414.00 +C 554.85 427.06 553.43 446.61 565.00 457.00 +C 560.52 462.44 567.36 465.22 566.00 470.00 +C 570.46 468.70 570.35 472.85 570.00 476.00 +C 566.48 475.45 569.96 472.02 568.00 471.00 +C 566.17 485.82 576.80 500.26 582.00 514.00 +C 572.43 505.03 561.49 497.29 552.00 489.00 +C 552.22 491.89 549.75 492.92 548.00 494.00 +C 557.27 505.71 565.71 520.76 574.00 534.00 +C 566.44 521.57 551.97 508.64 546.00 498.00 +C 539.07 502.65 541.65 514.66 541.00 519.00 +C 537.31 519.96 537.10 516.25 536.00 514.00 +C 537.51 511.50 538.03 517.88 540.00 515.00 +C 534.18 505.00 532.84 492.99 527.00 483.00 +C 524.41 488.32 532.96 497.36 529.00 502.00 +C 528.18 496.40 525.25 491.46 524.00 486.00 +C 522.84 484.63 521.01 487.90 519.00 486.00 +C 524.46 481.54 519.16 482.81 519.00 477.00 +C 521.03 477.73 521.96 480.19 524.00 481.00 +C 521.33 472.37 515.40 464.73 513.00 456.00 +C 509.54 455.55 506.98 457.91 509.00 461.00 +C 502.54 457.36 506.03 447.71 504.00 441.00 +C 503.18 441.36 502.43 442.36 502.00 443.00 +M 539.00 604.00 +C 527.73 595.70 515.59 586.82 508.00 574.00 +C 518.37 583.73 530.36 593.44 539.00 604.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2F95E1" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 362.00 467.00 +C 356.64 475.53 350.92 484.30 346.00 494.00 +C 353.26 487.24 364.25 479.31 367.00 469.00 +C 380.81 465.87 388.63 454.67 401.00 449.00 +C 398.54 448.25 396.00 448.89 398.00 445.00 +C 394.80 445.51 391.61 448.03 395.00 444.00 +C 400.24 440.65 402.91 435.94 401.00 431.00 +C 388.84 441.21 378.44 457.11 364.00 461.00 +C 364.67 463.55 363.22 465.10 362.00 467.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#3EA2EB" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 182.00 692.00 +C 191.96 691.43 203.49 702.37 198.00 713.00 +C 206.29 707.37 213.54 707.31 223.00 705.00 +C 251.40 698.07 273.63 678.76 292.00 656.00 +C 287.27 653.16 281.39 648.24 279.00 643.00 +C 326.28 632.80 365.29 594.04 412.00 586.00 +C 429.11 590.70 443.09 609.89 459.00 617.00 +C 458.68 617.18 460.55 607.39 461.00 606.00 +C 460.50 601.75 463.56 598.66 465.00 595.00 +C 479.22 587.51 494.95 591.99 511.00 601.00 +C 503.86 594.11 494.49 587.74 485.00 586.00 +C 491.78 581.98 497.88 575.01 501.00 568.00 +C 487.26 569.53 470.14 569.60 463.00 584.00 +C 474.88 564.78 462.42 547.29 458.00 526.00 +C 460.34 524.34 462.50 522.47 465.00 521.00 +C 460.26 512.37 484.27 493.14 489.00 483.00 +C 491.24 470.08 492.91 454.38 501.00 444.00 +C 458.11 482.52 431.30 524.46 392.25 565.25 C 353.20 606.04 298.45 628.66 250.00 653.00 +C 253.36 653.46 255.53 650.06 259.00 651.00 +C 235.00 667.82 205.43 673.87 182.00 692.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2B86D7" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 506.00 549.00 +C 505.80 548.49 505.34 545.29 504.00 544.00 +C 514.60 539.42 528.91 566.92 534.00 553.00 +C 538.83 554.56 543.35 561.99 548.00 560.00 +C 526.57 543.34 498.53 541.10 478.00 522.00 +C 482.51 534.21 499.77 539.35 506.00 549.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#217FD1" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 265.00 572.00 +C 272.91 559.67 277.34 557.38 289.25 548.25 C 301.16 539.12 270.36 529.36 273.00 546.00 +C 270.54 547.43 268.00 548.50 265.00 548.00 +C 262.86 551.52 261.96 555.41 260.00 559.00 +C 251.01 563.44 239.24 582.55 229.00 582.00 +C 227.11 585.61 225.37 589.20 224.00 593.00 +C 226.96 591.92 228.73 592.11 226.00 595.00 +C 239.48 593.51 250.09 571.50 265.00 572.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#1A71C4" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 506.00 549.00 +C 523.86 568.32 533.40 596.54 559.00 608.00 +C 547.52 597.67 532.79 589.31 536.00 577.00 +C 547.48 589.04 565.99 597.82 579.00 607.00 +C 577.82 605.62 576.85 603.61 575.00 603.00 +C 574.76 599.41 578.45 602.43 580.00 603.00 +C 567.56 589.44 542.36 585.01 536.00 565.00 +C 549.25 578.18 564.58 589.02 581.00 596.00 +C 578.15 590.56 570.62 588.99 569.00 583.00 +C 577.23 587.65 584.75 593.96 594.00 597.00 +C 579.29 585.61 565.33 568.20 548.00 560.00 +C 543.35 561.99 538.83 554.56 534.00 553.00 +C 528.91 566.92 514.60 539.42 504.00 544.00 +C 505.34 545.29 505.80 548.49 506.00 549.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2482D4" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 579.00 607.00 +C 590.12 618.36 605.01 623.52 618.00 630.00 +C 617.66 630.77 616.62 631.63 616.00 632.00 +C 626.68 629.86 634.32 625.62 644.00 622.00 +C 629.20 621.39 607.55 602.85 594.00 597.00 +C 584.75 593.96 577.23 587.65 569.00 583.00 +C 570.62 588.99 578.15 590.56 581.00 596.00 +C 564.58 589.02 549.25 578.18 536.00 565.00 +C 542.36 585.01 567.56 589.44 580.00 603.00 +C 578.45 602.43 574.76 599.41 575.00 603.00 +C 576.85 603.61 577.82 605.62 579.00 607.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2579CA" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 539.00 604.00 +C 530.36 593.44 518.37 583.73 508.00 574.00 +C 515.59 586.82 527.73 595.70 539.00 604.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#3291DF" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 223.00 705.00 +C 225.22 705.06 234.54 705.49 235.00 708.00 +C 236.60 706.27 238.54 704.00 240.00 702.00 +C 243.99 703.41 250.38 703.66 251.00 698.00 +C 264.92 700.68 277.12 691.17 285.00 680.00 +C 288.65 680.82 291.77 686.33 296.00 683.00 +C 304.77 678.12 310.61 661.55 321.00 666.00 +C 329.94 655.00 341.30 645.78 353.00 638.00 +C 361.79 632.15 365.87 621.61 374.00 615.00 +C 391.41 619.04 413.41 603.10 412.00 586.00 +C 365.29 594.04 326.28 632.80 279.00 643.00 +C 281.39 648.24 287.27 653.16 292.00 656.00 +C 273.63 678.76 251.40 698.07 223.00 705.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#0A458D" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 353.00 638.00 +C 350.70 643.11 354.66 638.06 357.00 638.00 +C 353.96 646.83 337.29 644.67 342.00 658.00 +C 335.09 651.76 327.18 667.29 321.00 672.00 +C 323.10 674.81 322.35 678.56 323.00 681.00 +C 326.87 678.71 325.77 673.62 325.00 670.00 +C 328.56 669.05 329.72 665.58 332.00 663.00 +C 335.14 668.32 327.78 675.87 330.00 681.00 +C 332.04 675.20 332.40 675.57 337.00 678.00 +C 334.12 673.59 336.80 666.89 342.00 666.00 +C 342.07 668.59 339.37 670.28 340.00 673.00 +C 344.02 666.74 346.34 674.90 350.00 678.00 +C 351.63 674.31 349.00 672.24 348.00 669.00 +C 354.22 668.97 352.09 675.65 356.00 679.00 +C 359.17 672.67 352.58 666.92 350.00 661.00 +C 354.79 661.26 357.66 657.92 362.00 661.00 +C 357.98 663.45 357.68 670.38 362.00 673.00 +C 361.27 675.03 358.81 675.96 358.00 678.00 +C 363.37 676.56 363.83 669.44 370.00 669.00 +C 368.08 665.56 368.48 664.73 370.00 660.00 +C 366.08 660.49 364.48 665.35 361.00 667.00 +C 361.77 660.90 373.72 656.45 367.00 650.00 +C 364.10 652.38 366.20 657.73 363.00 660.00 +C 362.92 654.97 363.86 643.50 371.00 650.00 +C 371.87 644.25 381.02 640.23 376.00 634.00 +C 381.83 636.25 381.51 630.32 385.00 629.00 +C 383.99 634.40 382.24 641.18 385.00 646.00 +C 378.63 651.91 369.65 661.51 375.00 671.00 +C 379.44 660.44 385.40 673.48 391.00 674.00 +C 388.84 669.44 384.72 666.41 380.00 665.00 +C 380.71 662.60 382.68 661.09 384.00 659.00 +C 382.66 664.57 387.40 667.64 393.00 667.00 +C 391.49 661.18 386.43 656.48 390.00 650.00 +C 396.09 657.58 391.42 676.69 401.00 684.00 +C 398.99 678.97 403.65 682.28 406.00 683.00 +C 414.92 674.84 399.31 672.92 402.00 664.00 +C 396.12 663.84 396.83 660.99 395.00 657.00 +C 407.52 652.04 387.61 640.96 386.00 628.00 +C 388.46 632.90 392.75 637.67 395.00 643.00 +C 404.21 630.62 398.75 663.17 405.00 652.00 +C 404.74 658.67 404.63 665.32 408.00 671.00 +C 410.32 668.22 412.69 670.20 415.00 672.00 +C 413.09 675.07 414.78 678.05 415.00 681.00 +C 418.29 680.76 420.77 678.66 424.00 678.00 +C 424.57 680.56 424.35 683.11 427.00 685.00 +C 429.06 681.00 425.69 677.05 423.00 674.00 +C 420.48 673.54 418.22 676.25 416.00 674.00 +C 416.62 671.57 419.93 671.87 421.00 670.00 +C 418.30 666.34 414.36 662.13 415.00 657.00 +C 417.41 655.99 420.51 658.77 422.00 657.00 +C 420.72 656.16 420.94 650.56 424.00 653.00 +C 423.79 650.05 424.07 646.42 427.00 645.00 +C 429.74 646.62 424.49 648.55 426.00 651.00 +C 429.94 648.23 432.39 643.66 433.00 639.00 +C 425.18 634.60 422.38 647.42 415.00 647.00 +C 415.05 644.47 418.44 643.96 418.00 641.00 +C 391.49 648.68 419.24 636.53 416.00 628.00 +C 421.01 630.56 423.38 623.73 421.00 620.00 +C 423.31 619.00 424.75 616.36 425.00 614.00 +C 417.81 613.72 420.06 619.98 418.00 624.00 +C 415.39 621.32 418.41 608.82 422.00 609.00 +C 422.72 604.36 418.54 601.25 418.00 597.00 +C 423.88 606.38 432.86 616.20 433.00 628.00 +C 438.00 627.95 436.17 631.69 436.00 635.00 +C 440.48 630.48 441.02 638.81 444.00 641.00 +C 433.55 645.36 425.86 667.71 444.00 662.00 +C 439.92 655.30 448.79 655.45 451.00 660.00 +C 450.83 656.91 449.40 654.26 450.00 651.00 +C 446.90 650.80 446.96 654.72 444.00 655.00 +C 444.01 646.96 451.93 649.89 456.00 653.00 +C 456.91 650.04 450.97 648.48 455.00 647.00 +C 455.14 642.94 452.55 648.46 451.00 646.00 +C 455.97 641.63 458.52 633.42 462.00 629.00 +C 463.97 633.45 463.41 638.63 466.00 643.00 +C 466.14 637.96 469.53 639.36 473.00 643.00 +C 469.71 638.60 475.27 625.66 474.00 624.00 +C 468.79 621.94 463.93 619.20 459.00 617.00 +C 443.09 609.89 429.11 590.70 412.00 586.00 +C 413.41 603.10 391.41 619.04 374.00 615.00 +C 365.87 621.61 361.79 632.15 353.00 638.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#298FD9" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 224.00 594.00 +C 217.91 598.52 215.37 606.29 211.00 612.00 +C 217.03 607.50 221.54 600.60 224.00 594.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2781D0" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 459.00 617.00 +C 463.93 619.20 468.79 621.94 474.00 624.00 +C 475.68 624.70 476.81 626.76 479.00 626.00 +C 477.33 617.94 463.13 613.40 461.00 606.00 +C 460.55 607.39 458.68 617.18 459.00 617.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#0E4182" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 487.00 788.00 +C 473.54 796.68 459.30 782.68 445.00 791.00 +C 437.58 796.52 441.37 802.11 431.00 804.00 +C 418.06 806.36 410.96 807.25 400.00 815.00 +C 377.54 830.88 351.79 843.18 327.00 854.00 +C 299.22 872.68 271.02 854.94 246.00 848.00 +C 206.42 812.84 166.32 820.86 131.23 854.23 C 96.14 887.60 40.28 878.62 0.00 898.00 +L 0.00 1023.00 +C 113.50 1024.86 227.56 1020.52 341.00 1023.00 C 454.44 1025.48 568.77 1018.25 682.00 1023.00 C 795.23 1027.75 910.26 1012.81 1023.00 1023.00 +C 1023.08 925.67 1014.24 823.88 1023.00 727.00 +C 1006.68 728.33 991.66 724.00 978.00 717.00 +C 979.33 720.16 980.59 722.11 982.00 725.00 +C 977.17 725.28 980.32 727.43 976.00 723.00 +C 963.73 733.16 942.86 702.44 929.00 699.00 +C 914.66 692.53 886.05 707.14 871.25 698.75 C 856.45 690.36 839.14 684.20 823.23 680.77 C 807.32 677.34 796.87 663.81 785.25 653.75 C 773.63 643.70 754.49 637.84 744.25 628.75 C 734.01 619.66 709.91 604.37 712.00 616.00 +C 712.43 622.07 705.69 626.95 709.00 633.00 +C 706.47 637.64 696.95 658.66 705.00 654.00 +C 700.90 662.75 696.41 671.52 694.00 681.00 +C 712.29 697.74 726.21 711.49 753.00 711.00 +C 737.00 717.08 724.14 727.65 709.70 737.70 C 695.25 747.74 672.21 748.90 656.07 753.07 C 639.94 757.24 623.84 768.16 612.08 778.08 C 600.33 788.00 583.76 807.36 579.00 800.00 +C 574.91 801.15 571.94 805.98 567.00 805.00 +C 574.93 802.26 576.29 793.35 579.00 787.00 +C 547.54 801.07 512.40 801.92 479.00 794.00 +C 481.68 792.22 484.57 790.25 487.00 788.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#3198E4" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 207.00 612.00 +C 194.39 613.84 204.04 636.37 197.00 633.00 +C 196.54 640.67 191.85 648.20 197.00 655.00 +C 200.45 648.92 206.66 644.15 208.00 637.00 +C 205.17 638.82 204.20 642.45 202.00 645.00 +C 199.26 634.37 202.42 621.69 207.00 612.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#44AAF1" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 673.00 616.00 +C 676.93 616.38 682.36 617.80 687.00 617.00 +C 665.44 612.73 651.04 633.09 638.00 641.00 +C 642.90 634.47 651.07 628.37 655.00 621.00 +C 640.53 627.75 632.41 639.18 618.00 643.00 +C 618.77 638.52 620.64 638.51 623.00 633.00 +C 607.37 638.58 602.61 659.24 588.00 664.00 +C 586.45 672.45 569.33 681.91 559.00 683.00 +C 558.96 679.85 563.02 678.70 564.00 676.00 +C 559.75 675.42 554.60 675.62 551.00 674.00 +C 559.49 668.16 568.06 661.78 575.00 654.00 +C 563.85 657.01 555.04 665.71 544.00 665.00 +C 544.98 662.99 547.36 662.36 549.00 661.00 +C 540.23 657.70 554.26 653.27 556.00 648.00 +C 552.25 648.45 550.76 653.30 547.00 654.00 +C 547.28 651.25 545.88 649.53 547.00 647.00 +C 542.78 646.96 542.13 652.31 538.00 653.00 +C 537.73 650.25 541.29 649.32 542.00 647.00 +C 531.58 649.24 523.39 656.96 513.00 659.00 +C 514.28 653.35 518.76 650.21 523.00 647.00 +C 515.09 645.48 505.29 647.03 501.00 638.00 +C 495.44 638.38 491.62 642.51 487.00 645.00 +C 483.07 647.12 477.74 647.80 474.00 651.00 +C 473.55 654.74 473.76 656.20 472.00 660.00 +C 469.39 665.64 464.82 669.56 460.00 673.00 +C 452.63 678.26 441.13 685.40 434.00 692.00 +C 423.91 705.99 433.08 722.91 427.00 739.00 +C 417.96 738.58 425.07 726.84 420.00 725.00 +C 417.66 733.97 409.33 741.74 408.00 751.00 +C 411.74 750.49 422.96 741.90 421.00 747.00 +C 435.56 743.92 436.66 722.57 453.00 723.00 +C 456.74 730.22 449.39 734.58 446.00 740.00 +C 453.35 736.10 458.36 727.70 466.00 724.00 +C 465.08 728.91 464.61 731.73 461.00 735.00 +C 468.55 734.44 474.30 729.62 480.00 725.00 +C 470.99 734.98 458.71 743.50 450.00 755.00 +C 462.31 745.87 472.55 732.24 486.00 725.00 +C 484.20 729.57 490.03 729.26 494.00 728.00 +C 490.89 730.00 486.24 735.09 493.00 733.00 +C 488.30 742.00 480.37 747.55 474.00 755.00 +C 478.26 753.34 491.07 740.27 487.00 750.00 +C 490.49 749.53 492.37 745.25 496.00 745.00 +C 492.65 750.07 490.23 751.18 495.00 753.00 +C 492.22 753.38 490.91 756.22 489.00 758.00 +C 492.81 759.98 494.82 752.91 498.00 751.00 +C 496.23 760.32 486.97 765.43 482.00 773.00 +C 496.16 766.42 506.26 749.65 523.00 748.00 +C 519.17 751.04 519.82 751.74 517.00 757.00 +C 519.06 755.70 520.95 756.42 523.00 757.00 +C 519.37 753.62 524.36 752.11 528.00 752.00 +C 522.96 757.69 523.47 763.21 516.00 769.00 +C 576.85 718.91 639.64 668.97 697.00 615.00 +C 689.27 616.42 681.07 616.00 673.00 616.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#62C4FB" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 644.00 622.00 +C 634.32 625.62 626.68 629.86 616.00 632.00 +C 600.85 635.03 583.37 623.83 569.01 634.01 C 554.64 644.18 537.72 638.88 523.00 647.00 +C 518.76 650.21 514.28 653.35 513.00 659.00 +C 523.39 656.96 531.58 649.24 542.00 647.00 +C 541.29 649.32 537.73 650.25 538.00 653.00 +C 542.13 652.31 542.78 646.96 547.00 647.00 +C 545.88 649.53 547.28 651.25 547.00 654.00 +C 550.76 653.30 552.25 648.45 556.00 648.00 +C 554.26 653.27 540.23 657.70 549.00 661.00 +C 547.36 662.36 544.98 662.99 544.00 665.00 +C 555.04 665.71 563.85 657.01 575.00 654.00 +C 568.06 661.78 559.49 668.16 551.00 674.00 +C 554.60 675.62 559.75 675.42 564.00 676.00 +C 563.02 678.70 558.96 679.85 559.00 683.00 +C 569.33 681.91 586.45 672.45 588.00 664.00 +C 602.61 659.24 607.37 638.58 623.00 633.00 +C 620.64 638.51 618.77 638.52 618.00 643.00 +C 632.41 639.18 640.53 627.75 655.00 621.00 +C 651.07 628.37 642.90 634.47 638.00 641.00 +C 651.04 633.09 665.44 612.73 687.00 617.00 +C 682.36 617.80 676.93 616.38 673.00 616.00 +C 662.51 616.00 653.44 618.47 644.00 622.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2F93E0" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 184.00 620.00 +C 177.33 615.60 176.12 626.75 170.00 623.00 +C 166.23 630.69 175.57 638.51 170.00 643.00 +C 174.60 645.14 172.89 651.60 177.00 654.00 +C 178.53 651.37 174.64 649.06 175.00 646.00 +C 183.07 655.01 186.87 647.94 179.00 641.00 +C 181.17 642.43 182.76 645.00 185.00 642.00 +C 183.09 634.76 187.61 626.45 184.00 620.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2C90DC" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 192.00 641.00 +C 196.31 635.41 193.62 625.74 189.00 621.00 +C 185.18 627.50 191.09 634.55 192.00 641.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2E93DF" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 165.00 646.00 +C 173.76 636.34 158.64 627.21 157.00 640.00 +C 156.91 642.82 158.67 645.06 158.00 648.00 +C 165.02 648.92 159.97 640.45 162.00 638.00 +C 162.82 640.68 163.83 643.75 165.00 646.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2176C8" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 474.00 651.00 +C 477.74 647.80 483.07 647.12 487.00 645.00 +C 486.35 643.16 487.39 639.27 485.00 637.00 +C 480.85 637.70 482.31 641.14 482.00 643.00 +C 477.19 643.30 474.59 646.17 474.00 651.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#3096E4" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 137.00 643.00 +C 131.88 642.86 131.19 648.65 128.00 651.00 +C 128.46 657.74 133.13 662.66 131.00 669.00 +C 128.51 667.09 127.38 663.91 129.00 661.00 +C 124.23 662.11 127.61 667.87 125.00 671.00 +C 133.29 665.97 132.51 676.99 128.00 681.00 +C 138.06 677.69 132.65 697.50 129.00 703.00 +C 137.97 702.41 144.96 695.93 147.00 688.00 +C 147.88 694.23 171.08 676.04 165.32 663.68 C 159.56 651.32 149.04 678.69 138.00 680.00 +C 140.00 676.31 141.14 672.29 141.00 668.00 +C 132.96 678.38 138.38 665.15 138.00 658.00 +C 125.19 663.18 140.12 648.46 137.00 643.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2882D5" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 460.00 673.00 +C 464.82 669.56 469.39 665.64 472.00 660.00 +C 467.95 663.96 464.02 669.10 460.00 673.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2C91DF" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 105.00 669.00 +C 99.53 669.25 99.78 663.03 96.00 661.00 +C 104.12 667.00 94.43 690.55 102.00 684.00 +C 101.75 690.16 107.24 705.37 100.00 705.00 +C 99.41 707.98 102.85 709.25 101.00 712.00 +C 108.18 712.83 109.05 701.08 112.00 704.00 +C 117.12 691.02 108.57 680.78 105.00 669.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2D93E2" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 94.00 664.00 +C 92.40 666.02 90.01 667.58 87.00 667.00 +C 86.91 677.03 76.54 682.43 72.00 690.00 +C 78.12 692.55 72.13 696.18 75.00 701.00 +C 81.49 693.99 81.83 681.09 88.00 673.00 +C 89.60 678.11 85.45 684.44 89.00 690.00 +C 91.94 684.61 92.40 678.22 98.00 674.00 +C 97.93 670.12 94.50 667.68 94.00 664.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#4A95DB" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 1023.00 727.00 +C 1023.00 726.96 1024.00 727.00 1024.00 727.00 +L 1024.00 676.00 +C 1024.00 676.00 1023.14 676.22 1023.00 676.00 +C 1021.55 692.09 1021.56 710.91 1023.00 727.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#08448D" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 235.00 708.00 +C 223.64 718.63 203.74 741.69 202.00 744.00 +C 183.62 766.99 154.91 779.70 138.00 805.00 +C 160.88 785.19 185.47 761.13 212.00 749.00 +C 212.56 752.49 210.29 755.07 209.00 758.00 +C 216.81 757.19 217.25 747.11 209.00 747.00 +C 212.20 746.40 215.49 745.25 217.00 749.00 +C 219.64 745.46 220.79 738.67 225.00 738.00 +C 227.43 738.51 226.98 742.61 230.00 742.00 +C 224.19 735.30 235.93 729.57 237.00 723.00 +C 235.11 725.03 233.05 724.82 232.00 722.00 +C 236.55 719.46 238.71 723.49 241.00 718.00 +C 240.22 723.49 236.42 727.92 237.00 734.00 +C 240.99 731.28 246.22 729.01 247.00 724.00 +C 247.60 727.28 248.63 733.19 252.00 728.00 +C 254.55 729.36 253.07 731.69 252.00 734.00 +C 258.10 734.87 254.94 726.69 257.00 723.00 +C 253.42 722.89 252.47 727.69 249.00 727.00 +C 249.88 724.60 249.45 722.52 249.00 720.00 +C 252.58 720.92 252.29 719.29 256.00 721.00 +C 254.24 717.99 267.10 712.42 258.00 716.00 +C 264.10 710.13 270.72 702.48 275.00 696.00 +C 270.29 702.08 270.62 714.31 279.00 717.00 +C 279.75 714.03 278.13 710.06 276.00 714.00 +C 278.26 710.15 273.93 706.17 276.00 703.00 +C 279.35 704.42 276.54 711.21 282.00 710.00 +C 282.03 707.03 278.35 703.47 281.00 701.00 +C 283.37 703.92 282.22 708.94 287.00 708.00 +C 287.19 704.69 285.28 702.04 287.00 699.00 +C 290.06 700.75 291.72 698.10 291.00 695.00 +C 285.92 699.75 290.30 691.62 291.00 689.00 +C 294.83 692.69 292.57 699.37 292.00 704.00 +C 298.14 702.99 297.28 695.39 299.00 691.00 +C 292.44 692.82 294.86 684.59 296.00 683.00 +C 291.77 686.33 288.65 680.82 285.00 680.00 +C 277.12 691.17 264.92 700.68 251.00 698.00 +C 250.38 703.66 243.99 703.41 240.00 702.00 +C 238.54 704.00 236.60 706.27 235.00 708.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#329AE7" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 72.00 686.00 +C 64.95 686.80 64.72 696.41 61.00 701.00 +C 70.26 698.23 62.45 710.08 64.00 715.00 +C 83.42 716.36 56.70 693.62 72.00 686.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#2C8EDE" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 171.00 700.00 +C 153.36 714.35 179.74 716.41 171.00 729.00 +C 180.09 726.24 190.19 718.30 198.00 713.00 +C 203.49 702.37 191.96 691.43 182.00 692.00 +C 178.46 694.74 174.50 697.15 171.00 700.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#3194E2" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 403.00 753.00 +C 400.98 764.84 383.40 773.74 382.00 784.00 +C 379.06 783.93 377.32 786.71 375.00 788.00 +C 388.69 790.56 390.27 768.25 403.00 765.00 +C 396.35 776.71 385.20 784.26 379.00 795.00 +C 383.98 793.63 391.32 797.38 393.00 790.00 +C 395.67 790.67 397.77 792.94 401.00 792.00 +C 400.75 794.36 399.31 797.00 397.00 798.00 +C 402.93 802.47 395.02 811.52 400.00 815.00 +C 410.96 807.25 418.06 806.36 431.00 804.00 +C 436.13 800.76 439.56 794.16 445.00 791.00 +C 459.30 782.68 473.54 796.68 487.00 788.00 +C 495.47 780.17 508.24 777.48 516.00 769.00 +C 523.47 763.21 522.96 757.69 528.00 752.00 +C 524.36 752.11 519.37 753.62 523.00 757.00 +C 520.95 756.42 519.06 755.70 517.00 757.00 +C 519.82 751.74 519.17 751.04 523.00 748.00 +C 506.26 749.65 496.16 766.42 482.00 773.00 +C 486.97 765.43 496.23 760.32 498.00 751.00 +C 494.82 752.91 492.81 759.98 489.00 758.00 +C 490.91 756.22 492.22 753.38 495.00 753.00 +C 490.23 751.18 492.65 750.07 496.00 745.00 +C 492.37 745.25 490.49 749.53 487.00 750.00 +C 491.07 740.27 478.26 753.34 474.00 755.00 +C 480.37 747.55 488.30 742.00 493.00 733.00 +C 486.24 735.09 490.89 730.00 494.00 728.00 +C 490.03 729.26 484.20 729.57 486.00 725.00 +C 472.55 732.24 462.31 745.87 450.00 755.00 +C 458.71 743.50 470.99 734.98 480.00 725.00 +C 474.30 729.62 468.55 734.44 461.00 735.00 +C 464.61 731.73 465.08 728.91 466.00 724.00 +C 458.36 727.70 453.35 736.10 446.00 740.00 +C 449.39 734.58 456.74 730.22 453.00 723.00 +C 436.66 722.57 435.56 743.92 421.00 747.00 +C 422.96 741.90 411.74 750.49 408.00 751.00 +C 409.33 741.74 417.66 733.97 420.00 725.00 +C 425.07 726.84 417.96 738.58 427.00 739.00 +C 433.08 722.91 423.91 705.99 434.00 692.00 +C 429.11 700.85 414.21 715.64 423.00 724.00 +C 415.75 728.69 404.94 741.66 403.00 753.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#3297E5" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 0.00 749.00 +L 0.00 808.00 +C 28.85 801.93 55.39 785.38 85.30 776.30 C 115.22 767.23 127.94 731.22 160.00 730.00 +C 159.50 728.24 157.28 729.28 156.00 729.00 +C 159.38 723.96 155.04 719.45 154.00 715.00 +C 156.42 714.13 157.53 711.46 157.00 709.00 +C 124.01 729.89 88.53 746.59 56.00 768.00 +C 64.54 740.99 101.39 737.59 110.00 710.00 +C 106.14 710.14 103.09 712.80 104.00 717.00 +C 99.47 714.18 99.70 721.86 96.00 722.00 +C 98.36 718.22 98.61 714.94 100.00 711.00 +C 95.27 713.29 96.28 717.64 94.00 722.00 +C 88.89 721.19 84.25 715.35 82.00 711.00 +C 84.03 711.73 84.96 714.19 87.00 715.00 +C 88.67 709.92 87.42 708.91 92.00 712.00 +C 92.84 706.94 87.90 703.67 84.00 702.00 +C 84.66 699.80 85.33 697.42 83.00 696.00 +C 82.99 701.48 77.69 707.33 76.00 713.00 +C 79.91 707.82 84.24 718.78 79.00 721.00 +C 78.40 718.44 77.39 715.40 75.00 714.00 +C 77.06 722.35 71.84 732.80 62.00 733.00 +C 62.18 735.66 60.63 738.25 59.00 740.00 +C 58.77 731.84 62.10 720.09 53.00 714.00 +C 49.76 720.90 41.66 747.19 31.00 739.00 +C 30.99 743.38 30.12 747.14 25.00 749.00 +C 24.37 745.31 26.40 742.33 27.00 739.00 +C 21.22 749.92 9.72 745.71 0.00 749.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#4C77AE" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 1023.00 1023.00 +C 1023.00 1023.50 1023.00 1024.00 1023.00 1024.00 +L 1024.00 1024.00 +L 1024.00 727.00 +C 1024.00 727.00 1023.00 726.96 1023.00 727.00 +C 1014.24 823.88 1023.08 925.67 1023.00 1023.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#1F72C5" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 327.00 854.00 +C 351.79 843.18 377.54 830.88 400.00 815.00 +C 395.02 811.52 402.93 802.47 397.00 798.00 +C 399.31 797.00 400.75 794.36 401.00 792.00 +C 397.77 792.94 395.67 790.67 393.00 790.00 +C 391.32 797.38 383.98 793.63 379.00 795.00 +C 385.20 784.26 396.35 776.71 403.00 765.00 +C 390.27 768.25 388.69 790.56 375.00 788.00 +C 377.32 786.71 379.06 783.93 382.00 784.00 +C 383.40 773.74 400.98 764.84 403.00 753.00 +C 401.40 754.55 401.45 755.02 400.00 753.00 +C 393.39 760.85 383.36 769.62 381.00 781.00 +C 378.68 778.93 357.34 791.35 358.00 797.00 +C 339.06 801.58 332.11 821.12 319.00 833.00 +C 327.52 832.31 333.91 825.24 342.00 823.00 +C 339.91 826.33 333.93 826.96 333.00 831.00 +C 334.80 830.51 339.12 827.44 339.00 831.00 +C 342.20 830.30 338.95 827.61 341.00 826.00 +C 342.00 830.88 342.90 829.99 347.00 830.00 +C 344.93 832.12 344.34 835.65 340.00 836.00 +C 345.57 839.47 337.64 839.06 342.00 843.00 +C 337.92 849.26 329.62 844.15 332.00 850.00 +C 327.72 846.95 329.47 848.89 329.00 852.00 +C 326.99 849.32 323.32 850.73 321.00 852.00 +C 322.01 852.69 325.57 854.09 327.00 854.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#246FB9" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 431.00 804.00 +C 441.37 802.11 437.58 796.52 445.00 791.00 +C 439.56 794.16 436.13 800.76 431.00 804.00 Z"/> +</g> +<g fill="None" fill-opacity="0.0" stroke="#265591" stroke-opacity="1.00" stroke-width="0.3"><path d=" +M 0.00 1024.00 +L 1023.00 1024.00 +C 1023.00 1024.00 1023.00 1023.50 1023.00 1023.00 +C 910.26 1012.81 795.23 1027.75 682.00 1023.00 C 568.77 1018.25 454.44 1025.48 341.00 1023.00 C 227.56 1020.52 113.50 1024.86 0.00 1023.00 +L 0.00 1024.00 Z"/> +</g> +<g fill="#4CACDF" fill-opacity="1.00" stroke="None"><path d=" +M 0.00 749.00 +C 9.72 745.71 21.22 749.92 27.00 739.00 +C 26.40 742.33 24.37 745.31 25.00 749.00 +C 30.12 747.14 30.99 743.38 31.00 739.00 +C 41.66 747.19 49.76 720.90 53.00 714.00 +C 62.10 720.09 58.77 731.84 59.00 740.00 +C 60.63 738.25 62.18 735.66 62.00 733.00 +C 71.84 732.80 77.06 722.35 75.00 714.00 +C 77.39 715.40 78.40 718.44 79.00 721.00 +C 84.24 718.78 79.91 707.82 76.00 713.00 +C 77.69 707.33 82.99 701.48 83.00 696.00 +C 85.33 697.42 84.66 699.80 84.00 702.00 +C 87.90 703.67 92.84 706.94 92.00 712.00 +C 87.42 708.91 88.67 709.92 87.00 715.00 +C 84.96 714.19 84.03 711.73 82.00 711.00 +C 84.25 715.35 88.89 721.19 94.00 722.00 +C 96.28 717.64 95.27 713.29 100.00 711.00 +C 98.61 714.94 98.36 718.22 96.00 722.00 +C 99.70 721.86 99.47 714.18 104.00 717.00 +C 103.09 712.80 106.14 710.14 110.00 710.00 +C 101.39 737.59 64.54 740.99 56.00 768.00 +C 88.53 746.59 124.01 729.89 157.00 709.00 +C 157.53 711.46 156.42 714.13 154.00 715.00 +C 155.04 719.45 159.38 723.96 156.00 729.00 +C 157.28 729.28 159.50 728.24 160.00 730.00 +C 163.91 729.85 167.36 730.11 171.00 729.00 +C 179.74 716.41 153.36 714.35 171.00 700.00 +C 167.78 701.65 151.03 706.59 154.00 701.00 +C 150.01 706.33 149.39 699.86 146.00 704.00 +C 183.88 650.82 275.80 649.86 311.92 589.92 C 348.04 529.97 421.28 508.19 454.00 449.00 +C 429.76 477.35 397.93 496.08 369.00 517.00 +C 365.80 517.64 369.47 513.27 366.00 513.00 +C 367.07 520.08 362.30 513.87 360.00 515.00 +C 394.32 445.88 488.63 431.80 511.00 354.00 +C 488.53 367.28 458.85 374.54 454.00 403.00 +C 457.36 405.17 444.12 423.38 432.77 425.77 C 421.42 428.16 408.87 442.58 400.00 446.00 +C 402.38 442.20 406.68 439.76 409.00 436.00 +C 403.63 436.19 399.56 444.65 395.00 444.00 +C 391.61 448.03 394.80 445.51 398.00 445.00 +C 396.00 448.89 398.54 448.25 401.00 449.00 +C 388.63 454.67 380.81 465.87 367.00 469.00 +C 364.25 479.31 353.26 487.24 346.00 494.00 +C 350.92 484.30 356.64 475.53 362.00 467.00 +C 352.25 479.98 329.53 484.58 321.00 501.00 +C 337.05 477.66 336.72 446.74 353.00 424.00 +C 370.79 406.21 398.13 389.45 409.25 366.25 C 420.36 343.04 451.13 327.69 461.00 304.00 +C 463.39 298.27 466.17 294.12 471.00 290.00 +C 486.71 270.88 497.83 246.40 515.00 229.00 +C 518.78 239.27 528.26 246.40 535.00 255.00 +C 544.63 263.91 557.87 268.39 564.00 281.00 +C 566.40 282.13 566.28 275.65 567.00 280.00 +C 568.37 279.23 567.39 277.54 569.00 277.00 +C 581.03 290.67 579.29 309.52 590.31 323.70 C 601.32 337.87 601.85 360.74 605.93 377.07 C 610.00 393.41 617.92 413.55 622.92 428.08 C 627.93 442.60 635.74 469.08 647.00 463.00 +C 664.45 489.96 698.50 501.71 714.00 529.00 +C 717.79 529.81 720.88 528.32 724.00 527.00 +C 739.59 541.50 750.51 560.48 772.00 569.00 +C 783.12 559.93 786.58 586.25 797.00 589.00 +C 797.53 585.98 798.78 581.23 803.00 582.00 +C 802.30 585.52 804.01 588.40 806.00 591.00 +C 808.42 589.70 810.04 587.43 811.00 585.00 +C 815.00 586.54 819.64 585.87 824.00 586.00 +C 825.54 592.62 838.11 604.83 844.00 598.00 +C 859.71 609.33 873.20 623.65 892.08 610.08 C 910.95 596.50 919.82 631.70 932.25 638.75 C 944.67 645.80 965.07 671.46 977.00 657.00 +C 982.19 661.87 988.68 657.53 994.00 662.00 +C 994.63 676.75 1015.94 667.43 1023.00 676.00 +C 1023.14 676.22 1024.00 676.00 1024.00 676.00 +L 1024.00 675.00 +C 1021.67 450.91 1023.67 224.85 1023.00 0.00 +L 0.00 0.00 +L 0.00 749.00 Z"/> +</g> +<g fill="#77C7EF" fill-opacity="1.00" stroke="None"><path d=" +M 1024.00 675.00 +L 1024.00 0.00 +L 1023.00 0.00 +C 1023.67 224.85 1021.67 450.91 1024.00 675.00 Z"/> +</g> +<g fill="#95DCFB" fill-opacity="1.00" stroke="None"><path d=" +M 471.00 290.00 +C 489.61 274.10 501.06 259.89 513.00 240.00 +C 515.38 242.23 516.29 246.20 520.00 247.00 +C 519.74 244.56 518.24 242.48 518.00 240.00 +C 524.38 242.68 529.11 253.30 535.00 255.00 +C 528.26 246.40 518.78 239.27 515.00 229.00 +C 497.83 246.40 486.71 270.88 471.00 290.00 Z"/> +</g> +<g fill="#6FC9FC" fill-opacity="1.00" stroke="None"><path d=" +M 471.00 290.00 +C 466.17 294.12 463.39 298.27 461.00 304.00 +C 475.43 290.39 502.42 289.18 520.00 288.00 +C 509.31 293.11 503.84 302.80 494.00 309.00 +C 507.42 314.37 482.79 319.72 481.00 328.00 +C 483.46 331.88 456.22 345.06 448.75 359.75 C 441.28 374.44 416.12 379.82 403.31 390.30 C 390.49 400.79 369.99 411.33 363.00 422.00 +C 359.78 422.17 355.44 425.02 353.00 424.00 +C 336.72 446.74 337.05 477.66 321.00 501.00 +C 329.53 484.58 352.25 479.98 362.00 467.00 +C 363.22 465.10 364.67 463.55 364.00 461.00 +C 378.44 457.11 388.84 441.21 401.00 431.00 +C 402.91 435.94 400.24 440.65 395.00 444.00 +C 399.56 444.65 403.63 436.19 409.00 436.00 +C 406.68 439.76 402.38 442.20 400.00 446.00 +C 408.87 442.58 421.42 428.16 432.77 425.77 C 444.12 423.38 457.36 405.17 454.00 403.00 +C 458.85 374.54 488.53 367.28 511.00 354.00 +C 488.63 431.80 394.32 445.88 360.00 515.00 +C 362.30 513.87 367.07 520.08 366.00 513.00 +C 369.47 513.27 365.80 517.64 369.00 517.00 +C 397.93 496.08 429.76 477.35 454.00 449.00 +C 421.28 508.19 348.04 529.97 311.92 589.92 C 275.80 649.86 183.88 650.82 146.00 704.00 +C 149.39 699.86 150.01 706.33 154.00 701.00 +C 151.03 706.59 167.78 701.65 171.00 700.00 +C 174.50 697.15 178.46 694.74 182.00 692.00 +C 205.43 673.87 235.00 667.82 259.00 651.00 +C 255.53 650.06 253.36 653.46 250.00 653.00 +C 298.45 628.66 353.20 606.04 392.25 565.25 C 431.30 524.46 458.11 482.52 501.00 444.00 +C 501.32 443.80 501.91 443.35 502.00 443.00 +C 504.56 432.56 516.41 423.84 521.77 413.77 C 527.13 403.70 530.54 390.24 536.00 381.00 +C 536.07 379.40 533.69 381.66 533.00 381.00 +C 534.15 377.82 537.14 375.47 539.00 373.00 +C 544.81 349.22 578.72 334.56 572.00 303.00 +C 561.22 301.13 569.21 287.55 567.00 280.00 +C 566.28 275.65 566.40 282.13 564.00 281.00 +C 557.87 268.39 544.63 263.91 535.00 255.00 +C 529.11 253.30 524.38 242.68 518.00 240.00 +C 518.24 242.48 519.74 244.56 520.00 247.00 +C 516.29 246.20 515.38 242.23 513.00 240.00 +C 501.06 259.89 489.61 274.10 471.00 290.00 Z"/> +</g> +<g fill="#1C71C4" fill-opacity="1.00" stroke="None"><path d=" +M 567.00 280.00 +C 569.21 287.55 561.22 301.13 572.00 303.00 +C 578.72 334.56 544.81 349.22 539.00 373.00 +C 538.20 376.27 537.45 378.54 536.00 381.00 +C 530.54 390.24 527.13 403.70 521.77 413.77 C 516.41 423.84 504.56 432.56 502.00 443.00 +C 502.43 442.36 503.18 441.36 504.00 441.00 +C 506.03 447.71 502.54 457.36 509.00 461.00 +C 506.98 457.91 509.54 455.55 513.00 456.00 +C 515.40 464.73 521.33 472.37 524.00 481.00 +C 521.96 480.19 521.03 477.73 519.00 477.00 +C 519.16 482.81 524.46 481.54 519.00 486.00 +C 521.01 487.90 522.84 484.63 524.00 486.00 +C 525.25 491.46 528.18 496.40 529.00 502.00 +C 532.96 497.36 524.41 488.32 527.00 483.00 +C 532.84 492.99 534.18 505.00 540.00 515.00 +C 538.03 517.88 537.51 511.50 536.00 514.00 +C 537.10 516.25 537.31 519.96 541.00 519.00 +C 541.65 514.66 539.07 502.65 546.00 498.00 +C 551.97 508.64 566.44 521.57 574.00 534.00 +C 565.71 520.76 557.27 505.71 548.00 494.00 +C 549.75 492.92 552.22 491.89 552.00 489.00 +C 561.49 497.29 572.43 505.03 582.00 514.00 +C 576.80 500.26 566.17 485.82 568.00 471.00 +C 569.96 472.02 566.48 475.45 570.00 476.00 +C 570.35 472.85 570.46 468.70 566.00 470.00 +C 567.36 465.22 560.52 462.44 565.00 457.00 +C 553.43 446.61 554.85 427.06 546.00 414.00 +C 548.10 414.07 549.70 417.01 550.00 419.00 +C 552.44 413.88 556.33 423.14 558.00 419.00 +C 572.51 445.12 586.60 475.25 605.00 495.00 +C 613.13 510.19 616.00 527.75 622.00 544.00 +C 619.70 525.63 614.55 504.95 610.00 486.00 +C 616.24 487.62 619.72 494.53 625.00 498.00 +C 620.06 473.87 598.78 457.86 588.00 437.00 +C 593.84 441.96 596.92 450.69 602.00 455.00 +C 601.89 450.76 607.23 442.28 614.00 444.00 +C 611.63 441.30 610.69 436.13 606.00 437.00 +C 608.91 436.18 607.48 433.05 610.00 433.00 +C 615.00 443.57 625.25 453.78 631.00 461.00 +C 628.88 467.43 632.83 471.09 634.00 477.00 +C 630.38 477.23 631.67 470.77 628.00 471.00 +C 625.86 478.00 625.30 487.15 627.00 495.00 +C 629.87 493.29 630.25 496.24 633.00 497.00 +C 636.42 494.66 634.72 495.48 635.00 492.00 +C 638.75 496.77 636.55 501.98 638.00 509.00 +C 643.43 506.95 635.12 496.33 643.00 497.00 +C 640.56 496.19 636.98 493.78 642.00 495.00 +C 638.81 492.75 641.02 486.71 637.00 486.00 +C 639.08 481.97 641.10 480.12 646.00 480.00 +C 653.93 492.80 668.45 505.06 665.00 522.00 +C 668.20 522.23 672.40 529.24 673.00 523.00 +C 674.79 526.91 676.70 528.28 681.00 527.00 +C 684.78 540.79 694.03 554.88 710.00 558.00 +C 706.71 554.28 703.91 550.14 704.00 545.00 +C 706.70 546.89 707.28 548.92 709.00 548.00 +C 705.27 546.16 710.19 534.53 716.00 541.00 +C 715.38 536.59 714.78 533.03 714.00 529.00 +C 698.50 501.71 664.45 489.96 647.00 463.00 +C 635.74 469.08 627.93 442.60 622.92 428.08 C 617.92 413.55 610.00 393.41 605.93 377.07 C 601.85 360.74 601.32 337.87 590.31 323.70 C 579.29 309.52 581.03 290.67 569.00 277.00 +C 567.39 277.54 568.37 279.23 567.00 280.00 Z"/> +</g> +<g fill="#93DAFD" fill-opacity="1.00" stroke="None"><path d=" +M 461.00 304.00 +C 451.13 327.69 420.36 343.04 409.25 366.25 C 398.13 389.45 370.79 406.21 353.00 424.00 +C 355.44 425.02 359.78 422.17 363.00 422.00 +C 369.99 411.33 390.49 400.79 403.31 390.30 C 416.12 379.82 441.28 374.44 448.75 359.75 C 456.22 345.06 483.46 331.88 481.00 328.00 +C 482.79 319.72 507.42 314.37 494.00 309.00 +C 503.84 302.80 509.31 293.11 520.00 288.00 +C 502.42 289.18 475.43 290.39 461.00 304.00 Z"/> +</g> +<g fill="#2B87DA" fill-opacity="1.00" stroke="None"><path d=" +M 589.00 375.00 +C 583.90 372.11 581.89 366.09 577.00 363.00 +C 576.88 369.52 592.57 384.32 586.00 383.00 +C 590.84 391.87 595.88 403.12 603.00 409.00 +C 600.61 394.48 591.08 381.38 589.00 367.00 +C 589.10 370.10 589.75 372.09 589.00 375.00 Z"/> +</g> +<g fill="#4699D2" fill-opacity="1.00" stroke="None"><path d=" +M 536.00 381.00 +C 537.45 378.54 538.20 376.27 539.00 373.00 +C 537.14 375.47 534.15 377.82 533.00 381.00 +C 533.69 381.66 536.07 379.40 536.00 381.00 Z"/> +</g> +<g fill="#135CAC" fill-opacity="1.00" stroke="None"><path d=" +M 502.00 443.00 +C 501.91 443.35 501.32 443.80 501.00 444.00 +C 492.91 454.38 491.24 470.08 489.00 483.00 +C 484.27 493.14 460.26 512.37 465.00 521.00 +C 462.50 522.47 460.34 524.34 458.00 526.00 +C 462.42 547.29 474.88 564.78 463.00 584.00 +C 470.14 569.60 487.26 569.53 501.00 568.00 +C 497.88 575.01 491.78 581.98 485.00 586.00 +C 494.49 587.74 503.86 594.11 511.00 601.00 +C 494.95 591.99 479.22 587.51 465.00 595.00 +C 463.56 598.66 460.50 601.75 461.00 606.00 +C 463.13 613.40 477.33 617.94 479.00 626.00 +C 476.81 626.76 475.68 624.70 474.00 624.00 +C 475.27 625.66 469.71 638.60 473.00 643.00 +C 469.53 639.36 466.14 637.96 466.00 643.00 +C 463.41 638.63 463.97 633.45 462.00 629.00 +C 458.52 633.42 455.97 641.63 451.00 646.00 +C 452.55 648.46 455.14 642.94 455.00 647.00 +C 450.97 648.48 456.91 650.04 456.00 653.00 +C 451.93 649.89 444.01 646.96 444.00 655.00 +C 446.96 654.72 446.90 650.80 450.00 651.00 +C 449.40 654.26 450.83 656.91 451.00 660.00 +C 448.79 655.45 439.92 655.30 444.00 662.00 +C 425.86 667.71 433.55 645.36 444.00 641.00 +C 441.02 638.81 440.48 630.48 436.00 635.00 +C 436.17 631.69 438.00 627.95 433.00 628.00 +C 432.86 616.20 423.88 606.38 418.00 597.00 +C 418.54 601.25 422.72 604.36 422.00 609.00 +C 418.41 608.82 415.39 621.32 418.00 624.00 +C 420.06 619.98 417.81 613.72 425.00 614.00 +C 424.75 616.36 423.31 619.00 421.00 620.00 +C 423.38 623.73 421.01 630.56 416.00 628.00 +C 419.24 636.53 391.49 648.68 418.00 641.00 +C 418.44 643.96 415.05 644.47 415.00 647.00 +C 422.38 647.42 425.18 634.60 433.00 639.00 +C 432.39 643.66 429.94 648.23 426.00 651.00 +C 424.49 648.55 429.74 646.62 427.00 645.00 +C 424.07 646.42 423.79 650.05 424.00 653.00 +C 420.94 650.56 420.72 656.16 422.00 657.00 +C 420.51 658.77 417.41 655.99 415.00 657.00 +C 414.36 662.13 418.30 666.34 421.00 670.00 +C 419.93 671.87 416.62 671.57 416.00 674.00 +C 418.22 676.25 420.48 673.54 423.00 674.00 +C 425.69 677.05 429.06 681.00 427.00 685.00 +C 424.35 683.11 424.57 680.56 424.00 678.00 +C 420.77 678.66 418.29 680.76 415.00 681.00 +C 414.78 678.05 413.09 675.07 415.00 672.00 +C 412.69 670.20 410.32 668.22 408.00 671.00 +C 404.63 665.32 404.74 658.67 405.00 652.00 +C 398.75 663.17 404.21 630.62 395.00 643.00 +C 392.75 637.67 388.46 632.90 386.00 628.00 +C 387.61 640.96 407.52 652.04 395.00 657.00 +C 396.83 660.99 396.12 663.84 402.00 664.00 +C 399.31 672.92 414.92 674.84 406.00 683.00 +C 403.65 682.28 398.99 678.97 401.00 684.00 +C 391.42 676.69 396.09 657.58 390.00 650.00 +C 386.43 656.48 391.49 661.18 393.00 667.00 +C 387.40 667.64 382.66 664.57 384.00 659.00 +C 382.68 661.09 380.71 662.60 380.00 665.00 +C 384.72 666.41 388.84 669.44 391.00 674.00 +C 385.40 673.48 379.44 660.44 375.00 671.00 +C 369.65 661.51 378.63 651.91 385.00 646.00 +C 382.24 641.18 383.99 634.40 385.00 629.00 +C 381.51 630.32 381.83 636.25 376.00 634.00 +C 381.02 640.23 371.87 644.25 371.00 650.00 +C 363.86 643.50 362.92 654.97 363.00 660.00 +C 366.20 657.73 364.10 652.38 367.00 650.00 +C 373.72 656.45 361.77 660.90 361.00 667.00 +C 364.48 665.35 366.08 660.49 370.00 660.00 +C 368.48 664.73 368.08 665.56 370.00 669.00 +C 363.83 669.44 363.37 676.56 358.00 678.00 +C 358.81 675.96 361.27 675.03 362.00 673.00 +C 357.68 670.38 357.98 663.45 362.00 661.00 +C 357.66 657.92 354.79 661.26 350.00 661.00 +C 352.58 666.92 359.17 672.67 356.00 679.00 +C 352.09 675.65 354.22 668.97 348.00 669.00 +C 349.00 672.24 351.63 674.31 350.00 678.00 +C 346.34 674.90 344.02 666.74 340.00 673.00 +C 339.37 670.28 342.07 668.59 342.00 666.00 +C 336.80 666.89 334.12 673.59 337.00 678.00 +C 332.40 675.57 332.04 675.20 330.00 681.00 +C 327.78 675.87 335.14 668.32 332.00 663.00 +C 329.72 665.58 328.56 669.05 325.00 670.00 +C 325.77 673.62 326.87 678.71 323.00 681.00 +C 322.35 678.56 323.10 674.81 321.00 672.00 +C 327.18 667.29 335.09 651.76 342.00 658.00 +C 337.29 644.67 353.96 646.83 357.00 638.00 +C 354.66 638.06 350.70 643.11 353.00 638.00 +C 341.30 645.78 329.94 655.00 321.00 666.00 +C 310.61 661.55 304.77 678.12 296.00 683.00 +C 294.86 684.59 292.44 692.82 299.00 691.00 +C 297.28 695.39 298.14 702.99 292.00 704.00 +C 292.57 699.37 294.83 692.69 291.00 689.00 +C 290.30 691.62 285.92 699.75 291.00 695.00 +C 291.72 698.10 290.06 700.75 287.00 699.00 +C 285.28 702.04 287.19 704.69 287.00 708.00 +C 282.22 708.94 283.37 703.92 281.00 701.00 +C 278.35 703.47 282.03 707.03 282.00 710.00 +C 276.54 711.21 279.35 704.42 276.00 703.00 +C 273.93 706.17 278.26 710.15 276.00 714.00 +C 278.13 710.06 279.75 714.03 279.00 717.00 +C 270.62 714.31 270.29 702.08 275.00 696.00 +C 270.72 702.48 264.10 710.13 258.00 716.00 +C 267.10 712.42 254.24 717.99 256.00 721.00 +C 252.29 719.29 252.58 720.92 249.00 720.00 +C 249.45 722.52 249.88 724.60 249.00 727.00 +C 252.47 727.69 253.42 722.89 257.00 723.00 +C 254.94 726.69 258.10 734.87 252.00 734.00 +C 253.07 731.69 254.55 729.36 252.00 728.00 +C 248.63 733.19 247.60 727.28 247.00 724.00 +C 246.22 729.01 240.99 731.28 237.00 734.00 +C 236.42 727.92 240.22 723.49 241.00 718.00 +C 238.71 723.49 236.55 719.46 232.00 722.00 +C 233.05 724.82 235.11 725.03 237.00 723.00 +C 235.93 729.57 224.19 735.30 230.00 742.00 +C 226.98 742.61 227.43 738.51 225.00 738.00 +C 220.79 738.67 219.64 745.46 217.00 749.00 +C 215.49 745.25 212.20 746.40 209.00 747.00 +C 217.25 747.11 216.81 757.19 209.00 758.00 +C 210.29 755.07 212.56 752.49 212.00 749.00 +C 185.47 761.13 160.88 785.19 138.00 805.00 +C 154.91 779.70 183.62 766.99 202.00 744.00 +C 203.74 741.69 223.64 718.63 235.00 708.00 +C 234.54 705.49 225.22 705.06 223.00 705.00 +C 213.54 707.31 206.29 707.37 198.00 713.00 +C 190.19 718.30 180.09 726.24 171.00 729.00 +C 167.36 730.11 163.91 729.85 160.00 730.00 +C 127.94 731.22 115.22 767.23 85.30 776.30 C 55.39 785.38 28.85 801.93 0.00 808.00 +L 0.00 898.00 +C 40.28 878.62 96.14 887.60 131.23 854.23 C 166.32 820.86 206.42 812.84 246.00 848.00 +C 271.02 854.94 299.22 872.68 327.00 854.00 +C 325.57 854.09 322.01 852.69 321.00 852.00 +C 323.32 850.73 326.99 849.32 329.00 852.00 +C 329.47 848.89 327.72 846.95 332.00 850.00 +C 329.62 844.15 337.92 849.26 342.00 843.00 +C 337.64 839.06 345.57 839.47 340.00 836.00 +C 344.34 835.65 344.93 832.12 347.00 830.00 +C 342.90 829.99 342.00 830.88 341.00 826.00 +C 338.95 827.61 342.20 830.30 339.00 831.00 +C 339.12 827.44 334.80 830.51 333.00 831.00 +C 333.93 826.96 339.91 826.33 342.00 823.00 +C 333.91 825.24 327.52 832.31 319.00 833.00 +C 332.11 821.12 339.06 801.58 358.00 797.00 +C 357.34 791.35 378.68 778.93 381.00 781.00 +C 383.36 769.62 393.39 760.85 400.00 753.00 +C 401.45 755.02 401.40 754.55 403.00 753.00 +C 404.94 741.66 415.75 728.69 423.00 724.00 +C 414.21 715.64 429.11 700.85 434.00 692.00 +C 441.13 685.40 452.63 678.26 460.00 673.00 +C 464.02 669.10 467.95 663.96 472.00 660.00 +C 473.76 656.20 473.55 654.74 474.00 651.00 +C 474.59 646.17 477.19 643.30 482.00 643.00 +C 482.31 641.14 480.85 637.70 485.00 637.00 +C 487.39 639.27 486.35 643.16 487.00 645.00 +C 491.62 642.51 495.44 638.38 501.00 638.00 +C 505.29 647.03 515.09 645.48 523.00 647.00 +C 537.72 638.88 554.64 644.18 569.01 634.01 C 583.37 623.83 600.85 635.03 616.00 632.00 +C 616.62 631.63 617.66 630.77 618.00 630.00 +C 605.01 623.52 590.12 618.36 579.00 607.00 +C 565.99 597.82 547.48 589.04 536.00 577.00 +C 532.79 589.31 547.52 597.67 559.00 608.00 +C 533.40 596.54 523.86 568.32 506.00 549.00 +C 499.77 539.35 482.51 534.21 478.00 522.00 +C 498.53 541.10 526.57 543.34 548.00 560.00 +C 565.33 568.20 579.29 585.61 594.00 597.00 +C 607.55 602.85 629.20 621.39 644.00 622.00 +C 653.44 618.47 662.51 616.00 673.00 616.00 +C 681.07 616.00 689.27 616.42 697.00 615.00 +C 639.64 668.97 576.85 718.91 516.00 769.00 +C 508.24 777.48 495.47 780.17 487.00 788.00 +C 484.57 790.25 481.68 792.22 479.00 794.00 +C 512.40 801.92 547.54 801.07 579.00 787.00 +C 576.29 793.35 574.93 802.26 567.00 805.00 +C 571.94 805.98 574.91 801.15 579.00 800.00 +C 583.76 807.36 600.33 788.00 612.08 778.08 C 623.84 768.16 639.94 757.24 656.07 753.07 C 672.21 748.90 695.25 747.74 709.70 737.70 C 724.14 727.65 737.00 717.08 753.00 711.00 +C 726.21 711.49 712.29 697.74 694.00 681.00 +C 696.41 671.52 700.90 662.75 705.00 654.00 +C 696.95 658.66 706.47 637.64 709.00 633.00 +C 705.69 626.95 712.43 622.07 712.00 616.00 +C 709.91 604.37 734.01 619.66 744.25 628.75 C 754.49 637.84 773.63 643.70 785.25 653.75 C 796.87 663.81 807.32 677.34 823.23 680.77 C 839.14 684.20 856.45 690.36 871.25 698.75 C 886.05 707.14 914.66 692.53 929.00 699.00 +C 942.86 702.44 963.73 733.16 976.00 723.00 +C 980.32 727.43 977.17 725.28 982.00 725.00 +C 980.59 722.11 979.33 720.16 978.00 717.00 +C 991.66 724.00 1006.68 728.33 1023.00 727.00 +C 1021.56 710.91 1021.55 692.09 1023.00 676.00 +C 1015.94 667.43 994.63 676.75 994.00 662.00 +C 988.68 657.53 982.19 661.87 977.00 657.00 +C 965.07 671.46 944.67 645.80 932.25 638.75 C 919.82 631.70 910.95 596.50 892.08 610.08 C 873.20 623.65 859.71 609.33 844.00 598.00 +C 838.11 604.83 825.54 592.62 824.00 586.00 +C 819.64 585.87 815.00 586.54 811.00 585.00 +C 810.04 587.43 808.42 589.70 806.00 591.00 +C 804.01 588.40 802.30 585.52 803.00 582.00 +C 798.78 581.23 797.53 585.98 797.00 589.00 +C 786.58 586.25 783.12 559.93 772.00 569.00 +C 750.51 560.48 739.59 541.50 724.00 527.00 +C 720.88 528.32 717.79 529.81 714.00 529.00 +C 714.78 533.03 715.38 536.59 716.00 541.00 +C 710.19 534.53 705.27 546.16 709.00 548.00 +C 707.28 548.92 706.70 546.89 704.00 545.00 +C 703.91 550.14 706.71 554.28 710.00 558.00 +C 694.03 554.88 684.78 540.79 681.00 527.00 +C 676.70 528.28 674.79 526.91 673.00 523.00 +C 672.40 529.24 668.20 522.23 665.00 522.00 +C 668.45 505.06 653.93 492.80 646.00 480.00 +C 641.10 480.12 639.08 481.97 637.00 486.00 +C 641.02 486.71 638.81 492.75 642.00 495.00 +C 636.98 493.78 640.56 496.19 643.00 497.00 +C 635.12 496.33 643.43 506.95 638.00 509.00 +C 636.55 501.98 638.75 496.77 635.00 492.00 +C 634.72 495.48 636.42 494.66 633.00 497.00 +C 630.25 496.24 629.87 493.29 627.00 495.00 +C 625.30 487.15 625.86 478.00 628.00 471.00 +C 631.67 470.77 630.38 477.23 634.00 477.00 +C 632.83 471.09 628.88 467.43 631.00 461.00 +C 625.25 453.78 615.00 443.57 610.00 433.00 +C 607.48 433.05 608.91 436.18 606.00 437.00 +C 610.69 436.13 611.63 441.30 614.00 444.00 +C 607.23 442.28 601.89 450.76 602.00 455.00 +C 596.92 450.69 593.84 441.96 588.00 437.00 +C 598.78 457.86 620.06 473.87 625.00 498.00 +C 619.72 494.53 616.24 487.62 610.00 486.00 +C 614.55 504.95 619.70 525.63 622.00 544.00 +C 616.00 527.75 613.13 510.19 605.00 495.00 +C 586.60 475.25 572.51 445.12 558.00 419.00 +C 556.33 423.14 552.44 413.88 550.00 419.00 +C 549.70 417.01 548.10 414.07 546.00 414.00 +C 554.85 427.06 553.43 446.61 565.00 457.00 +C 560.52 462.44 567.36 465.22 566.00 470.00 +C 570.46 468.70 570.35 472.85 570.00 476.00 +C 566.48 475.45 569.96 472.02 568.00 471.00 +C 566.17 485.82 576.80 500.26 582.00 514.00 +C 572.43 505.03 561.49 497.29 552.00 489.00 +C 552.22 491.89 549.75 492.92 548.00 494.00 +C 557.27 505.71 565.71 520.76 574.00 534.00 +C 566.44 521.57 551.97 508.64 546.00 498.00 +C 539.07 502.65 541.65 514.66 541.00 519.00 +C 537.31 519.96 537.10 516.25 536.00 514.00 +C 537.51 511.50 538.03 517.88 540.00 515.00 +C 534.18 505.00 532.84 492.99 527.00 483.00 +C 524.41 488.32 532.96 497.36 529.00 502.00 +C 528.18 496.40 525.25 491.46 524.00 486.00 +C 522.84 484.63 521.01 487.90 519.00 486.00 +C 524.46 481.54 519.16 482.81 519.00 477.00 +C 521.03 477.73 521.96 480.19 524.00 481.00 +C 521.33 472.37 515.40 464.73 513.00 456.00 +C 509.54 455.55 506.98 457.91 509.00 461.00 +C 502.54 457.36 506.03 447.71 504.00 441.00 +C 503.18 441.36 502.43 442.36 502.00 443.00 Z"/> +</g> +<g fill="#2F95E1" fill-opacity="1.00" stroke="None"><path d=" +M 362.00 467.00 +C 356.64 475.53 350.92 484.30 346.00 494.00 +C 353.26 487.24 364.25 479.31 367.00 469.00 +C 380.81 465.87 388.63 454.67 401.00 449.00 +C 398.54 448.25 396.00 448.89 398.00 445.00 +C 394.80 445.51 391.61 448.03 395.00 444.00 +C 400.24 440.65 402.91 435.94 401.00 431.00 +C 388.84 441.21 378.44 457.11 364.00 461.00 +C 364.67 463.55 363.22 465.10 362.00 467.00 Z"/> +</g> +<g fill="#3EA2EB" fill-opacity="1.00" stroke="None"><path d=" +M 182.00 692.00 +C 191.96 691.43 203.49 702.37 198.00 713.00 +C 206.29 707.37 213.54 707.31 223.00 705.00 +C 251.40 698.07 273.63 678.76 292.00 656.00 +C 287.27 653.16 281.39 648.24 279.00 643.00 +C 326.28 632.80 365.29 594.04 412.00 586.00 +C 429.11 590.70 443.09 609.89 459.00 617.00 +C 458.68 617.18 460.55 607.39 461.00 606.00 +C 460.50 601.75 463.56 598.66 465.00 595.00 +C 479.22 587.51 494.95 591.99 511.00 601.00 +C 503.86 594.11 494.49 587.74 485.00 586.00 +C 491.78 581.98 497.88 575.01 501.00 568.00 +C 487.26 569.53 470.14 569.60 463.00 584.00 +C 474.88 564.78 462.42 547.29 458.00 526.00 +C 460.34 524.34 462.50 522.47 465.00 521.00 +C 460.26 512.37 484.27 493.14 489.00 483.00 +C 491.24 470.08 492.91 454.38 501.00 444.00 +C 458.11 482.52 431.30 524.46 392.25 565.25 C 353.20 606.04 298.45 628.66 250.00 653.00 +C 253.36 653.46 255.53 650.06 259.00 651.00 +C 235.00 667.82 205.43 673.87 182.00 692.00 Z"/> +</g> +<g fill="#2B86D7" fill-opacity="1.00" stroke="None"><path d=" +M 506.00 549.00 +C 505.80 548.49 505.34 545.29 504.00 544.00 +C 514.60 539.42 528.91 566.92 534.00 553.00 +C 538.83 554.56 543.35 561.99 548.00 560.00 +C 526.57 543.34 498.53 541.10 478.00 522.00 +C 482.51 534.21 499.77 539.35 506.00 549.00 Z"/> +</g> +<g fill="#217FD1" fill-opacity="1.00" stroke="None"><path d=" +M 265.00 572.00 +C 272.91 559.67 277.34 557.38 289.25 548.25 C 301.16 539.12 270.36 529.36 273.00 546.00 +C 270.54 547.43 268.00 548.50 265.00 548.00 +C 262.86 551.52 261.96 555.41 260.00 559.00 +C 251.01 563.44 239.24 582.55 229.00 582.00 +C 227.11 585.61 225.37 589.20 224.00 593.00 +C 226.96 591.92 228.73 592.11 226.00 595.00 +C 239.48 593.51 250.09 571.50 265.00 572.00 Z"/> +</g> +<g fill="#1A71C4" fill-opacity="1.00" stroke="None"><path d=" +M 506.00 549.00 +C 523.86 568.32 533.40 596.54 559.00 608.00 +C 547.52 597.67 532.79 589.31 536.00 577.00 +C 547.48 589.04 565.99 597.82 579.00 607.00 +C 577.82 605.62 576.85 603.61 575.00 603.00 +C 574.76 599.41 578.45 602.43 580.00 603.00 +C 567.56 589.44 542.36 585.01 536.00 565.00 +C 549.25 578.18 564.58 589.02 581.00 596.00 +C 578.15 590.56 570.62 588.99 569.00 583.00 +C 577.23 587.65 584.75 593.96 594.00 597.00 +C 579.29 585.61 565.33 568.20 548.00 560.00 +C 543.35 561.99 538.83 554.56 534.00 553.00 +C 528.91 566.92 514.60 539.42 504.00 544.00 +C 505.34 545.29 505.80 548.49 506.00 549.00 Z"/> +</g> +<g fill="#2482D4" fill-opacity="1.00" stroke="None"><path d=" +M 579.00 607.00 +C 590.12 618.36 605.01 623.52 618.00 630.00 +C 617.66 630.77 616.62 631.63 616.00 632.00 +C 626.68 629.86 634.32 625.62 644.00 622.00 +C 629.20 621.39 607.55 602.85 594.00 597.00 +C 584.75 593.96 577.23 587.65 569.00 583.00 +C 570.62 588.99 578.15 590.56 581.00 596.00 +C 564.58 589.02 549.25 578.18 536.00 565.00 +C 542.36 585.01 567.56 589.44 580.00 603.00 +C 578.45 602.43 574.76 599.41 575.00 603.00 +C 576.85 603.61 577.82 605.62 579.00 607.00 Z"/> +</g> +<g fill="#2579CA" fill-opacity="1.00" stroke="None"><path d=" +M 539.00 604.00 +C 530.36 593.44 518.37 583.73 508.00 574.00 +C 515.59 586.82 527.73 595.70 539.00 604.00 Z"/> +</g> +<g fill="#3291DF" fill-opacity="1.00" stroke="None"><path d=" +M 223.00 705.00 +C 225.22 705.06 234.54 705.49 235.00 708.00 +C 236.60 706.27 238.54 704.00 240.00 702.00 +C 243.99 703.41 250.38 703.66 251.00 698.00 +C 264.92 700.68 277.12 691.17 285.00 680.00 +C 288.65 680.82 291.77 686.33 296.00 683.00 +C 304.77 678.12 310.61 661.55 321.00 666.00 +C 329.94 655.00 341.30 645.78 353.00 638.00 +C 361.79 632.15 365.87 621.61 374.00 615.00 +C 391.41 619.04 413.41 603.10 412.00 586.00 +C 365.29 594.04 326.28 632.80 279.00 643.00 +C 281.39 648.24 287.27 653.16 292.00 656.00 +C 273.63 678.76 251.40 698.07 223.00 705.00 Z"/> +</g> +<g fill="#0A458D" fill-opacity="1.00" stroke="None"><path d=" +M 353.00 638.00 +C 350.70 643.11 354.66 638.06 357.00 638.00 +C 353.96 646.83 337.29 644.67 342.00 658.00 +C 335.09 651.76 327.18 667.29 321.00 672.00 +C 323.10 674.81 322.35 678.56 323.00 681.00 +C 326.87 678.71 325.77 673.62 325.00 670.00 +C 328.56 669.05 329.72 665.58 332.00 663.00 +C 335.14 668.32 327.78 675.87 330.00 681.00 +C 332.04 675.20 332.40 675.57 337.00 678.00 +C 334.12 673.59 336.80 666.89 342.00 666.00 +C 342.07 668.59 339.37 670.28 340.00 673.00 +C 344.02 666.74 346.34 674.90 350.00 678.00 +C 351.63 674.31 349.00 672.24 348.00 669.00 +C 354.22 668.97 352.09 675.65 356.00 679.00 +C 359.17 672.67 352.58 666.92 350.00 661.00 +C 354.79 661.26 357.66 657.92 362.00 661.00 +C 357.98 663.45 357.68 670.38 362.00 673.00 +C 361.27 675.03 358.81 675.96 358.00 678.00 +C 363.37 676.56 363.83 669.44 370.00 669.00 +C 368.08 665.56 368.48 664.73 370.00 660.00 +C 366.08 660.49 364.48 665.35 361.00 667.00 +C 361.77 660.90 373.72 656.45 367.00 650.00 +C 364.10 652.38 366.20 657.73 363.00 660.00 +C 362.92 654.97 363.86 643.50 371.00 650.00 +C 371.87 644.25 381.02 640.23 376.00 634.00 +C 381.83 636.25 381.51 630.32 385.00 629.00 +C 383.99 634.40 382.24 641.18 385.00 646.00 +C 378.63 651.91 369.65 661.51 375.00 671.00 +C 379.44 660.44 385.40 673.48 391.00 674.00 +C 388.84 669.44 384.72 666.41 380.00 665.00 +C 380.71 662.60 382.68 661.09 384.00 659.00 +C 382.66 664.57 387.40 667.64 393.00 667.00 +C 391.49 661.18 386.43 656.48 390.00 650.00 +C 396.09 657.58 391.42 676.69 401.00 684.00 +C 398.99 678.97 403.65 682.28 406.00 683.00 +C 414.92 674.84 399.31 672.92 402.00 664.00 +C 396.12 663.84 396.83 660.99 395.00 657.00 +C 407.52 652.04 387.61 640.96 386.00 628.00 +C 388.46 632.90 392.75 637.67 395.00 643.00 +C 404.21 630.62 398.75 663.17 405.00 652.00 +C 404.74 658.67 404.63 665.32 408.00 671.00 +C 410.32 668.22 412.69 670.20 415.00 672.00 +C 413.09 675.07 414.78 678.05 415.00 681.00 +C 418.29 680.76 420.77 678.66 424.00 678.00 +C 424.57 680.56 424.35 683.11 427.00 685.00 +C 429.06 681.00 425.69 677.05 423.00 674.00 +C 420.48 673.54 418.22 676.25 416.00 674.00 +C 416.62 671.57 419.93 671.87 421.00 670.00 +C 418.30 666.34 414.36 662.13 415.00 657.00 +C 417.41 655.99 420.51 658.77 422.00 657.00 +C 420.72 656.16 420.94 650.56 424.00 653.00 +C 423.79 650.05 424.07 646.42 427.00 645.00 +C 429.74 646.62 424.49 648.55 426.00 651.00 +C 429.94 648.23 432.39 643.66 433.00 639.00 +C 425.18 634.60 422.38 647.42 415.00 647.00 +C 415.05 644.47 418.44 643.96 418.00 641.00 +C 391.49 648.68 419.24 636.53 416.00 628.00 +C 421.01 630.56 423.38 623.73 421.00 620.00 +C 423.31 619.00 424.75 616.36 425.00 614.00 +C 417.81 613.72 420.06 619.98 418.00 624.00 +C 415.39 621.32 418.41 608.82 422.00 609.00 +C 422.72 604.36 418.54 601.25 418.00 597.00 +C 423.88 606.38 432.86 616.20 433.00 628.00 +C 438.00 627.95 436.17 631.69 436.00 635.00 +C 440.48 630.48 441.02 638.81 444.00 641.00 +C 433.55 645.36 425.86 667.71 444.00 662.00 +C 439.92 655.30 448.79 655.45 451.00 660.00 +C 450.83 656.91 449.40 654.26 450.00 651.00 +C 446.90 650.80 446.96 654.72 444.00 655.00 +C 444.01 646.96 451.93 649.89 456.00 653.00 +C 456.91 650.04 450.97 648.48 455.00 647.00 +C 455.14 642.94 452.55 648.46 451.00 646.00 +C 455.97 641.63 458.52 633.42 462.00 629.00 +C 463.97 633.45 463.41 638.63 466.00 643.00 +C 466.14 637.96 469.53 639.36 473.00 643.00 +C 469.71 638.60 475.27 625.66 474.00 624.00 +C 468.79 621.94 463.93 619.20 459.00 617.00 +C 443.09 609.89 429.11 590.70 412.00 586.00 +C 413.41 603.10 391.41 619.04 374.00 615.00 +C 365.87 621.61 361.79 632.15 353.00 638.00 Z"/> +</g> +<g fill="#298FD9" fill-opacity="1.00" stroke="None"><path d=" +M 224.00 594.00 +C 217.91 598.52 215.37 606.29 211.00 612.00 +C 217.03 607.50 221.54 600.60 224.00 594.00 Z"/> +</g> +<g fill="#2781D0" fill-opacity="1.00" stroke="None"><path d=" +M 459.00 617.00 +C 463.93 619.20 468.79 621.94 474.00 624.00 +C 475.68 624.70 476.81 626.76 479.00 626.00 +C 477.33 617.94 463.13 613.40 461.00 606.00 +C 460.55 607.39 458.68 617.18 459.00 617.00 Z"/> +</g> +<g fill="#0E4182" fill-opacity="1.00" stroke="None"><path d=" +M 487.00 788.00 +C 473.54 796.68 459.30 782.68 445.00 791.00 +C 437.58 796.52 441.37 802.11 431.00 804.00 +C 418.06 806.36 410.96 807.25 400.00 815.00 +C 377.54 830.88 351.79 843.18 327.00 854.00 +C 299.22 872.68 271.02 854.94 246.00 848.00 +C 206.42 812.84 166.32 820.86 131.23 854.23 C 96.14 887.60 40.28 878.62 0.00 898.00 +L 0.00 1023.00 +C 113.50 1024.86 227.56 1020.52 341.00 1023.00 C 454.44 1025.48 568.77 1018.25 682.00 1023.00 C 795.23 1027.75 910.26 1012.81 1023.00 1023.00 +C 1023.08 925.67 1014.24 823.88 1023.00 727.00 +C 1006.68 728.33 991.66 724.00 978.00 717.00 +C 979.33 720.16 980.59 722.11 982.00 725.00 +C 977.17 725.28 980.32 727.43 976.00 723.00 +C 963.73 733.16 942.86 702.44 929.00 699.00 +C 914.66 692.53 886.05 707.14 871.25 698.75 C 856.45 690.36 839.14 684.20 823.23 680.77 C 807.32 677.34 796.87 663.81 785.25 653.75 C 773.63 643.70 754.49 637.84 744.25 628.75 C 734.01 619.66 709.91 604.37 712.00 616.00 +C 712.43 622.07 705.69 626.95 709.00 633.00 +C 706.47 637.64 696.95 658.66 705.00 654.00 +C 700.90 662.75 696.41 671.52 694.00 681.00 +C 712.29 697.74 726.21 711.49 753.00 711.00 +C 737.00 717.08 724.14 727.65 709.70 737.70 C 695.25 747.74 672.21 748.90 656.07 753.07 C 639.94 757.24 623.84 768.16 612.08 778.08 C 600.33 788.00 583.76 807.36 579.00 800.00 +C 574.91 801.15 571.94 805.98 567.00 805.00 +C 574.93 802.26 576.29 793.35 579.00 787.00 +C 547.54 801.07 512.40 801.92 479.00 794.00 +C 481.68 792.22 484.57 790.25 487.00 788.00 Z"/> +</g> +<g fill="#3198E4" fill-opacity="1.00" stroke="None"><path d=" +M 207.00 612.00 +C 194.39 613.84 204.04 636.37 197.00 633.00 +C 196.54 640.67 191.85 648.20 197.00 655.00 +C 200.45 648.92 206.66 644.15 208.00 637.00 +C 205.17 638.82 204.20 642.45 202.00 645.00 +C 199.26 634.37 202.42 621.69 207.00 612.00 Z"/> +</g> +<g fill="#44AAF1" fill-opacity="1.00" stroke="None"><path d=" +M 673.00 616.00 +C 676.93 616.38 682.36 617.80 687.00 617.00 +C 665.44 612.73 651.04 633.09 638.00 641.00 +C 642.90 634.47 651.07 628.37 655.00 621.00 +C 640.53 627.75 632.41 639.18 618.00 643.00 +C 618.77 638.52 620.64 638.51 623.00 633.00 +C 607.37 638.58 602.61 659.24 588.00 664.00 +C 586.45 672.45 569.33 681.91 559.00 683.00 +C 558.96 679.85 563.02 678.70 564.00 676.00 +C 559.75 675.42 554.60 675.62 551.00 674.00 +C 559.49 668.16 568.06 661.78 575.00 654.00 +C 563.85 657.01 555.04 665.71 544.00 665.00 +C 544.98 662.99 547.36 662.36 549.00 661.00 +C 540.23 657.70 554.26 653.27 556.00 648.00 +C 552.25 648.45 550.76 653.30 547.00 654.00 +C 547.28 651.25 545.88 649.53 547.00 647.00 +C 542.78 646.96 542.13 652.31 538.00 653.00 +C 537.73 650.25 541.29 649.32 542.00 647.00 +C 531.58 649.24 523.39 656.96 513.00 659.00 +C 514.28 653.35 518.76 650.21 523.00 647.00 +C 515.09 645.48 505.29 647.03 501.00 638.00 +C 495.44 638.38 491.62 642.51 487.00 645.00 +C 483.07 647.12 477.74 647.80 474.00 651.00 +C 473.55 654.74 473.76 656.20 472.00 660.00 +C 469.39 665.64 464.82 669.56 460.00 673.00 +C 452.63 678.26 441.13 685.40 434.00 692.00 +C 423.91 705.99 433.08 722.91 427.00 739.00 +C 417.96 738.58 425.07 726.84 420.00 725.00 +C 417.66 733.97 409.33 741.74 408.00 751.00 +C 411.74 750.49 422.96 741.90 421.00 747.00 +C 435.56 743.92 436.66 722.57 453.00 723.00 +C 456.74 730.22 449.39 734.58 446.00 740.00 +C 453.35 736.10 458.36 727.70 466.00 724.00 +C 465.08 728.91 464.61 731.73 461.00 735.00 +C 468.55 734.44 474.30 729.62 480.00 725.00 +C 470.99 734.98 458.71 743.50 450.00 755.00 +C 462.31 745.87 472.55 732.24 486.00 725.00 +C 484.20 729.57 490.03 729.26 494.00 728.00 +C 490.89 730.00 486.24 735.09 493.00 733.00 +C 488.30 742.00 480.37 747.55 474.00 755.00 +C 478.26 753.34 491.07 740.27 487.00 750.00 +C 490.49 749.53 492.37 745.25 496.00 745.00 +C 492.65 750.07 490.23 751.18 495.00 753.00 +C 492.22 753.38 490.91 756.22 489.00 758.00 +C 492.81 759.98 494.82 752.91 498.00 751.00 +C 496.23 760.32 486.97 765.43 482.00 773.00 +C 496.16 766.42 506.26 749.65 523.00 748.00 +C 519.17 751.04 519.82 751.74 517.00 757.00 +C 519.06 755.70 520.95 756.42 523.00 757.00 +C 519.37 753.62 524.36 752.11 528.00 752.00 +C 522.96 757.69 523.47 763.21 516.00 769.00 +C 576.85 718.91 639.64 668.97 697.00 615.00 +C 689.27 616.42 681.07 616.00 673.00 616.00 Z"/> +</g> +<g fill="#62C4FB" fill-opacity="1.00" stroke="None"><path d=" +M 644.00 622.00 +C 634.32 625.62 626.68 629.86 616.00 632.00 +C 600.85 635.03 583.37 623.83 569.01 634.01 C 554.64 644.18 537.72 638.88 523.00 647.00 +C 518.76 650.21 514.28 653.35 513.00 659.00 +C 523.39 656.96 531.58 649.24 542.00 647.00 +C 541.29 649.32 537.73 650.25 538.00 653.00 +C 542.13 652.31 542.78 646.96 547.00 647.00 +C 545.88 649.53 547.28 651.25 547.00 654.00 +C 550.76 653.30 552.25 648.45 556.00 648.00 +C 554.26 653.27 540.23 657.70 549.00 661.00 +C 547.36 662.36 544.98 662.99 544.00 665.00 +C 555.04 665.71 563.85 657.01 575.00 654.00 +C 568.06 661.78 559.49 668.16 551.00 674.00 +C 554.60 675.62 559.75 675.42 564.00 676.00 +C 563.02 678.70 558.96 679.85 559.00 683.00 +C 569.33 681.91 586.45 672.45 588.00 664.00 +C 602.61 659.24 607.37 638.58 623.00 633.00 +C 620.64 638.51 618.77 638.52 618.00 643.00 +C 632.41 639.18 640.53 627.75 655.00 621.00 +C 651.07 628.37 642.90 634.47 638.00 641.00 +C 651.04 633.09 665.44 612.73 687.00 617.00 +C 682.36 617.80 676.93 616.38 673.00 616.00 +C 662.51 616.00 653.44 618.47 644.00 622.00 Z"/> +</g> +<g fill="#2F93E0" fill-opacity="1.00" stroke="None"><path d=" +M 184.00 620.00 +C 177.33 615.60 176.12 626.75 170.00 623.00 +C 166.23 630.69 175.57 638.51 170.00 643.00 +C 174.60 645.14 172.89 651.60 177.00 654.00 +C 178.53 651.37 174.64 649.06 175.00 646.00 +C 183.07 655.01 186.87 647.94 179.00 641.00 +C 181.17 642.43 182.76 645.00 185.00 642.00 +C 183.09 634.76 187.61 626.45 184.00 620.00 Z"/> +</g> +<g fill="#2C90DC" fill-opacity="1.00" stroke="None"><path d=" +M 192.00 641.00 +C 196.31 635.41 193.62 625.74 189.00 621.00 +C 185.18 627.50 191.09 634.55 192.00 641.00 Z"/> +</g> +<g fill="#2E93DF" fill-opacity="1.00" stroke="None"><path d=" +M 165.00 646.00 +C 173.76 636.34 158.64 627.21 157.00 640.00 +C 156.91 642.82 158.67 645.06 158.00 648.00 +C 165.02 648.92 159.97 640.45 162.00 638.00 +C 162.82 640.68 163.83 643.75 165.00 646.00 Z"/> +</g> +<g fill="#2176C8" fill-opacity="1.00" stroke="None"><path d=" +M 474.00 651.00 +C 477.74 647.80 483.07 647.12 487.00 645.00 +C 486.35 643.16 487.39 639.27 485.00 637.00 +C 480.85 637.70 482.31 641.14 482.00 643.00 +C 477.19 643.30 474.59 646.17 474.00 651.00 Z"/> +</g> +<g fill="#3096E4" fill-opacity="1.00" stroke="None"><path d=" +M 137.00 643.00 +C 131.88 642.86 131.19 648.65 128.00 651.00 +C 128.46 657.74 133.13 662.66 131.00 669.00 +C 128.51 667.09 127.38 663.91 129.00 661.00 +C 124.23 662.11 127.61 667.87 125.00 671.00 +C 133.29 665.97 132.51 676.99 128.00 681.00 +C 138.06 677.69 132.65 697.50 129.00 703.00 +C 137.97 702.41 144.96 695.93 147.00 688.00 +C 147.88 694.23 171.08 676.04 165.32 663.68 C 159.56 651.32 149.04 678.69 138.00 680.00 +C 140.00 676.31 141.14 672.29 141.00 668.00 +C 132.96 678.38 138.38 665.15 138.00 658.00 +C 125.19 663.18 140.12 648.46 137.00 643.00 Z"/> +</g> +<g fill="#2882D5" fill-opacity="1.00" stroke="None"><path d=" +M 460.00 673.00 +C 464.82 669.56 469.39 665.64 472.00 660.00 +C 467.95 663.96 464.02 669.10 460.00 673.00 Z"/> +</g> +<g fill="#2C91DF" fill-opacity="1.00" stroke="None"><path d=" +M 105.00 669.00 +C 99.53 669.25 99.78 663.03 96.00 661.00 +C 104.12 667.00 94.43 690.55 102.00 684.00 +C 101.75 690.16 107.24 705.37 100.00 705.00 +C 99.41 707.98 102.85 709.25 101.00 712.00 +C 108.18 712.83 109.05 701.08 112.00 704.00 +C 117.12 691.02 108.57 680.78 105.00 669.00 Z"/> +</g> +<g fill="#2D93E2" fill-opacity="1.00" stroke="None"><path d=" +M 94.00 664.00 +C 92.40 666.02 90.01 667.58 87.00 667.00 +C 86.91 677.03 76.54 682.43 72.00 690.00 +C 78.12 692.55 72.13 696.18 75.00 701.00 +C 81.49 693.99 81.83 681.09 88.00 673.00 +C 89.60 678.11 85.45 684.44 89.00 690.00 +C 91.94 684.61 92.40 678.22 98.00 674.00 +C 97.93 670.12 94.50 667.68 94.00 664.00 Z"/> +</g> +<g fill="#4A95DB" fill-opacity="1.00" stroke="None"><path d=" +M 1023.00 727.00 +C 1023.00 726.96 1024.00 727.00 1024.00 727.00 +L 1024.00 676.00 +C 1024.00 676.00 1023.14 676.22 1023.00 676.00 +C 1021.55 692.09 1021.56 710.91 1023.00 727.00 Z"/> +</g> +<g fill="#08448D" fill-opacity="1.00" stroke="None"><path d=" +M 235.00 708.00 +C 223.64 718.63 203.74 741.69 202.00 744.00 +C 183.62 766.99 154.91 779.70 138.00 805.00 +C 160.88 785.19 185.47 761.13 212.00 749.00 +C 212.56 752.49 210.29 755.07 209.00 758.00 +C 216.81 757.19 217.25 747.11 209.00 747.00 +C 212.20 746.40 215.49 745.25 217.00 749.00 +C 219.64 745.46 220.79 738.67 225.00 738.00 +C 227.43 738.51 226.98 742.61 230.00 742.00 +C 224.19 735.30 235.93 729.57 237.00 723.00 +C 235.11 725.03 233.05 724.82 232.00 722.00 +C 236.55 719.46 238.71 723.49 241.00 718.00 +C 240.22 723.49 236.42 727.92 237.00 734.00 +C 240.99 731.28 246.22 729.01 247.00 724.00 +C 247.60 727.28 248.63 733.19 252.00 728.00 +C 254.55 729.36 253.07 731.69 252.00 734.00 +C 258.10 734.87 254.94 726.69 257.00 723.00 +C 253.42 722.89 252.47 727.69 249.00 727.00 +C 249.88 724.60 249.45 722.52 249.00 720.00 +C 252.58 720.92 252.29 719.29 256.00 721.00 +C 254.24 717.99 267.10 712.42 258.00 716.00 +C 264.10 710.13 270.72 702.48 275.00 696.00 +C 270.29 702.08 270.62 714.31 279.00 717.00 +C 279.75 714.03 278.13 710.06 276.00 714.00 +C 278.26 710.15 273.93 706.17 276.00 703.00 +C 279.35 704.42 276.54 711.21 282.00 710.00 +C 282.03 707.03 278.35 703.47 281.00 701.00 +C 283.37 703.92 282.22 708.94 287.00 708.00 +C 287.19 704.69 285.28 702.04 287.00 699.00 +C 290.06 700.75 291.72 698.10 291.00 695.00 +C 285.92 699.75 290.30 691.62 291.00 689.00 +C 294.83 692.69 292.57 699.37 292.00 704.00 +C 298.14 702.99 297.28 695.39 299.00 691.00 +C 292.44 692.82 294.86 684.59 296.00 683.00 +C 291.77 686.33 288.65 680.82 285.00 680.00 +C 277.12 691.17 264.92 700.68 251.00 698.00 +C 250.38 703.66 243.99 703.41 240.00 702.00 +C 238.54 704.00 236.60 706.27 235.00 708.00 Z"/> +</g> +<g fill="#329AE7" fill-opacity="1.00" stroke="None"><path d=" +M 72.00 686.00 +C 64.95 686.80 64.72 696.41 61.00 701.00 +C 70.26 698.23 62.45 710.08 64.00 715.00 +C 83.42 716.36 56.70 693.62 72.00 686.00 Z"/> +</g> +<g fill="#2C8EDE" fill-opacity="1.00" stroke="None"><path d=" +M 171.00 700.00 +C 153.36 714.35 179.74 716.41 171.00 729.00 +C 180.09 726.24 190.19 718.30 198.00 713.00 +C 203.49 702.37 191.96 691.43 182.00 692.00 +C 178.46 694.74 174.50 697.15 171.00 700.00 Z"/> +</g> +<g fill="#3194E2" fill-opacity="1.00" stroke="None"><path d=" +M 403.00 753.00 +C 400.98 764.84 383.40 773.74 382.00 784.00 +C 379.06 783.93 377.32 786.71 375.00 788.00 +C 388.69 790.56 390.27 768.25 403.00 765.00 +C 396.35 776.71 385.20 784.26 379.00 795.00 +C 383.98 793.63 391.32 797.38 393.00 790.00 +C 395.67 790.67 397.77 792.94 401.00 792.00 +C 400.75 794.36 399.31 797.00 397.00 798.00 +C 402.93 802.47 395.02 811.52 400.00 815.00 +C 410.96 807.25 418.06 806.36 431.00 804.00 +C 436.13 800.76 439.56 794.16 445.00 791.00 +C 459.30 782.68 473.54 796.68 487.00 788.00 +C 495.47 780.17 508.24 777.48 516.00 769.00 +C 523.47 763.21 522.96 757.69 528.00 752.00 +C 524.36 752.11 519.37 753.62 523.00 757.00 +C 520.95 756.42 519.06 755.70 517.00 757.00 +C 519.82 751.74 519.17 751.04 523.00 748.00 +C 506.26 749.65 496.16 766.42 482.00 773.00 +C 486.97 765.43 496.23 760.32 498.00 751.00 +C 494.82 752.91 492.81 759.98 489.00 758.00 +C 490.91 756.22 492.22 753.38 495.00 753.00 +C 490.23 751.18 492.65 750.07 496.00 745.00 +C 492.37 745.25 490.49 749.53 487.00 750.00 +C 491.07 740.27 478.26 753.34 474.00 755.00 +C 480.37 747.55 488.30 742.00 493.00 733.00 +C 486.24 735.09 490.89 730.00 494.00 728.00 +C 490.03 729.26 484.20 729.57 486.00 725.00 +C 472.55 732.24 462.31 745.87 450.00 755.00 +C 458.71 743.50 470.99 734.98 480.00 725.00 +C 474.30 729.62 468.55 734.44 461.00 735.00 +C 464.61 731.73 465.08 728.91 466.00 724.00 +C 458.36 727.70 453.35 736.10 446.00 740.00 +C 449.39 734.58 456.74 730.22 453.00 723.00 +C 436.66 722.57 435.56 743.92 421.00 747.00 +C 422.96 741.90 411.74 750.49 408.00 751.00 +C 409.33 741.74 417.66 733.97 420.00 725.00 +C 425.07 726.84 417.96 738.58 427.00 739.00 +C 433.08 722.91 423.91 705.99 434.00 692.00 +C 429.11 700.85 414.21 715.64 423.00 724.00 +C 415.75 728.69 404.94 741.66 403.00 753.00 Z"/> +</g> +<g fill="#3297E5" fill-opacity="1.00" stroke="None"><path d=" +M 0.00 749.00 +L 0.00 808.00 +C 28.85 801.93 55.39 785.38 85.30 776.30 C 115.22 767.23 127.94 731.22 160.00 730.00 +C 159.50 728.24 157.28 729.28 156.00 729.00 +C 159.38 723.96 155.04 719.45 154.00 715.00 +C 156.42 714.13 157.53 711.46 157.00 709.00 +C 124.01 729.89 88.53 746.59 56.00 768.00 +C 64.54 740.99 101.39 737.59 110.00 710.00 +C 106.14 710.14 103.09 712.80 104.00 717.00 +C 99.47 714.18 99.70 721.86 96.00 722.00 +C 98.36 718.22 98.61 714.94 100.00 711.00 +C 95.27 713.29 96.28 717.64 94.00 722.00 +C 88.89 721.19 84.25 715.35 82.00 711.00 +C 84.03 711.73 84.96 714.19 87.00 715.00 +C 88.67 709.92 87.42 708.91 92.00 712.00 +C 92.84 706.94 87.90 703.67 84.00 702.00 +C 84.66 699.80 85.33 697.42 83.00 696.00 +C 82.99 701.48 77.69 707.33 76.00 713.00 +C 79.91 707.82 84.24 718.78 79.00 721.00 +C 78.40 718.44 77.39 715.40 75.00 714.00 +C 77.06 722.35 71.84 732.80 62.00 733.00 +C 62.18 735.66 60.63 738.25 59.00 740.00 +C 58.77 731.84 62.10 720.09 53.00 714.00 +C 49.76 720.90 41.66 747.19 31.00 739.00 +C 30.99 743.38 30.12 747.14 25.00 749.00 +C 24.37 745.31 26.40 742.33 27.00 739.00 +C 21.22 749.92 9.72 745.71 0.00 749.00 Z"/> +</g> +<g fill="#4C77AE" fill-opacity="1.00" stroke="None"><path d=" +M 1023.00 1023.00 +C 1023.00 1023.50 1023.00 1024.00 1023.00 1024.00 +L 1024.00 1024.00 +L 1024.00 727.00 +C 1024.00 727.00 1023.00 726.96 1023.00 727.00 +C 1014.24 823.88 1023.08 925.67 1023.00 1023.00 Z"/> +</g> +<g fill="#1F72C5" fill-opacity="1.00" stroke="None"><path d=" +M 327.00 854.00 +C 351.79 843.18 377.54 830.88 400.00 815.00 +C 395.02 811.52 402.93 802.47 397.00 798.00 +C 399.31 797.00 400.75 794.36 401.00 792.00 +C 397.77 792.94 395.67 790.67 393.00 790.00 +C 391.32 797.38 383.98 793.63 379.00 795.00 +C 385.20 784.26 396.35 776.71 403.00 765.00 +C 390.27 768.25 388.69 790.56 375.00 788.00 +C 377.32 786.71 379.06 783.93 382.00 784.00 +C 383.40 773.74 400.98 764.84 403.00 753.00 +C 401.40 754.55 401.45 755.02 400.00 753.00 +C 393.39 760.85 383.36 769.62 381.00 781.00 +C 378.68 778.93 357.34 791.35 358.00 797.00 +C 339.06 801.58 332.11 821.12 319.00 833.00 +C 327.52 832.31 333.91 825.24 342.00 823.00 +C 339.91 826.33 333.93 826.96 333.00 831.00 +C 334.80 830.51 339.12 827.44 339.00 831.00 +C 342.20 830.30 338.95 827.61 341.00 826.00 +C 342.00 830.88 342.90 829.99 347.00 830.00 +C 344.93 832.12 344.34 835.65 340.00 836.00 +C 345.57 839.47 337.64 839.06 342.00 843.00 +C 337.92 849.26 329.62 844.15 332.00 850.00 +C 327.72 846.95 329.47 848.89 329.00 852.00 +C 326.99 849.32 323.32 850.73 321.00 852.00 +C 322.01 852.69 325.57 854.09 327.00 854.00 Z"/> +</g> +<g fill="#246FB9" fill-opacity="1.00" stroke="None"><path d=" +M 431.00 804.00 +C 441.37 802.11 437.58 796.52 445.00 791.00 +C 439.56 794.16 436.13 800.76 431.00 804.00 Z"/> +</g> +<g fill="#265591" fill-opacity="1.00" stroke="None"><path d=" +M 0.00 1024.00 +L 1023.00 1024.00 +C 1023.00 1024.00 1023.00 1023.50 1023.00 1023.00 +C 910.26 1012.81 795.23 1027.75 682.00 1023.00 C 568.77 1018.25 454.44 1025.48 341.00 1023.00 C 227.56 1020.52 113.50 1024.86 0.00 1023.00 +L 0.00 1024.00 Z"/> +</g> +</svg> \ 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 000000000..fbc35d186 Binary files /dev/null and b/img/blueprint-select-project.png differ 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/dump-imports-mmd.png b/img/dump-imports-mmd.png new file mode 100644 index 000000000..b900b2ca4 Binary files /dev/null and b/img/dump-imports-mmd.png differ diff --git a/img/misti.png b/img/misti.png new file mode 100644 index 000000000..8b722cb63 Binary files /dev/null and b/img/misti.png differ diff --git a/img/misti.svg b/img/misti.svg new file mode 100644 index 000000000..de6982a18 --- /dev/null +++ b/img/misti.svg @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/index.html b/index.html new file mode 100644 index 000000000..e1e4adafd --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + + +Misti + + + + + + + +
+ + \ 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,H4sIAAAAAAAAA8VdXY/bNtb+Ky+cW3eqQ33nrm+3CxRYNEGz7c0gCBRbMzXWY3tlO92g6H9fiBJl8vChRFqa7lUCD88HyYeHh+ehpD9WzfH38+rt4x+rf+0O29VbsV4dqpd69Xa1OR4u9X8uq/Xq2uxXb1cvx+11X5+/7X9/+O3ysl+tV5t9dT7X59Xb1erPtdJCohj0fDhen5729fdMXS83qDObAe3r1alq6sNFc+1mMCXD8fOluW4uxybE2htTbtQyk9d7Holk8KTabr8/vrzUh8s5yBNTbglP9sfn5zpsOAaRO+2LTFBy8+Bpt6/lf0N80ITu9SJKblB8rg91U13q983xualeglyxZZfw6Gl32P583YeOyiC0zKhcfq731WV3PASOiC631Gj8vdoEBYk3mtASPmyO+329uby7Xk7Xy0/VSx22dKH4En5V221oDFnOcvCk3GTu9WAwX7/sLhctdql9qP89dB/6galTvVHqzGbj+5ByzTFwL9W/7IU9YudNLzBqjAm6bG+vL6cg273AUrY/fD1sgu33Qvf6cINM0xybs40Y+XMwYFopuyudLr3NBFY6n4Kg4rAxgRNb6o5EyWnbJ0sadwGM8Y+HS90cqr3PWBttX3nMbVshY2/2au4cAF/C58LlEsL9f+rNtd3cvRaA0fi1V4JtLGhJmB2bvTaAN3csEpdTYGZ+OVfPXmHp1vCVZ4QZCpkNrTNzZ4J7ET4L0BltX5GTdGy+Vf+xt5j+D5/Uf0Z3G5FmeNUdm/dVU73ctrBdu26fqg00AUUnZtzqiePgeO50v68uv8115o2py9MxrNDl7u5wul7+tmtm+6opehVHj/KAsISnuqZXcfXUHDf1+fxzfb7uL7Mh+cZSt5TTIipzSoVzH+ssDv5fvp6mXR/EZiwn19aK4tnUQN7vhndI9XLBL7ZOTWFI0An0zxVrLuftN7vzN6fmeKk3l3q7iL9W1Al0FgabV/HUDjuBruJo8yq+OuJOoMMj4WYpr41sqWsPEiY/d2/i89eUlcUN1ZaXl+pgl5M8XYSaXgELdtxs6wPhsVOX+h/GT8uNeTHUGIulsGj7eDceHf7Nj/O2j76x/v/6H3aH3+pm5wtNn46EbwB2L7w2gdfrwh07g90Hv93h9Tpx75Zh9yRg21i0O4vFbLtLgXF72Vmyg/l357uiuSH2Pwznth/z4rk5HEsFdODl3RHd5eH8kA68fN2Y7tWV8KAO+vGKUd2rE3eEddCL14zrXt24N7CDvrx6ZPdayXNCO+jUXxLbnR2zCqTOuuh4OdQutDZswq06a99gVG+m4ahqzvWHU7WpP9Snqr3Psf212l81kv/peti0ZR9gwynsuQ2pzrg94/iecuZnZ+9n2TfIW08fWpm7/XCU7rpbFD9Xv7uKdsoR3v5uR4w8xZjp921fR6Lo4AqQutud4Cxl0ouwJGVMnSuyfbo01eH8dGzs+1UBbhpalvES5KAdYD7I8bg29UgMhki7Cc5Avn7/qTm+6Gi/y4s3Ny2+4+YYDMdeXB8uzQ5ciwrz8qZlMS+Flrpt6/9Ym4b81XMHYhcmlYruZ29S78d/mGo0zqTX1LcYx0/vjGM+tvXn67OniTeq8ZghJaFvFGka37r16VMbh4NMPgwyPpYfOjedifnT0dd43/Yv7G5rse/tN4lvf6Wbju7+XjUHX+N927+wu61F1d3Mt7vSTVd4MS42TFhXjf/CDkuTqsfCt8f1yLWOv9VP1XV/YbFChdVekdEoMFz4phFOU15ZA5J2XhE0Yta0fa+w5WXZCB7Thn3ih5ddYxVP2/VZyF52a3hPyG3Ya0U5LWsH9vpy+fq+kYvJ2kaNv4ZeyHwPVauemaqRyPjiMR0PuRLlaXn8ctS0EpdPmuTdrpk6lvDwVhj8erhUdk7W/TyeUOHDYf+EDDsa9vrMNuMz3nvmuTtMmXkzkehASddeKH8KtPzQCwWYV8mZq6Z7+boPHoAHJbWcH/vdQTt2+PqhpGb54cDgP7+e6r/VT7vDznh6BrlmNg1EpOtq07+vuy/Vvj5sQjxxSr32Mhk3HLZw3F2/dyl5eReyuNwKx2FuPCV3v6ejz80t4+kyM/6wxLR7L9kP189tw4D1AiVee624jYatE9zde9fIpFch6wMrm7k2pj0MWBf3eDh/ZkPWg6eHI9vX5Ka1zFb1/fV8Ob5MGrw1e/WczbQUmLbdenN35gbtByVvNw3jkPzSklT3OKME53rjwMT7Zveyu+y+TOPQaPnayLCNhYHD7Na9+HB6EQIRU8lclLhdCgHKhE8+WPk1zFXZfJkwZjwIjQy3DV4boIONMFxK3++FI7cZgkIpOw6+pn+RwE9T+7vlB5NcyJ8v5qUAL08GmYV82FaXKsyDXuJ++yOon15zQ6tllpr1TgpkUzV67SVn2AlbdkM/7l16yHbI8hvkZ6bW0I+AbNrTj41HXQ+6chNc0JuqeR4PA9CVXmpBP3bHcC92bubC14eJtfld8+zl1nfN81+1QpWp+xZp26G564N5cM8SaVXMPGa6vLlvUIKR8eM7L+9+fLfMZvHd5fgyarBt8NoQHGyEYU/6fu/mwG2GbAxSduamYNkPQLuH/cnwa9kPCL3YvpNuahnwajfJOKlmC9VNBn3vTp6G352WNj0V5o2WC2V/1339/8ft1/Eo0jdazuSkuVffxpSNwP2r9f3uBJPZDEouW9nxNfxbXW0ncijugBJZyIPPPkAyHOglFrLvldJyFwLTWeiFs5hivv8QV1Bkm9cvtt3MhJbZuk7cX2CzLIeV1jrxmfsn8iJgC/Xzwgd/yJEwCPr5wm8P+/oydV/Y05fxFfHD4dKMRwq94TLbzk/H7ThE2gahpti1m+9v1/fsZ2nsJr5P03Bc3R4VATo3/ndxDHeh5Se9Djtq9smzIDtts+EFqVG7TUBlatp2pZ9vRu1WngedaZufd4eq+Qry3lH7XGoZX16qy+a3UFeY0DKetG8urXaHc6gzttxCs3Q87uvqEDxNXGwpb7RMa8IBv7zdY13qefv4mvRM4KdtnlgGNWr25J9KOSzzraO/p+auyRv29dYznNCv4vYXDqyLpsB633RW7/X7zLcbQKHW35iyvp4oHS6Pzt0djGBvbnIzPOGT4uvFUtNx/vry+bgPsvpmkAnqt8uDw/XlM7gHPurBILOIB9fDefd8AE8PjvqgSS3ixdP+WNk3v0ddUCKL2N/ICyBhDgwyd3vAEt1fLru9K8OVf/NNbet/D3Qmehxb16g39VlWnY+oD1/q5qwnmMr//vdR32PtYPHul7///R8/fPr1h58//Pjup0Hdl6rZVZ91hazluPfKu5vNhMokjhJ+orFe6gLfAvDGbo3tgre3OAzD94ONGmcScx3A77QZ9YCLzHXB9bpLjznQhZZxw3qPrRcSBpm5Tjgf7x51A0gt44j+aLeHBz7PcE+bNsoL9pPQb8xm2Fr3OPWkKf5Ejtva9xOFJU+DFkngtqg1ndlH65w11k2t8SyzvGLrtjn1fRpPg8ZFN7e10Y98BJgyTzLj9n4dvWwYNqBmwW9yVFXzeajldaQR1E59XydgoXgukrmmDCbebeq7sbwvcCB1enJ6LLvWswwbBy23xX+One584419b34k3uiNZy4PdDV7bH2Y7Zcz7hsZoNDsWQaPCI3PtyEwy/z0w31uT8ZkZzk1/vSU2yGX3H3OcN4B2J2irqZMPE3sf09zNj6LSQAGmrmhv5oIxNWcCOyqxwM7dtN7J91ZeIfzD1rfZ9hdYQd2UeN7zY4ntqNXFCYROJEQNHMyAV4cB/pPM7NUJzeFBspue5/Rqb1w1t7HK+oO/V2TuUcY+GFXeH7pW87byRxf8AP71tBynkHjnScj5kbfdeJpDHyNyW3RaDzLLP5kmtsybz9vgFW9yHukucDMBHHs5TIoNzTb32ncUVZFdq2mCwx3wEDPH+LRUirI73yKmL4nyNEiKjhKelVQQ5HtKJ+OQHuidho4147CqXvGJ6qmnuYnS6a2A9710iAXULHUZXusUtob/bju//f2j4HIeLsSD/FDuVqvnnb1ftt+Bl1d2LsdH7bHzVX+92Pf7Ne6I0TfPnatv41W68donUYPZVp8/Lh+VMLyD/IHpeP2ixSk1fqR1kn6UKSGHFlyZMiJ1fpRrGN6SMrSEBSWoDAE49X6MUaexpZgbAgmq/VjAjxNLLnEkEtX68cUGUwtwdQQzFbrxwwJZpZgZgjmq/VjjgRzSzA3BIvV+rFAgoUlWBiC5Wr9WCLB0hIszelv0UAQOWRDhxh2JHgICgP8mACiFhYkoLCNITJBRC00CMKIbByRCSRq8UEISmRjiUwwUQsRStdx9iBKJmzjiUxAUQsTgpAiG1NkgopaqBCEFdm4IhNY1MKFILTIxhaZ4KIWMlSi8bLhRSa+ROQcL2HjS5j4EuQMMja8BItPMkBFwGkBIpSJLhG7nbbRJUx0icTptI0uYaJLtHgRKBwLG1zCBJfI3E7b4BImuETudNrGljCxJVq0CIGctqElTGiJ0u20jS1hYiuOXE7HNrRiE1qxhBbeh2xsxSa2YomtZJ2Ih4R1ObbBFbP9r4WLSNdx+VDmwhQGW6AJrliCK4PCNrpiE12xRFcOhW14xSa84hYwooDCNrxiE16xhFcJB8zGV2ziK24hE0dQ2AZYbAIsLp0YsfEVm/hKIudMJTbAEhNgCTlnKrEBlpgAS4RzphIbYIkJsCR2zlRiAyxhSVYLmZjQYCcg0TIBlrSQiQUUtgGWmABLWsjEMRS2AZaYAEuc8Sux8ZWY+EoKd5dtfCUmvpLSjREbYIkJsDRyYiS1AZaaAEvJiZHUBlhqAiwVToykNsBSE2Bp7Jzm1AZYagIslQCDsTO1AZayVD51TXMKknkTX2nmnObUxldq4ivNndOc2gBLTYClhXuabYClJsDS0j3NNsBSE2BZ5JzmzAZYZgIsI+c0ZzbAMhNgWQuZGB67MhtgmQmwTAIMH71sgGUmwDIJMJgnZzbAMhNgmYxgME/ObIRl7LwoEQaPYRk4MpoIy1rMJHCXy2yEZSbCshYzCTyIZTbCMhNhmXOLzGyAZSbA8hYyCTzE5TbAchNgeQuZBEb83AZYbgIsbyGTJNCyDbDcBFjeQiZJQcqa2/jKTXzlsg4BwZnb+MpNfOWpo4iR2+jKTXTlLV4SXFaw0ZWzioREV4EMg5qECa5cgqtci/whixJT2AZXboIrb/GSomNYboMrN8FVRE7DhQ2uwgRX0cIlRUepwsZWYWKrEG7DNrYKE1tFC5cUHYcKG1uFia0icRu2sVWY2CpkoQseaQobXYWJriJzBYHCBldhgqtwgquwwVWwilfhwkcBal4mtorSOcU2tgoTW2XkmqXShlZpQquU0IKhp7SxVZrYKlu0pCj0lDa0ShNapbsuUdrYKk1slS1aUhi3ShtbpYmtUmILBp/SxlZpYqts4ZIifJQ2tkoTW2XuXBGlDa7SBFcpwVUiVJc2ukpWUm0Bk8HKaAmqqrys2kImw6XRCBVWWWU1alGTIXx2f+LirLYatcDJYigOiqsRq65GsXPUu79xeVZgjRLnwHd/4/KsyBq1AMoSWGWNQJk1YnXWSJbu03WcP5QZlweV1oiVWqMWR1kGhw/UWiNWbI3cO2b3Ny7P6q1ROTJ8oOQaMfDJMr1j+FBV3yrrk3v4YGGfoU8W67McDR8q7fPavizXZyheECru8+o+uTdRQgV+XuGXRXvH6KMaPy/yy7p9BsvlqMrPy/yycp+jHZFQnZ8X+mkEe6jUz2v9NII9VO5n9X6SJXzce1DwJ1bxJ1nFzyEhCWr+xIr+JAv5OQyboOxPrO5PYiTugco/sdI/iZG4B6r/xMr/JEv6Oaa1AANAjAIgWdXPYWZCgAQgxgKQrOzn8NROgAggxgSQrO7nMG4CLoAYGUCyvp/DuAHYAGJ0AMXu8wIBRoAYJUCyyu+YPUAKEGMFSBb6HWEX8ALEiAGStf68gGEXUAPEuAGS5f4cLj1ADhBjB0gW/AtMBQN+gBhBQLLmX8ClCxgCYhQBxe5MjwBJQIwlIFn4d40+AB8jCkgW/x2bHuAKiJEFJOv/BeazAV1AjC8gSQEUMGUDhAExxoAS95mVAGdAjDQgyQM4wA9oA2K8AUkqwDH8gDkgRh2QZAMweAF3QIw8IMkHFJjTB+Bj9AFJSqDAgQ8wCMQoBJKsQIGZfUAiEGMRSBIDBYx8gEYgxiOQpAYKmDEBIoEYk0CSHHBgB3AJxMgEkvyAAzuATiDGJ5CkCApYOCXAKBCjFEiyBCWsnRIgFYixCiSZAkfgBcQCMWaBJFlQwsgHqAVi3AKlI5EPsAvE6AVK3cdcAgQDMYaBJGngWLqAYyBGMpDkDRzDB2gGYjwDSeoAVmMJEA3EmAaS5EEJcz5ANRDjGkjSByWMu4BsIMY2kCQQSpxyAb6BGOFA2Qj2AOVAjHMgSSOUePDQnSKGPUkklDBjA7QDMd6BJJVQwrgFiAdizANJNqGEcQtwD8TIB5J8Qgn3DMA+EKMfSDIKFMGjFiAgiDEQJEkFiuC6BxwEMRKCJLHgCFuAhyBGRJDkFiiCyAdUBDEugiTBQBGEPuAjiBESJDkGijD2ASdBjJQgSTRQBMELeAlixARJroEivO0CboIYOUGScKDIcakOIJAxFCRJB0fSCDgKYiQFFR0EHRfzAAYZU0FFh0G8dwKyghhbQZKBIMcNUMBYEKMsSLIQ5LgFClgLYrQFSSaCHDdBAXNBjLogSUeQ4zYooC+I8RckOQkiDGTAYRAjMUgSE0Q4fwREBjEmgyQ7QQTjMCAziLEZJBkKfEeKAKFBjNEgSVLgyzcEOA1ipAZJogLf6iDAaxAjNkhyFfiCGAFqgxi3QZKuwDfyCLAbxOgNkowFpqIJEBzEGA6SrAVm7wmQHMRYDpLEBU5CAM1BjOegjuiA+yggOogxHVS6Tx+A6iDGdQjJXcCzlwBUh2BUh5DcBcyeBaA6BKM6ROQs+QlAdQhGdQhJXcCSlQBMh2BMh5DMBUw+BSA6BCM6hCQuYMVLAJ5DMJ5DSN4CnvsEoDkEozmE5C1gyUEAmkMwmkNI2gIWfARgOQRjOYRkLSBLIADJIRjJITqSA/YdcByCcRxCchawzC4AxSEYxSEkZwHr1AJQHIJRHKKjOCBsAMUhGMUhJGUB6T0BGA7BGA4hGQtIbwlAcAhGcAjJWOAjiwAMh2AMh5CUBTyyCMBwCMZwCMlYwCOLAASHYASHkIQFPLIIwG8I/jyDcJ45BHqggT/RINxnDoEearCeanCfOQR8sIEBT7jPHAI928AfbhDuM4dAzzfwBxyE+8wh0DMO/CEHyVjAE6NATznwxxwkYYHzdYGedOCPOojCeWIR6GkH/rhD97wDlAbYYwSHkIQFfHBJAH5DMH5DSL4CPscjAL0hGL0huqce4MwDdkMwdkN0zz1A4ANyQzByQ3RPPsChA+SGYOSGkGQFvHYjALchGLch4syZnwtAbghGbghJVuD8XAByQzByQ3TPQMD8VAByQzByQ0iyAufnApAbgpEbonsUAubnApAbgpEbonsaAtsH7IZg7Ibo2A3cf8BuCMZuCMlW4PxcAHZD/SYf2P1SN5d6+2P34O7j4/BBkT9Wn/qneZNSPT78xyovVm//+HO9KqL+X9H/m3T/lnn3b3tnpv9PL9FeROj/o34Rqk0cqf8o8aTX2xbj+//IP/15e25Y/qz6JP/WdvLTpakO56dj82J0QWhdiLwUVdutroHopoHIV0Pf4Kxrim+KYl893auQNG+0/pDw0yI/2nVTkWuz2pKl/binfsrki41uyspcU5b189smFz7KupfHbLSXx2iKC11x2SsWmZ9i+foeTVmkKUtVl/NYafWbjv71Q9jfNne52ciFUu03R5vjft8++i6fuG+1nE3dmmo/EKu/6vOuj2isVmCa9v/J1FLMUjWLfoPd//VL91o43etEHxFfZcP7qHVdGurVyPbhQfSzKfoAoiJK3EMm6X9X/VRQKrz9ka+6ck26PjO5ckn4hYmNegPQTaGmznOe+5d86/FKDxGF37LuPm6sYSXVw4xfAN7Wn6/PRuzVAJf301D46nqqrvvL/vj8XBtASLUg6tu368vJGKBMjyzeKtoXoRhq9Mjn16tavYFJ0xLri9JPi/pYkzbS2nSpqNbyiV7q/t3uMV/6l7HrONKXr+e8GR+B0NeJPuZdKjGtq3ubkTb3GrCLvpel3zKRuszu6dHQ0yH5MhijY7EW9JM+EiX9Lpj6YWt427SuVpvPzG8HUWq+RfqEnnp4wkLpa+Sbd8xERpvNzA+0PI8p9QCTZSqm+6HsabevpbAOjps+v7DwtDtY2ZWWGfllMK2S7nV+WuzU1qKfku5LEfrS03OJLsOe1tIcX5r2XT1aWNBWcO4Ho+f6UDfVpR7eIXjTpk+6p67L7UWbNz3awvNbd/0HKzUNegab+gFwZ+8liT5Tfl3qJHUd2qjkfhO1OzwdDeRqm36ushO/kdkdTtfLdmeudc0jld0nfWaS9slR6qne8LPQc53Yb5F133zU+qqvMHUajFRCHvW9b6+e9/9Rv6g0j2J1LEyGDHY4Mfr1ar87mDtdpq+2yG9DAWjSdoJOKPcbo5fqX+ZmqYdGlYv3E6cOzkJFzH58Sr9F0Jo6dy/3ahtW5uTE2v6a9IbT3qBnMiHfR+s40OmLNlf9EX7DzaN9pucm0YCWoZqgIBErjKnNub3k5WWw/4iRnsPoHSj8wml3oOMrVIs7ce+7Knuoqoenm6eqOddoh9aCbOYHQ10Vz3VjreuZX6SU6s6nalOf61PVbilbO8eMtZHI/KLnSb5u8tQwdKVa1CuDNbEzhgau0g/3p+a4qc9nMBNCm4m4X7UqdKnIlfktArAnt4yDtqpUtBB+U45259I4HeUqMfMLrUohX6657qWvcyytaskZravq2C/8JruPep+Gr0Dp2Zbe5UKVmmI/nPeKq3bJwFReA9NQeSpVESP2W+bKCDvqF/qwqj2+pbMDdIJCUapBtsyUy34IGLSiLaDQo3aitjDPHdfSXDVGtaHQZzG509ujUSko9J04CRxWq7ajZxkKvEHT39V6eJE+0w+ypPIDzzJhrxkVJoy5UnAN03orBrROb7VvE2ju6xiOhuJe0Kq2KgWkb9XDgvYL5UqnevOspVxoEylUxI3DHFbKm/61tpp2zfWBFCnVtCZhE4DikZbFD9lROaSXQSBX+k/923G1XmjoGZKxUsEoCZoJfkjPDQpEISbyS8g0nVbBOtcjiFBcRuSXWveKd/2bwG3UaOM+OB0H6T7Iz4hpW7W+dDJ1HCqDprBLUHndQPM1GzCo4nUS5HRn4Ky9wFizo3VAFc/bK4i9naAZPVWX34zx1mK3IjuSHuZJHxI8mUVlwZkvaqZuO7tfljPo7j+ww6N7rh+6aUjHghaQodxGvb4vDayKJ7c4WLAy01JXmw57faDjUm3dfRhM061HgGyIAEEhGOW+uV7SV0drEQXNpNLLsxN9OOJhOILSFKWalWX0wQjbH3iKXeiphKoVtbcrA3Vy+rXQx1Utvva6bYDe/oPOI4mEHr2jYaUETZ4zidcCVTJkxGqtxEGzaOVv+uDQAOagwRkZFR0d0bC6g0L4tf2uhr2h6Zys2ixjz7Bh1AW6yoOxMWirJfMc3ctXE8yZFjl9oaY+Gq6fOg2az1NP/w1uXY1BN3lGQflFY2On0ZwpPZEtlWz0r43rkVTP8j0rMJ3Ga/cxaP0YracjnvS6tRj0E1ekVhqp3ECR+lQM9UO/LbxfIOaU6LYUPy2EH9xuHxjXR0DfrAu/NWbtx5l+diE1BJ51UrvElusz7Hl9BhZJ9NHypCd+rxpDSaot66Kf08JjSX1cr067U90W7ldvHz/++ed/AVt/doBa3wAA"; \ 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..55e1a2149 --- /dev/null +++ b/markdown-page/index.html @@ -0,0 +1,25 @@ + + + + + +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..e7a94392e --- /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/0.4.0/weekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectorsweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/ArgCopyMutationweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/AsmIsUsedweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/BranchDuplicateweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/ConstantAddressweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/DivideBeforeMultiplyweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/DumpIsUsedweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/DuplicatedConditionweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/EnsurePrgSeedweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/FalseConditionweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/FieldDoubleInitweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/InheritedStateMutationweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/NeverAccessedVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/OptimalMathFunctionweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/PreferAugmentedAssignweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/PreferredStdlibApiweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/ReadOnlyVariablesweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/StringReceiversOverlapweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/UnboundLoopsweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/UnusedOptionalweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/detectors/ZeroAddressweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/hacking/contributingweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/hacking/custom-detectorweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/hacking/designweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/hacking/developing-mistiweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/hacking/souffleweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/toolsweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/tools/DumpAstweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/tools/DumpCfgweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/tools/DumpConfigweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/tutorial/blueprintweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/tutorial/ci-cdweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/tutorial/cliweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/tutorial/configurationweekly0.5https://nowarp.io/tools/misti/docs/0.4.0/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/CellOverflowweekly0.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/SendInLoopweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/ShortCircuitConditionweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/StringReceiversOverlapweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/SuspiciousMessageModeweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/UnboundLoopweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/UnboundMapweekly0.5https://nowarp.io/tools/misti/docs/next/detectors/UnusedExpressionResultweekly0.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/tools/DumpImportsweekly0.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/CellOverflowweekly0.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/SendInLoopweekly0.5https://nowarp.io/tools/misti/docs/detectors/StringReceiversOverlapweekly0.5https://nowarp.io/tools/misti/docs/detectors/SuspiciousMessageModeweekly0.5https://nowarp.io/tools/misti/docs/detectors/UnboundLoopweekly0.5https://nowarp.io/tools/misti/docs/detectors/UnboundMapweekly0.5https://nowarp.io/tools/misti/docs/detectors/UnusedExpressionResultweekly0.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/tools/DumpImportsweekly0.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..072a19ffd --- /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-hl-3:#00f;--dark-hl-3:#569cd6;--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);--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);--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)}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);--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);--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..68cfc800d --- /dev/null +++ b/tools/misti/api/assets/navigation.js @@ -0,0 +1 @@ +window.navigationData="data:application/octet-stream;base64,H4sIAAAAAAAAA72cXXPbNhaG/4uvk+4m23a7uZMlOdXGil1TbmfayWhgEpKwoUAtCCrO7vS/74AfIj4ODg497d55rPc8Lw4AgiAA8rf/Xmn+rK/eXeWluHp1dWL6cPXu6lgVTcnrv+Sl+Oagj+XVq6vPQhZX796+usoPoiwUl1fvfksGb8kAxZnma1FrMa+ORyaLkbdrZK5FJUdiqHZNvv/291cXNH/medOrMaitQ3AHJouyUz3wuik1xgzECFg1kpq/Jw2gnyxsocSZK7h1ut9IDbTwMHnJ6trFLADam7c/OKWpTm0mcHH6H0nlmd+u7nyWkJqrHcs93Cj1yN99b5Us2yzuHjfb+9nmx5F4ZkqwJ798ltQl/u2tBcxL0dku+I41pa5T2CCAAqdT69dvAqDdNMrrzXbLKKDzRhoGvDL015NLil4Sb//6j7+/+c5O1ZIulaoUjdpKJ6DvPtC4dx8mQDdVVdKwRjkB/AtTUsh9TYMP6pRBp37gp0phbWfLUkiT112jTw0GHEUpXJ9JkujoUlDVt8DyWeh5VfDYyNuzfTk2pPfSTCsh90RuJ0aoNTvzodfciJLXCXCgR+8XbV3Co0D7E2kQCKuSy+ZoU+Da+8EqyIJrnutKzSu5E/voKN/hXDE2zpvORkKOQgzXdbGbSh0Z2CE7lq2Cu+MnpxG6Cc6QFNAazu8TZlgh0uoyLhTz8OcYvcj0G8j7qRGlFjLyK1P7eXX6um40MwUJs73gtz1o64WQKmAWsxmmMmmbGWbrT3VYfVzVjzUvSAkNYloqIRpJ4oKewSZ+wZ8Uk/lh0ZxKkTPNKcX3QkhJXMds4qn4NteYrZ9Wzsvy7szVrqy+UHKy9bQpKWgQz8YxmEfdgjwqWWsm9awoFK+BoRpwckNo2cRskIQ8mzlm66dViLMo+DXfVYqvm1KLU/mVkhsUR3uiQQ3jWYKGECyRb3M80ceHUU3LDYAjGY3wRcQnLH1/zRXzShaCOm4DYcR8EDsssdAOQOGpclk3it+rfcZpbeUE0KZLsEU8MddiGTf0k9mxsuaTmsyNIKVzEzGJ5+OZ3CCeQUaCl8Wiap5KvpICeH4F3NwQWk4xGyQpz+YGs/XTEvLAldC8yLRZ6powN4IjSUmuEqbxXCOmMBDPXPIzV7M853XNi5+HNQ1K5nAkKfOPCdN45hFTGJheHDuycs304aaflVPSBsJIOd9hdvGEITsAhad6UnzH1azZH7nUvJjVtdiTkgUDSene45bxhGFLEEdJWpmroSjF0+wELJrH7O2oCenCZqlcHbMQhGepOCvuZPl10qUbBJFyfIhbxVMMrQIMnmDNZbGSt1V1omQ2qkkpZQA8nosFzyI+QekPldJzofLGLMBMmAiAgbSccEskPdASxCWSbtfUHnjOzRZFbR60SkZrPjCSlnbCFMkbNoWBicyb+iRyUTX1mtc12/O1syyHJA4F0vLGLZG0QUsQhyfdyKeqkQX1ErXkpAQfIXw8LRv/GLOKpLCm9dJRPSWBNa03WvDHiE9Y+qbmxfL5ZJ77RSX9/SAsEyiSmBVuimUImsJASubdjhsr6RkPERMyDU1SGV5MHhFPP6P/cFVNWGuy5KRcfoXw8URs/K8xqy4FaIUay2D4i7YEm23CtfSw2BempQ/Lam16MM3MEuAkth+EGkwCE4BZ1ex2JbCxgHC9GEp5Pwj7SES3v4KU2MhT+36D9iM78gloIyfuU9bX/MDOItyzBvB+SMri2lwQKzmUCjwHANj4YcgZg52QhSeHto0AEyAS2c/ccz0rSyAR1MOLwvlLaSqkeIGHH4meDKpfVl1hILDb5i4OFfw5HMraf3v9xonSXElWxnbpmJRVbJnpErsdVfTjIDOA3F0IINeLSV0J2eP9/cMyy7br2cOH5QN0IYA2XhxyJey5juYxtixoEoaiO6m5tzMd1n8ObUkjde/vdQ/DckC01NiA3MqW8kwlLuUZw/XDXtachllWvIv02DAktqXu1Gv7F16xRjKpZl0mWBEt09Yndhuecx47IzdyRxXxOIY52igquRzisEJb8DAQa8tVj5jqEsRhJhuW66kGTgwG1wdVffm1KryDZtA1buGdKOQGodXXdQ0eA4KxrRwdLgQwoR1ZgjaVZbXOdKWAVQEbtR1kJKap8Vm28bhhI9lcOwZrpFmtV5of75lix+AEHIx2QtKjhXnYKLhCL0GhtoPsj6zlgfny6r7uCIlaD30ARmKL6mhOAFIradvLaYvXTNVc/cjyz1PpY6Rr9C1sdDLylZ8IdGEmzGwQesl2mveKnQ4TW2pwDQmJdkoMEpYDbcAwPWX1MLX06hsnDrvCu6Nnq4cJLTKcV1s9JObO+Q6dXgm1zXe06dU1q0V+XVZ2JwXrwABHMZb4/OY9gTW/eY9BlsU+NeYaipFhmLHEq+IZHWbd/FaF/wwSPrtexNBjPcKmPNbPb95TCtzJUjBTSRRar0vhhs1RUtq2OAXec32veMHNfnPk+TbgezH4E3TW5BPZYwQ+hSHdRabcPLrxkXAVuANq6nqwht1J3DYiDf4IbpIg3I/gNoiPXQjFc/zJOyBfYlK9bqy41DUSVjXhaunEt0zuG7YPlugQ/hBCMzAVOa38fUR6IilkIXJoB9yFdypa5y6e33PJFQMXs0GsHUKaFG3NmwMcfLEtbdAHI6OJdB6ap7Bl8PgcLo0la4U2x5lXx5Mo2wWbR/C8lw/1AtC7fCW1YjkJ2ikptGQXHnGkvht5EcRh0t8IGayhxXYAacupN1Ui2pan0Peq+hcnF9pSx6rXruCSaS1y9IGwl5BqeG8uE5ETcNteSjyQov9ZCZnxowgKHHZb3yGMRveSuF5zrl/u5UVjXtGkrJeB4l5oUu4bQtGMSEZoRt4brJCJ31nDSouxwduZ5uoMbWuHBoOWePC0E9/SW/3C92KTC5RO+WPVE9DTlSObI6VeZHOkVslHm4j2FgPtAtCeuJK7CUAjx3D303D3CZyTbaxdDCjMMhi3hVd50CTDRnZ6/wVpZ9ZydLJNAY0axZ0m4U4w7qX3Ex/1Rw79r9/8Pwb9zuXPHu5fv/nTB/rXb/6sIb6togmDe1nt99CHIixwqyB1ndtqf8vP3BppuxeAA9ggdKnuCZCnZn/rFQ7oGB3PUmPdgcxLo35qBNdknqVGd7kUyzkZaqkTSYcH/YPec8k78jIB0HXqqgS/MTJSOwWp63RvraNPHh2tf7+d9vyRtSEPPjusUo/txCWO2hJrYUplZB4THEpcbAbRv/veK2p7AItU1lZJLGyr9cscreOB7cQRzpqt2elErxTHowvFK+dLpT6XokYPC/T0QUqqnl96Mbl+LnQ3Et0blaz8WosaX2D2+XYU5clVO4sXYe3oYMki9lGC5HEXg5py5sXsMXWHWNZMssTwacODQPxib991XiaehQZ+pySVn5/NOYhT4vCBBx6CkPmmkWyqzdcT+HkTlNyFJdj1pjKbCd6r/EQHOzjt8zMrmxd5tIH4ZoTuVhrRu08LvyhprfrcrmbdG2S64CPbikPqxRy3XMnxnHpii8bzCKIxp6osXuzjxiZc2hdGzat1003GUNRDLVl+GAs00caLTjtdSvUSo0swfvz05Z3AD0avkvasAzrRaemdjHR9tFIzAvdLqISy93Q/Ei143b7BmCx4JyMVfLG8mT3ebrbZZnG7um4/Cbdd3i7Xy4+bDD+IajthFORYasF3QvJiJTMvr2il9X5eYGLnt9UQh67ewAlDm6TRIn0LNSLaDFTlK7mrMo7urYzMUY8eeTXvrfNiWXrXrz+tGrluRGq1Kq/Kkufju4yUS7e1CQKRluy17UcIphp0QWn48IL/VP4lDh9Gj0zfV7X39ihu4EZh+MbbP0pwG2D/yAGK+l6Jo9DizG/bcbakssNI1CbjZWIl0UYbdRLXfbdgGrSLwdHtkDA09prrQwV+5jRiAkRj67W90DQTORUnCNvCrgpezxRf/ruht6sThMAVP1ZnPqVZxwgEW3djHfY1QojthWEGl3nX1JoJIxNL3VoxWe8Sc5BeQ3tsDIDgosKFuYHh3kpC6uZGvq8dWJ01T4VInb7qgBcxdjWamJrn+lbUqTl2dwE6ARTymp0mgY2ews34tAIbPToumYyy5qnm+i5xyfVDkR2AktfsNAls6ROD9LQCW3psyORqz6n9YRSniMR+cNGmeMT2v2gRXiMVZ/nBzM0JREuNzmm/BF/nDS/9L/A3eWMbcWfzGSXr83T+bsoFN0jj+yntu0jmial/jwqbKV+wfhB6cHiWLbeLu/n28eEWfwa64O0Q5IHnyD7zRZU7XKi1LtwxANuKNY+QYRWjYCcGuyf2Etpd94L3wxK3wyMTwDub5r9e97JvoVVVAj20/TepU5qvBs6gVfIWse1/pj1F+6ihJ7qoBYSEvqs4h874j6w58YD/wkeFxTKoBYQEixVZ7bZw9IXuBQAEytcBFxE2+FHK2IHskQq+54J9itJHhgUdkIsY3i+qdr6t7pZRh19Tj0z7HIhbqhYSfpfd26etqhI6HeghKGcNrZfm3WKNI4VF9dToEk57fJYbWf0jL0/9Z3QSBrEwfLFoVpYbd2CJwC9KfEWTXiGuODFgms8nge+59z/Eh81e8FrIXRUN35pfSR1wvco2q+3Py4dsdfcRulk6REeN3Cc3s/mGDLXFAfPT75/+B4LtzL4jZgAA"; \ 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..c03ce31b3 --- /dev/null +++ b/tools/misti/api/assets/search.js @@ -0,0 +1 @@ +window.searchData="data:application/octet-stream;base64,H4sIAAAAAAAAA8S9XZMbN5Lv/VVOyLeyTLxX+U6W5Nk+a9k6annmiXVsKKhmSeKaTfaSbI28E/vdnyBQJKsSf4AACrRvxpomkJkAsoAEfnj515Pt5p+7J9//9q8nvy/Xiyff86dP1vP77sn3T+5Wy+/uVssnT588bldPvn9yv1k8rrrd4W/v71bLZ5/396snT5/crea7Xbd78v2TJ//79ChFy7OYbTffd6+Xu/3yxeb+fr5enCR+fFzf7Zeb9VmmnxioefrkYb7t1vuBjVDz9nGdqJaknKCz+9rdPfYliCgcJpug7fN8vVg5KW+73eNqH1Hppc3VO/aMxXb5pdtC53A/Rf2D8eYk7eVYUp9+KOllSCCxt7dpYPJMNsQRE/V8c0p9SV2fa1i4GR+4//5rskqbdKK+Rbfv7vab7S5V6zDDRN37zWaVrPeYeKLOzeP+4XH/Zr7/nKp4lGNqbS938w+rbvEyu9ZBxqmetllttsv/6X6x5Ut2OpprqhWPyXXgkk7Ud79c33Zfuu1y/0eq3nGWKv7342Z7P0+uc5In34JRv7ZcL/fL+Wr5P122F+Ks1ex5l9Mf+Nkm2tGPsan6z8kL9A6HRjQmRgfD8cC6ebDjNhxZ+9+i0sRZ3O27l7/8+u79m+fv/u0k7st8uzz0PGOBg5SXh9mjhYMSKH1S+uKnm19IEZbrfbf9OL8jSs8pS3RGRp40fQkjkJ8zYxhKtCJxOEo3ZbXc7d+V1McwY706IV1jVq0kdJHp5tiRLrtSTrlqmLDbPH78uOpK3GSctaIxPyzX8+0fheacMlc06O/d9sNm1xVadM5dw6T9/G5/u1+slh9K2szLXcOkL2XV86Vqvfz347LL/qaPmWoYgMK+RDNSw790Y7p1YBKQaBHIX8Os8OQk0a68SUq6YfPVqtgmkrfOwLD+uPyUPzD0uWqYsO7+eSxVrh3jrLUCiOL2oZkLDRKjoNj9/rL7OH9c7XcXYlkvfUl0ifQnK959y4qi6NE8YDte0BtOA7ah9Tu8DGpTv9vc7rfL9dnNxyuEvchx2suF6I2M6n31dbl/sVl0aZqPqafp3s2/dG97iT8uV90urtxLXqCdz1rD1LkNByutv/z7Sf3+j4dxI46SlRRaKXGefL1/f1CQo+2bU5ZLSseZQ52H/VO+/md9vjwjnvXGh1vhH/Ptern+RNbEPLtGya7eCr62jFYYlyjQCg/bzX91d/ufD/8v34xn4+x5JvltMrLsny7trsSsQd6pNkW+1n9ctBAk/jO/3JHOsu/3VMapXzGypeRbPsmZ6j2XbMvxoST7Ip70arsdxHMxU23KP9OHzgrLHMgVbar3eFaUuI4TEvebrqAljiYd81awifrKYbXt0tB0TnN1/yCqMjxjUJDQDCc6FGHNz9aJA9Age9wPksbFgDGZg2KyTZs8Bzias7kM7BIsifReh2xJn8wh4Z/Zd530lXVdtlxTey5qQ0nHZWVM842YRekOctGmiJck2VZhOuUEve0eNtuIzmGqEqWjGbiVDifg9pc40xsQsUOdvoiuMTl553SXTXe2hRa0DtlGfVyKvm+G2S5oHuQNum4cAmITzpmKDBjW+nERKqXmx2kn1r5zlBgvCCr9ZpT3UhWQEk5zBmRNjkMEjaEf8i+ICp4/ZCdtmCi/Oc57ALy1p279eD9UlL7c5LX52dVuf33x4tXtbZqSb86pL9XpyXqo9R/P3/588/PfUtUOkk/T++r/e/Xi13c3v/z8/sfnNz/9+vZVogEoX4Elgz7abtHz1s1PHfXo57ztqp7QwbLhWOxFLcNyjWWjMp1243334XG52i/X3823n15sHv54/bifHwzwinnK8b7P8Z7kSN6I+Tyg6bhx5rKm5xc1D2rjclHPZio2aPbNerffPo6aZ5qJ34xFFppLRQcxd2i7WqHxu0swc4rl4x20n7u736vVeS/sCjZrzmQgpp9otBfl73eLb5e7b5frz4c26BZX8Ri0h7i01ske42vZT9pgWa0Fln9O/RP7d5/n2+7m/jCt6BbeAvHUDzgg/E8v5eOu2926bTS1yjYW+SeUaNhf7X5fPvy6ftx11bxvJNErzcN2c5DaLf7Pn1K8+/nvXe8utco3FvlXFDAWCe3ub3a/DlszEgMd06ZHP570SF2epD+P6IlXyUldlSgnYFBpZOOLqxHNhIwsiWCiFpZFLcE6zI1U4raVRSch46ZGJOktnRiFBGtxWuSRU6dp0UbI0GkRRo6dxVFF8EOqHUnklCYzegiVoVLEkN4/5EUJwaq/TmSQXozMaCBUjmtFAPGCREb9D9v5+u7zy8eH1fJueH4zPPaTHMkRwA8BTeFapJp+uKg5Wkm0qDUigxQTC6OEC6IrRAxJxhdED+mWF0USaXWeGVVk2FwUYSQZPTHaKPSYtMgjrdYnRSHFbZAUkSQVYFJ0Umx/aaSS9gFXjlqKS5kXwSSVrU40U9hfZUU2aU11lSinsHh5EU9S+a4U/WQUMBIJ3XWr1S9fuu3H1eafCWHQMHlyDPQC6QhX6kjHi7jCaA2NylYj7olbVhjxBIVWiHUuGFwQ5aRYWxTfXKrbzMgmyc6imOaCoROjmWxvSItjLtXupAimoK6TYpcLRk+KWgpsLo1XLn2ElSOVgpLlxSgXylMnOsnuZ7LikktNcpWIJLtIebHIhTJdKQpJKlQs/jiMmfP1/vlise12/s5IUM5xjvQoJKApUqNE04uLmuNVRQyoEpEkmFgal8RF14hOUowviVGSLS+LVJLqPDdeSbe5LGpJMXpq7FLmMYkRTFKtT4tjStsgLZpJKcC0mKbU/uLIJukDrh3flJYyM8pJKVulWKesv8qLeJKa6jpxT1nxMqOflPJdKwZKL2AkElosvywX3Q/dx822e/242i8fVn8khEMoW3JM9DKmM1zZUCeSlRsiwTqoESflWVwYMSUrqRA7ZRaoIIoqKU1RPJXbNpmRVVE5imKszIJMjLamt489OdAPXy8263331b9tdHpzYS3VOt/J1dDf0ZkeGWRWgCf/Ly16QeSd2+CTYvAKX2tSNJ5ZqElxeYUylUboucNE5Vi9QsnzovbM8taJ3yd3QVmRfG6TXiWmn1zkvOg+s8xXivOLCh2L+B/vH5I3n58Tp0f3vvxIFZ/lv4ypitfQWWOVqD1oU2mEjgTWiMbDhpZE3hesLIuyI3WZG1Ffsq8seg4bODVSzmn1xJgoUpvT4p+8uk2LdcLGTotr8mwtjmEiH1fteCWvRJmxSbgcleKQnH4jL+aINMF14oucomTGEuGyXCtuuFSYaIzQ7+davNisF8vE0/ogV0bUENYYq1VfI5CUH1D4xtSJLNLNLY41klRUiT4yClMUj+SWpDBCyWmT7JgluwyFUUxGISbHNZM8LDXSyWmVibHPxDZKjIYyCjQxPppYnvKIKadDqB5DTSx1blSVUdZacdak/jAz8sppyivFYpOKmxudZZT3avFadoEjEVy33j1uuzfbT7dd0kLPKH1y1PYKagnX81jLqws6o9U1LmCN6OyScYURWURshSjsotEFkVeaxUXR1uU6zoywEm0tiqouGjsxkirwjLTo6XItT4qYiuo8KUq6aPikyKjI7tJo6PKHWTkCKipdXtRzsUx1Ip2C/icrurncNFeJaAqKlRfFXCzXlSKXxIJFopWP89Wuy1lqGmdIjld+xHrCVUr0/HhJbbSeSClrxCyX7SuMWqKCK8QtCYYXRC6pVhfFLil1nRm9JNtbFL8kGDwxginykrQYJqW2J0UxhXWfFMckGD8pkim0vTSWSflYK0czhSXMi2cSylUnoinql7JimpQmukpUU1S0vLgmoWxXimySCxeLbZbdavFy8/hh1d2sl/4ziKC84xzp0U1AU6RmiaYfL2qOVxcxoEqEk2BiaYwTF10jykkxviTOSba8LNJJqvPcWCfd5rJoJ8XoqfFOmcckRjxJtT4t5iltg7SoJ6UA0+KeUvuLI5+kD7h27FNayszoJ6VsleKfsv4qLwJKaqrrxEBlxcuMglLKd604KL2AkUjopOx2P993Gc+A4IzJcdFNXG+4ygN6sbzcYClQGzVipny7CyOoLEUV4qmCghVEV6WlKoq1StoqM/IqLk9RHFZQoIlRWRUvTIvRSlprUsRWqe2S4reCwk2K5iqVrTS2K+lMKkd6lWogL+4rKHedKLBKv5oVE5Y08VUixCpFz4sXC8p+peixuPCRWHJ9GNaf3911u123+Pt8u5x/WIEnTv1qwRmTY8mf43rDzRHQi+XlxpKB2qgRS+bbXRhLZimqEEsWFKwgliwtVVEsWdJWmbFkcXnqjNkljXZxzP6zWtDOmq9UyrGCP79sx9uHrlm8oY4/t4Sb1aq727/sPi7XdivuVYsaVPZXlPlwaOzwbvJ1CzvU8uf77nWH8W88HX9yX5s4by8o2cR5e5URP23eXtJsk+btldouad5eULhJ8/ZKZcubtRYUss6stUo/kzVrLQlyrjJrrVL0vFlrQdmvNGstLnxk1rp52C/v56vX8/3nH/tn2BOmrCBX8nz1l4jGcCsgjUBS7jQVFb/GHDXH3MLZaaKKCvPSrMIUzEjzS1I0F81rk8xZaEEZimKirEJMjIYmelhaHJTXKpMioMltlBT7ZBVoUtQzuTylax55HUJlQjG51HlRXlZZ68R3E/vDrMgurymvEtNNLG5eNJdV3ivFcQUFjkRwD9vuY7d9/vjpvlvvu8Xz3W75KSWGg/mSo7g3Ua3h+sdaobTcWA5XRI1oLtfowoguQ02FqC67UAWRXVmJiqK7/DbKjPAKy1IU5WUXZmKkV8Hz0qK9/FaaFPFVabOkqC+7YJMivyrlKo3+8juOyhFgldLnRYHZZa4TCVboP7OiwfymvUpEWKHYeVFhdrmvFBkWFvxidLg9bGlZrJYfnj8sk0PDYabMuBDqu1T9I32+nLJwcGRJvVgwxdZJUeAFBdXiv6SCFEd+6aWYEPOltUVRtJdh/4Q4L6kAVSK8Qq/Kie3SWqNCVFfcNhnxXFJhKkRyxWWZFsOlffxXid6KS1wStyWVs2bEVtjvFcRqaU14xSitsKgl8VlSWa8amWUUNhKTbbv54pf16o+cTcJenuSI7G1QW7i+fW2elNxwzC90jWgs1dDCWCxBfIVILLkQBXFYXgkqjS7pBZq4EzazdCUxZrqHZUaYE2yfLxYvu7tV1aYYyPxzSmD3kW7ny7RtqznlGEv+c0rz9rFuz/rNQOaf8q0nzliS7Z84X5nyZZe955j+oV/5JccJRc9+wzG50Nd7vXHCGJs2L01v2Emz0klfX9KcNLkgk2akk8qRNztLLlCdudmEDytrZpYe/lxlXjahmHmzsuRyXmlOllnQyIxs160XN+ufNpuHhKnYOXHyHOzWlx+u1oH825iqaN0MSlRjnhW2qXBmBQVWmEtFDC2YPV2ysmhGEavLzDnERfuKYryIgROjuqxWTxvdY7U5aTzPrNukETxi7KQxO9PW0nl97OOqvEqcWaK8uCNSjjqRRla/kRVbxJrgKtFEVlHy4odIWa4UMVwsTCxG+LzZ7l8st3ePy33OxfAwX3rkENUaqVuoFUrLDi2gSVWijEyjS2OPdDU1IpLcQpXEKUUlKotestsoN6YpK0tZpJNbmKnxz3TPS4yKsltpWqxUo83SIqjcgk2Lq2qUqzjayu44asdgNUqfGZnllrlSvDa9/8yL4rKb9jqx3fRiZ0Z8ueW+VhxYVvBYdLjfLtef3nZ33fJLt9398qXbruZJq0kwY3p8GNcbaQqsF8vLDhGxVVVixGy7S6PEHEU14sT8gpVEioWlKosVC9oqN1osLU9ZvJhfoKkRYw0vTIwZC1prWtRYp+3S4sb8wk2LHOuUrTh2LOhMakePdWogM37ML3elCLJGv5oXQxY08XWiyBpFz4wj88t+rUiytPCxWPJx97C8W24ed6+73W7+qXu9WXQpoSTKlx5JRrVG2gJqhdKyw0hoUpUoMtPo0hgyXU2NCDK3UCXxY1GJyqLH7DbKjR3LylIWOeYWZmrcON3zEqPG7FaaFjPWaLO0iDG3YNPixRrlKo4WszuO2rFijdJnRoq5Za4UJ07vP/OixOymvU6MOL3YmRFibrmvFR+WFTwSHT6uP2we14vEzWqD1MmR4K9AQ7imhxp+jWqLVtSwWDUivJhZhdFcQGSFyC1qbEGUdtnSoogsXqeZ0VeCjUWRVtTIiVFVbr2WnUSIV/OVTx9kFjH7xEG0cNc7ZZD57abFvvGGmhTnZn8dSTFt1OBJ8Wu2vaWxaryrrByXZpcqLwaNlqVOvJn5OWfFlvGmuEocmVmcvJgxWp4rxYcJBbocC75OIs3nxLmR4OskojyQ/2tMVUp9vK5Ei8M2TYsBxwLrRYDI0PL4L2jllOgP1mVZ7Be2b0rkhwysE/eltXpW7ABrs0bkkFq3OXEDMrZG1JBq68SYAX5c14kYUktUFC+gclSNFtL6jZJYATbBNSOFtKIUxQmoLNeNEsKFicYIh6p99fVh2+12y836bbd7XO2T4gWUMSN2iOqNVS/Ui+XlxxfQqjqxRq7dxTFIhqIqsUl2wYpilrJSFcYy+W2VHeMUlqcw9sku0OSYqIIXpsZK+a01MYaq0naJsVV24SbGXFXKVh6L5Xcm1WO0KjWQG7tll7tWTFehX82M9fKb+EoxYIWi58aG2WW/WsxYWPiLseThrZLNer5KjiGPGTJjR0/PpWo/6fn1ktqEmjtprxcbxuybFAsGBFeL/aKGF8d6l62eENvF67oolkuwd0LsFjW4SqyW6SU5sVm8tivEYtl1nxF7RY2vEGtl2z4ttop/rFeJpbJLWBI7RctVM1bK7JcKYqN4E10xFsosWknsEy3bVWOdhMJFYpv/6bab54vFISxKCGwGqZOjmv8AGsK1OdTwH1Ft0aoZFqtGJBMzqzCGCYisEL1EjS2IWy5bWhSxxOs0M1ZJsLEoSokaOTE+yfSAtMgkXquTYpLsOk6KRqIGT4pDsu0tjUDiH1zl2CO7VHlRR7QsdeKNzP4kK9KIN8VVYozM4uRFF9HyXCmuSCgQiCiO/4qEEcd/RWMHffbcj8v14oeDUTfrl1T6x/69WCgfZEyNIE7FgBZ96vbPV6ujzF2aNSRTNUterQ+3vS7yraEZ61j0eb4raiw/3wR7+Kw1TJ3989jh/tB9nn9ZDkza//GAfZPmqGjMsXw/H/7vRUOGqa9gxL8PA6CLRhxSTzBiOCHwvMPv/Tz1E1TnB/1Ye2aY7wkpC+tCtpBALt+GnFAtYAQJzibbcCEkD1jhBeGT7UiYagVsyZhc5diTGZaGjCt8dibD0rRQM2BfKLgssCpnOhr6whInoMl2JIWxoaZLC1wnWpgWmQZMTI1FC3rLwdjx/PZdzvAxSP7XjCDUgNJBZFjuyf2nZ1RuF4qtKRnV/PopWqHIq6e0sc4zrWgtIs+ynJHHsw8OPlexsnQ88k2utDaSZ3/mKOVZPW0V5JKtRWOX/x15w1d96/JGNL/xq67G5BieOdB5llded7nUrw7nTvP9/ONq88+sORTJ8xfNpZAVxXMqWg3T5xTQvOy5RdiuojkfrrNpQ2R63SXOCaGR0wbLdBuz5mrQ0hrDZoa9xXM5bHztATS9JLlzPWh/paE0ZnXZXBB/eVMH1VQ7M+eK2DWuM7ymFiF3MgnLcK2BNtZPDy8HdJ6ZM9iSLH/NWIuMKB1qaR1MHmmhcbkDbcSqCVeRXKjA3DtI6pQh+a6RuPUZl4wU210S4+CqnhbiJPtsWoQDTZwW4CRbmBPfQDtrhDfp1pZGN9j02sFNcjkyYxtofaXQJrWnS41s8Pc2NbBJtDIvrsFOcZ2wJrEAmVENLMG1gppwEcQ5kiCk/fxxfjk+HovKQXNNwdHnzne96M5DxHG3iP1rdIPIUMK+267nq9138/V6s5/Dt+lOid6fE6VuQPnU7V8vd/vlc1/8eUsDVODnjNcZLEoY4oeschwfWlTTHK2U0Cdj3r8/qC214ZtT9nRTqKBQDDKKScvsehYNTVOMe9YXMGDjwvsUCw0dCqpp7aD3uP31zZu3r25v379+/vbfX70FnQe0mmSb9iWAr/9us/64/BT58l2CeK+CNw7dPj4czwwG26eX7udILWhvf+H3FVef/nkF5Vzy3GmWPRuIKTbxwjf2cbmaWH/PehHXsnC1XE+1sBdxLQvvNquJBjoJNe0brNXYbuzFuCM4RmaeoYPExd9o6vrMReVJKzNe/QzLmzyypNuUM5ikW7TfbFYl1hzz1bNkd/arEoNI9np2LT+tN9tu8Wa7+a/ubl9imi+hYq25Kcab+f5zSaWNcle36u/d9sNm50/Ykw07C6jo8fO7/e1+sVp+KKw0T0A929z5wTfb7uPSX6q7bBnJXs+uL7Yd0KLXZaOGeadZRMeWV+svifa8Wn8pHlVGFfH65vbdzft3N69f/fLru0zl39DMObVxKGvcprfPX7wqtKjPWm7PtJH3ZE75sDs2JzAjGbEGOCU5pEg+Rnv0UogwfLHD5BnOaKVPrGmsP7+6PTnB2Hnz6VNXZtQpa017yHQ0s5Jc1pr29MPb8y/z5eowSy+yDAiZaCP6brqvd509wO6fRj8beU6Uuo633/7xenduEbR2NxDqUqd+NQOTse7P280//2OzeLXdwhNR2IRhpkmWDPuQd/O7/atjoogXDAwZZZlkiLeOXmrAN33mdCvGQkI2LXdv5ttdtx03VK5xVEp9K19s7h+WK7suNtVUIKqCvUOXu+kzZrqdl+2vcD1sRIH7+ZWAK+uVZfSHxsirLT/fX1FdASsK6gvUQ3zYWG6/m+/2t/vN1n8x9Gzrcvv+mCprKfj5bn+z7+7fzLfz+/Aq/VD6KEdqWwwLEe6/n9++G5fTb5OhJcMs0wzJjwWjdmTGgwObRrJCbvup27/Zbj5t5/ev1vvtsoutpMTtRJKuYO3BXyYZeRRwBdt+PAYrU+wbCrmCjS8O7jRfR5fMLto4FHIdG/fbeXxZL8XGk5Ar2PjzfL/80lVpcV/UFex9vruvYiyRc5X+aHm/PNTIxL5oIOUKVt7aPnmSiWcRV7CvfzpykoEDGVew8N12vpxWgScJV2nf+b677yZ2lCMpVxxxagw4V7Dw83w32cKxjCuOiDUGxOvU4WQLxzKuOGLXGLCvVofTLBzLuHpEUS+guE59VrIWSbpu9FMp+LlOrdaw0xNzzRitSoh2nbqcbiMRcrUocnoQeZ0anGjdUML1ItwKAe51am+qfSMR14q/J4ff16m7abYNBNS27XBj4jTjhhKuOW+pMm25Vr8y1UYi5Cq9y/7zZjFx+nwUcY110PVyf+MfD8pZCD1KuOJ8oNZqoyfsijb/uOxW0xrek3SV9u9PO0031xd1rXX7H/443I85ffn+LOcKlr7t9o/b9bsDtppi6FjM1XqoStYiYTVsxhDycIPyotvuEmnkMXkalgyRwB+clHgt+aqAiAxA6Je0jB9nmZaKkpF9SGjIZpu5mtFHadew+oIbLu3h6dheqmFR+tTJTuiOZv9tO3/4nOeDR0W+gBIPPBZyugNesKvE/cIiazjfJYNLXC/J4vP2Nrfb6d/mg9PnaV52zlin0Qdb7h4Oom+I76MddxfsGsqZYORAZPq3m1ab2QelR+b5d/UHqib5xn53R8rN2/Ra3z475imq4dDVPYd+8+ZtZre0fTbKNtmg4n4IGVLU+xBBVfocaFxRT5No3adu/8MPo+vqSywcSrmGlQ/bzV2326Xy1QvWImm1rMbdwt3H2Anq5fb93cf4CerxvQlvtt2iOxQBP0zhSSZZMr69g+EhK24f7/JsOGcotoBuH3y1+NTdLM4nrMDGwYPyPlk1tT/Md8u7H1abu98TlI8SVzPhxY9/S9DtUhUrHW2gXVxalz7WdLG6om2QI635Ox+P2YOHRhex83uefpe8gt7d9i5Hr0teQe9id2GFdazXJS/TG/6qwPspkc/q8vspiS5+Fnm5Cs5p/3x3J7rLnH5Q2CmuT23J+gAu27Db3+9vXuabccpXzZLfLwZJyI7EG27S62N7d/iKLgRAsEbOOatZs9jtC60Z5JxiDTm+8+rrJcgGXfaYb5ol487suJcipSsbpq3Skb348W+Xq+HFj3/787uuo9KyPutQrimd1Ul7Vi8V0Wr/k662T16jtFmFraIzrQM8ac3r+SJ6N9vlp+WFrU0jzacMFdp3s0jp3c4N3KefrrlL61dPmru83jSiedt9zNDrUhdp9RYiMsKvk36ar4olaXOdoQ19jirawcQ6yYZRviqWwIWGJFtIzunWfNxsX83vPhf5CMpbzaJMXxnnquOtX5f7nzM7KpKtzA682JUExlJ4GA2pHC04mHxh5WOMWfoMGbEOol7IlITVp7Ep+etQqab8NF9/ehzuHLxoyzHHFYx5udx24/3IF605ZZlkjk9QD40f/yx8Z5lkQlFkHLAhP0j2BRXHyyGbkkPndFsuR9EhY9ID6nRrUuLNkD05oWdGW9kUFy45izXZMH9Vy1a028mya5C7qlXJR3dChmWf28loy3XCikmwIdcZiyYZHv+YsowT9PnHnKWcuFVe/305uvJH2L+6/55AI3xBlfrvAkKRbstFVhGyJZlapNtykV+EbEkmGem2rDaF9eIyTrYF7yfLMclm+Ku/p7MRUz8oV/7ytZ6gXRnrPhkWJawBBS3KWA+KW4TmvLlR9cCusYSrWJc7ZvjWpc/OM6zbdrvN6kvXXx78drPJ6qgGRkJBdW2lc/g8A8+561o1OCaRsN4RNA+IqWvnh4+lprmclb+K5XpxKOcPf+TOIIYfBhVSvWWfr1Yu4YvNet2lXDoTa+CAtOtZvVx/muiTSFR9TzjXxwRPGAmZbiNcR4yuH5bszV2uF8u77tK6pEsUlX8eoG8WX//WrbvtfBjRROUOc+TEVb3tcC/eenhtcWALHtR/yJhvxEgGtuj9+22368qM6vPWsyvkDpda7IKT0f14/YhyaT14+2yQMqeQod3Yg3tGf11f2v5g1Y/Sl5pQFtdj9QVhvScoFEM/uCjp58tLjAHbxgKq2ja/OFcN2DRPnqsm25IW8QXsyQv4km36mHb5XMiqj3l3zqXbdZd212DE23NuGYza5Y/vP/7thz9uLi4OhapsLKG6dcedTlZH+TcZElXdXnfEtYK1vqC6trp568V9X0ETh/krW7Y6FLv0Ez7nvkZ9pe4muFBtuRsL4j3NaGxPohjnmOLPH80HeguH8b6Ixevc1Ir0Be7L2hPIJFWfgSQv679PuVHEM+E+5xKRBCsu7gjzLEjeFYa1B0L2/ejGAhi12yRZgfsbECCCwN0JHiTO+NSc3Zf3CqfZMExd0YjTkliSEcPUU4wADb2a7/fLu+67T4e53PIu0t59yvd9ynizq/Ojn/93s1zfdvfLPv9Jg5X8cX4XVUIypxaeliq0dLjZ7zf30y365iQo0zAqLWTof20GeyTKzezFXMnIVfffFWx0UiqaOHDF1123L3ZFkrmyK+43D9PN+cZJya08Wi2hc9/dYJGp3MZezJWMzHZCaGOZE8ZMHHf/yAlp708Nrep7w7j3ttuH+mg//vCtopmnG5cfHydalRkz0/YFFZXSX5ebW9hfp9tJBsByS4sHwHRbh192uaFlX3bUSvIthQaZJJurDzJVviXYR07+lkqGnXJzC4eddDuHI3i5mWUjeLqV2V9RxfExbmV4cnJ5UpJNKI+m2b98ma8S5j3HpHmnKKj80Ch/kn4TVhOt5FNJAlvS+p9/Su6VPIt+KuuTkGHD9Y4fH1crr5oKzfqGCMu1kQoN2fzq/mH/RzWjqbRrWZ082sfNzR7rc+1M60njRub1owkWjndsrfd8/Ti9Ks9yrmVpDSuva+Hd5v4g7ecKho5EXcve1eOHyYY6GVfzzl3VPtUTdz276/arvrxrWT5fLH5+jL56mGbxWc61LH1YPU43sxdytT6r+zTfV+kQhpKuNxZ8qTAOfLmihffLdYVGP0q5mpWPq/3yYfVHlQ+JCLuWzfvlfXQTamKs0ku5Xr/6H912U+N7Gkq6lrWL5ZfloqviBSNRV7S3hqFXjbDW+/lybduuQow1EnYtm7v/TlmniJvqZFzLwk8pq1JxAz/lrEgV9Po1PvmTmKvZOf9axc6jmCvOpN5tbvfb5fpTjRnVQFZFi8uXey9+9QWLvSlVHFmcG85dw+ty68f76JKcHh4H3w9dDW2UH0p1yb9luSteB7uh/oeb9cdk7YfEFXXf5+i+r6CbLoUOaz60CnrQ/TNszxzFA+J/M25xmzVEhA/KXfpp+sP3uOWoT73SbWBDnz1kypf56jFxzwO15Zh1kjHDdnkz9MaLphxS/2VtclJe0iK2nIHNKFlV8PqvrILXU6rgNamCKZwH9kn1tp19yyZuOKuw0SxgQ/aqe/WtZSHD8jYp1N5MFrIqi1BecfvYt2zixrGpG8YCBuQBkupbxEJW5VH62pvCQlblOdNVtoF9yyZsAKu48cvaMXHLV435StiOsrlK9c1dEQMze8z627kitmUPM5U3cEVMy/sKr7ply1lZrWOf+BXU255VfVtWxMDMrr7yRqyIYXkjY+WtVxG7sv0/c7PV5tOnLnZM3yWIBuDnwv60+fRT96U7Q9xu/XgPpB3TJX88zsrBp3yOz16++uHXv2Up/OaYJU3tKTPWf/Pzj7/kqe9zVNH+j+dvf87T3ueoov3V27e/vM1Tf8xSrp/GUz9tPh3Pa4XjqZO0Y9Ji19NKiXMNvLeHtXL1fnPKll4NpzLiAe2n8YcMupqTJPw9p5W+YNDy9OaOUkMBwW52E12f921wGc6697vFt8vdtw/bzb6723eLCbYsug+PmdYcs1Spi+X6Y5T4+er7HFW0/3O+jQbKvvY+RxXt3Xab643HLKX6h1/h/3tcdvvUT3GQ+M//Hqnyso9yWN4pX6ZnzaXP8//0f1iuP3fb5aXvNcHMxI/WM9T/cmtblvY5e4Z533Rtu9I+dM8u72uvbVdiF+AZ5vcDFSwbdg4vD66S2jkMEv/5nQNVXtY5DMs7pXPwrKnbOSSYmdg5eIZO7BwSLEvrHDzDpnUOCXaldQ6eXdM6hwS7EjsHz7CJnQO2bPTi93Z+16V2DoPEf37nQJWXdQ7D8k7pHDxr6nYOCWYmdg6eoRM7hwTL0joHz7BpnUOCXWmdg2fXtM4hwa7EzsEzbGLnELAMrNbZS6ljq3UuQfbBSJftu223e1xFn5VyCd/3CaN6RqvtNttbIt6vYCJ+lC21oyNlmdLhXTQns+sbmzaWF9xw2u1v9/N9DE9cNnMg5Bo27mrYuLuujccqmOR+3wyl1LIy/D0mfu5JX/1gR8PtWCxk42PJtyEFsYL31od85vBroQ3fHDNnWdJLSK36x48fV7HNSSfrbMKMyrfpX88fHpLbwGkY5cxuC1ec8Em2l93dajfRnm8GcvIMGwuLmPn20AoVzDzKuZKZL+y4MF+u9zWMHUurZPJ4fLZpSMcQ7CCJ6MLegXpk8fgcNqdsfIby0vqxEhuzO7ML1oU7tX9utr+vloMbsYO92jFl1rUXz9fz1R+75S76HjtVMMyU6UKn4mCn/kf/c6pXn0waZ5xuVLFjxywqc+2AxJBz20ugl18fNst1bNtHirlE1HXsTfwYo4Zmfo4JFoIPcj+/2393t1l/XH6KfIyHVO9dquSp1rv53eFBlo/LT6/n63l8NWko38uX6vfDooTcaLu5fzEubIkx34zkZNjly7tg6aUbodNtTX3gssha98rS5GodiqllZ3SXxDQrn53+9S17lryRImr4MyA8Uulp74ullSnvibFSN+m1xCa/WeamxKFlH+Byveh1XHwPIOUrBOKub/eFR8By7U58DqzI7vFDd9MNh/Ku5dWv1vvtH282o1lWqWOPZVWzODL27/av4nfQHQ13CVOPu3Zf5qtXXx/O4z469klEH/Pkjvl9EYJ2vNu8G/b7iZa4XLVt2b3b/H10FjLRmmO+K9jzZtstlnfDhdN0m055J9sV8tELnpkNGawBy717PCwGGWyBTwmT/f6rjbVGXViwOs/SB9myavJcEGjN8ZXTrw/bbrcbbk1NsMnLXNWy5Xpxsz7L3mVZRjPXtOzzfFdsGM1bty1Xi9L6Gme9godZHHHfreMvAWIHO+WtXVsnwdmVdc452aZgH/Qw3+6iWMXa5VKl9j429SES6COfy+Xu5dOMWcXuS5JQ5t1+sVp+uFRmlyq1zBaGHTKk9bm98FGurNL2ZYC2LLqPy3W3uFnfjgt6yRqSb5o94lz9L1/9+PzXn969v3338qebH96/ef7u396/+unV61c/v7s9Gfdlvl3OP4TbISZkmqVBP3ncLy+GpIc0qT7ycbO9n+/fbHbLfdIgaGWPM2WV1NoPLdl295sv3W23il+IcrbinKGSBctdhnaXuKrm53d33S6hRx7od1nqWWH98PXj3r7K5h7sS7cHZK5k2d1mteru9kfZqXVEs1Wy5r6Xd1ivSDVllKdae73ZLu+X++WX7ic7wK6S24pmrGTR+vBm9/Nt9+q/H5ONGeWpZMfuFKVkGuNnrOvBPy671SLTfV2eSnZ8fBw/sXaho3/MemItrQ5ebNaLZcFnfM5Xy0u2dzfrjxvv/rgLLjLONcUWCmhtR9UtXq3GEwaKaM+2jDNMMWW028CV8DZ6lPxsxDn5FAPyIWzQgkz0erJmICeydaTIIpevpiWf5xfXVKElLl9NSxbdqovuLQwbc8pa055+xajIoHPeqRahAH47X+8+xme2fZLk7WrvqEwri+5iOol9F5aPS3kUH7rVYYL6bwaZU+04SbhQ1RemSTkzpMf1tpvffT7MA6MjhJU5SJxaxeHx6fN8d/v4YbHcxgdKV5hT2ul677vtp+62u7A45MLaY9LpWg8Tmv3t44ddt/8lPgk7zX9OyStoP6TZdXf7tHKPkleq8Z+Wu+Qqt2lr1PlBUE6lD9NXrPXEso/TV6r31/OH1Go/JK1R66/nDzmVPkhesc7Tyj1KXqgd9dCHw0LL9acYZzomyVrjve2+HI70/BEt2UnyKEtq6U6m41lFLy1pWnEyhOaqY8v9/Pfu5ebu17c/pVlxTj9B//ASL9IW9Aaak+IKTZB65Q/WmXrpj5cbW/DTL//INcBlqaT/9auXN7++zjXhlKuSFf9287d/y7Whz1PJghdvb97dvHj+U64Vg3xTLBkAhx+e3756//KXF++HHyMCDCd5wxxTvovBzP71crdfHmDWP1y6yBzpZAbNM8EU8sLA77FJY1z/N33u5MbxSj5l5eGCbXnLDykmjm6JXnSHg9Kb7U1sKeKCiSMZ1S2835V71jcuc3WbVpu7cptc5uo27ej4mG3YQEIN68gDRbePD3ZrRDfB04iUKlYO+pDBpa/HAPLwx8TNT/vNZrX7bvF4//AcnLqxv77vf03e4P+SSDvW2Fjay6DUQbWMzcvvscIqk/qokfpj9mE9as7kCPHPH1f7Xx7Ga/sJxng5C+0ZbZx99K8wiJjgklfQ+6nbv+x2d9vlwwioJ5jg5axjjavVgeSspgkJKLNt1Ptt8q3ZAP1Z94dkGXi3/5r1SdnknmFFdpBPa+l3wBFDlot6dtCI7ZfH/cNjTuf2zSjXlZoN9egvPvpHt85mvviYfmTrJZHmF/og7WVQKizIQeCUHp2qzOzRB9kr9OieMdk9esCe9B7dMyGtR0/Qm9yjeyZk9+hp1mT16Miooh4d25bZo3vWVOzREwyM9+j+J1XUoyd9WtEe3TOkqEdPcKakHt2zpm6PHjAT9ej4PO7A0ryjuC99maD0TubLmHhcLnpKsaCPh7pze3oqpEZ/jw3L7/VjtmX0/dicxBEg1Yb0cQCbkz8aZFiWNyYEDSwbGSJ25o4P2LKao0SqsRfGisCnWTZipH+i8XEDG1U2eqQ6X9oYgi2rPJLETAbjyc39w2YLrtM7m92nyBpRqFS/Mo5SX0Y1wCIehU8ZVULqM8cVIKbCyBI0LntsuWBf+ugSNCltfMmwI3mECZqUPcbkWZc1ysSMLBpn4rZmjjRB6yqONRkGx0eb8CdbNN5kfbrRESdoWNGYk+GMSaNO0Lq6484Fs8cjDx5tsnjF4X8Dg9bhf5OPfi3Xix8el6v9zfrdUOJ5h8hAJkmcMl5ZM0MHE5+vVu9G1QG1DhJO0/h5vksu6jjt1JKuDwdfO1uEf+tWD6+73W7+Ce0kHRUb5yqwhR4xOIgcHQBxhwsGyo8pCpSN7rka1vP40zypKVCRF+6MNWUEOKeMZQMM0ZsypBTYEB4zaLnJKJGmK3UcIMqWYcybrCspXCR6swJEaENaSEjUXg4CL+q6OJYRlYmjV4ElSQEosSYr5EyxIDnI9A3JDiuhPSdjvnTbw7UQ347u6T8OuP2P7w8/RofcwSaw1ze3727e//3V29ubX87PAp53gY1kjhLHu8qRoVDzu+cv3qUqHqYt0uvVYKjyovUmWSvF7NwpvNwu0W3bd6ula//T79jWu9UyItzdAu7t2fWUeOmmKHv1dbl/sVn4t1h76gYpSxTu5l+6t72oH5fDG5o9jShpiUq7f8cJ+uXfw+poshJV/Q4h0oV6qmiyiaX6R2gDOyrbIPFEta9Gb2DEdL6KvpsXV3joEi/V5yjNxFK9Q1MaVKg+4UR1SaoK1bjMb7vDPDCsh6QqbaMAEhu10YW7Q+NKXvYbRS8p8tKVKHPe9KO9XSSsiqQqUXS5453Y4d6+e/nLr+/sjTBhHeNEJWpe/HRDY2RPyyhNiZK71fIYV9kIO6ILJZ2kMkXX7ltWqmbbzfed/eRfbO7v54Nr0X11KG3R4P+4TtPoJyxR133t7h57w8O6SKoSRZ/n68WqS+pkUdISlUt0lHrRfe0norHd94vuayxeCj3schJ+SlGm4FCuiHT3c5loPMcASmjCMnVwYgG0kXRlygarkMcBJ6YTJy9T7ZYij2LQscWTWj9pscpX68P8bJGqFiQvU31eA02pZ5i6TPExUP6h+zz/soyrBWnLlB6tHi2MAoUk3TRlo1c4Isr6dNOUpSgqVvL89l2KnnGywvLM9/OPq80/k8rlpy1T2r/kkqLTT1qmknxO0e8epC2s3MA5mGGdnpKUq0Abs4kKl2SCitDLHWMtlx5VSB6M4PQVD0TRCWzaIDQGZ8EB6Jhs6ghwqXBeytKyXUBlsKDBPIXRDMVjKJI5pylXcklBsXB8CQLQQhMWRsqh2w5QzOynLVMKrjUA6kapCnv+hHqcXIXwZDjq58fpCmcHoRPgaILgpy3utqys5+v1xl2DeaH38lNPKG2a1loqb3998+btq9vb96+fv/33V2+jnuMlLexPwveKnfuUy3dtxZWg6/uBnnGywoE1eDc/GlpB4vLxHN9vHxjRaeLigTZZK0hbWsX4ynxYwTTppFb178MPN+owbXk5wWX3gWKOUhaXEt2njcs4TlmmEFybDZSNUpUpIrdjowW3XQUF5BLsoJpTumJlsbuusVqco3AFMHSlNVoO9NMWBk7w5moUO5GEpZUcvKAaVjBIXaYY30MNdNKEhUFw+LppFAaj1JOciNwqHfagU8LCzo1cHo16tVOSSSUCd0SHSzVKXNiCgaugUfN5SQtjU3zZMwpNacrCyNS/1hkFpcNUhaEifeEMxYnnNOVKyPNlATWnVOWKvLfJAqoG6SYp8x8eCyscpi2enoF3YvDMbJSwTF3oKRig0E9auCaY8toLWiWM5yucrgVfAEbzNpB4wsIQegEptDY0Tlum9KfNp5+6L110PBykKVbyY7+N/oKeQbJiVRca7JSiTMH/e1x2+8taxslK2dCHx0+XVY2TFa9Q3HWXVY2Tlan6v5vl+ra7X67m+/3yLtqB+kkLR/Ku2yeq9JOWLkwmqaujap9RpzB1seKMmoWpyxTvt3+83kVjwFOKQgWft5t//sdmgfdyDvWQhOUDzquvd93DpR6SJixTd9Nf5pekEiUuU/vKbmFabtZJemHqSVsWjtccXlAMU09Y3b6MOsfJJqh6tf5yUY9LM608++5rfD40Tlc40bT7+W7QAv3xZsvl9v2Hx+Vq0W2Pp23PeUJKj/dYLrffHfNe+DJv3v7gEuZYQjPWM+f57bvb/WbbFRrlZ69jmn3avlt0h0W/+OvEy/Ob4STHZUsuTJIe77LUj9JPUv5q8am7WXxNUHtOOUnhD/Pd8u6H1ebu9zS1NP0k5S9+/Fua1lPCyZWbWLP1qjWw+ytcrxe2gWWqz1I9Ve1x1pVYZpJ8qiul+dFURc93+5t9d/9mvp3fp3QPNP0k5cOON0E3ST5Jtbvv4OfNIrF/oukrKE/vHGn6Csp/mq8/PeJdSlj7IEMF9S+X2y608IH1D3NUavmsZq/X5lkNXkft37bzB7RCivUeU0/rwTZru6MicUQcpZ6o+P7hMJVebta/rpcoIPeV0xxVSp5R7Kkq++XOAOSiWsepqwyRiZpJ8irVnKiaJJ+kOmkOVjD1qjLjKp1oVZxfTZtWTVokPRrRp8hdMD1acUw5ZfEUmpK+1pduSoEZ9U1IWGwNWJKx8JplUGELZS3IphtkFwy/wB0W0IxB+nrKf8qrCj/bdFOW6/3Pj/epFrjUkYOyOaofbtZoHxhUfEhbSe19htr7emozatklreJmGVpPqacrfpNRxX3aCiNAhtLXtZT2B7VuQwd9j9rdOd/R4a7bS0d/j1b0Z4QvGvF6/vCQa8QpTwUjsqqgVtn/sdn+vjo8Jpuj3ss02Yzn6/nqj91yd2FtamgEyVKpAdxB+NjSkd8O5zyTjYhv7z+acHj0PGef/1H9Id/EDf++CTk7/1MNSTgCAAzJOAuQaEjCoQDfjozTAckNc+mYAGqW1PMCed4ROzgQdI6UEwQZdRE9SoCrIulMQXpNxA8XwHpIO2WQaEL0uIGvPuncQaLq4AEEX+3FkwhZKoNHEkKKL55NSFefdkgBGpJ3WiHRpIRjC74xGecXEs24dJDBtyH1RENy0yQcbUDNknHGIdGUS4cdfCtSTz0kGpB0/MG3IuscRJ57Bg9EBH3z4smI1C46eEQC9M0Xz0rklTp6aCJY8qTTE6mecPEYBXCD5PMUiUZcPFjh25B8wiLRhOhRC1990pmLRNWRwxcgir98CiNDbfA4BlZ88VxGhurIAQ2sPOGkRp762JGNoAkpZzcSzbh0iMO3IfU0R6IBl491+Cakn+9INCLzoIdvUeGJj0TzUo5++DblnAFJNCThMIhvR8apkNTmir283TfIhRuH3KMacRXBp2DPKmI3DiWpiLxNONAS34V7SdGlG4cG2lJvHLqkMnbj0EBdyo1Dl1RduHFooC3xxqHLZUu8cWhU0Mwbhy4ZEbxxaKD04o1DKUouKSgWHr9wcnjTe+KVk8dL4yPliV06OdKYdO3kSeF/Pu33jX//r9Mfv3/Cn4ln7ZOnTz66OcL3vzkznj6529z38eJic/do//mffbK/93exff+bS/3d7MnT32ZPtX5mFP/P/3z62zGz/cH+4Sjj/BebkT15+ht7qtkzLccZmZeRjTLyJ09/4ygj9zLyUUbx5OlvAmUUXkYxyiifPP1NoozSyyhHGdWTp78pVDnKy6hGGfWTp79ppFF7GfUoo3ny9DeDNBovoxllbJ48/a15KuSzho8zNl7GZpSxffL0t/apap5xo0cZWy9jO3aAgz+w2VOlnhlNXMB3Hka8x7oP9h/gQGMPYge/YNCHmO9EbOxF7OAbTKA6Zr4jsbEnsYN/MAkz+87Ext7EDj7CFDTbdyg29ih28BOmYW37TsXGXsUOvsKgXzHfsdjYs9jBX1gDM/vOxcbexQ4+w1qY2XcwNvYwfvAZPoN9he9hfOxh/OAznCHN3PcwTvoo20nhXgp0U2MP4wef4QI1Ffc9jI89jMvgV8V9D+NjD+Mq+FVx38P42MP4wWc49G3uexgfexg3QffkvofxsYfxg89w2NFy38P42MP4wWc47Gy572F87GHCehj8MITvYWLsYcJ6WANHJN/DxNjDhPWwFmb2PUyQkdAOhXDYFmAwHHuYOPiMgB+G8D1MjD1MhPsw4XuYGHuYOPiM4FCz72Fi7GHCBDt94XuYGHuYOPiMgJ2+8D1MjD1MHHxGwABC+B4mxh4mDz4joG9L38Pk2MPkwWeEhpl9D5NjD5MHnxEGxj2+h8mxh8lwHyZ9D5Mk3rIeBkcMCUKusYfJg88I+GFI38Pk2MPkwWckHDGk72Fy7GHy4DMS9p7S9zA59jB58BkJ3VP6HibHHiYPPiPFU2me8WYchUnfw+TYw9TBZ6R8KsQz05Aw1fcwNfYwdfAZCb9n5XuYGnuY4kGzle9hauxh6uAzUj9V4plRcpzZ9zA19jBlQ3qDwlble5giUf3BZyTstxUI7McepnS4zL6HqbGHKRNuKt/D1NjDVBMus+9hauxhynoY/KqU72Fq7GF6Fiyz9j1Mjz1Ms2CZte9heuxh+uAzavZU8WezRowz+x6mxx6mDz6j4PesfQ/TYw/TMlxm38P02MO0nThy1Htq38M0mTvq4IehwfRx7GH64DMKzpK172F67GH64DMKDnTa9zA99jAd7sO072F67GEm3IcZ38PM2MMMC5bZ+B5mxh5mrIfBDtD4HmbGHmash8HY0/geZsYeZg4+o/Bk3/cwM/YwYz0M9mHG9zAz9jBz8BkFOwPje5ghKxQHn9HwkzRgkWLsYebgMxp+ksb3MDP2MHPwGQ3DR+N7mBl7WDMLlrnxPawZe1jDgrObxvewZuxhzcFnNHTPxvewZuxhzcFnNJyUNb6HNWMPa8KjZON7WDP2sObgMxoGro3vYc3Ywxq7AAY/jMb3sGbsYY0JZ/Y9rCHrYNbD4FfVgKWwsYc11sNg4Nr4HtaMPaw9+Ixun/L2mZ6NP4zW97B27GHtwWfM7KlQz3Qzzus7WDt2sPbgMoY9FfqZZu04s+9g7djBWhHseVvfwdqxg7UytOrY+v7Vjv2rPXiM4TCz71/t2L/ag8cYAYvs+1c79q/WLrJKmNn3r3bsX+3BY4yCmX3/asla68FjjIaZwXIrXW89uIzBq3gztOJKllxn1sfwQt4MLLrOyKrrjAcd3P1G85OF15kI+bj7iWYnS68zGXRz9xvNT1ZfZyro6e43mp8swM50yNndTzQ7WYKdmaC/u99ofrIKO2uCLu9+o/nJQuysDXq9+43mJ95nF/Cx4zO03u8t+LOg7zO45E+8zy7jG7ySjFb96bK/Xclv4JoZQwv/dOXfLuYHvB+t/dPFf7uej70frf7T5X+7oh/wfgQAKAFg4aknQwyAQgAWBEwMUQCKAezKfsD7EQggJIDZxf2A9wMWwAgMYHZ9P+D9AAcwwgOYXeIPeD8gAowgAWZX+QPeD6AAI1SA2YX+Bi7aMsAFGAEDzK71NzB2ZgANMMIGmF3uD3g/oAOM4AFmV/yx9wM+wAggYHbNP+D9ABEwwgiYXfYPeD+gBIxgAmZX/rH3A07ACChgdu0/4P0AFTDCCphd/g94P6AFjOACZglAwPsBMGCEGDALAQLeD5gBI9CAWQ4Q8H6ADRjhBsyigCbAbIH3EXTALA1oMLYF8IAResAsEAh4P+AHjAAEZpkA9n5AEBhBCMxSgYD3A4jACEVgMrwExwBHYAQkMMsGsPcDksAISmCWDgS8H8AERmgCs4Ag4P2AJzACFJhlBAHvB0iBEabALCYIeD+gCoxgBWZJQcD7AVhghCwwCwsaOBNngC0wAheY5QUNpEgM4AVG+AJT4YktA4SBEcTAVHBuywBjYAQyMBWe3jKAGRjhDEyFZ7gMkAZGUAOz9KAxcOcFgA2M0AZmAULT4Pxo3wdxPxWedwDiwAhyYCoy7wDQgRHqwFRk3gG4AyPgganIvAOgB0bYA9OReQegD4zgB6Yj8w4AIBghEMxChQbPOwCDYARCMMsVWjzvABiCEQ7BdGTeAUgEIyiC6fC8A7AIRmAE05F5B8ARjPAIpiPzDkAkGEESTIfnHYBJMAIlmI7MOwCWYIRLMBOZdwAywQiaYCYy7wBwghE6wUxk3gH4BCOAgpnIvAMgCkYYBbPYocXzDkApGMEUzJKHFs87AKhghFQwE5l3AFbBCKxgJjzvALSCEVzBTGTeAYAFI8SCmci8AzALRqAFa8LzDkAtGMEWrInMOwC4YIRcsCYy7wDsghF4wZrIvAPgC0b4BWsi8w5AMBhBGKyJzDsAxGCEYjALJlo87wAcgxGQwSybaPG8A6AMRlgGayLzDkAzGMEZrAnPOwDPYARosDYy7wBIgxGmwdrIvANgDUa4BmvD8w4ANhghG6yNzDsA22AEbrA2Mu8AfIMRwMHayLwDIA5GGAdrI/MOQDkYwRysjcw7AOhghHQwCy9aPO8ArIMR2MEsv2jxvAPgDkZ4B5+F5x0c8A5OeAefBecdHOAOTnAHn4XnHRzgDk5wB5+F5x0c8A5OeAefBeEaB7iDE9zBZ2G+xgHu4AR38FkYsXHAOzjhHXwWpmwc8A5OeAefhUEbB7yDE97BZ2HWxgHv4IR3cMsvWkjbOOAdnPAObvlFC2kbB7yDE97BWZi2ccA7OOEdnAVpGwe4gxPcwVmYtnGAOzjBHZyFaRsHvIMT3sFZcNbLAe7gBHdwFp71coA7OMEdnIVnvRzwDk54B2fhWS8HvIPTkw88POvl6OwDPfzAw7Nejo4/eOcfDt7UwlkvhycgiPdZfsFmcNrL0SkIegyCh6e9HB2EoCcheHDay9FRCHoWgoenvRydhqDHIXh42svRgQh6IoIHp70cHYmgZyJ4eNrL0akIwju4CE97OQAenAAPLsLTXg6AByfAg4vwtJcD4MEJ8OAiPO3lAHhwAjy4cKdw8OkhQDw4IR7cnZOYwYkvB8iDE+TBRXjiywHy4AR5cBGc+HJAPDghHlyEJ74cEA9OiAd3xCPgQMABCfLg0h0uhFMvDpgHJ8yDW4bBZvg4E4AenEAPbikGm+FTSQB7cII9uHRdIIx/OeAenHAPLp0T4hAEgA9OwAeXkTEYgA9OwAeX4TEYcA9OuAeXkTEYcA9OuAe3HCPQiQDuwQn34JZjBDoRwD044R7ccoxAJwK4ByfcgyvngjgEBOSDE/LBlXNBPAoD9MEJ+uAWZQQ6EYA+OEEf3KIM3IkA8sEJ+eCWZAQ6EUA+OCEf3J21wP4L0Acn6INblIH9F5APTsgHd+QD+y8gH5yQD64ifSAgH5yQD+7IB/Z/QD44IR/ckQ/s/4B8cEI+uCUZAf8H5IMT8sEtyWAMx4AAfXCCPrhFGYzhURiwD07YB7cwI+D/AH5wAj+4gx/Q/wH74IR9cMsyAv4P2Acn7INbmBHwfwA/OIEf3MIM7P+AfXDCPrhjH9j/AfvghH1wxz6w/wP2wQn74I59YP8H7IMT9sEd+8D+D9gHJ+yDW5YR8H/APjhhH9y409g4BgTwgxP4wS3MYPiuAg7oByf0g7uzGtj/Af7gBH9whz+g/wP6wQn94JZmBPwf0A9O6AdvwqeCOMAfnOAPbnEG9n9APzihH9zRD+z/gH5wQj+4ox/Y/wH94IR+cEc/sP8D+sEJ/eCOfmD/B/SDE/rBLc0I+D+gH5zQD25pBsO3ZXCAPzjBH9ziDMYCFwOgmwGIA7rzHNj/AQDhBIBwB0Cg/wP+wQn/4G2kAwT8gxP+wSMHOzgAIJwAEN66AThwNwLwQEJAeOsGYHiGnAMEwgkC4a3rAuE5NQ4YCCcMhLeREBAwEE4YCLdMA2/e4YCBcMJAuGUaePMOBwyEEwbC2/AQDBAIJwhEzMJDsAAIRBAEImbhdRgBGIggDETMwuswAjAQQRiImIXXYQRgIIIwEDFzDghnQAJQEEEoiLBUg3F8VQbAIIJgEDELr8MIgEEEwSBiFlyHEYCCCEJBxCy8DiMABRGEgohZeAOCABREEAoiWHADggAQRBAIIlh4A4IAEEQQCCJYeAOCABBEEAgiWHgDggAURBAKIlh4A4IAFEQQCiJYeAOCABREEAoi3K1P+BYjATiIIBxEuJufOL5zBYAQQUCIYOEtCAKAEEFAiGDBLQgCcBBBOIjg4S0IAnAQQTiI4OEtCAJwEEE4iODBLQgCYBBBMIjg4S0IAlAQQSiI4OEtCAJQEEEoiODhLQgCYBBBMIjg4S0IAmAQQTCI4OEtCAJgEEEwiLBcg3F8cQ8AIYKAEGHBBsO3WglAQgS9IEqENyEIdEUUvSNKBDchCHRJFL0lSoRDQIHuifIuigpvQhDwqijigCK4CUGgy6LobVEivAlBoPui6IVRIrwJQaAro+idUSK8CUGgW6PotVEivAlBoIuj6M1RIrwJQaC7owgGEQ6D4KvRBMAggmAQ4TAIhxBCAAwiCAYRMrwNQQAKIggFETK4DUEABiIIAxEyvA1BAAQiCAIREQQiAAIRBIGIMAIRAIEIgkBEBIEIgEAEQSBChrchCIBABEEgQoa3IQiAQARBIEKFtyEIgEAEQSBChbchCEBABCEgwhGQwAV9gIAIQkCEJRqMQwYjAAIRBIEIFd6HIAADEYSBCBXchyAAAhEEgQgV3ocgAAIRBIGIyI1TAjAQQRiIsEwDz58FYCCCMBBhmQaePwvAQARhIEKH5x8AgQiCQISOzD8AAhEEgQgdmX8ABCIIAhE6Mv8ABEQQAiJ0ZP4BAIggAEToyPwDABBBAIjQbv6B598AgQiCQIRFGixwVSVgIIIwEKEj8w/AQARhIEKH5x+AgQjCQISJzD8AAxGEgQgTmX8ABiIIAxEmPP8ACEQQBCJMZP4BEIggCESYyPwDIBBBEIgwkfkHICCCEBBhIvMPAEAEASDCROYfAIAIAkCEJRoscFkqQCCCIBBhkQYL3HkKGIggDEQ0kfkHYCCCMBDRhOcfgIEIwkBEE5l/AAYiCAMRTWT+ARiIIAxENOH5B0AggiAQ0UTmHwCBCIJARBOZfwAEIggCEU1k/gEIiCAERDSR+QcAIIIAENFE5h8AgAgCQIQlGixwcS5AIIIgEGGRBhN4/g0YiCAMRLSR+QdgIIIwENGG5x+AgAhCQEQbmX8AACIIABFtZP4B+Icg/EO04fkHwB+C4A/RRuYfAH8Igj9EG5l/APwhCP4QbWT+AfiHIPxDzsLzDwn4hyT8Q87C8w8J+Ick/ENansFC1zeDW5QJAJEz99oAvsIZEBBJCIichecfEgAQSQCInAXnHxLgD0nwh5yF5x8S4A9J8IechecfEvAPSfiHnAX3QUuAPyTBH3IW3gctAf6QBH9IFt4HLQH/kIR/SBbmbxLwD0n4h2Rh/iYB/5CEf0gW5m8S8A9J+Id0710IOP+WAIBIAkCke/NCQAAsAQGRhIBIR0AC94EDAiIJAZGOgATuBAcERBICIt37F4F7wQECkQSBSPcGRuBucABBJIEg0kINJuEVohJQEEkoiLRUg0n8Bg7AIJJgEGm5BpMKXSUqAQiRBIRIHt6JKgEIkQSESB6MAyXgIJJwEMnDcaAEHEQSDiJ5eBuCBBxEEg4iw9dfSYBBJMEgkoeHYQkoiCQURPLwMCwBBJEEgkgRngVLAEEkgSBShHeiSkBBJKEgUoR3okpAQSShINJSDSbhRhgJMIgkGESKyCgMOIgkHESKcBgoAQeRhINIEQwDJcAgkmAQKcJhoAQYRBIMIkVwH6AEFEQSCiIjh0EkoCCSPqEhwxuhJXpEg76iYZlGwH3ROxr0IQ0ZGYXRUxr0LQ0ZGYXRaxrecxp2FJb4KQ/4ogZxPxneBy3Roxr0VQ0Z6f7Quxr0YQ0Z3Igv0csa9GkNGd6IL9HjGvR1DRlcA5ToeQ0CQaSKBIEAgkgCQaSKBIEAgkgCQWTkAiwJGIgkDESq8D5oCRCIJAhEqvA+aAkQiCQIRFqmwfCDGxJAEEkgiFThPVgSQBBJIIiMQBAJIIgkEERGIIgEEEQSCCIjEEQCCCIJBJFhCCIBBJEEgsgIBJEAgkgCQaSDIPDzAQxEEgYidXgbtAQMRBIGInV4G7QEDEQSBiJ1+BSSBAxEEgYidXgNWgIEIgkCkTq8Bi0BAZGEgEjt5h94BgQQiCQIRFqmwRRkMBJAEEkgiLRQgym4Ci4BBZGEgkhLNZjCMyCAQSTBINJyDYbf+JAAhEgCQqQFG4EXlgAIkQSESAs2Al0IACGSgBDp7sGC0yfAQSThINKdBMFPs0gAQiQBIdKCDabwQhYgIZKQEOlICH7rRAISIgkJkSb8PowEIEQSECKbWWQKCkiIJCREukc88IMrErAQSViIbJwT4nfNAAyRBIZICzeYgjRVAhoiCQ2RFm8wjdcyAA+RhIfIJhIIAh4iCQ+R7kIs3ATACwkOke5ECHzcUgIcIgkOke5AiMYdEeAhkvAQafkGw2/ISABEJAEi0vIN/NqkBDxEEh4iLd7Ab0ZKgEMkwSHS4g38bKQEOEQSHCLdkRANgY4EQEQSICLdkRD8Io0EREQSIiLdkRANX1ySAIlIgkSkZRxM4yV1AEUkgSLSQg6G34iRgIpIQkVkG96TIAEVkYSKyNZ5Ie5IABaRBIsoizmYxs+5AS6iCBdRlnPgEijARRThIspxETODj9EBLqIIF1EWc+A3NRXAIopgEeUOhhjYEyjARRThIsodDDGwJ1CAjChCRpQlHczAkEQBNKIIGlEWdTATqAPfDRVhI8rCDmbw442AjihCR5SlHczop2r2THt14PuhInhEuSfA8ZM0CvARRfiIcs+A4zdpFAAkigAS5Z4CN/hLAIREEUKi3HPggToAiEQRRKIcImngmKwAIlEEkSiHSEIWAE8kiEQ5RIIfh1AAkSiCSJRDJA0MzxVAJIogEtU/EY6/BYBIFEEkioUPaipASBQhJMoREnzDvwKERBFCohwhwZesK0BIFCEkyhESfMu6AoREEUKi3I1ZDf6WACJRBJEo93J4g78lAEkUgSTKvR6Or7pWgJIoQkmUpR4M33WtACZRBJMo94o4vm5YAVCiCChR7rwIvm9YAVKiCClR7rwIvvJVAVSiCCpRFn0wfOerAqxEEVaiLPtg+NpNBWCJIrBEWfjB8L2bCtASRWiJcrQEX32oAC1RhJYod3sWvvtQAVyiCC5R7vYsfP2cArxEEV6iLADh+Po5BYiJIsREWQLCZxD6KoBMFEEmyjIQji8AUwCaKAJNlIUgHN+ApQA1UYSaKEtBOL4BSwFsogg2URaDcHwDlgLcRBFuoiwH4fgGLAXAiSLgRLlXyPENWAqQE0XIibIghOMrmBQgJ4qQE2VJCMdXMCmAThRBJ8qiEI4vwVGAnSjCTpSFIRxfgqMAPVGEnihLQzi+hkQBfKIIPlGWh3B8DYkCAEXRB8otEOH4IgiF3iinj5RbIsLxRRAKvVNOHyq3SIQz7InorXL6WLllIpxhT0TvldMHyy0U4Qx7Inqz3Hu03HoiPgqv4LvlxBMtFeH4KLxCb5fTx8stFuH4MLJC75fTB8wtF+H4MLJCb5jTR8wtGOH4OKhC75gTkqIsGuH4OKgCLEURlqIsG+H4QJ4CMEURmKIsHeFcw5kzwCmK4BSlYxMWwFMU4SnK8hHO8UPyAKgoAlSUBSQcn6lSgKgoQlSUdp6IXRkgFUWQinKnSkJ1ADyRMBWlm1gdAE8kTEVZRMLxuRYFmIoiTEVZRMLxyQIFmIoiTEVZRMLxyQIFmIoiTEVZRMLx3m4FmIoiTEVZRsKFhJUIoIoiUEVZSMIFXNJXgKooQlWUiU2dAVdRhKsooyN+ALiKIlxFWUzC8f5eBbiKIlxFWUzC8Q5LBbiKIlxFGeeJ+GsEYEURsKIa54lwVV8BsKIIWFGWk3CJFwMBWFEErCjLSTjeYakAWFEErCjLSTjeYakAWFEErCjLSTjeYakAWFEErCgLSjjeYakAWVGErKgmvMdBAbSiCFpRFpXwAx7jz2YNFQAckbAVZVEJx3vkFGArirAVZVEJx7uUFGArirAV5dgK3ieiAFxRBK4oB1cwKVeArihCV1TksIkCdEURuqJaEWkEQFcUoSvKwhKOUb0CdEURuqIi500UgCuKwBVlWQnHqF8BuKIIXFGWlXCFhyUAVxSBK8rCEq7wsAToiiJ0RVlYwjErV4CuKEJXtIUlXMF1dQ3oiiZ0RUfoigZ0RRO6omc87EYa0BVN6Iq2tERxxFk1oCua0BXtnlqHO4Y0gCuawBUdeWpdA7aiCVvRM+eFsC/SgK1owlb0zHkh7Is0YCuasBU9c14I+yIN2IombEXPnBfCvkgDtqIJW9HMkWbYFWjAVjRhK9qiEo5huQZsRRO2ohkPj+sasBVN2IpmIhxZaMBWNGEr2qISruG4rgFb0YStaItKuIbjugZsRRO2oi0q4Rh3a8BWNGEr2qISruGEUQO2oglb0RaVcI2/BcBWNGEr2rISrvG3AOCKJnBFc+eJ+FsAcEUTuKK580T8LQC4oglc0ZaVcAMZmwZwRRO4oiPHTzRgK5qwFc1lpEcGbEUTtqItKgn0yACtaIJWNI/1iACtaIJWtCUlHANzDdCKJmhFW1LCMTDXAK1oglY0b8NL6hqgFU3QirakhBsYGWiAVjRBK9qSEm7wxwzQiiZoRQvnhzgyAGhFE7SiRcQPAVnRhKxoEfNDQFY0IStaqHCUrwFZ0YSsaEdWcJSvAVnRhKxoR1ZMwALgiISsaEdWTMAC4IiErGgRhs0agBVNwIp2YCUQXACwoglY0Q6sBIILAFY0ASvagRW8bUIDsKIJWNEOrATGRQBWNAEr2oEVA5fwNAArmoAV7cAK3jahAVjRBKxoB1bwrgcNwIomYEU7sNLgDg2AFU3AinZgpcH9EQArmoAV7cAK3rWgAVjRBKxoB1bwrgUNwIomYEU7sIJ3LWgAVjQBK9qBFbxrQQOwoglY0Q6s4F0LGoAVTcCKdmAF71rQAKxoAla0Ayt414IGYEUTsKIdWMG7FjQAK5qAFe3ACt61oAFY0QSsaAdWWvw5A7CiCVjRDqy0cM6sAVjRBKxoHb6mRgOuoglX0RaTSP1UiWdGSZIf+CHBKtphFbxrQgOsoglW0VpE+iOAVTTBKtphFbztQgOsoglW0Q6r4G0XGmAVTbCKdlgFb7vQAKtoglW0dn6IPyWAVTTBKtpSEoG3XWiAVTTBKtpSEoHfXdMAq2iCVbSlJAJvu9AAq2iCVbTDKoEpJ8AqmmAVbSmJmOFvEWAVTbCKNpEYEVAVTaiKNrEYEVAVTaiKNpG5CoAqmkAVbRmJwBtPNIAqmkAV7aBKYO0EQBVNoIo2zg9xbwCgiiZQRbvDKrg7AkxFE6aiG+eGOMgFTEUTpqItIhEzHGMCpqIJU9GNc0PcGQCmoglT0RaRiFkL3QAwFU2YiraIRBxOe4BKBExFE6aiLSIRjGELgCMSpqItIxGMP5XtM6ofuCFBKtoSEsEE1g/ckCAVbQmJYBLXAHBDglS0JSSCKWwB8EOCVLQlJLgGAFDRBKhoy0cE01A/ACqaABVtAYlg8OisBkRFE6Ki20hnCICKJkBFtzLiQwCoaAJUdKsiXgyIiiZERbdhJwQ8RROeolvnhPDwsAY8RROeoiOHVTTAKZrgFN3GfBDgFE1wipnNwl+BATjFEJxiZixUgwbQFENoipk5H4SjiQE0xRCaYtxZFbxxygCcYghOMRaPCA5XvgzgKYbwFGP5iOAwKDEAqBgCVIzlIwJvnDIAqBgCVIzlIwJvnDIAqBgCVMysCX9HBgAVQ4CKmbUxN/L90BCgYiwfEXjrlgFAxRCgYiwfEXjrlgFAxRCgYiwfEfg2awOAiiFAxTDniXBQNwCoGAJUDHOeCCN8A4CKIUDFWD4i8L4nA4CKIUDFWD4i8L4nA4CKIUDFWD4i8L4nA4CKIUDFWD4i8L4nA4CKIUDFWD4i8J2WBgAVQ4CKsXxE4FsFDQAqhgAVY/mIwLuODAAqhgAVY/mIwLuODAAqhgAVYwGJwLuODCAqhhAVYwGJENgTAVExhKgYS0iExJ4IkIohSMVYQiIk9kSAVAxBKsYSEiGxJwKkYghSMZaQCIk9ESAVQ5CKsYRESOyJAKkYglSMJSRCYk8ESMUQpGIsIRESeyJAKoYgFSPCW24MICqGEBUj3EFS7MkAqRiCVIwlJELCAMsApGIIUjHCOSKcKBmAVAxBKsYSEqHgsXgDkIohSMUIExmYAFIxBKkY0cTqADgiQSrGIhK84cMApGIIUjGWkAi87cgApGIIUjGSRRoBIBVDkIqxhCRQAkBUDCEqxgKSUCMComIIUTEyfMOIAUDFEKBipIqEuQCoGAJUjNThCb8BQMUQoGKkiYR4AKgYAlSMbMKTNQOAiiFAxcg2OFMAOMUQnGLULDzhNwCnGIJTjGKRGBXgFENwilE8PNkyAKcYglOMpSO4BgBMMQSmGCXDE34DYIohMMUoFZ7wGwBTDIEpJnLXlwEsxRCWYpSJ+BBgKYawFKNiExXAUgxhKUaFnRCQFENIitGz8ITfAJRiCEoxOrz70ACUYghKMTrmgwClGIJSjBaRrwCgFENQitEyWIMApBgCUozlIgJvQTUApBgCUox2AzJcwjcApBgCUozlIkIFagA4IQEpxoEUpdDBBgNAiiEgxTiQouAKtgEgxRCQYiwXOQxnPkQwgKMYwlGMxSICb5IwgKMYwlGMxSL4vigDMIohGMUYEb6ixACOYghHMSZ856sBGMUQjGKMc0P8IQOOYghHMY6jBLwIcBRDOIoxJuJFgKMYwlGM4ygBLwIcxRCOYiwXCXkR8ELCUYzjKJgEGcBRDOEopol0hgCjGIJRjMMogUYEGMUQjGIcRgk0IsAohmAU4zBKoBEBRjEEoxiHUQKNCDCKIRjFWC4SaETAUQzhKMZxFHxrmQEcxRCOYprwErYBGMUQjGIcRgk1InBDglGMwyiBRgQgxRCQYhxICTQiACmGgBTjQEqgEQFIMQSkGAtGAo0IQIohIMU4kKLxGjYAKYaAFNOGr54zgKMYwlGM4yiBRgQkxRCSYtrYoAxIiiEkxbSxQRmgFENQimljgzJAKYaglGYWHpQbQFIaQlIaR1Lw9XcNYCkNYSmNYyn4+rgGsJSGsJTGsRQNNxo1gKU0hKU0kfdQGoBSGoJSGodS8H78BqCUhqCUxqEUfP1cA1BKQ1BK41AKvn6uASilISilcSgFXx/XAJTSEJTSOJSi4bmMBqCUhqCUxqEUHFs1AKU0BKU0DqXg3egNQCkNQSmNQykGErEGoJSGoJTG3fvF4A6NBqCUhqCUxt37xeAm3gaglIaglMbd+8VghNwAlNIQlNI4lIJvoGsASmkISmksGQl8S4CkNISkNI6khNwAOCIhKY0jKXhDfgNISkNISuNICt6Q3wCS0hCS0jiSgnejN4CkNISkNDy8ft0AkNIQkNI4kIKv0GsASGkISGkcSAk0AgApDQEpjQMpeDN5A0BKQ0BK40CKwd0JACkNASmNAykNRDkNACkNASmNAyl4L3gDQEpDQErjQAreC94AkNIQkNJYLoJnqw3gKA3hKI3jKA0eWAFHaQhHaSwXEXgveQNASkNASuNACt5L3gCQ0hCQ0jiQgveSNwCkNASkNA6k4L3kDQApDQEpjQMpeC95A0BKQ0BK40AK3kveAJDSEJDSOJDS4o8RgJSGgJTGghHRMiwAOCIhKY0jKS2HAgBJaQhJaRxJaQUWADyRkJTGkhGBb8BrAEppCEppHErBe7kbgFIaglIai0ZEC3lYA1hKQ1hK41hKC68FaQBLaQhLaRxLaRssAHgiYSmNYykt7lMBS2kIS2ksGpEz7ImApTSEpTQWjsgZ9kRAUxpCUxoLR+QMeyKgKQ2hKY2FIxLfgNcAmtIQmtJYOCJn8IKaBtCUhtCUxuIRifcRN4CnNISnNBaPyBn2RMBTGsJTGotH5Ax7IuApDeEpjeUjcoY9EQCVhgCVxj2egm/AawBQaQhQaSwfkQx7IgAqDQEqjSUkkmFPBEilIUilsYREMuyJAKk0BKk07nQKw30iYCoNYSqNRSSSYU8ETKUhTKWxiEQyeFVSA5hKQ5hKYyGJZNgTAVVpCFVpLCSRDHsioCoNoSqNhSSSYU8EVKUhVKWxkEQy3CcCqtIQqtJYSCI59kRAVRpCVRoLSSTHngioSkOoSmMpieTYEwFWaQhWadx78hx7IsAqDcEqjcMqHHsi4CoN4SqNe0mFY08EXKUhXKWJcJUGcJWGcJXGYhLJcZwJuEpDuEpjMYnE2zAbwFUawlUai0kk3obZAK7SEK7SGOeIuE8FXKUhXKXpH1PBMyYAVhoCVprGzVewJwOw0hCw0lhQEhQAHJGQlaZxfA9PuQBZaQhZadzT8ngfZwPISkPISmNBicT7OBtAVhpCVhoLSiTex9kAstIQstJYUiLxPs4GoJWGoJXGkhKJ93E2AK00BK00FpVIvI+zAWylIWylaZwnYlcGbKUhbKWxqETifZwNYCsNYSuNRSUS7+NsAFtpCFtpWrf1C3siYCsNYSuNZSUS7+NsAFxpCFxpWrf3C3sigCsNgStNf+0XXgcDdKUhdKWxsETieyEaQFcaQlcaC0skvheiAXSlIXSlcU/No1fmGsBWGsJWmp6tQDjTALbSELbSzpwfwi+hBXClJXClnTk/hF9CC+BKS+BKa1mJxJe/tQCutASutJaVSLyLsgVwpSVwpbWwROJ32lpAV1pCV1p38RfeOdMCutISutL2r6rAGz1bQFdaQlfaWXhNuwVwpSVwpbWsRCr4KbYArrQErrSWlUj80loL4EpL4ErrLv7CS9ItgCstgSute3QefUktQCstQSstc24IB6UWoJWWoJWWOTeEg1IL0EpL0ErLnBviTxGglZaglZY5N4QzhRaglZaglZaFdyG2gKy0hKy0lpRIDTcRtgCttASttJaUSM2wAOCGBK20zJ1g5lgAcEOCVlpLSqQWUABAKy1BK60lJRrC6haQlZaQldaSEvjqaQvASkvASms5Cb7DsAVcpSVcpbWYRGq4XaAFXKUlXKW1mERi0twCrtISrtK6R+c1nLK3gKu0hKu0PNIXAqzSEqzS8ibixQCrtASrtLyNeDHAKi3BKq3DKgEvBlylJVylFSzixYCrtISrtO58CvZigFVaglVaS0mwFwOo0hKo0orwTZwtYCotYSqte3g+4MWAqbSEqbTCOSHuzAFTaQlTaYXrCuGyTwuYSkuYSivCu79agFRaglRadzYl4MUAqbQEqbRyFvFigFRaglRaySJeDJBKS5BK6w6nBLwYIJWWIJXWEpKAFwOi0hKi0lpAgr0Y8JSW8JTW4pGAFwOc0hKc0rr35wNeDHBKS3BKK50T4tgc4JSW4JTW4RSDY3OAU1qCU1oZvnSuBTSlJTSldTQl4MWAprSEprSOpgS8GNCUltCU1tGUgBcDmtISmtI6mhLwYkBTWkJTWgtHAl4MYEpLYEpr2Qj2YoBSWoJSWktGAl4MSEpLSErrSErAiwFJaQlJaS0Ywc/ntgCktASktA6k4F1XLQApLQEprQMpBi5ftwCktASktA6kGLh83QKQ0hKQ0jqQYuDydQtASktASutAioHL1y0AKS0BKa0DKQZHZQCktASktA6kGAhSWgBSWgJSWh2ZnACO0hKO0losEviMAEZpCUZpLRXBnxGAKC2BKK1lIoHPCDCUljCU1sR6QsBQWsJQWhPrCQFDaQlDaR1DCXzIgKG0hKG0jqEEulLAUFrCUFr3HH2gKwUQpSUQpe0Pp6jDIkGr+FNpmqdS+L0C4Ckt4Smt4yl4/1cLeEpLeErreEoDuVwLeEpLeErreIqBezFbwFNawlNai0fwigugKS2hKa07pgJPqbQAprQEprQOpsADEi1gKS1hKa1jKXBvfgtQSktQSutQCl72AySlJSSldSQFrj63AKS0BKS0DqTg5gMcpSUcpXUcJVD/wAEJRmktFVGB+gP+RyhKa6EIfnGiBRClJRCltUwEPzjRAobSEobSWiSCLwdvAUJpCUJpLRHB9xG3gKC0hKC07t0UXH8AoLQEoLT9q/QwsAH8pCX8pLU4BN9m3AJ80hJ80loagq9XagE9aQk9ad2rKfDceAvgSUvgSeuOpkB20gJ20hJ20ro3UwL6gf8ReNK6B+mxeuB+BJ2wmXsxBeXvfxsLGP7xKMHuOgxI8D1w+MejBNsHBiT4Pjj841GC7QXxLuL+V0+GoDJk+GhF/6snQ1IZ1hvhaND/6IlQVERkSO5/9WRoKiMyKve/ejIMlWFnLAL2LP2vnoyGyrDOiUfX/ldPBnVQ91A9HmH7X6kMRl3UvVWPR9n+V08GdVL3XD0eaftfPRnUTd3JFfxWWf+rJ4O6qTu8gp8r63/1ZFA3dedXJJxJ9b96MqifuqfrMXbuf/VkUD91r9dj8tz/6smgfuoesMcRSP+rJ4P6qQUoDEch/a+eDOqnDrpgcNX/SmVw6qechbFB/6sng/op5+FF2/5XTwb1Uy7CiwX9r54M6qcOwuD1gv5XTwb1U8dh8JJB/6sng/qpQzF41aD/1ZNB/dTSlcDCQf+rJ4P6qSMyeO2g/9WTQf3UQRkcrfe/ejKonzouE/puAZgZ/vEog4V3jPS/ejKon1raAlF3/5sngXqpEOEtD/2vngzqpUKGdz30v3oyqJe6J++DdiAvFdRLLXphQTuQlwrqpZa+MDyX6X/1ZFAvFU14b2D/qyeDeml/ECbwtQBsM/xjL6M/CxP4WgC5Gf7xKIOFT3L0v3oyqJf2J2ICvTrgN8M/HmWI8HmO/ldPBvVTd8UYPtLR/+rJoH4qVfhUR/+rJ4P6qcM5+ERA/6sng/qpIzr4UED/qyeD+qmDOvhcQP+rJ4P6qTsmg48G9L96MqifOraDTwf0v1IZivqpwzv4gED/qyeD+qkjPPiMQP+rJ4P6qYM8+JhA/6sng/qpOzWDTwr0v3oyqJ+6gzP4sED/qyeD+qk7O4PPC/S/ejKonzrog48M9L96MqifuhM0+NRA/6sng/qpYz/44ED/qyeD+qnDP/jsQP8rlaGpnzoChI8P9L96MqifuhvK8CnL/ldPBvVTd0kZPmjZ/+rJoH7q7inDZy37Xz0Z1E/dZWX4uGX/qyeD+qk7WYNPmfW/ejKon7rDNfigWf+rJ4P6qTtfg8+a9b96MqifuovLQisXgA8N/9jLcIQIn/vrf6UyDPXT/v6yQCwFKNHwj0cZPHwHWv+rJ4P6aewas/5XTwb1UyPDt2j1v3oyqJ86YIQvcep/9WRQP3UXmuF14v5XTwb1U3enGb6ltP/Vk0H91F1rhu/57H/1ZFA/NW34psz+V08G9VOHjfBlmf2vVEZD/dQ9FIOvi+x/9WRQP7U4iOGLRPpfPRnUTxvnp4F5A4BIwz8eZdhVKXybR/+rJ4P6qUVDzAR8HcCk4R+PMuw8Cr8F1v/qyaB+2rh5VGCGDKDS8I9HGXZVKvTNAbA0/ONRhl2V0qE6RX7aUD+1uIjh93v7X6mMlvqpRUZcBPpkAJmGfzzK4FZGIHYAoGn4x6MMYVFPYKwEsGn4x6MMGX7Xuv/Vk0H91CEn/Lh2/6sng/qpw06hFWkAnoZ/PMqwb22FVqQBfBr+8SjD4qfQijQAUMM/HmW0Vkag/wAUavhHJ4M5DBVYxWUIRDEKopjlSjywissQimIURTFLlnhgDYUhGMUojGKWLHHMhPtfPRmCyrD9aYPbliEYxSiMYhYtsQa3LUM0ilEaxSxaCjxh3v/qydBUhgm/Yt7/6skwVEYTfsi8/9WT0VAZbfgt8/5XTwb10/6ED+7XGaJRjNIoZtFS4Cnq/ldPBvVTi5YCLyn3v3oyqJ9atBR4erT/1ZNB/dSipcDro/2vngzqp+5hGvzsYv+rJ4P6KXPbjNGmqv5HTwR1U/c6DX74r//Vk0Hd1F2rht/+63/1ZFA3tWQpNNwyBKMYhVHMkqXQcMsQjGIURjFLlkLDLUMwilEYxdxjNYGQnyEYxSiMYu6atUDIzxCMYhRGMR65HL//1ZNB3ZRH7sfvf/VkUDd1960FQn6GYBSjMIq5K9fwk2T9r54M6qfu1jW8bab/1ZNB/bR/wSZUFuSnFEax/hGbgH8gGMUojGLu/jX8fEf/qyeD+qm7gi3k6whHMYqjWP+cTaA+EI5iFEex/kWbUH0gP6U4irm72IL1gfyU4igmIvdT9r96MqifuhvZ8D2f/a+eDOqn7lK2wJ4chnAUoziKORyFD+X2v3oyqJ/KyGWV/a9UBsVRzOEofH9u/6sng/ppj6MCfopwFKM4ivV3tOHlQoZwFKM4ivXXtOHlQoZwFKM4ivU3tQXaFuEoRnEUczgqgNYYwlGM4ijmcFQArTGEoxjFUay/sg0vJzOEoxjFUazHUaGyID+lOIr1OCpQFoSjGMVRrMdRgbIgHMUojmI9jsJL4wzhKEZxFOtxVCAOQjiKURzFehwViIMQjmIUR7EeRwW+OYSjGMVRzOGoAFpjCEcxiqOYw1EBtMYQjmIUR7H+QrfAN4dwFKM4ivU4KuCnCEcxiqNYj6MCfopwFKM4ivU4KuCnCEcxiqOYO5MUQGsM4ShGcRRzx5ICaI0hHMUojmLuZFIArTGEoxjFUazHUYF2QTiKURzF3PM5AbTGEI5iFEcx94JOAK0xhKMYxVHMPaITQGsM4ShGcRRzN74F0BpDOIpRHMV6HBX4bhGOYhRHMXdmKYDWGMJRjOIo5nBUAK0xhKMYxVHMnVwKoDWGcBSjOIq5w0uBTY4M4ShGcRRzl8AFNjkyhKMYxVHMnVsKbHJkCEcxiqOYO7oU2OTIEI5iFEex/vRSwE8RjmIURzF3IVxgkyNDOIpRHMXcnXCBTY4M4ShGcRRzJ5kCmxwZwlGM4ijmTjMFNjkyhKMYxVHMnWgK+TrCUYziKOZONQU2wDOEo45//M+nT5brL9123y1u1ovu65Pvf/vtyfv3227X7Z88/deT90v3V96yp1bbk+//9UQr/eT7f/3v/z49Kjn8v6cn6fa3g7r37/d/PHRDMVKcpcjWZVO8/692/9Wz/r+y/2+fThpx/Ef/l8NLWvYfh0vKUwyaLxYja7g+m3O4fDFRxt1mvdtv58v1fjcUd3gh4SSOt735h8cQEuUuursVkaiHEsVRokiVuH68Hwk8PGd9Enh4sDpRzvZx1RHLmqFl6miZTJO4Wi26fXe332yJeWehokkTtZ6v/tgtd78v16O2Pcxez23Le5+y89QksdtPd5uHP+4f9/P9crMeStaDkjdtmrTd/XL3uOtGFpqBnAOZSRNEvspBIbXmqTKOlT9qUTnwNSl6X7OnGBKlLvfd/cN8Ox+73IHqnOQqZo4NMUtzlQ/zXfd+sbl7/7hdjb5dNRDbzuTRXJH2bXyY75Z3H1abu99H9Snbga0tO9ma1jpnocvF17HcYR00p7ptTaZc6uUHhDgw+OTlszQv//Bx1FR82FRaJhq32e8396NPj80GYppTN953EmbW9P+QvTMcHiZNUrWdr+8+Lx4fVsu7+X40sDQDlSyxf/zwuFyNa5MPOnB1HH+U7u1VJu1TOMjdH0SCHo4NPUweJdvzNSmi77rVavOl235cbf45Kv6g4Q7L8EmyPn4aFV4N+5LZ2ZXSKvPu4yfP6cXQ6U9faJvW2Hefu/HHaQZDV8uP0o5iWR89HBbu3T/ksQjHAOMwd3P/MMc0xy+Gz/o0nPUCOe8Tc9En5qp3YK57v+XHQIQf7RFH3xbHEUeI40+ylyyOgY4wxzTNMc0xaJCzPo0UfRop+95IHosjdWI7HyrShixzGrDM5GAQl2mdnBX3cdmtFkSWGMpK63+srC/z7XL+gcYXs2EsJdPGirvVfLezmQaS1OCDM32tNonmrZYjhx70MaeA4nCiNVHWd0TeQFyyPd8ttssv3WjgHny26aZsHg5hzbj3H3xfPNEXVsvvtt3ucTWKSsRgTEpuueV3h7nCyCA1cAGTLMeVbNF9nD+uxu4uBvJk/xG1iUPwSfC4yoY+f5ydiKNkffxHYoe3GQU4bOi4sknshTerVXe3v9usF0vP2sPi4WC6c/JgdewNDwuGGVoW3cflulsEuhY1/H7TItNert+5yOGn15xHzWNPapdcMzQcw/qxEjacMehTkKZOYaBKdEKn5BDvH8SRehnO6GRyq262y//pNo/7h8fRp8YGDpgY9VhhYy8eNlWqrx4i/W79OA78hvGTYamNfv+wXNnmeFwvyfRmMD5p1R7bIXGWebdZf1yOYhwxkCeOyw+pAU7v5ofZcLcbVWAjh62Q2KHYNYRHOgvTg4/+FM4fgxN2DE7YMThhx+DkwLX6IOeY5jjYseYYwByDOs6O0Q4/RjviGO0ocQxyjtGOOUY7TXsMco4BDDtGO8coRRz7VaGO0c7xaxXNMc0xWJLH4E2e+87jX6Q6RjvHQKg5/qU9huOz/sNU7NiUzf/f2dXuuI0ry3c5vy8Qi6S+7qtcHASaMcejs7bkleTZZIHz7he01K0ixcnW5F8QJCVZJPujurq5/eNSHlHJv6nkEZXVP2z/q1LCSQimqtU/SKoiUVwt71NXG3Jdb+8cbuTe/iD/S3mRk5JB28cMtyuuf5D/HuZ7r3+QUDZMuV3/IKvcCmfWVlwq8joOS9cP899+GuODgDyQ4cGm7jX29Rj2VbVuVJL0Esg0dWgRdfdPtIlbUdNQ0GJQWTVq1wvW6K2wsfFsEZMNySef5K9oOL8AkSNyKiQ1JeD9Cmg/xTEOWLey3rmL/fORvvcJfuvnpQ//sIuZDNiPG3AY3sPjzuPj7e3qwxr5H9EWbeDbFmKWTFuLoWrE0pC7YOqX/rVLyCjMTVmHskR7HllFOe3yrTXMkZMg9rYQe1toKKTRkdjbQoyhEStkxMIYSZaNU/sv1l5odyPnxLRi/wux5GLErNhtKzhWjKoVm2CFAbASGDtJlp24ISduyAk15ASnlWe1YsBbSahbSczbilzCR8LJwAbhQotzt3SBg8kTqZhnOF3EgjuDZ//yiIOWEt6vFu6hFvdeC51YS7xQkznN80nX8XKJ88nQOrc/rxHC9kTWR7bM6/u8nK/9y/d7t7x/91cf/k0cbp9wx+v2Pen+DWXhLzwwk545/CWtuN5WNn0rEUArwVNbc4n4lvn0w/oj459V488q9Wcp8U0/4+pjHxHu8YL8jV3k3A6FiN/JwXJqME6k9xbsY6BdYXghn7vlEgJB7eNaHZ6C9sQddIFKafMwTwo+QKG/mzz9G2waXxRReXOniMiwJUsYYz6wrVMtkXDDxW2K+21jpr/9qrqF2/drXxnws/Uu9MNkgeII/YsaQA3fqiCzz+MDPqXYMUIxX9sogP6LLDLK5X93ac/9R3/2L/5tnPztcV36+/Vn9JQSnd3vLvD5cbsfV7jBBSCrkTnsbW3PSmNFBwLXgaQFjw/xw/yY/H26zD7+DZh5FL99wN666+zzr4/fn2QGM/iBIjuPj5er7xPSBPMRU/zuMeuHdz/1iz/PSwjaM4aihcU25ncXe/AffupeX/08+/MnlQDkpe3vLngID27d9dYt72+P4TX9NQVGI6ZkI4/0KffJv/mpe1zCv/Pnbp77S/wcrI2a6ouOIXnOFJYnBCDdvY8fAkSvoeO29CGT787jcP2ZXxaMmg2ZXx6fMfvh3A/XcbzH4LC5LKkUyIC/j9Py2k+vj37JHsYCax6WVDpknrNM/XCZ/KsPtZk5eI9rF/8grBRYkmTNPOgx3/vXfnzMNz/P3cXfxnMcgSCXa8kq3PE5j+FlfAznw7Igv2vL3z3zG/ot/US45iS/lQMPXsn/uAf32o/DsTxVoAbK1r+7FuuD1qwjZgOKSMbU/u4iBM4uEyYUFoP301cXIZsPRJUxNgju52AUznmZQ6RH+NfGBJC4HzFTidkoKW34xyCowiCIo5lWzKOgDsvLbFh4qOHC+wj5W5OvlSjCkHwohbGv2HByXvz54pPqEGqXWGrhcbsnWjWH9cy20MR4l+axwdzjdk+0Kw45z1aLIyfN7ArWCQbsQzbrUPLXWmVEjNLdpDLoGTbf7uOUUCE18hRsUJ4NwVvUQbHhxT8E3HiWye8YdlG8LZFEbnTxSYo3wB3URQUiqh6o5VYis81hjSthJitSFONv9+VnPyx++oh9gTVI3p240+OHzy2rNeglSbjPch0kPskQzv/5Z2yeDdo/EmOaYgdUomBQKm0iUKhV7i3VjFqV0CSN4D+6awgJojfHo9JoHfVU6aEmizkBfF7G++TPB0rCYjrZOCWapLhaFCRlvT3ko7s+kgegpkMlbyetAhcVuSYf3XUZU72+xWy7Eb70OWBQ4Mk9+MO/PuJvgzE+WULaUJ41pOg14UzIK5Ka3Q1yKx9FQQLqs1X7JxVhK3IER0pP1gf14/D9reuvjyl6VoXSE3LbCZ7/8ervh8wGBbGl6gZOJKPhf4SMKc4tKtzKKp/ifLb/cagcO4z3GzIM33BCUSHepljz3EsuumELUoH0C94GQ0bSbf2KpUG6oeC26lsfb9ACBXKuYUGGcyJQjlMBFO/tURpJuAP6MsZ6ttB6tgc51a5tUVNCVjTCM17fLi8/D6IB9OCkXXqCjcPgD4yQwSShIhmhAPfW/7iP/RDLJJD8bgwXlz3BNq7q+YPTeoNBDq4iDX1A7Yc9QY6jC/yGjdNAWj1XQQo6w1Nufnkfz9k3tyf0+KQPDJjDePYvP9Pzb5A7r8gAOsDdp/E//nXJvCDy5A3ZVBIhHmwU7qeG5DEDYug0i3M8pN7KkguB3sZrWIp4tU/Y70HWJQPQJ7vH4ao2TkMqp0fckadyvG7E87FqjPGOit5OTgMqdvXHyXev75/0AVX4YcR7VmRBeoNOclSLPHZVkR5khTqkU+iLK7HSFSknFVBdxNgCoKXSz3rS0LL42lOGJIow2PZWsW55xdItEe8IDFGdhqgaBRRkI9PbON265T7OB9/vkLRvyn1fqy6H5JDepvGWUaVirNaQOdQGdRTkYZ2yIZnmt8f1ms9eYZ/VJ/Lwbi7r0KuGFfyy1dCMpDAF9uhK0E+rhqEg5TYCm4j6ELMibfXj8G4O6wtNpXuzVDFIxRndix/81C0+BFXzu7/eN/4/DrBKDLA0ETK7eox92PJZg26BdKfTnqtwjRmPvDJge9SV9CCi5ps8V4jbD5dgcxJQ7G0jPeYK+vzi8We2+Jk1pTdqb8hcJuDPt1wx0mBfVklWcWK4eNWQ6ihJte/FL585R4zdyApzQHs5WAQLx6wkw/+LX3ImFMMCQ+8akWPEXwt7aslADbCS7mfk48nAfwU7mHaD4VVJkn+AlX1BgzRMWXLcA4Aem3UMNuuU5KgIQMycXoycyBASAJMFwdUlCzYXv5z9/Dr1B57FYaTYSiNCK/rcVhKnVro225reA8eoD78DSRoEnF/QyQWW15x255/4Y+2HZfr5THjj3AK/c8Nv1sA8HXdAhU6BrNNf/JJVeqBvLy0XfABWspsQjFTBXPyi8prc8cHCRkkbxcAwxZJJgzM6SrJ5LSAtPh3hgD2mZG+oAL38DGY/+YlYUiR19xe/ZIIeg6F5yduGDSpxk9iwzjuRleeY/PKYhkMTq8ECUEmHextoYqrRl5S0HXnS5d0wjEcRV4HFXVdrMGNpPzB0S//h81EMrjI5zuWAmGxEdFakGODiF+kJVhOeyMQxopN6dGvFdGuvsPTGtWSl+uKXUBXyQd2W9lxiIF1K1lIVe3vNFx7R3/rwyeKPj4aJTLMRLDkZaJPIDPWJNl6mLvzt1CeIGOaXhj4WG702jWOS9WJxwtIWaoNLPJdDLPrTfWoA0KqQxaKLX55kR/ReUZGIHDsgQClrYrDZuSTZbQRL9gei8Z//iRZ//Eh/TtbLn0hBB5lyrg5PQVPu/VSaEpM83PMJoVs3PmPoX0liXJGSD4i2kmRtAtTjNWdcMKgrpX+rKnaRBL15MuQzvilJtgpQ8pvRBJAT3C7xsceGi5r8bO/dcL6uNeSjOBD7QuRrkQTVe5fMLMCdTAqE3rv5U04AjxgpS3nv5l/V+lBC47S38ERmFjv4sdSHvToqqDgZJelJcdt7N+czdHSeZKyyYmWSanRtou2qyOjvvZvzOQZGamT16L2bf1GXw2K50zRN2z8LR3+FbBSNH4Hky9+7+VfBH3o9S3/NT4IZ/Jxk/eG9mz/xfBgZkSLmJ9jR/uM25Bdgfryc+9hiO2yybhrOlbx3c8Y843cn6dP3/hK7TdRjtaT5i3PPqNivRSSlvYUJlxi70BKhUuPKlmufvqi+zEnEOMJXGCPNynI0jFRpjMjIjA7ZkjEYttiQrWgQrN2QreBYIXitdL5bUS9aaSF3J5ECiYFzYkecFEGd4FTShN3KQ1tpnm6l2tZKN2xLhicHbST6CungLXWqhcwTqYSzrqyWOLmt159/bCWJ2KUYTNAqknLoL8M4+XMuFi+QXnPktM21DnDup4yoA+erVLs8mKxfrMgHXg4LL5VVk0z60R00XUaMhatiL5hx9nnFvUzdPdZKoBSlUt0j2zAJqM/5ibGO3aCoqyQ1OCvktRsuj9QvofC62pXipBppBT5WoCO16b5cXAS6gx6WC4uGGk4VZNl0xT0oW3DqYUVm3hmJucEacyWGpiIV4itIxBshbcxaqeGousZiWkXmAP3wFg+zwcmVtcwPqGVuUS2DJ2oZWVKLiLORKnRL6tr/uS2ywCKNIQs+T+62u/Z/+zxJj53T5BZQxEMBE1lhcvJNPyzmMOsLPzp7doLGYAha7JxkFfu3yz1ZJfWwgj1/+4zqxGyHFDvtoMeaY4HbzpHVywgwnVRToLlzpMh0R9SvmmweTNhJ2mgHTYYBYTmzIoNnBPvWzcu8jLH6ucACX0mWdyLUzRUlFCv+cFK7lUXNvrTBA1CSkxPz8Dl7jbM+SrIT4RP0ZJwTJgj1b6xgOjcYFcMlmdhHgLmfj1xnRds8BB3O/WtaR8ZogqyfxKDxp0TSriIrdRHegSy2yPJUpJBkh7x2y9K/xqwx1vdrifxrMls9QH97hv39a/zS+F2br24pQc4L0LD7kxysdYROfRc2SdYkPQOox5FJWEarv3xa5/H6kc5gQj0L2cqSAm6jeRN+HQslbGqfAudeGMv9bHx+xD104VgMgBs2pUqB/xqnP679nGjykXMhO5B25CUVXiKd3ZAVtxguE2RYlMs2ZMXziDovPj1ZmKk3ZG92AtwvKwOQUJVYpiLJugT43k1zvL8c8okNWa9KUHPDuqK+q99618fSx+Q3soLNl73CMnXD/Jb8eIsC4S+72MMbYmDUfNle/9VNQz/EnQQO+3sbsnb9hJz96xJOZgKHP5icoKBwt+6eoOHeab+wygFt9sm72WhC1hfW9+DbcEjafpEBm+RvkDmfj/qa+qRVF7JA1g/LwWE26DAln97JI6PkFO1N4ykPyH/XrC2OD0k0oOvExgozzJ8+9CUXaH1L1vnMn3eD40GuySl7/Rw0cVHgWWIMTw6R6ufPVf4YIpLjP/r5eWofL7Nfxrf4gKABZDnbOZzaHBo2mDfkCMF+Xj1IZkGxksSyFntV6vp0ebE1RXam0cbuU6lNT6QEtp9nf41/O9bam71lUjurCtYRPqHXMVvxA9Ay7lp27aIp2BR/DmYyuxlQgUF2H/fz6qqFX1u1cPGLo7/ZK8zaEFawznyeH/dnydUn4yZxogjLjT/nbKe2E/PjmiQE/zP2cVcWFmgrqUBVMiG4lh1Rk/FGwJ/9rc85D4xfKh0uu/eC1lrFI/Wuqew/mgWyLZiU/XSquqrwdGnlqfJ49TnanKpHToetyuiIQqhfc5IionTNGZmyboQVN1J+M8IlGxHoGZldbKXmZ6WIZGUusRUcKz/KirDSyue0UhN1UhN10qbjpAbp5JM7wXEyK76U/17JZ6ml1b12muJzhjxbd0HOsCLDhquPJ4Og8apkdEclQ4or+ZK1jOivxerUso61zFioyRasaz8kHfJIqJKRbvBr+dEreEEeZ3gD1oGAR0Uw2YxzHV/j9cFSkxSbW9KfXcdkvjQaKBkuW0u5vJYhUjU5Wuc6XnKKEBtd57NLjUkK8ki6FFjHK5XZ2ifUk50W1/Fy9R8+Dokwwqqr3faRyx6PjnUYPrfkzJrr4yUO0nCVyInCty52Iw7XoKVB/ogPFW6+UuxgKdLlUgxrKS2IpZjjUjZXS9ZEw6PDXyZXPyJ917QqhiJ1pwH0eJOOwxaTVoQRrRjjVoxxK8a4JTdueNyWMkcCGYwv9pttxLfJJpbnF6r50ihNN7qO05JPYWRRjDgnI87JiMM1EjQZcSqmUd8mXkqW0oqPtOJmrNyKZCXitRIXWDEYTiy7k73hRBzhRO/jRJTryPEVt+7HITnFSiRZQ775cx/DOBddvUPuJR9fk2xRVl3p+L1WPZtYKXI6csD/LE7D2L0SkU+9j0So9+ycPOh+uvgjF4Pxa0OOBH9CHXkYpHJb9gtPF3/kYJC3IwvEmY4ai422FanRvfXDW+wrMKmXGyzqfeiFitwKUqp664fDHkd+hBSn3kKM/xH0Cj/joAh4Eg1VWcT46gyLC1GTbRxP6fX3pb8FMxzXvzHCIsONDW3q4uNRoHjKkWMrV6wwwzdt80RtQlvvfe97bz15xn7Vi4W3B+hVSieyd3K7WOegUsBubbffwsoe5A31KFVAsYbeFnsiudonrI85wAJrvm4XjZIM0ieC/kgbJI1cX4c8MEnxTdGC+4WlWnHHqLXeRWpHAf3CzlpBUz0+Dt6oFPYLG2CFzRL/UYupQLPWJNwZ3r0umfDI4WFoNfk/ke34t/H8uPpUTIdFVbKKcpuT18IZG6RqVCYQH2cHV7g3SX8YODF/3m7UiTcPcmK7/VDekJ0HK7TbkF5e6YroajG1JXrBckHOD3hi4AaNhBRb0CRRaCWq6ooU6Q3+0i2HuylR91KTujfmdgIctU+60cFnL46KB3uTSLFZNjjpo2JX49Buj2liJQxVxb5TgOsm7/98pEw5RpJ7Uq19eQXJXh6kiHiOJIeqdU5zQfZwDo/bMq6z/OPYC+HJJPMfr5vA2zNIkj1zw1V0VZfebyWNy5JttXonsXzqlsy2xqm/xBSCQWK8kvinInms8ZEZMI46jIr9vocEHh2GXpL2FbB1/lcckUCkLJywXOCptxRyRnV9RuqRkNaXjUuKPJ4Vrpx0Dq83KEmd61oue++SST9YrixJlfcTKpd3OMzTmz2+I7OZJ26IFrY+kVhzga5P3dFJ77guSC7wnuZ2GObVQsbU+zhMvYixICOT+zXNoDAoIZWOxDUzeGkOyZ7/06UyeNk5mSvfpzE4z3zXuEElRUmKHbfVTyMIFw112YySGCftvap3oo17/z8ffUrw7M8hV/yJkdMM4tba794jO7D+4XKe6Epv7stO/i029FgHFEaxInXuk7+NH/5Y0EYGSC/0Pim5WZCz2Sb/FPZtm+E4ahUJYjIoiyHTARMGCYCKLK2tadPkg42OXFUUUIgfoX/5M8PLTeiOZjkJX03OhRbcTPyDI/80xSPf9pFMy8J7cqVFqpVKbitDRlthl1vSg0+P4bOLhTE+l/1GlmDm7sPLdwnDt5NkCNka+SxcJPcppYuxlXYr7XMrdvtFDi775HotVFVbsiVk9suvVAOogqnkxuF6v/90H8xJxjdzmIH0C/YbNedS+Kh3jcx+uzcZms7ZkSuY8JJFq1zsE13wsk9ZUqu3/UGCy0IH18tBKFRYpPILqS4YKbMYKbMYyZiN5EBG772uNI4VbYNU5K0kelZaTa0w11YSCCsLaqU928qHtiLVcMLWOPk5ToSCTkr8TqpPjbTitcX+WdhDtH7nnM1yGA80raaaZHVofu8mL325OdorngGqe06WUXah9gLrMGIdHqyhqV5dI2IeI0mVEQNpJMo0si+M+E4jhXQj0hIj+8vqxVtSzbRSnLBCLlpZBytVQKtVQFkZJ9d9O7k42clrOKk2OZJaIm7kw/ttyHB4/qO/r9exRWuEVN3ejStrJJ9d1KyFKpzUiCiHprS5rLWRtTZGl0bqqbLHjYSdRny80dEBolawMlvcivzHylmx8m2tEG1W6g62kYUQ4t3JWjs5sk50QE7CYUe2Yz/DoMgKovVq5As2sjsb1hdlmkZQKXrScHDXQpNT41bobLsLJoa7wSXlO1s/SvfR9dcQZMcyCMyzyTsqN8CXfuimn3F8iR75K1j5yT6oe9qdMEl7bsi37n5PFgx1YY226BZk+8iGe+hxB1stoaAjw+ENMrO30EQ3OqmavVh5w/3w08s4x9q4Bg2UvC25n6ZYxhVlrXKoKzJhmafXzC1muCnJCuo8vYaW+tkn5QSka3ZVlepPCpJW2OCzbhpn4zW7JkwzQ/YW6Z1gyBPPaGdUHHrSg1GQM0jn5Tw+lu+HDYw5ht6MRK7ickvHtqKeoCR7aZgraMEUWpJ02+bLRZRzNB2RRFkl1t9v3fRHIuLD2qTbC+usRdmQD03vmGg6kgAhbteF82pJHxIoy6ykACdytBrVn/YhSeQYqPCAfFc9donAPBJuYyJsdtIL2q5dga+C7YIsaC7rZPK3/nLrhi4lyZB2afaLPXU4VEGq8MJTPpk6gW38GsKfvvDx+yn3fbCaV9aawrfqNEm1THhCfrpldGGyRHtkh8zyPo1//T2eMx0ykTpftyV51IOqJ+G3UfZLdgwcBwqibnXvsTG6qUniJQAfNTKRAFoYLtKlB8QDGR2JO/c6udmPNg+eqXRhL4jQh2Qj4nEaDF4YK7mMaDJFVdiS/vGJ/i17+S8qoMkWsx3tcN0vpnYknwRomQt+cX+RIeIOmLvSF1OblpyouCIeNz+SpuQA4SVm/GwRSYCkW0jSx/qkAlUhHcmE/qm7yxQ30P/W7U5gkp822wSNtQOhE5tmp43IPTr9TEQ9BaYK5Wmnczibsl1nfyRZMVEg29E2rFsSumEd1pKl+8fwvDMrTVsd6mAa0qqv5Mo+m/Qosyuie4lJcdUKu8oa4oi9wH5gS5riFS5UMft4WBnOvHBkvf4xh7nKh3EU0WRbdY4SjehAQZHbF3qBmqY0muUIYVdIKdyItzVCwBpJMI0QdkbIKSPklBFyyp6U+BO2VnhgKzywFXLKiuOw4vCsGHsranUnlKzTrFwKNE7shCOTwI/DxcXoxWpSWpRJx6OjwS3tipKqojGvcWTWlVUKo6fTaIKsbgeuOf5KWCqUqLcW7r4WQrHWigs5NWwjtTN9MBi2ShWODIazAtFodO/6H4UE/yLsi3/vPvqU6ULJrM7IPJEduwK9p5Fxcop69HrPDTgLLENncuQUlif2MaTknOTQZdydz1OSmRdRgyIzAOHf//Ove3/3z7bJ//2/f//3v/8PwGWGUByeBAA="; \ 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..b4cee8721 --- /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

Compilation units representing the actual entrypoints of the analysis targets +based on user's input. Might be empty if no paths are specified.

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

Minimum severity level to report warnings.

+
outputFormat: OutputFormat
outputPath: 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

    • tactPaths: string[]
    • options: Partial<CLIOptions> = {}

    Returns Promise<Driver>

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..51a666eab --- /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..862927659 --- /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..c089be553 --- /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..7d9398ffc --- /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

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..cf20e8b1a --- /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..eb5fbe547 --- /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>

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..25bcf0df2 --- /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..825e3f15c --- /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..1cf4805ba --- /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..23cbacec1 --- /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..d93419db8 --- /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..5fa519fef --- /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..c0d7d5fca --- /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..24792f98f --- /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..761e2cf4b --- /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..8bf112246 --- /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..b426bf968 --- /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>

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

An optional detector that identifies send functions being called inside loops.

+

Calling send functions inside loops can lead to unintended consequences, such as +excessive message sending, increased gas consumption, and potential race conditions. +Loops with send calls should be refactored to avoid these issues. This detector helps +flag such code, prompting the developer to reconsider the design.

+
fun exampleWhileLoop(limit: Int, owner: Address) {
+  let i = 0;
+  while (i < limit) {
+      send(SendParameters{ // Highlighted: An auditor should review the loop
+          to: owner,
+          value: 0,
+          bounce: false,
+          body: Msg{ a: i }.toCell()
+      });
+      i += 1;
+  }
+}
+
+ +

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_shortCircuitCondition.ShortCircuitCondition.html b/tools/misti/api/classes/detectors_builtin_shortCircuitCondition.ShortCircuitCondition.html new file mode 100644 index 000000000..9a58b7474 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_shortCircuitCondition.ShortCircuitCondition.html @@ -0,0 +1,52 @@ +ShortCircuitCondition | Misti

A detector that suggests optimizing boolean expressions to leverage short-circuit evaluation.

+

TVM supports short-circuit operations. When using logical AND (&&) or logical OR (||) operations, +placing constant or cheaper conditions first can prevent unnecessary execution +of expensive operations when the result is already determined.

+
// Bad: Expensive operation is always executed
+if (expensive_function() && constant_false) {
+  // ...
+}
+
+ +

Use instead:

+
// Good: Expensive operation is skipped when constant_false is false
+if (constant_false && expensive_function()) {
+  // ...
+}
+
+ +

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_stringReceiversOverlap.StringReceiversOverlap.html b/tools/misti/api/classes/detectors_builtin_stringReceiversOverlap.StringReceiversOverlap.html new file mode 100644 index 000000000..bc42f6128 --- /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_suspiciousMessageMode.SuspiciousMessageMode.html b/tools/misti/api/classes/detectors_builtin_suspiciousMessageMode.SuspiciousMessageMode.html new file mode 100644 index 000000000..b7eda6907 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_suspiciousMessageMode.SuspiciousMessageMode.html @@ -0,0 +1,59 @@ +SuspiciousMessageMode | Misti

Detects suspicious usage of the mode field in SendParameters struct instances.

+

Incorrect usage of the mode field in SendParameters can lead to unintended behavior when sending messages, +such as incorrect flags being set, which can cause security vulnerabilities or unexpected contract behavior.

+

What it checks:

+
    +
  • Ensures that the mode expression only uses the bitwise OR operator |.
  • +
  • Warns if integer literals are used instead of symbolic constants.
  • +
  • Warns if the same flag is used multiple times in the mode expression.
  • +
+
// Suspicious usage:
+send(SendParameters{
+    to: recipient,
+    value: amount,
+    mode: SendRemainingBalance | SendRemainingBalance // Bad: Duplicate flag
+});
+
+// Correct usage:
+send(SendParameters{
+    to: recipient,
+    value: amount,
+    mode: SendRemainingBalance | SendDestroyIfZero // Ok
+});
+
+ +

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_unboundLoop.UnboundLoop.html b/tools/misti/api/classes/detectors_builtin_unboundLoop.UnboundLoop.html new file mode 100644 index 000000000..0b076d684 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_unboundLoop.UnboundLoop.html @@ -0,0 +1,65 @@ +UnboundLoop | 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>

diff --git a/tools/misti/api/classes/detectors_builtin_unboundMap.UnboundMap.html b/tools/misti/api/classes/detectors_builtin_unboundMap.UnboundMap.html new file mode 100644 index 000000000..bb709f2a2 --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_unboundMap.UnboundMap.html @@ -0,0 +1,64 @@ +UnboundMap | Misti

An optional detector that highlights cases where a map field allows inserting +values (e.g., via .set) but lacks functionality for removing entries (e.g., via .del).

+

A map without a method to remove elements can lead to storage overflow, particularly +in long-term contract usage. Failing to provide a way to clear or delete entries +can result in uncontrolled storage growth, which not only wastes resources but +may also increase the cost of contract execution and maintenance over time.

+
contract Test {
+    map: Map;
+
+    setEntry(key: Int, value: String) {
+        self.map.set(key, value); // Bad
+    }
+}
+
+ +

Use instead:

+
contract Test {
+    map: Map;
+
+    setEntry(key: Int, value: String) {
+        self.map.set(key, value);
+    }
+
+    delEntry(key: Int) {
+        self.map.del(key); // Fixed: Added a new API method
+    }
+}
+
+ +

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_unusedExpressionResult.UnusedExpressionResult.html b/tools/misti/api/classes/detectors_builtin_unusedExpressionResult.UnusedExpressionResult.html new file mode 100644 index 000000000..9c1b9010f --- /dev/null +++ b/tools/misti/api/classes/detectors_builtin_unusedExpressionResult.UnusedExpressionResult.html @@ -0,0 +1,49 @@ +UnusedExpressionResult | Misti

A detector that identifies expression statements whose result is unused.

+

Expression statements that don't alter the contract's state and whose results are not used +can lead to inefficiency, dead code, and potential confusion. They add unnecessary complexity +without contributing to the logic or state of the contract.

+
self.foo == 3; // Warning: unused boolean expression
+inc(a); // Warning: unused return value
+
+ +

Use instead:

+
self.foo = 3; // Fixed: corrected assignment
+newValue = inc(a); // OK: result is now used
+let _ = inc(a); // OK: explicitly ignored
+
+ +

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_unusedOptional.UnusedOptional.html b/tools/misti/api/classes/detectors_builtin_unusedOptional.UnusedOptional.html new file mode 100644 index 000000000..a32caec76 --- /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..04b28446b --- /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..7e9bd6b94 --- /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

  • 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..9675db987 --- /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

  • 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..574c5254d --- /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..3a578e8be --- /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[]>

  • 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..1b200bf1e --- /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: "debug" | "quiet" | "default"
diff --git a/tools/misti/api/classes/internals_config.MistiEnv.html b/tools/misti/api/classes/internals_config.MistiEnv.html new file mode 100644 index 000000000..0037238b4 --- /dev/null +++ b/tools/misti/api/classes/internals_config.MistiEnv.html @@ -0,0 +1,7 @@ +MistiEnv | Misti

Environment variables to configure advanced Misti options.

+

Constructors

Properties

Constructors

Properties

MISTI_TIMEOUT: number = ...

Timeout for the detector execution in milliseconds.

+
MISTI_TRACE: boolean = ...

Whether to trace the execution.

+
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..3afdeb6f5 --- /dev/null +++ b/tools/misti/api/classes/internals_context.MistiContext.html @@ -0,0 +1,8 @@ +MistiContext | Misti

Represents the context for a Misti run.

+

Constructors

Properties

Constructors

Properties

config: MistiConfig
logger: Logger
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..ee9daeae0 --- /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..18343e304 --- /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..bd81c0a8b --- /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..58761bff2 --- /dev/null +++ b/tools/misti/api/classes/internals_ir_astStore.TactASTStore.html @@ -0,0 +1,135 @@ +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.

      +
    • contractEntries: Map<number, Set<number>> = ...

      Items defined within contracts and traits.

      +
    • programEntries: Map<string, Set<number>>

      Identifiers of AST elements defined on the top-level of each file.

      +
    • 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.

    +
  • Parameters

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

    Returns IterableIterator<AstAsmFunctionDef>

  • 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<{
          filename?: string;
          includeStdlib: boolean;
      }> & {
          includeContract?: boolean;
      } = {}

      Additional parameters:

      +
        +
      • 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.

    +
  • Parameters

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

    Returns IterableIterator<AstContract>

  • 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<{
          filename?: string;
          includeStdlib: boolean;
      }> = {}

    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.

    +
  • Returns all the items defined within the program.

    +

    Type Parameters

    • T extends {
          id: number;
          loc: SrcInfo;
      }

    Parameters

    • items: Map<number, T>

      The collection of items (functions or constants).

      +
    • params: Partial<{
          filename?: string;
          includeStdlib: boolean;
      }> = {}

      Additional parameters:

      +
        +
      • includeStdlib: If true, includes items defined in stdlib.
      • +
      • filename: Filters out nodes defined in the given file.
      • +
      +

    Returns IterableIterator<T>

    An iterator for the items.

    +
  • Retrieves items of specified kinds defined within a given file.

    +

    Parameters

    • kinds: (
          | "string"
          | "number"
          | "boolean"
          | "op_binary"
          | "op_unary"
          | "field_access"
          | "id"
          | "method_call"
          | "static_call"
          | "struct_instance"
          | "null"
          | "init_of"
          | "conditional"
          | "statement_let"
          | "statement_return"
          | "statement_expression"
          | "statement_assign"
          | "statement_augmentedassign"
          | "statement_condition"
          | "statement_while"
          | "statement_until"
          | "statement_repeat"
          | "statement_try"
          | "statement_try_catch"
          | "statement_foreach"
          | "func_id"
          | "primitive_type_decl"
          | "struct_decl"
          | "message_decl"
          | "contract"
          | "trait"
          | "field_decl"
          | "typed_parameter"
          | "function_def"
          | "asm_function_def"
          | "function_decl"
          | "module"
          | "native_function_decl"
          | "struct_field_initializer"
          | "type_id"
          | "optional_type"
          | "map_type"
          | "bounced_message_type"
          | "contract_init"
          | "receiver"
          | "import"
          | "constant_def"
          | "constant_decl")[]

      An array of kinds to filter the items.

      +
    • params: Partial<{
          filename?: string;
          includeStdlib: boolean;
      }> & {
          filename: string;
      }

      Additional parameters:

      +
        +
      • includeStdlib: If true, includes items defined in stdlib.
      • +
      • filename: The filename to filter items by (required).
      • +
      +

    Returns (
        | AstFuncId
        | AstExpression
        | AstStatement
        | AstTypeDecl
        | AstFieldDecl
        | AstTypedParameter
        | AstFunctionDef
        | AstAsmFunctionDef
        | AstFunctionDecl
        | AstNativeFunctionDecl
        | AstStructFieldInitializer
        | AstType
        | AstContractInit
        | AstReceiver
        | AstImport
        | AstConstantDef
        | AstConstantDecl)[]

    An array of matching AstNode items.

    +
  • Retrieves a message by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the message.

      +

    Returns undefined | AstMessageDecl

    The message if found, otherwise undefined.

    +
  • Parameters

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

    Returns IterableIterator<AstMessageDecl>

  • Retrieves return types from the callable methods defined in the given contract/trait.

    +

    Parameters

    • entryId: number

      AST identifier of the contract or trait to analyze.

      +
    • withTraits: boolean = true

      Include methods from directly or indirectly inherited traits.

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

    Returns Map<FunctionName, null | AstType>

  • 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.

    +
  • Parameters

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

    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.

    +
  • Parameters

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

    Returns IterableIterator<AstPrimitiveTypeDecl>

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

    +

    Parameters

    • __namedParameters: Partial<Partial<{
          filename?: string;
          includeStdlib: boolean;
      }>> = {}

    Returns (
        | AstFuncId
        | AstExpression
        | AstStatement
        | AstTypeDecl
        | AstFieldDecl
        | AstTypedParameter
        | AstFunctionDef
        | AstAsmFunctionDef
        | AstFunctionDecl
        | AstNativeFunctionDecl
        | AstStructFieldInitializer
        | AstType
        | AstContractInit
        | AstReceiver
        | AstImport
        | AstConstantDef
        | AstConstantDecl)[]

  • 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.

    +
  • Parameters

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

    Returns IterableIterator<AstStructDecl>

  • Retrieves a trait by its ID.

    +

    Parameters

    • id: number

      The unique identifier of the trait.

      +

    Returns undefined | AstTrait

    The trait if found, otherwise undefined.

    +
  • Parameters

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

    Returns IterableIterator<AstTrait>

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

Transforms AstStore to TactASTStore.

+

Methods

Methods

diff --git a/tools/misti/api/classes/internals_ir_builders_imports.ImportGraphBuilder.html b/tools/misti/api/classes/internals_ir_builders_imports.ImportGraphBuilder.html new file mode 100644 index 000000000..804bc7e2f --- /dev/null +++ b/tools/misti/api/classes/internals_ir_builders_imports.ImportGraphBuilder.html @@ -0,0 +1,6 @@ +ImportGraphBuilder | Misti

Methods

Methods

diff --git a/tools/misti/api/classes/internals_ir_builders_ir.TactIRBuilder.html b/tools/misti/api/classes/internals_ir_builders_ir.TactIRBuilder.html new file mode 100644 index 000000000..61a9792b8 --- /dev/null +++ b/tools/misti/api/classes/internals_ir_builders_ir.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: BasicBlockIdx[] = []

      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..8bf9fa245 --- /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<EdgeIdx> = ...
srcEdges: Set<EdgeIdx> = ...
stmtID: number

Methods

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..2fd9c4fc3 --- /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: FunctionName

      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: ItemOrigin

      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 | CFGIdx = 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: CFGIdx

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.

+

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: ItemOrigin

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 an Edge from the CFG based on its unique index.

    +

    Parameters

    • idx: EdgeIdx

      The index of the edge to retrieve.

      +

    Returns undefined | Edge

    The Edge if found, otherwise undefined.

    +
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..3b70ee714 --- /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

idx: EdgeIdx
diff --git a/tools/misti/api/classes/internals_ir_imports.ImportEdge.html b/tools/misti/api/classes/internals_ir_imports.ImportEdge.html new file mode 100644 index 000000000..e39154bed --- /dev/null +++ b/tools/misti/api/classes/internals_ir_imports.ImportEdge.html @@ -0,0 +1,9 @@ +ImportEdge | Misti

Represents an edge in the import graph, connecting two files.

+

Constructors

Properties

dst +idx +loc +src +

Constructors

Properties

loc: SrcInfo

Source location of the import statement.

+
diff --git a/tools/misti/api/classes/internals_ir_imports.ImportGraph.html b/tools/misti/api/classes/internals_ir_imports.ImportGraph.html new file mode 100644 index 000000000..d54f184c9 --- /dev/null +++ b/tools/misti/api/classes/internals_ir_imports.ImportGraph.html @@ -0,0 +1,41 @@ +ImportGraph | Misti

Represents the entire import graph of a project.

+

Constructors

Properties

edges: ImportEdge[]
nodes: ImportNode[]

Methods

  • Performs a BFS on the import graph.

    +

    Parameters

    • start: ImportNodeIdx

      The starting node index for the BFS.

      +
    • callback: ((node: ImportNode, edge: null | ImportEdge) => void)

      A function called for each visited node and the edge through which it was reached.

      +
    • __namedParameters: Partial<{
          direction: ImportDirection;
      }> = {}

    Returns void

  • Finds a node in the graph by its import path.

    +

    Parameters

    • importPath: string

      The absolute path of the file to find.

      +

    Returns undefined | ImportNode

    The ImportNode if found, or undefined if not found.

    +
  • Iterates over all edges in the graph and calls the provided callback for each edge.

    +

    Parameters

    • callback: ((edge: ImportEdge) => void)

      A function to be called for each edge in the graph.

      +
        • (edge): void
        • Parameters

          Returns void

    Returns void

  • Iterates over all nodes in the graph and calls the provided callback for each nodes.

    +

    Parameters

    • callback: ((node: ImportNode) => void)

      A function to be called for each nodes in the graph.

      +
        • (node): void
        • Parameters

          Returns void

    Returns void

  • Returns all direct and indirect import connections for the given node index.

    +

    Parameters

    Returns ImportNode[]

    An array of ImportNodes that are directly or indirectly imported by the given node.

    +
  • Returns all nodes that directly or indirectly import the given node.

    +

    Parameters

    Returns ImportNode[]

    An array of ImportNodes that directly or indirectly import the given node.

    +
  • Resolves project root based on the import directives. +The project root is a directory including all the imported files.

    +

    Returns undefined | string

    Project root directory or undefined if there are no user imports.

    +
diff --git a/tools/misti/api/classes/internals_ir_imports.ImportNode.html b/tools/misti/api/classes/internals_ir_imports.ImportNode.html new file mode 100644 index 000000000..016989071 --- /dev/null +++ b/tools/misti/api/classes/internals_ir_imports.ImportNode.html @@ -0,0 +1,21 @@ +ImportNode | Misti

Represents a node in the import graph, corresponding to a file.

+

Constructors

  • Parameters

    • name: string

      Displayed name.

      +
    • origin: ItemOrigin

      Origin of the node.

      +
    • importPath: string

      Absolute path to the imported file.

      +
    • language: ImportLanguage

      Language in which the imported file is written.

      +
    • hasContract: boolean

      True if this file has a contract definition.

      +
    • inEdges: Set<ImportEdgeIdx> = ...
    • outEdges: Set<ImportEdgeIdx> = ...

    Returns ImportNode

Properties

hasContract: boolean

True if this file has a contract definition.

+
importPath: string

Absolute path to the imported file.

+
inEdges: Set<ImportEdgeIdx> = ...
language: ImportLanguage

Language in which the imported file is written.

+
name: string

Displayed name.

+
origin: ItemOrigin

Origin of the node.

+
outEdges: Set<ImportEdgeIdx> = ...
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..a6e582d4f --- /dev/null +++ b/tools/misti/api/classes/internals_ir_ir.CompilationUnit.html @@ -0,0 +1,43 @@ +CompilationUnit | Misti

Represents a Compilation Unit, encapsulating the information necessary for +analyzing a single Tact project.

+

Constructors

Properties

The AST of the project.

+
contracts: Map<ContractIdx, Contract>

A mapping from unique IDs of contract entries to contracts.

+
functions: Map<CFGIdx, CFG>

A mapping from unique IDs of free functions to their CFGs.

+
imports: ImportGraph

A graph showing the connections between project files.

+
projectName: ProjectName

The name of the project this Compilation Unit belongs to.

+

Methods

  • Looks for a CFG with a specific index.

    +

    Parameters

    Returns undefined | CFG

    Found CFG or undefined if not found.

    +
  • Looks for a CFG for a function node with a specific name.

    +

    Parameters

    Returns undefined | CFG

    Found CFG or undefined if not found.

    +
  • Looks for a CFG for a method node with a specific name.

    +

    Parameters

    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..67f6dab7e --- /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: ContractName

      The unique name identifying this contract within the project.

      +
    • methods: Map<CFGIdx, CFG>

      A mapping of method ids to their CFGs.

      +
    • ref: SrcInfo

      AST reference that corresponds to the contract definition.

      +
    • idx: undefined | ContractIdx = undefined

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

      +

    Returns Contract

Properties

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

+
methods: Map<CFGIdx, CFG>

A mapping of method ids to their CFGs.

+

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-1.SetJoinSemilattice.html b/tools/misti/api/classes/internals_lattice-1.SetJoinSemilattice.html new file mode 100644 index 000000000..31edb6344 --- /dev/null +++ b/tools/misti/api/classes/internals_lattice-1.SetJoinSemilattice.html @@ -0,0 +1,10 @@ +SetJoinSemilattice | Misti

Class SetJoinSemilattice<T>

Implementation of a join semilattice for sets.

+

Type Parameters

  • T

    The type of elements in the sets.

    +

Implements

Constructors

Methods

Constructors

Methods

diff --git a/tools/misti/api/classes/internals_lattice-1.SetMeetSemilattice.html b/tools/misti/api/classes/internals_lattice-1.SetMeetSemilattice.html new file mode 100644 index 000000000..478832fd2 --- /dev/null +++ b/tools/misti/api/classes/internals_lattice-1.SetMeetSemilattice.html @@ -0,0 +1,10 @@ +SetMeetSemilattice | Misti

Class SetMeetSemilattice<T>

Implementation of a meet semilattice for sets.

+

Type Parameters

  • T

    The type of elements in the sets.

    +

Implements

Constructors

Methods

Constructors

Methods

diff --git a/tools/misti/api/classes/internals_lattice_generic.SetJoinSemilattice.html b/tools/misti/api/classes/internals_lattice_generic.SetJoinSemilattice.html new file mode 100644 index 000000000..edc9f750c --- /dev/null +++ b/tools/misti/api/classes/internals_lattice_generic.SetJoinSemilattice.html @@ -0,0 +1,10 @@ +SetJoinSemilattice | Misti

Implementation of a join semilattice for sets.

+

Type Parameters

  • T

    The type of elements in the sets.

    +

Implements

Constructors

Methods

Constructors

Methods

  • Returns the bottom element: empty set.

    +

    Returns Set<T>

  • Joins two sets by union.

    +

    Parameters

    • a: Set<T>
    • b: Set<T>

    Returns Set<T>

  • Subset relation: a ≤ b iff a ⊆ b

    +

    Parameters

    • a: Set<T>
    • b: Set<T>

    Returns boolean

diff --git a/tools/misti/api/classes/internals_lattice_generic.SetMeetSemilattice.html b/tools/misti/api/classes/internals_lattice_generic.SetMeetSemilattice.html new file mode 100644 index 000000000..b876f1c65 --- /dev/null +++ b/tools/misti/api/classes/internals_lattice_generic.SetMeetSemilattice.html @@ -0,0 +1,10 @@ +SetMeetSemilattice | Misti

Implementation of a meet semilattice for sets.

+

Type Parameters

  • T

    The type of elements in the sets.

    +

Implements

Constructors

Methods

Constructors

Methods

  • Reverse subset relation: a ≤ b iff b ⊆ a

    +

    Parameters

    • a: Set<T>
    • b: Set<T>

    Returns boolean

  • Meets two sets by intersection.

    +

    Parameters

    • a: Set<T>
    • b: Set<T>

    Returns Set<T>

  • Returns the top element: empty set.

    +

    Returns Set<T>

diff --git a/tools/misti/api/classes/internals_lattice_interval.IntervalLattice.html b/tools/misti/api/classes/internals_lattice_interval.IntervalLattice.html new file mode 100644 index 000000000..03fdd2d6f --- /dev/null +++ b/tools/misti/api/classes/internals_lattice_interval.IntervalLattice.html @@ -0,0 +1,50 @@ +IntervalLattice | Misti

Infinite-length lattice representing interval of numbers.

+

Constructors

Properties

EmptyInterval: Interval = ...
FullInterval: Interval = ...
bottom: Interval = IntervalLattice.EmptyInterval
top: Interval = IntervalLattice.FullInterval

Methods

  • Adds two Nums.

    +

    Parameters

    Returns Num

  • Compare two Nums.

    +

    Parameters

    Returns number

  • Checks if an interval contains zero.

    +

    Parameters

    Returns boolean

  • Divide two Nums.

    +

    Parameters

    Returns Num

  • Parameters

    • i: number

    Returns IntNum

  • Abstract unary - (negation) on intervals.

    +

    Parameters

    Returns Interval

  • Checks if the interval is the empty interval.

    +

    Parameters

    Returns boolean

  • Checks if the interval is the full interval.

    +

    Parameters

    Returns boolean

  • Checks if a Num is zero.

    +

    Parameters

    Returns boolean

  • Finds the maximum of given Num values.

    +

    Parameters

    • Rest...nums: Num[]

    Returns Num

  • Finds the minimum of given Num values.

    +

    Parameters

    • Rest...nums: Num[]

    Returns Num

  • Multiply two Nums.

    +

    Parameters

    Returns Num

  • Negate a Num.

    +

    Parameters

    Returns Num

  • Number as interval.

    +

    Parameters

    • i: number

    Returns Interval

  • Helper method to display Num as string

    +

    Parameters

    Returns string

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..52b30cbf8 --- /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..38339849e --- /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

  • 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.QuietLogger.html b/tools/misti/api/classes/internals_logger.QuietLogger.html new file mode 100644 index 000000000..404c68221 --- /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..c5af2cdb3 --- /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..1484dc7ce --- /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..280dbcfbe --- /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..0001bc2b1 --- /dev/null +++ b/tools/misti/api/classes/internals_solver_worklist.WorklistSolver.html @@ -0,0 +1,12 @@ +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_config.TactConfigManager.html b/tools/misti/api/classes/internals_tact_config.TactConfigManager.html new file mode 100644 index 000000000..7f48e3568 --- /dev/null +++ b/tools/misti/api/classes/internals_tact_config.TactConfigManager.html @@ -0,0 +1,24 @@ +TactConfigManager | Misti

Manages the logic around the Tact configuration file.

+

Tact config describes the structure of the project, and includes the entry +points to run compilation and analysis on.

+

Methods

  • Find the project config based on the provided name.

    +

    Parameters

    Returns undefined | {
        mode?:
            | "fullWithDecompilation"
            | "full"
            | "funcOnly"
            | "checkOnly";
        name: string;
        options?: {
            debug?: boolean;
            experimental?: {
                inline?: boolean;
            };
            external?: boolean;
            interfacesGetter?: boolean;
            ipfsAbiGetter?: boolean;
            masterchain?: boolean;
        };
        output: string;
        path: string;
    }

  • Find the project config based on the provided path.

    +

    Parameters

    • projectPath: string

    Returns undefined | {
        mode?:
            | "fullWithDecompilation"
            | "full"
            | "funcOnly"
            | "checkOnly";
        name: string;
        options?: {
            debug?: boolean;
            experimental?: {
                inline?: boolean;
            };
            external?: boolean;
            interfacesGetter?: boolean;
            ipfsAbiGetter?: boolean;
            masterchain?: boolean;
        };
        output: string;
        path: string;
    }

  • Returns {
        $schema?: string;
        projects: {
            mode?:
                | "fullWithDecompilation"
                | "full"
                | "funcOnly"
                | "checkOnly";
            name: string;
            options?: {
                debug?: boolean;
                experimental?: {
                    inline?: boolean;
                };
                external?: boolean;
                interfacesGetter?: boolean;
                ipfsAbiGetter?: boolean;
                masterchain?: boolean;
            };
            output: string;
            path: string;
        }[];
    }

    • Optional$schema?: string
    • projects: {
          mode?:
              | "fullWithDecompilation"
              | "full"
              | "funcOnly"
              | "checkOnly";
          name: string;
          options?: {
              debug?: boolean;
              experimental?: {
                  inline?: boolean;
              };
              external?: boolean;
              interfacesGetter?: boolean;
              ipfsAbiGetter?: boolean;
              masterchain?: boolean;
          };
          output: string;
          path: string;
      }[]
  • Returns absolute paths to entry points specified in the Tact configuration file.

    +

    Returns string[]

  • Gets projects defined within the configuration file.

    +

    Returns {
        mode?:
            | "fullWithDecompilation"
            | "full"
            | "funcOnly"
            | "checkOnly";
        name: string;
        options?: {
            debug?: boolean;
            experimental?: {
                inline?: boolean;
            };
            external?: boolean;
            interfacesGetter?: boolean;
            ipfsAbiGetter?: boolean;
            masterchain?: boolean;
        };
        output: string;
        path: string;
    }[]

  • Returns an absolute path or the project based on the project path.

    +

    Parameters

    • projectPath: string

    Returns string

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..408a5d3ee --- /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..9a2bc0ac4 --- /dev/null +++ b/tools/misti/api/classes/internals_warnings.MistiTactWarning.html @@ -0,0 +1,24 @@ +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

  • Checks whether this warning is suppressing using a Misti annotation.

    +

    Returns boolean

  • Constructs a warning object with a description and the source code location.

    +

    Parameters

    • 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..e6841f0d2 --- /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

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..cc6c36943 --- /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

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..bda85ce6d --- /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_dumpImports.DumpImports.html b/tools/misti/api/classes/tools_dumpImports.DumpImports.html new file mode 100644 index 000000000..b434d3b74 --- /dev/null +++ b/tools/misti/api/classes/tools_dumpImports.DumpImports.html @@ -0,0 +1,20 @@ +DumpImports | Misti

A tool that dumps the import graph of the given compilation unit.

+

Hierarchy (view full)

  • Tool<DumpImportGraphOptions>
    • DumpImports

Constructors

Properties

options: DumpImportGraphOptions

User-defined options for the tool merged with the default options.

+

Accessors

  • get defaultOptions(): DumpImportGraphOptions
  • The default options for the tool.

    +

    Returns DumpImportGraphOptions

  • 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..1a98a5040 --- /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

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..4253c859f --- /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..d221dbb34 --- /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..f70c46f70 --- /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..334d815c6 --- /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..c30845166 --- /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..5a0a20bc1 --- /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..ceb37754a --- /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..934d0add3 --- /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..27a9146ef --- /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..440310fca --- /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..11481e1a2 --- /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..e92ae65ae --- /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..5c1ed233f --- /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..ca662cf7a --- /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..564453778 --- /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_annotation.getMistiAnnotation.html b/tools/misti/api/functions/internals_annotation.getMistiAnnotation.html new file mode 100644 index 000000000..eb1616f01 --- /dev/null +++ b/tools/misti/api/functions/internals_annotation.getMistiAnnotation.html @@ -0,0 +1,4 @@ +getMistiAnnotation | Misti
  • Retrieves the Misti annotation from the current source location if present.

    +

    These can be single or multi-line comments on the current or previous line +annotated with SUPPRESS_MARKER.

    +

    Parameters

    • loc: SrcInfo

    Returns MistiAnnotation | null

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..79f10929d --- /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..1aef489a8 --- /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_imports.ParserHack.parseImports.html b/tools/misti/api/functions/internals_ir_builders_imports.ParserHack.parseImports.html new file mode 100644 index 000000000..de3e59fd8 --- /dev/null +++ b/tools/misti/api/functions/internals_ir_builders_imports.ParserHack.parseImports.html @@ -0,0 +1,4 @@ +parseImports | Misti
diff --git a/tools/misti/api/functions/internals_ir_builders_ir.createIR.html b/tools/misti/api/functions/internals_ir_builders_ir.createIR.html new file mode 100644 index 000000000..699201198 --- /dev/null +++ b/tools/misti/api/functions/internals_ir_builders_ir.createIR.html @@ -0,0 +1,5 @@ +createIR | Misti
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..34a01b863 --- /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..b815f2f42 --- /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..b775249d8 --- /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..649eed77c --- /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_lattice_num.intNum-1.html b/tools/misti/api/functions/internals_lattice_num.intNum-1.html new file mode 100644 index 000000000..7f62e8324 --- /dev/null +++ b/tools/misti/api/functions/internals_lattice_num.intNum-1.html @@ -0,0 +1 @@ +intNum | Misti
  • Parameters

    • value: number

    Returns IntNum

diff --git a/tools/misti/api/functions/internals_lattice_num.mInf-1.html b/tools/misti/api/functions/internals_lattice_num.mInf-1.html new file mode 100644 index 000000000..adc7561b7 --- /dev/null +++ b/tools/misti/api/functions/internals_lattice_num.mInf-1.html @@ -0,0 +1 @@ +mInf | Misti
  • Returns MInf

diff --git a/tools/misti/api/functions/internals_lattice_num.pInf-1.html b/tools/misti/api/functions/internals_lattice_num.pInf-1.html new file mode 100644 index 000000000..dd65d56e3 --- /dev/null +++ b/tools/misti/api/functions/internals_lattice_num.pInf-1.html @@ -0,0 +1 @@ +pInf | Misti
  • Returns PInf

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..6663f3102 --- /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..59e895eee --- /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..57e360dfe --- /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..d2b63e0d4 --- /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..e8a41c213 --- /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..3308fa73a --- /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..514559466 --- /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..4b38cd5bc --- /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..803a95523 --- /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..2c03c505b --- /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..cd63d3780 --- /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_parser.parseTactProject.html b/tools/misti/api/functions/internals_tact_parser.parseTactProject.html new file mode 100644 index 000000000..b6e20a8d7 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_parser.parseTactProject.html @@ -0,0 +1,5 @@ +parseTactProject | Misti
  • Parses the project defined in the Tact configuration file, generating its AST.

    +

    Parameters

    • mistiCtx: MistiContext

      Misti context

      +
    • projectConfig: {
          mode?:
              | "fullWithDecompilation"
              | "full"
              | "funcOnly"
              | "checkOnly";
          name: string;
          options?: {
              debug?: boolean;
              experimental?: {
                  inline?: boolean;
              };
              external?: boolean;
              interfacesGetter?: boolean;
              ipfsAbiGetter?: boolean;
              masterchain?: boolean;
          };
          output: string;
          path: string;
      }
      • Optionalmode?:
            | "fullWithDecompilation"
            | "full"
            | "funcOnly"
            | "checkOnly"
      • name: string
      • Optionaloptions?: {
            debug?: boolean;
            experimental?: {
                inline?: boolean;
            };
            external?: boolean;
            interfacesGetter?: boolean;
            ipfsAbiGetter?: boolean;
            masterchain?: boolean;
        }
        • Optionaldebug?: boolean
        • Optionalexperimental?: {
              inline?: boolean;
          }
          • Optionalinline?: boolean
        • Optionalexternal?: boolean
        • OptionalinterfacesGetter?: boolean
        • OptionalipfsAbiGetter?: boolean
        • Optionalmasterchain?: boolean
      • output: string
      • path: string
    • projectRoot: string

      Absolute path to the root the project

      +

    Returns AstStore | never

    A mapping of project names to their corresponding ASTs.

    +
diff --git a/tools/misti/api/functions/internals_tact_stdlib.definedInStdlib.html b/tools/misti/api/functions/internals_tact_stdlib.definedInStdlib.html new file mode 100644 index 000000000..f038e6a7c --- /dev/null +++ b/tools/misti/api/functions/internals_tact_stdlib.definedInStdlib.html @@ -0,0 +1,5 @@ +definedInStdlib | Misti
  • Checks if a given location or file path is defined in the Tact stdlib.

    +

    Parameters

    • ctx: MistiContext

      MistiContext object

      +
    • locOrPath: string | SrcInfo

      SrcInfo object or string file path

      +

    Returns boolean

    boolean indicating if the location is in the stdlib

    +
diff --git a/tools/misti/api/functions/internals_tact_stdlib.getStdlibPath.html b/tools/misti/api/functions/internals_tact_stdlib.getStdlibPath.html new file mode 100644 index 000000000..78942c09c --- /dev/null +++ b/tools/misti/api/functions/internals_tact_stdlib.getStdlibPath.html @@ -0,0 +1,3 @@ +getStdlibPath | Misti
  • Returns an absolute path to Tact stdlib.

    +

    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_tact_util.collectConditions.html b/tools/misti/api/functions/internals_tact_util.collectConditions.html new file mode 100644 index 000000000..643544ebc --- /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..cf863ab0a --- /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..e401fa718 --- /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..3b3836506 --- /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..fc7bb109e --- /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..b863d6c7e --- /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..17bf3cbc0 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.isSelf.html @@ -0,0 +1,2 @@ +isSelf | Misti
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..7a3c68a12 --- /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..1e45b05e3 --- /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..244e6cd03 --- /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..8fb309a9d --- /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..e779bbfe3 --- /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.srcInfoToString.html b/tools/misti/api/functions/internals_tact_util.srcInfoToString.html new file mode 100644 index 000000000..ee5530fd4 --- /dev/null +++ b/tools/misti/api/functions/internals_tact_util.srcInfoToString.html @@ -0,0 +1,2 @@ +srcInfoToString | Misti
  • Converts SrcInfo to the string representation shown to the user.

    +

    Parameters

    • loc: SrcInfo

    Returns string

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..91b75165c --- /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.hasSubdirs.html b/tools/misti/api/functions/internals_util.hasSubdirs.html new file mode 100644 index 000000000..375d49fb6 --- /dev/null +++ b/tools/misti/api/functions/internals_util.hasSubdirs.html @@ -0,0 +1,2 @@ +hasSubdirs | Misti
  • Checks if there are subdirectories present in the absolute path.

    +

    Parameters

    • filePath: string
    • subdirs: string[]

    Returns boolean

diff --git a/tools/misti/api/functions/internals_util.intersectLists.html b/tools/misti/api/functions/internals_util.intersectLists.html new file mode 100644 index 000000000..0c5e83f07 --- /dev/null +++ b/tools/misti/api/functions/internals_util.intersectLists.html @@ -0,0 +1 @@ +intersectLists | Misti

Function intersectLists

diff --git a/tools/misti/api/functions/internals_util.intersectMaps.html b/tools/misti/api/functions/internals_util.intersectMaps.html new file mode 100644 index 000000000..d72918954 --- /dev/null +++ b/tools/misti/api/functions/internals_util.intersectMaps.html @@ -0,0 +1 @@ +intersectMaps | Misti

Function intersectMaps

diff --git a/tools/misti/api/functions/internals_util.intersectSets.html b/tools/misti/api/functions/internals_util.intersectSets.html new file mode 100644 index 000000000..cdaeee86f --- /dev/null +++ b/tools/misti/api/functions/internals_util.intersectSets.html @@ -0,0 +1 @@ +intersectSets | Misti

Function intersectSets

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..9f2652572 --- /dev/null +++ b/tools/misti/api/functions/internals_util.isListSubsetOf.html @@ -0,0 +1 @@ +isListSubsetOf | Misti

Function isListSubsetOf

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..4a11f7cd3 --- /dev/null +++ b/tools/misti/api/functions/internals_util.isMapSubsetOf.html @@ -0,0 +1 @@ +isMapSubsetOf | Misti

Function isMapSubsetOf

diff --git a/tools/misti/api/functions/internals_util.isSetSubsetOf.html b/tools/misti/api/functions/internals_util.isSetSubsetOf.html new file mode 100644 index 000000000..0736a9556 --- /dev/null +++ b/tools/misti/api/functions/internals_util.isSetSubsetOf.html @@ -0,0 +1 @@ +isSetSubsetOf | Misti

Function isSetSubsetOf

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..a2be5c4ef --- /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..daa824794 --- /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..cf58d0960 --- /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..179ea9007 --- /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..85e6fec07 --- /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..d5a9432f5 --- /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..05a32200e --- /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..35707d567 --- /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..d229d8b3a --- /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..49c19531c --- /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..a174b85d0 --- /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..399f37090 --- /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..938e9c056 --- /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.

+ +
    +
  • Code Analysis: Identify and fix potential security flaws and code problems early in the development cycle.
  • +
  • CI/CD Integration: +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. +

    (optional) Install Soufflé to enable more built-in functionality.

    +
  2. +
  3. +

    Install Misti:

    +
  4. +
+
npm install -g @nowarp/misti
+
+ +
    +
  1. Run Misti by specifying a Tact contract, project config, or directory to check:
  2. +
+
misti path/to/contracts
+
+ +

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..289fbc26f --- /dev/null +++ b/tools/misti/api/interfaces/cli_options.CLIOptions.html @@ -0,0 +1,19 @@ +CLIOptions | Misti

Interface CLIOptions

interface CLIOptions {
    allDetectors: boolean;
    colors: boolean;
    config: undefined | string;
    disabledDetectors: undefined | string[];
    enabledDetectors: undefined | string[];
    listDetectors: boolean;
    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[]
listDetectors: boolean
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..fc56e4142 --- /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..257ad87af --- /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-1.JoinSemilattice.html b/tools/misti/api/interfaces/internals_lattice-1.JoinSemilattice.html new file mode 100644 index 000000000..64737fe04 --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice-1.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.

    +

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.

    +
  • Determines if one element in the semilattice is less than or equal to another element.

    +

    Parameters

    • a: T

      The element to compare.

      +
    • 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-1.MeetSemilattice.html b/tools/misti/api/interfaces/internals_lattice-1.MeetSemilattice.html new file mode 100644 index 000000000..a8c6f10cd --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice-1.MeetSemilattice.html @@ -0,0 +1,16 @@ +MeetSemilattice | Misti

Interface MeetSemilattice<T>

Interface for a meet semilattice that introduces the meet operation.

+
interface MeetSemilattice<T> {
    leq(a: T, b: T): boolean;
    meet(a: T, b: T): T;
    top(): T;
}

Type Parameters

  • T

    The type of elements in the semilattice.

    +

Implemented by

Methods

Methods

  • Determines if one element in the semilattice is less than or equal to another element.

    +

    Parameters

    • a: T

      The element to compare.

      +
    • 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.

    +
diff --git a/tools/misti/api/interfaces/internals_lattice_generic.JoinSemilattice.html b/tools/misti/api/interfaces/internals_lattice_generic.JoinSemilattice.html new file mode 100644 index 000000000..634831357 --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice_generic.JoinSemilattice.html @@ -0,0 +1,16 @@ +JoinSemilattice | Misti

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.

    +

Implemented by

Methods

Methods

  • Represents the bottom element of the lattice.

    +

    Returns T

    The bottom element.

    +
  • 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.

    +
  • Determines if one element in the semilattice is less than or equal to another element.

    +

    Parameters

    • a: T

      The element to compare.

      +
    • 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_generic.MeetSemilattice.html b/tools/misti/api/interfaces/internals_lattice_generic.MeetSemilattice.html new file mode 100644 index 000000000..49804be66 --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice_generic.MeetSemilattice.html @@ -0,0 +1,16 @@ +MeetSemilattice | Misti

Interface for a meet semilattice that introduces the meet operation.

+
interface MeetSemilattice<T> {
    leq(a: T, b: T): boolean;
    meet(a: T, b: T): T;
    top(): T;
}

Type Parameters

  • T

    The type of elements in the semilattice.

    +

Implemented by

Methods

Methods

  • Determines if one element in the semilattice is less than or equal to another element.

    +

    Parameters

    • a: T

      The element to compare.

      +
    • 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.

    +
  • Represents the top element of the lattice.

    +

    Returns T

    The top element.

    +
diff --git a/tools/misti/api/interfaces/internals_lattice_num.IntNum.html b/tools/misti/api/interfaces/internals_lattice_num.IntNum.html new file mode 100644 index 000000000..858b8913b --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice_num.IntNum.html @@ -0,0 +1,3 @@ +IntNum | Misti
interface IntNum {
    kind: "IntNum";
    value: number;
}

Properties

Properties

kind: "IntNum"
value: number
diff --git a/tools/misti/api/interfaces/internals_lattice_num.MInf.html b/tools/misti/api/interfaces/internals_lattice_num.MInf.html new file mode 100644 index 000000000..fda0e3fe3 --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice_num.MInf.html @@ -0,0 +1,3 @@ +MInf | Misti

Negative infinitiy.

+
interface MInf {
    kind: "MInf";
}

Properties

Properties

kind: "MInf"
diff --git a/tools/misti/api/interfaces/internals_lattice_num.PInf.html b/tools/misti/api/interfaces/internals_lattice_num.PInf.html new file mode 100644 index 000000000..072883e3e --- /dev/null +++ b/tools/misti/api/interfaces/internals_lattice_num.PInf.html @@ -0,0 +1,3 @@ +PInf | Misti

Positive infinitiy.

+
interface PInf {
    kind: "PInf";
}

Properties

Properties

kind: "PInf"
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..e1dca0a22 --- /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..1de912cbf --- /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..a94a0097c --- /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.svg b/tools/misti/api/media/misti.svg new file mode 100644 index 000000000..de6982a18 --- /dev/null +++ b/tools/misti/api/media/misti.svg @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/misti/api/modules/cli.html b/tools/misti/api/modules/cli.html new file mode 100644 index 000000000..157e40c59 --- /dev/null +++ b/tools/misti/api/modules/cli.html @@ -0,0 +1,25 @@ +cli | 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..c36ed8bd1 --- /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..fa76e3b1f --- /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..cd16ab004 --- /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..36507eec3 --- /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_types.html b/tools/misti/api/modules/cli_types.html new file mode 100644 index 000000000..4a6a3242d --- /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..7d97243da --- /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..ae72b6d4f --- /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..7d34bcd4c --- /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..f868a3d04 --- /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..c01cb3287 --- /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..732e511ad --- /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..6d72f9eb8 --- /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..ff72c6526 --- /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..a0ad5d591 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_duplicatedCondition.html @@ -0,0 +1,2 @@ +detectors/builtin/duplicatedCondition | Misti
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..40983af71 --- /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..cc855c54e --- /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..eff605ba5 --- /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..907278f57 --- /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..46cf85833 --- /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..19bdaf0d8 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_optimalMathFunction.html @@ -0,0 +1,2 @@ +detectors/builtin/optimalMathFunction | Misti
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..bfadcc374 --- /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..6afd799a6 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_preferredStdlibApi.html @@ -0,0 +1,2 @@ +detectors/builtin/preferredStdlibApi | Misti
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..61ce485c1 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_readOnlyVariables.html @@ -0,0 +1,2 @@ +detectors/builtin/readOnlyVariables | Misti
diff --git a/tools/misti/api/modules/detectors_builtin_sendInLoop.html b/tools/misti/api/modules/detectors_builtin_sendInLoop.html new file mode 100644 index 000000000..a3d1d92fd --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_sendInLoop.html @@ -0,0 +1,2 @@ +detectors/builtin/sendInLoop | Misti

Module detectors/builtin/sendInLoop

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_shortCircuitCondition.html b/tools/misti/api/modules/detectors_builtin_shortCircuitCondition.html new file mode 100644 index 000000000..166506887 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_shortCircuitCondition.html @@ -0,0 +1,2 @@ +detectors/builtin/shortCircuitCondition | Misti
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..afcb8a74b --- /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_suspiciousMessageMode.html b/tools/misti/api/modules/detectors_builtin_suspiciousMessageMode.html new file mode 100644 index 000000000..9a1e381cc --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_suspiciousMessageMode.html @@ -0,0 +1,2 @@ +detectors/builtin/suspiciousMessageMode | Misti
diff --git a/tools/misti/api/modules/detectors_builtin_unboundLoop.html b/tools/misti/api/modules/detectors_builtin_unboundLoop.html new file mode 100644 index 000000000..66d3ef997 --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_unboundLoop.html @@ -0,0 +1,2 @@ +detectors/builtin/unboundLoop | Misti

Module detectors/builtin/unboundLoop

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_unboundMap.html b/tools/misti/api/modules/detectors_builtin_unboundMap.html new file mode 100644 index 000000000..b53e3bc7e --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_unboundMap.html @@ -0,0 +1,2 @@ +detectors/builtin/unboundMap | Misti

Module detectors/builtin/unboundMap

Index

Classes

diff --git a/tools/misti/api/modules/detectors_builtin_unusedExpressionResult.html b/tools/misti/api/modules/detectors_builtin_unusedExpressionResult.html new file mode 100644 index 000000000..c49a1aa6c --- /dev/null +++ b/tools/misti/api/modules/detectors_builtin_unusedExpressionResult.html @@ -0,0 +1,2 @@ +detectors/builtin/unusedExpressionResult | Misti
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..44b3d5c9a --- /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..1d34e3f05 --- /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..bb4882fbb --- /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..856df38cb --- /dev/null +++ b/tools/misti/api/modules/index.html @@ -0,0 +1,89 @@ +index | Misti

Module index

References

Re-exports ASTDetector
Re-exports BASE_DOC_URL
Re-exports BuiltInDetectors
Re-exports DEFAULT_STDLIB_PATH_ELEMENTS
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 LogFunction
Re-exports LogLevel
Re-exports Logger
Re-exports MISTI_VERSION
Re-exports MeetSemilattice
Re-exports MistiAnnotation
Re-exports MistiConfig
Re-exports MistiContext
Re-exports MistiEnv
Re-exports MistiTactWarning
Re-exports MutatedElement
Re-exports QuietLogger
Re-exports SUPPRESS_MARKER
Re-exports Semilattice
Re-exports SetJoinSemilattice
Re-exports SetMeetSemilattice
Re-exports Severity
Re-exports SouffleDetector
Re-exports SrcInfoSet
Re-exports TACT_VERSION
Re-exports TactConfigManager
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 definedInStdlib
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 getMistiAnnotation
Re-exports getStdlibPath
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 parseTactProject
Re-exports removeSelf
Re-exports severityToString
Renames and re-exports internals/solver
Re-exports srcInfoToString
Re-exports statementsAreEqual
Re-exports throwZodError
Re-exports tryMsg
diff --git a/tools/misti/api/modules/internals_annotation.html b/tools/misti/api/modules/internals_annotation.html new file mode 100644 index 000000000..bb773f05b --- /dev/null +++ b/tools/misti/api/modules/internals_annotation.html @@ -0,0 +1,5 @@ +internals/annotation | Misti

Module internals/annotation

Represents annotations in the comments processed by Misti.

+

Index

Type Aliases

Variables

Functions

diff --git a/tools/misti/api/modules/internals_config.html b/tools/misti/api/modules/internals_config.html new file mode 100644 index 000000000..935287f59 --- /dev/null +++ b/tools/misti/api/modules/internals_config.html @@ -0,0 +1,4 @@ +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..2fc876e5c --- /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..0a4bdf22f --- /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..02a80ee16 --- /dev/null +++ b/tools/misti/api/modules/internals_ir.html @@ -0,0 +1,29 @@ +internals/ir | Misti

Module internals/ir

References

Re-exports AstItemParams
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 Edge
Re-exports EdgeIdx
Re-exports FunctionKind
Re-exports FunctionName
Re-exports ImportDirection
Re-exports ImportEdge
Re-exports ImportEdgeIdx
Re-exports ImportGraph
Re-exports ImportLanguage
Re-exports ImportNode
Re-exports ImportNodeIdx
Re-exports ProjectName
Re-exports TactASTStore
Re-exports TactASTStoreBuilder
Re-exports TactIRBuilder
Re-exports createIR
Re-exports getPredecessors
Re-exports getSuccessors
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..a1a1badff --- /dev/null +++ b/tools/misti/api/modules/internals_ir_astStore.html @@ -0,0 +1,3 @@ +internals/ir/astStore | Misti

Module internals/ir/astStore

Index

Classes

Type Aliases

diff --git a/tools/misti/api/modules/internals_ir_builders.html b/tools/misti/api/modules/internals_ir_builders.html new file mode 100644 index 000000000..3d0c4cc61 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_builders.html @@ -0,0 +1,4 @@ +internals/ir/builders | Misti

Module internals/ir/builders

References

Re-exports TactASTStoreBuilder
Re-exports TactIRBuilder
Re-exports createIR
diff --git a/tools/misti/api/modules/internals_ir_builders_astStore.html b/tools/misti/api/modules/internals_ir_builders_astStore.html new file mode 100644 index 000000000..821086cbc --- /dev/null +++ b/tools/misti/api/modules/internals_ir_builders_astStore.html @@ -0,0 +1,2 @@ +internals/ir/builders/astStore | Misti

Module internals/ir/builders/astStore

Index

Classes

diff --git a/tools/misti/api/modules/internals_ir_builders_imports.ParserHack.html b/tools/misti/api/modules/internals_ir_builders_imports.ParserHack.html new file mode 100644 index 000000000..085b50c0e --- /dev/null +++ b/tools/misti/api/modules/internals_ir_builders_imports.ParserHack.html @@ -0,0 +1,2 @@ +ParserHack | Misti
diff --git a/tools/misti/api/modules/internals_ir_builders_imports.html b/tools/misti/api/modules/internals_ir_builders_imports.html new file mode 100644 index 000000000..4b1225504 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_builders_imports.html @@ -0,0 +1,3 @@ +internals/ir/builders/imports | Misti

Module internals/ir/builders/imports

Index

Namespaces

Classes

diff --git a/tools/misti/api/modules/internals_ir_builders_ir.html b/tools/misti/api/modules/internals_ir_builders_ir.html new file mode 100644 index 000000000..3060e5f07 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_builders_ir.html @@ -0,0 +1,3 @@ +internals/ir/builders/ir | Misti

Module internals/ir/builders/ir

Index

Classes

Functions

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..04f00eace --- /dev/null +++ b/tools/misti/api/modules/internals_ir_cfg.html @@ -0,0 +1,13 @@ +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_imports.html b/tools/misti/api/modules/internals_ir_imports.html new file mode 100644 index 000000000..408d834e7 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_imports.html @@ -0,0 +1,8 @@ +internals/ir/imports | Misti
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..22753d4cf --- /dev/null +++ b/tools/misti/api/modules/internals_ir_indices.IdxGenerator.html @@ -0,0 +1,5 @@ +IdxGenerator | Misti

Generates unique indexes 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..778ddb0cb --- /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..bd3aa2ad6 --- /dev/null +++ b/tools/misti/api/modules/internals_ir_ir.html @@ -0,0 +1,5 @@ +internals/ir/ir | Misti

Module internals/ir/ir

Defined the Intermediate Representation (IR) for Tact used in analysis.

+

Index

Classes

Type Aliases

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..2a50c6f8b --- /dev/null +++ b/tools/misti/api/modules/internals_ir_types.html @@ -0,0 +1,4 @@ +internals/ir/types | Misti

Module internals/ir/types

Index

Type Aliases

diff --git a/tools/misti/api/modules/internals_lattice-1.html b/tools/misti/api/modules/internals_lattice-1.html new file mode 100644 index 000000000..a5ee245ef --- /dev/null +++ b/tools/misti/api/modules/internals_lattice-1.html @@ -0,0 +1,6 @@ +internals/lattice | 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..edda24704 --- /dev/null +++ b/tools/misti/api/modules/internals_lattice.html @@ -0,0 +1,15 @@ +internals/lattice | Misti

Module internals/lattice

References

Re-exports IntNum
Re-exports Interval
Re-exports IntervalLattice
Re-exports JoinSemilattice
Re-exports MInf
Re-exports MeetSemilattice
Re-exports Num
Re-exports PInf
Re-exports Semilattice
Re-exports SetJoinSemilattice
Re-exports SetMeetSemilattice
Re-exports intNum
Re-exports mInf
Re-exports pInf
diff --git a/tools/misti/api/modules/internals_lattice_generic.html b/tools/misti/api/modules/internals_lattice_generic.html new file mode 100644 index 000000000..dfc950e74 --- /dev/null +++ b/tools/misti/api/modules/internals_lattice_generic.html @@ -0,0 +1,6 @@ +internals/lattice/generic | Misti

Module internals/lattice/generic

Index

Classes

Interfaces

Type Aliases

diff --git a/tools/misti/api/modules/internals_lattice_interval.html b/tools/misti/api/modules/internals_lattice_interval.html new file mode 100644 index 000000000..03cf87ca9 --- /dev/null +++ b/tools/misti/api/modules/internals_lattice_interval.html @@ -0,0 +1,3 @@ +internals/lattice/interval | Misti

Module internals/lattice/interval

Index

Classes

Type Aliases

diff --git a/tools/misti/api/modules/internals_lattice_num.html b/tools/misti/api/modules/internals_lattice_num.html new file mode 100644 index 000000000..66f23503a --- /dev/null +++ b/tools/misti/api/modules/internals_lattice_num.html @@ -0,0 +1,11 @@ +internals/lattice/num | Misti

Module internals/lattice/num

Numbers that could include positive and negative infinitiy.

+

We use these instead of number to distinguish infinities, since in Node.js +positive and negative infinities are numbers as well.

+

Index

Interfaces

Type Aliases

Num +

Functions

diff --git a/tools/misti/api/modules/internals_logger.html b/tools/misti/api/modules/internals_logger.html new file mode 100644 index 000000000..6effc5cdc --- /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..ac22ef72d --- /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..6147d650d --- /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..e8e846eee --- /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..252ab82d4 --- /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..9b10df5de --- /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..6aed2c346 --- /dev/null +++ b/tools/misti/api/modules/internals_tact.html @@ -0,0 +1,33 @@ +internals/tact | Misti

Module internals/tact

References

Re-exports DEFAULT_STDLIB_PATH_ELEMENTS
Re-exports MutatedElement
Re-exports SrcInfoSet
Re-exports TactConfigManager
Re-exports collectConditions
Re-exports collectFields
Re-exports collectMutations
Re-exports definedInStdlib
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 getStdlibPath
Re-exports hasInExpressions
Re-exports isPrimitiveLiteral
Re-exports isSelf
Re-exports isSelfAccess
Re-exports isStdlibMutationMethod
Re-exports mutationNames
Re-exports nodesAreEqual
Re-exports parseTactProject
Re-exports removeSelf
Re-exports srcInfoToString
Re-exports statementsAreEqual
diff --git a/tools/misti/api/modules/internals_tact_config.html b/tools/misti/api/modules/internals_tact_config.html new file mode 100644 index 000000000..ccd892942 --- /dev/null +++ b/tools/misti/api/modules/internals_tact_config.html @@ -0,0 +1,2 @@ +internals/tact/config | Misti

Module internals/tact/config

Index

Classes

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..dc45e1d5d --- /dev/null +++ b/tools/misti/api/modules/internals_tact_constEval.html @@ -0,0 +1,5 @@ +internals/tact/constEval | Misti
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..b716797ae --- /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_parser.html b/tools/misti/api/modules/internals_tact_parser.html new file mode 100644 index 000000000..fabe15650 --- /dev/null +++ b/tools/misti/api/modules/internals_tact_parser.html @@ -0,0 +1,2 @@ +internals/tact/parser | Misti

Module internals/tact/parser

Index

Functions

diff --git a/tools/misti/api/modules/internals_tact_stdlib.html b/tools/misti/api/modules/internals_tact_stdlib.html new file mode 100644 index 000000000..622dabb43 --- /dev/null +++ b/tools/misti/api/modules/internals_tact_stdlib.html @@ -0,0 +1,4 @@ +internals/tact/stdlib | 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..1603a6fbe --- /dev/null +++ b/tools/misti/api/modules/internals_tact_util.html @@ -0,0 +1,17 @@ +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..74920a288 --- /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..75087275b --- /dev/null +++ b/tools/misti/api/modules/internals_util.html @@ -0,0 +1,13 @@ +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..913b5ef73 --- /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..58589bda1 --- /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..1bc1b8156 --- /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..d02a0ddbe --- /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..9468d3ad8 --- /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..3acb0fd0c --- /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_dumpImports.html b/tools/misti/api/modules/tools_dumpImports.html new file mode 100644 index 000000000..f43a2d5cb --- /dev/null +++ b/tools/misti/api/modules/tools_dumpImports.html @@ -0,0 +1,2 @@ +tools/dumpImports | Misti

Module tools/dumpImports

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..aa226683d --- /dev/null +++ b/tools/misti/api/modules/tools_tool.html @@ -0,0 +1,7 @@ +tools/tool | Misti
diff --git a/tools/misti/api/modules/version.html b/tools/misti/api/modules/version.html new file mode 100644 index 000000000..2692ea452 --- /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..7cebf4c5e --- /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..fb8af36eb --- /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..1f4c52c8a --- /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..8f0c9c95f --- /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..e95cc3506 --- /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..dd5643cb9 --- /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..1e29141a8 --- /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..6fe6d8574 --- /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..2bbcdad1c --- /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..26201254f --- /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..73768699f --- /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..5febb8d14 --- /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..e6a951754 --- /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_annotation.MistiAnnotation.html b/tools/misti/api/types/internals_annotation.MistiAnnotation.html new file mode 100644 index 000000000..572501cd8 --- /dev/null +++ b/tools/misti/api/types/internals_annotation.MistiAnnotation.html @@ -0,0 +1,2 @@ +MistiAnnotation | Misti
MistiAnnotation: {
    detectors: string[];
    kind: "suppress";
}

Represents a Misti annotation.

+
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..5e39129bd --- /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_astStore.AstItemParams.html b/tools/misti/api/types/internals_ir_astStore.AstItemParams.html new file mode 100644 index 000000000..3db5c479c --- /dev/null +++ b/tools/misti/api/types/internals_ir_astStore.AstItemParams.html @@ -0,0 +1,4 @@ +AstItemParams | Misti
AstItemParams: Partial<{
    filename?: string;
    includeStdlib: boolean;
}>

Parameters for filtering AST items.

+

Type declaration

  • Optionalfilename?: string

    Filter items by specific filename.

    +
  • includeStdlib: boolean

    Include standard library items if true.

    +
diff --git a/tools/misti/api/types/internals_ir_cfg.BasicBlockIdx.html b/tools/misti/api/types/internals_ir_cfg.BasicBlockIdx.html new file mode 100644 index 000000000..039e8ab4e --- /dev/null +++ b/tools/misti/api/types/internals_ir_cfg.BasicBlockIdx.html @@ -0,0 +1 @@ +BasicBlockIdx | Misti

Type Alias BasicBlockIdx

BasicBlockIdx: number & {
    __brand: unique symbol;
}
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..ab36cb356 --- /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.CFGIdx.html b/tools/misti/api/types/internals_ir_cfg.CFGIdx.html new file mode 100644 index 000000000..983438fb3 --- /dev/null +++ b/tools/misti/api/types/internals_ir_cfg.CFGIdx.html @@ -0,0 +1 @@ +CFGIdx | Misti
CFGIdx: number & {
    __brand: unique symbol;
}
diff --git a/tools/misti/api/types/internals_ir_cfg.EdgeIdx.html b/tools/misti/api/types/internals_ir_cfg.EdgeIdx.html new file mode 100644 index 000000000..fe1d85d0e --- /dev/null +++ b/tools/misti/api/types/internals_ir_cfg.EdgeIdx.html @@ -0,0 +1 @@ +EdgeIdx | Misti
EdgeIdx: number & {
    __brand: unique symbol;
}
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..f73344169 --- /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_imports.ImportDirection.html b/tools/misti/api/types/internals_ir_imports.ImportDirection.html new file mode 100644 index 000000000..0d5d5f159 --- /dev/null +++ b/tools/misti/api/types/internals_ir_imports.ImportDirection.html @@ -0,0 +1 @@ +ImportDirection | Misti
ImportDirection: "forward" | "backward"
diff --git a/tools/misti/api/types/internals_ir_imports.ImportEdgeIdx.html b/tools/misti/api/types/internals_ir_imports.ImportEdgeIdx.html new file mode 100644 index 000000000..6a6e3cd8f --- /dev/null +++ b/tools/misti/api/types/internals_ir_imports.ImportEdgeIdx.html @@ -0,0 +1 @@ +ImportEdgeIdx | Misti
ImportEdgeIdx: number & {
    __brand: unique symbol;
}
diff --git a/tools/misti/api/types/internals_ir_imports.ImportLanguage.html b/tools/misti/api/types/internals_ir_imports.ImportLanguage.html new file mode 100644 index 000000000..813c8fbe8 --- /dev/null +++ b/tools/misti/api/types/internals_ir_imports.ImportLanguage.html @@ -0,0 +1 @@ +ImportLanguage | Misti
ImportLanguage: "tact" | "func"
diff --git a/tools/misti/api/types/internals_ir_imports.ImportNodeIdx.html b/tools/misti/api/types/internals_ir_imports.ImportNodeIdx.html new file mode 100644 index 000000000..cc52b614a --- /dev/null +++ b/tools/misti/api/types/internals_ir_imports.ImportNodeIdx.html @@ -0,0 +1 @@ +ImportNodeIdx | Misti
ImportNodeIdx: number & {
    __brand: unique symbol;
}
diff --git a/tools/misti/api/types/internals_ir_ir.ContractIdx.html b/tools/misti/api/types/internals_ir_ir.ContractIdx.html new file mode 100644 index 000000000..fdbb0c718 --- /dev/null +++ b/tools/misti/api/types/internals_ir_ir.ContractIdx.html @@ -0,0 +1 @@ +ContractIdx | Misti

Type Alias ContractIdx

ContractIdx: number & {
    __brand: unique symbol;
}
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..6cc529fd4 --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.ContractName.html @@ -0,0 +1 @@ +ContractName | Misti
ContractName: string & {
    __brand: unique symbol;
}
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..609642760 --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.FunctionName.html @@ -0,0 +1 @@ +FunctionName | Misti
FunctionName: string & {
    __brand: unique symbol;
}
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..47a513d7d --- /dev/null +++ b/tools/misti/api/types/internals_ir_types.ProjectName.html @@ -0,0 +1 @@ +ProjectName | Misti
ProjectName: string & {
    __brand: unique symbol;
}
diff --git a/tools/misti/api/types/internals_lattice-1.Semilattice.html b/tools/misti/api/types/internals_lattice-1.Semilattice.html new file mode 100644 index 000000000..d6f3c349f --- /dev/null +++ b/tools/misti/api/types/internals_lattice-1.Semilattice.html @@ -0,0 +1,2 @@ +Semilattice | Misti

Type Alias Semilattice<T>

Semilattice<T>: JoinSemilattice<T> | MeetSemilattice<T>

Union type representing either a join or meet semilattice.

+

Type Parameters

  • T
diff --git a/tools/misti/api/types/internals_lattice_generic.Semilattice.html b/tools/misti/api/types/internals_lattice_generic.Semilattice.html new file mode 100644 index 000000000..ca5a117d5 --- /dev/null +++ b/tools/misti/api/types/internals_lattice_generic.Semilattice.html @@ -0,0 +1,2 @@ +Semilattice | Misti
Semilattice<T>: JoinSemilattice<T> | MeetSemilattice<T>

Union type representing either a join or meet semilattice.

+

Type Parameters

  • T
diff --git a/tools/misti/api/types/internals_lattice_interval.Interval.html b/tools/misti/api/types/internals_lattice_interval.Interval.html new file mode 100644 index 000000000..17a40a69b --- /dev/null +++ b/tools/misti/api/types/internals_lattice_interval.Interval.html @@ -0,0 +1 @@ +Interval | Misti
Interval: [Num, Num]
diff --git a/tools/misti/api/types/internals_lattice_num.Num.html b/tools/misti/api/types/internals_lattice_num.Num.html new file mode 100644 index 000000000..2cef5013f --- /dev/null +++ b/tools/misti/api/types/internals_lattice_num.Num.html @@ -0,0 +1 @@ +Num | Misti
Num: IntNum | PInf | MInf
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..c18ce1369 --- /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..db9104cab --- /dev/null +++ b/tools/misti/api/types/internals_solver_worklist.AnalysisKind.html @@ -0,0 +1,7 @@ +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.
  • +
+
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..e7dcf6c35 --- /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..6790ebb76 --- /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..08f1d649b --- /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..c2b7c5bf4 --- /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..686821f5b --- /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..6f2543aa5 --- /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_annotation.SUPPRESS_MARKER.html b/tools/misti/api/variables/internals_annotation.SUPPRESS_MARKER.html new file mode 100644 index 000000000..7eb45bb2d --- /dev/null +++ b/tools/misti/api/variables/internals_annotation.SUPPRESS_MARKER.html @@ -0,0 +1,3 @@ +SUPPRESS_MARKER | Misti

Variable SUPPRESS_MARKERConst

SUPPRESS_MARKER: "@misti:suppress" = "@misti:suppress"

The marker used to identify Misti suppress annotations. +Syntax: // @misti:suppress Detector1,Detector2

+
diff --git a/tools/misti/api/variables/internals_tact_stdlib.DEFAULT_STDLIB_PATH_ELEMENTS.html b/tools/misti/api/variables/internals_tact_stdlib.DEFAULT_STDLIB_PATH_ELEMENTS.html new file mode 100644 index 000000000..7dca2801c --- /dev/null +++ b/tools/misti/api/variables/internals_tact_stdlib.DEFAULT_STDLIB_PATH_ELEMENTS.html @@ -0,0 +1,2 @@ +DEFAULT_STDLIB_PATH_ELEMENTS | Misti

Variable DEFAULT_STDLIB_PATH_ELEMENTSConst

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..5a86b62dc --- /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..b3098dbc9 --- /dev/null +++ b/tools/misti/api/variables/version_info.MISTI_VERSION.html @@ -0,0 +1 @@ +MISTI_VERSION | Misti

Variable MISTI_VERSIONConst

MISTI_VERSION: "0.5.0-49c942d" = '0.5.0-49c942d'
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..d5f2fb5a9 --- /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..ae5b6aa9e --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,37 @@ + + + + + +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..ce7b7d93e --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,33 @@ + + + + + +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..539f505ae --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,32 @@ + + + + + +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..4da0c6d1b --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/UnboundLoops/index.html @@ -0,0 +1,36 @@ + + + + + +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..5a2996314 --- /dev/null +++ b/tools/misti/docs/0.1.2/detectors/ZeroAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..c7a932f6a --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/CHANGELOG/index.html @@ -0,0 +1,46 @@ + + + + + +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..ce03c1cfa --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/contributing/index.html @@ -0,0 +1,69 @@ + + + + + +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..f257f8adb --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/custom-detector/index.html @@ -0,0 +1,35 @@ + + + + + +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..76de84e4c --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/design/index.html @@ -0,0 +1,37 @@ + + + + + +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..77237b812 --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/souffle/index.html @@ -0,0 +1,41 @@ + + + + + +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..d2aeec982 --- /dev/null +++ b/tools/misti/docs/0.1.2/hacking/tools/index.html @@ -0,0 +1,54 @@ + + + + + +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..6593b7628 --- /dev/null +++ b/tools/misti/docs/0.1.2/index.html @@ -0,0 +1,40 @@ + + + + + +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..c03e78b83 --- /dev/null +++ b/tools/misti/docs/0.1.2/tutorial/configuration/index.html @@ -0,0 +1,57 @@ + + + + + +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..5f08e22e5 --- /dev/null +++ b/tools/misti/docs/0.1.2/tutorial/getting-started/index.html @@ -0,0 +1,42 @@ + + + + + +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..df6578973 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/BranchDuplicate/index.html @@ -0,0 +1,36 @@ + + + + + +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..6806353e3 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/ConstantAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..bee84e390 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,37 @@ + + + + + +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..915ef08b3 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/DumpIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +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..6983c22c9 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/FieldDoubleInit/index.html @@ -0,0 +1,31 @@ + + + + + +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..1449eafec --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,33 @@ + + + + + +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..0a837a802 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,31 @@ + + + + + +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..03f022635 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,32 @@ + + + + + +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..84eedccf4 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/UnboundLoops/index.html @@ -0,0 +1,36 @@ + + + + + +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..b54eadf5b --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/ZeroAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..d6fb0b422 --- /dev/null +++ b/tools/misti/docs/0.2.0/detectors/index.html @@ -0,0 +1,38 @@ + + + + + +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..8284a3a48 --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/contributing/index.html @@ -0,0 +1,69 @@ + + + + + +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..4ab9b73c1 --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/custom-detector/index.html @@ -0,0 +1,35 @@ + + + + + +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..357fe7198 --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/design/index.html @@ -0,0 +1,37 @@ + + + + + +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..9b4ae7099 --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/souffle/index.html @@ -0,0 +1,41 @@ + + + + + +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..28c54e232 --- /dev/null +++ b/tools/misti/docs/0.2.0/hacking/tools/index.html @@ -0,0 +1,54 @@ + + + + + +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..ca900062f --- /dev/null +++ b/tools/misti/docs/0.2.0/index.html @@ -0,0 +1,40 @@ + + + + + +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..fcbb0eafd --- /dev/null +++ b/tools/misti/docs/0.2.0/tutorial/ci-cd/index.html @@ -0,0 +1,36 @@ + + + + + +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..09be866b0 --- /dev/null +++ b/tools/misti/docs/0.2.0/tutorial/configuration/index.html @@ -0,0 +1,63 @@ + + + + + +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..aa1203dba --- /dev/null +++ b/tools/misti/docs/0.2.0/tutorial/getting-started/index.html @@ -0,0 +1,52 @@ + + + + + +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..a4fdc96b3 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/BranchDuplicate/index.html @@ -0,0 +1,36 @@ + + + + + +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..28341f9e6 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/ConstantAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..931655a81 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,37 @@ + + + + + +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..45aaba0ee --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/DumpIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +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..5a58a7b33 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/FieldDoubleInit/index.html @@ -0,0 +1,31 @@ + + + + + +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..5663daf18 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,33 @@ + + + + + +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..46b08b947 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,31 @@ + + + + + +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..f8c62255b --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,32 @@ + + + + + +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..f200d4a5b --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/UnboundLoops/index.html @@ -0,0 +1,36 @@ + + + + + +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..968e6c637 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/ZeroAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..dca39a023 --- /dev/null +++ b/tools/misti/docs/0.2.1/detectors/index.html @@ -0,0 +1,38 @@ + + + + + +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..f49ec6c5b --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/contributing/index.html @@ -0,0 +1,69 @@ + + + + + +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..a3892e756 --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/custom-detector/index.html @@ -0,0 +1,35 @@ + + + + + +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..a306323dc --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/design/index.html @@ -0,0 +1,37 @@ + + + + + +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..f63551a70 --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/souffle/index.html @@ -0,0 +1,41 @@ + + + + + +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..54b8b4832 --- /dev/null +++ b/tools/misti/docs/0.2.1/hacking/tools/index.html @@ -0,0 +1,54 @@ + + + + + +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..479fa6dc0 --- /dev/null +++ b/tools/misti/docs/0.2.1/index.html @@ -0,0 +1,40 @@ + + + + + +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..8572a732b --- /dev/null +++ b/tools/misti/docs/0.2.1/tutorial/ci-cd/index.html @@ -0,0 +1,36 @@ + + + + + +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..e3e66fcf3 --- /dev/null +++ b/tools/misti/docs/0.2.1/tutorial/configuration/index.html @@ -0,0 +1,63 @@ + + + + + +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..09bdb72f8 --- /dev/null +++ b/tools/misti/docs/0.2.1/tutorial/getting-started/index.html @@ -0,0 +1,52 @@ + + + + + +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..6b4bf78f8 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/BranchDuplicate/index.html @@ -0,0 +1,36 @@ + + + + + +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..589b5e4b1 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/ConstantAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..72b3c850d --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,37 @@ + + + + + +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..f56117414 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/DumpIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +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..9bc4b1415 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/FieldDoubleInit/index.html @@ -0,0 +1,31 @@ + + + + + +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..74de9a96e --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,33 @@ + + + + + +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..3e4a095fb --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,31 @@ + + + + + +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..40c7f4dd6 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,32 @@ + + + + + +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..45a1a4e3a --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/UnboundLoops/index.html @@ -0,0 +1,36 @@ + + + + + +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..dc8ed82c5 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/ZeroAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..8928d1905 --- /dev/null +++ b/tools/misti/docs/0.2.2/detectors/index.html @@ -0,0 +1,38 @@ + + + + + +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..f3c0c3d9e --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/contributing/index.html @@ -0,0 +1,69 @@ + + + + + +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..b1220a702 --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/custom-detector/index.html @@ -0,0 +1,35 @@ + + + + + +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..d18ef269c --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/design/index.html @@ -0,0 +1,37 @@ + + + + + +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..06d6ec6f9 --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/souffle/index.html @@ -0,0 +1,41 @@ + + + + + +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..3cf187c13 --- /dev/null +++ b/tools/misti/docs/0.2.2/hacking/tools/index.html @@ -0,0 +1,54 @@ + + + + + +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..cfc10c459 --- /dev/null +++ b/tools/misti/docs/0.2.2/index.html @@ -0,0 +1,40 @@ + + + + + +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..5a017ceb9 --- /dev/null +++ b/tools/misti/docs/0.2.2/tutorial/blueprint/index.html @@ -0,0 +1,35 @@ + + + + + +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..3a53494c2 --- /dev/null +++ b/tools/misti/docs/0.2.2/tutorial/ci-cd/index.html @@ -0,0 +1,36 @@ + + + + + +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..facecdf59 --- /dev/null +++ b/tools/misti/docs/0.2.2/tutorial/configuration/index.html @@ -0,0 +1,63 @@ + + + + + +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..7e7a62ddc --- /dev/null +++ b/tools/misti/docs/0.2.2/tutorial/getting-started/index.html @@ -0,0 +1,52 @@ + + + + + +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..770f911d3 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/ArgCopyMutation/index.html @@ -0,0 +1,37 @@ + + + + + +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..3440e6ef1 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/AsmIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +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..271b6cff3 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/BranchDuplicate/index.html @@ -0,0 +1,36 @@ + + + + + +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..e9c869991 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/ConstantAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..a07233572 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,37 @@ + + + + + +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..05cfeb94a --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/DumpIsUsed/index.html @@ -0,0 +1,34 @@ + + + + + +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..0e76f4270 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/FieldDoubleInit/index.html @@ -0,0 +1,35 @@ + + + + + +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..c71ebe663 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/InheritedStateMutation/index.html @@ -0,0 +1,36 @@ + + + + + +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..c7fa7544c --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,33 @@ + + + + + +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..f22d7de74 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,34 @@ + + + + + +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..0bcc76409 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/PreferredStdlibApi/index.html @@ -0,0 +1,37 @@ + + + + + +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..73a9000ba --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,32 @@ + + + + + +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..dea93e440 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/StringReceiversOverlap/index.html @@ -0,0 +1,32 @@ + + + + + +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..cc2276d63 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/UnboundLoops/index.html @@ -0,0 +1,36 @@ + + + + + +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..00023b019 --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/ZeroAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..4de97bb0e --- /dev/null +++ b/tools/misti/docs/0.3.0/detectors/index.html @@ -0,0 +1,29 @@ + + + + + +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..68849ea96 --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/contributing/index.html @@ -0,0 +1,69 @@ + + + + + +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..80e948ad9 --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/custom-detector/index.html @@ -0,0 +1,41 @@ + + + + + +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..a20a9145c --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/design/index.html @@ -0,0 +1,37 @@ + + + + + +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..c8ba47c32 --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/souffle/index.html @@ -0,0 +1,41 @@ + + + + + +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..e3640b74d --- /dev/null +++ b/tools/misti/docs/0.3.0/hacking/tools/index.html @@ -0,0 +1,54 @@ + + + + + +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..f975f6077 --- /dev/null +++ b/tools/misti/docs/0.3.0/index.html @@ -0,0 +1,42 @@ + + + + + +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..25c377e7c --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/blueprint/index.html @@ -0,0 +1,35 @@ + + + + + +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..8ce3eb37f --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/ci-cd/index.html @@ -0,0 +1,36 @@ + + + + + +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..9dfabc46e --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/cli/index.html @@ -0,0 +1,105 @@ + + + + + +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..17980e7ee --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/configuration/index.html @@ -0,0 +1,66 @@ + + + + + +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..fa59ce731 --- /dev/null +++ b/tools/misti/docs/0.3.0/tutorial/getting-started/index.html @@ -0,0 +1,65 @@ + + + + + +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..35952bc26 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/ArgCopyMutation/index.html @@ -0,0 +1,37 @@ + + + + + +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..f03c55a96 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/AsmIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +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..75d4aa6f7 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/BranchDuplicate/index.html @@ -0,0 +1,36 @@ + + + + + +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..bf4150a67 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/ConstantAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..cc59e387e --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,37 @@ + + + + + +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..9a704b565 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/DumpIsUsed/index.html @@ -0,0 +1,34 @@ + + + + + +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..5820edf3a --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/FieldDoubleInit/index.html @@ -0,0 +1,35 @@ + + + + + +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..c8e9508ea --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/InheritedStateMutation/index.html @@ -0,0 +1,36 @@ + + + + + +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..c612442e2 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,33 @@ + + + + + +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..e83a49b98 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,34 @@ + + + + + +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..c60a0d44a --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/PreferredStdlibApi/index.html @@ -0,0 +1,37 @@ + + + + + +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..521b3726d --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,32 @@ + + + + + +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..576007e1b --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/StringReceiversOverlap/index.html @@ -0,0 +1,32 @@ + + + + + +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..b365a93ed --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/UnboundLoops/index.html @@ -0,0 +1,36 @@ + + + + + +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..5daa459d1 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/ZeroAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..15bd87544 --- /dev/null +++ b/tools/misti/docs/0.3.1/detectors/index.html @@ -0,0 +1,29 @@ + + + + + +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..f8f4eb9f6 --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/contributing/index.html @@ -0,0 +1,69 @@ + + + + + +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..d525d71af --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/custom-detector/index.html @@ -0,0 +1,41 @@ + + + + + +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..74815abd1 --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/design/index.html @@ -0,0 +1,37 @@ + + + + + +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..8ec05ff60 --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/souffle/index.html @@ -0,0 +1,41 @@ + + + + + +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..8bdfaae52 --- /dev/null +++ b/tools/misti/docs/0.3.1/hacking/tools/index.html @@ -0,0 +1,54 @@ + + + + + +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..632127f8d --- /dev/null +++ b/tools/misti/docs/0.3.1/index.html @@ -0,0 +1,42 @@ + + + + + +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..b57cc39db --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/blueprint/index.html @@ -0,0 +1,35 @@ + + + + + +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..26b7e5a79 --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/ci-cd/index.html @@ -0,0 +1,36 @@ + + + + + +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..1e92f3957 --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/cli/index.html @@ -0,0 +1,105 @@ + + + + + +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..3b008f542 --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/configuration/index.html @@ -0,0 +1,66 @@ + + + + + +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..cdccc4df1 --- /dev/null +++ b/tools/misti/docs/0.3.1/tutorial/getting-started/index.html @@ -0,0 +1,65 @@ + + + + + +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/0.4.0/detectors/ArgCopyMutation/index.html b/tools/misti/docs/0.4.0/detectors/ArgCopyMutation/index.html new file mode 100644 index 000000000..73f68df0d --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/ArgCopyMutation/index.html @@ -0,0 +1,37 @@ + + + + + +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/0.4.0/detectors/AsmIsUsed/index.html b/tools/misti/docs/0.4.0/detectors/AsmIsUsed/index.html new file mode 100644 index 000000000..db28e6210 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/AsmIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +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/0.4.0/detectors/BranchDuplicate/index.html b/tools/misti/docs/0.4.0/detectors/BranchDuplicate/index.html new file mode 100644 index 000000000..e22ae260d --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/BranchDuplicate/index.html @@ -0,0 +1,36 @@ + + + + + +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/0.4.0/detectors/ConstantAddress/index.html b/tools/misti/docs/0.4.0/detectors/ConstantAddress/index.html new file mode 100644 index 000000000..2124df785 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/ConstantAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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/0.4.0/detectors/DivideBeforeMultiply/index.html b/tools/misti/docs/0.4.0/detectors/DivideBeforeMultiply/index.html new file mode 100644 index 000000000..bf75942b6 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,37 @@ + + + + + +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/0.4.0/detectors/DumpIsUsed/index.html b/tools/misti/docs/0.4.0/detectors/DumpIsUsed/index.html new file mode 100644 index 000000000..c6741fd05 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/DumpIsUsed/index.html @@ -0,0 +1,34 @@ + + + + + +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/0.4.0/detectors/DuplicatedCondition/index.html b/tools/misti/docs/0.4.0/detectors/DuplicatedCondition/index.html new file mode 100644 index 000000000..90e5c51b1 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/DuplicatedCondition/index.html @@ -0,0 +1,32 @@ + + + + + +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/0.4.0/detectors/EnsurePrgSeed/index.html b/tools/misti/docs/0.4.0/detectors/EnsurePrgSeed/index.html new file mode 100644 index 000000000..1591b3211 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/EnsurePrgSeed/index.html @@ -0,0 +1,35 @@ + + + + + +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/0.4.0/detectors/FalseCondition/index.html b/tools/misti/docs/0.4.0/detectors/FalseCondition/index.html new file mode 100644 index 000000000..a45c891b3 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/FalseCondition/index.html @@ -0,0 +1,34 @@ + + + + + +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/0.4.0/detectors/FieldDoubleInit/index.html b/tools/misti/docs/0.4.0/detectors/FieldDoubleInit/index.html new file mode 100644 index 000000000..bb97333cc --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/FieldDoubleInit/index.html @@ -0,0 +1,35 @@ + + + + + +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/0.4.0/detectors/InheritedStateMutation/index.html b/tools/misti/docs/0.4.0/detectors/InheritedStateMutation/index.html new file mode 100644 index 000000000..15fad28ae --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/InheritedStateMutation/index.html @@ -0,0 +1,36 @@ + + + + + +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/0.4.0/detectors/NeverAccessedVariables/index.html b/tools/misti/docs/0.4.0/detectors/NeverAccessedVariables/index.html new file mode 100644 index 000000000..618e7daa9 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,33 @@ + + + + + +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/0.4.0/detectors/OptimalMathFunction/index.html b/tools/misti/docs/0.4.0/detectors/OptimalMathFunction/index.html new file mode 100644 index 000000000..fde5ccc30 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/OptimalMathFunction/index.html @@ -0,0 +1,31 @@ + + + + + +OptimalMathFunction | Misti + + + + + + + +
Version: 0.4.0

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/0.4.0/detectors/PreferAugmentedAssign/index.html b/tools/misti/docs/0.4.0/detectors/PreferAugmentedAssign/index.html new file mode 100644 index 000000000..ccb6b68fb --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,34 @@ + + + + + +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/0.4.0/detectors/PreferredStdlibApi/index.html b/tools/misti/docs/0.4.0/detectors/PreferredStdlibApi/index.html new file mode 100644 index 000000000..d2b89435e --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/PreferredStdlibApi/index.html @@ -0,0 +1,37 @@ + + + + + +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/0.4.0/detectors/ReadOnlyVariables/index.html b/tools/misti/docs/0.4.0/detectors/ReadOnlyVariables/index.html new file mode 100644 index 000000000..af41820d1 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,32 @@ + + + + + +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/0.4.0/detectors/StringReceiversOverlap/index.html b/tools/misti/docs/0.4.0/detectors/StringReceiversOverlap/index.html new file mode 100644 index 000000000..49c38b65c --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/StringReceiversOverlap/index.html @@ -0,0 +1,32 @@ + + + + + +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/0.4.0/detectors/UnboundLoops/index.html b/tools/misti/docs/0.4.0/detectors/UnboundLoops/index.html new file mode 100644 index 000000000..90062f58f --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/UnboundLoops/index.html @@ -0,0 +1,36 @@ + + + + + +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/0.4.0/detectors/UnusedOptional/index.html b/tools/misti/docs/0.4.0/detectors/UnusedOptional/index.html new file mode 100644 index 000000000..27718e464 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/UnusedOptional/index.html @@ -0,0 +1,34 @@ + + + + + +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/0.4.0/detectors/ZeroAddress/index.html b/tools/misti/docs/0.4.0/detectors/ZeroAddress/index.html new file mode 100644 index 000000000..4d02ab5f8 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/ZeroAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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/0.4.0/detectors/index.html b/tools/misti/docs/0.4.0/detectors/index.html new file mode 100644 index 000000000..f00940b91 --- /dev/null +++ b/tools/misti/docs/0.4.0/detectors/index.html @@ -0,0 +1,29 @@ + + + + + +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/0.4.0/hacking/contributing/index.html b/tools/misti/docs/0.4.0/hacking/contributing/index.html new file mode 100644 index 000000000..b5aac0ffd --- /dev/null +++ b/tools/misti/docs/0.4.0/hacking/contributing/index.html @@ -0,0 +1,69 @@ + + + + + +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/0.4.0/hacking/custom-detector/index.html b/tools/misti/docs/0.4.0/hacking/custom-detector/index.html new file mode 100644 index 000000000..2f5f86541 --- /dev/null +++ b/tools/misti/docs/0.4.0/hacking/custom-detector/index.html @@ -0,0 +1,41 @@ + + + + + +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/0.4.0/hacking/design/index.html b/tools/misti/docs/0.4.0/hacking/design/index.html new file mode 100644 index 000000000..e3f61d296 --- /dev/null +++ b/tools/misti/docs/0.4.0/hacking/design/index.html @@ -0,0 +1,37 @@ + + + + + +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/0.4.0/hacking/developing-misti/index.html b/tools/misti/docs/0.4.0/hacking/developing-misti/index.html new file mode 100644 index 000000000..8b7c696c5 --- /dev/null +++ b/tools/misti/docs/0.4.0/hacking/developing-misti/index.html @@ -0,0 +1,47 @@ + + + + + +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/0.4.0/hacking/souffle/index.html b/tools/misti/docs/0.4.0/hacking/souffle/index.html new file mode 100644 index 000000000..319060c53 --- /dev/null +++ b/tools/misti/docs/0.4.0/hacking/souffle/index.html @@ -0,0 +1,41 @@ + + + + + +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/0.4.0/index.html b/tools/misti/docs/0.4.0/index.html new file mode 100644 index 000000000..687113a63 --- /dev/null +++ b/tools/misti/docs/0.4.0/index.html @@ -0,0 +1,47 @@ + + + + + +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/0.4.0/tools/DumpAst/index.html b/tools/misti/docs/0.4.0/tools/DumpAst/index.html new file mode 100644 index 000000000..d5ea33a96 --- /dev/null +++ b/tools/misti/docs/0.4.0/tools/DumpAst/index.html @@ -0,0 +1,33 @@ + + + + + +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/0.4.0/tools/DumpCfg/index.html b/tools/misti/docs/0.4.0/tools/DumpCfg/index.html new file mode 100644 index 000000000..0c541de51 --- /dev/null +++ b/tools/misti/docs/0.4.0/tools/DumpCfg/index.html @@ -0,0 +1,65 @@ + + + + + +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/0.4.0/tools/DumpConfig/index.html b/tools/misti/docs/0.4.0/tools/DumpConfig/index.html new file mode 100644 index 000000000..db775429f --- /dev/null +++ b/tools/misti/docs/0.4.0/tools/DumpConfig/index.html @@ -0,0 +1,30 @@ + + + + + +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/0.4.0/tools/index.html b/tools/misti/docs/0.4.0/tools/index.html new file mode 100644 index 000000000..c8b4a1c2c --- /dev/null +++ b/tools/misti/docs/0.4.0/tools/index.html @@ -0,0 +1,39 @@ + + + + + +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/0.4.0/tutorial/blueprint/index.html b/tools/misti/docs/0.4.0/tutorial/blueprint/index.html new file mode 100644 index 000000000..8cb5d2ac9 --- /dev/null +++ b/tools/misti/docs/0.4.0/tutorial/blueprint/index.html @@ -0,0 +1,51 @@ + + + + + +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/0.4.0/tutorial/ci-cd/index.html b/tools/misti/docs/0.4.0/tutorial/ci-cd/index.html new file mode 100644 index 000000000..bfea4023f --- /dev/null +++ b/tools/misti/docs/0.4.0/tutorial/ci-cd/index.html @@ -0,0 +1,45 @@ + + + + + +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/0.4.0/tutorial/cli/index.html b/tools/misti/docs/0.4.0/tutorial/cli/index.html new file mode 100644 index 000000000..c01cb0301 --- /dev/null +++ b/tools/misti/docs/0.4.0/tutorial/cli/index.html @@ -0,0 +1,108 @@ + + + + + +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/0.4.0/tutorial/configuration/index.html b/tools/misti/docs/0.4.0/tutorial/configuration/index.html new file mode 100644 index 000000000..a286cc80a --- /dev/null +++ b/tools/misti/docs/0.4.0/tutorial/configuration/index.html @@ -0,0 +1,80 @@ + + + + + +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/0.4.0/tutorial/getting-started/index.html b/tools/misti/docs/0.4.0/tutorial/getting-started/index.html new file mode 100644 index 000000000..b925d65ed --- /dev/null +++ b/tools/misti/docs/0.4.0/tutorial/getting-started/index.html @@ -0,0 +1,65 @@ + + + + + +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/docs/detectors/ArgCopyMutation/index.html b/tools/misti/docs/detectors/ArgCopyMutation/index.html new file mode 100644 index 000000000..a3c51a57f --- /dev/null +++ b/tools/misti/docs/detectors/ArgCopyMutation/index.html @@ -0,0 +1,37 @@ + + + + + +ArgCopyMutation | Misti + + + + + + + +
Version: 0.5

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..57b98e81b --- /dev/null +++ b/tools/misti/docs/detectors/AsmIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +AsmIsUsed | Misti + + + + + + + +
Version: 0.5

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..fb8219843 --- /dev/null +++ b/tools/misti/docs/detectors/BranchDuplicate/index.html @@ -0,0 +1,36 @@ + + + + + +BranchDuplicate | Misti + + + + + + + +
Version: 0.5

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/CellOverflow/index.html b/tools/misti/docs/detectors/CellOverflow/index.html new file mode 100644 index 000000000..8273ad887 --- /dev/null +++ b/tools/misti/docs/detectors/CellOverflow/index.html @@ -0,0 +1,42 @@ + + + + + +CellOverflow | Misti + + + + + + + +
Version: 0.5

CellOverflow

+

A detector that identifies cell overflow problems.

+

Why is it bad?

+

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.

+

Example

+
// 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()
+

Resources

+
    +
  1. Cell & Bag of Cells (BoC) | TON Docs
  2. +
  3. TVM Exit codes | TON Docs
  4. +
  5. Cells, Builders and Slices | Tact Docs
  6. +
+ + \ 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..20bb7c466 --- /dev/null +++ b/tools/misti/docs/detectors/ConstantAddress/index.html @@ -0,0 +1,34 @@ + + + + + +ConstantAddress | Misti + + + + + + + +
Version: 0.5

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..df8f30480 --- /dev/null +++ b/tools/misti/docs/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,37 @@ + + + + + +DivideBeforeMultiply | Misti + + + + + + + +
Version: 0.5

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..ef4a65a1f --- /dev/null +++ b/tools/misti/docs/detectors/DumpIsUsed/index.html @@ -0,0 +1,34 @@ + + + + + +DumpIsUsed | Misti + + + + + + + +
Version: 0.5

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..1d8eb63ef --- /dev/null +++ b/tools/misti/docs/detectors/DuplicatedCondition/index.html @@ -0,0 +1,32 @@ + + + + + +DuplicatedCondition | Misti + + + + + + + +
Version: 0.5

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..85e1f4845 --- /dev/null +++ b/tools/misti/docs/detectors/EnsurePrgSeed/index.html @@ -0,0 +1,35 @@ + + + + + +EnsurePrgSeed | Misti + + + + + + + +
Version: 0.5

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..e8748b64d --- /dev/null +++ b/tools/misti/docs/detectors/FalseCondition/index.html @@ -0,0 +1,34 @@ + + + + + +FalseCondition | Misti + + + + + + + +
Version: 0.5

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..98a9581a6 --- /dev/null +++ b/tools/misti/docs/detectors/FieldDoubleInit/index.html @@ -0,0 +1,35 @@ + + + + + +FieldDoubleInit | Misti + + + + + + + +
Version: 0.5

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..f9dd5b23d --- /dev/null +++ b/tools/misti/docs/detectors/InheritedStateMutation/index.html @@ -0,0 +1,36 @@ + + + + + +InheritedStateMutation | Misti + + + + + + + +
Version: 0.5

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..2a6019d37 --- /dev/null +++ b/tools/misti/docs/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,33 @@ + + + + + +NeverAccessedVariables | Misti + + + + + + + +
Version: 0.5

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..20096c4be --- /dev/null +++ b/tools/misti/docs/detectors/OptimalMathFunction/index.html @@ -0,0 +1,31 @@ + + + + + +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..c06a76fb3 --- /dev/null +++ b/tools/misti/docs/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,34 @@ + + + + + +PreferAugmentedAssign | Misti + + + + + + + +
Version: 0.5

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..af0d93b63 --- /dev/null +++ b/tools/misti/docs/detectors/PreferredStdlibApi/index.html @@ -0,0 +1,37 @@ + + + + + +PreferredStdlibApi | Misti + + + + + + + +
Version: 0.5

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..53abb23bd --- /dev/null +++ b/tools/misti/docs/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,32 @@ + + + + + +ReadOnlyVariables | Misti + + + + + + + +
Version: 0.5

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/SendInLoop/index.html b/tools/misti/docs/detectors/SendInLoop/index.html new file mode 100644 index 000000000..93cd15db2 --- /dev/null +++ b/tools/misti/docs/detectors/SendInLoop/index.html @@ -0,0 +1,32 @@ + + + + + +SendInLoop | Misti + + + + + + + +
Version: 0.5

SendInLoop

+

An optional detector that identifies send functions being called inside loops.

+

Why is it bad?

+

Calling send functions inside loops can lead to unintended consequences, such as +excessive message sending, increased gas consumption, and potential race conditions. +Loops with send calls should be refactored to avoid these issues. This detector helps +flag such code, prompting the developer to reconsider the design.

+

Example

+
fun exampleWhileLoop(limit: Int, owner: Address) {
let i = 0;
while (i < limit) {
send(SendParameters{ // Highlighted: An auditor should review the loop
to: owner,
value: 0,
bounce: false,
body: Msg{ a: i }.toCell()
});
i += 1;
}
}
+ + \ 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..cc1289a3e --- /dev/null +++ b/tools/misti/docs/detectors/StringReceiversOverlap/index.html @@ -0,0 +1,32 @@ + + + + + +StringReceiversOverlap | Misti + + + + + + + +
Version: 0.5

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/SuspiciousMessageMode/index.html b/tools/misti/docs/detectors/SuspiciousMessageMode/index.html new file mode 100644 index 000000000..638c1daf0 --- /dev/null +++ b/tools/misti/docs/detectors/SuspiciousMessageMode/index.html @@ -0,0 +1,36 @@ + + + + + +SuspiciousMessageMode | Misti + + + + + + + +
Version: 0.5

SuspiciousMessageMode

+

Detects suspicious usage of the mode field in SendParameters struct instances.

+

Why is it bad?

+

Incorrect usage of the mode field in SendParameters can lead to unintended behavior when sending messages, +such as incorrect flags being set, which can cause security vulnerabilities or unexpected contract behavior.

+

What it checks:

+
    +
  • Ensures that the mode expression only uses the bitwise OR operator |.
  • +
  • Warns if integer literals are used instead of symbolic constants.
  • +
  • Warns if the same flag is used multiple times in the mode expression.
  • +
+

Example

+
// Suspicious usage:
send(SendParameters{
to: recipient,
value: amount,
mode: SendRemainingBalance | SendRemainingBalance // Bad: Duplicate flag
});

// Correct usage:
send(SendParameters{
to: recipient,
value: amount,
mode: SendRemainingBalance | SendDestroyIfZero // Ok
});
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/UnboundLoop/index.html b/tools/misti/docs/detectors/UnboundLoop/index.html new file mode 100644 index 000000000..a2c8d8bcc --- /dev/null +++ b/tools/misti/docs/detectors/UnboundLoop/index.html @@ -0,0 +1,36 @@ + + + + + +UnboundLoop | Misti + + + + + + + +
Version: 0.5

UnboundLoop

+

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/UnboundMap/index.html b/tools/misti/docs/detectors/UnboundMap/index.html new file mode 100644 index 000000000..c44609a3d --- /dev/null +++ b/tools/misti/docs/detectors/UnboundMap/index.html @@ -0,0 +1,35 @@ + + + + + +UnboundMap | Misti + + + + + + + +
Version: 0.5

UnboundMap

+

An optional detector that highlights cases where a map field allows inserting +values (e.g., via .set) but lacks functionality for removing entries (e.g., via .del).

+

Why is it bad?

+

A map without a method to remove elements can lead to storage overflow, particularly +in long-term contract usage. Failing to provide a way to clear or delete entries +can result in uncontrolled storage growth, which not only wastes resources but +may also increase the cost of contract execution and maintenance over time.

+

Example

+
contract Test {
map: Map<Int, String>;

setEntry(key: Int, value: String) {
self.map.set(key, value); // Bad
}
}
+

Use instead:

+
contract Test {
map: Map<Int, String>;

setEntry(key: Int, value: String) {
self.map.set(key, value);
}

delEntry(key: Int) {
self.map.del(key); // Fixed: Added a new API method
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/detectors/UnusedExpressionResult/index.html b/tools/misti/docs/detectors/UnusedExpressionResult/index.html new file mode 100644 index 000000000..a42971278 --- /dev/null +++ b/tools/misti/docs/detectors/UnusedExpressionResult/index.html @@ -0,0 +1,33 @@ + + + + + +UnusedExpressionResult | Misti + + + + + + + +
Version: 0.5

UnusedExpressionResult

+

A detector that identifies expression statements whose result is unused.

+

Why is it bad?

+

Expression statements that don't alter the contract's state and whose results are not used +can lead to inefficiency, dead code, and potential confusion. They add unnecessary complexity +without contributing to the logic or state of the contract.

+

Example

+
self.foo == 3; // Warning: unused boolean expression
inc(a); // Warning: unused return value
+

Use instead:

+
self.foo = 3; // Fixed: corrected assignment
newValue = inc(a); // OK: result is now used
let _ = inc(a); // OK: explicitly ignored
+ + \ 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..bbdebbe1e --- /dev/null +++ b/tools/misti/docs/detectors/UnusedOptional/index.html @@ -0,0 +1,34 @@ + + + + + +UnusedOptional | Misti + + + + + + + +
Version: 0.5

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..d8b98b613 --- /dev/null +++ b/tools/misti/docs/detectors/ZeroAddress/index.html @@ -0,0 +1,34 @@ + + + + + +ZeroAddress | Misti + + + + + + + +
Version: 0.5

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..5a23ebd05 --- /dev/null +++ b/tools/misti/docs/detectors/index.html @@ -0,0 +1,29 @@ + + + + + +Detectors Overview | Misti + + + + + + + +
Version: 0.5

Detectors Overview

+

Built-in Detectors

+
#DetectorSeverityRequires SouffléEnabled by default
1ArgCopyMutationHigh
2AsmIsUsedInfo
3BranchDuplicateHigh
4CellOverflowCritical
5ConstantAddressInfo
6DivideBeforeMultiplyHigh
7DumpIsUsedInfo
8DuplicatedConditionHigh
9EnsurePrgSeedMedium
10FalseConditionMedium
11FieldDoubleInitMedium
12InheritedStateMutationLow
13NeverAccessedVariablesMedium
14OptimalMathFunctionLow
15PreferAugmentedAssignInfo
16PreferredStdlibApiInfo
17ReadOnlyVariablesMedium
18SendInLoopMedium
19StringReceiversOverlapHigh
20SuspiciousMessageModeMedium
21UnboundLoopHigh
22UnboundMapLow
23UnusedExpressionResultMedium
24UnusedOptionalLow
25ZeroAddressLow
+

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..b42bc7805 --- /dev/null +++ b/tools/misti/docs/hacking/contributing/index.html @@ -0,0 +1,69 @@ + + + + + +Contributing Guide | Misti + + + + + + + +
Version: 0.5

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..7b596021f --- /dev/null +++ b/tools/misti/docs/hacking/custom-detector/index.html @@ -0,0 +1,41 @@ + + + + + +Custom Detector Guide | Misti + + + + + + + +
Version: 0.5

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: 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: 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 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..cf4fe4949 --- /dev/null +++ b/tools/misti/docs/hacking/design/index.html @@ -0,0 +1,37 @@ + + + + + +Design Overview | Misti + + + + + + + +
Version: 0.5

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..366475f80 --- /dev/null +++ b/tools/misti/docs/hacking/developing-misti/index.html @@ -0,0 +1,47 @@ + + + + + +Developing Misti | Misti + + + + + + + +
Version: 0.5

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/detectors/NeverAccessedVariables.tact
+

Adding Backtraces to the Logger

+

To add debug traces to all log messages, set the MISTI_TRACE environment variable to 1:

+
MISTI_TRACE=1 yarn misti test/detectors/NeverAccessedVariables.tact
+

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/detectors/NeverAccessedVariables.tact
+

And for another specific test:

+
BLESS=1 yarn test test/builtinDetectors.spec.ts test/detectors/BranchDuplicate.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..6d7337633 --- /dev/null +++ b/tools/misti/docs/hacking/souffle/index.html @@ -0,0 +1,41 @@ + + + + + +Soufflé Integration Guide | Misti + + + + + + + +
Version: 0.5

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..3d7dd90bf --- /dev/null +++ b/tools/misti/docs/index.html @@ -0,0 +1,47 @@ + + + + + +Introduction | Misti + + + + + + + +
Version: 0.5

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..1bb59e885 --- /dev/null +++ b/tools/misti/docs/next/detectors/ArgCopyMutation/index.html @@ -0,0 +1,37 @@ + + + + + +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..5d5cb67d4 --- /dev/null +++ b/tools/misti/docs/next/detectors/AsmIsUsed/index.html @@ -0,0 +1,31 @@ + + + + + +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..e1389366e --- /dev/null +++ b/tools/misti/docs/next/detectors/BranchDuplicate/index.html @@ -0,0 +1,36 @@ + + + + + +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/CellOverflow/index.html b/tools/misti/docs/next/detectors/CellOverflow/index.html new file mode 100644 index 000000000..75dd1b03e --- /dev/null +++ b/tools/misti/docs/next/detectors/CellOverflow/index.html @@ -0,0 +1,42 @@ + + + + + +CellOverflow | Misti + + + + + + + +
Version: Next

CellOverflow

+

A detector that identifies cell overflow problems.

+

Why is it bad?

+

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.

+

Example

+
// 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()
+

Resources

+
    +
  1. Cell & Bag of Cells (BoC) | TON Docs
  2. +
  3. TVM Exit codes | TON Docs
  4. +
  5. Cells, Builders and Slices | Tact Docs
  6. +
+ + \ 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..223ba8f7f --- /dev/null +++ b/tools/misti/docs/next/detectors/ConstantAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..7a59775b2 --- /dev/null +++ b/tools/misti/docs/next/detectors/DivideBeforeMultiply/index.html @@ -0,0 +1,37 @@ + + + + + +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..0ae25f04f --- /dev/null +++ b/tools/misti/docs/next/detectors/DumpIsUsed/index.html @@ -0,0 +1,34 @@ + + + + + +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..1b1ff23b9 --- /dev/null +++ b/tools/misti/docs/next/detectors/DuplicatedCondition/index.html @@ -0,0 +1,32 @@ + + + + + +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..448028295 --- /dev/null +++ b/tools/misti/docs/next/detectors/EnsurePrgSeed/index.html @@ -0,0 +1,35 @@ + + + + + +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..af4008f00 --- /dev/null +++ b/tools/misti/docs/next/detectors/FalseCondition/index.html @@ -0,0 +1,34 @@ + + + + + +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..2fb2fa75d --- /dev/null +++ b/tools/misti/docs/next/detectors/FieldDoubleInit/index.html @@ -0,0 +1,35 @@ + + + + + +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..e8744ba32 --- /dev/null +++ b/tools/misti/docs/next/detectors/InheritedStateMutation/index.html @@ -0,0 +1,36 @@ + + + + + +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..d3af5f89c --- /dev/null +++ b/tools/misti/docs/next/detectors/NeverAccessedVariables/index.html @@ -0,0 +1,33 @@ + + + + + +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..8a3515e3a --- /dev/null +++ b/tools/misti/docs/next/detectors/OptimalMathFunction/index.html @@ -0,0 +1,31 @@ + + + + + +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..10cf7f0a0 --- /dev/null +++ b/tools/misti/docs/next/detectors/PreferAugmentedAssign/index.html @@ -0,0 +1,34 @@ + + + + + +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..3fc0abeb9 --- /dev/null +++ b/tools/misti/docs/next/detectors/PreferredStdlibApi/index.html @@ -0,0 +1,37 @@ + + + + + +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..d183c6cb5 --- /dev/null +++ b/tools/misti/docs/next/detectors/ReadOnlyVariables/index.html @@ -0,0 +1,32 @@ + + + + + +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/SendInLoop/index.html b/tools/misti/docs/next/detectors/SendInLoop/index.html new file mode 100644 index 000000000..8b2ebf49d --- /dev/null +++ b/tools/misti/docs/next/detectors/SendInLoop/index.html @@ -0,0 +1,32 @@ + + + + + +SendInLoop | Misti + + + + + + + +
Version: Next

SendInLoop

+

An optional detector that identifies send functions being called inside loops.

+

Why is it bad?

+

Calling send functions inside loops can lead to unintended consequences, such as +excessive message sending, increased gas consumption, and potential race conditions. +Loops with send calls should be refactored to avoid these issues. This detector helps +flag such code, prompting the developer to reconsider the design.

+

Example

+
fun exampleWhileLoop(limit: Int, owner: Address) {
let i = 0;
while (i < limit) {
send(SendParameters{ // Highlighted: An auditor should review the loop
to: owner,
value: 0,
bounce: false,
body: Msg{ a: i }.toCell()
});
i += 1;
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/ShortCircuitCondition/index.html b/tools/misti/docs/next/detectors/ShortCircuitCondition/index.html new file mode 100644 index 000000000..33e0be5b4 --- /dev/null +++ b/tools/misti/docs/next/detectors/ShortCircuitCondition/index.html @@ -0,0 +1,33 @@ + + + + + +ShortCircuitCondition | Misti + + + + + + + +
Version: Next

ShortCircuitCondition

+

A detector that suggests optimizing boolean expressions to leverage short-circuit evaluation.

+

Why is it bad?

+

TVM supports short-circuit operations. When using logical AND (&&) or logical OR (||) operations, +placing constant or cheaper conditions first can prevent unnecessary execution +of expensive operations when the result is already determined.

+

Example

+
// Bad: Expensive operation is always executed
if (expensive_function() && constant_false) {
// ...
}
+

Use instead:

+
// Good: Expensive operation is skipped when constant_false is false
if (constant_false && expensive_function()) {
// ...
}
+ + \ 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..1777fe488 --- /dev/null +++ b/tools/misti/docs/next/detectors/StringReceiversOverlap/index.html @@ -0,0 +1,32 @@ + + + + + +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/SuspiciousMessageMode/index.html b/tools/misti/docs/next/detectors/SuspiciousMessageMode/index.html new file mode 100644 index 000000000..7ab8e458b --- /dev/null +++ b/tools/misti/docs/next/detectors/SuspiciousMessageMode/index.html @@ -0,0 +1,36 @@ + + + + + +SuspiciousMessageMode | Misti + + + + + + + +
Version: Next

SuspiciousMessageMode

+

Detects suspicious usage of the mode field in SendParameters struct instances.

+

Why is it bad?

+

Incorrect usage of the mode field in SendParameters can lead to unintended behavior when sending messages, +such as incorrect flags being set, which can cause security vulnerabilities or unexpected contract behavior.

+

What it checks:

+
    +
  • Ensures that the mode expression only uses the bitwise OR operator |.
  • +
  • Warns if integer literals are used instead of symbolic constants.
  • +
  • Warns if the same flag is used multiple times in the mode expression.
  • +
+

Example

+
// Suspicious usage:
send(SendParameters{
to: recipient,
value: amount,
mode: SendRemainingBalance | SendRemainingBalance // Bad: Duplicate flag
});

// Correct usage:
send(SendParameters{
to: recipient,
value: amount,
mode: SendRemainingBalance | SendDestroyIfZero // Ok
});
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/UnboundLoop/index.html b/tools/misti/docs/next/detectors/UnboundLoop/index.html new file mode 100644 index 000000000..1a2969df1 --- /dev/null +++ b/tools/misti/docs/next/detectors/UnboundLoop/index.html @@ -0,0 +1,36 @@ + + + + + +UnboundLoop | Misti + + + + + + + +
Version: Next

UnboundLoop

+

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/UnboundMap/index.html b/tools/misti/docs/next/detectors/UnboundMap/index.html new file mode 100644 index 000000000..b44ed2721 --- /dev/null +++ b/tools/misti/docs/next/detectors/UnboundMap/index.html @@ -0,0 +1,35 @@ + + + + + +UnboundMap | Misti + + + + + + + +
Version: Next

UnboundMap

+

An optional detector that highlights cases where a map field allows inserting +values (e.g., via .set) but lacks functionality for removing entries (e.g., via .del).

+

Why is it bad?

+

A map without a method to remove elements can lead to storage overflow, particularly +in long-term contract usage. Failing to provide a way to clear or delete entries +can result in uncontrolled storage growth, which not only wastes resources but +may also increase the cost of contract execution and maintenance over time.

+

Example

+
contract Test {
map: Map<Int, String>;

setEntry(key: Int, value: String) {
self.map.set(key, value); // Bad
}
}
+

Use instead:

+
contract Test {
map: Map<Int, String>;

setEntry(key: Int, value: String) {
self.map.set(key, value);
}

delEntry(key: Int) {
self.map.del(key); // Fixed: Added a new API method
}
}
+ + \ No newline at end of file diff --git a/tools/misti/docs/next/detectors/UnusedExpressionResult/index.html b/tools/misti/docs/next/detectors/UnusedExpressionResult/index.html new file mode 100644 index 000000000..6bc9c5d2b --- /dev/null +++ b/tools/misti/docs/next/detectors/UnusedExpressionResult/index.html @@ -0,0 +1,33 @@ + + + + + +UnusedExpressionResult | Misti + + + + + + + +
Version: Next

UnusedExpressionResult

+

A detector that identifies expression statements whose result is unused.

+

Why is it bad?

+

Expression statements that don't alter the contract's state and whose results are not used +can lead to inefficiency, dead code, and potential confusion. They add unnecessary complexity +without contributing to the logic or state of the contract.

+

Example

+
self.foo == 3; // Warning: unused boolean expression
inc(a); // Warning: unused return value
+

Use instead:

+
self.foo = 3; // Fixed: corrected assignment
newValue = inc(a); // OK: result is now used
let _ = inc(a); // OK: explicitly ignored
+ + \ 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..49c12a06f --- /dev/null +++ b/tools/misti/docs/next/detectors/UnusedOptional/index.html @@ -0,0 +1,34 @@ + + + + + +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..ffe629dd5 --- /dev/null +++ b/tools/misti/docs/next/detectors/ZeroAddress/index.html @@ -0,0 +1,34 @@ + + + + + +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..8aa80d2d6 --- /dev/null +++ b/tools/misti/docs/next/detectors/index.html @@ -0,0 +1,29 @@ + + + + + +Detectors Overview | Misti + + + + + + + +
Version: Next

Detectors Overview

+

Built-in Detectors

+
#DetectorSeverityRequires SouffléEnabled by default
1ArgCopyMutationHigh
2AsmIsUsedInfo
3BranchDuplicateHigh
4CellOverflowCritical
5ConstantAddressInfo
6DivideBeforeMultiplyHigh
7DumpIsUsedInfo
8DuplicatedConditionHigh
9EnsurePrgSeedMedium
10FalseConditionMedium
11FieldDoubleInitMedium
12InheritedStateMutationLow
13NeverAccessedVariablesMedium
14OptimalMathFunctionLow
15PreferAugmentedAssignInfo
16PreferredStdlibApiInfo
17ReadOnlyVariablesMedium
18SendInLoopMedium
19ShortCircuitConditionLow
20StringReceiversOverlapHigh
21SuspiciousMessageModeMedium
22UnboundLoopHigh
23UnboundMapLow
24UnusedExpressionResultMedium
25UnusedOptionalLow
26ZeroAddressLow
+

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..333f3e00e --- /dev/null +++ b/tools/misti/docs/next/hacking/contributing/index.html @@ -0,0 +1,69 @@ + + + + + +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..50bc95b1e --- /dev/null +++ b/tools/misti/docs/next/hacking/custom-detector/index.html @@ -0,0 +1,41 @@ + + + + + +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: 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: 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 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..7e612a0a5 --- /dev/null +++ b/tools/misti/docs/next/hacking/design/index.html @@ -0,0 +1,37 @@ + + + + + +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..f3acd80ca --- /dev/null +++ b/tools/misti/docs/next/hacking/developing-misti/index.html @@ -0,0 +1,47 @@ + + + + + +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/detectors/NeverAccessedVariables.tact
+

Adding Backtraces to the Logger

+

To add debug traces to all log messages, set the MISTI_TRACE environment variable to 1:

+
MISTI_TRACE=1 yarn misti test/detectors/NeverAccessedVariables.tact
+

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/detectors/NeverAccessedVariables.tact
+

And for another specific test:

+
BLESS=1 yarn test test/builtinDetectors.spec.ts test/detectors/BranchDuplicate.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..56293fcfd --- /dev/null +++ b/tools/misti/docs/next/hacking/souffle/index.html @@ -0,0 +1,41 @@ + + + + + +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..9c648d2ab --- /dev/null +++ b/tools/misti/docs/next/index.html @@ -0,0 +1,47 @@ + + + + + +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..450740cf8 --- /dev/null +++ b/tools/misti/docs/next/tools/DumpAst/index.html @@ -0,0 +1,33 @@ + + + + + +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:

+
misti -t "DumpAst" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

If you wish to include the standard library in the dump, set dumpStdlib to true:

+
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..1ffa33d76 --- /dev/null +++ b/tools/misti/docs/next/tools/DumpCfg/index.html @@ -0,0 +1,65 @@ + + + + + +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:

+
misti -t "DumpCfg:format=mmd" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in Graphviz DOT format, use the following command:

+
misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in JSON format, use the following command:

+
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:

+
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:

+
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..72969bde2 --- /dev/null +++ b/tools/misti/docs/next/tools/DumpConfig/index.html @@ -0,0 +1,30 @@ + + + + + +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:

+
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/DumpImports/index.html b/tools/misti/docs/next/tools/DumpImports/index.html new file mode 100644 index 000000000..dc990e066 --- /dev/null +++ b/tools/misti/docs/next/tools/DumpImports/index.html @@ -0,0 +1,100 @@ + + + + + +DumpImports | Misti + + + + + + + +
Version: Next

DumpImports

+

Misti provides a feature to dump the Import Graph of your Tact code in JSON, DOT, and Mermaid formats. This tool helps you understand the dependencies between different files and modules in your project, including how contracts import each other and use the standard library.

+

Usage

+

To dump the Import Graph in Mermaid format, use the following command:

+
misti -t "DumpImports:format=mmd" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the Import Graph in Graphviz DOT format, use the following command:

+
misti -t "DumpImports:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the Import Graph in JSON format, use the following command:

+
misti -t "DumpImports:format=json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

You can also include Tact standard library imports in the dump by adding dumpStdlib=true to the DumpImports options:

+
misti -t "DumpImports:format=dot,dumpStdlib=true" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Working with Mermaid and Graphviz

+

For guidance on how to work with Mermaid diagrams, Graphviz DOT files, and viewing them in Visual Studio Code, please refer to the DumpCfg documentation and the Graphviz section.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: Provide a detailed representation of the Import Graph in JSON format, including nodes and edges with their properties. Useful for programmatic analysis or custom tooling.

    +
  • +
  • +

    DOT Dumps: Offer a visual representation of the project's import dependencies. Useful for understanding how files and contracts depend on each other.

    +
  • +
  • +

    Mermaid Dumps: Similar to DOT dumps but using Mermaid syntax, which can be easier to work with in certain environments, especially when using markdown files or online editors.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the dependency structure of their Tact projects, facilitating better project organization, dependency management, and code optimization.

+

Including Standard Library Imports

+

By default, the Import Graph excludes imports from the standard library. If you want to include standard library imports in your graph, add dumpStdlib=true to the command:

+
misti -t "DumpImports:format=mmd,dumpStdlib=true" contracts/main.tact
+

Example

+

Consider a project with the following structure:

+
    +
  • main.tact:
  • +
+
import "./constants.tact";
import "./messages.tact";
import "@stdlib/ownable";
contract C{}
+
    +
  • constants.tact:
  • +
+
const SOMETHING: Int = 123;
+
    +
  • messages.tact:
  • +
+
import "./constants.tact";
message Msg { a: Bool }
+

To dump the Import Graph in Mermaid format, run:

+
misti -t "DumpImports:format=mmd:dumpStdlib=true" contracts/main.tact
+

The output will look like:

+
graph TD
node_1["main"]:::contractNode
node_2["constants"]
node_3["messages"]
node_4["@stdlib/ownable.tact"]:::stdlibNode
node_1 --> node_2
node_3 --> node_2
node_1 --> node_3
node_1 --> node_4
classDef contractNode fill:#90EE90,stroke:#333,stroke-width:2px;
classDef stdlibNode fill:#FFFF80,stroke:#333,stroke-width:2px;
+

Which will be rendered as:

+

Mermaid Output

+

In this diagram:

+
    +
  • Nodes representing files that contain contracts are filled with green.
  • +
  • Edges represent import relationships between files.
  • +
+

You can paste this Mermaid code into the Mermaid Live Editor or view it directly in VS Code with the appropriate extension.

+

Interpreting the Import Graph

+

The Import Graph shows how files in your project are interconnected through import statements. Each node represents a file, and each edge represents an import from one file to another.

+
    +
  • Nodes: +
      +
    • Files containing contracts are highlighted (green in the examples).
    • +
    • Standard library files are highlighted differently (yellow) when included.
    • +
    +
  • +
  • Edges: +
      +
    • Directed edges show the import relationship (A --> B means A imports B).
    • +
    +
  • +
+

Understanding the Import Graph can help you:

+
    +
  • Identify unnecessary dependencies.
  • +
  • Visualize the structure of your project.
  • +
+

Conclusion

+

By utilizing the DumpImports tool, developers can gain deeper insights into the dependency structure of their Tact projects, facilitating better project organization, dependency management, and code optimization.

+ + \ 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..744a76524 --- /dev/null +++ b/tools/misti/docs/next/tools/index.html @@ -0,0 +1,39 @@ + + + + + +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:

+
misti --list-tools
+

To invoke a specific tool, use the following command format:

+
misti -t "ToolName:option=value,option=value" /path/to/tact.config.json
+

Usage Examples

+

Dump the AST of the project:

+
misti -t "DumpAst" my-example.tact
+

Dump the CFGs of the project in Mermaid format to the file /tmp/my-example.DumpCfg.out:

+
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
4DumpImportsDumps the graph of imports
+ + \ 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..177bcfef6 --- /dev/null +++ b/tools/misti/docs/next/tutorial/blueprint/index.html @@ -0,0 +1,51 @@ + + + + + +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..7d2a8aa13 --- /dev/null +++ b/tools/misti/docs/next/tutorial/ci-cd/index.html @@ -0,0 +1,45 @@ + + + + + +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..f272c07da --- /dev/null +++ b/tools/misti/docs/next/tutorial/cli/index.html @@ -0,0 +1,116 @@ + + + + + +Command-Line Interface | Misti + + + + + + + +
Version: Next

Command-Line Interface

+

CLI Options

+

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
  • +
+

Exit Codes

+

Misti returns different exit codes depending on the execution result:

+
    +
  • 0: Successful execution with no warnings or errors.
  • +
  • 1: Warnings were reported.
  • +
  • 2: Execution failed due to an internal or execution error.
  • +
+ + \ 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..810110f76 --- /dev/null +++ b/tools/misti/docs/next/tutorial/configuration/index.html @@ -0,0 +1,96 @@ + + + + + +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:

+
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:

+
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.

+

Environment Variables

+

Misti offers advanced configuration through environment variables to control specific options.

+
    +
  • MISTI_TIMEOUT
    +Sets the timeout for detector execution in milliseconds.
    +Default: 15000
    +Example: +
    export MISTI_TIMEOUT=20000
    +
  • +
  • MISTI_TRACE
    +Enables tracing of the execution. Set to 1 to enable tracing, otherwise it is disabled.
    +Default: false
    +Example: +
    export MISTI_TRACE=1
    +
  • +
+

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..9fae360a6 --- /dev/null +++ b/tools/misti/docs/next/tutorial/getting-started/index.html @@ -0,0 +1,68 @@ + + + + + +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

+
npm install -g @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:

+
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": "misti path/to/tact.config.json"
}
}
+

More usage examples

+

Below are a few usage examples for common scenarios when using the misti CLI.

+

Suppressing Warnings

+

If you want to suppress some warnings in specific places of source code, you should use the @misti:suppress annotations in the comment on the previous line, for example:

+
fun test(): Int {
// @misti:suppress NeverAccessedVariables
let sum: Int = 0; // OK: The warning will be suppressed
return 52;
}
+

This syntax also enables you to list a few detectors to be suppressed, including the custom ones, for example:

+
// @misti:suppress NeverAccessedVariables,MyCustomDetector,ReadOnlyVariables
+

Alternatively, you could run misti while entirely suppressing specific detectors:

+
misti --suppress ReadOnlyVariables path/to/tact.config.json
+

Enabling All Detectors

+

Running misti with all available built-in detectors enabled:

+
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:

+
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..934dac6bc --- /dev/null +++ b/tools/misti/docs/tools/DumpAst/index.html @@ -0,0 +1,33 @@ + + + + + +DumpAst | Misti + + + + + + + +
Version: 0.5

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:

+
misti -t "DumpAst" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

If you wish to include the standard library in the dump, set dumpStdlib to true:

+
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..5bbaa2d8b --- /dev/null +++ b/tools/misti/docs/tools/DumpCfg/index.html @@ -0,0 +1,65 @@ + + + + + +DumpCfg | Misti + + + + + + + +
Version: 0.5

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:

+
misti -t "DumpCfg:format=mmd" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in Graphviz DOT format, use the following command:

+
misti -t "DumpCfg:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the CFG in JSON format, use the following command:

+
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:

+
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:

+
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..31dc816c7 --- /dev/null +++ b/tools/misti/docs/tools/DumpConfig/index.html @@ -0,0 +1,30 @@ + + + + + +DumpConfig | Misti + + + + + + + +
Version: 0.5

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:

+
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/DumpImports/index.html b/tools/misti/docs/tools/DumpImports/index.html new file mode 100644 index 000000000..5a026366d --- /dev/null +++ b/tools/misti/docs/tools/DumpImports/index.html @@ -0,0 +1,100 @@ + + + + + +DumpImports | Misti + + + + + + + +
Version: 0.5

DumpImports

+

Misti provides a feature to dump the Import Graph of your Tact code in JSON, DOT, and Mermaid formats. This tool helps you understand the dependencies between different files and modules in your project, including how contracts import each other and use the standard library.

+

Usage

+

To dump the Import Graph in Mermaid format, use the following command:

+
misti -t "DumpImports:format=mmd" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the Import Graph in Graphviz DOT format, use the following command:

+
misti -t "DumpImports:format=dot" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

To dump the Import Graph in JSON format, use the following command:

+
misti -t "DumpImports:format=json" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

You can also include Tact standard library imports in the dump by adding dumpStdlib=true to the DumpImports options:

+
misti -t "DumpImports:format=dot,dumpStdlib=true" <TACT_CONFIG_PATH|TACT_FILE_PATH>
+

Working with Mermaid and Graphviz

+

For guidance on how to work with Mermaid diagrams, Graphviz DOT files, and viewing them in Visual Studio Code, please refer to the DumpCfg documentation and the Graphviz section.

+

Understanding the Dumps

+
    +
  • +

    JSON Dumps: Provide a detailed representation of the Import Graph in JSON format, including nodes and edges with their properties. Useful for programmatic analysis or custom tooling.

    +
  • +
  • +

    DOT Dumps: Offer a visual representation of the project's import dependencies. Useful for understanding how files and contracts depend on each other.

    +
  • +
  • +

    Mermaid Dumps: Similar to DOT dumps but using Mermaid syntax, which can be easier to work with in certain environments, especially when using markdown files or online editors.

    +
  • +
+

By utilizing these tools, developers can gain deeper insights into the dependency structure of their Tact projects, facilitating better project organization, dependency management, and code optimization.

+

Including Standard Library Imports

+

By default, the Import Graph excludes imports from the standard library. If you want to include standard library imports in your graph, add dumpStdlib=true to the command:

+
misti -t "DumpImports:format=mmd,dumpStdlib=true" contracts/main.tact
+

Example

+

Consider a project with the following structure:

+
    +
  • main.tact:
  • +
+
import "./constants.tact";
import "./messages.tact";
import "@stdlib/ownable";
contract C{}
+
    +
  • constants.tact:
  • +
+
const SOMETHING: Int = 123;
+
    +
  • messages.tact:
  • +
+
import "./constants.tact";
message Msg { a: Bool }
+

To dump the Import Graph in Mermaid format, run:

+
misti -t "DumpImports:format=mmd:dumpStdlib=true" contracts/main.tact
+

The output will look like:

+
graph TD
node_1["main"]:::contractNode
node_2["constants"]
node_3["messages"]
node_4["@stdlib/ownable.tact"]:::stdlibNode
node_1 --> node_2
node_3 --> node_2
node_1 --> node_3
node_1 --> node_4
classDef contractNode fill:#90EE90,stroke:#333,stroke-width:2px;
classDef stdlibNode fill:#FFFF80,stroke:#333,stroke-width:2px;
+

Which will be rendered as:

+

Mermaid Output

+

In this diagram:

+
    +
  • Nodes representing files that contain contracts are filled with green.
  • +
  • Edges represent import relationships between files.
  • +
+

You can paste this Mermaid code into the Mermaid Live Editor or view it directly in VS Code with the appropriate extension.

+

Interpreting the Import Graph

+

The Import Graph shows how files in your project are interconnected through import statements. Each node represents a file, and each edge represents an import from one file to another.

+
    +
  • Nodes: +
      +
    • Files containing contracts are highlighted (green in the examples).
    • +
    • Standard library files are highlighted differently (yellow) when included.
    • +
    +
  • +
  • Edges: +
      +
    • Directed edges show the import relationship (A --> B means A imports B).
    • +
    +
  • +
+

Understanding the Import Graph can help you:

+
    +
  • Identify unnecessary dependencies.
  • +
  • Visualize the structure of your project.
  • +
+

Conclusion

+

By utilizing the DumpImports tool, developers can gain deeper insights into the dependency structure of their Tact projects, facilitating better project organization, dependency management, and code optimization.

+ + \ 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..3f4122ce0 --- /dev/null +++ b/tools/misti/docs/tools/index.html @@ -0,0 +1,39 @@ + + + + + +Tools Overview | Misti + + + + + + + +
Version: 0.5

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:

+
misti --list-tools
+

To invoke a specific tool, use the following command format:

+
misti -t "ToolName:option=value,option=value" /path/to/tact.config.json
+

Usage Examples

+

Dump the AST of the project:

+
misti -t "DumpAst" my-example.tact
+

Dump the CFGs of the project in Mermaid format to the file /tmp/my-example.DumpCfg.out:

+
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
4DumpImportsDumps the graph of imports
+ + \ 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..07c4ae2e4 --- /dev/null +++ b/tools/misti/docs/tutorial/blueprint/index.html @@ -0,0 +1,51 @@ + + + + + +Using Misti with Blueprint | Misti + + + + + + + +
Version: 0.5

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/tutorial/ci-cd/index.html b/tools/misti/docs/tutorial/ci-cd/index.html new file mode 100644 index 000000000..9102f289b --- /dev/null +++ b/tools/misti/docs/tutorial/ci-cd/index.html @@ -0,0 +1,45 @@ + + + + + +Integrating Misti into CI/CD | Misti + + + + + + + +
Version: 0.5

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..cb730defd --- /dev/null +++ b/tools/misti/docs/tutorial/cli/index.html @@ -0,0 +1,116 @@ + + + + + +Command-Line Interface | Misti + + + + + + + +
Version: 0.5

Command-Line Interface

+

CLI Options

+

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
  • +
+

Exit Codes

+

Misti returns different exit codes depending on the execution result:

+
    +
  • 0: Successful execution with no warnings or errors.
  • +
  • 1: Warnings were reported.
  • +
  • 2: Execution failed due to an internal or execution error.
  • +
+ + \ 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..a0993f994 --- /dev/null +++ b/tools/misti/docs/tutorial/configuration/index.html @@ -0,0 +1,96 @@ + + + + + +Configuration | Misti + + + + + + + +
Version: 0.5

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:

+
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:

+
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.

+

Environment Variables

+

Misti offers advanced configuration through environment variables to control specific options.

+
    +
  • MISTI_TIMEOUT
    +Sets the timeout for detector execution in milliseconds.
    +Default: 15000
    +Example: +
    export MISTI_TIMEOUT=20000
    +
  • +
  • MISTI_TRACE
    +Enables tracing of the execution. Set to 1 to enable tracing, otherwise it is disabled.
    +Default: false
    +Example: +
    export MISTI_TRACE=1
    +
  • +
+

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..4cfc75215 --- /dev/null +++ b/tools/misti/docs/tutorial/getting-started/index.html @@ -0,0 +1,68 @@ + + + + + +Getting started | Misti + + + + + + + +
Version: 0.5

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

+
npm install -g @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:

+
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": "misti path/to/tact.config.json"
}
}
+

More usage examples

+

Below are a few usage examples for common scenarios when using the misti CLI.

+

Suppressing Warnings

+

If you want to suppress some warnings in specific places of source code, you should use the @misti:suppress annotations in the comment on the previous line, for example:

+
fun test(): Int {
// @misti:suppress NeverAccessedVariables
let sum: Int = 0; // OK: The warning will be suppressed
return 52;
}
+

This syntax also enables you to list a few detectors to be suppressed, including the custom ones, for example:

+
// @misti:suppress NeverAccessedVariables,MyCustomDetector,ReadOnlyVariables
+

Alternatively, you could run misti while entirely suppressing specific detectors:

+
misti --suppress ReadOnlyVariables path/to/tact.config.json
+

Enabling All Detectors

+

Running misti with all available built-in detectors enabled:

+
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:

+
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..fd31bb32d --- /dev/null +++ b/tools/misti/index.html @@ -0,0 +1,24 @@ + + + + + +Welcome to Misti | Misti + + + + + + + +

Misti

TON Security Tool

Detect security issues in TON smart contracts before they reach production

Misti Overview

Misti is a comprehensive security tool designed to identify and prevent vulnerabilities in TON smart contracts. By streamlining the development process and integrating security checks early, Misti ensures your code remains robust and secure.

🔒 Code Analysis

Identify and fix potential security flaws and code problems early in the development cycle.

⚙️ CI/CD Integration

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.

Discover Detectors

Misti supports 26 specialized detectors designed to identify code issues, detect vulnerabilities, and enforce best practices.

🌐 TON & Tact Specific

Detect patterns unique to TON and Tact that could lead to unintended behavior, such as CellOverflow or StringReceiversOverlap.

🚫 DoS Prevention

Identify vulnerabilities that could lead to Denial of Service attacks, like SendInLoop or UnboundMap.

➗ Arithmetic Accuracy

Avoid critical calculation errors with detectors like DivideBeforeMultiply.

🔐 Access Control

Ensure only authorized entities perform actions, preventing unauthorized access with detectors like SuspiciousMessageMode.

⚡ Code Optimization

Enhance code efficiency and readability with detectors like OptimalMathFunction and PreferAugmentedAssign.

🕵️ Suspicious Patterns

Uncover subtle issues in your code with detectors such as ZeroAddress and InheritedStateMutation.

Request an Audit

Certain types of bugs cannot be caught by automated tools as they demand a deep understanding of the underlying system.
We offer audit services for TON smart contracts, backed by deep security expertise, as our availability allows. If you are interested, reach out to us.

+ + \ No newline at end of file