diff --git a/.gitattributes b/.gitattributes
index b27d219..6313b56 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1 @@
-* text=auto
-*.zig text=auto eol=lf
+* text=auto eol=lf
diff --git a/.gitignore b/.gitignore
index eec8995..6b430f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,8 @@
-/zig-out
-/zig-cache
-/saved_logs
-/repos
+zig-out
+zig-cache
+.zig-cache
+saved_logs
+repos
node_modules
-/.env
+.env
d_*.log
diff --git a/build.zig b/build.zig
index 04a7d5b..a67b561 100644
--- a/build.zig
+++ b/build.zig
@@ -1,19 +1,31 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
- const zig_lsp = b.dependency("zig-lsp", .{}).module("zig-lsp");
-
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
+ const block_len = b.option(
+ u8,
+ "block-len",
+ "how many bytes to consider when predicting the next character. " ++
+ "defaults to 8. " ++
+ "note: this may affect performance.",
+ ) orelse 8;
+
+ const options = b.addOptions();
+ options.addOption(u8, "block_len", block_len);
+
+ const lsp_module = b.dependency("lsp-codegen", .{}).module("lsp");
+
const exe = b.addExecutable(.{
.name = "sus",
- .root_source_file = .{ .path = "src/main.zig" },
+ .root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
- exe.root_module.addImport("zig-lsp", zig_lsp);
b.installArtifact(exe);
+ exe.root_module.addImport("lsp", lsp_module);
+ exe.root_module.addOptions("build_options", options);
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
@@ -23,25 +35,4 @@ pub fn build(b: *std.Build) void {
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
-
- const build_exe_tests = b.addTest(.{
- .root_source_file = .{ .path = "src/main.zig" },
- .target = target,
- .optimize = .Debug,
- });
- const run_exe_tests = b.addRunArtifact(build_exe_tests);
-
- const test_step = b.step("test", "Run unit tests");
- test_step.dependOn(&run_exe_tests.step);
-
- const block_len = b.option(
- u8,
- "block-len",
- "how many bytes to consider when predicting the next character. " ++
- "defaults to 8. " ++
- "note: this may affect performance.",
- ) orelse 8;
- const options = b.addOptions();
- options.addOption(u8, "block_len", block_len);
- exe.root_module.addOptions("build_options", options);
}
diff --git a/build.zig.zon b/build.zig.zon
index f5a6c72..4d84dac 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -2,9 +2,9 @@
.name = "sus",
.version = "0.1.0",
.dependencies = .{
- .@"zig-lsp" = .{
- .url = "https://github.com/ziglibs/zig-lsp/archive/1c18c0c64b076e79385e525214a7acc4fdf7d398.tar.gz",
- .hash = "12208c1385f4c1adca29fd17cc93397a60e54d5987bb27b9f961cb1945a96fc4a7e1",
+ .@"lsp-codegen" = .{
+ .url = "git+https://github.com/zigtools/zig-lsp-codegen.git#13d1d9e44e1c602953437438b163950298ff8d85",
+ .hash = "1220518fd5cefa481497bb3484ffab48a42e69c31088e37f52ea361f9ce884d2131c",
},
},
.paths = .{
diff --git a/server/index.ejs b/server/index.ejs
new file mode 100644
index 0000000..85fea17
--- /dev/null
+++ b/server/index.ejs
@@ -0,0 +1,113 @@
+
+
+
+
+
+ sus
+
+
+
+
+
+ Zig Language Server Fuzzer
+
+ Note that results are not expected to be long-lasting. When documenting a result, copy the reproduction steps.
+
+
+ <% for (const entry of entries) { %>
+ -
+
+
+
<%= entry.stderr.slice(0, entry.stderr.indexOf("\n")) %>
+
+
+
+
+ <% } %>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/index.js b/server/index.js
new file mode 100644
index 0000000..8fee831
--- /dev/null
+++ b/server/index.js
@@ -0,0 +1,201 @@
+const express = require("express");
+const sqlite3 = require("better-sqlite3")(":memory:");
+const child_process = require("child_process");
+const axios = require("axios").default;
+const fs = require("fs");
+const path = require("path");
+
+function getHostZigName() {
+ let os = process.platform;
+ if (os == "darwin") os = "macos";
+ if (os == "win32") os = "windows";
+ let arch = process.arch;
+ if (arch == "ia32") arch = "x86";
+ if (arch == "x64") arch = "x86_64";
+ if (arch == "arm64") arch = "aarch64";
+ if (arch == "ppc") arch = "powerpc";
+ if (arch == "ppc64") arch = "powerpc64le";
+ return `${os}-${arch}`;
+}
+
+function getZigDownloadUrl(builtWithZigVersion) {
+ return `https://ziglang.org/builds/zig-${getHostZigName()}-${builtWithZigVersion}.${process.platform === "win32" ? "zip" : "tar.xz"}`;
+}
+
+async function checkAndUpdateZigAndZls() {
+ const index = (await axios.get("https://zigtools-releases.nyc3.digitaloceanspaces.com/zls/index.json", {
+ responseType: "json",
+ })).data;
+ const latest = index.versions[index.latest];
+
+ const zigExePath = path.join(__dirname, "zig_install", `zig${process.platform === "win32" ? ".exe" : ""}`);
+
+ var doWeNeedToInstallNewZig = true;
+ if (fs.existsSync(zigExePath)) {
+ const versionResult = child_process.spawnSync(zigExePath, ["version"]);
+ doWeNeedToInstallNewZig = versionResult.stdout.toString("ascii").trim() !== latest.builtWithZigVersion;
+ }
+
+ if (doWeNeedToInstallNewZig) {
+ console.log("Installing new Zig version", latest.builtWithZigVersion);
+ fs.rmSync(path.join(__dirname, "zig_install"), {
+ force: true,
+ recursive: true,
+ });
+ fs.mkdirSync(path.join(__dirname, "zig_install"));
+
+ const tarball = (await axios.get(getZigDownloadUrl(latest.builtWithZigVersion), {
+ responseType: "arraybuffer"
+ })).data;
+
+ const untar_result = child_process.spawnSync("tar", ["-xJf", "-", "-C", path.join(__dirname, "zig_install"), "--strip-components=1"], {
+ input: tarball
+ });
+
+ if (untar_result.status !== 0) throw "Failed to untar";
+ }
+
+ if (!fs.existsSync(path.join(__dirname, "zls_repo"))) {
+ const clone_result = child_process.spawnSync("git", ["clone", "https://github.com/zigtools/zls", "zls_repo"]);
+ if (clone_result.status !== 0) throw "Failed to clone";
+ }
+
+ const checkout_result = child_process.spawnSync("git", ["checkout", latest.commit], {
+ cwd: path.join(__dirname, "zls_repo"),
+ stdio: ["ignore", "inherit", "inherit"]
+ });
+ if (checkout_result.status !== 0) throw "Failed to checkout";
+
+ const build_result = child_process.spawnSync(zigExePath, ["build"], {
+ cwd: path.join(__dirname, "zls_repo"),
+ stdio: ["ignore", "inherit", "inherit"]
+ });
+ if (build_result.status !== 0) throw "Failed to build";
+
+ commit_hash = latest.commit;
+}
+
+// TODO: handle multiple queued messages
+
+var commit_hash;
+/**
+ * @type {child_process.ChildProcess | undefined}
+ */
+var fuzzer_process;
+var remaining_length = 0;
+var received_data = [];
+
+async function updateAllAndFuzz() {
+ if (fuzzer_process) {
+ fuzzer_process.kill("SIGKILL");
+ }
+
+ await checkAndUpdateZigAndZls();
+
+ fuzzer_process = child_process.spawn("../zig-out/bin/sus", ["--rpc"], {
+ stdio: ["pipe", "pipe", "ignore"],
+ env: {
+ zig_path: path.join(__dirname, "zig_install", `zig${process.platform === "win32" ? ".exe" : ""}`),
+ zls_path: path.join(__dirname, "zls_repo", "zig-out", "bin", `zls${process.platform === "win32" ? ".exe" : ""}`),
+ cycles_per_gen: "250",
+ mode: "markov",
+ markov_training_dir: path.join(__dirname, "zig_install", "lib", "std"),
+ ...process.env
+ }
+ });
+
+ fuzzer_process.stdout.on("data", data => {
+ if (!Buffer.isBuffer(data)) throw "expected buffer";
+
+ if (remaining_length === 0) {
+ remaining_length = data.readUInt32LE();
+
+ const d = data.subarray(4);
+ received_data.push(d);
+ remaining_length -= d.byteLength;
+ } else {
+ remaining_length -= data.byteLength;
+ received_data.push(data);
+ }
+
+ if (remaining_length === 0) {
+ handleData(Buffer.concat(received_data));
+ received_data = [];
+ }
+
+ if (remaining_length < 0) {
+ console.error(remaining_length);
+ throw "too much data";
+ }
+ });
+}
+
+sqlite3.exec(`CREATE TABLE entries (
+ entry_id INTEGER PRIMARY KEY NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ zig_version VARCHAR(32) NOT NULL,
+ zls_version VARCHAR(32) NOT NULL,
+ zls_commit VARCHAR(40) NOT NULL,
+
+ principal TEXT NOT NULL,
+ message TEXT NOT NULL,
+ stderr TEXT NOT NULL
+);`);
+
+/**
+ * @param {Buffer} data
+ */
+function handleData(data) {
+ var offset = 0;
+ const timestamp = new Date(Number(data.readBigInt64LE()));
+ offset += 8;
+
+ const zig_version_len = data.readInt8(offset);
+ offset += 1;
+ const zig_version = data.subarray(offset, offset + zig_version_len).toString("ascii");
+ offset += zig_version_len;
+
+ const zls_version_len = data.readInt8(offset);
+ offset += 1;
+ const zls_version = data.subarray(offset, offset + zls_version_len).toString("ascii");
+ offset += zls_version_len;
+
+ const principal_len = data.readUInt32LE(offset);
+ offset += 4;
+ const principal = data.subarray(offset, offset + principal_len).toString("utf8");
+ offset += principal_len;
+
+ const message_len = data.readUInt16LE(offset);
+ offset += 2;
+ const message = data.subarray(offset, offset + message_len).toString("utf8");
+ offset += message_len;
+
+ const stderr_len = data.readUInt16LE(offset);
+ offset += 2;
+ const stderr = data.subarray(offset, offset + stderr_len).toString("utf8");
+ offset += stderr_len;
+
+ sqlite3.prepare(`
+INSERT INTO entries (created_at, zig_version, zls_version, zls_commit, principal, message, stderr)
+VALUES (?, ?, ?, ?, ?, ?, ?);
+`).bind([+timestamp, zig_version, zls_version, commit_hash, principal, message, stderr]).run();
+}
+
+const app = express();
+app.set("views", __dirname);
+
+app.get("/", (req, res) => {
+ res.render("index.ejs", {
+ entries: sqlite3.prepare("SELECT * from entries ORDER BY created_at DESC").all(),
+ });
+});
+
+app.listen(3000, () => {
+ console.log("Server listening @ http://localhost:3000");
+});
+
+updateAllAndFuzz();
+
+setInterval(() => {
+ updateAllAndFuzz();
+}, 60_000);
diff --git a/server/package-lock.json b/server/package-lock.json
new file mode 100644
index 0000000..e0abfdd
--- /dev/null
+++ b/server/package-lock.json
@@ -0,0 +1,1330 @@
+{
+ "name": "server",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "server",
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^1.6.7",
+ "better-sqlite3": "^9.4.3",
+ "ejs": "^3.1.9",
+ "express": "^4.18.2"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
+ "node_modules/async": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
+ "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
+ "node_modules/axios": {
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
+ "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
+ "dependencies": {
+ "follow-redirects": "^1.15.4",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/better-sqlite3": {
+ "version": "9.4.3",
+ "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-9.4.3.tgz",
+ "integrity": "sha512-ud0bTmD9O3uWJGuXDltyj3R47Nz0OHX8iqPOT5PMspGqlu/qQFn+5S2eFBUCrySpavTjFXbi4EgrfVvPAHlImw==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "bindings": "^1.5.0",
+ "prebuild-install": "^7.1.1"
+ }
+ },
+ "node_modules/bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "dependencies": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz",
+ "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "node_modules/ejs": {
+ "version": "3.1.9",
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
+ "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==",
+ "dependencies": {
+ "jake": "^10.8.5"
+ },
+ "bin": {
+ "ejs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
+ },
+ "node_modules/filelist": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
+ "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
+ "dependencies": {
+ "minimatch": "^5.0.1"
+ }
+ },
+ "node_modules/filelist/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/filelist/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
+ "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
+ "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/jake": {
+ "version": "10.8.7",
+ "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
+ "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==",
+ "dependencies": {
+ "async": "^3.2.3",
+ "chalk": "^4.0.2",
+ "filelist": "^1.0.4",
+ "minimatch": "^3.1.2"
+ },
+ "bin": {
+ "jake": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/napi-build-utils": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/node-abi": {
+ "version": "3.56.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.56.0.tgz",
+ "integrity": "sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==",
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
+ "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
+ "node_modules/prebuild-install": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz",
+ "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==",
+ "dependencies": {
+ "detect-libc": "^2.0.0",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^1.0.1",
+ "node-abi": "^3.3.0",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^4.0.0",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0"
+ },
+ "bin": {
+ "prebuild-install": "bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/semver": {
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
+ "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz",
+ "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==",
+ "dependencies": {
+ "define-data-property": "^1.1.2",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.3",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz",
+ "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==",
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/simple-get": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+ "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "decompress-response": "^6.0.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tar-fs": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+ "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ }
+ }
+}
diff --git a/server/package.json b/server/package.json
new file mode 100644
index 0000000..a5be8e6
--- /dev/null
+++ b/server/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "server",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "Auguste Rame",
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^1.6.7",
+ "better-sqlite3": "^9.4.3",
+ "ejs": "^3.1.9",
+ "express": "^4.18.2"
+ }
+}
diff --git a/src/Fuzzer.zig b/src/Fuzzer.zig
index a37ddc5..a9ac9bc 100644
--- a/src/Fuzzer.zig
+++ b/src/Fuzzer.zig
@@ -1,19 +1,16 @@
const std = @import("std");
-const lsp = @import("zig-lsp");
const utils = @import("utils.zig");
-const lsp_types = lsp.types;
-const ChildProcess = std.ChildProcess;
+const lsp = @import("lsp");
const Mode = @import("mode.zig").Mode;
const ModeName = @import("mode.zig").ModeName;
+const Reducer = @import("Reducer.zig");
const Fuzzer = @This();
-pub const Connection = lsp.Connection(std.fs.File.Reader, std.fs.File.Writer, Fuzzer);
-
// note: if you add or change config options, update the usage in main.zig then
// run `zig build run -- --help` and paste the contents into the README
pub const Config = struct {
- output_as_dir: bool,
+ rpc: bool,
zls_path: []const u8,
mode_name: ModeName,
cycles_per_gen: u32,
@@ -22,7 +19,7 @@ pub const Config = struct {
zls_version: []const u8,
pub const Defaults = struct {
- pub const output_as_dir = false;
+ pub const rpc = false;
pub const cycles_per_gen: u32 = 25;
};
@@ -43,100 +40,76 @@ pub const Config = struct {
}
};
+pub const SentMessage = struct {
+ id: i64,
+ start: u32,
+ end: u32,
+};
+
allocator: std.mem.Allocator,
-connection: Connection,
-progress_node: *std.Progress.Node,
+progress_node: std.Progress.Node,
mode: *Mode,
config: Config,
-rand: std.rand.DefaultPrng,
+rand: std.Random.DefaultPrng,
cycle: usize = 0,
-zls_process: ChildProcess,
-stderr_thread_keep_running: std.atomic.Value(bool) = std.atomic.Value(bool).init(true),
-stderr_thread: std.Thread,
+zls_process: std.process.Child,
+id: i64 = 0,
+
+transport: lsp.TransportOverStdio,
+
+sent_data: std.ArrayListUnmanaged(u8) = .{},
+sent_messages: std.ArrayListUnmanaged(SentMessage) = .{},
+sent_ids: std.AutoArrayHashMapUnmanaged(i64, void) = .{},
-stdin_output: std.ArrayListUnmanaged(u8) = .{},
-stdout_output: std.ArrayListUnmanaged(u8) = .{},
-stderr_output: std.ArrayListUnmanaged(u8) = .{},
principal_file_source: []const u8 = "",
principal_file_uri: []const u8,
pub fn create(
allocator: std.mem.Allocator,
- progress: *std.Progress,
+ progress: std.Progress.Node,
mode: *Mode,
config: Config,
+ principal_file_uri: []const u8,
) !*Fuzzer {
- var fuzzer = try allocator.create(Fuzzer);
+ const fuzzer = try allocator.create(Fuzzer);
errdefer allocator.destroy(fuzzer);
- var seed: u64 = 0;
- try std.os.getrandom(std.mem.asBytes(&seed));
-
- const cwd_path = try std.process.getCwdAlloc(allocator);
- defer allocator.free(cwd_path);
-
- const principal_file_path = try std.fs.path.join(allocator, &.{ cwd_path, "tmp", "principal.zig" });
- defer allocator.free(principal_file_path);
-
- const principal_file_uri = try std.fmt.allocPrint(allocator, "{+/}", .{std.Uri{
- .scheme = "file",
- .user = null,
- .password = null,
- .host = null,
- .port = null,
- .path = principal_file_path,
- .query = null,
- .fragment = null,
- }});
- errdefer allocator.free(principal_file_uri);
-
- var env_map = try allocator.create(std.process.EnvMap);
- env_map.* = std.process.getEnvMap(allocator) catch std.process.EnvMap.init(allocator);
- try env_map.put("NO_COLOR", "");
+ const seed = std.crypto.random.int(u64);
- defer {
- env_map.deinit();
- allocator.destroy(env_map);
- }
+ var env_map = try std.process.getEnvMap(allocator);
+ defer env_map.deinit();
+
+ try env_map.put("NO_COLOR", "");
- var zls_process = std.ChildProcess.init(&.{ config.zls_path, "--enable-debug-log" }, allocator);
- zls_process.env_map = env_map;
+ var zls_process = std.process.Child.init(&.{ config.zls_path, "--enable-debug-log" }, allocator);
+ zls_process.env_map = &env_map;
zls_process.stdin_behavior = .Pipe;
- zls_process.stderr_behavior = .Pipe;
+ zls_process.stderr_behavior = .Ignore;
zls_process.stdout_behavior = .Pipe;
try zls_process.spawn();
errdefer _ = zls_process.kill() catch @panic("failed to kill zls process");
+ var sent_ids = std.AutoArrayHashMapUnmanaged(i64, void){};
+ try sent_ids.ensureTotalCapacity(allocator, config.cycles_per_gen);
+
fuzzer.* = .{
.allocator = allocator,
- .connection = undefined, // set below
.progress_node = progress.start("fuzzer", 0),
.mode = mode,
.config = config,
- .rand = std.rand.DefaultPrng.init(seed),
+ .rand = std.Random.DefaultPrng.init(seed),
.zls_process = zls_process,
- .stderr_thread = undefined, // set below
+ .transport = lsp.TransportOverStdio.init(zls_process.stdout.?, zls_process.stdin.?),
+ .sent_ids = sent_ids,
.principal_file_uri = principal_file_uri,
};
- fuzzer.connection = Connection.init(
- allocator,
- zls_process.stdout.?.reader(),
- zls_process.stdin.?.writer(),
- fuzzer,
- );
-
- fuzzer.stderr_thread = try std.Thread.spawn(.{}, readStderr, .{fuzzer});
-
return fuzzer;
}
pub fn wait(fuzzer: *Fuzzer) void {
- fuzzer.stderr_thread_keep_running.store(false, .Release);
- fuzzer.stderr_thread.join();
-
_ = fuzzer.zls_process.wait() catch |err| {
std.log.err("failed to await zls process: {}", .{err});
};
@@ -145,54 +118,36 @@ pub fn wait(fuzzer: *Fuzzer) void {
pub fn destroy(fuzzer: *Fuzzer) void {
const allocator = fuzzer.allocator;
- fuzzer.stdin_output.deinit(allocator);
- fuzzer.stdout_output.deinit(allocator);
- fuzzer.stderr_output.deinit(allocator);
+ fuzzer.sent_data.deinit(allocator);
+ fuzzer.sent_messages.deinit(allocator);
+ fuzzer.sent_ids.deinit(allocator);
allocator.free(fuzzer.principal_file_source);
- allocator.free(fuzzer.principal_file_uri);
-
- fuzzer.connection.write_buffer.deinit(fuzzer.connection.allocator);
- fuzzer.connection.callback_map.deinit(fuzzer.connection.allocator);
fuzzer.* = undefined;
allocator.destroy(fuzzer);
}
-fn readStderr(fuzzer: *Fuzzer) void {
- var buffer: [std.mem.page_size]u8 = undefined;
- while (fuzzer.stderr_thread_keep_running.load(.Acquire)) {
- const stderr = fuzzer.zls_process.stderr.?;
- const amt = stderr.reader().read(&buffer) catch break;
- fuzzer.stderr_output.appendSlice(fuzzer.allocator, buffer[0..amt]) catch break;
- }
-}
-
-pub fn random(fuzzer: *Fuzzer) std.rand.Random {
+pub fn random(fuzzer: *Fuzzer) std.Random {
return fuzzer.rand.random();
}
pub fn initCycle(fuzzer: *Fuzzer) !void {
- fuzzer.progress_node.activate();
-
- var arena = std.heap.ArenaAllocator.init(fuzzer.allocator);
- defer arena.deinit();
-
- _ = try fuzzer.connection.requestSync(arena.allocator(), "initialize", lsp_types.InitializeParams{
+ try fuzzer.sendRequest("initialize", lsp.types.InitializeParams{
.capabilities = .{},
});
- try fuzzer.connection.notify("initialized", .{});
+ try fuzzer.sendNotification("initialized", .{});
var settings = std.json.ObjectMap.init(fuzzer.allocator);
defer settings.deinit();
try settings.putNoClobber("skip_std_references", .{ .bool = true }); // references collection into std is very slow
try settings.putNoClobber("zig_exe_path", .{ .string = fuzzer.config.zig_env.value.zig_exe });
- try fuzzer.connection.notify("workspace/didChangeConfiguration", lsp_types.DidChangeConfigurationParams{
+ try fuzzer.sendNotification("workspace/didChangeConfiguration", lsp.types.DidChangeConfigurationParams{
.settings = .{ .object = settings },
});
- try fuzzer.connection.notify("textDocument/didOpen", lsp_types.DidOpenTextDocumentParams{ .textDocument = .{
+ try fuzzer.sendNotification("textDocument/didOpen", lsp.types.DidOpenTextDocumentParams{ .textDocument = .{
.uri = fuzzer.principal_file_uri,
.languageId = "zig",
.version = @intCast(fuzzer.cycle),
@@ -203,30 +158,31 @@ pub fn initCycle(fuzzer: *Fuzzer) !void {
pub fn closeCycle(fuzzer: *Fuzzer) !void {
fuzzer.progress_node.end();
- var arena = std.heap.ArenaAllocator.init(fuzzer.allocator);
- defer arena.deinit();
-
- _ = try fuzzer.connection.notify("textDocument/didClose", .{
+ _ = try fuzzer.sendNotification("textDocument/didClose", .{
.textDocument = .{ .uri = fuzzer.principal_file_uri },
});
- _ = try fuzzer.connection.requestSync(arena.allocator(), "shutdown", {});
- try fuzzer.connection.notify("exit", {});
+ _ = try fuzzer.sendRequest("shutdown", {});
+ try fuzzer.sendNotification("exit", {});
+}
+
+pub fn reduce(fuzzer: *Fuzzer) !void {
+ var reducer = Reducer.fromFuzzer(fuzzer);
+ defer reducer.deinit();
+
+ try reducer.reduce();
}
pub fn fuzz(fuzzer: *Fuzzer) !void {
- fuzzer.progress_node.setCompletedItems(fuzzer.cycle);
fuzzer.cycle += 1;
if (fuzzer.cycle % fuzzer.config.cycles_per_gen == 0) {
- var arena_allocator = std.heap.ArenaAllocator.init(fuzzer.allocator);
- defer arena_allocator.deinit();
- const arena = arena_allocator.allocator();
-
- while (fuzzer.connection.callback_map.count() != 0) {
- _ = arena_allocator.reset(.retain_capacity);
- try fuzzer.connection.acceptUntilResponse(arena);
- }
+ // detch from cycle count to prevent pipe fillage on windows
+ try utils.waitForResponseToRequests(
+ fuzzer.allocator,
+ &fuzzer.transport,
+ &fuzzer.sent_ids,
+ );
while (true) {
fuzzer.allocator.free(fuzzer.principal_file_source);
@@ -234,80 +190,20 @@ pub fn fuzz(fuzzer: *Fuzzer) !void {
if (std.unicode.utf8ValidateSlice(fuzzer.principal_file_source)) break;
}
- try fuzzer.connection.notify("textDocument/didChange", lsp_types.DidChangeTextDocumentParams{
+ fuzzer.sent_data.clearRetainingCapacity();
+ fuzzer.sent_messages.clearRetainingCapacity();
+ std.debug.assert(fuzzer.sent_ids.count() == 0);
+
+ try fuzzer.sendNotification("textDocument/didChange", lsp.types.DidChangeTextDocumentParams{
.textDocument = .{ .uri = fuzzer.principal_file_uri, .version = @intCast(fuzzer.cycle) },
- .contentChanges = &[1]lsp_types.TextDocumentContentChangeEvent{
+ .contentChanges = &[1]lsp.types.TextDocumentContentChangeEvent{
.{ .literal_1 = .{ .text = fuzzer.principal_file_source } },
},
});
}
- try fuzzer.fuzzFeatureRandom(fuzzer.principal_file_uri, fuzzer.principal_file_source);
-}
-
-pub fn logPrincipal(fuzzer: *Fuzzer) !void {
- var bytes: [32]u8 = undefined;
- fuzzer.random().bytes(&bytes);
-
- try std.fs.cwd().makePath("saved_logs");
-
- const log_entry_path = try std.fmt.allocPrint(fuzzer.allocator, "saved_logs/{d}", .{std.fmt.fmtSliceHexLower(&bytes)});
- defer fuzzer.allocator.free(log_entry_path);
-
- if (fuzzer.config.output_as_dir) {
- try std.fs.cwd().makeDir(log_entry_path);
-
- var entry_dir = try std.fs.cwd().openDir(log_entry_path, .{});
- defer entry_dir.close();
- const principal_file = try entry_dir.createFile("principal.zig", .{});
- defer principal_file.close();
-
- try principal_file.writeAll(fuzzer.principal_file_source);
-
- for (
- [_]std.ArrayListUnmanaged(u8){ fuzzer.stdin_output, fuzzer.stdout_output, fuzzer.stderr_output },
- [_][]const u8{ "stdin.log", "stdout.log", "stderr.log" },
- ) |output, path| {
- const output_file = try entry_dir.createFile(path, .{});
- defer output_file.close();
-
- try output_file.writeAll(output.items);
- }
- } else {
- const entry_file = try std.fs.cwd().createFile(log_entry_path, .{});
- defer entry_file.close();
-
- var iovecs: [13]std.os.iovec_const = undefined;
-
- for ([_][]const u8{
- std.mem.asBytes(&std.time.milliTimestamp()),
-
- std.mem.asBytes(&@as(u8, @intCast(fuzzer.config.zig_env.value.version.len))),
- fuzzer.config.zig_env.value.version,
-
- std.mem.asBytes(&@as(u8, @intCast(fuzzer.config.zls_version.len))),
- fuzzer.config.zls_version,
-
- std.mem.asBytes(&@as(u32, @intCast(fuzzer.principal_file_source.len))),
- fuzzer.principal_file_source,
-
- std.mem.asBytes(&@as(u32, @intCast(fuzzer.stdin_output.items.len))),
- fuzzer.stdin_output.items,
-
- std.mem.asBytes(&@as(u32, @intCast(fuzzer.stdout_output.items.len))),
- fuzzer.stdout_output.items,
-
- std.mem.asBytes(&@as(u32, @intCast(fuzzer.stderr_output.items.len))),
- fuzzer.stderr_output.items,
- }, 0..) |val, i| {
- iovecs[i] = .{
- .iov_base = val.ptr,
- .iov_len = val.len,
- };
- }
-
- try entry_file.writevAll(&iovecs);
- }
+ try fuzzer.fuzzFeatureRandom(fuzzer.principal_file_uri, fuzzer.principal_file_source);
+ fuzzer.progress_node.completeOne();
}
pub const WhatToFuzz = enum {
@@ -329,29 +225,6 @@ pub const WhatToFuzz = enum {
rename,
};
-fn requestCallback(comptime method: []const u8) lsp.RequestCallback(Connection, method) {
- const Context = struct {
- pub fn res(_: *Connection, _: lsp.Result(method)) !void {}
-
- pub fn err(_: *Connection, resperr: lsp_types.ResponseError) !void {
- return switch (resperr.code) {
- @intFromEnum(lsp_types.ErrorCodes.ParseError) => error.ParseError,
- @intFromEnum(lsp_types.ErrorCodes.InvalidRequest) => error.InvalidRequest,
- @intFromEnum(lsp_types.ErrorCodes.MethodNotFound) => error.MethodNotFound,
- @intFromEnum(lsp_types.ErrorCodes.InvalidParams) => error.InvalidParams,
- @intFromEnum(lsp_types.ErrorCodes.InternalError) => error.InternalError,
- @intFromEnum(lsp_types.ErrorCodes.ServerNotInitialized) => error.ServerNotInitialized,
- @intFromEnum(lsp_types.ErrorCodes.UnknownErrorCode) => error.UnknownErrorCode,
- else => error.InternalError,
- };
- }
- };
- return .{
- .onResponse = &Context.res,
- .onError = &Context.err,
- };
-}
-
pub fn fuzzFeatureRandom(
fuzzer: *Fuzzer,
file_uri: []const u8,
@@ -361,89 +234,78 @@ pub fn fuzzFeatureRandom(
const wtf = rand.enumValue(WhatToFuzz);
switch (wtf) {
- .completion => try fuzzer.connection.request(
+ .completion => try fuzzer.sendRequest(
"textDocument/completion",
.{
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
},
- requestCallback("textDocument/completion"),
),
- .declaration => try fuzzer.connection.request(
+ .declaration => try fuzzer.sendRequest(
"textDocument/declaration",
.{
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
},
- requestCallback("textDocument/declaration"),
),
- .definition => try fuzzer.connection.request(
+ .definition => try fuzzer.sendRequest(
"textDocument/definition",
.{
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
},
- requestCallback("textDocument/definition"),
),
- .type_definition => try fuzzer.connection.request(
+ .type_definition => try fuzzer.sendRequest(
"textDocument/typeDefinition",
.{
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
},
- requestCallback("textDocument/typeDefinition"),
),
- .implementation => try fuzzer.connection.request(
+ .implementation => try fuzzer.sendRequest(
"textDocument/implementation",
.{
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
},
- requestCallback("textDocument/implementation"),
),
- .references => try fuzzer.connection.request(
+ .references => try fuzzer.sendRequest(
"textDocument/references",
.{
.context = .{ .includeDeclaration = rand.boolean() },
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
},
- requestCallback("textDocument/references"),
),
- .signature_help => try fuzzer.connection.request(
+ .signature_help => try fuzzer.sendRequest(
"textDocument/signatureHelp",
.{
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
},
- requestCallback("textDocument/signatureHelp"),
),
- .hover => try fuzzer.connection.request(
+ .hover => try fuzzer.sendRequest(
"textDocument/hover",
.{
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
},
- requestCallback("textDocument/hover"),
),
- .semantic => try fuzzer.connection.request(
+ .semantic => try fuzzer.sendRequest(
"textDocument/semanticTokens/full",
.{ .textDocument = .{ .uri = file_uri } },
- requestCallback("textDocument/semanticTokens/full"),
),
- .document_symbol => try fuzzer.connection.request(
+ .document_symbol => try fuzzer.sendRequest(
"textDocument/documentSymbol",
.{ .textDocument = .{ .uri = file_uri } },
- requestCallback("textDocument/documentSymbol"),
),
.folding_range => {
- _ = try fuzzer.connection.request(
+ _ = try fuzzer.sendRequest(
"textDocument/foldingRange",
.{ .textDocument = .{ .uri = file_uri } },
- requestCallback("textDocument/foldingRange"),
);
},
- .formatting => try fuzzer.connection.request(
+ .formatting => try fuzzer.sendRequest(
"textDocument/formatting",
.{
.textDocument = .{ .uri = file_uri },
@@ -452,90 +314,63 @@ pub fn fuzzFeatureRandom(
.insertSpaces = true,
},
},
- requestCallback("textDocument/formatting"),
),
- .document_highlight => try fuzzer.connection.request(
+ .document_highlight => try fuzzer.sendRequest(
"textDocument/documentHighlight",
.{
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
},
- requestCallback("textDocument/documentHighlight"),
),
- .inlay_hint => try fuzzer.connection.request(
+ .inlay_hint => try fuzzer.sendRequest(
"textDocument/inlayHint",
.{
.textDocument = .{ .uri = file_uri },
.range = utils.randomRange(rand, file_data),
},
- requestCallback("textDocument/inlayHint"),
),
- // TODO: Nest positions properly to avoid crash
- // .selection_range => {
- // var positions: [16]lsp_types.Position = undefined;
- // for (positions) |*pos| {
- // pos.* = utils.randomPosition(rand, file_data);
- // }
- // try fuzzer.connection.request(
- // "textDocument/selectionRange",
- // .{
- // .textDocument = .{ .uri = file_uri },
- // .positions = &positions,
- // },
- // requestCallback("textDocument/selectionRange"),
- // );
- // },
- .rename => try fuzzer.connection.request(
+ .rename => try fuzzer.sendRequest(
"textDocument/rename",
.{
.textDocument = .{ .uri = file_uri },
.position = utils.randomPosition(rand, file_data),
.newName = "helloWorld",
},
- requestCallback("textDocument/rename"),
),
}
}
-// Handlers
+fn sendRequest(fuzzer: *Fuzzer, comptime method: []const u8, params: lsp.ParamsType(method)) !void {
+ const start = fuzzer.sent_data.items.len;
-pub fn @"window/logMessage"(_: *Connection, params: lsp.Params("window/logMessage")) !void {
- switch (params.type) {
- .Error => std.log.err("logMessage: {s}", .{params.message}),
- .Warning => std.log.warn("logMessage: {s}", .{params.message}),
- .Info => std.log.info("logMessage: {s}", .{params.message}),
- .Log => std.log.debug("logMessage: {s}", .{params.message}),
- }
-}
+ const request_id = fuzzer.id;
-pub fn @"window/showMessage"(_: *Connection, params: lsp.Params("window/showMessage")) !void {
- switch (params.type) {
- .Error => std.log.err("showMessage: {s}", .{params.message}),
- .Warning => std.log.warn("showMessage: {s}", .{params.message}),
- .Info => std.log.info("showMessage: {s}", .{params.message}),
- .Log => std.log.debug("showMessage: {s}", .{params.message}),
- }
-}
+ try utils.stringifyRequest(
+ fuzzer.sent_data.writer(fuzzer.allocator),
+ &fuzzer.id,
+ method,
+ params,
+ );
-pub fn @"textDocument/publishDiagnostics"(_: *Connection, _: lsp.Params("textDocument/publishDiagnostics")) !void {}
-pub fn @"workspace/semanticTokens/refresh"(_: *Connection, _: lsp.types.RequestId, _: lsp.Params("workspace/semanticTokens/refresh")) !void {}
+ try fuzzer.transport.writeJsonMessage(fuzzer.sent_data.items[start..]);
-pub fn dataRecv(
- conn: *Connection,
- data: []const u8,
-) !void {
- const fuzzer: *Fuzzer = conn.context;
- try fuzzer.stdout_output.ensureUnusedCapacity(fuzzer.allocator, data.len + 1);
- fuzzer.stdout_output.appendSliceAssumeCapacity(data);
- fuzzer.stdout_output.appendAssumeCapacity('\n');
+ try fuzzer.sent_messages.append(fuzzer.allocator, .{
+ .id = request_id,
+ .start = @intCast(start),
+ .end = @intCast(fuzzer.sent_data.items.len),
+ });
+
+ fuzzer.sent_ids.putAssumeCapacityNoClobber(request_id, {});
}
-pub fn dataSend(
- conn: *Connection,
- data: []const u8,
-) !void {
- const fuzzer: *Fuzzer = conn.context;
- try fuzzer.stdin_output.ensureUnusedCapacity(fuzzer.allocator, data.len + 1);
- fuzzer.stdin_output.appendSliceAssumeCapacity(data);
- fuzzer.stdin_output.appendAssumeCapacity('\n');
+fn sendNotification(fuzzer: *Fuzzer, comptime method: []const u8, params: lsp.ParamsType(method)) !void {
+ const start = fuzzer.sent_data.items.len;
+
+ try utils.stringifyNotification(
+ fuzzer.sent_data.writer(fuzzer.allocator),
+ method,
+ params,
+ );
+
+ try fuzzer.transport.writeJsonMessage(fuzzer.sent_data.items[start..]);
}
diff --git a/src/Reducer.zig b/src/Reducer.zig
new file mode 100644
index 0000000..90a4251
--- /dev/null
+++ b/src/Reducer.zig
@@ -0,0 +1,265 @@
+const std = @import("std");
+
+const utils = @import("utils.zig");
+const Fuzzer = @import("Fuzzer.zig");
+const lsp = @import("lsp");
+
+const Reducer = @This();
+
+allocator: std.mem.Allocator,
+sent_data: []const u8,
+sent_messages: []const Fuzzer.SentMessage,
+principal_file_source: []const u8,
+principal_file_uri: []const u8,
+config: Fuzzer.Config,
+random: std.Random,
+
+zls_process: std.process.Child,
+transport: lsp.TransportOverStdio,
+id: i64 = 0,
+write_buffer: std.ArrayListUnmanaged(u8) = .{},
+
+pub fn fromFuzzer(fuzzer: *Fuzzer) Reducer {
+ return .{
+ .allocator = fuzzer.allocator,
+ .sent_data = fuzzer.sent_data.items,
+ .sent_messages = fuzzer.sent_messages.items,
+ .config = fuzzer.config,
+ .principal_file_source = fuzzer.principal_file_source,
+ .principal_file_uri = fuzzer.principal_file_uri,
+ .random = fuzzer.random(),
+
+ .zls_process = undefined,
+ .transport = undefined,
+ };
+}
+
+pub fn deinit(reducer: *Reducer) void {
+ reducer.write_buffer.deinit(reducer.allocator);
+}
+
+const Message = struct { id: i64, data: []const u8 };
+fn message(reducer: *Reducer, index: u32) Message {
+ const msg = reducer.sent_messages[index];
+ return .{
+ .id = msg.id,
+ .data = reducer.sent_data[msg.start..msg.end],
+ };
+}
+
+/// Creates new process and does LSP init; does not kill old one
+fn createNewProcessAndInitialize(reducer: *Reducer) !void {
+ reducer.id = 0;
+
+ var env_map = try std.process.getEnvMap(reducer.allocator);
+ defer env_map.deinit();
+
+ try env_map.put("NO_COLOR", "");
+
+ var zls_process = std.process.Child.init(&.{ reducer.config.zls_path, "--enable-debug-log" }, reducer.allocator);
+ zls_process.env_map = &env_map;
+ zls_process.stdin_behavior = .Pipe;
+ zls_process.stderr_behavior = .Pipe;
+ zls_process.stdout_behavior = .Pipe;
+
+ try zls_process.spawn();
+ errdefer _ = zls_process.kill() catch @panic("failed to kill zls process");
+
+ reducer.zls_process = zls_process;
+ reducer.transport = lsp.TransportOverStdio.init(reducer.zls_process.stdout.?, reducer.zls_process.stdin.?);
+
+ try reducer.sendRequest("initialize", lsp.types.InitializeParams{
+ .capabilities = .{},
+ });
+ try reducer.sendNotification("initialized", .{});
+
+ var settings = std.json.ObjectMap.init(reducer.allocator);
+ defer settings.deinit();
+ try settings.putNoClobber("skip_std_references", .{ .bool = true }); // references collection into std is very slow
+ try settings.putNoClobber("zig_exe_path", .{ .string = reducer.config.zig_env.value.zig_exe });
+
+ try reducer.sendNotification("workspace/didChangeConfiguration", lsp.types.DidChangeConfigurationParams{
+ .settings = .{ .object = settings },
+ });
+
+ try reducer.sendNotification("textDocument/didOpen", lsp.types.DidOpenTextDocumentParams{ .textDocument = .{
+ .uri = reducer.principal_file_uri,
+ .languageId = "zig",
+ .version = 0,
+ .text = reducer.principal_file_source,
+ } });
+}
+
+fn shutdownProcessCleanly(reducer: *Reducer) !void {
+ _ = try reducer.sendNotification("textDocument/didClose", .{
+ .textDocument = .{ .uri = reducer.principal_file_uri },
+ });
+
+ _ = try reducer.sendRequest("shutdown", {});
+ try reducer.sendNotification("exit", {});
+}
+
+pub fn reduce(reducer: *Reducer) !void {
+ try reducer.createNewProcessAndInitialize();
+
+ var stderr = std.ArrayListUnmanaged(u8){};
+ defer stderr.deinit(reducer.allocator);
+
+ var keep_running_stderr = std.atomic.Value(bool).init(true);
+ const stderr_thread = try std.Thread.spawn(.{}, readStderr, .{
+ reducer.allocator,
+ reducer.zls_process.stderr.?,
+ &stderr,
+ &keep_running_stderr,
+ });
+
+ const msg: Message = for (0..reducer.sent_messages.len) |msg_idx| {
+ const msg = reducer.message(@intCast(msg_idx));
+ reducer.repeatMessage(msg) catch {
+ keep_running_stderr.store(false, .release);
+ stderr_thread.join();
+ _ = try reducer.zls_process.wait();
+ break msg;
+ };
+ } else {
+ std.log.err("Could not reproduce!", .{});
+ try reducer.shutdownProcessCleanly();
+ keep_running_stderr.store(false, .release);
+ stderr_thread.join();
+ _ = try reducer.zls_process.wait();
+ return;
+ };
+
+ const processed_stderr = if (std.mem.indexOf(u8, stderr.items, "panic:")) |panic_start|
+ stderr.items[panic_start..]
+ else
+ stderr.items;
+
+ if (reducer.config.rpc) {
+ var iovecs: [12]std.posix.iovec_const = undefined;
+
+ for ([_][]const u8{
+ std.mem.asBytes(&@as(u32, @intCast(
+ 8 +
+ 1 + reducer.config.zig_env.value.version.len +
+ 1 + reducer.config.zls_version.len +
+ 4 + reducer.principal_file_source.len +
+ 2 + msg.data.len +
+ 2 + processed_stderr.len,
+ ))),
+
+ std.mem.asBytes(&std.time.milliTimestamp()),
+
+ std.mem.asBytes(&@as(u8, @intCast(reducer.config.zig_env.value.version.len))),
+ reducer.config.zig_env.value.version,
+
+ std.mem.asBytes(&@as(u8, @intCast(reducer.config.zls_version.len))),
+ reducer.config.zls_version,
+
+ std.mem.asBytes(&@as(u32, @intCast(reducer.principal_file_source.len))),
+ reducer.principal_file_source,
+
+ std.mem.asBytes(&@as(u16, @intCast(msg.data.len))),
+ msg.data,
+
+ std.mem.asBytes(&@as(u16, @intCast(processed_stderr.len))),
+ processed_stderr,
+ }, 0..) |val, i| {
+ iovecs[i] = .{ .base = val.ptr, .len = val.len };
+ }
+
+ try std.io.getStdOut().writevAll(&iovecs);
+ } else {
+ var bytes: [32]u8 = undefined;
+ reducer.random.bytes(&bytes);
+
+ try std.fs.cwd().makePath("saved_logs");
+
+ const log_entry_path = try std.fmt.allocPrint(reducer.allocator, "saved_logs/{d}", .{std.fmt.fmtSliceHexLower(&bytes)});
+ defer reducer.allocator.free(log_entry_path);
+
+ const entry_file = try std.fs.cwd().createFile(log_entry_path, .{});
+ defer entry_file.close();
+
+ var timestamp_buf: [32]u8 = undefined;
+ var iovecs: [16]std.posix.iovec_const = undefined;
+
+ for ([_][]const u8{
+ "timestamp: ",
+ try std.fmt.bufPrint(×tamp_buf, "{d}", .{std.time.milliTimestamp()}),
+ "\n",
+ "zig version: ",
+ reducer.config.zig_env.value.version,
+ "\nzls version: ",
+ reducer.config.zls_version,
+ "\n\n",
+ "principal:\n",
+ reducer.principal_file_source,
+ "\n\n",
+ "message:\n",
+ msg.data,
+ "\n\n",
+ "stderr:\n",
+ processed_stderr,
+ }, &iovecs) |val, *iovec| {
+ iovec.* = .{ .base = val.ptr, .len = val.len };
+ }
+
+ try entry_file.writevAll(&iovecs);
+ }
+}
+
+fn repeatMessage(reducer: *Reducer, msg: Message) !void {
+ try reducer.transport.writeJsonMessage(msg.data);
+
+ try utils.waitForResponseToRequest(
+ reducer.allocator,
+ &reducer.transport,
+ msg.id,
+ );
+}
+
+fn sendRequest(reducer: *Reducer, comptime method: []const u8, params: lsp.ParamsType(method)) !void {
+ const request_id = reducer.id;
+ reducer.write_buffer.clearRetainingCapacity();
+
+ try utils.stringifyRequest(
+ reducer.write_buffer.writer(reducer.allocator),
+ &reducer.id,
+ method,
+ params,
+ );
+
+ try reducer.transport.writeJsonMessage(reducer.write_buffer.items);
+
+ try utils.waitForResponseToRequest(
+ reducer.allocator,
+ &reducer.transport,
+ request_id,
+ );
+}
+
+fn sendNotification(reducer: *Reducer, comptime method: []const u8, params: lsp.ParamsType(method)) !void {
+ reducer.write_buffer.clearRetainingCapacity();
+
+ try utils.stringifyNotification(
+ reducer.write_buffer.writer(reducer.allocator),
+ method,
+ params,
+ );
+
+ try reducer.transport.writeJsonMessage(reducer.write_buffer.items);
+}
+
+fn readStderr(
+ allocator: std.mem.Allocator,
+ stderr: std.fs.File,
+ out: *std.ArrayListUnmanaged(u8),
+ keep_running: *std.atomic.Value(bool),
+) void {
+ var buffer: [4096]u8 = undefined;
+ while (keep_running.load(.acquire)) {
+ const amt = stderr.read(&buffer) catch break;
+ out.appendSlice(allocator, buffer[0..amt]) catch break;
+ }
+}
diff --git a/src/main.zig b/src/main.zig
index c864c21..19a88a3 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -46,18 +46,18 @@ fn initConfig(allocator: std.mem.Allocator, env_map: std.process.EnvMap, arg_it:
};
defer if (maybe_zig_path) |path| allocator.free(path);
- var output_as_dir =
- if (env_map.get("output_as_dir")) |str|
+ var rpc =
+ if (env_map.get("rpc")) |str|
if (std.mem.eql(u8, str, "false"))
false
else if (std.mem.eql(u8, str, "true"))
true
else blk: {
- std.log.warn("expected boolean (true|false) in env option 'output_as_dir' but got '{s}'", .{str});
- break :blk Fuzzer.Config.Defaults.output_as_dir;
+ std.log.warn("expected boolean (true|false) in env option 'rpc' but got '{s}'", .{str});
+ break :blk Fuzzer.Config.Defaults.rpc;
}
else
- Fuzzer.Config.Defaults.output_as_dir;
+ Fuzzer.Config.Defaults.rpc;
var mode_name: ?ModeName = blk: {
if (env_map.get("mode")) |mode_name| {
@@ -91,8 +91,8 @@ fn initConfig(allocator: std.mem.Allocator, env_map: std.process.EnvMap, arg_it:
if (std.mem.eql(u8, arg, "--help")) {
try std.io.getStdOut().writeAll(usage);
std.process.exit(0);
- } else if (std.mem.eql(u8, arg, "--output-as-dir")) {
- output_as_dir = true;
+ } else if (std.mem.eql(u8, arg, "--rpc")) {
+ rpc = true;
} else if (std.mem.eql(u8, arg, "--zls-path")) {
if (maybe_zls_path) |path| {
allocator.free(path);
@@ -179,7 +179,7 @@ fn initConfig(allocator: std.mem.Allocator, env_map: std.process.EnvMap, arg_it:
errdefer zig_env.deinit();
return .{
- .output_as_dir = output_as_dir,
+ .rpc = rpc,
.zls_path = zls_path,
.mode_name = mode,
.cycles_per_gen = cycles_per_gen,
@@ -189,7 +189,7 @@ fn initConfig(allocator: std.mem.Allocator, env_map: std.process.EnvMap, arg_it:
};
}
-// note: if you change this text, run `zig build run -- --help` and paste the contents into the README
+// if you change this text, run `zig build run -- --help` and paste the contents into the README
const usage =
std.fmt.comptimePrint(
\\sus - ZLS fuzzing tooling
@@ -202,7 +202,7 @@ const usage =
\\General Options:
\\ --help Print this help and exit
\\ --mode [mode] Specify fuzzing mode - one of {s}
- \\ --output-as-dir Output fuzzing results as directories (default: {s})
+ \\ --rpc Use RPC mode (default: {})
\\ --zls-path [path] Specify path to ZLS executable (default: Search in PATH)
\\ --zig-path [path] Specify path to Zig executable (default: Search in PATH)
\\ --cycles-per-gen How many times to fuzz a random feature before regenerating a new file. (default: {d})
@@ -211,8 +211,8 @@ const usage =
\\For a listing of build options, use 'zig build --help'.
\\
, .{
- if (Fuzzer.Config.Defaults.output_as_dir) "true" else "false",
std.meta.fieldNames(ModeName).*,
+ Fuzzer.Config.Defaults.rpc,
Fuzzer.Config.Defaults.cycles_per_gen,
});
@@ -268,11 +268,10 @@ pub fn main() !void {
var config = try initConfig(gpa, env_map, &arg_it);
defer config.deinit(gpa);
- var progress = std.Progress{
- .terminal = null,
- };
+ var progress = std.Progress.start(.{});
+ defer progress.end();
- progress.log(
+ std.debug.print(
\\zig-version: {s}
\\zls-version: {s}
\\zig-path: {s}
@@ -289,11 +288,29 @@ pub fn main() !void {
config.cycles_per_gen,
});
- var mode = try Mode.init(config.mode_name, gpa, &progress, &arg_it, env_map);
+ var mode = try Mode.init(config.mode_name, gpa, progress, &arg_it, env_map);
defer mode.deinit(gpa);
+ const cwd_path = try std.process.getCwdAlloc(gpa);
+ defer gpa.free(cwd_path);
+
+ const principal_file_path = try std.fs.path.join(gpa, &.{ cwd_path, "tmp", "principal.zig" });
+ defer gpa.free(principal_file_path);
+
+ const principal_file_uri = try std.fmt.allocPrint(gpa, "{}", .{std.Uri{
+ .scheme = "file",
+ .path = .{ .raw = principal_file_path },
+ }});
+ defer gpa.free(principal_file_uri);
+
while (true) {
- var fuzzer = try Fuzzer.create(gpa, &progress, &mode, config);
+ var fuzzer = try Fuzzer.create(
+ gpa,
+ progress,
+ &mode,
+ config,
+ principal_file_uri,
+ );
errdefer {
fuzzer.wait();
fuzzer.destroy();
@@ -302,10 +319,8 @@ pub fn main() !void {
try fuzzer.initCycle();
while (true) {
- progress.maybeRefresh();
-
if (fuzzer.cycle >= 100_000) {
- progress.log("Fuzzer running too long with no result... restarting\n", .{});
+ std.debug.print("Fuzzer running too long with no result... restarting\n", .{});
try fuzzer.closeCycle();
fuzzer.wait();
@@ -314,13 +329,14 @@ pub fn main() !void {
}
fuzzer.fuzz() catch {
- progress.log("Restarting fuzzer...\n", .{});
+ std.debug.print("Reducing...\n", .{});
fuzzer.wait();
- fuzzer.logPrincipal() catch {
- progress.log("failed to log principal\n", .{});
- };
+ try fuzzer.reduce();
fuzzer.destroy();
+
+ std.debug.print("Restarting fuzzer...\n", .{});
+
break;
};
}
diff --git a/src/mode.zig b/src/mode.zig
index 9457c7b..d35ac3a 100644
--- a/src/mode.zig
+++ b/src/mode.zig
@@ -8,7 +8,7 @@ pub const Mode = union(enum) {
pub fn init(
mode_name: ModeName,
allocator: std.mem.Allocator,
- progress: *std.Progress,
+ progress: std.Progress.Node,
arg_it: *std.process.ArgIterator,
envmap: std.process.EnvMap,
) !Mode {
diff --git a/src/modes/BestBehavior.zig b/src/modes/BestBehavior.zig
index e952e5d..384fa39 100644
--- a/src/modes/BestBehavior.zig
+++ b/src/modes/BestBehavior.zig
@@ -1,9 +1,8 @@
const std = @import("std");
-const utils = @import("../utils.zig");
const BestBehavior = @This();
-random: std.rand.DefaultPrng,
+random: std.Random.DefaultPrng,
tests: std.ArrayListUnmanaged([]const u8),
const usage =
@@ -24,18 +23,17 @@ fn fatal(comptime format: []const u8, args: anytype) noreturn {
pub fn init(
allocator: std.mem.Allocator,
- progress: *std.Progress,
+ progress: std.Progress.Node,
arg_it: *std.process.ArgIterator,
envmap: std.process.EnvMap,
) !*BestBehavior {
var bb = try allocator.create(BestBehavior);
errdefer allocator.destroy(bb);
- var seed: u64 = 0;
- try std.os.getrandom(std.mem.asBytes(&seed));
+ const seed = std.crypto.random.int(u64);
bb.* = .{
- .random = std.rand.DefaultPrng.init(seed),
+ .random = std.Random.DefaultPrng.init(seed),
.tests = .{},
};
errdefer bb.deinit(allocator);
@@ -58,7 +56,7 @@ pub fn init(
fatalWithUsage("missing mode argument '--source-dir'", .{});
}
- progress.log(
+ std.debug.print(
\\
\\source-dir: {s}
\\
@@ -92,7 +90,6 @@ pub fn init(
var file_buf = std.ArrayListUnmanaged(u8){};
defer file_buf.deinit(allocator);
- progress_node.activate();
while (try walker.next()) |entry| {
if (entry.kind != .file) continue;
if (!std.mem.eql(u8, std.fs.path.extension(entry.basename), ".zig")) continue;
diff --git a/src/modes/MarkovMode.zig b/src/modes/MarkovMode.zig
index 6ac19bb..850c162 100644
--- a/src/modes/MarkovMode.zig
+++ b/src/modes/MarkovMode.zig
@@ -7,7 +7,7 @@ const Markov = @This();
const MarkovModel = markov.Model(build_options.block_len, false);
model: MarkovModel,
-random: std.rand.DefaultPrng,
+random: std.Random.DefaultPrng,
maxlen: u32 = Defaults.maxlen,
const Defaults = struct {
@@ -36,22 +36,19 @@ fn fatal(comptime format: []const u8, args: anytype) noreturn {
pub fn init(
allocator: std.mem.Allocator,
- progress: *std.Progress,
+ progress: std.Progress.Node,
arg_it: *std.process.ArgIterator,
envmap: std.process.EnvMap,
) !*Markov {
- var seed: u64 = 0;
- try std.os.getrandom(std.mem.asBytes(&seed));
+ const seed = std.crypto.random.int(u64);
var mm = try allocator.create(Markov);
mm.* = .{
- .model = undefined, // set below
- .random = std.rand.DefaultPrng.init(seed),
+ .model = .{ .allocator = allocator },
+ .random = std.Random.DefaultPrng.init(seed),
};
errdefer mm.deinit(allocator);
- mm.model = MarkovModel.init(allocator, mm.random.random());
-
var training_dir: ?[]const u8 = envmap.get("markov_training_dir");
if (envmap.get("markov_maxlen")) |str| {
@@ -80,7 +77,7 @@ pub fn init(
fatalWithUsage("missing mode argument '--training-dir'", .{});
}
- progress.log(
+ std.debug.print(
\\
\\training-dir: {s}
\\maxlen: {d}
@@ -112,7 +109,6 @@ pub fn init(
var file_buf = std.ArrayListUnmanaged(u8){};
defer file_buf.deinit(allocator);
- progress_node.activate();
while (try walker.next()) |entry| {
if (entry.kind != .file) continue;
if (!std.mem.eql(u8, std.fs.path.extension(entry.basename), ".zig")) continue;
@@ -146,6 +142,6 @@ pub fn deinit(mm: *Markov, allocator: std.mem.Allocator) void {
pub fn gen(mm: *Markov, allocator: std.mem.Allocator) ![]const u8 {
var buffer = try std.ArrayListUnmanaged(u8).initCapacity(allocator, mm.maxlen);
errdefer buffer.deinit(allocator);
- try mm.model.gen(buffer.writer(allocator), .{ .maxlen = mm.maxlen });
+ try mm.model.gen(mm.random.random(), buffer.writer(allocator), .{ .maxlen = mm.maxlen });
return try buffer.toOwnedSlice(allocator);
}
diff --git a/src/modes/markov.zig b/src/modes/markov.zig
index 3c726f1..3e3681f 100644
--- a/src/modes/markov.zig
+++ b/src/modes/markov.zig
@@ -151,15 +151,11 @@ pub fn Model(comptime byte_len: comptime_int, comptime debug: bool) type {
return struct {
table: Table = .{},
allocator: mem.Allocator,
- rand: std.rand.Random,
pub const Iter = Iterator(byte_len);
pub const Table = std.AutoArrayHashMapUnmanaged(Iter.Block, Follows);
const Self = @This();
- pub fn init(allocator: mem.Allocator, rand: std.rand.Random) Self {
- return .{ .allocator = allocator, .rand = rand };
- }
pub fn deinit(self: *Self, allocator: mem.Allocator) void {
var iter = self.table.iterator();
while (iter.next()) |*m| m.value_ptr.deinit(allocator);
@@ -195,6 +191,7 @@ pub fn Model(comptime byte_len: comptime_int, comptime debug: bool) type {
/// previous input to feed().
pub fn gen(
self: *Self,
+ random: std.Random,
writer: anytype,
options: GenOptions,
) !void {
@@ -204,7 +201,7 @@ pub fn Model(comptime byte_len: comptime_int, comptime debug: bool) type {
else
start_block)
else blk: {
- const id = self.rand.intRangeLessThan(usize, 0, self.table.count());
+ const id = random.intRangeLessThan(usize, 0, self.table.count());
break :blk self.table.keys()[id];
};
_ = try writer.write(&start_block);
@@ -227,7 +224,7 @@ pub fn Model(comptime byte_len: comptime_int, comptime debug: bool) type {
};
// pick a random item
- var r = self.rand.intRangeAtMost(usize, 0, follows.count());
+ var r = random.intRangeAtMost(usize, 0, follows.count());
const first_follow = follows.constItems()[0];
var c = first_follow.char;
if (debug) std.debug.print("follows {any} r {}\n", .{ follows.constItems(), r });
@@ -250,7 +247,7 @@ pub fn Model(comptime byte_len: comptime_int, comptime debug: bool) type {
// var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
// const allr = arena.allocator();
// var argit = try std.process.ArgIterator.initWithAllocator(allr);
-// var prng = std.rand.DefaultPrng.init(@bitCast(u64, std.time.milliTimestamp()));
+// var prng = std.Random.DefaultPrng.init(@bitCast(u64, std.time.milliTimestamp()));
// const M = Model(build_options.block_len, false);
// var model = M.init(allr, prng.random());
// _ = argit.next();
diff --git a/src/utils.zig b/src/utils.zig
index b9b0577..e7c16fc 100644
--- a/src/utils.zig
+++ b/src/utils.zig
@@ -1,6 +1,5 @@
const std = @import("std");
-const lsp = @import("zig-lsp");
-const lsp_types = lsp.types;
+const lsp = @import("lsp");
/// Use after `isArrayList` and/or `isHashMap`
pub fn isManaged(comptime T: type) bool {
@@ -60,7 +59,7 @@ pub fn isHashMap(comptime T: type) bool {
pub fn randomize(
comptime T: type,
allocator: std.mem.Allocator,
- random: std.rand.Random,
+ random: std.Random,
) anyerror!T {
if (T == std.json.Value) {
const Valids = enum {
@@ -138,12 +137,12 @@ pub fn randomize(
};
}
-pub fn randomPosition(random: std.rand.Random, data: []const u8) lsp_types.Position {
+pub fn randomPosition(random: std.Random, data: []const u8) lsp.types.Position {
// TODO: Consider offsets
const line_count = std.mem.count(u8, data, "\n");
const line = if (line_count == 0) 0 else random.intRangeLessThan(usize, 0, line_count);
- var lines = std.mem.split(u8, data, "\n");
+ var lines = std.mem.splitScalar(u8, data, '\n');
var character: usize = 0;
@@ -161,7 +160,7 @@ pub fn randomPosition(random: std.rand.Random, data: []const u8) lsp_types.Posit
};
}
-pub fn randomRange(random: std.rand.Random, data: []const u8) lsp_types.Range {
+pub fn randomRange(random: std.Random, data: []const u8) lsp.types.Range {
const a = randomPosition(random, data);
const b = randomPosition(random, data);
@@ -169,3 +168,88 @@ pub fn randomRange(random: std.rand.Random, data: []const u8) lsp_types.Range {
return if (is_a_first) .{ .start = a, .end = b } else .{ .start = b, .end = a };
}
+
+pub fn stringifyRequest(
+ writer: anytype,
+ id: *i64,
+ comptime method: []const u8,
+ params: lsp.ParamsType(method),
+) !void {
+ try std.json.stringify(.{
+ .jsonrpc = "2.0",
+ .id = id.*,
+ .method = method,
+ .params = switch (@TypeOf(params)) {
+ void => .{},
+ ?void => null,
+ else => params,
+ },
+ }, .{}, writer);
+ id.* +%= 1;
+}
+
+pub fn stringifyNotification(
+ writer: anytype,
+ comptime method: []const u8,
+ params: lsp.ParamsType(method),
+) !void {
+ try std.json.stringify(.{
+ .jsonrpc = "2.0",
+ .method = method,
+ .params = params,
+ }, .{}, writer);
+}
+
+pub fn waitForResponseToRequest(
+ allocator: std.mem.Allocator,
+ transport: *lsp.TransportOverStdio,
+ id: i64,
+) !void {
+ while (true) {
+ const json_message = try transport.readJsonMessage(allocator);
+ defer allocator.free(json_message);
+
+ const result = try std.json.parseFromSlice(
+ struct { id: ?lsp.JsonRPCMessage.ID },
+ allocator,
+ json_message,
+ .{
+ .ignore_unknown_fields = true,
+ },
+ );
+
+ defer result.deinit();
+
+ if (result.value.id) |received_id| {
+ if (received_id == .number and received_id.number == id) {
+ return;
+ }
+ }
+ }
+}
+
+pub fn waitForResponseToRequests(
+ allocator: std.mem.Allocator,
+ transport: *lsp.TransportOverStdio,
+ ids: *std.AutoArrayHashMapUnmanaged(i64, void),
+) !void {
+ while (ids.count() != 0) {
+ const json_message = try transport.readJsonMessage(allocator);
+ defer allocator.free(json_message);
+
+ const result = try std.json.parseFromSlice(
+ struct { id: ?lsp.JsonRPCMessage.ID },
+ allocator,
+ json_message,
+ .{
+ .ignore_unknown_fields = true,
+ },
+ );
+ defer result.deinit();
+
+ if (result.value.id) |received_id| {
+ if (received_id != .number) continue;
+ std.debug.assert(ids.swapRemove(received_id.number));
+ }
+ }
+}