PageSourceSearch

https://noir-lang.org/docs/assets/js/8b8f9119.b08bc957.js

js noir-lang.org collected 2026-10-03 22:53:18 UTC 21,570 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocs=globalThis.webpackChunkdocs||[]).push([[2615],{10372(e,n,r){r.r(n),r.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"guides/building_a_web_app","title":"Building a web app with Noir and Barretenberg","description":"Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment.","source":"@site/versioned_docs/version-v1.0.0-rc.1/guides/building_a_web_app.md","sourceDirName":"guides","slug":"/guides/building_a_web_app","permalink":"/docs/v1.0.0-rc.1/guides/building_a_web_app","draft":false,"unlisted":false,"editUrl":"https://github.com/noir-lang/noir/edit/master/docs/versioned_docs/version-v1.0.0-rc.1/guides/building_a_web_app.md","tags":[],"version":"v1.0.0-rc.1","frontMatter":{"title":"Building a web app with Noir and Barretenberg","description":"Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment.","keywords":["how to","guide","javascript","typescript","noir","barretenberg","zero-knowledge","proofs","app"],"pagination_next":"language/data_types/index"},"sidebar":"sidebar","previous":{"title":"Oracles","permalink":"/docs/v1.0.0-rc.1/guides/oracles"},"next":{"title":"Data Types","permalink":"/docs/v1.0.0-rc.1/language/data_types/"}}');var t=r(74848),s=r(28453);const o={title:"Building a web app with Noir and Barretenberg",description:"Learn how to setup a new app that uses Noir to generate and verify zero-knowledge SNARK proofs in a typescript or javascript environment.",keywords:["how to","guide","javascript","typescript","noir","barretenberg","zero-knowledge","proofs","app"],pagination_next:"language/data_types/index"},a=void 0,l={},c=[{value:"Dependencies",id:"dependencies",level:2},{value:"Setting up our Noir program",id:"setting-up-our-noir-program",level:2},{value:"Compiling the circuit",id:"compiling-the-circuit",level:2},{value:"Setting up our app",id:"setting-up-our-app",level:2},{value:"Some more JS",id:"some-more-js",level:2},{value:"Executing and proving",id:"executing-and-proving",level:2},{value:"Verifying",id:"verifying",level:2},{value:"Next steps",id:"next-steps",level:2}];function d(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h2:"h2",img:"img",li:"li",p:"p",pre:"pre",sub:"sub",sup:"sup",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.p,{children:"NoirJS is a Typescript package meant to work both in a browser and a server environment."}),"\n",(0,t.jsx)(n.p,{children:"In this tutorial, we will combine NoirJS with Aztec's Barretenberg backend to build a simple web app. From here, you should get an idea of how to proceed with your own Noir projects."}),"\n",(0,t.jsxs)(n.p,{children:["You can find the complete app code for this guide ",(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/tiny-noirjs-app",children:"here"}),"."]}),"\n",(0,t.jsx)(n.h2,{id:"dependencies",children:"Dependencies"}),"\n",(0,t.jsxs)(n.p,{children:["Before we start, we want to make sure we have Node installed. If you don't have it already you can install it ",(0,t.jsx)(n.a,{href:"https://nodejs.org/en/download",children:"here"}),", we recommend using ",(0,t.jsx)(n.a,{href:"https://yarnpkg.com/getting-started/install",children:"Yarn"})," as our package manager for this tutorial."]}),"\n",(0,t.jsxs)(n.p,{children:["We'll also need version 1.0.0-beta.20 nargo installed, see the Noir ",(0,t.jsx)(n.a,{href:"/docs/v1.0.0-rc.1/installation",children:"installation guide"})," for details."]}),"\n",(0,t.jsx)(n.p,{children:"We'll keep this barebones. Doing the bare minimum is not only simple, but also allows you to easily adapt it to almost any frontend framework."}),"\n",(0,t.jsx)(n.p,{children:"This means we can start with the dependencies even on an empty folder:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn add @noir-lang/[email protected] @aztec/[email protected] buffer vite [email protected]\n"})}),"\n",(0,t.jsx)(n.p,{children:"Wait, what are these dependencies?"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"noir_js"})," is the main Noir package. It will execute our program, and generate the witness that will be sent to the backend."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"bb.js"})," is the Typescript interface for Aztec's Barretenberg proving backend. It also uses the ",(0,t.jsx)(n.code,{children:"wasm"})," version in order to run on the browser."]}
1),"\n"]}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsx)(n.p,{children:"In this guide, we will install versions pinned to 1.0.0-beta.20. These work with Barretenberg version 3.0.0-nightly.20251104, so we are using that version too. You can also try older or later versions."})}),"\n",(0,t.jsx)(n.h2,{id:"setting-up-our-noir-program",children:"Setting up our Noir program"}),"\n",(0,t.jsx)(n.p,{children:"ZK is a powerful technology: an app can prove that a computation was carried out correctly without revealing some of its inputs, and Noir lets you express this in a single line of code."}),"\n",(0,t.jsx)(n.admonition,{type:"tip",children:(0,t.jsxs)(n.p,{children:["For syntax highlighting and editor support, check out the ",(0,t.jsx)(n.a,{href:"/docs/v1.0.0-rc.1/tooling/language_server",children:"Language Server"}),"."]})}),"\n",(0,t.jsxs)(n.p,{children:["A Noir program needs a ",(0,t.jsx)(n.code,{children:"main.nr"})," and a ",(0,t.jsx)(n.code,{children:"Nargo.toml"})," file. ",(0,t.jsx)(n.code,{children:"nargo new"})," scaffolds both for us:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"nargo new circuit\n"})}),"\n",(0,t.jsxs)(n.p,{children:["This creates a ",(0,t.jsx)(n.code,{children:"circuit"})," directory containing a ",(0,t.jsx)(n.code,{children:"Nargo.toml"})," (already populated with the package name and ",(0,t.jsx)(n.code,{children:'type = "bin"'}),") and a ",(0,t.jsx)(n.code,{children:"src/main.nr"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["To make our program interesting, let's give it a real use-case scenario: Bob wants to prove he is older than 18, without disclosing his age. Open ",(0,t.jsx)(n.code,{children:"circuit/src/main.nr"})," and replace its contents with:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-rust",metastring:'title="age_check" showLineNumbers ',children:"fn main(age: u8) {\n    assert(age > 18);\n}\n"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.sup,{children:(0,t.jsx)(n.sub,{children:(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/noir/blob/master/examples/browser/src/main.nr#L1-L5",target:"_blank",rel:"noopener noreferrer",children:"Source code: examples/browser/src/main.nr#L1-L5"})})})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"This program accepts a private input called age, and simply proves this number is higher than 18."}),"\n",(0,t.jsx)(n.p,{children:"This is all that we need to get started with Noir."}),"\n",(0,t.jsx)(n.h2,{id:"compiling-the-circuit",children:"Compiling the circuit"}),"\n",(0,t.jsx)(n.p,{children:"Before we can execute a Noir program, we need to compile it into ACIR, an abstract representation of the circuit."}),"\n",(0,t.jsxs)(n.p,{children:["This can be done by cd-ing into our circuit directory and running the ",(0,t.jsx)(n.code,{children:"nargo compile"})," command."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"cd circuit\n\nnargo compile\n"})}),"\n",(0,t.jsxs)(n.p,{children:["This will write the compiled circuit into the ",(0,t.jsx)(n.code,{children:"target"})," directory, which we'll then load into our JS later on."]}),"\n",(0,t.jsx)(n.h2,{id:"setting-up-our-app",children:"Setting up our app"}),"\n",(0,t.jsxs)(n.p,{children:["A single ",(0,t.jsx)(n.code,{children:"html"})," file and a single ",(0,t.jsx)(n.code,{children:"js"})," file are enough for this app. Let's create them in the project root:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"touch index.html index.js\n"})}),"\n",(0,t.jsx)(n.p,{children:"And add something useful to our HTML file:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-html",metastring:'title="index" showLineNumbers ',children:'<!DOCTYPE html>\n<head>\n  <style>\n    .outer {\n        display: flex;\n        justify-content: space-between;\n        width: 100%;\n    }\n    .inner {\n        width: 45%;\n        border: 1px solid black;\n        padding: 10px;\n        word-wrap: break-word;\n    }\n  </style>\n</head>\n<body>\n  <script type="module" src="/index.js"><\/script>\n  <h1>Noir app</h1>\n  <div class="input-area">\n    <input id="age" type="number" placeholder="Enter age" />\n    <button id="submit">Submit Age</button>\n  </div>\n  <div class="outer">\n    <div id="logs" class="inner"><h2>Logs</h2></div>\n    <div id="results" class="inner"><h2>Proof</h2></div>\n  </div>\n</body>\n</html>\n'})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.sup,{children:(0,t.jsx)(n.sub,{children:(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/noir/blob/master/examples/browser/index.html#L1-L31",target:"_blank",rel:"noopener noreferrer",children:"Source code: examples/browser/index.html#L1-L31"})})})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"This is a minimal UI: some CSS to make two boxes that will display output on the screen."}),"\n",(0,t.jsxs)(n.p,{children:["For the JS, rather than logging everything to the console, we'll add a small helper to display output on the page. Paste this boilerplate into ",(0,t.jsx)(n.code,{children:"index.js"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"const show = (id, content) => {\n  const container = document.getElementById(id);\n  container.appendChild(document.createTextNode(content));\n  container.appendChild(document.createElement('br'));\n};\n\ndocument.getElementById('submit').addEventListener('click', async () => {\n  try {\n    // code will go in here\n  }  catch {\n    show('logs', 'Something went wrong');\n  }\n});\n"})}),"\n",(0,t.jsxs)(n.admonition,{type:"info",children:[(0,t.jsx)(n.p,{children:"At this point in the tutorial, your folder structure should look like this:"}),(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tree",children:".\n\u251c\u2500\u2500 circuit\n\u2502   \u251c\u2500\u2500 Nargo.toml\n\u2502   \u251c\u2500\u2500 src\n\u2502   \u2502   \u2514\u2500\u2500 main.nr\n\u2502   \u2514\u2500\u2500 target\n\u2502       \u2514\u2500\u2500 circuit.json\n\u251c\u2500\u2500 index.html\n\u251c\u2500\u2500 index.js\n\u251c\u2500\u2500 package.json\n\u251c\u2500\u2500 etc...\n"})})]}),"\n",(0,t.jsx)(n.h2,{id:"some-more-js",children:"Some more JS"}),"\n",(0,t.jsx)(n.p,{children:"Next we want to execute our circuit to get the witness, and then feed that witness to Barretenberg. Both packages are straightforward to work with. Let's import them at the top of the file and initialize the WASM modules:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="imports" showLineNumbers ',children:"import { Barretenberg, UltraHonkBackend } from '@aztec/bb.js';\nimport { Noir } from '@noir-lang/noir_js';\nimport initNoirC from '@noir-lang/noirc_abi';\nimport initACVM from '@noir-lang/acvm_js';\nimport acvm from '@noir-lang/acvm_js/web/acvm_js_bg.wasm?url';\nimport noirc from '@noir-lang/noirc_abi/web/noirc_abi_wasm_bg.wasm?url';\nimport circuit from './target/circuit.json';
1\n// Initialize WASM modules\nawait Promise.all([initACVM(fetch(acvm)), initNoirC(fetch(noirc))]);\n"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.sup,{children:(0,t.jsx)(n.sub,{children:(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/noir/blob/master/examples/browser/index.js#L1-L11",target:"_blank",rel:"noopener noreferrer",children:"Source code: examples/browser/index.js#L1-L11"})})})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"And instantiate them inside our try-catch block:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="init" showLineNumbers ',children:"show('logs', 'Creating Noir...');\nconst noir = new Noir(circuit);\nshow('logs', 'Creating Barretenberg... \u23f3');\nconst barretenbergAPI = await Barretenberg.new();\nshow('logs', 'Created Barretenberg... \u2705');\nshow('logs', 'Creating UltraHonkBackend...');\nconst backend = new UltraHonkBackend(circuit.bytecode, barretenbergAPI);\n"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.sup,{children:(0,t.jsx)(n.sub,{children:(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/noir/blob/master/examples/browser/index.js#L23-L31",target:"_blank",rel:"noopener noreferrer",children:"Source code: examples/browser/index.js#L23-L31"})})})}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"executing-and-proving",children:"Executing and proving"}),"\n",(0,t.jsxs)(n.p,{children:["Now for the app itself. We're capturing whatever is in the input when the user presses the submit button. Inside our ",(0,t.jsx)(n.code,{children:"try"})," block, let's grab that input and get its value. Noir will execute it and give us a witness:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="execute" showLineNumbers ',children:"const age = document.getElementById('age').value;\nshow('logs', 'Generating witness... \u23f3');\nconst { witness } = await noir.execute({ age });
1\nshow('logs', 'Generated witness... \u2705');\n"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.sup,{children:(0,t.jsx)(n.sub,{children:(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/noir/blob/master/examples/browser/index.js#L32-L37",target:"_blank",rel:"noopener noreferrer",children:"Source code: examples/browser/index.js#L32-L37"})})})}),"\n"]}),"\n",(0,t.jsx)(n.admonition,{type:"note",children:(0,t.jsxs)(n.p,{children:["For the remainder of the tutorial, everything will be happening inside the ",(0,t.jsx)(n.code,{children:"try"})," block"]})}),"\n",(0,t.jsx)(n.p,{children:"Now we're ready to prove. Let's feed some inputs to our circuit and calculate the proof:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="prove" showLineNumbers ',children:"show('logs', 'Generating proof... \u23f3');\nconst proof = await backend.generateProof(witness);\nshow('logs', 'Generated proof... \u2705');\nshow('results', proof.proof);\n"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.sup,{children:(0,t.jsx)(n.sub,{children:(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/noir/blob/master/examples/browser/index.js#L38-L43",target:"_blank",rel:"noopener noreferrer",children:"Source code: examples/browser/index.js#L38-L43"})})})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Our program is now complete. To serve it conveniently, we can use a bundler like ",(0,t.jsx)(n.code,{children:"vite"})," by creating a ",(0,t.jsx)(n.code,{children:"vite.config.js"})," file:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"touch vite.config.js\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Noir needs to load two WASM modules, but Vite doesn't include them by default in the bundle. We need to add the configuration below to ",(0,t.jsx)(n.code,{children:"vite.config.js"})," to make it work.\nWe also need to target ESNext since ",(0,t.jsx)(n.code,{children:"bb.js"})," uses top-level await, which isn't supported in some browsers."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="config" showLineNumbers ',children:"import { defineConfig } from 'vite';\nimport { nodePolyfills } from 'vite-plugin-node-polyfills';\n\nexport default defineConfig({\n  plugins: [\n    nodePolyfills({\n      // Whether to polyfill specific globals.\n      globals: {\n        Buffer: true,\n        global: true,\n        process: true,\n      },\n      // Whether to polyfill `node:` protocol imports.\n      protocolImports: true,\n    }),\n  ],\n  // Serve the app cross-origin isolated so the browser exposes SharedArrayBuffer\n  // and Barretenberg can prove across multiple threads. A production host must\n  // send these same headers on the page (and any documents it embeds).\n  server: {\n    headers: {\n      'Cross-Origin-Opener-Policy': 'same-origin',\n      'Cross-Origin-Embedder-Policy': 'require-corp',\n    },\n  },\n  preview: {\n    headers: {\n      'Cross-Origin-Opener-Policy': 'same-origin',\n      'Cross-Origin-Embedder-Policy': 'require-corp',\n    },\n  },\n  optimizeDeps: {\n    exclude: ['@aztec/bb.js'],\n  },\n  resolve: {\n    alias: {\n      pino: 'pino/browser.js',\n    },\n  },\n});\n"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.sup,{children:(0,t.jsx)(n.sub,{children:(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/noir/blob/master/examples/browser/vite.config.js#L1-L42",target:"_blank",rel:"noopener noreferrer",children:"Source code: examples/browser/vite.config.js#L1-L42"})})})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"This should be enough for vite. We don't even need to install it, just run:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"yarn vite dev\n"})}),"\n",(0,t.jsxs)(n.p,{children:["If it doesn't open a browser for you, visit ",(0,t.jsx)(n.code,{children:"localhost:5173"}),". You should now see the minimal UI with a single input."]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.img,{alt:"Noir Webapp UI",src:r(30133).A+"",width:"910",height:"271"})}),"\n",(0,t.jsxs)(n.p,{children:["Now, our circuit requires a private input ",(0,t.jsx)(n.code,{children:"fn main(age: u8)"}),", and fails if it is less than 18. Let's see if it works. Submit any number above 18 (as long as it fits in 8 bits) and you should get a valid proof. Otherwise the proof won't generate correctly."]}),"\n",(0,t.jsx)(n.p,{children:"The contents of the \"proof\" box aren't meant to be human-readable; it's the raw proof data."}),"\n",(0,t.jsx)(n.h2,{id:"verifying",children:"Verifying"}),"\n",(0,t.jsx)(n.p,{children:"Generating a proof isn't enough on its own; we also want to verify it. Let's add these lines to verify the proof:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",metastring:'title="verify" showLineNumbers ',children:"show('logs', 'Verifying proof... \u231b');\nconst isValid = await backend.verifyProof(proof);
1\nshow('logs', `Proof is ${isValid ? 'valid' : 'invalid'}... \u2705`);\n"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.sup,{children:(0,t.jsx)(n.sub,{children:(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/noir/blob/master/examples/browser/index.js#L45-L49",target:"_blank",rel:"noopener noreferrer",children:"Source code: examples/browser/index.js#L45-L49"})})})}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"You have successfully generated a client-side Noir web app!"}),"\n",(0,t.jsx)(n.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,t.jsx)(n.p,{children:"At this point, you have a working ZK app that runs in the browser (and on mobile too)."}),"\n",(0,t.jsx)(n.p,{children:"If you want to continue learning by doing, here are some challenges for you:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Install ",(0,t.jsx)(n.a,{href:"https://noir-lang.org/docs/installation",children:"nargo"})," and write ",(0,t.jsx)(n.a,{href:"../tooling/tests",children:"Noir tests"})]}),"\n",(0,t.jsxs)(n.li,{children:["Change the circuit to accept a ",(0,t.jsx)(n.a,{href:"../language/data_types/#private--public-types",children:"public input"})," as the cutoff age. It could be different depending on the purpose, for example!"]}),"\n",(0,t.jsxs)(n.li,{children:["Using Noir's Rust-like syntax, write a struct ",(0,t.jsx)(n.code,{children:"Country"})," that implements a trait ",(0,t.jsx)(n.code,{children:"MinAge"})," with a method ",(0,t.jsx)(n.code,{children:"get_min_age"}),". Then, make a struct ",(0,t.jsx)(n.code,{children:"Person"})," have a ",(0,t.jsx)(n.code,{children:"u8"})," as its age and a country of type ",(0,t.jsx)(n.code,{children:"Country"}),". You can pass a ",(0,t.jsx)(n.code,{children:"person"})," in JS just like a JSON object ",(0,t.jsx)(n.code,{children:"person: { age, country: { min_age: 18 }}"})]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["For more examples, see how NoirJS is used with common frameworks in the ",(0,t.jsx)(n.a,{href:"https://github.com/noir-lang/awesome-noir?tab=readme-ov-file#boilerplates",children:"awesome-noir repo"}),"."]})]})}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)}},30133(e,n,r){const i=r.p+"assets/images/webapp1-d6f2b2258acb7f8a416c4fb4264b3697.png";r.d(n,["A",0,i])},28453(e,n,r){r.d(n,{R:()=>o,x:()=>a});var i=r(96540);const t={},s=i.createContext(t);function o(e){const n=i.useContext(s);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:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.