From d3b51fbae9327da15829fe6ce5f28fc61378610c Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Fri, 28 May 2021 21:27:10 +0300 Subject: [PATCH 01/90] [feature] Report rule applications to trace. Currently only "Open" is actually reported. This is for the interactive UI later on. --- .gitignore | 11 +- package-lock.json | 2157 ++++++++++++++++- package.json | 3 + .../org/tygus/suslik/report/ProofTrace.scala | 28 +- .../suslik/synthesis/SynthesisRunner.scala | 2 +- .../synthesis/rules/UnfoldingRules.scala | 4 + src/viz/ts/open.ts | 10 +- src/viz/ts/proof-trace.ts | 6 +- 8 files changed, 2185 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 47973596e..b9d183350 100644 --- a/.gitignore +++ b/.gitignore @@ -94,9 +94,6 @@ fabric.properties # Compiled class file *.class -# Log file -*.log - # BlueJ files *.ctxt @@ -118,9 +115,6 @@ hs_err_pid* *~ .*.swp -# stats -*.csv - # Emacs-generated .#* @@ -151,4 +145,9 @@ node_modules # certification results certify/ +# logs, stats, and other outputs +*.log +*.csv *results.tex +trace.json +*.trace.json diff --git a/package-lock.json b/package-lock.json index 76769b08e..63900accd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,2129 @@ { "name": "suslik", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "suslik", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "array-equal": "^1.0.0", + "jquery": "^3.5.0", + "vue": "^2.6.11", + "vue-context": "^5.2.0" + }, + "devDependencies": { + "@types/jquery": "^3.3.34", + "@types/node": "^13.11.1", + "cssnano": "^4.1.10", + "nw-vue-devtools-prebuilt": "0.0.10", + "typescript": "^3.8.3" + } + }, + "node_modules/@types/jquery": { + "version": "3.3.34", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.34.tgz", + "integrity": "sha512-lW9vsVL53Xu/Nj4gi2hNmHGc4u3KKghjqTkAlO0kF5GIOPxbqqnQpgqJBzmn3yXLrPqHb6cmNJ6URnS23Vtvbg==", + "dev": true, + "dependencies": { + "@types/sizzle": "*" + } + }, + "node_modules/@types/node": { + "version": "13.11.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.1.tgz", + "integrity": "sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==", + "dev": true + }, + "node_modules/@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "dev": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", + "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", + "dev": true + }, + "node_modules/alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.11.1.tgz", + "integrity": "sha512-DCTr3kDrKEYNw6Jb9HFxVLQNaue8z+0ZfRBRjmCunKDEXEBajKDj2Y+Uelg+Pi29OnvaSGwjOsnRyNEkXzHg5g==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001038", + "electron-to-chromium": "^1.3.390", + "node-releases": "^1.1.53", + "pkg-up": "^2.0.0" + }, + "bin": { + "browserslist": "cli.js" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001040", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001040.tgz", + "integrity": "sha512-Ep0tEPeI5wCvmJNrXjE3etgfI+lkl1fTDU6Y3ZH1mhrjkPlVI9W4pcKbMo+BQLpEWKVYYp2EmYaRsqpPC3k7lQ==", + "dev": true + }, + "node_modules/capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/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==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "dependencies": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "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==", + "dev": true, + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "dev": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "dependencies": { + "capture-stack-trace": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + }, + "engines": { + "node": ">4" + } + }, + "node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", + "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/csso": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.0.3.tgz", + "integrity": "sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ==", + "dev": true, + "dependencies": { + "css-tree": "1.0.0-alpha.39" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "1.0.0-alpha.39", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.39.tgz", + "integrity": "sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.6", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz", + "integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "dev": true + }, + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/download-crx": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/download-crx/-/download-crx-1.1.0.tgz", + "integrity": "sha512-I+itPJvylK8ByLad3kVuic+tHsO84N1JWCniHcEhfw0HfI+DrELQ44VE4WW7XxM8BrEBs4vEFcE/HWUdw4pRXA==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "got": "^6.3.0", + "lodash": "^4.13.1", + "urijs": "^1.18.1" + }, + "bin": { + "download-crx": "bin/download" + } + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.3.403", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.403.tgz", + "integrity": "sha512-JaoxV4RzdBAZOnsF4dAlZ2ijJW72MbqO5lNfOBHUWiBQl3Rwe+mk2RCUMrRI3rSClLJ8HSNQNqcry12H+0ZjFw==", + "dev": true + }, + "node_modules/entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "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==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "dependencies": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, + "node_modules/hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "node_modules/hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "node_modules/html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "dependencies": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "node_modules/is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "dependencies": { + "html-comment-regex": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/jquery": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.0.tgz", + "integrity": "sha512-Xb7SVYMvygPxbFMpTFQiHh1J7HClEaThguL15N/Gg37Lri/qKyhRGZYzHRyLH8Stq3Aow0LsHO2O2ci86fCrNQ==" + }, + "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": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/jszip": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.4.0.tgz", + "integrity": "sha512-gZAOYuPl4EhPTXT0GjhI3o+ZAz3su6EhLrKUoAivcKqyqC7laS5JEv4XWZND9BgcDcF83vI85yGbDmDR6UhrIg==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/node-releases": { + "version": "1.1.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz", + "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==", + "dev": true + }, + "node_modules/normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/nw-vue-devtools-prebuilt": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/nw-vue-devtools-prebuilt/-/nw-vue-devtools-prebuilt-0.0.10.tgz", + "integrity": "sha512-zea3OR/eUQb/cpTWBOovwJlP5WDo3InMd8XHxcSiGyhHQYQ3OM/m4nRtjXj9wFpKN42cNfbAmcd9YjR+sXRQ0g==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "download-crx": "^1.1.0", + "unzip-crx-3": "^0.2.0" + } + }, + "node_modules/object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-calc": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.2.tgz", + "integrity": "sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-colormin/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-convert-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "dependencies": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-merge-longhand/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-font-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-gradients/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-params/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-display-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-positions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-repeat-style/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "dependencies": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-string/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-timing-functions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-unicode/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "dependencies": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-url/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-whitespace/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-ordered-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-reduce-transforms/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "dev": true, + "dependencies": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-svgo/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz", + "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==", + "dev": true + }, + "node_modules/prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "node_modules/rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/stylehacks/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "node_modules/typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "node_modules/uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "node_modules/unzip-crx-3": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz", + "integrity": "sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==", + "dev": true, + "dependencies": { + "jszip": "^3.1.0", + "mkdirp": "^0.5.1", + "yaku": "^0.16.6" + } + }, + "node_modules/unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/urijs": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", + "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==", + "dev": true + }, + "node_modules/url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "dependencies": { + "prepend-http": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, + "node_modules/vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true + }, + "node_modules/vue": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz", + "integrity": "sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==" + }, + "node_modules/vue-clickaway": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/vue-clickaway/-/vue-clickaway-2.2.2.tgz", + "integrity": "sha512-25SpjXKetL06GLYoLoC8pqAV6Cur9cQ//2g35GRFBV4FgoljbZZjTINR8g2NuVXXDMLSUXaKx5dutgO4PaDE7A==", + "dependencies": { + "loose-envify": "^1.2.0" + } + }, + "node_modules/vue-context": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vue-context/-/vue-context-5.2.0.tgz", + "integrity": "sha512-XH3SwDanAcE7ppzVEkXqpMyzkFKUDp8TDh4vBE9UPbT6OHwLIwtANH6ZAakq8q2iV+hGtDDfwYgX12IbZjyNnw==", + "dependencies": { + "vue-clickaway": "^2.2.2" + } + }, + "node_modules/yaku": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/yaku/-/yaku-0.16.7.tgz", + "integrity": "sha1-HRlceKqbW/hHnIlblQT9TwhHmE4=", + "dev": true + } + }, "dependencies": { "@types/jquery": { "version": "3.3.34", @@ -1579,6 +3700,23 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, "string.prototype.trimend": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", @@ -1621,23 +3759,6 @@ "es-abstract": "^1.17.5" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, "stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", diff --git a/package.json b/package.json index 46cd75246..56da7cd06 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,9 @@ "nw-vue-devtools-prebuilt": "0.0.10", "typescript": "^3.8.3" }, + "alias": { + "vue": "./node_modules/vue/dist/vue" + }, "browserslist": [ "Chrome 80" ], diff --git a/src/main/scala/org/tygus/suslik/report/ProofTrace.scala b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala index e056e7599..a944352be 100644 --- a/src/main/scala/org/tygus/suslik/report/ProofTrace.scala +++ b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala @@ -8,6 +8,7 @@ import org.tygus.suslik.synthesis.Memoization import org.tygus.suslik.synthesis.Memoization.GoalStatus import org.tygus.suslik.synthesis.SearchTree.{AndNode, OrNode, SearchNode} import org.tygus.suslik.synthesis.rules.Rules +import org.tygus.suslik.synthesis.rules.Rules.SynthesisRule import upickle.default.{macroRW, ReadWriter => RW} import scala.annotation.tailrec @@ -19,10 +20,13 @@ sealed abstract class ProofTrace { def add(node: SearchNode, status: GoalStatus, from: Option[String] = None) { } def add(result: Rules.RuleResult, parent: OrNode) { } def add(backlink: BackLink) { } + def add(ruleTrail: RuleTrail) { } } object ProofTrace { case class BackLink(bud: Goal, companion: Goal) + case class RuleTrail(from: Goal, to: Seq[Goal], rule: SynthesisRule, + subst: Map[String, String]) var current: ProofTrace = ProofTraceNone // oops, not thread-safe } @@ -69,8 +73,14 @@ class ProofTraceJson(val outputFile: File) extends ProofTrace { } override def add(backlink: BackLink) { - writeObject(CyclicEntry( - BackLinkEntry(backlink.bud.label.pp, backlink.companion.label.pp))) + writeObject(BackLinkEntry("BackLink", + backlink.bud.label.pp, backlink.companion.label.pp)) + } + + override def add(ruleTrail: RuleTrail) { + writeObject(RuleTrailEntry("RuleTrail", + ruleTrail.from.label.pp, ruleTrail.to.map(_.label.pp), + ruleTrail.rule.toString, ruleTrail.subst)) } } @@ -83,7 +93,7 @@ object ProofTraceJson { implicit val rw: RW[NodeEntry] = macroRW } - case class GoalEntry(id: String, + case class GoalEntry(id: GoalEntry.Id, pre: String, post: String, sketch: String, @@ -91,6 +101,7 @@ object ProofTraceJson { existentials: Seq[(String, String)], ghosts: Seq[(String, String)]) object GoalEntry { + type Id = String implicit val rw: RW[GoalEntry] = macroRW def apply(goal: Goal): GoalEntry = GoalEntry(goal.label.pp, @@ -120,10 +131,19 @@ object ProofTraceJson { implicit val rw: RW[CyclicEntry] = macroRW } - case class BackLinkEntry(bud: String, companion: String) + case class BackLinkEntry(tag: String, bud: String, companion: String) object BackLinkEntry { implicit val rw: RW[BackLinkEntry] = macroRW } + + case class RuleTrailEntry(tag: String, + from: GoalEntry.Id, + to: Seq[GoalEntry.Id], + ruleName: String, + subst: Map[String, String]) + object RuleTrailEntry { + implicit val rw: RW[RuleTrailEntry] = macroRW + } } // [Certify] Collects non-backtracked SearchTree nodes (and their ancestors), used to populate the CertTree diff --git a/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunner.scala b/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunner.scala index 318425fae..e9c755a5d 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunner.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunner.scala @@ -192,7 +192,7 @@ object SynthesisRunner extends SynthesisRunnerUtil { _.copy(logToFile = b) }).text("log results to a csv file; default: false") - opt[String]('j', "traceToJsonFile").action(cfg { fn => + opt[String]('j', "traceToJson").action(cfg { fn => _.copy(traceToJsonFile = Some(new File(fn))) }).text("dump entire proof search trace to a json file; default: none") diff --git a/src/main/scala/org/tygus/suslik/synthesis/rules/UnfoldingRules.scala b/src/main/scala/org/tygus/suslik/synthesis/rules/UnfoldingRules.scala index 848f38620..039b6bb35 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/rules/UnfoldingRules.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/rules/UnfoldingRules.scala @@ -6,6 +6,7 @@ import org.tygus.suslik.language.{CardType, Ident} import org.tygus.suslik.logic.Specifications._ import org.tygus.suslik.logic._ import org.tygus.suslik.logic.smt.SMTSolving +import org.tygus.suslik.report.ProofTrace import org.tygus.suslik.synthesis.Termination.Transition import org.tygus.suslik.synthesis._ import org.tygus.suslik.synthesis.rules.Rules._ @@ -51,6 +52,9 @@ object UnfoldingRules extends SepLogicUtils with RuleUtils { hasProgressed = true, isCompanion = true)) + ProofTrace.current.add(ProofTrace.RuleTrail(goal, newGoals.map(_._2), this, + Map("pred" -> pred, "args" -> args.toString))) + // This is important, otherwise the rule is unsound and produces programs reading from ghosts // We can make the conditional without additional reading // TODO: Generalise this in the future diff --git a/src/viz/ts/open.ts b/src/viz/ts/open.ts index 96392ffb6..8673ae941 100644 --- a/src/viz/ts/open.ts +++ b/src/viz/ts/open.ts @@ -26,7 +26,7 @@ class MainDocument { var data = ProofTrace.Data.parse(content), pt = new ProofTrace(data); - this.pane.replaceWith(this.pane = $(pt.view.$el)); + this.pane.replaceWith(this.pane = $(pt.view.$el as HTMLElement)); return pt; } catch (e) { @@ -39,8 +39,10 @@ class MainDocument { } async openUrl(url: string, opts?: OpenOptions) { - this.storage['suslik:doc:lastUrl'] = url; - return this.open(await (await fetch(url)).text(), opts) + var doc = await this.open(await (await fetch(url)).text(), opts) + if (doc) + this.storage['suslik:doc:lastUrl'] = url; + return doc; } openRecent(opts?: OpenOptions) { @@ -59,7 +61,7 @@ class MainDocument { } type OpenOptions = {name?: string, silent?: boolean}; -const DEFAULT_URL = '/trace.out'; +const DEFAULT_URL = '/trace.json'; class DragDropJson extends EventEmitter { diff --git a/src/viz/ts/proof-trace.ts b/src/viz/ts/proof-trace.ts index a8d286a3c..ac40aab55 100644 --- a/src/viz/ts/proof-trace.ts +++ b/src/viz/ts/proof-trace.ts @@ -1,6 +1,6 @@ import arreq from 'array-equal'; import $ from 'jquery'; -import Vue from 'vue/dist/vue'; +import Vue from 'vue'; import { VueContext } from 'vue-context' import 'vue-context/dist/css/vue-context.css'; @@ -22,7 +22,7 @@ class ProofTrace { viewById: JSONMap } - view: Vue + view: Vue & {root: View.Node} constructor(data: ProofTrace.Data) { this.data = data; @@ -239,7 +239,7 @@ namespace ProofTrace { JSON.parse(ln)); var nodes = [], statuses = []; for (let e of entries) { - if (e.tag) nodes.push(e); + if (["AndNode", "OrNode"].includes(e.tag)) nodes.push(e); else if (e.status) statuses.push(e); } return {nodes, statuses}; From 47210bf7b16d4be608f05bf01b3ec600835e4df9 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Sat, 29 May 2021 23:33:32 +0300 Subject: [PATCH 02/90] [feature] Trace derivation trail with vector args. `OrVec` is used as an Either to properly serialize to JSON. --- build.sbt | 2 +- .../org/tygus/suslik/report/ProofTrace.scala | 53 +++++++++++++------ .../synthesis/rules/UnfoldingRules.scala | 4 +- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/build.sbt b/build.sbt index 0e8fdd3a4..8e2c5c353 100644 --- a/build.sbt +++ b/build.sbt @@ -25,7 +25,7 @@ libraryDependencies ++= Seq( "org.scalaz" %% "scalaz-core" % "7.2.11", "com.github.scopt" %% "scopt" % "3.7.0", "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2", - "com.lihaoyi" %% "upickle" % "0.9.5", + "com.lihaoyi" %% "upickle" % "1.3.15", "org.bitbucket.franck44.scalasmt" %% "scalasmt" % "2.1.1-SNAPSHOT" withSources() ) diff --git a/src/main/scala/org/tygus/suslik/report/ProofTrace.scala b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala index a944352be..303988ca8 100644 --- a/src/main/scala/org/tygus/suslik/report/ProofTrace.scala +++ b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala @@ -1,7 +1,6 @@ package org.tygus.suslik.report import java.io.{BufferedWriter, File, FileWriter} - import org.tygus.suslik.language.Expressions import org.tygus.suslik.logic.Specifications.Goal import org.tygus.suslik.synthesis.Memoization @@ -12,6 +11,8 @@ import org.tygus.suslik.synthesis.rules.Rules.SynthesisRule import upickle.default.{macroRW, ReadWriter => RW} import scala.annotation.tailrec +import scala.language.implicitConversions + sealed abstract class ProofTrace { import ProofTrace._ @@ -20,13 +21,23 @@ sealed abstract class ProofTrace { def add(node: SearchNode, status: GoalStatus, from: Option[String] = None) { } def add(result: Rules.RuleResult, parent: OrNode) { } def add(backlink: BackLink) { } - def add(ruleTrail: RuleTrail) { } + def add(derivationTrail: DerivationTrail) { } } object ProofTrace { case class BackLink(bud: Goal, companion: Goal) - case class RuleTrail(from: Goal, to: Seq[Goal], rule: SynthesisRule, - subst: Map[String, String]) + + abstract class OrVec() + case class Single(s: String) extends OrVec + case class Vec(ss: Seq[String]) extends OrVec + + object OrVec { + implicit def orVecFromT(s: String): Single = Single(s) + implicit def orVecFromSeq(s: Seq[String]): Vec = Vec(s) + } + + case class DerivationTrail(from: Goal, to: Seq[Goal], rule: SynthesisRule, + subst: Map[String, OrVec]) var current: ProofTrace = ProofTraceNone // oops, not thread-safe } @@ -77,10 +88,10 @@ class ProofTraceJson(val outputFile: File) extends ProofTrace { backlink.bud.label.pp, backlink.companion.label.pp)) } - override def add(ruleTrail: RuleTrail) { - writeObject(RuleTrailEntry("RuleTrail", - ruleTrail.from.label.pp, ruleTrail.to.map(_.label.pp), - ruleTrail.rule.toString, ruleTrail.subst)) + override def add(derivationTrail: DerivationTrail) { + val d = derivationTrail + writeObject(DerivationTrailEntry("DerivationTrail", + d.from.label.pp, d.to.map(_.label.pp), d.rule.toString, d.subst)) } } @@ -136,13 +147,25 @@ object ProofTraceJson { implicit val rw: RW[BackLinkEntry] = macroRW } - case class RuleTrailEntry(tag: String, - from: GoalEntry.Id, - to: Seq[GoalEntry.Id], - ruleName: String, - subst: Map[String, String]) - object RuleTrailEntry { - implicit val rw: RW[RuleTrailEntry] = macroRW + import upickle.default._ + import ProofTrace.{OrVec, Single, Vec} + + implicit val ovRW: RW[OrVec] = + readwriter[ujson.Value].bimap[OrVec]( + { case Single(x) => x case Vec(v) => v }, + json => json.arrOpt match { + case Some(v) => Vec(v.map(_.str)) + case None => Single(json.str) + } + ) + + case class DerivationTrailEntry(tag: String, + from: GoalEntry.Id, + to: Seq[GoalEntry.Id], + ruleName: String, + subst: Map[String, OrVec]) + object DerivationTrailEntry { + implicit val rw: RW[DerivationTrailEntry] = macroRW } } diff --git a/src/main/scala/org/tygus/suslik/synthesis/rules/UnfoldingRules.scala b/src/main/scala/org/tygus/suslik/synthesis/rules/UnfoldingRules.scala index 039b6bb35..d218f7c1b 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/rules/UnfoldingRules.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/rules/UnfoldingRules.scala @@ -52,8 +52,8 @@ object UnfoldingRules extends SepLogicUtils with RuleUtils { hasProgressed = true, isCompanion = true)) - ProofTrace.current.add(ProofTrace.RuleTrail(goal, newGoals.map(_._2), this, - Map("pred" -> pred, "args" -> args.toString))) + ProofTrace.current.add(ProofTrace.DerivationTrail(goal, newGoals.map(_._2), this, + Map("pred" -> pred, "args" -> args.map(_.toString)))) // This is important, otherwise the rule is unsound and produces programs reading from ghosts // We can make the conditional without additional reading From 2ceaad074208037f5ae71a5e1c8280be246cf39f Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Sat, 29 May 2021 23:34:23 +0300 Subject: [PATCH 03/90] [ui] Parse & display derivation trail. Currently shown in the hint area (status bar). This should be temporary. --- src/viz/ts/main.ts | 10 +++--- src/viz/ts/open.ts | 17 +++++----- src/viz/ts/proof-trace.css | 8 ++++- src/viz/ts/proof-trace.ts | 64 ++++++++++++++++++++++++++++++++------ 4 files changed, 77 insertions(+), 22 deletions(-) diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index af1a52a10..d8b8f7751 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -18,19 +18,19 @@ if (typeof nw !== 'undefined') { $(async () => { var doc = new MainDocument($('#proof-trace-pane'), $('#notifications')); + doc.on('open', pt => Object.assign(window, {pt})); + try { - var pt = await doc.openRecent({silent: true}); - Object.assign(window, {pt}); + await doc.openRecent({silent: true}); } catch (e) { console.error('open failed:', e); } var drop = new DragDropJson($('html')); drop.on('open', async ({file}) => { try { - var pt = await doc.open(file); - Object.assign(window, {pt}); + await doc.open(file); } - catch (e) { } + catch (e) { console.error('open failed:', e); } }); Object.assign(window, {doc}); diff --git a/src/viz/ts/open.ts b/src/viz/ts/open.ts index 8673ae941..722b43178 100644 --- a/src/viz/ts/open.ts +++ b/src/viz/ts/open.ts @@ -5,28 +5,31 @@ import { ProofTrace } from './proof-trace'; -class MainDocument { +class MainDocument extends EventEmitter { + pt: ProofTrace pane: JQuery notifications: JQuery storage: {'suslik:doc:lastUrl'?: string} = localStorage; - constructor(pane: JQuery, notifications: JQuery) { + constructor(pane: JQuery, notifications: JQuery) { + super(); this.pane = pane; this.notifications = notifications; } - async open(content: string | File, opts: OpenOptions = {}) { + async open(content: string | File, opts: OpenOptions = {}): Promise { if (content instanceof File) { return this.open(await this.read(content), {name: content.name, ...opts}); } else { try { var data = ProofTrace.Data.parse(content), - pt = new ProofTrace(data); + pt = this.pt = new ProofTrace(data); this.pane.replaceWith(this.pane = $(pt.view.$el as HTMLElement)); + this.emit('open', pt); return pt; } catch (e) { @@ -39,10 +42,10 @@ class MainDocument { } async openUrl(url: string, opts?: OpenOptions) { - var doc = await this.open(await (await fetch(url)).text(), opts) - if (doc) + var pt = await this.open(await (await fetch(url)).text(), opts) + if (pt) this.storage['suslik:doc:lastUrl'] = url; - return doc; + return pt; } openRecent(opts?: OpenOptions) { diff --git a/src/viz/ts/proof-trace.css b/src/viz/ts/proof-trace.css index 8ab3a29ea..7b4965dff 100644 --- a/src/viz/ts/proof-trace.css +++ b/src/viz/ts/proof-trace.css @@ -8,7 +8,7 @@ } .proof-trace .subtrees { - white-space: nowrap; + display: flex; } .proof-trace-node { @@ -52,11 +52,16 @@ } .proof-trace-goal { + clear: both; /* skip any floats from title */ white-space: normal; border: 1px solid #999; padding: 2px; } +.proof-trace-goal .synth-arrow { + color: #88f; +} + .proof-trace-node:hover > .proof-trace-goal { background: #fff; } @@ -67,6 +72,7 @@ margin-right: 0.2em; margin-bottom: 0.5em; vertical-align: top; + flex-shrink: 0; } .proof-trace-vars > span:not(:last-child)::after { diff --git a/src/viz/ts/proof-trace.ts b/src/viz/ts/proof-trace.ts index ac40aab55..f3f783022 100644 --- a/src/viz/ts/proof-trace.ts +++ b/src/viz/ts/proof-trace.ts @@ -1,3 +1,4 @@ +import assert from 'assert'; import arreq from 'array-equal'; import $ from 'jquery'; import Vue from 'vue'; @@ -96,6 +97,11 @@ class ProofTrace { m.set(parent, l.concat([child])); } + parent(node: Data.NodeEntry) { + var id = node.id.slice(1); + return this.nodeIndex.byId.get(id); + } + children(node: Data.NodeEntry) { function lex2(a1: number[], a2: number[]) { let n = Math.min(2, a1.length, a2.length); @@ -134,7 +140,9 @@ class ProofTrace { createNode(node: Data.NodeEntry): View.Node { var v = {value: node, children: undefined, focus: false, expanded: false, status: this.getStatus(node), + derivation: this.getDerivationTrail(node), numDescendants: this.getSubtreeSize(node)}; + console.log(node, v.derivation); this.nodeIndex.viewById.set(node.id, v); return v; } @@ -178,6 +186,17 @@ class ProofTrace { this.expandAll(c); } + getDerivationTrail(node: Data.NodeEntry) { + if (node.tag !== Data.NodeType.AndNode) return; + var from = this.parent(node), + to = this.children(node); + assert(from.tag == Data.NodeType.OrNode && + to.every(v => v.tag == Data.NodeType.OrNode)); + return this.data.trail.find(dte => + dte.from === from.goal.id && + arreq(dte.to, to.map(v => v.goal.id))); + } + viewAction(ev: View.ActionEvent) { switch (ev.type) { case 'expand': @@ -200,7 +219,8 @@ namespace ProofTrace { export type Data = { nodes: Data.NodeEntry[], - statuses: Data.StatusEntry[] + statuses: Data.StatusEntry[], + trail: Data.DerivationTrailEntry[] }; export namespace Data { @@ -216,15 +236,18 @@ namespace ProofTrace { export type NodeId = number[]; export enum NodeType { AndNode = 'AndNode', OrNode = 'OrNode' }; + const NODE_TAGS = Object.values(NodeType); export type GoalEntry = { - id: string + id: GoalId pre: string, post: string, sketch: string, programVars: [string, string][] existentials: [string, string][] ghosts: [string, string][] }; + export type GoalId = string + export type Environment = Map; export type StatusEntry = { @@ -234,15 +257,27 @@ namespace ProofTrace { export type GoalStatusEntry = {tag: "Succeeded" | "Failed", from?: string | string[]}; + export type DerivationTrailEntry = { + tag: "DerivationTrail" + from: GoalId + to: GoalId[] + ruleName: string + subst: {[metavar: string]: OrVec} + }; + const DERIVATION_TRAIL_TAG = "DerivationTrail" + + export type OrVec = T | T[]; + export function parse(traceText: string): Data { var entries = traceText.split('\n\n').filter(x => x).map(ln => JSON.parse(ln)); - var nodes = [], statuses = []; + var nodes = [], statuses = [], trail = []; for (let e of entries) { - if (["AndNode", "OrNode"].includes(e.tag)) nodes.push(e); + if (NODE_TAGS.includes(e.tag)) nodes.push(e); + else if (e.tag === DERIVATION_TRAIL_TAG) trail.push(e); else if (e.status) statuses.push(e); } - return {nodes, statuses}; + return {nodes, statuses, trail}; } export function envOfGoal(goal: GoalEntry) { @@ -362,7 +397,8 @@ Vue.component('proof-trace', {
@@ -14,10 +16,11 @@ import AppToolbar from './app-toolbar.vue'; import AppContextMenu from './app-context-menu'; import ProofTrace from './proof-trace.vue'; +import ProofInteraction from './proof-interaction.vue'; export default { - props: ['root'], + props: ['root', 'interaction'], data: () => ({options: {}, zoom: 1}), methods: { toplevelAction(ev) { @@ -27,6 +30,6 @@ export default { this.$emit('action', ev); } }, - components: { AppToolbar, AppContextMenu, ProofTrace } + components: { AppToolbar, AppContextMenu, ProofTrace, ProofInteraction } } From b7c0dc730b12682b7dd4096bb75d9d0bd591ef55 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Sat, 5 Jun 2021 20:17:06 +0300 Subject: [PATCH 15/90] [feature] Start with an empty trace then build incrementally. For exploring interactively in client-server mode. --- src/main/resources/application.conf | 8 +++ .../suslik/interaction/SynthesisServer.scala | 10 ++- src/viz/ts/main.ts | 9 +++ src/viz/ts/open.ts | 19 ++++-- src/viz/ts/proof-interaction.ts | 3 + src/viz/ts/proof-trace.ts | 66 +++++++++++++++---- 6 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 src/main/resources/application.conf diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf new file mode 100644 index 000000000..5506f5ac9 --- /dev/null +++ b/src/main/resources/application.conf @@ -0,0 +1,8 @@ +akka.http { + server { + websocket { + periodic-keep-alive-mode = ping + periodic-keep-alive-max-idle = 30 seconds + } + } +} \ No newline at end of file diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala index 7b91d22ca..ff75da7a5 100644 --- a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -101,9 +101,13 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { val tactic = new PhasedSynthesis(env.config) { override def filterExpansions(allExpansions: Seq[Rules.RuleResult]): Seq[Rules.RuleResult] = { - outbound.put(write(allExpansions.map(_.subgoals.map(GoalEntry(_))))) - val choice = inbound.take() - allExpansions.filter(_.subgoals.exists(goal => goal.label.pp.contains(choice))) + allExpansions.find(_.subgoals.isEmpty) match { + case Some(fin) => Seq(fin) + case _ => + outbound.put(write(allExpansions.map(_.subgoals.map(GoalEntry(_))))) + val choice = inbound.take() + allExpansions.filter(_.subgoals.exists(goal => goal.label.pp.contains(choice))) + } } } val trace = new ProofTraceJson { diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index 71a91b6f4..29bafde09 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -1,5 +1,6 @@ import $ from 'jquery'; import { MainDocument, DragDropJson } from './open'; +import { ProofTrace } from './proof-trace'; import { ProofInteraction } from './proof-interaction'; @@ -21,10 +22,13 @@ $(async () => { var doc = new MainDocument($('#proof-trace-pane'), $('#notifications')); doc.on('open', pt => Object.assign(window, {pt})); + /* try { await doc.openRecent({silent: true}); } catch (e) { console.error('open failed:', e); } + */ + doc.new(); var drop = new DragDropJson($('html')); drop.on('open', async ({file}) => { @@ -36,6 +40,11 @@ $(async () => { var pi = new ProofInteraction(doc.pt.view); pi.on('message', console.log); + pi.on('trace', u => { + var data = ProofTrace.Data.fromEntries([u]); + console.log(data); + doc.pt.append(data); + }); Object.assign(window, {doc, pi}); }); \ No newline at end of file diff --git a/src/viz/ts/open.ts b/src/viz/ts/open.ts index 722b43178..19133e5f2 100644 --- a/src/viz/ts/open.ts +++ b/src/viz/ts/open.ts @@ -19,18 +19,18 @@ class MainDocument extends EventEmitter { this.notifications = notifications; } + new() { + return this.set(new ProofTrace(ProofTrace.Data.empty())); + } + async open(content: string | File, opts: OpenOptions = {}): Promise { if (content instanceof File) { return this.open(await this.read(content), {name: content.name, ...opts}); } else { try { - var data = ProofTrace.Data.parse(content), - pt = this.pt = new ProofTrace(data); - - this.pane.replaceWith(this.pane = $(pt.view.$el as HTMLElement)); - this.emit('open', pt); - return pt; + var data = ProofTrace.Data.parse(content); + return this.set(new ProofTrace(data)); } catch (e) { if (!opts.silent) { @@ -52,6 +52,13 @@ class MainDocument extends EventEmitter { return this.openUrl(this.storage['suslik:doc:lastUrl'] || DEFAULT_URL, opts); } + set(pt: ProofTrace) { + this.pt = pt; + this.pane.replaceWith(this.pane = $(pt.view.$el as HTMLElement)); + this.emit('open', pt); + return pt; + } + async read(file: File) { return new TextDecoder().decode(await file.arrayBuffer()); } diff --git a/src/viz/ts/proof-interaction.ts b/src/viz/ts/proof-interaction.ts index 0bef1f518..d0b8aca82 100644 --- a/src/viz/ts/proof-interaction.ts +++ b/src/viz/ts/proof-interaction.ts @@ -43,6 +43,9 @@ class ProofInteraction extends EventEmitter { this.view.interaction.choices = msg; this.emit('choose', msg); } + else { + this.emit('trace', msg); + } } handleAction(action: ProofInteraction.View.Action) { diff --git a/src/viz/ts/proof-trace.ts b/src/viz/ts/proof-trace.ts index fc4ff4fa7..3fa94e2b6 100644 --- a/src/viz/ts/proof-trace.ts +++ b/src/viz/ts/proof-trace.ts @@ -33,6 +33,12 @@ class ProofTrace { this.createView(); } + append(data: Data) { + this.updateIndex(data); + for (let node of data.nodes) + this.addNode(node); + } + createIndex() { this.nodeIndex = { byId: new JSONMap(), @@ -40,26 +46,33 @@ class ProofTrace { statusById: new JSONMap(), viewById: new JSONMap() }; + this.updateIndex(this.data); + } + + updateIndex(data: Data) { // Build byId - for (let node of this.data.nodes) { + for (let node of data.nodes) { if (!this.nodeIndex.byId.get(node.id)) this.nodeIndex.byId.set(node.id, node); } // Build childrenById - for (let node of this.data.nodes) { + for (let node of data.nodes) { if (node.id.length >= 1) { var parent = node.id.slice(1); - this.addChild(parent, node); + this.addChildToIndex(parent, node); } } // Build statusById - for (let entry of this.data.statuses) { + for (let entry of data.statuses) { var id = entry.at; this.nodeIndex.statusById.set(id, entry); } + // - compute transitive success + // This has to be computed over *all* data; can optimize by only + // considering ancestors of newly indexed nodes for (let node of this.data.nodes.sort((a, b) => b.id.length - a.id.length)) { if (!this.nodeIndex.statusById.get(node.id)) { let children = (this.nodeIndex.childrenById.get(node.id) || []) @@ -82,14 +95,14 @@ class ProofTrace { // Build subtreeSizeById var sz = this.nodeIndex.subtreeSizeById; - for (let node of this.data.nodes.sort((a, b) => b.id.length - a.id.length)) { + for (let node of data.nodes.sort((a, b) => b.id.length - a.id.length)) { let children = (this.nodeIndex.childrenById.get(node.id) || []); sz.set(node.id, 1 + children.map(u => sz.get(u.id) || 1) .reduce((x,y) => x + y, 0)); } } - addChild(parent: Data.NodeId, child: Data.NodeEntry) { + addChildToIndex(parent: Data.NodeId, child: Data.NodeEntry) { var m = this.nodeIndex.childrenById; // Note: nodes can re-occur if they were suspended during the search var l = m.get(parent) || []; @@ -98,7 +111,7 @@ class ProofTrace { } parent(node: Data.NodeEntry) { - var id = node.id.slice(1); + var id = Data.parentId(node.id); return this.nodeIndex.byId.get(id); } @@ -120,14 +133,31 @@ class ProofTrace { createView() { this.view = new Vue(ProofTracePane); - this.view.root = this.createNode(this.root); - this.expandNode(this.view.root); - this.expandNode(this.view.root.children[0]); + if (this.root) { + this.view.root = this.createNode(this.root); + this.expandNode(this.view.root); + this.expandNode(this.view.root.children[0]); + } this.view.$mount(); this.view.$on('action', (ev: View.ActionEvent) => this.viewAction(ev)); } + addNode(node: Data.NodeEntry) { + if (node.id.length == 0) { // this is the root + this.root = node; + this.view.root = this.createNode(node); + } + else { + var parentId = Data.parentId(node.id), + parentView = this.nodeIndex.viewById.get(parentId); + if (parentView) { + parentView.children ??= []; + parentView.children.push(this.createNode(node)); + } + } + } + getStatus(node: Data.NodeEntry): Data.GoalStatusEntry { var entry = this.nodeIndex.statusById.get(node.id); return entry && entry.status; @@ -267,9 +297,17 @@ namespace ProofTrace { export type OrVec = T | T[]; + export function empty() { + return {nodes: [], statuses: [], trail: []}; + } + export function parse(traceText: string): Data { - var entries = traceText.split('\n\n').filter(x => x).map(ln => - JSON.parse(ln)); + var entries = traceText.split('\n\n').filter(x => x) + .map(ln => JSON.parse(ln)); + return fromEntries(entries); + } + + export function fromEntries(entries: any[]): Data { var nodes = [], statuses = [], trail = []; for (let e of entries) { if (NODE_TAGS.includes(e.tag)) nodes.push(e); @@ -279,6 +317,10 @@ namespace ProofTrace { return {nodes, statuses, trail}; } + export function parentId(id: NodeId) { + return id.slice(1); + } + export function envOfGoal(goal: GoalEntry) { var d: Environment = new Map; function intro(vs: [string, string][], of: string) { From bbf1be74cde08173acfb3b4426e199ac1b9d3512 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Sat, 5 Jun 2021 21:48:01 +0300 Subject: [PATCH 16/90] [feature] More interaction. Display more info with choices: goal from which each choice was derived and name of rule. Update status when sent from server. --- src/main/resources/application.conf | 6 ++ .../suslik/interaction/SynthesisServer.scala | 87 +++++++++++++++---- src/viz/ts/main.ts | 3 +- src/viz/ts/proof-interaction.css | 2 + src/viz/ts/proof-interaction.ts | 7 +- src/viz/ts/proof-trace.ts | 39 ++++++++- src/viz/vue/proof-interaction.vue | 3 +- 7 files changed, 119 insertions(+), 28 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 5506f5ac9..f5ee6f3fe 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1,3 +1,9 @@ +suslik { + server { + port = 8033 + } +} + akka.http { server { websocket { diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala index ff75da7a5..523c043c3 100644 --- a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -1,20 +1,24 @@ package org.tygus.suslik.interaction -import akka.NotUsed - import java.util.concurrent.ArrayBlockingQueue import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success} +import org.slf4j.Logger +import upickle.default.{macroRW, ReadWriter => RW} + +import akka.{Done, NotUsed} import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors import akka.http.scaladsl.Http -import akka.http.scaladsl.model.ws.{BinaryMessage, Message, TextMessage} +import akka.http.scaladsl.model.ws.{Message, TextMessage} import akka.http.scaladsl.server.Route import akka.http.scaladsl.server.Directives._ import akka.stream.scaladsl.{Flow, Sink, Source} + import org.tygus.suslik.language.Statements import org.tygus.suslik.logic.Environment import org.tygus.suslik.report.ProofTraceJson +import org.tygus.suslik.report.ProofTraceJson.GoalEntry import org.tygus.suslik.synthesis.rules.Rules import org.tygus.suslik.synthesis.tactics.PhasedSynthesis import org.tygus.suslik.synthesis.{SynConfig, Synthesis, SynthesisRunnerUtil} @@ -22,21 +26,27 @@ import org.tygus.suslik.synthesis.{SynConfig, Synthesis, SynthesisRunnerUtil} class SynthesisServer { - val runner = new ClientSessionSynthesis val config: SynConfig = SynConfig() - def start(): Unit = { // + /* Server configuration */ + protected def port(implicit system: ActorSystem[_]): Int = + system.settings.config.getInt("suslik.server.port"); + + def start(): Unit = { val root = Behaviors.setup[Nothing] { context => - implicit val system: ActorSystem[Nothing] = context.system - startHttpServer(routes) + implicit val system: ActorSystem[_] = context.system + startHttpServer(routes, port) Behaviors.empty } ActorSystem[Nothing](root, "SynthesisServer") } - private def startHttpServer(routes: Route)(implicit system: ActorSystem[_]): Unit = { + /** + * Server startup boilerplate. + */ + private def startHttpServer(routes: Route, port: Int)(implicit system: ActorSystem[_]): Unit = { import system.executionContext - Http().newServerAt("localhost", 8080).bind(routes) + Http().newServerAt("localhost", port).bind(routes) .onComplete { case Success(binding) => val address = binding.localAddress @@ -47,7 +57,7 @@ class SynthesisServer { } } - def go(session: SynthesisRunnerUtil = runner): String = { + def go(session: SynthesisRunnerUtil): String = { val dir = "./src/test/resources/synthesis/all-benchmarks/sll" /** @todo */ val fn = "free.syn" session.synthesizeFromFile(dir, fn, config).toString() @@ -64,7 +74,7 @@ class SynthesisServer { session.wsFlow }), get { - new Thread(() => go()).start(); complete(".") + new Thread(() => go(new AsyncSynthesisRunner)).start(); complete(".") } ) } @@ -84,11 +94,11 @@ object SynthesisServer { * Data is serialized in and out using a JSON format. */ class AsyncSynthesisRunner extends SynthesisRunnerUtil { - import org.tygus.suslik.report.ProofTraceJson._ import upickle.default.{Writer, write} + import AsyncSynthesisRunner._ val inbound = new ArrayBlockingQueue[String](1) - val outbound = new ArrayBlockingQueue[String](1) + val outbound = new ArrayBlockingQueueWithCancel[String](1) /** * Creates a `PhasedSynthesizer` that expands goals based on input sent @@ -104,7 +114,7 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { allExpansions.find(_.subgoals.isEmpty) match { case Some(fin) => Seq(fin) case _ => - outbound.put(write(allExpansions.map(_.subgoals.map(GoalEntry(_))))) + outbound.put(serializeChoices(allExpansions)) val choice = inbound.take() allExpansions.filter(_.subgoals.exists(goal => goal.label.pp.contains(choice))) } @@ -130,26 +140,65 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { } catch { case e: Throwable => outbound.put(e.toString); throw e } } + + protected def serializeChoices(allExpansions: Seq[Rules.RuleResult]): String = + write(allExpansions.map(ExpansionChoice.from)) +} + +object AsyncSynthesisRunner { + + class ArrayBlockingQueueWithCancel[E](capacity: Int) + extends ArrayBlockingQueue[E](capacity) { + private var waiting: Option[Thread] = None + override def take(): E = { + assert(waiting.isEmpty) /* allow at most one consumer thread */ + waiting = Some(Thread.currentThread()) + try super.take() finally { waiting = None } + } + def cancel() { waiting foreach (_.interrupt()) } + } + + type GoalLabel = String + + case class ExpansionChoice(from: Set[GoalLabel], + rule: String, + subgoals: Seq[GoalEntry]) + + object ExpansionChoice { + def from(rr: Rules.RuleResult): ExpansionChoice = + ExpansionChoice(rr.subgoals.flatMap(_.parent).map(_.label.pp).toSet, + rr.rule.toString, + rr.subgoals.map(GoalEntry(_))) + + implicit val readWriter: RW[ExpansionChoice] = macroRW + } } /** * Connects `AsyncSynthesisRunner` to an HTTP client. */ -class ClientSessionSynthesis extends AsyncSynthesisRunner { +class ClientSessionSynthesis(implicit ec: ExecutionContext) extends AsyncSynthesisRunner { + + val logger: Logger = org.slf4j.LoggerFactory.getLogger(getClass) - def subscribe(implicit ec: ExecutionContext): Source[String, _] = + def subscribe: Source[String, _] = Source.unfoldAsync(())(_ => Future { try Some((), outbound.take()) catch { case _: InterruptedException => None } }) - def offer(implicit ec: ExecutionContext): Sink[String, _] = + def offer: Sink[String, Future[Done]] = Sink.foreachAsync[String](1)(s => Future { inbound.put(s) }) - def wsFlow(implicit ec: ExecutionContext): Flow[Message, Message, NotUsed] = + def done(d: Done): Unit = { + outbound.cancel() + logger.info(s"client session ended; $d") + } + + def wsFlow: Flow[Message, Message, NotUsed] = Flow.fromSinkAndSource(Flow[Message].mapConcat { case m: TextMessage.Strict => println(m.text); List(m.text) case _ => println("some other message"); Nil - }.to(offer), + }.to(offer.mapMaterializedValue(m => m.foreach(done))), subscribe.map(TextMessage(_))) } \ No newline at end of file diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index 29bafde09..bf404ec72 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -39,10 +39,9 @@ $(async () => { }); var pi = new ProofInteraction(doc.pt.view); - pi.on('message', console.log); + pi.on('message', m => console.log('%cmessage', 'color: blue', m)); pi.on('trace', u => { var data = ProofTrace.Data.fromEntries([u]); - console.log(data); doc.pt.append(data); }); diff --git a/src/viz/ts/proof-interaction.css b/src/viz/ts/proof-interaction.css index a88ee26cd..f0141f396 100644 --- a/src/viz/ts/proof-interaction.css +++ b/src/viz/ts/proof-interaction.css @@ -3,4 +3,6 @@ max-width: 20em; vertical-align: top; margin-right: .5em; + border: 1px solid #888; + padding: 2px; } \ No newline at end of file diff --git a/src/viz/ts/proof-interaction.ts b/src/viz/ts/proof-interaction.ts index d0b8aca82..ec2403bc5 100644 --- a/src/viz/ts/proof-interaction.ts +++ b/src/viz/ts/proof-interaction.ts @@ -12,7 +12,7 @@ class ProofInteraction extends EventEmitter { constructor(view: Vue & {interaction: ProofInteraction.View.State}) { super(); - this.baseURL = new URL('http://localhost:8080'); + this.baseURL = new URL('http://localhost:8033'); this.view = view; this.view.interaction = {choices: undefined}; this.view.$on('interaction:action', action => this.handleAction(action)); @@ -49,10 +49,11 @@ class ProofInteraction extends EventEmitter { } handleAction(action: ProofInteraction.View.Action) { - console.log(action); switch (action.type) { case 'select': - this.continue(action.goal.id); break; + this.view.interaction.choices = undefined; // clear choices + this.continue(action.goal.id); + break; } } diff --git a/src/viz/ts/proof-trace.ts b/src/viz/ts/proof-trace.ts index 3fa94e2b6..d7d74c211 100644 --- a/src/viz/ts/proof-trace.ts +++ b/src/viz/ts/proof-trace.ts @@ -25,6 +25,8 @@ class ProofTrace { view: Vue & {root: View.Node} + _dirty: {nodes: Data.NodeEntry[]} = {nodes: []} + constructor(data: ProofTrace.Data) { this.data = data; this.root = this.data.nodes[0]; @@ -34,9 +36,11 @@ class ProofTrace { } append(data: Data) { + Data.append(this.data, data); this.updateIndex(data); for (let node of data.nodes) this.addNode(node); + this.refreshView(); } createIndex() { @@ -68,6 +72,7 @@ class ProofTrace { for (let entry of data.statuses) { var id = entry.at; this.nodeIndex.statusById.set(id, entry); + this._dirty.nodes.push(this.nodeIndex.byId.get(id)); } // - compute transitive success @@ -80,13 +85,17 @@ class ProofTrace { if (children.length) { switch (node.tag) { case Data.NodeType.OrNode: - if (children.some(x => x && x.status.tag === 'Succeeded')) + if (children.some(x => x && x.status.tag === 'Succeeded')) { this.nodeIndex.statusById.set(node.id, {at: node.id, status: {tag: 'Succeeded', from: '*'}}); + this._dirty.nodes.push(node); + } break; case Data.NodeType.AndNode: if (children.length == node.nChildren && - children.every(x => x && x.status.tag === 'Succeeded')) + children.every(x => x && x.status.tag === 'Succeeded')) { this.nodeIndex.statusById.set(node.id, {at: node.id, status: {tag: 'Succeeded', from: '*'}}); + this._dirty.nodes.push(node); + } break; } } @@ -94,8 +103,9 @@ class ProofTrace { } // Build subtreeSizeById + // (same here) var sz = this.nodeIndex.subtreeSizeById; - for (let node of data.nodes.sort((a, b) => b.id.length - a.id.length)) { + for (let node of this.data.nodes.sort((a, b) => b.id.length - a.id.length)) { let children = (this.nodeIndex.childrenById.get(node.id) || []); sz.set(node.id, 1 + children.map(u => sz.get(u.id) || 1) .reduce((x,y) => x + y, 0)); @@ -133,6 +143,7 @@ class ProofTrace { createView() { this.view = new Vue(ProofTracePane); + this._dirty.nodes = []; if (this.root) { this.view.root = this.createNode(this.root); this.expandNode(this.view.root); @@ -143,6 +154,12 @@ class ProofTrace { this.view.$on('action', (ev: View.ActionEvent) => this.viewAction(ev)); } + refreshView() { + for (let node of this._dirty.nodes) + this.refreshNode(node); + this._dirty.nodes = []; + } + addNode(node: Data.NodeEntry) { if (node.id.length == 0) { // this is the root this.root = node; @@ -154,6 +171,7 @@ class ProofTrace { if (parentView) { parentView.children ??= []; parentView.children.push(this.createNode(node)); + parentView.expanded = true; /** @todo only if view is visible */ } } } @@ -176,6 +194,14 @@ class ProofTrace { return v; } + refreshNode(node: Data.NodeEntry) { + var view = this.nodeIndex.viewById.get(node.id); + if (view) { + view.status = this.getStatus(node); + view.numDescendants = this.getSubtreeSize(node); + } + } + expandNode(nodeView: View.Node, focus: boolean = false) { nodeView.focus = focus; nodeView.expanded = true; @@ -301,6 +327,13 @@ namespace ProofTrace { return {nodes: [], statuses: [], trail: []}; } + export function append(to: Data, from: Data): Data { + to.nodes.push(...from.nodes); + to.statuses.push(...from.statuses); + to.trail.push(...from.trail); + return to; + } + export function parse(traceText: string): Data { var entries = traceText.split('\n\n').filter(x => x) .map(ln => JSON.parse(ln)); diff --git a/src/viz/vue/proof-interaction.vue b/src/viz/vue/proof-interaction.vue index df01d30b9..6e951f3a5 100644 --- a/src/viz/vue/proof-interaction.vue +++ b/src/viz/vue/proof-interaction.vue @@ -1,7 +1,8 @@ -
+
diff --git a/src/viz/ts/open.ts b/src/viz/ts/app.ts similarity index 81% rename from src/viz/ts/open.ts rename to src/viz/ts/app.ts index 19133e5f2..62048bdd1 100644 --- a/src/viz/ts/open.ts +++ b/src/viz/ts/app.ts @@ -1,5 +1,9 @@ import { EventEmitter } from 'events'; import $ from 'jquery'; +import Vue from 'vue'; + +// @ts-ignore +import app from '../vue/app.vue'; import { ProofTrace } from './proof-trace'; @@ -7,20 +11,27 @@ import { ProofTrace } from './proof-trace'; class MainDocument extends EventEmitter { + container: JQuery + + app: Vue pt: ProofTrace - pane: JQuery notifications: JQuery + props: any + storage: {'suslik:doc:lastUrl'?: string} = localStorage; - constructor(pane: JQuery, notifications: JQuery) { + constructor(container: JQuery, notifications: JQuery) { super(); - this.pane = pane; + this.container = container; + this.app = new Vue(app).$mount(); this.notifications = notifications; } + get $el() { return this.app.$el; } + new() { - return this.set(new ProofTrace(ProofTrace.Data.empty())); + return this.set(ProofTrace.Data.empty()); } async open(content: string | File, opts: OpenOptions = {}): Promise { @@ -29,8 +40,7 @@ class MainDocument extends EventEmitter { } else { try { - var data = ProofTrace.Data.parse(content); - return this.set(new ProofTrace(data)); + return this.set(ProofTrace.Data.parse(content)); } catch (e) { if (!opts.silent) { @@ -52,9 +62,9 @@ class MainDocument extends EventEmitter { return this.openUrl(this.storage['suslik:doc:lastUrl'] || DEFAULT_URL, opts); } - set(pt: ProofTrace) { + set(ptData: ProofTrace.Data) { + var pt = new ProofTrace(ptData, this.app.$refs.proofTrace as any); this.pt = pt; - this.pane.replaceWith(this.pane = $(pt.view.$el as HTMLElement)); this.emit('open', pt); return pt; } diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index 6b9ae33f9..7831cba9c 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -1,5 +1,5 @@ import $ from 'jquery'; -import { MainDocument, DragDropJson } from './open'; +import { MainDocument, DragDropJson } from './app'; import { ProofTrace } from './proof-trace'; import { ProofInteraction } from './proof-interaction'; import { BenchmarksDB } from './benchmarks'; @@ -23,6 +23,8 @@ $(async () => { var doc = new MainDocument($('#proof-trace-pane'), $('#notifications')); doc.on('open', pt => Object.assign(window, {pt})); + document.querySelector('#document-area').replaceWith(doc.$el); + /* try { await doc.openRecent({silent: true}); diff --git a/src/viz/ts/proof-interaction.ts b/src/viz/ts/proof-interaction.ts index 10fa38112..1fb1280e8 100644 --- a/src/viz/ts/proof-interaction.ts +++ b/src/viz/ts/proof-interaction.ts @@ -9,7 +9,7 @@ class ProofInteraction extends EventEmitter { ws: WebSocket pt: ProofTrace - view: Vue & ProofInteraction.ViewProps + view: Vue & ProofInteraction.View.Props constructor(pt: ProofTrace) { super(); @@ -81,22 +81,22 @@ class ProofInteraction extends EventEmitter { namespace ProofInteraction { - export type ViewProps = { - interaction: ProofInteraction.View.State - highlight: {[kind: string]: ProofTrace.Data.NodeId[]} - } - export namespace View { + export type Props = { + interaction: ProofInteraction.View.State + highlight: {[kind: string]: ProofTrace.Data.NodeId[]} + }; + export type State = { focused: ProofTrace.Data.NodeId[] choices: ProofTrace.Data.GoalEntry[] - } + }; export type Action = { type: 'select' goal?: ProofTrace.Data.GoalEntry - } + }; } diff --git a/src/viz/ts/proof-trace.ts b/src/viz/ts/proof-trace.ts index 207220577..d4bd62ed8 100644 --- a/src/viz/ts/proof-trace.ts +++ b/src/viz/ts/proof-trace.ts @@ -26,16 +26,16 @@ class ProofTrace { viewById: JSONMap } - view: Vue & {root: View.Node} + view: Vue & View.Props _dirty: {nodes: Set} = {nodes: new Set} - constructor(data: ProofTrace.Data) { + constructor(data: ProofTrace.Data, view?: Vue & View.Props) { this.data = data; this.root = this.data.nodes[0]; this.createIndex(); - this.createView(); + this.createView(view); } append(data: Data) { @@ -173,15 +173,14 @@ class ProofTrace { .sort(byId2); // modifies the list but that's ok } - createView() { - this.view = new Vue(ProofTracePane); + createView(view?: Vue & View.Props) { + this.view = view || new Vue(ProofTracePane).$mount(); this._dirty.nodes.clear(); if (this.root) { this.view.root = this.createNode(this.root); this.expandNode(this.view.root); this.expandNode(this.view.root.children[0]); } - this.view.$mount(); this.view.$on('action', (ev: View.ActionEvent) => this.viewAction(ev)); } @@ -397,6 +396,8 @@ namespace ProofTrace { // View Part // ========= export namespace View { + + export type Props = {root: View.Node}; export type Node = { value: Data.NodeEntry diff --git a/src/viz/vue/app-benchmark-list.vue b/src/viz/vue/app-benchmark-list.vue new file mode 100644 index 000000000..9381cdb52 --- /dev/null +++ b/src/viz/vue/app-benchmark-list.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/viz/vue/app.vue b/src/viz/vue/app.vue new file mode 100644 index 000000000..c84be370f --- /dev/null +++ b/src/viz/vue/app.vue @@ -0,0 +1,15 @@ + + + \ No newline at end of file diff --git a/src/viz/vue/proof-trace-pane.vue b/src/viz/vue/proof-trace-pane.vue index 4d2584212..cbefd84d7 100644 --- a/src/viz/vue/proof-trace-pane.vue +++ b/src/viz/vue/proof-trace-pane.vue @@ -21,8 +21,8 @@ import ProofInteraction from './proof-interaction.vue'; export default { - props: ['root', 'interaction'], - data: () => ({options: {}, zoom: 1, highlight: {'special': [[]]}}), + data: () => ({root: undefined, options: {}, zoom: 1, + interaction: {}, highlight: {'special': [[]]}}), computed: { jointHigh() { return {'interact-focus': this.interaction?.focused, ...this.highlight}; From 7478779b6093f1d9da2ab2fa72222839e8063f85 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Fri, 11 Jun 2021 13:01:10 +0300 Subject: [PATCH 23/90] [ui] Display list of benchmarks on startup. --- src/viz/ts/app.ts | 35 +++++++++++++----- src/viz/ts/benchmarks.ts | 10 +++--- src/viz/ts/main.ts | 24 ++++++++----- src/viz/vue/app-benchmark-list.vue | 11 ------ src/viz/vue/app.vue | 6 ++-- src/viz/vue/benchmark-list-pane.vue | 55 +++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 35 deletions(-) delete mode 100644 src/viz/vue/app-benchmark-list.vue create mode 100644 src/viz/vue/benchmark-list-pane.vue diff --git a/src/viz/ts/app.ts b/src/viz/ts/app.ts index 62048bdd1..b59decd87 100644 --- a/src/viz/ts/app.ts +++ b/src/viz/ts/app.ts @@ -4,17 +4,17 @@ import Vue from 'vue'; // @ts-ignore import app from '../vue/app.vue'; - +import { BenchmarksDB } from './benchmarks'; import { ProofTrace } from './proof-trace'; +import { ProofInteraction } from './proof-interaction'; class MainDocument extends EventEmitter { - container: JQuery - app: Vue pt: ProofTrace + pi: ProofInteraction notifications: JQuery props: any @@ -23,15 +23,18 @@ class MainDocument extends EventEmitter { constructor(container: JQuery, notifications: JQuery) { super(); - this.container = container; this.app = new Vue(app).$mount(); this.notifications = notifications; + + (this.app.$refs.benchmarks).$on('action', ev => { + this.emit('benchmarks:action', ev); + }); } get $el() { return this.app.$el; } new() { - return this.set(ProofTrace.Data.empty()); + return this.setProofTrace(ProofTrace.Data.empty()); } async open(content: string | File, opts: OpenOptions = {}): Promise { @@ -40,7 +43,7 @@ class MainDocument extends EventEmitter { } else { try { - return this.set(ProofTrace.Data.parse(content)); + return this.setProofTrace(ProofTrace.Data.parse(content)); } catch (e) { if (!opts.silent) { @@ -62,13 +65,29 @@ class MainDocument extends EventEmitter { return this.openUrl(this.storage['suslik:doc:lastUrl'] || DEFAULT_URL, opts); } - set(ptData: ProofTrace.Data) { - var pt = new ProofTrace(ptData, this.app.$refs.proofTrace as any); + setProofTrace(ptData: ProofTrace.Data) { + var pt = new ProofTrace(ptData, this.app.$refs.proofTrace as any), + pi = new ProofInteraction(pt); this.pt = pt; + this.pi = pi; + pi.on('trace', u => + this.pt.append(ProofTrace.Data.fromEntries([u]))); + this.emit('open', pt); return pt; } + setBenchmarks(bmData: BenchmarksDB.Data) { + var bm = this.app.$refs.benchmarks; + bm.data = bmData; + bm.show = true; + } + + hideBenchmarks() { + var bm = this.app.$refs.benchmarks; + bm.show = false; + } + async read(file: File) { return new TextDecoder().decode(await file.arrayBuffer()); } diff --git a/src/viz/ts/benchmarks.ts b/src/viz/ts/benchmarks.ts index 8285e8e32..b69b1f46e 100644 --- a/src/viz/ts/benchmarks.ts +++ b/src/viz/ts/benchmarks.ts @@ -1,10 +1,10 @@ class BenchmarksDB { - db: BenchmarksDB.Data + data: BenchmarksDB.Data - constructor(db: BenchmarksDB.Data) { - this.db = db; + constructor(data: BenchmarksDB.Data) { + this.data = data; } getSpec(dir: string, fn: string) { @@ -16,12 +16,12 @@ class BenchmarksDB { } getDefs(dir: string) { - return Object.entries(this.db[dir]) + return Object.entries(this.data[dir]) .map(([fn, txt]) => fn.endsWith('.def') && txt).filter(x => x); } getInputSpec(dir: string, fn: string) { - return this.db[dir][fn].match(/###([^]*?)###/)[1]; + return this.data[dir][fn].match(/###+([^]*?)###+/)[1]; } static async load(url = '/benchmarks.db.json') { diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index 7831cba9c..2b9423002 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -25,13 +25,16 @@ $(async () => { document.querySelector('#document-area').replaceWith(doc.$el); + const bench = await BenchmarksDB.load(); + doc.setBenchmarks(bench.data); + /* try { await doc.openRecent({silent: true}); } catch (e) { console.error('open failed:', e); } */ - doc.new(); + doc.new(); var drop = new DragDropJson($('html')); drop.on('open', async ({file}) => { @@ -41,16 +44,21 @@ $(async () => { catch (e) { console.error('open failed:', e); } }); + /* var pi = new ProofInteraction(doc.pt); pi.on('message', m => console.log('%cmessage', 'color: blue', m)); - pi.on('trace', u => { - var data = ProofTrace.Data.fromEntries([u]); - doc.pt.append(data); - }); pi.start(); + */ + + var spec = bench.getSpec('sll', 'free.syn'); - const bench = await BenchmarksDB.load(), - spec = bench.getSpec('sll', 'free.syn'); + doc.on('benchmarks:action', async ev => { + spec = bench.getSpec(ev.dir, ev.fn); + doc.hideBenchmarks(); + await doc.pi.start(); + doc.pi.ws.send(JSON.stringify(spec)); + Object.assign(window, {spec}); + }); - Object.assign(window, {doc, pi, bench, spec}); + Object.assign(window, {doc, bench, spec}); }); \ No newline at end of file diff --git a/src/viz/vue/app-benchmark-list.vue b/src/viz/vue/app-benchmark-list.vue deleted file mode 100644 index 9381cdb52..000000000 --- a/src/viz/vue/app-benchmark-list.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/src/viz/vue/app.vue b/src/viz/vue/app.vue index c84be370f..8e36346a8 100644 --- a/src/viz/vue/app.vue +++ b/src/viz/vue/app.vue @@ -1,15 +1,15 @@ \ No newline at end of file diff --git a/src/viz/vue/benchmark-list-pane.vue b/src/viz/vue/benchmark-list-pane.vue new file mode 100644 index 000000000..11d7a440f --- /dev/null +++ b/src/viz/vue/benchmark-list-pane.vue @@ -0,0 +1,55 @@ + + + + + From 7b5492e6d0bc9c915b45770e3e66ba73e49492e9 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Tue, 15 Jun 2021 19:39:47 +0300 Subject: [PATCH 24/90] [ui] Reload button. --- .../suslik/interaction/SynthesisServer.scala | 4 ++++ src/viz/ts/proof-trace.css | 2 +- src/viz/vue/app-toolbar.vue | 24 ++++++++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala index 6b1884b56..e9898b124 100644 --- a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -214,6 +214,10 @@ class ClientSessionSynthesis(implicit ec: ExecutionContext) extends AsyncSynthes val logger: Logger = org.slf4j.LoggerFactory.getLogger(getClass) + { + logger.info("client session started") + } + def subscribe: Source[String, _] = Source.unfoldAsync(())(_ => Future { try Some((), outbound.take()) diff --git a/src/viz/ts/proof-trace.css b/src/viz/ts/proof-trace.css index 7b4965dff..f1033e113 100644 --- a/src/viz/ts/proof-trace.css +++ b/src/viz/ts/proof-trace.css @@ -238,8 +238,8 @@ position: fixed; top: 0; left: 20em; + width: calc(100% - 20em); background: #ffffffd0; - padding: 1em 5em .75em 1em; z-index: 1; } diff --git a/src/viz/vue/app-toolbar.vue b/src/viz/vue/app-toolbar.vue index 2c4ff80ec..cb6c3cc00 100644 --- a/src/viz/vue/app-toolbar.vue +++ b/src/viz/vue/app-toolbar.vue @@ -1,5 +1,8 @@ + + From e06fd41625c5d40ec7ac9fd664df954bbd4c17c6 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Thu, 17 Jun 2021 19:07:03 +0300 Subject: [PATCH 25/90] [feature] Serialization additions. Serialize formula ASTs. Refactor the interaction protocol's client message format. --- .../suslik/interaction/SynthesisServer.scala | 49 +++++++++---- .../org/tygus/suslik/report/ProofTrace.scala | 71 +++++++++++++++++-- src/viz/ts/main.ts | 2 +- src/viz/ts/proof-interaction.ts | 34 +++++++-- src/viz/ts/proof-trace.ts | 10 ++- src/viz/vue/proof-trace-goal.vue | 4 +- 6 files changed, 143 insertions(+), 27 deletions(-) diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala index e9898b124..1c785be04 100644 --- a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -5,7 +5,6 @@ import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success} import org.slf4j.Logger import upickle.default.{macroRW, ReadWriter => RW} - import akka.{Done, NotUsed} import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors @@ -14,11 +13,12 @@ import akka.http.scaladsl.model.ws.{Message, TextMessage} import akka.http.scaladsl.server.Route import akka.http.scaladsl.server.Directives._ import akka.stream.scaladsl.{Flow, Keep, Sink, Source} - +import org.tygus.suslik.interaction.AsyncSynthesisRunner.ChooseMessage import org.tygus.suslik.language.Statements import org.tygus.suslik.logic.Environment import org.tygus.suslik.report.ProofTraceJson import org.tygus.suslik.report.ProofTraceJson.GoalEntry +import org.tygus.suslik.synthesis.SearchTree.{NodeId, OrNode} import org.tygus.suslik.synthesis.rules.Rules import org.tygus.suslik.synthesis.tactics.PhasedSynthesis import org.tygus.suslik.synthesis.{SynConfig, Synthesis, SynthesisRunnerUtil} @@ -100,6 +100,9 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { val inbound = new ArrayBlockingQueueWithCancel[String](1) val outbound = new ArrayBlockingQueueWithCancel[String](1) + val cached = new collection.mutable.HashMap[NodeId, OrNode]() + val logger: Logger = org.slf4j.LoggerFactory.getLogger(getClass) + def go(spec: SpecMessage): Unit = { new Thread(() => synthesizeFromSpec(spec, SynConfig())).start() } @@ -125,6 +128,8 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { } } val trace = new ProofTraceJson { + override def add(node: OrNode): Unit = + { cached.put(node.id, node); super.add(node) } override protected def writeObject[T](t: T)(implicit w: Writer[T]): Unit = outbound.put(write(t)) } @@ -153,7 +158,9 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { protected def wrapError[T](op: => T): T = { try op catch { - case e: Throwable => outbound.put(write(SynthesisErrorEntry(e.toString))); throw e + case e: Throwable => + logger.error("Error", e) + outbound.put(write(SynthesisErrorEntry(e.toString))); throw e } } @@ -199,10 +206,25 @@ object AsyncSynthesisRunner { implicit val rw: RW[SynthesisErrorEntry] = macroRW } - case class SpecMessage(name: String, defs: Seq[String], in: String) + /* Messages sent from the client */ + + sealed abstract class ClientMessage(tag: String) + object ClientMessage { implicit val rw: RW[ClientMessage] = macroRW } + + case class SpecMessage(name: String, defs: Seq[String], in: String) extends ClientMessage("Spec") object SpecMessage { implicit val rw: RW[SpecMessage] = macroRW } + + case class ExpandRequestMessage(id: NodeId) extends ClientMessage("ExpandRequest") + object ExpandRequestMessage { + implicit val rw: RW[ExpandRequestMessage] = macroRW + } + + case class ChooseMessage(choice: String) extends ClientMessage("Choose") + object ChooseMessage { + implicit val rw: RW[ChooseMessage] = macroRW + } } /** @@ -210,9 +232,7 @@ object AsyncSynthesisRunner { */ class ClientSessionSynthesis(implicit ec: ExecutionContext) extends AsyncSynthesisRunner { import upickle.default.read - import AsyncSynthesisRunner.SpecMessage - - val logger: Logger = org.slf4j.LoggerFactory.getLogger(getClass) + import AsyncSynthesisRunner._ { logger.info("client session started") @@ -225,13 +245,12 @@ class ClientSessionSynthesis(implicit ec: ExecutionContext) extends AsyncSynthes }) def offer: Sink[String, Future[Done]] = - Sink.foreachAsync[String](1)(s => Future { inbound.put(s) }) - - def initializeAnd[Mat](sink: Sink[String, Mat]): Sink[String, Mat] = - Flow[String].flatMapPrefix(1) { s => - wrapError { go(read[SpecMessage](s.head)) }; Flow[String] - } - .toMat(sink)(Keep.right) + Sink.foreachAsync[String](1) { s => Future { wrapError { + read[ClientMessage](s) match { + case sp@SpecMessage(_, _, _) => go(sp) + case ChooseMessage(choice) => inbound.put(choice) + } + }}} def done(d: Done): Unit = { outbound.cancel(); inbound.cancel() @@ -242,6 +261,6 @@ class ClientSessionSynthesis(implicit ec: ExecutionContext) extends AsyncSynthes Flow.fromSinkAndSource(Flow[Message].mapConcat { case m: TextMessage.Strict => List(m.text) case _ => logger.warn("received a non-text message"); Nil - }.to(initializeAnd(offer).mapMaterializedValue(m => m.foreach(done))), + }.to((offer).mapMaterializedValue(m => m.foreach(done))), subscribe.map(TextMessage(_))) } \ No newline at end of file diff --git a/src/main/scala/org/tygus/suslik/report/ProofTrace.scala b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala index 6ffd177b7..aa4ce1bd9 100644 --- a/src/main/scala/org/tygus/suslik/report/ProofTrace.scala +++ b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala @@ -2,6 +2,7 @@ package org.tygus.suslik.report import java.io.{BufferedWriter, File, FileWriter} import org.tygus.suslik.language.Expressions +import org.tygus.suslik.logic.{Block, Heaplet, PointsTo, SApp, Specifications} import org.tygus.suslik.logic.Specifications.Goal import org.tygus.suslik.synthesis.Memoization import org.tygus.suslik.synthesis.Memoization.GoalStatus @@ -108,8 +109,8 @@ object ProofTraceJson { } case class GoalEntry(id: GoalEntry.Id, - pre: String, - post: String, + pre: AssertionEntry, + post: AssertionEntry, sketch: String, programVars: Seq[(String, String)], existentials: Seq[(String, String)], @@ -118,8 +119,8 @@ object ProofTraceJson { type Id = String implicit val rw: RW[GoalEntry] = macroRW - def apply(goal: Goal): GoalEntry = GoalEntry(goal.label.pp, - goal.pre.pp, goal.post.pp, goal.sketch.pp, + def apply(goal: Goal): GoalEntry = apply(goal.label.pp, + AssertionEntry(goal.pre), AssertionEntry(goal.post), goal.sketch.pp, vars(goal, goal.programVars), vars(goal, goal.existentials), vars(goal, goal.universalGhosts)) @@ -127,6 +128,16 @@ object ProofTraceJson { vs.map(v => (goal.getType(v).pp, v.pp)).toSeq } + case class AssertionEntry(pp: String, phi: Seq[AST], sigma: Seq[AST]) + object AssertionEntry { + implicit val rw: RW[AssertionEntry] = macroRW + + def apply(a: Specifications.Assertion): AssertionEntry = + apply(a.pp, + a.phi.conjuncts.toSeq.map(AST.fromExpr), + a.sigma.chunks.map(AST.fromHeaplet)) + } + case class GoalStatusEntry(tag: String, from: Option[String] = None) val Succeeded = new GoalStatusEntry("Succeeded") val Failed = new GoalStatusEntry("Failed") @@ -165,6 +176,58 @@ object ProofTraceJson { object DerivationTrailEntry { implicit val rw: RW[DerivationTrailEntry] = macroRW } + + + case class AST(root: String, subtrees: Seq[AST]) { + def -:(root: String): AST = AST(root, Seq(this)) + def :/(sub: Seq[AST]): AST = AST(root, subtrees ++ sub) + + import Expressions._ + import AST._ + + def toExpr: Expr = (root, subtrees) match { + case ("Var", Seq(Leaf(v))) => Var(v) + case ("IntConst", Seq(Leaf(v))) => IntConst(Integer.parseInt(v)) + case ("BoolConst", Seq(Leaf(v))) => BoolConst(v == "true") + case _ => throw new RuntimeException(s"error in expression: '${this}'") + } + } + + object AST { + implicit val rw: RW[AST] = macroRW + + def apply(root: String): AST = apply(root, Seq()) + def apply(root: AnyVal): AST = apply(root.toString) + + import Expressions._ + + def fromExpr(e: Expr): AST = e match { + case Var(name) => "Var" -: AST(name) + case IntConst(_) => "IntConst" -: AST(e.pp) + case BoolConst(_) => "BoolConst" -: AST(e.pp) + case UnaryExpr(op, arg) => op.pp -: fromExpr(arg) + case BinaryExpr(op, left, right) => AST(op.pp, Seq(left, right).map(fromExpr)) + case SetLiteral(elems) => AST("{}", elems.map(fromExpr)) + case IfThenElse(cond, left, right) => AST("ite", Seq(cond, left, right).map(fromExpr)) + case Unknown(name, params, pendingSubst) => + AST("Unknown", AST(name) +: params.toSeq.map(fromExpr) :+ fromSubst(pendingSubst)) + } + + def fromSubst(subst: Subst): AST = + AST("{}") :/ + subst.toSeq.map { case (v, e) => AST("↦", Seq(v, e).map(fromExpr)) } + + def fromHeaplet(heaplet: Heaplet): AST = heaplet match { + case PointsTo(loc, offset, value) => AST("↦", Seq(fromExpr(loc), AST(offset), fromExpr(value))) + case Block(loc, sz) => AST("[]", Seq(fromExpr(loc), AST(sz))) + case SApp(pred, args, tag, card) => AST("SApp", AST(pred) +: args.map(fromExpr)) + } + + object Leaf { + def unapply(t: AST): Option[String] = + if (t.subtrees.isEmpty) Some(t.root) else None + } + } } // [Certify] Collects non-backtracked SearchTree nodes (and their ancestors), used to populate the CertTree diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index 2b9423002..e3016cae6 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -56,7 +56,7 @@ $(async () => { spec = bench.getSpec(ev.dir, ev.fn); doc.hideBenchmarks(); await doc.pi.start(); - doc.pi.ws.send(JSON.stringify(spec)); + doc.pi.sendSpec(spec); Object.assign(window, {spec}); }); diff --git a/src/viz/ts/proof-interaction.ts b/src/viz/ts/proof-interaction.ts index 1fb1280e8..6d5215f1f 100644 --- a/src/viz/ts/proof-interaction.ts +++ b/src/viz/ts/proof-interaction.ts @@ -9,7 +9,7 @@ class ProofInteraction extends EventEmitter { ws: WebSocket pt: ProofTrace - view: Vue & ProofInteraction.View.Props + view: Vue & View.Props constructor(pt: ProofTrace) { super(); @@ -28,11 +28,19 @@ class ProofInteraction extends EventEmitter { this.ws.addEventListener('error', reject) }); } - + + sendSpec(spec: Data.Spec) { + this._send(spec, ProofInteraction.Data.Classes.SPEC); + } + continue(choice: string) { - this.ws.send(choice); + this._send({choice}, ProofInteraction.Data.Classes.CHOOSE); } + _send(json: any, $type?: string) { + this.ws.send(JSON.stringify($type ? {$type, ...json} : json)) + } + handleMessage(data: string) { try { var msg = JSON.parse(data); @@ -51,7 +59,7 @@ class ProofInteraction extends EventEmitter { else this.emit('trace', msg); } - handleAction(action: ProofInteraction.View.Action) { + handleAction(action: View.Action) { switch (action.type) { case 'select': this.view.interaction.choices = undefined; // clear choices @@ -79,8 +87,26 @@ class ProofInteraction extends EventEmitter { } +import Data = ProofInteraction.Data; +import View = ProofInteraction.View; + + namespace ProofInteraction { + export namespace Data { + + export enum Classes { + SPEC = "org.tygus.suslik.interaction.AsyncSynthesisRunner.SpecMessage", + CHOOSE = "org.tygus.suslik.interaction.AsyncSynthesisRunner.ChooseMessage" + } + + export type Spec = { + name?: string + defs: string[] + in: string + } + } + export namespace View { export type Props = { diff --git a/src/viz/ts/proof-trace.ts b/src/viz/ts/proof-trace.ts index d4bd62ed8..65ffb1dba 100644 --- a/src/viz/ts/proof-trace.ts +++ b/src/viz/ts/proof-trace.ts @@ -320,7 +320,7 @@ namespace ProofTrace { export type GoalEntry = { id: GoalId - pre: string, post: string, sketch: string, + pre: AssertionEntry, post: AssertionEntry, sketch: string, programVars: [string, string][] existentials: [string, string][] ghosts: [string, string][] @@ -328,6 +328,14 @@ namespace ProofTrace { export type GoalId = string + export type AssertionEntry = { + pp: String, + phi: AST[], + sigma: AST[] + }; + + export type AST = any /** @todo */ + export type Environment = Map; export type StatusEntry = { diff --git a/src/viz/vue/proof-trace-goal.vue b/src/viz/vue/proof-trace-goal.vue index fc6cd1a76..8a2b82c07 100644 --- a/src/viz/vue/proof-trace-goal.vue +++ b/src/viz/vue/proof-trace-goal.vue @@ -2,9 +2,9 @@
- + - +
From f3703f251d2f501dd7cd6ce9f9a692e517c57fd7 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Thu, 17 Jun 2021 22:33:31 +0300 Subject: [PATCH 26/90] [feature] Arbitary interactive expansion thingamabob. The protocol functionality is still there, but UI interaction is TBD. --- .../suslik/interaction/SynthesisServer.scala | 43 +++++++++++++++++-- .../scala/org/tygus/suslik/report/Log.scala | 14 +++--- .../tygus/suslik/synthesis/Synthesis.scala | 32 ++++++++------ src/viz/ts/main.ts | 31 +++++++------ src/viz/ts/proof-interaction.ts | 22 +++++++--- 5 files changed, 97 insertions(+), 45 deletions(-) diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala index 1c785be04..2a393172b 100644 --- a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -16,12 +16,14 @@ import akka.stream.scaladsl.{Flow, Keep, Sink, Source} import org.tygus.suslik.interaction.AsyncSynthesisRunner.ChooseMessage import org.tygus.suslik.language.Statements import org.tygus.suslik.logic.Environment -import org.tygus.suslik.report.ProofTraceJson +import org.tygus.suslik.report.{Log, ProofTrace, ProofTraceJson} import org.tygus.suslik.report.ProofTraceJson.GoalEntry -import org.tygus.suslik.synthesis.SearchTree.{NodeId, OrNode} +import org.tygus.suslik.synthesis.SearchTree.{AndNode, NodeId, OrNode} +import org.tygus.suslik.synthesis.Termination.isTerminatingExpansion import org.tygus.suslik.synthesis.rules.Rules -import org.tygus.suslik.synthesis.tactics.PhasedSynthesis +import org.tygus.suslik.synthesis.tactics.{PhasedSynthesis, Tactic} import org.tygus.suslik.synthesis.{SynConfig, Synthesis, SynthesisRunnerUtil} +import org.tygus.suslik.util.SynStats class SynthesisServer { @@ -103,6 +105,8 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { val cached = new collection.mutable.HashMap[NodeId, OrNode]() val logger: Logger = org.slf4j.LoggerFactory.getLogger(getClass) + protected var isynth: IterativeUnorderedSynthesis = null + def go(spec: SpecMessage): Unit = { new Thread(() => synthesizeFromSpec(spec, SynConfig())).start() } @@ -133,6 +137,9 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { override protected def writeObject[T](t: T)(implicit w: Writer[T]): Unit = outbound.put(write(t)) } + val stats = new SynStats(2500) + val config = SynConfig() + isynth = new IterativeUnorderedSynthesis(new PhasedSynthesis(env.config), log, trace)(stats, config) new Synthesis(tactic, log, trace) } @@ -156,6 +163,9 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { synthesizeFromSpec(spec.name, (spec.defs :+ spec.in).mkString("\n"), noOutputCheck, params) + def grow(id: NodeId): Unit = + cached.get(id).foreach(isynth.grow) + protected def wrapError[T](op: => T): T = { try op catch { case e: Throwable => @@ -181,6 +191,30 @@ object AsyncSynthesisRunner { def cancel() { waiting foreach (_.interrupt()) } } + class IterativeUnorderedSynthesis(tactic: Tactic, log: Log, trace: ProofTrace) + (implicit stats: SynStats, config: SynConfig) + extends Synthesis(tactic, log, trace) { + + def grow(node: OrNode): Unit = { + val goal = node.goal + implicit val log: Log = this.log + implicit val ctx: Log.Context = Log.Context(goal) + + for { + (e, i) <- expansionsForNode(node).zipWithIndex + andNode = AndNode(i +: node.id, node, e) + if isTerminatingExpansion(andNode) // termination check + } { + trace.add(andNode, andNode.nChildren) + for (_ <- 1 to andNode.nChildren) trace.add(andNode.nextChild) + } + } + + protected def submitNodes(nodes: Seq[OrNode]): Unit = { + for (node <- nodes) trace.add(node) + } + } + type GoalLabel = String case class ExpansionChoiceEntry(from: Set[GoalLabel], @@ -249,6 +283,7 @@ class ClientSessionSynthesis(implicit ec: ExecutionContext) extends AsyncSynthes read[ClientMessage](s) match { case sp@SpecMessage(_, _, _) => go(sp) case ChooseMessage(choice) => inbound.put(choice) + case ExpandRequestMessage(id) => grow(id) } }}} @@ -261,6 +296,6 @@ class ClientSessionSynthesis(implicit ec: ExecutionContext) extends AsyncSynthes Flow.fromSinkAndSource(Flow[Message].mapConcat { case m: TextMessage.Strict => List(m.text) case _ => logger.warn("received a non-text message"); Nil - }.to((offer).mapMaterializedValue(m => m.foreach(done))), + }.to(offer.mapMaterializedValue(m => m.foreach(done))), subscribe.map(TextMessage(_))) } \ No newline at end of file diff --git a/src/main/scala/org/tygus/suslik/report/Log.scala b/src/main/scala/org/tygus/suslik/report/Log.scala index 73e253297..da7d01659 100644 --- a/src/main/scala/org/tygus/suslik/report/Log.scala +++ b/src/main/scala/org/tygus/suslik/report/Log.scala @@ -8,12 +8,7 @@ import org.tygus.suslik.util.SynLogging import scala.Console.{GREEN, MAGENTA, RESET} class Log(val out: SynLogging) { - - case class Context(goal: Option[Goal] = None) - - object Context{ - def apply(goal: Goal): Context = Context(Some(goal)) - } + import Log.Context def showChildren(goal: Goal)(c: RuleResult): String = { def showFootprint(f: Footprint): String = s"$GREEN${f.pre.pp}$MAGENTA${f.post.pp}$RESET" @@ -40,6 +35,13 @@ class Log(val out: SynLogging) { out.print(s"$RESET") } } +} + +object Log { + case class Context(goal: Option[Goal] = None) + object Context { + def apply(goal: Goal): Context = Context(Some(goal)) + } } diff --git a/src/main/scala/org/tygus/suslik/synthesis/Synthesis.scala b/src/main/scala/org/tygus/suslik/synthesis/Synthesis.scala index faf3299d6..2cbd18e72 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/Synthesis.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/Synthesis.scala @@ -87,7 +87,7 @@ class Synthesis(tactic: Tactic, implicit val log: Log, implicit val trace: Proof else { val (node, addNewNodes) = popNode // Select next node to expand val goal = node.goal - implicit val ctx: log.Context = log.Context(goal) + implicit val ctx: Log.Context = Log.Context(goal) stats.addExpandedGoal(node) log.print(s"Expand: ${node.pp()}[${node.cost}]", Console.YELLOW) // log.print(s"${goal.pp}", Console.BLUE) @@ -159,13 +159,9 @@ class Synthesis(tactic: Tactic, implicit val log: Log, implicit val trace: Proof config: SynConfig): Option[Solution] = { val goal = node.goal memo.save(goal, Expanded) - implicit val ctx = log.Context(goal) + implicit val ctx: Log.Context = Log.Context(goal) - // Apply all possible rules to the current goal to get a list of alternative expansions, - // each of which can have multiple open subgoals - val rules = tactic.nextRules(node) - val allExpansions = applyRules(rules)(node, stats, config, ctx) - val expansions = tactic.filterExpansions(allExpansions) + val expansions = expansionsForNode(node) // Check if any of the expansions is a terminal expansions.find(_.subgoals.isEmpty) match { @@ -173,14 +169,13 @@ class Synthesis(tactic: Tactic, implicit val log: Log, implicit val trace: Proof trace.add(e, node) successLeaves = node :: successLeaves node.succeed(e.producer(Nil)) match { - case Left(sibling) => { + case Left(sibling) => // This node had a suspended and-sibling: add to the worklist worklist = addNewNodes(List(sibling)) None - } case Right(sol) => Some(sol) // This node had no more and-siblings: return solution } - case None => { // no terminals: add all expansions to worklist + case None => // no terminals: add all expansions to worklist // Create new nodes from the expansions val newNodes = for { (e, i) <- expansions.zipWithIndex @@ -201,15 +196,28 @@ class Synthesis(tactic: Tactic, implicit val log: Log, implicit val trace: Proof stats.addGeneratedGoals(newNodes.size) } None - } } } + protected def allExpansionsForNode(node: OrNode)(implicit stats: SynStats, + config: SynConfig): Seq[RuleResult] = { + val goal = node.goal + implicit val ctx: Log.Context = Log.Context(goal) + + // Apply all possible rules to the current goal to get a list of alternative expansions, + // each of which can have multiple open subgoals + val rules = tactic.nextRules(node) + applyRules(rules)(node, stats, config, ctx) + } + + protected def expansionsForNode(node: OrNode)(implicit stats: SynStats, + config: SynConfig): Seq[RuleResult] = + tactic.filterExpansions(allExpansionsForNode(node)) protected def applyRules(rules: List[SynthesisRule])(implicit node: OrNode, stats: SynStats, config: SynConfig, - ctx: log.Context): Seq[RuleResult] = { + ctx: Log.Context): Seq[RuleResult] = { implicit val goal: Goal = node.goal rules match { case Nil => Vector() // No more rules to apply: done expanding the goal diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index e3016cae6..29e4d7a85 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -28,6 +28,15 @@ $(async () => { const bench = await BenchmarksDB.load(); doc.setBenchmarks(bench.data); + async function startBenchmark(w: {dir: string, fn: string}) { + var spec = bench.getSpec(w.dir, w.fn); + doc.hideBenchmarks(); + await doc.pi.start(spec); + Object.assign(window, {spec}); + } + + doc.on('benchmarks:action', startBenchmark); + /* try { await doc.openRecent({silent: true}); @@ -44,21 +53,11 @@ $(async () => { catch (e) { console.error('open failed:', e); } }); - /* - var pi = new ProofInteraction(doc.pt); - pi.on('message', m => console.log('%cmessage', 'color: blue', m)); - pi.start(); - */ - - var spec = bench.getSpec('sll', 'free.syn'); - - doc.on('benchmarks:action', async ev => { - spec = bench.getSpec(ev.dir, ev.fn); - doc.hideBenchmarks(); - await doc.pi.start(); - doc.pi.sendSpec(spec); - Object.assign(window, {spec}); - }); + /* Start a benchmark on load if instructed so by local config */ + var openOnStart = localStorage['openOnStart'] + if (openOnStart) { + startBenchmark(JSON.parse(openOnStart)); + } - Object.assign(window, {doc, bench, spec}); + Object.assign(window, {doc, bench}); }); \ No newline at end of file diff --git a/src/viz/ts/proof-interaction.ts b/src/viz/ts/proof-interaction.ts index 6d5215f1f..7d96cc315 100644 --- a/src/viz/ts/proof-interaction.ts +++ b/src/viz/ts/proof-interaction.ts @@ -20,23 +20,28 @@ class ProofInteraction extends EventEmitter { this.view.$on('interaction:action', action => this.handleAction(action)); } - start() { + async start(spec?: Data.Spec) { this.ws = new WebSocket(`ws://${this.baseURL.host}${this.baseURL.pathname}`); this.ws.addEventListener('message', m => this.handleMessage(m.data)); - return new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { this.ws.addEventListener('open', resolve); this.ws.addEventListener('error', reject) }); + if (spec) this.sendSpec(spec); } sendSpec(spec: Data.Spec) { this._send(spec, ProofInteraction.Data.Classes.SPEC); } - continue(choice: string) { + sendChoose(choice: string) { this._send({choice}, ProofInteraction.Data.Classes.CHOOSE); } + sendExpandRequest(nodeId: ProofTrace.Data.NodeId) { + this._send({id: nodeId}, ProofInteraction.Data.Classes.EXPAND_REQUEST); + } + _send(json: any, $type?: string) { this.ws.send(JSON.stringify($type ? {$type, ...json} : json)) } @@ -63,7 +68,7 @@ class ProofInteraction extends EventEmitter { switch (action.type) { case 'select': this.view.interaction.choices = undefined; // clear choices - this.continue(action.goal.id); + this.sendChoose(action.goal.id); break; } } @@ -95,9 +100,12 @@ namespace ProofInteraction { export namespace Data { - export enum Classes { - SPEC = "org.tygus.suslik.interaction.AsyncSynthesisRunner.SpecMessage", - CHOOSE = "org.tygus.suslik.interaction.AsyncSynthesisRunner.ChooseMessage" + export namespace Classes { + const NS = "org.tygus.suslik.interaction.AsyncSynthesisRunner"; + + export const SPEC = `${NS}.SpecMessage`, + CHOOSE = `${NS}.ChooseMessage`, + EXPAND_REQUEST = `${NS}.ExpandRequestMessage`; } export type Spec = { From d883d88db1e26b019fb7b5d5eb3998c20de26466 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Sat, 19 Jun 2021 15:34:15 +0300 Subject: [PATCH 27/90] [ui] Show spec in editor. --- package-lock.json | 741 +++++++++++++++--- package.json | 4 +- .../suslik/interaction/SynthesisServer.scala | 7 +- .../tygus/suslik/synthesis/Termination.scala | 4 +- src/viz/ts/app.ts | 8 +- src/viz/ts/ide.css | 25 + src/viz/ts/main.ts | 4 +- src/viz/ts/proof-trace.css | 6 +- src/viz/vue/app-toolbar.vue | 3 + src/viz/vue/app.vue | 28 +- src/viz/vue/benchmark-list-pane.vue | 10 +- src/viz/vue/editor-pane.vue | 38 + src/viz/vue/proof-trace-pane.vue | 2 +- 13 files changed, 757 insertions(+), 123 deletions(-) create mode 100644 src/viz/ts/ide.css create mode 100644 src/viz/vue/editor-pane.vue diff --git a/package-lock.json b/package-lock.json index 25b879341..30470bef7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,11 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@codemirror/basic-setup": "^0.18.2", "array-equal": "^1.0.0", "find": "^0.3.0", "jquery": "^3.5.0", + "split.js": "^1.6.4", "vue": "^2.6.13", "vue-context": "^5.2.0" }, @@ -19,7 +21,7 @@ "@types/jquery": "^3.3.34", "@types/node": "^13.11.1", "@vue/component-compiler-utils": "^3.2.0", - "cssnano": "^5.0.5", + "cssnano": "^5.0.6", "nw-vue-devtools-prebuilt": "^0.0.10", "typescript": "^4.3.2", "vue-hot-reload-api": "^2.3.4", @@ -27,29 +29,261 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "dev": true, "dependencies": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", - "dev": true + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.14.0", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@codemirror/autocomplete": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-0.18.7.tgz", + "integrity": "sha512-4x6xH2jDuJzweB0Wdx3VQrFUvZF0V7RAHoomQOCq3NxUOZd/UXcSXrj3LXItFAxi6K4OlTLayFuI3z4k3UKUQQ==", + "dependencies": { + "@codemirror/language": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/tooltip": "^0.18.4", + "@codemirror/view": "^0.18.0", + "lezer-tree": "^0.13.0" + } + }, + "node_modules/@codemirror/basic-setup": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@codemirror/basic-setup/-/basic-setup-0.18.2.tgz", + "integrity": "sha512-4UNFQ4jhU7wKxJH23AJcZW6Ho54VXUpmbtFnN5amIdtGci4ZLvci4M7JKgKFraHmKfDIYQnSzN8d8ohXR7CRhw==", + "dependencies": { + "@codemirror/autocomplete": "^0.18.0", + "@codemirror/closebrackets": "^0.18.0", + "@codemirror/commands": "^0.18.0", + "@codemirror/comment": "^0.18.0", + "@codemirror/fold": "^0.18.0", + "@codemirror/gutter": "^0.18.3", + "@codemirror/highlight": "^0.18.0", + "@codemirror/history": "^0.18.0", + "@codemirror/language": "^0.18.0", + "@codemirror/lint": "^0.18.0", + "@codemirror/matchbrackets": "^0.18.0", + "@codemirror/rectangular-selection": "^0.18.0", + "@codemirror/search": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "node_modules/@codemirror/closebrackets": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@codemirror/closebrackets/-/closebrackets-0.18.0.tgz", + "integrity": "sha512-O1RAgUkzF4nq/B8IyXenZKZ1rJi2Mc7I6y4IhWhELiTnjyQy7YdAthTsJ40mNr8kZ6gRbasYe3K7TraITElZJA==", + "dependencies": { + "@codemirror/language": "^0.18.0", + "@codemirror/rangeset": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "0.18.3", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-0.18.3.tgz", + "integrity": "sha512-nHYDG13qOirioXTAKmjl10W2L0eZ1ftvmTwvUTNY27UWVBPFSpk5zDXP3WqJ0mgMhQ4AOFLJaTjJEO3hmPComg==", + "dependencies": { + "@codemirror/language": "^0.18.0", + "@codemirror/matchbrackets": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0", + "lezer-tree": "^0.13.0" + } + }, + "node_modules/@codemirror/comment": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@codemirror/comment/-/comment-0.18.1.tgz", + "integrity": "sha512-Inhqs0F24WE28Fcp1dBZghwixBGv1HDwY9MjE0d5tpMY/IPGI6uT30fGyHAXrir6hUqk7eJRkO4UYnODGOnoIA==", + "dependencies": { + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "node_modules/@codemirror/fold": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@codemirror/fold/-/fold-0.18.1.tgz", + "integrity": "sha512-vvMUgDeSmeVow7/75YoNTERxPsdnIBeEw1JL2YVpLyscsUlalqwuxdhiHDLT5zjAu6JvMoTC103mwqgAYwM9tA==", + "dependencies": { + "@codemirror/gutter": "^0.18.0", + "@codemirror/language": "^0.18.0", + "@codemirror/rangeset": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "node_modules/@codemirror/gutter": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/gutter/-/gutter-0.18.4.tgz", + "integrity": "sha512-Sf2IWshMi9zwVVqpGmd2NRplY0qfrE2IiBEII9n2gB9M8hgIMg5GCyhdnsUDsOm0gcSut65W62vV7/DfYJHQCA==", + "dependencies": { + "@codemirror/rangeset": "^0.18.3", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "node_modules/@codemirror/highlight": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/highlight/-/highlight-0.18.4.tgz", + "integrity": "sha512-3azJntqWrShOIq/0kVcdMc9k7ACL0LQErgK+A6aWXmCj5Mx0gShq+Iajy8AMQ2zB0v3nhCBgFaniL1LLD5m5hQ==", + "dependencies": { + "@codemirror/language": "^0.18.0", + "@codemirror/rangeset": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0", + "lezer-tree": "^0.13.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/history": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@codemirror/history/-/history-0.18.1.tgz", + "integrity": "sha512-Aad3p4zs6UYKCUMXYjh7cvPK0ajuL+rMib9yBZ61w81LLl6OkM31Xrn9J6CLJmPxCwP3OJFiqBmNSBQ05oIsTw==", + "dependencies": { + "@codemirror/state": "^0.18.3", + "@codemirror/view": "^0.18.0" + } + }, + "node_modules/@codemirror/language": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.18.2.tgz", + "integrity": "sha512-2Kz0Xyfvt1Ex2KfTUcYZ3IBxpnFCqHaJijwZknGBT7JXv9dwbOPs9SfPfL4oxVuDIHZx8JTPfoV3LTTJrm8M3Q==", + "dependencies": { + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0", + "lezer": "^0.13.4", + "lezer-tree": "^0.13.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-0.18.4.tgz", + "integrity": "sha512-H77qYfZOmo1kKf0ZQagzk/JRGVhIpwP0hq1TSO6DFC1WLjW6gcsFJO5NDMS86enm0KX0w4/IkA7PItz2mjmHhQ==", + "dependencies": { + "@codemirror/panel": "^0.18.1", + "@codemirror/state": "^0.18.0", + "@codemirror/tooltip": "^0.18.4", + "@codemirror/view": "^0.18.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/matchbrackets": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@codemirror/matchbrackets/-/matchbrackets-0.18.0.tgz", + "integrity": "sha512-dPDopnZVkD54sSYdmQbyQbPdiuIA83p7XxX6Hp1ScEkOjukwCiFXiA/84x10FUTsQpUYp8bDzm7gwII119bGIw==", + "dependencies": { + "@codemirror/language": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0", + "lezer-tree": "^0.13.0" + } + }, + "node_modules/@codemirror/panel": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@codemirror/panel/-/panel-0.18.2.tgz", + "integrity": "sha512-ea/g2aAKtfmie1kD7C8GDutD/5u+uzRJr/varUiAbHKr1sAdjtz5xYvC3GBAMYMan1GOh0vD5zP1yEupJl3b3Q==", + "dependencies": { + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "node_modules/@codemirror/rangeset": { + "version": "0.18.3", + "resolved": "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.18.3.tgz", + "integrity": "sha512-p6bPVr6Cw0yh/QSelsg0RoNaG4btuzZo7YMT+WFwZsjbr7+X0dVpd2vqLAHIeDUfvOzrEI/dXXPKLpZZgYeU+g==", + "dependencies": { + "@codemirror/state": "^0.18.0" + } + }, + "node_modules/@codemirror/rectangular-selection": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@codemirror/rectangular-selection/-/rectangular-selection-0.18.0.tgz", + "integrity": "sha512-BQ4pp2zhXCVZNqct5LtLR3AOWVseENBF/3oOgBmwsCKH7c11NfTqIqgWG5EW8NLOXp8HP8cDm3np8eWez0VkGQ==", + "dependencies": { + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "node_modules/@codemirror/search": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-0.18.4.tgz", + "integrity": "sha512-3chVkMPzl+pTUSqtimTicebhti4SLpvkj03pQx2aPZScXxIiYuDk4cLdIJK9omjmO1+oycRKbOrqvG7iZJJwMg==", + "dependencies": { + "@codemirror/panel": "^0.18.1", + "@codemirror/rangeset": "^0.18.0", + "@codemirror/state": "^0.18.6", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.18.7.tgz", + "integrity": "sha512-cVyTiAC9vv90NKmGOfNtBjyIem3BqKui1L5Hfcxurp8K9votQj2oH9COcgWPnQ2Xs64yC70tEuTt9DF1pj5PFQ==", + "dependencies": { + "@codemirror/text": "^0.18.0" + } + }, + "node_modules/@codemirror/text": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@codemirror/text/-/text-0.18.0.tgz", + "integrity": "sha512-HMzHNIAbjCiCf3tEJMRg6ul01KPuXxQGNiHlHgAnqPguq/CX+L4Nvj5JlWQAI91Pupk18zhmM1c6eaazX4YeTg==" + }, + "node_modules/@codemirror/tooltip": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/tooltip/-/tooltip-0.18.4.tgz", + "integrity": "sha512-LDlDOSEfjoG24uapLN7exK3Z3JchYFKUwWqo1x/9YdlAkmD1ik7cMSQZboCquP1uJVcXhtbpKmaO6vENGVaarg==", + "dependencies": { + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "node_modules/@codemirror/view": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.18.17.tgz", + "integrity": "sha512-AneqrYFgQJFZY5CdIRvllaLWL7r966JZK64d05PrScYhhRT6y5iiq0VBO9nxX5Y2gbTXBdO1/eZdtJlhwa6hww==", + "dependencies": { + "@codemirror/rangeset": "^0.18.2", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" } }, "node_modules/@trysound/sax": { @@ -89,17 +323,16 @@ "dev": true }, "node_modules/@vue/component-compiler-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.2.0.tgz", - "integrity": "sha512-lejBLa7xAMsfiZfNp7Kv51zOzifnb29FwdnMLa96z26kXErPFioSf9BMcePVIQ6/Gc6/mC0UrPpxAWIHyae0vw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.2.2.tgz", + "integrity": "sha512-rAYMLmgMuqJFWAOb3Awjqqv5X3Q3hVr4jH/kgrFJpiU0j3a90tnNBplqbj+snzrgZhC9W128z+dtgMifOiMfJg==", "dev": true, - "license": "MIT", "dependencies": { "consolidate": "^0.15.1", "hash-sum": "^1.0.2", "lru-cache": "^4.1.2", "merge-source-map": "^1.1.0", - "postcss": "^7.0.14", + "postcss": "^7.0.36", "postcss-selector-parser": "^6.0.2", "source-map": "~0.6.1", "vue-template-es2015-compiler": "^1.9.0" @@ -109,9 +342,9 @@ } }, "node_modules/@vue/component-compiler-utils/node_modules/postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "dependencies": { "chalk": "^2.4.2", @@ -227,9 +460,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001234", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001234.tgz", - "integrity": "sha512-a3gjUVKkmwLdNysa1xkUAwN2VfJUJyVW47rsi3aCbkRCtbHAfo+rOsCqVw29G6coQ8gzAPb5XBXwiGHwme3isA==", + "version": "1.0.30001237", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001237.tgz", + "integrity": "sha512-pDHgRndit6p1NR2GhzMbQ6CkRrp4VKuSsqbcLeOQppYPKOYkKT/6ZvZDvKJUqcmtyWIAHuZq3SVS2vc1egCZzw==", "dev": true, "funding": { "type": "opencollective", @@ -341,6 +574,11 @@ "node": ">=0.10.0" } }, + "node_modules/crelt": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", + "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==" + }, "node_modules/css-color-names": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-1.0.1.tgz", @@ -419,13 +657,13 @@ } }, "node_modules/cssnano": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.5.tgz", - "integrity": "sha512-L2VtPXnq6rmcMC9vkBOP131sZu3ccRQI27ejKZdmQiPDpUlFkUbpXHgKN+cibeO1U4PItxVZp1zTIn5dHsXoyg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.6.tgz", + "integrity": "sha512-NiaLH/7yqGksFGsFNvSRe2IV/qmEBAeDE64dYeD8OBrgp6lE8YoMeQJMtsv5ijo6MPyhuoOvFhI94reahBRDkw==", "dev": true, "dependencies": { "cosmiconfig": "^7.0.0", - "cssnano-preset-default": "^5.1.2", + "cssnano-preset-default": "^5.1.3", "is-resolvable": "^1.1.0" }, "engines": { @@ -440,9 +678,9 @@ } }, "node_modules/cssnano-preset-default": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.2.tgz", - "integrity": "sha512-spilp8LRw0sacuxiN9A/dyyPr6G/WISKMBKcBD4NMoPV0ENx4DeuWvIIrSx9PII2nJIDCO3kywkqTPreECBVOg==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.3.tgz", + "integrity": "sha512-qo9tX+t4yAAZ/yagVV3b+QBKeLklQbmgR3wI7mccrDcR+bEk9iHgZN1E7doX68y9ThznLya3RDmR+nc7l6/2WQ==", "dev": true, "dependencies": { "css-declaration-sorter": "^6.0.3", @@ -467,9 +705,9 @@ "postcss-normalize-string": "^5.0.1", "postcss-normalize-timing-functions": "^5.0.1", "postcss-normalize-unicode": "^5.0.1", - "postcss-normalize-url": "^5.0.1", + "postcss-normalize-url": "^5.0.2", "postcss-normalize-whitespace": "^5.0.1", - "postcss-ordered-values": "^5.0.1", + "postcss-ordered-values": "^5.0.2", "postcss-reduce-initial": "^5.0.1", "postcss-reduce-transforms": "^5.0.1", "postcss-svgo": "^5.0.2", @@ -554,9 +792,9 @@ } }, "node_modules/domutils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.6.0.tgz", - "integrity": "sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", "dev": true, "dependencies": { "dom-serializer": "^1.0.1", @@ -589,9 +827,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.3.748", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.748.tgz", - "integrity": "sha512-fmIKfYALVeEybk/L2ucdgt7jN3JsbGtg3K9pmF/MRWgkeADBI1VSAa5IzdG2gZwTxsnsrFtdMpOTSM5mrBRKVQ==", + "version": "1.3.752", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.752.tgz", + "integrity": "sha512-2Tg+7jSl3oPxgsBsWKh5H83QazTkmWG/cnNwJplmyZc7KcN61+I10oUgaXSVk/NwfvN3BdkKDR4FYuRBQQ2v0A==", "dev": true }, "node_modules/entities": { @@ -844,6 +1082,19 @@ "set-immediate-shim": "~1.0.1" } }, + "node_modules/lezer": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/lezer/-/lezer-0.13.5.tgz", + "integrity": "sha512-cAiMQZGUo2BD8mpcz7Nv1TlKzWP7YIdIRrX41CiP5bk5t4GHxskOxWUx2iAOuHlz8dO+ivbuXr0J1bfHsWD+lQ==", + "dependencies": { + "lezer-tree": "^0.13.2" + } + }, + "node_modules/lezer-tree": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/lezer-tree/-/lezer-tree-0.13.2.tgz", + "integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ==" + }, "node_modules/lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -954,18 +1205,21 @@ } }, "node_modules/node-releases": { - "version": "1.1.72", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", - "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", "dev": true }, "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.0.1.tgz", + "integrity": "sha512-VU4pzAuh7Kip71XEmO9aNREYAdMHFGTVj/i+CaTImS8x0i1d3jUZkXhqluy/PRgjPLMgsLQulYY3PJ/aSbSjpQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/nth-check": { @@ -1037,9 +1291,9 @@ } }, "node_modules/postcss": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz", - "integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz", + "integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==", "dev": true, "peer": true, "dependencies": { @@ -1359,13 +1613,13 @@ } }, "node_modules/postcss-normalize-url": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.1.tgz", - "integrity": "sha512-hkbG0j58Z1M830/CJ73VsP7gvlG1yF+4y7Fd1w4tD2c7CaA2Psll+pQ6eQhth9y9EaqZSLzamff/D0MZBMbYSg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.2.tgz", + "integrity": "sha512-k4jLTPUxREQ5bpajFQZpx8bCF2UrlqOTzP9kEqcEnOfwsRshWs2+oAFIHfDQB8GO2PaUaSE0NlTAYtbluZTlHQ==", "dev": true, "dependencies": { "is-absolute-url": "^3.0.3", - "normalize-url": "^4.5.0", + "normalize-url": "^6.0.1", "postcss-value-parser": "^4.1.0" }, "engines": { @@ -1391,9 +1645,9 @@ } }, "node_modules/postcss-ordered-values": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.1.tgz", - "integrity": "sha512-6mkCF5BQ25HvEcDfrMHCLLFHlraBSlOXFnQMHYhSpDO/5jSR1k8LdEXOkv+7+uzW6o6tBYea1Km0wQSRkPJkwA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz", + "integrity": "sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ==", "dev": true, "dependencies": { "cssnano-utils": "^2.0.1", @@ -1614,6 +1868,11 @@ "node": ">=0.10.0" } }, + "node_modules/split.js": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/split.js/-/split.js-1.6.4.tgz", + "integrity": "sha512-kYmQZprRJrF1IOjg/E+gdBEsKFv5kbgUE6RJVJZvrIzTOK/IHzKSqIeiJnWs7IP5D9TnpTQ2CbanuDuIWcyDUQ==" + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1641,6 +1900,11 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "node_modules/style-mod": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", + "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" + }, "node_modules/stylehacks": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz", @@ -1896,6 +2160,11 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "node_modules/w3c-keyname": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", + "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" + }, "node_modules/yaku": { "version": "0.16.7", "resolved": "https://registry.npmjs.org/yaku/-/yaku-0.16.7.tgz", @@ -1920,31 +2189,254 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" } }, "@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", "dev": true }, "@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.0", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, + "@codemirror/autocomplete": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-0.18.7.tgz", + "integrity": "sha512-4x6xH2jDuJzweB0Wdx3VQrFUvZF0V7RAHoomQOCq3NxUOZd/UXcSXrj3LXItFAxi6K4OlTLayFuI3z4k3UKUQQ==", + "requires": { + "@codemirror/language": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/tooltip": "^0.18.4", + "@codemirror/view": "^0.18.0", + "lezer-tree": "^0.13.0" + } + }, + "@codemirror/basic-setup": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@codemirror/basic-setup/-/basic-setup-0.18.2.tgz", + "integrity": "sha512-4UNFQ4jhU7wKxJH23AJcZW6Ho54VXUpmbtFnN5amIdtGci4ZLvci4M7JKgKFraHmKfDIYQnSzN8d8ohXR7CRhw==", + "requires": { + "@codemirror/autocomplete": "^0.18.0", + "@codemirror/closebrackets": "^0.18.0", + "@codemirror/commands": "^0.18.0", + "@codemirror/comment": "^0.18.0", + "@codemirror/fold": "^0.18.0", + "@codemirror/gutter": "^0.18.3", + "@codemirror/highlight": "^0.18.0", + "@codemirror/history": "^0.18.0", + "@codemirror/language": "^0.18.0", + "@codemirror/lint": "^0.18.0", + "@codemirror/matchbrackets": "^0.18.0", + "@codemirror/rectangular-selection": "^0.18.0", + "@codemirror/search": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "@codemirror/closebrackets": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@codemirror/closebrackets/-/closebrackets-0.18.0.tgz", + "integrity": "sha512-O1RAgUkzF4nq/B8IyXenZKZ1rJi2Mc7I6y4IhWhELiTnjyQy7YdAthTsJ40mNr8kZ6gRbasYe3K7TraITElZJA==", + "requires": { + "@codemirror/language": "^0.18.0", + "@codemirror/rangeset": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "@codemirror/commands": { + "version": "0.18.3", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-0.18.3.tgz", + "integrity": "sha512-nHYDG13qOirioXTAKmjl10W2L0eZ1ftvmTwvUTNY27UWVBPFSpk5zDXP3WqJ0mgMhQ4AOFLJaTjJEO3hmPComg==", + "requires": { + "@codemirror/language": "^0.18.0", + "@codemirror/matchbrackets": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0", + "lezer-tree": "^0.13.0" + } + }, + "@codemirror/comment": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@codemirror/comment/-/comment-0.18.1.tgz", + "integrity": "sha512-Inhqs0F24WE28Fcp1dBZghwixBGv1HDwY9MjE0d5tpMY/IPGI6uT30fGyHAXrir6hUqk7eJRkO4UYnODGOnoIA==", + "requires": { + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "@codemirror/fold": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@codemirror/fold/-/fold-0.18.1.tgz", + "integrity": "sha512-vvMUgDeSmeVow7/75YoNTERxPsdnIBeEw1JL2YVpLyscsUlalqwuxdhiHDLT5zjAu6JvMoTC103mwqgAYwM9tA==", + "requires": { + "@codemirror/gutter": "^0.18.0", + "@codemirror/language": "^0.18.0", + "@codemirror/rangeset": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "@codemirror/gutter": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/gutter/-/gutter-0.18.4.tgz", + "integrity": "sha512-Sf2IWshMi9zwVVqpGmd2NRplY0qfrE2IiBEII9n2gB9M8hgIMg5GCyhdnsUDsOm0gcSut65W62vV7/DfYJHQCA==", + "requires": { + "@codemirror/rangeset": "^0.18.3", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "@codemirror/highlight": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/highlight/-/highlight-0.18.4.tgz", + "integrity": "sha512-3azJntqWrShOIq/0kVcdMc9k7ACL0LQErgK+A6aWXmCj5Mx0gShq+Iajy8AMQ2zB0v3nhCBgFaniL1LLD5m5hQ==", + "requires": { + "@codemirror/language": "^0.18.0", + "@codemirror/rangeset": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0", + "lezer-tree": "^0.13.0", + "style-mod": "^4.0.0" + } + }, + "@codemirror/history": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@codemirror/history/-/history-0.18.1.tgz", + "integrity": "sha512-Aad3p4zs6UYKCUMXYjh7cvPK0ajuL+rMib9yBZ61w81LLl6OkM31Xrn9J6CLJmPxCwP3OJFiqBmNSBQ05oIsTw==", + "requires": { + "@codemirror/state": "^0.18.3", + "@codemirror/view": "^0.18.0" + } + }, + "@codemirror/language": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.18.2.tgz", + "integrity": "sha512-2Kz0Xyfvt1Ex2KfTUcYZ3IBxpnFCqHaJijwZknGBT7JXv9dwbOPs9SfPfL4oxVuDIHZx8JTPfoV3LTTJrm8M3Q==", + "requires": { + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0", + "lezer": "^0.13.4", + "lezer-tree": "^0.13.0" + } + }, + "@codemirror/lint": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-0.18.4.tgz", + "integrity": "sha512-H77qYfZOmo1kKf0ZQagzk/JRGVhIpwP0hq1TSO6DFC1WLjW6gcsFJO5NDMS86enm0KX0w4/IkA7PItz2mjmHhQ==", + "requires": { + "@codemirror/panel": "^0.18.1", + "@codemirror/state": "^0.18.0", + "@codemirror/tooltip": "^0.18.4", + "@codemirror/view": "^0.18.0", + "crelt": "^1.0.5" + } + }, + "@codemirror/matchbrackets": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@codemirror/matchbrackets/-/matchbrackets-0.18.0.tgz", + "integrity": "sha512-dPDopnZVkD54sSYdmQbyQbPdiuIA83p7XxX6Hp1ScEkOjukwCiFXiA/84x10FUTsQpUYp8bDzm7gwII119bGIw==", + "requires": { + "@codemirror/language": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0", + "lezer-tree": "^0.13.0" + } + }, + "@codemirror/panel": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@codemirror/panel/-/panel-0.18.2.tgz", + "integrity": "sha512-ea/g2aAKtfmie1kD7C8GDutD/5u+uzRJr/varUiAbHKr1sAdjtz5xYvC3GBAMYMan1GOh0vD5zP1yEupJl3b3Q==", + "requires": { + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "@codemirror/rangeset": { + "version": "0.18.3", + "resolved": "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.18.3.tgz", + "integrity": "sha512-p6bPVr6Cw0yh/QSelsg0RoNaG4btuzZo7YMT+WFwZsjbr7+X0dVpd2vqLAHIeDUfvOzrEI/dXXPKLpZZgYeU+g==", + "requires": { + "@codemirror/state": "^0.18.0" + } + }, + "@codemirror/rectangular-selection": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@codemirror/rectangular-selection/-/rectangular-selection-0.18.0.tgz", + "integrity": "sha512-BQ4pp2zhXCVZNqct5LtLR3AOWVseENBF/3oOgBmwsCKH7c11NfTqIqgWG5EW8NLOXp8HP8cDm3np8eWez0VkGQ==", + "requires": { + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "@codemirror/search": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-0.18.4.tgz", + "integrity": "sha512-3chVkMPzl+pTUSqtimTicebhti4SLpvkj03pQx2aPZScXxIiYuDk4cLdIJK9omjmO1+oycRKbOrqvG7iZJJwMg==", + "requires": { + "@codemirror/panel": "^0.18.1", + "@codemirror/rangeset": "^0.18.0", + "@codemirror/state": "^0.18.6", + "@codemirror/text": "^0.18.0", + "@codemirror/view": "^0.18.0", + "crelt": "^1.0.5" + } + }, + "@codemirror/state": { + "version": "0.18.7", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.18.7.tgz", + "integrity": "sha512-cVyTiAC9vv90NKmGOfNtBjyIem3BqKui1L5Hfcxurp8K9votQj2oH9COcgWPnQ2Xs64yC70tEuTt9DF1pj5PFQ==", + "requires": { + "@codemirror/text": "^0.18.0" + } + }, + "@codemirror/text": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@codemirror/text/-/text-0.18.0.tgz", + "integrity": "sha512-HMzHNIAbjCiCf3tEJMRg6ul01KPuXxQGNiHlHgAnqPguq/CX+L4Nvj5JlWQAI91Pupk18zhmM1c6eaazX4YeTg==" + }, + "@codemirror/tooltip": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/@codemirror/tooltip/-/tooltip-0.18.4.tgz", + "integrity": "sha512-LDlDOSEfjoG24uapLN7exK3Z3JchYFKUwWqo1x/9YdlAkmD1ik7cMSQZboCquP1uJVcXhtbpKmaO6vENGVaarg==", + "requires": { + "@codemirror/state": "^0.18.0", + "@codemirror/view": "^0.18.0" + } + }, + "@codemirror/view": { + "version": "0.18.17", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.18.17.tgz", + "integrity": "sha512-AneqrYFgQJFZY5CdIRvllaLWL7r966JZK64d05PrScYhhRT6y5iiq0VBO9nxX5Y2gbTXBdO1/eZdtJlhwa6hww==", + "requires": { + "@codemirror/rangeset": "^0.18.2", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, "@trysound/sax": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz", @@ -1979,16 +2471,16 @@ "dev": true }, "@vue/component-compiler-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.2.0.tgz", - "integrity": "sha512-lejBLa7xAMsfiZfNp7Kv51zOzifnb29FwdnMLa96z26kXErPFioSf9BMcePVIQ6/Gc6/mC0UrPpxAWIHyae0vw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.2.2.tgz", + "integrity": "sha512-rAYMLmgMuqJFWAOb3Awjqqv5X3Q3hVr4jH/kgrFJpiU0j3a90tnNBplqbj+snzrgZhC9W128z+dtgMifOiMfJg==", "dev": true, "requires": { "consolidate": "^0.15.1", "hash-sum": "^1.0.2", "lru-cache": "^4.1.2", "merge-source-map": "^1.1.0", - "postcss": "^7.0.14", + "postcss": "^7.0.36", "postcss-selector-parser": "^6.0.2", "prettier": "^1.18.2", "source-map": "~0.6.1", @@ -1996,9 +2488,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -2090,9 +2582,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001234", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001234.tgz", - "integrity": "sha512-a3gjUVKkmwLdNysa1xkUAwN2VfJUJyVW47rsi3aCbkRCtbHAfo+rOsCqVw29G6coQ8gzAPb5XBXwiGHwme3isA==", + "version": "1.0.30001237", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001237.tgz", + "integrity": "sha512-pDHgRndit6p1NR2GhzMbQ6CkRrp4VKuSsqbcLeOQppYPKOYkKT/6ZvZDvKJUqcmtyWIAHuZq3SVS2vc1egCZzw==", "dev": true }, "capture-stack-trace": { @@ -2182,6 +2674,11 @@ "capture-stack-trace": "^1.0.0" } }, + "crelt": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", + "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==" + }, "css-color-names": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-1.0.1.tgz", @@ -2233,20 +2730,20 @@ "dev": true }, "cssnano": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.5.tgz", - "integrity": "sha512-L2VtPXnq6rmcMC9vkBOP131sZu3ccRQI27ejKZdmQiPDpUlFkUbpXHgKN+cibeO1U4PItxVZp1zTIn5dHsXoyg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.6.tgz", + "integrity": "sha512-NiaLH/7yqGksFGsFNvSRe2IV/qmEBAeDE64dYeD8OBrgp6lE8YoMeQJMtsv5ijo6MPyhuoOvFhI94reahBRDkw==", "dev": true, "requires": { "cosmiconfig": "^7.0.0", - "cssnano-preset-default": "^5.1.2", + "cssnano-preset-default": "^5.1.3", "is-resolvable": "^1.1.0" } }, "cssnano-preset-default": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.2.tgz", - "integrity": "sha512-spilp8LRw0sacuxiN9A/dyyPr6G/WISKMBKcBD4NMoPV0ENx4DeuWvIIrSx9PII2nJIDCO3kywkqTPreECBVOg==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.3.tgz", + "integrity": "sha512-qo9tX+t4yAAZ/yagVV3b+QBKeLklQbmgR3wI7mccrDcR+bEk9iHgZN1E7doX68y9ThznLya3RDmR+nc7l6/2WQ==", "dev": true, "requires": { "css-declaration-sorter": "^6.0.3", @@ -2271,9 +2768,9 @@ "postcss-normalize-string": "^5.0.1", "postcss-normalize-timing-functions": "^5.0.1", "postcss-normalize-unicode": "^5.0.1", - "postcss-normalize-url": "^5.0.1", + "postcss-normalize-url": "^5.0.2", "postcss-normalize-whitespace": "^5.0.1", - "postcss-ordered-values": "^5.0.1", + "postcss-ordered-values": "^5.0.2", "postcss-reduce-initial": "^5.0.1", "postcss-reduce-transforms": "^5.0.1", "postcss-svgo": "^5.0.2", @@ -2329,9 +2826,9 @@ } }, "domutils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.6.0.tgz", - "integrity": "sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", "dev": true, "requires": { "dom-serializer": "^1.0.1", @@ -2358,9 +2855,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.748", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.748.tgz", - "integrity": "sha512-fmIKfYALVeEybk/L2ucdgt7jN3JsbGtg3K9pmF/MRWgkeADBI1VSAa5IzdG2gZwTxsnsrFtdMpOTSM5mrBRKVQ==", + "version": "1.3.752", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.752.tgz", + "integrity": "sha512-2Tg+7jSl3oPxgsBsWKh5H83QazTkmWG/cnNwJplmyZc7KcN61+I10oUgaXSVk/NwfvN3BdkKDR4FYuRBQQ2v0A==", "dev": true }, "entities": { @@ -2573,6 +3070,19 @@ "set-immediate-shim": "~1.0.1" } }, + "lezer": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/lezer/-/lezer-0.13.5.tgz", + "integrity": "sha512-cAiMQZGUo2BD8mpcz7Nv1TlKzWP7YIdIRrX41CiP5bk5t4GHxskOxWUx2iAOuHlz8dO+ivbuXr0J1bfHsWD+lQ==", + "requires": { + "lezer-tree": "^0.13.2" + } + }, + "lezer-tree": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/lezer-tree/-/lezer-tree-0.13.2.tgz", + "integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ==" + }, "lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -2668,15 +3178,15 @@ "peer": true }, "node-releases": { - "version": "1.1.72", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", - "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", "dev": true }, "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.0.1.tgz", + "integrity": "sha512-VU4pzAuh7Kip71XEmO9aNREYAdMHFGTVj/i+CaTImS8x0i1d3jUZkXhqluy/PRgjPLMgsLQulYY3PJ/aSbSjpQ==", "dev": true }, "nth-check": { @@ -2732,9 +3242,9 @@ "dev": true }, "postcss": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz", - "integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz", + "integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==", "dev": true, "peer": true, "requires": { @@ -2935,13 +3445,13 @@ } }, "postcss-normalize-url": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.1.tgz", - "integrity": "sha512-hkbG0j58Z1M830/CJ73VsP7gvlG1yF+4y7Fd1w4tD2c7CaA2Psll+pQ6eQhth9y9EaqZSLzamff/D0MZBMbYSg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.2.tgz", + "integrity": "sha512-k4jLTPUxREQ5bpajFQZpx8bCF2UrlqOTzP9kEqcEnOfwsRshWs2+oAFIHfDQB8GO2PaUaSE0NlTAYtbluZTlHQ==", "dev": true, "requires": { "is-absolute-url": "^3.0.3", - "normalize-url": "^4.5.0", + "normalize-url": "^6.0.1", "postcss-value-parser": "^4.1.0" } }, @@ -2955,9 +3465,9 @@ } }, "postcss-ordered-values": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.1.tgz", - "integrity": "sha512-6mkCF5BQ25HvEcDfrMHCLLFHlraBSlOXFnQMHYhSpDO/5jSR1k8LdEXOkv+7+uzW6o6tBYea1Km0wQSRkPJkwA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz", + "integrity": "sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ==", "dev": true, "requires": { "cssnano-utils": "^2.0.1", @@ -3112,6 +3622,11 @@ "dev": true, "peer": true }, + "split.js": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/split.js/-/split.js-1.6.4.tgz", + "integrity": "sha512-kYmQZprRJrF1IOjg/E+gdBEsKFv5kbgUE6RJVJZvrIzTOK/IHzKSqIeiJnWs7IP5D9TnpTQ2CbanuDuIWcyDUQ==" + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -3141,6 +3656,11 @@ } } }, + "style-mod": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", + "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" + }, "stylehacks": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz", @@ -3342,6 +3862,11 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "w3c-keyname": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", + "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" + }, "yaku": { "version": "0.16.7", "resolved": "https://registry.npmjs.org/yaku/-/yaku-0.16.7.tgz", diff --git a/package.json b/package.json index 6f3f0c691..7d80ac23c 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,11 @@ }, "homepage": "https://github.com/TyGuS/suslik#readme", "dependencies": { + "@codemirror/basic-setup": "^0.18.2", "array-equal": "^1.0.0", "find": "^0.3.0", "jquery": "^3.5.0", + "split.js": "^1.6.4", "vue": "^2.6.13", "vue-context": "^5.2.0" }, @@ -25,7 +27,7 @@ "@types/jquery": "^3.3.34", "@types/node": "^13.11.1", "@vue/component-compiler-utils": "^3.2.0", - "cssnano": "^5.0.5", + "cssnano": "^5.0.6", "nw-vue-devtools-prebuilt": "^0.0.10", "typescript": "^4.3.2", "vue-hot-reload-api": "^2.3.4", diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala index 2a393172b..2f0852339 100644 --- a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -140,7 +140,8 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { val stats = new SynStats(2500) val config = SynConfig() isynth = new IterativeUnorderedSynthesis(new PhasedSynthesis(env.config), log, trace)(stats, config) - new Synthesis(tactic, log, trace) + //new Synthesis(tactic, log, trace) + isynth } /** @@ -191,6 +192,10 @@ object AsyncSynthesisRunner { def cancel() { waiting foreach (_.interrupt()) } } + /** + * Provides a Synthesis object that can be asked to expand nodes on-demand. + * All expansions are immediately sent to the trace (no nodes are suspended). + */ class IterativeUnorderedSynthesis(tactic: Tactic, log: Log, trace: ProofTrace) (implicit stats: SynStats, config: SynConfig) extends Synthesis(tactic, log, trace) { diff --git a/src/main/scala/org/tygus/suslik/synthesis/Termination.scala b/src/main/scala/org/tygus/suslik/synthesis/Termination.scala index f340e893f..52f3a1076 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/Termination.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/Termination.scala @@ -66,8 +66,8 @@ object Termination { def isTerminatingExpansion(andNode: AndNode)(implicit log: Log, config: SynConfig, stats: SynStats): Boolean = { if (andNode.transitions.exists(_.isBacklink)) { // Construct the trace using only success leaves from my branch of the search and my own proof branch - val relevantSucceessLeaves = andNode.parent.partialDerivation - val trace = collectTrace(andNode.parent :: relevantSucceessLeaves, andNode.transitions) + val relevantSuccessLeaves = andNode.parent.partialDerivation + val trace = collectTrace(andNode.parent :: relevantSuccessLeaves, andNode.transitions) // log.print(List((s"New backlink formed by ${andNode.rule}", Console.CYAN))) // log.print(List((s"${trace.map(_.pp).mkString("\n")};", Console.CYAN))) val traceToCheck = s"${trace.map(_.pp).mkString("\n")};" diff --git a/src/viz/ts/app.ts b/src/viz/ts/app.ts index b59decd87..a85a9ae35 100644 --- a/src/viz/ts/app.ts +++ b/src/viz/ts/app.ts @@ -8,6 +8,8 @@ import { BenchmarksDB } from './benchmarks'; import { ProofTrace } from './proof-trace'; import { ProofInteraction } from './proof-interaction'; +import './ide.css'; + class MainDocument extends EventEmitter { @@ -85,7 +87,11 @@ class MainDocument extends EventEmitter { hideBenchmarks() { var bm = this.app.$refs.benchmarks; - bm.show = false; + //bm.show = false; + } + + setEditorText(text: string) { + (this.app.$refs.editors).open(text); } async read(file: File) { diff --git a/src/viz/ts/ide.css b/src/viz/ts/ide.css new file mode 100644 index 000000000..5ceaee170 --- /dev/null +++ b/src/viz/ts/ide.css @@ -0,0 +1,25 @@ +html, body { + width: 100%; + height: 100%; + margin: 0; + overscroll-behavior: none; +} + +* { + box-sizing: border-box; +} + +.app--ide { + height: 100%; +} + +.ide-pane { + position: relative; + height: 100%; + overflow: auto; +} + +div.gutter.gutter-horizontal { + cursor: col-resize; + background: #ddd; +} \ No newline at end of file diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index 29e4d7a85..b1f0c1b81 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -10,7 +10,7 @@ declare var nw: any; if (typeof nw !== 'undefined') { var win = nw.Window.get(); - win.zoomLevel = -2; + //win.zoomLevel = -2; Object.assign(window, { printDocument() { win.print({autoprint: false, scaleFactor: 5}); @@ -31,6 +31,8 @@ $(async () => { async function startBenchmark(w: {dir: string, fn: string}) { var spec = bench.getSpec(w.dir, w.fn); doc.hideBenchmarks(); + doc.new(); + doc.setEditorText([...spec.defs, spec.in].join('\n')); await doc.pi.start(spec); Object.assign(window, {spec}); } diff --git a/src/viz/ts/proof-trace.css b/src/viz/ts/proof-trace.css index f1033e113..b33831792 100644 --- a/src/viz/ts/proof-trace.css +++ b/src/viz/ts/proof-trace.css @@ -235,10 +235,10 @@ /* Toobar */ .proof-trace-toolbar { - position: fixed; + position: sticky; top: 0; - left: 20em; - width: calc(100% - 20em); + left: 2em; + width: calc(100% - 2em); background: #ffffffd0; z-index: 1; } diff --git a/src/viz/vue/app-toolbar.vue b/src/viz/vue/app-toolbar.vue index cb6c3cc00..b89eddf74 100644 --- a/src/viz/vue/app-toolbar.vue +++ b/src/viz/vue/app-toolbar.vue @@ -16,6 +16,9 @@ + \ No newline at end of file diff --git a/src/viz/vue/benchmark-list-pane.vue b/src/viz/vue/benchmark-list-pane.vue index 11d7a440f..3eb10e0e5 100644 --- a/src/viz/vue/benchmark-list-pane.vue +++ b/src/viz/vue/benchmark-list-pane.vue @@ -1,5 +1,5 @@ @@ -21,7 +24,7 @@ import ProofInteraction from './proof-interaction.vue'; export default { - data: () => ({root: undefined, options: {}, zoom: 1, + data: () => ({traces: {}, options: {}, zoom: 1, interaction: {}, highlight: {'special': [[]]}}), computed: { jointHigh() { @@ -29,7 +32,8 @@ export default { } }, methods: { - toplevelAction(ev) { + toplevelAction(ev, id) { + ev = {id, ...ev}; switch (ev.type) { case 'menu': this.$refs.contextMenu.open(ev); break; } diff --git a/src/viz/vue/proof-trace.vue b/src/viz/vue/proof-trace.vue index 03559ff59..8ab41a982 100644 --- a/src/viz/vue/proof-trace.vue +++ b/src/viz/vue/proof-trace.vue @@ -32,10 +32,9 @@ export default { data: () => ({statusClass: undefined}), mounted() { this.$watch('root.expanded', () => { - requestAnimationFrame(() => { - if (this.root.focus && this.$refs.subtrees) - this.focusElement(this.$refs.subtrees); - }); + if (this.root?.focus && this.$refs.subtrees) + requestAnimationFrame(() => + this.focusElement(this.$refs.subtrees)); }); if (this.$refs.nroot) this.statusClass = this.$refs.nroot.statusClass; @@ -61,7 +60,7 @@ export default { }, getHigh(id) { return Object.entries(this.highlight || {}) - .map(([k, v]) => v.some(x => arreq(x, id)) ? k : undefined) + .map(([k, v]) => v?.some(x => arreq(x, id)) ? k : undefined) .filter(x => x); } }, diff --git a/src/viz/vue/widgets/slider-switch.vue b/src/viz/vue/widgets/slider-switch.vue new file mode 100644 index 000000000..4e0adbd47 --- /dev/null +++ b/src/viz/vue/widgets/slider-switch.vue @@ -0,0 +1,80 @@ + + + + + \ No newline at end of file From a774c0c869c33464cc5066cfe8b3caf291d9e045 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Thu, 24 Jun 2021 23:00:25 +0300 Subject: [PATCH 42/90] [bugfix] Strip away params line. When sending input to server. `#` is not a comment in `.syn` format. --- src/viz/ts/benchmarks.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/viz/ts/benchmarks.ts b/src/viz/ts/benchmarks.ts index 6f90ba763..71f74c24b 100644 --- a/src/viz/ts/benchmarks.ts +++ b/src/viz/ts/benchmarks.ts @@ -46,10 +46,10 @@ namespace BenchmarksDB { } export function parseInputSpec(text: string) { - var hashline = text.match(/^#[.]?(.*)/)?.[1], + var hashline = text.match(/^#[.]?(.*)\n([^]*)/), enclosure = text.match(/###+([^]*?)###+/), - params = hashline?.trim().split(/\s+/), - in_ = enclosure?.[1] || text; + params = hashline?.[1].trim().split(/\s+/), + in_ = enclosure?.[1] || hashline?.[2] || text; return {in: in_, params}; } From 28a4da17d72b042d539f2e2a24a430f36f960a8b Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Fri, 25 Jun 2021 14:43:01 +0300 Subject: [PATCH 43/90] [perf] Some throttling of messages in auto. Handling messages one by one is currently inefficient, collate to speed up indexing. --- package-lock.json | 20 +++++++++++--- package.json | 2 ++ src/viz/ts/app.ts | 48 ++++++++++++++++++++++++++++----- src/viz/ts/main.ts | 25 ++++++++++------- src/viz/ts/proof-interaction.ts | 1 + src/viz/ts/proof-trace.ts | 9 ++++--- 6 files changed, 82 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 30470bef7..24ea58cae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,12 +13,14 @@ "array-equal": "^1.0.0", "find": "^0.3.0", "jquery": "^3.5.0", + "lodash": "^4.17.21", "split.js": "^1.6.4", "vue": "^2.6.13", "vue-context": "^5.2.0" }, "devDependencies": { "@types/jquery": "^3.3.34", + "@types/lodash": "^4.14.170", "@types/node": "^13.11.1", "@vue/component-compiler-utils": "^3.2.0", "cssnano": "^5.0.6", @@ -304,6 +306,12 @@ "@types/sizzle": "*" } }, + "node_modules/@types/lodash": { + "version": "4.14.170", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.170.tgz", + "integrity": "sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q==", + "dev": true + }, "node_modules/@types/node": { "version": "13.11.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.1.tgz", @@ -1113,8 +1121,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.memoize": { "version": "4.1.2", @@ -2452,6 +2459,12 @@ "@types/sizzle": "*" } }, + "@types/lodash": { + "version": "4.14.170", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.170.tgz", + "integrity": "sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q==", + "dev": true + }, "@types/node": { "version": "13.11.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.1.tgz", @@ -3101,8 +3114,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.memoize": { "version": "4.1.2", diff --git a/package.json b/package.json index ea2b55ad3..9393d0e56 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,14 @@ "array-equal": "^1.0.0", "find": "^0.3.0", "jquery": "^3.5.0", + "lodash": "^4.17.21", "split.js": "^1.6.4", "vue": "^2.6.13", "vue-context": "^5.2.0" }, "devDependencies": { "@types/jquery": "^3.3.34", + "@types/lodash": "^4.14.170", "@types/node": "^13.11.1", "@vue/component-compiler-utils": "^3.2.0", "cssnano": "^5.0.6", diff --git a/src/viz/ts/app.ts b/src/viz/ts/app.ts index 8d0bb1bc7..7e3e64754 100644 --- a/src/viz/ts/app.ts +++ b/src/viz/ts/app.ts @@ -1,4 +1,5 @@ import { EventEmitter } from 'events'; +import _ from 'lodash'; import $ from 'jquery'; import Vue from 'vue'; @@ -16,6 +17,8 @@ class SuSLikApp extends EventEmitter { app: Vue notifications: JQuery + doc: MainDocument + constructor(notifications: JQuery) { super(); this.notifications = notifications; @@ -36,6 +39,8 @@ class SuSLikApp extends EventEmitter { } add(doc: MainDocument) { + this.doc?.close(); + this.doc = doc; doc.on('error', err => this.message(err.message)); } @@ -69,6 +74,7 @@ class SuSLikApp extends EventEmitter { class MainDocument extends EventEmitter { id: string pane: Vue & ProofTrace.View.PaneProps + options: DocumentOptions pt: ProofTrace pi: ProofInteraction @@ -77,10 +83,12 @@ class MainDocument extends EventEmitter { storage: {'suslik:doc:lastUrl'?: string} = localStorage; - constructor(id: string, pane: Vue & ProofTrace.View.PaneProps) { + constructor(id: string, pane: Vue & ProofTrace.View.PaneProps, + options: DocumentOptions = {}) { super(); this.id = id; this.pane = pane; + this.options = options; } new() { @@ -112,7 +120,7 @@ class MainDocument extends EventEmitter { } openRecent(opts?: OpenOptions) { - return this.openUrl(this.storage['suslik:doc:lastUrl'] || DEFAULT_URL, opts); + return this.openUrl(this.storage['suslik:doc:lastUrl'] || MainDocument.DEFAULT_URL, opts); } setProofTrace(ptData: ProofTrace.Data) { @@ -130,9 +138,12 @@ class MainDocument extends EventEmitter { if (this.pi) this.pi.sendExpandRequest(nodeView.value.id); } }); - pi.on('trace', u => - this.pt.append(ProofTrace.Data.fromEntries([u]))); + pi.on('trace', throttleCollate((values: [any][]) => { + this.pt.append(ProofTrace.Data.fromEntries(values.map(x => x[0])), + {expand: this.options.expandImmediately}); + }, this.options.throttle)); + this.emit('open', pt); return pt; } @@ -140,10 +151,24 @@ class MainDocument extends EventEmitter { async read(file: File) { return new TextDecoder().decode(await file.arrayBuffer()); } + + close() { + this.pt?.destroy(); + this.pi?.destroy(); + } } -type OpenOptions = {name?: string, silent?: boolean}; -const DEFAULT_URL = '/trace.json'; +namespace MainDocument { + export type Options = { + throttle?: number /* min delay between trace updates */ + expandImmediately?: true /* whether to expand nodes as soon as they are received */ + }; + export type OpenOptions = {name?: string, silent?: boolean}; + export const DEFAULT_URL = '/trace.json'; +} + +import DocumentOptions = MainDocument.Options; +import OpenOptions = MainDocument.OpenOptions; class DragDropJson extends EventEmitter { @@ -168,5 +193,16 @@ class DragDropJson extends EventEmitter { } +/** + * Service routine; throttle call then invoke with accumulated + * lists of args. + */ +function throttleCollate(func: (c: T[]) => void, wait?: number) { + var queue = [], + tflush = _.throttle(() => { func(queue); queue = []; }, wait); + return (...args: any[]) => { queue.push(args); tflush(); }; +} + + export { SuSLikApp, MainDocument, OpenOptions, DragDropJson } diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index fa8ffd706..9d1459399 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -1,9 +1,10 @@ import $ from 'jquery'; import { SuSLikApp, MainDocument, DragDropJson } from './app'; -import { ProofTrace } from './proof-trace'; import { ProofInteraction } from './proof-interaction'; import { BenchmarksDB } from './benchmarks'; +import ProofMode = ProofInteraction.Data.ProofMode; + declare var nw: any; @@ -27,31 +28,37 @@ $(async () => { const bench = await BenchmarksDB.load(); app.setBenchmarks(bench.data); - async function startBenchmark(w: {dir: string, fn: string}) { + async function startBenchmark(w: {dir: string, fn: string}, mode: ProofMode = ProofMode.INTERACTIVE) { var spec = bench.getSpec(w.dir, w.fn), - doc = new MainDocument('benchmark-0', app.app.$refs.proofTrace as any) + doc = new MainDocument('benchmark-0', app.app.$refs.proofTrace as any, + OPTIONS[mode]); app.hideBenchmarks(); app.setEditorText(BenchmarksDB.Data.unparseSpec(spec)); app.add(doc); doc.new(); - await doc.pi.start(spec); + await doc.pi.start(spec, mode); } - async function restartBenchmark(mode?: ProofInteraction.Data.ProofMode) { + async function restartBenchmark(mode: ProofMode = ProofMode.INTERACTIVE) { console.log(app.getEditorText()); var spec = BenchmarksDB.Data.parseSpec('todo', app.getEditorText()), - doc = new MainDocument('benchmark-0', app.app.$refs.proofTrace as any); + doc = new MainDocument('benchmark-0', app.app.$refs.proofTrace as any, + OPTIONS[mode]); app.add(doc); doc.new(); await doc.pi.start(spec, mode); } function proofMode() { - return app.options.auto ? ProofInteraction.Data.ProofMode.AUTOMATIC - : ProofInteraction.Data.ProofMode.INTERACTIVE; + return app.options.auto ? ProofMode.AUTOMATIC : ProofMode.INTERACTIVE; } - app.on('benchmarks:action', startBenchmark); + const OPTIONS: {[mode: string]: MainDocument.Options} = { + [ProofMode.AUTOMATIC]: {throttle: 750}, + [ProofMode.INTERACTIVE]: {expandImmediately: true} + }; + + app.on('benchmarks:action', w => startBenchmark(w, proofMode())); app.on('proofTrace:action', (action) => { switch (action.type) { case 'restart': restartBenchmark(proofMode()); break; diff --git a/src/viz/ts/proof-interaction.ts b/src/viz/ts/proof-interaction.ts index 466c7231b..074c00b41 100644 --- a/src/viz/ts/proof-interaction.ts +++ b/src/viz/ts/proof-interaction.ts @@ -30,6 +30,7 @@ class ProofInteraction extends EventEmitter { destroy() { this._actionHook.detach(); + this.ws?.close(); } async start(spec?: Data.Spec, mode?: Data.ProofMode) { diff --git a/src/viz/ts/proof-trace.ts b/src/viz/ts/proof-trace.ts index 2cdf1bd3f..6603e391a 100644 --- a/src/viz/ts/proof-trace.ts +++ b/src/viz/ts/proof-trace.ts @@ -42,11 +42,11 @@ class ProofTrace extends EventEmitter { this.createView(pane); } - append(data: Data) { + append(data: Data, opts: {expand?: boolean} = {}) { Data.append(this.data, data); this.updateIndex(data); for (let node of data.nodes) - this.addNode(node); + this.addNode(node, opts); this.refreshView(); } @@ -201,7 +201,7 @@ class ProofTrace extends EventEmitter { this._actionHook.detach(); } - addNode(node: Data.NodeEntry) { + addNode(node: Data.NodeEntry, opts: {expand?: boolean}) { if (node.id.length == 0) { // this is the root this.root = node; this.view.root = this.createNode(node); @@ -212,7 +212,8 @@ class ProofTrace extends EventEmitter { if (parentView) { parentView.children ??= []; parentView.children.push(this.createNode(node)); - parentView.expanded = true; /** @todo only if view is visible */ + if (opts.expand) + parentView.expanded = true; /** @todo only if parent is visible */ } } } From 190968984ca842f43e614e3fa7481ffa84e8b610 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Sun, 4 Jul 2021 15:27:02 +0300 Subject: [PATCH 44/90] Switched to `Simple` synthesis tactic (for server). --- .../scala/org/tygus/suslik/interaction/SynthesisServer.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala index 240def0d0..5e6d1776c 100644 --- a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -154,8 +154,8 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { val stats = new SynStats(2500) val config = SynConfig() - isynth = new IterativeUnorderedSynthesis(new AutomaticPhased(env.config), log, trace)(stats, config) - new Synthesis(new AutomaticPhased(env.config), log, trace) + isynth = new IterativeUnorderedSynthesis(new AutomaticSimple(env.config), log, trace)(stats, config) + new Synthesis(new AutomaticSimple(env.config), log, trace) //isynth } From 7eb8c371211893cb36caeae05ef2aa9c272dc5fb Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Mon, 5 Jul 2021 16:01:19 +0300 Subject: [PATCH 45/90] [ui] Restore focus and report success. In interactive mode, when expanding nodes. --- .../suslik/interaction/SynthesisServer.scala | 26 +++++++++++++------ src/viz/ts/proof-trace.ts | 6 +++-- src/viz/vue/proof-trace.vue | 7 ++--- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala index 5e6d1776c..9a3fd1977 100644 --- a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -185,7 +185,10 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { SynthesisRunner.parseParams("." +: spec.params.toArray, config) def grow(id: NodeId): Unit = - cached.get(id).foreach(isynth.grow) + cached.get(id) match { + case Some(node) => isynth.grow(node) + case _ => logger.warn(s"requested unknown node ${id.mkString(",")}") + } protected def wrapError[T](op: => T): T = { try op catch { @@ -225,13 +228,20 @@ object AsyncSynthesisRunner { implicit val log: Log = this.log implicit val ctx: Log.Context = Log.Context(goal) - for { - (e, i) <- expansionsForNode(node).zipWithIndex - andNode = AndNode(i +: node.id, node, e) - if isTerminatingExpansion(andNode) // termination check - } { - trace.add(andNode, andNode.nChildren) - for (_ <- 1 to andNode.nChildren) trace.add(andNode.nextChild) + val expansions = expansionsForNode(node) + + expansions.find(_.subgoals.isEmpty) match { + case Some(e) => + trace.add(e, node) /* node succeeded; record status */ + case None => + for { + (e, i) <- expansions.zipWithIndex + andNode = AndNode(i +: node.id, node, e) + if isTerminatingExpansion(andNode) // termination check + } { + trace.add(andNode, andNode.nChildren) + for (_ <- 1 to andNode.nChildren) trace.add(andNode.nextChild) + } } } diff --git a/src/viz/ts/proof-trace.ts b/src/viz/ts/proof-trace.ts index 6603e391a..c4dbbe1f4 100644 --- a/src/viz/ts/proof-trace.ts +++ b/src/viz/ts/proof-trace.ts @@ -212,8 +212,10 @@ class ProofTrace extends EventEmitter { if (parentView) { parentView.children ??= []; parentView.children.push(this.createNode(node)); - if (opts.expand) - parentView.expanded = true; /** @todo only if parent is visible */ + if (opts.expand) { /** @todo only if parent is visible */ + parentView.focus = true; + parentView.expanded = true; + } } } } diff --git a/src/viz/vue/proof-trace.vue b/src/viz/vue/proof-trace.vue index 8ab41a982..b1e2ca97b 100644 --- a/src/viz/vue/proof-trace.vue +++ b/src/viz/vue/proof-trace.vue @@ -50,13 +50,14 @@ export default { }, expandAll() { this.action({type: 'expandAll', target: this.root})}, focusElement(el) { - var box = el.getBoundingClientRect(), clrse = 50, - viewport = window.visualViewport, + var pane = el.closest('.ide-pane') || document.body, + box = el.getBoundingClientRect(), clrse = 50, + viewport = pane.getBoundingClientRect(), //window.visualViewport, v = (box.bottom + clrse) - viewport.height, hl = box.left - clrse - viewport.width * 0.33, hr = (box.right + clrse) - viewport.width, h = Math.min(hl, hr); - window.scrollBy({left: Math.max(h, 0), top: Math.max(v, 0), behavior: 'smooth'}); + pane.scrollBy({left: Math.max(h, 0), top: Math.max(v, 0), behavior: 'smooth'}); }, getHigh(id) { return Object.entries(this.highlight || {}) From c53c079aecdd4cf72b923e598dab77698c73575e Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Wed, 14 Jul 2021 18:20:52 +0300 Subject: [PATCH 46/90] [bugfix] Multithread mayhem! `ProofTrace.current` is now stored in TLS, to allow concurrent requests. Hopefully avoids all races and deadlocks. --- .../CertificationBenchmarks.scala | 7 ++++-- .../suslik/interaction/SynthesisServer.scala | 24 +++++++++++++------ .../org/tygus/suslik/report/ProofTrace.scala | 10 +++++++- .../synthesis/SynthesisRunnerUtil.scala | 4 +++- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/main/scala/org/tygus/suslik/certification/CertificationBenchmarks.scala b/src/main/scala/org/tygus/suslik/certification/CertificationBenchmarks.scala index 8e4ac0a32..5f97cfb3f 100644 --- a/src/main/scala/org/tygus/suslik/certification/CertificationBenchmarks.scala +++ b/src/main/scala/org/tygus/suslik/certification/CertificationBenchmarks.scala @@ -17,7 +17,7 @@ import org.tygus.suslik.logic.Preprocessor.preprocessProgram import org.tygus.suslik.parsing.SSLParser import org.tygus.suslik.report.ProofTraceCert import org.tygus.suslik.report.StopWatch.timed -import org.tygus.suslik.synthesis.tactics.PhasedSynthesis +import org.tygus.suslik.synthesis.tactics.{AutomaticSimple, AutomaticPhased} import org.tygus.suslik.synthesis.{SynConfig, Synthesis, SynthesisException, SynthesisRunnerUtil, dotSus, dotSyn} import org.tygus.suslik.util.{SynStatUtil, SynStats} import scopt.OptionParser @@ -81,7 +81,10 @@ class CertificationBenchmarks( } override def createSynthesizer(env: Environment): Synthesis = { - val tactic = new PhasedSynthesis(env.config) + val tactic = if (env.config.simple) + new AutomaticSimple(env.config) + else + new AutomaticPhased(env.config) val trace = new ProofTraceCert() new Synthesis(tactic, log, trace) } diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala index 9a3fd1977..44a2ed300 100644 --- a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -25,6 +25,8 @@ import org.tygus.suslik.synthesis.tactics._ import org.tygus.suslik.synthesis.{SynConfig, Synthesis, SynthesisRunner, SynthesisRunnerUtil} import org.tygus.suslik.util.SynStats +import scala.collection.mutable + class SynthesisServer { @@ -204,14 +206,22 @@ class AsyncSynthesisRunner extends SynthesisRunnerUtil { object AsyncSynthesisRunner { + trait Guard[T] extends mutable.Set[T] { + def using[R](t: T, op: => R): R = { + synchronized { this += t } + try op finally synchronized { this -= t } + } + } + + class ThreadBuffer extends mutable.HashSet[Thread] with Guard[Thread] { + def usingCurrent[R](op: => R): R = using(Thread.currentThread(), op) + } + class ArrayBlockingQueueWithCancel[E](capacity: Int) extends ArrayBlockingQueue[E](capacity) { - private var waiting: Option[Thread] = None - override def take(): E = { - assert(waiting.isEmpty) /* allow at most one consumer thread */ - waiting = Some(Thread.currentThread()) - try super.take() finally { waiting = None } - } + private val waiting = new ThreadBuffer + override def take(): E = waiting.usingCurrent { super.take() } + override def put(e: E): Unit = waiting.usingCurrent { super.put(e) } def cancel() { waiting foreach (_.interrupt()) } } @@ -228,7 +238,7 @@ object AsyncSynthesisRunner { implicit val log: Log = this.log implicit val ctx: Log.Context = Log.Context(goal) - val expansions = expansionsForNode(node) + val expansions = ProofTrace.using(trace) { expansionsForNode(node) } expansions.find(_.subgoals.isEmpty) match { case Some(e) => diff --git a/src/main/scala/org/tygus/suslik/report/ProofTrace.scala b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala index aa4ce1bd9..8ff2b3dd7 100644 --- a/src/main/scala/org/tygus/suslik/report/ProofTrace.scala +++ b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala @@ -1,6 +1,8 @@ package org.tygus.suslik.report import java.io.{BufferedWriter, File, FileWriter} +import scala.language.implicitConversions +import scala.util.DynamicVariable import org.tygus.suslik.language.Expressions import org.tygus.suslik.logic.{Block, Heaplet, PointsTo, SApp, Specifications} import org.tygus.suslik.logic.Specifications.Goal @@ -40,7 +42,13 @@ object ProofTrace { case class DerivationTrail(from: Goal, to: Seq[Goal], rule: SynthesisRule, subst: Map[String, OrVec]) - var current: ProofTrace = ProofTraceNone // oops, not thread-safe + def current: ProofTrace = _current.value + def current_=(trace: ProofTrace): Unit = _current.value = trace + + def using[T](trace: ProofTrace)(op: => T): T = _current.withValue(trace)(op) + + // need to be thread-local, for `SynthesisServer` + private val _current = new DynamicVariable[ProofTrace](ProofTraceNone) } object ProofTraceNone extends ProofTrace diff --git a/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunnerUtil.scala b/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunnerUtil.scala index 7f286f27c..70868dc53 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunnerUtil.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunnerUtil.scala @@ -136,8 +136,10 @@ trait SynthesisRunnerUtil { new InteractivePhased(env.config, env.stats) } else if (env.config.script.nonEmpty) new ReplaySynthesis(env.config) + else if (env.config.simple) + new AutomaticSimple(env.config) else - new PhasedSynthesis(env.config) + new AutomaticPhased(env.config) val trace : ProofTrace = if (env.config.certTarget != NoCert) new ProofTraceCert() else { env.config.traceToJsonFile match { case None => ProofTraceNone From 2635a9a69a3be0c5e35fb9d8c8d115088847e953 Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Wed, 14 Jul 2021 18:25:20 +0300 Subject: [PATCH 47/90] [ui] Connection error reporting. --- src/viz/ts/app.ts | 4 +++- src/viz/ts/ide.css | 16 +++++++++++++++- src/viz/ts/proof-interaction.ts | 5 +++++ src/viz/ts/proof-trace.css | 11 ----------- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/viz/ts/app.ts b/src/viz/ts/app.ts index 7e3e64754..1f8df1986 100644 --- a/src/viz/ts/app.ts +++ b/src/viz/ts/app.ts @@ -143,7 +143,9 @@ class MainDocument extends EventEmitter { this.pt.append(ProofTrace.Data.fromEntries(values.map(x => x[0])), {expand: this.options.expandImmediately}); }, this.options.throttle)); - + pi.on('error', err => + this.emit('error', {message: `oops: ${err.message}`})); + this.emit('open', pt); return pt; } diff --git a/src/viz/ts/ide.css b/src/viz/ts/ide.css index 5ceaee170..d9e4f7eab 100644 --- a/src/viz/ts/ide.css +++ b/src/viz/ts/ide.css @@ -22,4 +22,18 @@ html, body { div.gutter.gutter-horizontal { cursor: col-resize; background: #ddd; -} \ No newline at end of file +} + + +#notifications { + position: fixed; + bottom: 0; + right: 0; + z-index: 99; +} + +#notifications > div { + background: #fbb; + color: #333; + padding: 9px 1em; +} diff --git a/src/viz/ts/proof-interaction.ts b/src/viz/ts/proof-interaction.ts index 074c00b41..96c434e1e 100644 --- a/src/viz/ts/proof-interaction.ts +++ b/src/viz/ts/proof-interaction.ts @@ -40,6 +40,7 @@ class ProofInteraction extends EventEmitter { this.ws.addEventListener('open', resolve); this.ws.addEventListener('error', reject) }); + this.ws.addEventListener('error', err => this.emit('error', err)); if (spec) this.sendSpec(spec, mode); } @@ -56,6 +57,10 @@ class ProofInteraction extends EventEmitter { } _send(json: any, $type?: string) { + if (this.ws.readyState !== WebSocket.OPEN) { + this.emit('error', {message: 'disconnected from server'}); + return; + } this.ws.send(JSON.stringify($type ? {$type, ...json} : json)) } diff --git a/src/viz/ts/proof-trace.css b/src/viz/ts/proof-trace.css index 794595282..a49a9ccf2 100644 --- a/src/viz/ts/proof-trace.css +++ b/src/viz/ts/proof-trace.css @@ -256,14 +256,3 @@ padding: .1em .5em; background: #ddd; } - -#notifications { - position: fixed; - top: 0; - right: 0; -} -#notifications > div { - background: #fbb; - color: #333; - padding: 9px; -} From a60cf30ec466de823d30d3d6cb794d412b5f50fb Mon Sep 17 00:00:00 2001 From: Shachar Itzhaky Date: Wed, 14 Jul 2021 18:26:13 +0300 Subject: [PATCH 48/90] [ui] Sane autoscroll. Coalesces the areas of expanded nodes and tries to fit all of them into the viewport. --- src/viz/vue/proof-trace.vue | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/viz/vue/proof-trace.vue b/src/viz/vue/proof-trace.vue index b1e2ca97b..3d555bafc 100644 --- a/src/viz/vue/proof-trace.vue +++ b/src/viz/vue/proof-trace.vue @@ -21,11 +21,27 @@