diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index 10f942ec..54b7d6b2 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -15,27 +15,31 @@ jobs: const { owner, repo, number: issue_number } = context.issue; const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); const title = pr.data.title; - const labRegex = /\[LAB(\d+)\]/; - const titleRegex = /^\[LAB\d+\] [\da-zA-Z]+$/; - if (!titleRegex.test(title)) { - core.setFailed('PR title does not match the required format. Please use the format [LAB#] student#.'); + const titleRegex = /^\[LAB(\d+)\] [a-zA-Z]?\d+$/; + const match = title.match(titleRegex); + + let labNumberStr = undefined; + if (match) { + labNumberStr = match[1]; + } else { + core.setFailed('PR title does not match the required format. Please use the format: [LAB#] .'); } - if (pr.data.head.ref !== pr.data.base.ref) { - core.setFailed('The source branch and target branch must be the same.'); + const labelToAdd = `lab${labNumberStr}`; + if (labNumberStr) { + await github.rest.issues.addLabels({ owner, repo, issue_number, labels: [labelToAdd] }); } if (pr.data.base.ref === 'main') { core.setFailed('The target branch cannot be main.'); } - const match = title.match(labRegex); - if (match) { - const labelToAdd = 'lab' + match[1]; - await github.rest.issues.addLabels({ owner, repo, issue_number, labels: [labelToAdd] }); - } else { - core.setFailed('No match found in PR title. Please add a label in the format [LAB#] to the PR title.'); + if (labNumberStr < 3 && pr.data.head.ref !== pr.data.base.ref) { + core.setFailed('The source branch and target branch must be the same.'); + } + if (labNumberStr >= 3 && pr.data.head.ref !== labelToAdd) { + core.setFailed(`The source branch must be '${labelToAdd}'`); } checklist-check: runs-on: ubuntu-latest @@ -49,12 +53,12 @@ jobs: const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); const body = pr.data.body; - const checkboxes = body.match(/\- \[[x ]\]/g); + const checkboxes = body.match(/^ ?(-|\*) \[[x ]\]/gmi); if (!checkboxes || checkboxes.length !== 5) { core.setFailed('The PR description must contain exactly 5 checkboxes.'); } - const unchecked = body.match(/\- \[ \]/g); + const unchecked = body.match(/^ ?(-|\*) \[ \]/gm); if (unchecked && unchecked.length > 0) { - core.setFailed(`There are ${unchecked.length} unchecked items in the PR description.`); + core.setFailed(`There are ${unchecked.length} unchecked item(s) in the PR description.`); } diff --git a/.github/workflows/lab-autograding.yml b/.github/workflows/lab-autograding.yml new file mode 100644 index 00000000..ba7a31f9 --- /dev/null +++ b/.github/workflows/lab-autograding.yml @@ -0,0 +1,56 @@ +name: Autograding + +on: + pull_request_target: + types: [labeled, synchronize, opened, reopened, ready_for_review] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-22.04] + fail-fast: false + steps: + - uses: actions/checkout@v4 + with: + ref: "${{ github.event.pull_request.merge_commit_sha }}" + fetch-depth: 1 + - uses: actions/setup-node@v4 + with: + node-version: latest + - name: Extract lab number and Check no changes other than specific files + uses: actions/github-script@v5 + id: lab + with: + result-encoding: string + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { owner, repo, number: issue_number } = context.issue; + const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); + const labels = pr.data.labels; + const lab = labels.find((label) => label.name.startsWith('lab')); + if (!lab) { + core.setFailed('No lab label found on the PR.'); + return { number: 0 }; + } + const labNumberMatch = lab.name.match(/lab(\d+)/); + if (!labNumberMatch) { + core.setFailed('Invalid lab label found on the PR.'); + return { number: 0 }; + } + const labNumber = labNumberMatch[1]; + console.log(`Lab number: ${labNumber}`) + + const files = await github.rest.pulls.listFiles({ owner, repo, pull_number: issue_number }); + const changedFiles = files.data.map((file) => file.filename); + const allowedFileRegex = /^lab\d+\/main_test.js$/; + const specialChangedFiles = ["lab5/Answer.md", "lab5/antiasan.c", "lab6/Answer.md", "lab7/sol.py"]; + if (!changedFiles.every((file) => (allowedFileRegex.test(file) || specialChangedFiles.includes(file)))) { + core.setFailed('The PR contains changes to files other than the allowed files.'); + } + return labNumber; + - name: Grading + run: | + cd lab${{ steps.lab.outputs.result }} + ./validate.sh diff --git a/.github/workflows/lab1.yml b/.github/workflows/lab1.yml deleted file mode 100644 index 49a5d578..00000000 --- a/.github/workflows/lab1.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: lab1 autograding - -on: - pull_request: - types: [labeled, synchronize, opened, reopened, ready_for_review] - -jobs: - build: - if: contains(github.event.pull_request.labels.*.name, 'lab1') - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-22.04] - fail-fast: false - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - name: dependency (ubuntu) - run: | - curl -fsSL https://deb.nodesource.com/setup_21.x | sudo -E bash - &&\ - sudo apt-get install -y nodejs - - name: grading - run: | - cd lab1 - ./validate.sh diff --git a/.github/workflows/lab2.yml b/.github/workflows/lab2.yml deleted file mode 100644 index 2cb76fa7..00000000 --- a/.github/workflows/lab2.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: lab2 autograding - -on: - pull_request: - types: [labeled, synchronize, opened, reopened, ready_for_review] - -jobs: - build: - if: contains(github.event.pull_request.labels.*.name, 'lab2') - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-22.04] - fail-fast: false - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - name: dependency (ubuntu) - run: | - curl -fsSL https://deb.nodesource.com/setup_21.x | sudo -E bash - &&\ - sudo apt-get install -y nodejs - - name: grading - run: | - cd lab2 - ./validate.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..40b878db --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/lab1/main_test.js b/lab1/main_test.js index 74a716b4..ec5e8865 100644 --- a/lab1/main_test.js +++ b/lab1/main_test.js @@ -3,21 +3,54 @@ const assert = require('assert'); const { MyClass, Student } = require('./main'); test("Test MyClass's addStudent", () => { - // TODO - throw new Error("Test not implemented"); + + //case 1 + const myclass = new MyClass(); + assert.strictEqual(myclass.addStudent("for_test"), -1); + + //case 2 + const student = new Student(); + assert.strictEqual(myclass.addStudent(student), 0); + }); test("Test MyClass's getStudentById", () => { - // TODO - throw new Error("Test not implemented"); + + //case 1 + const myclass = new MyClass(); + assert.strictEqual(myclass.getStudentById(-1), null); + + //case 2 + assert.strictEqual(myclass.getStudentById(1),null); + + //case 3 + const student1 = new Student(); + myclass.addStudent(student1); + assert.strictEqual(myclass.getStudentById(0),student1); + }); test("Test Student's setName", () => { - // TODO - throw new Error("Test not implemented"); + + const student = new Student(); + + //case 1 + assert.strictEqual(student.setName(1), undefined); + + //case 2 + assert.strictEqual(student.setName('Amy'), undefined); + }); test("Test Student's getName", () => { - // TODO - throw new Error("Test not implemented"); -}); \ No newline at end of file + + const student = new Student(); + + //case 1 + assert.strictEqual(student.getName(),''); + + //case 2 + student.setName('Amy'); + assert.strictEqual(student.getName(),'Amy'); + +}); diff --git a/lab2/main_test.js b/lab2/main_test.js index 5034468e..57ce4ce7 100644 --- a/lab2/main_test.js +++ b/lab2/main_test.js @@ -1,6 +1,104 @@ const test = require('node:test'); const assert = require('assert'); +const fs = require('fs'); + +test.mock.method(fs, "readFile", (path, encoding, callback) => { + callback(null, "Amy\nJack"); +}); + +const names = ['Amy', 'Jack']; const { Application, MailSystem } = require('./main'); -// TODO: write your tests here -// Remember to use Stub, Mock, and Spy when necessary \ No newline at end of file +test("Test MailSystem's write", () => { + + const mailSystem = new MailSystem(); + assert.strictEqual(mailSystem.write(names[0]), 'Congrats, ' + names[0] + '!'); + +}); + +test("Test MailSystem's send", () => { + + const mailSystem = new MailSystem(); + + //case 1 + test.mock.method(Math, "random", () => true); + for(let i = 0; i < names.length; i++) { + assert.strictEqual(mailSystem.send(names[i]), true); + } + + //case 2 + test.mock.method(Math, "random", () => false); + for(let i = 0; i < names.length; i++) { + assert.strictEqual(mailSystem.send(names[i]), false); + } + +}); + +test("Test Application's getNames", async () => { + + const application = new Application(); + application.people = names; + const [people, selected] = await application.getNames(); + assert.deepStrictEqual(people, names); + assert.deepStrictEqual(selected, []); + +}); + +test("Test Application's getRandomPerson", () => { + + const application = new Application(); + application.people = names; + + for(let i = 0; i < names.length; i++) { + test.mock.method(Math, "floor", () => i); + assert.strictEqual(application.getRandomPerson(), names[i]); + } + +}); + +test("Test Application's selectNextPerson", async () => { + + const application = new Application(); + application.people = names; + + application.getRandomPerson = () => "Amy"; + assert.strictEqual(application.selectNextPerson(),'Amy'); + assert.deepStrictEqual(application.selected,["Amy"]); + + let count = 1; + application.getRandomPerson = () => { + if (count % 2){ + count++; + return "Amy"; + } + return "Jack"; + }; + assert.strictEqual(application.selectNextPerson(),'Jack'); + assert.deepStrictEqual(application.selected,["Amy","Jack"]); + + assert.strictEqual(application.selectNextPerson(),null); + +}); + +test("Test Application's notifySelected", () => { + + const application = new Application(); + + application.mailSystem.write = test.mock.fn(application.mailSystem.write); + application.mailSystem.send = test.mock.fn(() => true); + + application.selected = names; + application.notifySelected(); + + + //check call arguments + assert.strictEqual(application.mailSystem.write.mock.calls[0].arguments[0], names[0]); + assert.strictEqual(application.mailSystem.send.mock.calls[0].arguments[0], names[0]); + assert.strictEqual(application.mailSystem.write.mock.calls[1].arguments[0], names[1]); + assert.strictEqual(application.mailSystem.send.mock.calls[1].arguments[0], names[1]); + + // //check call times + assert.strictEqual(application.mailSystem.write.mock.calls.length, names.length); + assert.strictEqual(application.mailSystem.send.mock.calls.length, names.length); + +}); diff --git a/lab3/README.md b/lab3/README.md new file mode 100644 index 00000000..f95c2ca0 --- /dev/null +++ b/lab3/README.md @@ -0,0 +1,29 @@ +# Lab3 + +## Introduction + +In this lab, you will write unit tests for functions implemented in `main.js`. You can learn how to use classes and functions in it by uncommenting the code in it. (But remember don't commit them on GitHub) + +## Preparation (Important!!!) + +1. Sync fork on GitHub +2. `git checkout -b lab3` (**NOT** your student ID !!!) + +## Requirement + +1. (40%) Write test cases in `main_test.js` and achieve 100% code coverage. +2. (30%) For each function, parameterize their testcases to test the error-results. +3. (30%) For each function, use at least 3 parameterized testcases to test the non-error-results. + +You can run `validate.sh` in your local to test if you satisfy the requirements. + +Please note that you must not alter files other than `main_test.js`. You will get 0 points if + +1. you modify other files to achieve requirements. +2. you can't pass all CI on your PR. + +## Submission + +You need to open a pull request to your branch (e.g. 311XXXXXX, your student number) and contain the code that satisfies the abovementioned requirements. + +Moreover, please submit the URL of your PR to E3. Your submission will only be accepted when you present at both places. diff --git a/lab3/main.js b/lab3/main.js new file mode 100644 index 00000000..cee5de7f --- /dev/null +++ b/lab3/main.js @@ -0,0 +1,34 @@ +class Calculator { + exp(x) { + if (!Number.isFinite(x)) { + throw Error('unsupported operand type'); + } + const result = Math.exp(x); + if (result === Infinity) { + throw Error('overflow'); + } + return result; + } + + log(x) { + if (!Number.isFinite(x)) { + throw Error('unsupported operand type'); + } + const result = Math.log(x); + if (result === -Infinity) { + throw Error('math domain error (1)'); + } + if (Number.isNaN(result)) { + throw Error('math domain error (2)'); + } + return result; + } +} + +// const calculator = new Calculator(); +// console.log(calculator.exp(87)); +// console.log(calculator.log(48763)); + +module.exports = { + Calculator +}; \ No newline at end of file diff --git a/lab3/main_test.js b/lab3/main_test.js new file mode 100644 index 00000000..e6d6414e --- /dev/null +++ b/lab3/main_test.js @@ -0,0 +1,5 @@ +const {describe, it} = require('node:test'); +const assert = require('assert'); +const { Calculator } = require('./main'); + +// TODO: write your tests here diff --git a/lab3/validate.sh b/lab3/validate.sh new file mode 100755 index 00000000..7a758fb3 --- /dev/null +++ b/lab3/validate.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Check for unwanted files +for file in *; do + if [[ $file != "main.js" && $file != "main_test.js" && $file != "README.md" && $file != "validate.sh" ]]; then + echo "[!] Unwanted file detected: $file." + exit 1 + fi +done + +node=$(which node) +test_path="${BASH_SOURCE[0]}" +solution_path="$(realpath .)" +tmp_dir=$(mktemp -d -t lab3-XXXXXXXXXX) + +cd $tmp_dir + +rm -rf * +cp $solution_path/*.js . +result=$($"node" --test --experimental-test-coverage) ; ret=$? +if [ $ret -ne 0 ] ; then + echo "[!] testing fails" + exit 1 +else + coverage=$(echo "$result" | grep 'all files' | awk -F '|' '{print $2}' | sed 's/ //g') + if (( $(echo "$coverage < 100" | bc -l) )); then + echo "[!] Coverage is only $coverage%" + exit 1 + else + echo "[V] Coverage is 100%" + fi +fi + +rm -rf $tmp_dir + +exit 0 + +# vim: set fenc=utf8 ff=unix et sw=2 ts=2 sts=2: \ No newline at end of file diff --git a/lab4/README.md b/lab4/README.md new file mode 100644 index 00000000..2a719b8b --- /dev/null +++ b/lab4/README.md @@ -0,0 +1,29 @@ +# Lab4 + +## Introduction + +In this lab, you will write tests in `main_test.js`. You can learn how to use [Puppeteer](https://pptr.dev/) to tests a web UI. + +## Preparation (Important!!!) + +1. Sync fork your branch (e.g., `SQLab:311XXXXXX`) +2. `git checkout -b lab4` (**NOT** your student ID !!!) + +## Requirement + +1. (100%) Goto https://pptr.dev/, type `chipi chipi chapa chapa` into the search box, click on **1st** result in the **Docs** section, and print the title. + +For the detailed steps and hints, please check the slide of this lab. + +You can run `validate.sh` in your local to test if you satisfy the requirements. + +Please note that you must not alter files other than `main_test.js`. You will get 0 points if + +1. you modify other files to achieve requirements. +2. you can't pass all CI on your PR. + +## Submission + +You need to open a pull request to your branch (e.g. 311XXXXXX, your student number) and contain the code that satisfies the abovementioned requirements. + +Moreover, please submit the URL of your PR to E3. Your submission will only be accepted when you present at both places. diff --git a/lab4/main_test.js b/lab4/main_test.js new file mode 100644 index 00000000..e37d21a5 --- /dev/null +++ b/lab4/main_test.js @@ -0,0 +1,22 @@ +const puppeteer = require('puppeteer'); + +(async () => { + // Launch the browser and open a new blank page + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + + // Navigate the page to a URL + await page.goto('https://pptr.dev/'); + + // Hints: + // Click search button + // Type into search box + // Wait for search result + // Get the `Docs` result section + // Click on first result in `Docs` section + // Locate the title + // Print the title + + // Close the browser + await browser.close(); +})(); \ No newline at end of file diff --git a/lab4/package-lock.json b/lab4/package-lock.json new file mode 100644 index 00000000..ced9fee4 --- /dev/null +++ b/lab4/package-lock.json @@ -0,0 +1,1174 @@ +{ + "name": "lab4", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "puppeteer": "^22.5.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.1.tgz", + "integrity": "sha512-bC49z4spJQR3j8vFtJBLqzyzFV0ciuL5HYX7qfSl3KEqeMVV+eTquRvmXxpvB0AMubRrvv7y5DILiLLPi57Ewg==", + "dependencies": { + "@babel/highlight": "^7.24.1", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.1.tgz", + "integrity": "sha512-EPmDPxidWe/Ex+HTFINpvXdPHRmgSF3T8hGvzondYjmgzTQ/0EbLpSxyt+w3zzlYSk9cNBQNF9k0dT5Z2NiBjw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.0.tgz", + "integrity": "sha512-MC7LxpcBtdfTbzwARXIkqGZ1Osn3nnZJlm+i0+VqHl72t//Xwl9wICrXT8BwtgC6s1xJNHsxOpvzISUqe92+sw==", + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.4.0", + "semver": "7.6.0", + "tar-fs": "3.0.5", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" + }, + "node_modules/@types/node": { + "version": "20.11.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", + "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", + "optional": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" + }, + "node_modules/bare-events": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.1.tgz", + "integrity": "sha512-9GYPpsPFvrWBkelIhOhTWtkeZxVxZOdb3VnFTCzlOo3OjvmTvzLoZFUT8kNFACx0vJej6QPney1Cf9BvzCNE/A==", + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.2.tgz", + "integrity": "sha512-X9IqgvyB0/VA5OZJyb5ZstoN62AzD7YxVGog13kkfYWYqJYcK0kcqLZ6TrmH5qr4/8//ejVcX4x/a0UvaogXmA==", + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-os": "^2.0.0", + "bare-path": "^2.0.0", + "streamx": "^2.13.0" + } + }, + "node_modules/bare-os": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.1.tgz", + "integrity": "sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w==", + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.0.tgz", + "integrity": "sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw==", + "optional": true, + "dependencies": { + "bare-os": "^2.1.0" + } + }, + "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/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "engines": { + "node": ">=10.0.0" + } + }, + "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/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chromium-bidi": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.13.tgz", + "integrity": "sha512-OHbYCetDxdW/xmlrafgOiLsIrw4Sp1BEeolbZ1UGJO5v/nekQOJBj/Kzyw6sqKcAVabUTo0GS3cTYgr6zIf00g==", + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0", + "zod": "3.22.4" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1249869", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1249869.tgz", + "integrity": "sha512-Ctp4hInA0BEavlUoRy9mhGq0i+JSo/AwVyX2EFgZmV1kYB+Zq+EMBAn52QWu6FbRr10hRb6pBl420upbp4++vg==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "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/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "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/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "engines": { + "node": ">= 0.4.0" + } + }, + "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/pac-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "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/puppeteer": { + "version": "22.5.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.5.0.tgz", + "integrity": "sha512-PNVflixb6w3FMhehYhLcaQHTCcNKVkjxekzyvWr0n0yBnhUYF0ZhiG4J1I14Mzui2oW8dGvUD8kbXj0GiN1pFg==", + "hasInstallScript": true, + "dependencies": { + "@puppeteer/browsers": "2.2.0", + "cosmiconfig": "9.0.0", + "puppeteer-core": "22.5.0" + }, + "bin": { + "puppeteer": "lib/esm/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "22.5.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.5.0.tgz", + "integrity": "sha512-bcfmM1nNSysjnES/ZZ1KdwFAFFGL3N76qRpisBb4WL7f4UAD4vPDxlhKZ1HJCDgMSWeYmeder4kftyp6lKqMYg==", + "dependencies": { + "@puppeteer/browsers": "2.2.0", + "chromium-bidi": "0.5.13", + "debug": "4.3.4", + "devtools-protocol": "0.0.1249869", + "ws": "8.16.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "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/semver/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/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "node_modules/streamx": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", + "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tar-fs": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", + "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "optional": true + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/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/wrap-ansi/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/wrap-ansi/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/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/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/lab4/package.json b/lab4/package.json new file mode 100644 index 00000000..5014ba08 --- /dev/null +++ b/lab4/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "puppeteer": "^22.5.0" + } +} diff --git a/lab4/validate.sh b/lab4/validate.sh new file mode 100755 index 00000000..e963b24b --- /dev/null +++ b/lab4/validate.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# Check for unwanted files +for file in *; do + if [[ $file != "node_modules" && $file != "main_test.js" && $file != "package-lock.json" && $file != "package.json" && $file != "README.md" && $file != "validate.sh" ]]; then + echo "[!] Unwanted file detected: $file." + exit 1 + fi +done + +node=$(which node) +test_path="${BASH_SOURCE[0]}" +solution_path="$(realpath .)" +tmp_dir=$(mktemp -d -t lab4-XXXXXXXXXX) +answer="Experimental WebDriver BiDi support" + +cd $tmp_dir + +rm -rf * +cp $solution_path/*.js . +cp $solution_path/*.json . + +# Install dependencies +npm ci + +result=$($"node" main_test.js) ; ret=$? +if [ $ret -ne 0 ] ; then + echo "[!] testing fails" + exit 1 +else + title=$(echo "$result" | head -1) + if [[ $title != $answer ]]; then + echo "[!] Expected: $answer" + echo "[!] Actual: $title" + exit 1 + else + echo "[V] Pass" + fi +fi + +rm -rf $tmp_dir + +exit 0 + +# vim: set fenc=utf8 ff=unix et sw=2 ts=2 sts=2: \ No newline at end of file diff --git a/lab5/Answer.md b/lab5/Answer.md new file mode 100644 index 00000000..e8c0abdb --- /dev/null +++ b/lab5/Answer.md @@ -0,0 +1,92 @@ +# Answer + +Name: +ID: + +## Test Valgrind and ASan +### Result +| | Valgrind | Asan | +| -------------------- | -------- | ---- | +| Heap out-of-bounds | | | +| Stack out-of-bounds | | | +| Global out-of-bounds | | | +| Use-after-free | | | +| Use-after-return | | | + +### Heap out-of-bounds +#### Source code +``` + +``` +#### Valgrind Report +``` + +``` +### ASan Report +``` + +``` + +### Stack out-of-bounds +#### Source code +``` + +``` +#### Valgrind Report +``` + +``` +### ASan Report +``` + +``` + +### Global out-of-bounds +#### Source code +``` + +``` +#### Valgrind Report +``` + +``` +### ASan Report +``` + +``` + +### Use-after-free +#### Source code +``` + +``` +#### Valgrind Report +``` + +``` +### ASan Report +``` + +``` + +### Use-after-return +#### Source code +``` + +``` +#### Valgrind Report +``` + +``` +### ASan Report +``` + +``` + +## ASan Out-of-bound Write bypass Redzone +### Source code +``` + +``` +### Why + diff --git a/lab5/Makefile b/lab5/Makefile new file mode 100644 index 00000000..ff992551 --- /dev/null +++ b/lab5/Makefile @@ -0,0 +1,17 @@ +.PHONY: all +all: uaf_asan + +uaf_asan: uaf.c libantiasan.so + gcc -fsanitize=address -Og -g -o $@ $< -lantiasan -L. + +libantiasan.so: antiasan.c + gcc -g -fPIC -c antiasan.c + gcc -shared antiasan.o -o libantiasan.so + +.PHINY: run +run: + LD_LIBRARY_PATH=. ./uaf_asan + +.PHONY: clean +clean: + rm uaf_asan antiasan.o libantiasan.so diff --git a/lab5/README.md b/lab5/README.md new file mode 100644 index 00000000..d5f47c2c --- /dev/null +++ b/lab5/README.md @@ -0,0 +1,29 @@ +# Lab5 + +## Introduction + +In this lab, you will write a function antoasan to bypass detection of ASan in `antiasan.c` and answer questions of slide in `Answer.md`. + +## Preparation (Important!!!) + +1. Sync fork your branch (e.g., `SQLab:311XXXXXX`) +2. `git checkout -b lab5` (**NOT** your student ID !!!) + +## Requirement + +1. (50%) Test Valgrind and ASan to detect common memory corruption vulns, and then asnwer result, report of Valgrind/ASan and Vulnerable code in `Answer.md`. +2. (40%) Write a vulnerable code to bypass redzone between 2 int [8] arrays and asnwer reason and code in `Answer.md`. + +3. (30%) write a function antoasan to bypass detection of ASan in `antiasan.c`. +You can run `validate.sh` in your local to test if you satisfy the requirements. + +Please note that you must not alter files other than `antiasan.c` and `Answer.md`. You will get 0 points if + +1. you modify other files to achieve requirements. +2. you can't pass all CI on your PR. + +## Submission + +You need to open a pull request to your branch (e.g. 311XXXXXX, your student number) and contain the code that satisfies the abovementioned requirements. + +Moreover, please submit the URL of your PR to E3. Your submission will only be accepted when you present at both places. diff --git a/lab5/ans b/lab5/ans new file mode 100644 index 00000000..bfd3d2cb --- /dev/null +++ b/lab5/ans @@ -0,0 +1,3 @@ +LD_LIBRARY_PATH=. ./uaf_asan +s[0x10] = H +s[0x10] = H diff --git a/lab5/antiasan.c b/lab5/antiasan.c new file mode 100644 index 00000000..0c49d229 --- /dev/null +++ b/lab5/antiasan.c @@ -0,0 +1,5 @@ +// TODO: +void antiasan(unsigned long addr) +{ + +} diff --git a/lab5/antiasan.h b/lab5/antiasan.h new file mode 100644 index 00000000..30351797 --- /dev/null +++ b/lab5/antiasan.h @@ -0,0 +1,6 @@ +#ifndef HIJACK_H +#define HIJACK_H + +void antiasan(unsigned long); + +#endif diff --git a/lab5/uaf.c b/lab5/uaf.c new file mode 100644 index 00000000..16feb47d --- /dev/null +++ b/lab5/uaf.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include "antiasan.h" + +int main(void) +{ + char *s = (char *)malloc(0x18); + strcpy(s, "HAHAHAHAHAHAHAHAHAHAHAH"); + printf("s[0x10] = %c\n", s[0x10]); + free(s); + antiasan((unsigned long)&s[0x10]); + printf("s[0x10] = %c\n", s[0x10]); + return 0; +} diff --git a/lab5/validate.sh b/lab5/validate.sh new file mode 100755 index 00000000..cf879bdc --- /dev/null +++ b/lab5/validate.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# Check for unwanted files +for file in *; do + if [[ $file != "uaf.c" && $file != "antiasan.c" && $file != "antiasan.h" && $file != "Makefile" && $file != "README.md" && $file != "Answer.md" && $file != "validate.sh" && $file != "ans" ]]; then + echo "[!] Unwanted file detected: $file." + exit 1 + fi +done + +test_path="${BASH_SOURCE[0]}" +solution_path="$(realpath .)" +tmp_dir=$(mktemp -d -t lab5-XXXXXXXXXX) +answer="" + +cd $tmp_dir + +rm -rf * +cp $solution_path/Makefile . +cp $solution_path/*.c . +cp $solution_path/*.h . +cp $solution_path/ans . + +make +make run > out 2>&1 +result=$(diff ans out) +if [[ -n $result ]]; then + echo "[!] Expected: " + cat ans + echo "" + echo "[!] Actual: " + cat out + echo "" + exit 1 +else + echo "[V] Pass" +fi + +rm -rf $tmp_dir + +exit 0 + +# vim: set fenc=utf8 ff=unix et sw=2 ts=2 sts=2: diff --git a/lab6/.gitignore b/lab6/.gitignore new file mode 100644 index 00000000..1a6229dc --- /dev/null +++ b/lab6/.gitignore @@ -0,0 +1,2 @@ +fuzz/ +src/bmpcomp diff --git a/lab6/Answer.md b/lab6/Answer.md new file mode 100644 index 00000000..fabc82e6 --- /dev/null +++ b/lab6/Answer.md @@ -0,0 +1,12 @@ +Name: +ID: + +### Fuzz Monitor +``` + +``` + +### Run Crash Result +``` + +``` diff --git a/lab6/src/1.bmp b/lab6/src/1.bmp new file mode 100644 index 00000000..edcc39db Binary files /dev/null and b/lab6/src/1.bmp differ diff --git a/lab6/src/hw0302.c b/lab6/src/hw0302.c new file mode 100644 index 00000000..1e9a9d6e --- /dev/null +++ b/lab6/src/hw0302.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +typedef struct _BMPHeader { + char BM[2]; + uint32_t size; + uint32_t reserve; + uint32_t offset; + uint32_t header_size; + uint32_t width; + uint32_t height; + uint16_t planes; + uint16_t bpp; + uint32_t compression; + uint32_t bitmap_size; + uint32_t h_res; + uint32_t v_res; + uint32_t palette; + uint32_t important; +}__attribute__((__packed__)) Header; +int main(int argc, char **argv) { + FILE *pF[9]; + char *filename = argv[1]; + for ( int i=0; i<9; ++i ) { + pF[i] = fopen(filename, "rb"); + if ( pF[i] == NULL ) { + printf("error! file %s doesn't exist.\n", filename); + return 0; + } + } + char output[11] = {'o', 'u', 't', 'p', 'u', 't', '.', 'b', 'm', 'p', '\0'}; + FILE *pR = fopen(output, "wb"); + Header H[9], res; + printf("size of Herder %d\n", sizeof(Header)); + for ( int i=0; i<9; ++i ) fread(H+i, sizeof(Header), 1, pF[i]); + res = H[0]; + res.height = H[0].height + H[3].height + H[6].height; + res.width = H[0].width + H[1].width + H[2].width; + res.bitmap_size = res.height*res.width*3+(res.width%4*res.height); + res.size = res.bitmap_size + res.offset; + fwrite(&res, sizeof(Header), 1, pR); + for ( int i=2; i<9; i+=3 ) { + for ( int j=0; j +#include +#include + +int encrypt(int a1, int a2) { + if ( a1 <= 0x40 || a1 > 90 ) { + puts("Login failed"); + exit(1); + } + return (0x1F * a2 + a1 - 65) % 26 + 65; +} + +int main(void) { + char secret[0x20] = "VXRRJEURXDASBFHM"; + char pwd[0x20] = {0}; + + printf("Enter the password: "); + scanf("%16s", pwd); + for ( int j = 0; j < 0x10; ++j ) + pwd[j] = encrypt(pwd[j], j + 8); + if ( !strcmp(secret, pwd) ) + puts("Login successful"); + else + puts("Login failed"); + return 0; +} diff --git a/lab7/sol.py b/lab7/sol.py new file mode 100644 index 00000000..b5d2ec85 --- /dev/null +++ b/lab7/sol.py @@ -0,0 +1,17 @@ +import angr, sys + +def success_condition(state): + return b"Login successful" in state.posix.dumps(sys.stdout.fileno()) + +def fail_condition(state): + return b"Login failed" in state.posix.dumps(sys.stdout.fileno()) + +proj = angr.Project("./login") + +init_state = proj.factory.entry_state() +simulation = proj.factory.simgr(init_state) +simulation.explore(find=success_condition, avoid=fail_condition) + + +solution = simulation.found[0] +print(solution.posix.dumps(sys.stdin.fileno())) diff --git a/lab7/validate.sh b/lab7/validate.sh new file mode 100755 index 00000000..a6be9226 --- /dev/null +++ b/lab7/validate.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Check for unwanted files +for file in *; do + if [[ $file != "login.c" && $file != "sol.py" && $file != "Makefile" && $file != "README.md" && $file != "validate.sh" ]]; then + echo "[!] Unwanted file detected: $file." + exit 1 + fi +done + +test_path="${BASH_SOURCE[0]}" +solution_path="$(realpath .)" +tmp_dir=$(mktemp -d -t lab7-XXXXXXXXXX) +answer="" + +cd $tmp_dir + +pip install angr +rm -rf * +cp $solution_path/Makefile . +cp $solution_path/*.c . +cp $solution_path/sol.py . + +make +result=$(python3 sol.py) +if [[ $result != "b'HETOBRCUVWOBFEBB'" ]]; then + echo "[!] Expected: " + echo "b'HETOBRCUVWOBFEBB'" + echo "" + echo "[!] Actual: " + echo $result + echo "" + exit 1 +else + echo "[V] Pass" +fi + +rm -rf $tmp_dir + +exit 0 + +# vim: set fenc=utf8 ff=unix et sw=2 ts=2 sts=2: diff --git a/scripts/merge-all.sh b/scripts/merge-all.sh new file mode 100755 index 00000000..4743ac08 --- /dev/null +++ b/scripts/merge-all.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "$0 " + exit 1 +fi + +git fetch origin + +for branch in $(git branch -r | grep -v HEAD); do + # Remove the "origin/" prefix + branch=${branch#origin/} + + if [[ "$branch" != "main" ]]; then + git checkout "$branch" + if [[ $? -ne 0 ]]; then + echo "Checkout failed for branch $branch" + exit 1 + fi + git merge --squash -s recursive -X theirs main + if [[ $? -ne 0 ]]; then + echo "Merge failed for branch $branch" + exit 1 + fi + git commit -m "$1" + fi +done + +git checkout main