diff --git a/.gitignore b/.gitignore index 47973596e..cb9347f1f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,7 @@ target/ lib_managed/ src_managed/ project/boot/ -project/ -project/plugins/project/ +target/ .history .cache .lib/ @@ -94,9 +93,6 @@ fabric.properties # Compiled class file *.class -# Log file -*.log - # BlueJ files *.ctxt @@ -118,9 +114,6 @@ hs_err_pid* *~ .*.swp -# stats -*.csv - # Emacs-generated .#* @@ -151,4 +144,11 @@ node_modules # certification results certify/ +# logs, stats, and other outputs +/logs +*.log +*.csv *results.tex +trace.json +*.trace.json +*.db.json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..2598f0cfe --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ext/tutorial"] + path = ext/tutorial + url = https://github.com/TyGuS/suslik-tutorial.git diff --git a/Aptfile b/Aptfile new file mode 100644 index 000000000..fe3ec6344 --- /dev/null +++ b/Aptfile @@ -0,0 +1 @@ +z3 diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..c05dcf0b4 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: target/universal/stage/bin/synthesis-server diff --git a/build.sbt b/build.sbt index 0e8fdd3a4..8f130cf88 100644 --- a/build.sbt +++ b/build.sbt @@ -10,31 +10,38 @@ scalaVersion := "2.12.12" javacOptions ++= Seq("-source", "1.8", "-target", "1.8", "-Xlint") scalacOptions += "-target:jvm-1.8" -resolvers in ThisBuild ++= Seq( +ThisBuild / resolvers ++= Seq( Resolver.sonatypeRepo("releases"), Resolver.sonatypeRepo("snapshots") ) resolvers += Resolver.bintrayIvyRepo("com.eed3si9n", "sbt-plugins") +lazy val akkaHttpVersion = "10.2.4" +lazy val akkaVersion = "2.6.14" + libraryDependencies ++= Seq( "org.slf4j" % "slf4j-api" % "1.6.4" withSources(), "ch.qos.logback" % "logback-classic" % "1.1.3" % "test", "org.scalatest" %% "scalatest" % "3.0.1" % "test", - "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.6" withSources(), + "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2" withSources(), "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", - "org.bitbucket.franck44.scalasmt" %% "scalasmt" % "2.1.1-SNAPSHOT" withSources() + "com.lihaoyi" %% "upickle" % "1.3.15", + "org.bitbucket.franck44.scalasmt" %% "scalasmt" % "2.1.1-SNAPSHOT" withSources(), + // Server stuff + "com.typesafe.akka" %% "akka-http" % akkaHttpVersion, + "com.typesafe.akka" %% "akka-stream" % akkaVersion, + "com.typesafe.akka" %% "akka-actor-typed" % akkaVersion ) scalacOptions ++= Seq() -logLevel in ThisBuild := Level.Warn +ThisBuild / logLevel := Level.Warn // creating a logger and setting level to warn/whatever for console -initialCommands in console := +console / initialCommands := """| | import ch.qos.logback.classic.Logger | import org.slf4j.LoggerFactory @@ -43,15 +50,16 @@ initialCommands in console := | root.setLevel(Level.OFF) | """.stripMargin -mainClass in assembly := Some("org.tygus.suslik.synthesis.SynthesisRunner") - -test in assembly := {} +Test / parallelExecution := false -parallelExecution in Test := false +assembly / assemblyJarName := "suslik.jar" +assembly / mainClass := Some("org.tygus.suslik.synthesis.SynthesisRunner") +assembly / test := {} -assemblyJarName in assembly := "suslik.jar" - -assemblyMergeStrategy in assembly := { - case PathList("META-INF", xs @ _*) => MergeStrategy.discard - case x => MergeStrategy.first +assembly / assemblyMergeStrategy := { + case PathList("META-INF", _*) => MergeStrategy.discard + case x if Assembly.isConfigFile(x) => MergeStrategy.concat + case _ => MergeStrategy.first } + +enablePlugins(JavaAppPackaging) diff --git a/ext/tutorial b/ext/tutorial new file mode 160000 index 000000000..2eaf0fa04 --- /dev/null +++ b/ext/tutorial @@ -0,0 +1 @@ +Subproject commit 2eaf0fa044084a6fb1dbf7f0598e08f487a4cb72 diff --git a/logback.prod.xml b/logback.prod.xml new file mode 100644 index 000000000..a448cda7e --- /dev/null +++ b/logback.prod.xml @@ -0,0 +1,28 @@ + + + + + + + + + logs/suslik-server.log + + logs/suslik-server.%i.log.zip + 1 + 30 + + + + 50MB + + + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{35} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 76769b08e..a44f9a6b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,2482 @@ { "name": "suslik", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "suslik", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@codemirror/basic-setup": "^0.18.2", + "@codemirror/stream-parser": "^0.18.2", + "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", + "nw-vue-devtools-prebuilt": "^0.0.10", + "typescript": "^4.3.2", + "vue-hot-reload-api": "^2.3.4", + "vue-template-compiler": "^2.6.13" + } + }, + "node_modules/@babel/code-frame": { + "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.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "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.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.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/stream-parser": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@codemirror/stream-parser/-/stream-parser-0.18.2.tgz", + "integrity": "sha512-3RTRmhIixcC2ps/G8So+BL0qJkwaspjyYt4smVYlSn4eNbxGK9K2RCnSmOPRv0SkuQMu3oUFbprFI/SbtZrPKg==", + "dependencies": { + "@codemirror/highlight": "^0.18.0", + "@codemirror/language": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "lezer": "^0.13.0", + "lezer-tree": "^0.13.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": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz", + "integrity": "sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "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/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", + "integrity": "sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "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/@vue/component-compiler-utils": { + "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, + "dependencies": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "optionalDependencies": { + "prettier": "^1.18.2" + } + }, + "node_modules/@vue/component-compiler-utils/node_modules/postcss": { + "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", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/@vue/component-compiler-utils/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/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/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "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.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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.30001237", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001237.tgz", + "integrity": "sha512-pDHgRndit6p1NR2GhzMbQ6CkRrp4VKuSsqbcLeOQppYPKOYkKT/6ZvZDvKJUqcmtyWIAHuZq3SVS2vc1egCZzw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "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/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/colord": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.0.1.tgz", + "integrity": "sha512-vm5YpaWamD0Ov6TSG0GGmUIwstrWcfKQV/h2CmbR7PbNu41+qdB5PW9lpzhjedrpm08uuYvcXi0Oel1RLZIJuA==", + "dev": true + }, + "node_modules/colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "dev": true, + "dependencies": { + "bluebird": "^3.1.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "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": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "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/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", + "integrity": "sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.0.3.tgz", + "integrity": "sha512-52P95mvW1SMzuRZegvpluT6yEv0FqQusydKQPZsNN5Q7hh8EwQvN8E2nwuJ16BBvNN6LcoIZXu/Bk58DAhrrxw==", + "dev": true, + "dependencies": { + "timsort": "^0.3.0" + }, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", + "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "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": "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.3", + "is-resolvable": "^1.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "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", + "cssnano-utils": "^2.0.1", + "postcss-calc": "^8.0.0", + "postcss-colormin": "^5.2.0", + "postcss-convert-values": "^5.0.1", + "postcss-discard-comments": "^5.0.1", + "postcss-discard-duplicates": "^5.0.1", + "postcss-discard-empty": "^5.0.1", + "postcss-discard-overridden": "^5.0.1", + "postcss-merge-longhand": "^5.0.2", + "postcss-merge-rules": "^5.0.2", + "postcss-minify-font-values": "^5.0.1", + "postcss-minify-gradients": "^5.0.1", + "postcss-minify-params": "^5.0.1", + "postcss-minify-selectors": "^5.1.0", + "postcss-normalize-charset": "^5.0.1", + "postcss-normalize-display-values": "^5.0.1", + "postcss-normalize-positions": "^5.0.1", + "postcss-normalize-repeat-style": "^5.0.1", + "postcss-normalize-string": "^5.0.1", + "postcss-normalize-timing-functions": "^5.0.1", + "postcss-normalize-unicode": "^5.0.1", + "postcss-normalize-url": "^5.0.2", + "postcss-normalize-whitespace": "^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", + "postcss-unique-selectors": "^5.0.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-2.0.1.tgz", + "integrity": "sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", + "dev": true + }, + "node_modules/dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "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", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "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.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": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "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/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/find": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/find/-/find-0.3.0.tgz", + "integrity": "sha512-iSd+O4OEYV/I36Zl8MdYJO0xD82wH528SaCieTVHhclgiYNe9y+yPKSwK+A7/WsmHL1EZ+pYUJBXWTL5qofksw==", + "dependencies": { + "traverse-chain": "~0.1.0" + } + }, + "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-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/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", + "dev": true + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "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/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": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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-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-color-stop/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/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-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/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/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/jszip": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.6.0.tgz", + "integrity": "sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "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", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "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/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true + }, + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "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/nanoid": { + "version": "3.1.23", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", + "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", + "dev": true, + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "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": "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": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", + "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "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/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/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "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": { + "colorette": "^1.2.2", + "nanoid": "^3.1.23", + "source-map-js": "^0.6.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-calc": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.0.0.tgz", + "integrity": "sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.0.tgz", + "integrity": "sha512-+HC6GfWU3upe5/mqmxuqYZ9B2Wl4lcoUUNkoaX59nEWV4EtADCMiBqui111Bu8R8IvaZTmqmxrqOAqjbHIwXPw==", + "dev": true, + "dependencies": { + "browserslist": "^4.16.6", + "caniuse-api": "^3.0.0", + "colord": "^2.0.1", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz", + "integrity": "sha512-C3zR1Do2BkKkCgC0g3sF8TS0koF2G+mN8xxayZx3f10cIRmTaAnpgpRQZjNekTZxM2ciSPoh2IWJm0VZx8NoQg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz", + "integrity": "sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz", + "integrity": "sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz", + "integrity": "sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz", + "integrity": "sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz", + "integrity": "sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw==", + "dev": true, + "dependencies": { + "css-color-names": "^1.0.1", + "postcss-value-parser": "^4.1.0", + "stylehacks": "^5.0.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.2.tgz", + "integrity": "sha512-5K+Md7S3GwBewfB4rjDeol6V/RZ8S+v4B66Zk2gChRqLTCC8yjnHQ601omj9TKftS19OPGqZ/XzoqpzNQQLwbg==", + "dev": true, + "dependencies": { + "browserslist": "^4.16.6", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^2.0.1", + "postcss-selector-parser": "^6.0.5", + "vendors": "^1.0.3" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz", + "integrity": "sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.1.tgz", + "integrity": "sha512-odOwBFAIn2wIv+XYRpoN2hUV3pPQlgbJ10XeXPq8UY2N+9ZG42xu45lTn/g9zZ+d70NKSQD6EOi6UiCMu3FN7g==", + "dev": true, + "dependencies": { + "cssnano-utils": "^2.0.1", + "is-color-stop": "^1.1.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz", + "integrity": "sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.2", + "browserslist": "^4.16.0", + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0", + "uniqs": "^2.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz", + "integrity": "sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.2", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz", + "integrity": "sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz", + "integrity": "sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ==", + "dev": true, + "dependencies": { + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz", + "integrity": "sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz", + "integrity": "sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w==", + "dev": true, + "dependencies": { + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz", + "integrity": "sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz", + "integrity": "sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q==", + "dev": true, + "dependencies": { + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz", + "integrity": "sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA==", + "dev": true, + "dependencies": { + "browserslist": "^4.16.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "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": "^6.0.1", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz", + "integrity": "sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "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", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz", + "integrity": "sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw==", + "dev": true, + "dependencies": { + "browserslist": "^4.16.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz", + "integrity": "sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA==", + "dev": true, + "dependencies": { + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", + "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.2.tgz", + "integrity": "sha512-YzQuFLZu3U3aheizD+B1joQ94vzPfE6BNUcSYuceNxlVnKKsOtdo6hL9/zyC168Q8EwfLSgaDSalsUGa9f2C0A==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.1.0", + "svgo": "^2.3.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz", + "integrity": "sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.2", + "postcss-selector-parser": "^6.0.5", + "uniqs": "^2.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "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/prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=4" + } + }, + "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/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "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, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/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/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/source-map-js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", + "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", + "dev": true, + "peer": true, + "engines": { + "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", + "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/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", + "integrity": "sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA==", + "dev": true, + "dependencies": { + "browserslist": "^4.16.0", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "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/svgo": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.3.1.tgz", + "integrity": "sha512-riDDIQgXpEnn0BEl9Gvhh1LNLIyiusSpt64IR8upJu7MwxnzetmF/Y57pXQD2NMX2lVyMRzXt5f2M5rO4wG7Dw==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.1.1", + "chalk": "^4.1.0", + "commander": "^7.1.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.2", + "csso": "^4.2.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/svgo/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/svgo/node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/svgo/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/svgo/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/svgo/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/svgo/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/traverse-chain": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz", + "integrity": "sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=" + }, + "node_modules/typescript": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "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/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.7", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.7.tgz", + "integrity": "sha512-Id+IKjdU0Hx+7Zx717jwLPsPeUqz7rAtuVBRLLs+qn+J2nf9NGITWVCxcijgYxBqe83C7sqsQPs6H1pyz3x9gA==", + "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/vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/vue": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.13.tgz", + "integrity": "sha512-O+pAdJkce1ooYS1XyoQtpBQr9An+Oys3w39rkqxukVO3ZD1ilYJkWBGoRuadiQEm2LLJnCL2utV4TMSf52ubjw==" + }, + "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/vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", + "dev": true + }, + "node_modules/vue-template-compiler": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.13.tgz", + "integrity": "sha512-latKAqpUjCkovB8XppW5gnZbSdYQzkf8pavsMBZYZrQcG6lAnj0EH4Ty7jMwAwFw5Cf4mybKBHlp1UTjnLPOWw==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, + "node_modules/vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "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", + "integrity": "sha1-HRlceKqbW/hHnIlblQT9TwhHmE4=", + "dev": true + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + } + }, "dependencies": { + "@babel/code-frame": { + "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.14.5" + } + }, + "@babel/helper-validator-identifier": { + "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.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.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/stream-parser": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/@codemirror/stream-parser/-/stream-parser-0.18.2.tgz", + "integrity": "sha512-3RTRmhIixcC2ps/G8So+BL0qJkwaspjyYt4smVYlSn4eNbxGK9K2RCnSmOPRv0SkuQMu3oUFbprFI/SbtZrPKg==", + "requires": { + "@codemirror/highlight": "^0.18.0", + "@codemirror/language": "^0.18.0", + "@codemirror/state": "^0.18.0", + "@codemirror/text": "^0.18.0", + "lezer": "^0.13.0", + "lezer-tree": "^0.13.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", + "integrity": "sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow==", + "dev": true + }, "@types/jquery": { "version": "3.3.34", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.34.tgz", @@ -13,16 +2486,22 @@ "@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", "integrity": "sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==", "dev": true }, - "@types/q": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", - "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, "@types/sizzle": { @@ -31,6 +2510,45 @@ "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", "dev": true }, + "@vue/component-compiler-utils": { + "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.36", + "postcss-selector-parser": "^6.0.2", + "prettier": "^1.18.2", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "dependencies": { + "postcss": { + "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", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "alphanum-sort": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", @@ -60,6 +2578,12 @@ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -67,39 +2591,22 @@ "dev": true }, "browserslist": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.11.1.tgz", - "integrity": "sha512-DCTr3kDrKEYNw6Jb9HFxVLQNaue8z+0ZfRBRjmCunKDEXEBajKDj2Y+Uelg+Pi29OnvaSGwjOsnRyNEkXzHg5g==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001038", - "electron-to-chromium": "^1.3.390", - "node-releases": "^1.1.53", - "pkg-up": "^2.0.0" - } - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", "dev": true, "requires": { - "caller-callsite": "^2.0.0" + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" } }, "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "caniuse-api": { @@ -115,9 +2622,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001040", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001040.tgz", - "integrity": "sha512-Ep0tEPeI5wCvmJNrXjE3etgfI+lkl1fTDU6Y3ZH1mhrjkPlVI9W4pcKbMo+BQLpEWKVYYp2EmYaRsqpPC3k7lQ==", + "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": { @@ -135,38 +2642,6 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" - }, - "dependencies": { - "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, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "color": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", - "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", - "dev": true, - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" } }, "color-convert": { @@ -184,14 +2659,31 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "color-string": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", - "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "colord": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.0.1.tgz", + "integrity": "sha512-vm5YpaWamD0Ov6TSG0GGmUIwstrWcfKQV/h2CmbR7PbNu41+qdB5PW9lpzhjedrpm08uuYvcXi0Oel1RLZIJuA==", + "dev": true + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, + "consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", "dev": true, "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "bluebird": "^3.1.1" } }, "core-util-is": { @@ -201,15 +2693,16 @@ "dev": true }, "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", "dev": true, "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" } }, "create-error-class": { @@ -221,54 +2714,53 @@ "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": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-1.0.1.tgz", + "integrity": "sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA==", "dev": true }, "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==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.0.3.tgz", + "integrity": "sha512-52P95mvW1SMzuRZegvpluT6yEv0FqQusydKQPZsNN5Q7hh8EwQvN8E2nwuJ16BBvNN6LcoIZXu/Bk58DAhrrxw==", "dev": true, "requires": { - "postcss": "^7.0.1", "timsort": "^0.3.0" } }, "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", "dev": true, "requires": { "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" } }, - "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 - }, "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==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "dev": true, "requires": { - "mdn-data": "2.0.4", + "mdn-data": "2.0.14", "source-map": "^0.6.1" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", + "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", "dev": true }, "cssesc": { @@ -278,159 +2770,110 @@ "dev": true }, "cssnano": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", - "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.6.tgz", + "integrity": "sha512-NiaLH/7yqGksFGsFNvSRe2IV/qmEBAeDE64dYeD8OBrgp6lE8YoMeQJMtsv5ijo6MPyhuoOvFhI94reahBRDkw==", "dev": true, "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.7", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" + "cosmiconfig": "^7.0.0", + "cssnano-preset-default": "^5.1.3", + "is-resolvable": "^1.1.0" } }, "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, - "requires": { - "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" - } - }, - "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 - }, - "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 - }, - "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==", + "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", + "cssnano-utils": "^2.0.1", + "postcss-calc": "^8.0.0", + "postcss-colormin": "^5.2.0", + "postcss-convert-values": "^5.0.1", + "postcss-discard-comments": "^5.0.1", + "postcss-discard-duplicates": "^5.0.1", + "postcss-discard-empty": "^5.0.1", + "postcss-discard-overridden": "^5.0.1", + "postcss-merge-longhand": "^5.0.2", + "postcss-merge-rules": "^5.0.2", + "postcss-minify-font-values": "^5.0.1", + "postcss-minify-gradients": "^5.0.1", + "postcss-minify-params": "^5.0.1", + "postcss-minify-selectors": "^5.1.0", + "postcss-normalize-charset": "^5.0.1", + "postcss-normalize-display-values": "^5.0.1", + "postcss-normalize-positions": "^5.0.1", + "postcss-normalize-repeat-style": "^5.0.1", + "postcss-normalize-string": "^5.0.1", + "postcss-normalize-timing-functions": "^5.0.1", + "postcss-normalize-unicode": "^5.0.1", + "postcss-normalize-url": "^5.0.2", + "postcss-normalize-whitespace": "^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", + "postcss-unique-selectors": "^5.0.1" + } + }, + "cssnano-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-2.0.1.tgz", + "integrity": "sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ==", "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "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 + "requires": {} }, "csso": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.0.3.tgz", - "integrity": "sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", "dev": true, "requires": { - "css-tree": "1.0.0-alpha.39" - }, - "dependencies": { - "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, - "requires": { - "mdn-data": "2.0.6", - "source-map": "^0.6.1" - } - }, - "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 - } + "css-tree": "^1.1.2" } }, - "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, - "requires": { - "object-keys": "^1.0.12" - } + "de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", + "dev": true }, "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", "dev": true, "requires": { "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", "entities": "^2.0.0" - }, - "dependencies": { - "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 - } } }, "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", "dev": true }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "domhandler": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", "dev": true, "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "domelementtype": "^2.2.0" } }, - "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==", + "domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", "dev": true, "requires": { - "is-obj": "^2.0.0" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" } }, "download-crx": { @@ -452,15 +2895,15 @@ "dev": true }, "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==", + "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": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", - "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true }, "error-ex": { @@ -472,35 +2915,11 @@ "is-arrayish": "^0.2.1" } }, - "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, - "requires": { - "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" - } - }, - "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, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", @@ -508,27 +2927,14 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "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 - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, + "find": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/find/-/find-0.3.0.tgz", + "integrity": "sha512-iSd+O4OEYV/I36Zl8MdYJO0xD82wH528SaCieTVHhclgiYNe9y+yPKSwK+A7/WsmHL1EZ+pYUJBXWTL5qofksw==", "requires": { - "locate-path": "^2.0.0" + "traverse-chain": "~0.1.0" } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", @@ -554,25 +2960,22 @@ "url-parse-lax": "^1.0.0" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "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==", + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "hex-color-regex": { @@ -593,12 +2996,6 @@ "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", "dev": true }, - "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 - }, "immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -606,21 +3003,15 @@ "dev": true }, "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" } }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -628,9 +3019,9 @@ "dev": true }, "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=", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", "dev": true }, "is-arrayish": { @@ -639,12 +3030,6 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "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 - }, "is-color-stop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", @@ -657,41 +3042,22 @@ "hsla-regex": "^1.0.0", "rgb-regex": "^1.0.1", "rgba-regex": "^1.0.0" + }, + "dependencies": { + "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 + } } }, - "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 - }, - "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 - }, - "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 - }, "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 }, - "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, - "requires": { - "has": "^1.0.3" - } - }, "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", @@ -710,24 +3076,6 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, - "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, - "requires": { - "html-comment-regex": "^1.1.0" - } - }, - "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, - "requires": { - "has-symbols": "^1.0.1" - } - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -744,26 +3092,16 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "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==", + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "jszip": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.4.0.tgz", - "integrity": "sha512-gZAOYuPl4EhPTXT0GjhI3o+ZAz3su6EhLrKUoAivcKqyqC7laS5JEv4XWZND9BgcDcF83vI85yGbDmDR6UhrIg==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.6.0.tgz", + "integrity": "sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ==", "dev": true, "requires": { "lie": "~3.3.0", @@ -772,6 +3110,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", @@ -781,21 +3132,16 @@ "immediate": "~3.0.5" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.memoize": { "version": "4.1.2", @@ -823,648 +3169,405 @@ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true }, - "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 - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { - "minimist": "^1.2.5" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, - "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 - }, - "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==", + "mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true }, - "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, - "requires": { - "boolbase": "~1.0.0" - } - }, - "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==", + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", "dev": true, "requires": { - "download-crx": "^1.1.0", - "unzip-crx-3": "^0.2.0" + "source-map": "^0.6.1" } }, - "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 - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "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, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "minimist": "^1.2.5" } }, - "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==", + "nanoid": { + "version": "3.1.23", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", + "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } + "peer": true }, - "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, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } + "node-releases": { + "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": "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 }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "nth-check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", + "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", "dev": true, "requires": { - "p-try": "^1.0.0" + "boolbase": "^1.0.0" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "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, "requires": { - "p-limit": "^1.1.0" + "download-crx": "^1.1.0", + "unzip-crx-3": "^0.2.0" } }, - "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 - }, "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "callsites": "^3.0.0" } }, - "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 - }, - "pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { - "find-up": "^2.1.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "postcss": { - "version": "7.0.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", - "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "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": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" + "colorette": "^1.2.2", + "nanoid": "^3.1.23", + "source-map-js": "^0.6.2" } }, "postcss-calc": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.2.tgz", - "integrity": "sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.0.0.tgz", + "integrity": "sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g==", "dev": true, "requires": { - "postcss": "^7.0.27", "postcss-selector-parser": "^6.0.2", "postcss-value-parser": "^4.0.2" } }, "postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.0.tgz", + "integrity": "sha512-+HC6GfWU3upe5/mqmxuqYZ9B2Wl4lcoUUNkoaX59nEWV4EtADCMiBqui111Bu8R8IvaZTmqmxrqOAqjbHIwXPw==", "dev": true, "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "browserslist": "^4.16.6", + "caniuse-api": "^3.0.0", + "colord": "^2.0.1", + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz", + "integrity": "sha512-C3zR1Do2BkKkCgC0g3sF8TS0koF2G+mN8xxayZx3f10cIRmTaAnpgpRQZjNekTZxM2ciSPoh2IWJm0VZx8NoQg==", "dev": true, "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz", + "integrity": "sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg==", "dev": true, - "requires": { - "postcss": "^7.0.0" - } + "requires": {} }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz", + "integrity": "sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA==", "dev": true, - "requires": { - "postcss": "^7.0.0" - } + "requires": {} }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz", + "integrity": "sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw==", "dev": true, - "requires": { - "postcss": "^7.0.0" - } + "requires": {} }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz", + "integrity": "sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q==", "dev": true, - "requires": { - "postcss": "^7.0.0" - } + "requires": {} }, "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==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz", + "integrity": "sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw==", "dev": true, "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "dependencies": { - "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 - } + "css-color-names": "^1.0.1", + "postcss-value-parser": "^4.1.0", + "stylehacks": "^5.0.1" } }, "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==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.2.tgz", + "integrity": "sha512-5K+Md7S3GwBewfB4rjDeol6V/RZ8S+v4B66Zk2gChRqLTCC8yjnHQ601omj9TKftS19OPGqZ/XzoqpzNQQLwbg==", "dev": true, "requires": { - "browserslist": "^4.0.0", + "browserslist": "^4.16.6", "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" - }, - "dependencies": { - "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, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } + "cssnano-utils": "^2.0.1", + "postcss-selector-parser": "^6.0.5", + "vendors": "^1.0.3" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz", + "integrity": "sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA==", "dev": true, "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.1.tgz", + "integrity": "sha512-odOwBFAIn2wIv+XYRpoN2hUV3pPQlgbJ10XeXPq8UY2N+9ZG42xu45lTn/g9zZ+d70NKSQD6EOi6UiCMu3FN7g==", "dev": true, "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "cssnano-utils": "^2.0.1", + "is-color-stop": "^1.1.0", + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz", + "integrity": "sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw==", "dev": true, "requires": { - "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", + "alphanum-sort": "^1.0.2", + "browserslist": "^4.16.0", + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0", "uniqs": "^2.0.0" - }, - "dependencies": { - "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 - } } }, "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==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz", + "integrity": "sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og==", "dev": true, "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "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, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } + "alphanum-sort": "^1.0.2", + "postcss-selector-parser": "^6.0.5" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz", + "integrity": "sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg==", "dev": true, - "requires": { - "postcss": "^7.0.0" - } + "requires": {} }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz", + "integrity": "sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ==", "dev": true, "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz", + "integrity": "sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg==", "dev": true, "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz", + "integrity": "sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w==", "dev": true, "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz", + "integrity": "sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA==", "dev": true, "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz", + "integrity": "sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q==", "dev": true, "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz", + "integrity": "sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA==", "dev": true, "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "browserslist": "^4.16.0", + "postcss-value-parser": "^4.1.0" } }, "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==", + "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": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "is-absolute-url": "^3.0.3", + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz", + "integrity": "sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA==", "dev": true, "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "postcss-value-parser": "^4.1.0" } }, "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==", + "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-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz", + "integrity": "sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw==", "dev": true, "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" + "browserslist": "^4.16.0", + "caniuse-api": "^3.0.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz", + "integrity": "sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA==", "dev": true, "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "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 - } + "cssnano-utils": "^2.0.1", + "postcss-value-parser": "^4.1.0" } }, "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==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", + "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", "dev": true, "requires": { "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" + "util-deprecate": "^1.0.2" } }, "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==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.2.tgz", + "integrity": "sha512-YzQuFLZu3U3aheizD+B1joQ94vzPfE6BNUcSYuceNxlVnKKsOtdo6hL9/zyC168Q8EwfLSgaDSalsUGa9f2C0A==", "dev": true, "requires": { - "is-svg": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "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 - } + "postcss-value-parser": "^4.1.0", + "svgo": "^2.3.0" } }, "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==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz", + "integrity": "sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w==", "dev": true, "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", + "alphanum-sort": "^1.0.2", + "postcss-selector-parser": "^6.0.5", "uniqs": "^2.0.0" } }, "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==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", "dev": true }, "prepend-http": { @@ -1473,16 +3576,23 @@ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", "dev": true }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true, + "optional": true + }, "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 }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "readable-stream": { @@ -1509,9 +3619,9 @@ } }, "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "rgb-regex": { @@ -1532,41 +3642,30 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, "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 }, - "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, - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "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 - } - } - }, "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 }, + "source-map-js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", + "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", + "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", @@ -1579,48 +3678,6 @@ "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, - "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, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "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, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimstart": "^1.0.0" - } - }, - "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, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimend": "^1.0.0" - } - }, - "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, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -1638,58 +3695,94 @@ } } }, + "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": "4.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz", + "integrity": "sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA==", "dev": true, "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "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, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } + "browserslist": "^4.16.0", + "postcss-selector-parser": "^6.0.4" } }, "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==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" } }, "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "dev": true, - "requires": { - "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" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.3.1.tgz", + "integrity": "sha512-riDDIQgXpEnn0BEl9Gvhh1LNLIyiusSpt64IR8upJu7MwxnzetmF/Y57pXQD2NMX2lVyMRzXt5f2M5rO4wG7Dw==", + "dev": true, + "requires": { + "@trysound/sax": "0.1.1", + "chalk": "^4.1.0", + "commander": "^7.1.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.2", + "csso": "^4.2.0", + "stable": "^0.1.8" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "timed-out": { @@ -1704,16 +3797,15 @@ "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", "dev": true }, - "typescript": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", - "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", - "dev": true + "traverse-chain": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz", + "integrity": "sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=" }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "typescript": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", "dev": true }, "uniqs": { @@ -1722,12 +3814,6 @@ "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", "dev": true }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, "unzip-crx-3": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz", @@ -1746,9 +3832,9 @@ "dev": true }, "urijs": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", - "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==", + "version": "1.19.7", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.7.tgz", + "integrity": "sha512-Id+IKjdU0Hx+7Zx717jwLPsPeUqz7rAtuVBRLLs+qn+J2nf9NGITWVCxcijgYxBqe83C7sqsQPs6H1pyz3x9gA==", "dev": true }, "url-parse-lax": { @@ -1766,18 +3852,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "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, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, "vendors": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", @@ -1785,9 +3859,9 @@ "dev": true }, "vue": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz", - "integrity": "sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==" + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.13.tgz", + "integrity": "sha512-O+pAdJkce1ooYS1XyoQtpBQr9An+Oys3w39rkqxukVO3ZD1ilYJkWBGoRuadiQEm2LLJnCL2utV4TMSf52ubjw==" }, "vue-clickaway": { "version": "2.2.2", @@ -1805,11 +3879,50 @@ "vue-clickaway": "^2.2.2" } }, + "vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", + "dev": true + }, + "vue-template-compiler": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.13.tgz", + "integrity": "sha512-latKAqpUjCkovB8XppW5gnZbSdYQzkf8pavsMBZYZrQcG6lAnj0EH4Ty7jMwAwFw5Cf4mybKBHlp1UTjnLPOWw==", + "dev": true, + "requires": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, + "vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "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", "integrity": "sha1-HRlceKqbW/hHnIlblQT9TwhHmE4=", "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true } } } diff --git a/package.json b/package.json index 46cd75246..ac0656b62 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "Synthestic Separation Logic -- low-level pointer program synthesis", "main": "dist/index.html", + "type": "module", "repository": { "type": "git", "url": "git+https://github.com/TyGuS/suslik.git" @@ -14,17 +15,33 @@ }, "homepage": "https://github.com/TyGuS/suslik#readme", "dependencies": { + "@codemirror/basic-setup": "^0.18.2", + "@codemirror/stream-parser": "^0.18.2", "array-equal": "^1.0.0", + "find": "^0.3.0", "jquery": "^3.5.0", - "vue": "^2.6.11", + "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", - "cssnano": "^4.1.10", - "nw-vue-devtools-prebuilt": "0.0.10", - "typescript": "^3.8.3" + "@vue/component-compiler-utils": "^3.2.0", + "cssnano": "^5.0.6", + "nw-vue-devtools-prebuilt": "^0.0.10", + "typescript": "^4.3.2", + "vue-hot-reload-api": "^2.3.4", + "vue-template-compiler": "^2.6.13" + }, + "scripts": { + "build": "npx --package=parcel-bundler@1.12.5 -- parcel build --no-minify src/viz/index.html && node src/viz/scripts/bundle-benchmarks-for-web.mjs", + "watch": "parcel watch --public-url=. --hmr-hostname=localhost src/viz/index.html" + }, + "posthtml": { + "recognizeSelfClosing": true }, "browserslist": [ "Chrome 80" diff --git a/project/assembly.sbt b/project/assembly.sbt index 98ca55417..91877e293 100644 --- a/project/assembly.sbt +++ b/project/assembly.sbt @@ -1 +1 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.7") \ No newline at end of file +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.0.0") \ No newline at end of file diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 000000000..10fd9eee0 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.5.5 diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 000000000..8e80c625e --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.7.6") diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf new file mode 100644 index 000000000..f5ee6f3fe --- /dev/null +++ b/src/main/resources/application.conf @@ -0,0 +1,14 @@ +suslik { + server { + port = 8033 + } +} + +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/LanguageUtils.scala b/src/main/scala/org/tygus/suslik/LanguageUtils.scala index c165817a2..9e779d6af 100644 --- a/src/main/scala/org/tygus/suslik/LanguageUtils.scala +++ b/src/main/scala/org/tygus/suslik/LanguageUtils.scala @@ -1,5 +1,7 @@ package org.tygus.suslik +import scala.util.DynamicVariable + /** * @author Ilya Sergey */ @@ -8,17 +10,17 @@ object LanguageUtils { private val init = 0 - private var now = init + private val now = new DynamicVariable(init) def resetFreshNameGenerator(): Unit = { - now = init + now.value = init } val cardinalityPrefix = "_alpha_" def getTotallyFreshName(prefix: String): String = { - val s = s"$prefix$now" - now = now + 1 + val s = s"$prefix${now.value}" + now.value += 1 s } 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/certification/source/SuslikProofStep.scala b/src/main/scala/org/tygus/suslik/certification/source/SuslikProofStep.scala index 462ec19d7..0e83b7817 100644 --- a/src/main/scala/org/tygus/suslik/certification/source/SuslikProofStep.scala +++ b/src/main/scala/org/tygus/suslik/certification/source/SuslikProofStep.scala @@ -356,7 +356,7 @@ case class AbduceCall( } case _ => fail_with_bad_proof_structure() } - case UnificationRules.HeapUnifyPointer => node.kont match { + case UnificationRules.UnifyPointerFlat => node.kont match { case SubstVarProducer(from, to) >> IdProducer >> ExtractHelper(goal) => node.children match { case ::(head, Nil) => SuslikProofStep.HeapUnifyPointer(from, to) diff --git a/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala new file mode 100644 index 000000000..0d25304e3 --- /dev/null +++ b/src/main/scala/org/tygus/suslik/interaction/SynthesisServer.scala @@ -0,0 +1,410 @@ +package org.tygus.suslik.interaction + +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.{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.LanguageUtils +import org.tygus.suslik.language.Statements +import org.tygus.suslik.logic.{Environment, Specifications} +import org.tygus.suslik.report.{Log, ProofTrace, ProofTraceJson} +import org.tygus.suslik.report.ProofTraceJson.GoalEntry +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._ +import org.tygus.suslik.synthesis.{InputFormat, SynConfig, Synthesis, SynthesisRunner, SynthesisRunnerUtil} +import org.tygus.suslik.util.SynStats + +import scala.collection.mutable + + +class SynthesisServer { + + val config: SynConfig = SynConfig() + + /* Server configuration */ + protected def port(implicit system: ActorSystem[_]): Int = { + val envPort = System.getenv("PORT") + if (envPort != null) Integer.parseInt(envPort) + else system.settings.config.getInt("suslik.server.port") + } + + def start(): Unit = { + val root = Behaviors.setup[Nothing] { context => + implicit val system: ActorSystem[_] = context.system + startHttpServer(routes, port) + Behaviors.empty + } + ActorSystem[Nothing](root, "SynthesisServer") + } + + /** + * Server startup boilerplate. + */ + private def startHttpServer(routes: Route, port: Int)(implicit system: ActorSystem[_]): Unit = { + import system.executionContext + Http().newServerAt("0.0.0.0", port).bind(routes) + .onComplete { + case Success(binding) => + val address = binding.localAddress + system.log.info("Server online at http://{}:{}/", address.getHostString, address.getPort) + case Failure(ex) => + system.log.error("Failed to bind HTTP endpoint, terminating system", ex) + system.terminate() + } + } + + 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() + } + + private def routes(implicit system: ActorSystem[_]) = { + import system.executionContext + concat( + pathSingleSlash { + concat( + handleWebSocketMessages({ + val session = new ClientSessionSynthesis() + session.wsFlow + }), + get { + getFromFile("./dist/index.html") + } + ) + }, + getFromDirectory("./dist") + ) + } +} + +object SynthesisServer { + def main(args: Array[String]): Unit = { + val server = new SynthesisServer + server.start() + } +} + +/** + * A synthesizer that sends and receives choices via async queues. + * Data is serialized in and out using a JSON format. + */ +class AsyncSynthesisRunner extends SynthesisRunnerUtil { + import upickle.default.{Writer, write} + import AsyncSynthesisRunner._ + + 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) + + val config: SynConfig = SynConfig(timeOut = 15000, maxOpenDepth = 2, maxCloseDepth = 2) + protected var isynth: IterativeUnorderedSynthesis = _ + + protected val trace: ProofTraceJson = 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)) + } + + def goAutomatic(spec: SpecMessage): Unit = { + def inThread(op: => Unit): Unit = { new Thread(() => op).start() } + inThread { + LanguageUtils.resetFreshNameGenerator() + synthesizeFromSpec(spec) + } + } + + def goInteractive(spec: SpecMessage): Unit = { + val specConfig = configFromSpec(spec) + val (funSpec, env, sketch) = prepareSynthesisTask(textFromSpec(spec), specConfig) + createSynthesizer(env) // just to initialize isynth :/ + + val initialGoal = Specifications.topLevelGoal(funSpec, env, sketch) + trace.add(OrNode(Vector(), initialGoal, None)) + } + + /** + * Creates a `PhasedSynthesizer` that expands goals based on input sent + * from the client (through `inbound`) and reports everything back to the + * client in JSON format (through `outbound`). + * @param env synthesis environment + * @return a configured `Synthesis` instance + */ + override def createSynthesizer(env: Environment): Synthesis = { + val tactic = + if (env.config.simple) + new AutomaticSimple(env.config) + else + new AutomaticPhased(env.config) + /** @todo this is defunct */ + /* + new PhasedSynthesis(env.config) { + override def filterExpansions(allExpansions: Seq[Rules.RuleResult]): Seq[Rules.RuleResult] = { + allExpansions.find(_.subgoals.isEmpty) match { + case Some(fin) => Seq(fin) + case _ => + outbound.put(serializeChoices(allExpansions)) + val choice = inbound.take() + allExpansions.filter(_.subgoals.exists(goal => goal.label.pp.contains(choice))) + } + } + }*/ + + isynth = new IterativeUnorderedSynthesis(tactic, log, trace)(env.stats, env.config) + isynth + } + + /** + * Wraps parent implementation, reporting success or failure to the client. + */ + override def synthesizeFromSpec(testName: String, text: String, out: String, + params: SynConfig): List[Statements.Procedure] = + wrapError(sticky = true) { + try { + val ret = super.synthesizeFromSpec(testName, text, out, params) + outbound.put(write(SynthesisResultEntry(ret.map(x => SynthesizedProcedureEntry(x.pp))))) + ret + } + catch { + case _: InterruptedException => List() /* can happen if `inbound` is cancelled */ + } + finally { + outbound.put(serializeStats()) + } + } + + def synthesizeFromSpec(spec: SpecMessage): List[Statements.Procedure] = + synthesizeFromSpec(spec.name, textFromSpec(spec), + noOutputCheck, configFromSpec(spec)) + + def textFromSpec(spec: SpecMessage): String = (spec.spec.defs :+ spec.spec.in).mkString("\n") + + def configFromSpec(spec: SpecMessage): SynConfig = { + val configOptions = spec.spec.config.inputFormat.toSeq map { fmt => + (c: SynConfig) => c.copy(inputFormat = parseInputFormatSpecifier(fmt)) + } + val startConfig = configOptions.foldLeft(config)((c, f) => f(c)) + SynthesisRunner.parseParams("." +: spec.params.toArray, startConfig) + } + + import org.tygus.suslik.synthesis.{dotSyn, dotSus} + + def parseInputFormatSpecifier(fmt: String): InputFormat = fmt match { + case "syn" => dotSyn; case "sus" => dotSus; + case _ => throw new RuntimeException(s"unrecognized input format '$fmt'") + } + + def grow(id: NodeId): Unit = + 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 = wrapError(sticky = false)(op) + + protected def wrapError[T](sticky: Boolean)(op: => T): T = { + try op catch { + case e: Throwable => + logger.error("Error", e) + outbound.put(write(SynthesisErrorEntry(e.toString, sticky))); throw e + } + } + + protected def serializeChoices(allExpansions: Seq[Rules.RuleResult]): String = + write(allExpansions.map(ExpansionChoiceEntry.from)) + + protected def serializeStats(): String = if (isynth != null) write(isynth.serializeStats()) else "{}" +} + +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 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(): Unit = { 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) { + + def grow(node: OrNode): Unit = { + val goal = node.goal + implicit val log: Log = this.log + implicit val ctx: Log.Context = Log.Context(goal) + + val expansions = ProofTrace.using(trace) { 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) + } + } + } + + protected def submitNodes(nodes: Seq[OrNode]): Unit = { + for (node <- nodes) trace.add(node) + } + + def serializeStats(): SynthesisStatsEntry = + SynthesisStatsEntry("SynthesisStatsEntry", stats.duration) + } + + type GoalLabel = String + + case class ExpansionChoiceEntry(from: Set[GoalLabel], + rule: String, + subgoals: Seq[GoalEntry]) + + object ExpansionChoiceEntry { + def from(rr: Rules.RuleResult): ExpansionChoiceEntry = + ExpansionChoiceEntry(rr.subgoals.flatMap(_.parent).map(_.label.pp).toSet, + rr.rule.toString, + rr.subgoals.map(GoalEntry(_))) + + implicit val rw: RW[ExpansionChoiceEntry] = macroRW + } + + case class SynthesisResultEntry(procs: Seq[SynthesizedProcedureEntry]) + object SynthesisResultEntry { + implicit val rw: RW[SynthesisResultEntry] = macroRW + } + + case class SynthesizedProcedureEntry(pp: String) + object SynthesizedProcedureEntry { + implicit val rw: RW[SynthesizedProcedureEntry] = macroRW + } + + case class SynthesisErrorEntry(error: String, sticky: Boolean = false) + object SynthesisErrorEntry { + implicit val rw: RW[SynthesisErrorEntry] = macroRW + } + + case class SynthesisStatsEntry(tag: String, duration: Long) + object SynthesisStatsEntry { + implicit val rw: RW[SynthesisStatsEntry] = macroRW + } + + /* Messages sent from the client */ + + sealed abstract class ClientMessage(val tag: String) + object ClientMessage { implicit val rw: RW[ClientMessage] = macroRW } + + case class SpecMessage(mode: String = "automatic", name: String, + spec: SpecEntry, + params: Seq[String] = Seq()) extends ClientMessage("Spec") + object SpecMessage { + implicit val rw: RW[SpecMessage] = macroRW + } + + case class SpecEntry(defs: Seq[String], in: String, + config: SpecConfigEntry = SpecConfigEntry()) + object SpecEntry { + implicit val rw: RW[SpecEntry] = macroRW + } + + case class SpecConfigEntry(inputFormat: Option[String] = None) + object SpecConfigEntry { + implicit val rw: RW[SpecConfigEntry] = 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 + } +} + +/** + * Connects `AsyncSynthesisRunner` to an HTTP client. + */ +class ClientSessionSynthesis(implicit ec: ExecutionContext) extends AsyncSynthesisRunner { + import upickle.default.read + import AsyncSynthesisRunner._ + + protected val HARD_MAX_TIMEOUT: Long = 3600 * 1000 + + { + logger.info("client session started") + } + + def subscribe: Source[String, _] = + Source.unfoldAsync(())(_ => Future { + try Some((), outbound.take()) + catch { case _: InterruptedException => None } + }) + + def offer: Sink[String, Future[Done]] = + Sink.foreachAsync[String](1) { s => Future { wrapError { + read[ClientMessage](s) match { + case sp@SpecMessage(mode, _, _, _) => mode match { + case "automatic" => goAutomatic(sp) + case "interactive" => goInteractive(sp) + } + case ChooseMessage(choice) => inbound.put(choice) + case ExpandRequestMessage(id) => grow(id) + } + }}} + + def done(d: Done): Unit = { + outbound.cancel(); inbound.cancel() + logger.info(s"client session ended; $d") + } + + def wsFlow: Flow[Message, Message, NotUsed] = + 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))), + subscribe.map(TextMessage(_))) + + protected def adjustConfig(config: SynConfig): SynConfig = + config.copy(timeOut = Math.min(config.timeOut, HARD_MAX_TIMEOUT)) + + override def synthesizeFromSpec(testName: String, text: String, out: String, + params: SynConfig): List[Statements.Procedure] = + super.synthesizeFromSpec(testName, text, out, adjustConfig(params)) +} \ No newline at end of file diff --git a/src/main/scala/org/tygus/suslik/language/Expressions.scala b/src/main/scala/org/tygus/suslik/language/Expressions.scala index 58ed7f9b6..9d9134de6 100644 --- a/src/main/scala/org/tygus/suslik/language/Expressions.scala +++ b/src/main/scala/org/tygus/suslik/language/Expressions.scala @@ -480,6 +480,12 @@ object Expressions { e.resolveOverloading(gamma)) } + + def unifySyntactic(that: Expr, unificationVars: Set[Var]): Option[Subst] = (this, that) match { + case (_, _) if this == that => Some(Map()) + case (v@Var(_), _) if unificationVars.contains(v) => Some(Map(v -> that)) + case _ => None + } } // Program-level variable: program-level or ghost diff --git a/src/main/scala/org/tygus/suslik/logic/Preprocessor.scala b/src/main/scala/org/tygus/suslik/logic/Preprocessor.scala index b17c75c70..7948b79da 100644 --- a/src/main/scala/org/tygus/suslik/logic/Preprocessor.scala +++ b/src/main/scala/org/tygus/suslik/logic/Preprocessor.scala @@ -17,11 +17,10 @@ object Preprocessor extends SepLogicUtils { val Program(preds, funs, goal) = prog val funMap = funs.map(fs => fs.name -> fs).toMap - // [Cardinality] Instrument predicates with missing cardinality constraints - // val newPreds = preds + // [Cardinality] Instrument predicates with missing cardinality constraints, unless in simple mode + val newPreds = if (params.simple) preds + else preds.map(p => p.copy(clauses = p.clauses.map(addCardConstraints))) - // Enable predicate instrumentation - val newPreds = preds.map(p => p.copy(clauses = p.clauses.map(addCardConstraints))) val predMap = newPreds.map(ps => ps.name -> ps).toMap (List(goal.spec), predMap, funMap, goal.body) } diff --git a/src/main/scala/org/tygus/suslik/logic/PureLogicUtils.scala b/src/main/scala/org/tygus/suslik/logic/PureLogicUtils.scala index 60580246e..aed5b4cb9 100644 --- a/src/main/scala/org/tygus/suslik/logic/PureLogicUtils.scala +++ b/src/main/scala/org/tygus/suslik/logic/PureLogicUtils.scala @@ -162,6 +162,14 @@ trait PureLogicUtils { None } + def extractEquality(e: Expr): Option[(Expr, Expr)] = e match { + case BinaryExpr(OpEq, l, r) => Some(l, r) + case BinaryExpr(OpBoolEq, l, r) => Some(l, r) + case BinaryExpr(OpSetEq, l, r) => Some(l, r) + case BinaryExpr(OpIntervalEq, l, r) => Some(l, r) + case _ => None + } + /** * Assemble a formula from a list of conjunctions */ diff --git a/src/main/scala/org/tygus/suslik/logic/SpatialFormulas.scala b/src/main/scala/org/tygus/suslik/logic/SpatialFormulas.scala index feb6bd79a..440f189e2 100644 --- a/src/main/scala/org/tygus/suslik/logic/SpatialFormulas.scala +++ b/src/main/scala/org/tygus/suslik/logic/SpatialFormulas.scala @@ -30,6 +30,10 @@ sealed abstract class Heaplet extends PrettyPrinting with HasExpressions[Heaplet // produce pairs of expressions that must be equal for the this and that to be the same heaplet def unify(that: Heaplet): Option[ExprSubst] + // Unify syntactically: find a subst for existentials in this + // that makes it syntactically equal to that + def unifySyntactic(that: Heaplet, unificationVars: Set[Var]): Option[Subst] + def compare(that: Heaplet): Int = this.pp.compare(that.pp) def resolve(gamma: Gamma, env: Environment): Option[Gamma] @@ -97,6 +101,15 @@ case class PointsTo(loc: Expr, offset: Int = 0, value: Expr) extends Heaplet { case PointsTo(l, o, v) if l == loc && o == offset => Some(Map(value -> v)) case _ => None } + + override def unifySyntactic(that: Heaplet, unificationVars: Set[Var]): Option[Subst] = that match { + case PointsTo(l, o, v) if o == offset => + for { + sub1 <- loc.unifySyntactic(l, unificationVars) + sub2 <- value.subst(sub1).unifySyntactic(v.subst(sub1), unificationVars) + } yield sub1 ++ sub2 + case _ => None + } } /** @@ -125,6 +138,11 @@ case class Block(loc: Expr, sz: Int) extends Heaplet { case Block(l, s) if sz == s => Some(Map(loc -> l)) case _ => None } + + override def unifySyntactic(that: Heaplet, unificationVars: Set[Var]): Option[Subst] = that match { + case Block(l, s) if sz == s => loc.unifySyntactic(l, unificationVars) + case _ => None + } } case class PTag(calls: Int = 0, unrolls: Int = 0) extends PrettyPrinting { @@ -136,7 +154,7 @@ case class PTag(calls: Int = 0, unrolls: Int = 0) extends PrettyPrinting { /** * - * @card is a cardinality of a current call. + * @param card is a cardinality of a current call. * * Predicate application */ @@ -147,7 +165,8 @@ case class SApp(pred: Ident, args: Seq[Expr], tag: PTag, card: Expr) extends Hea override def pp: String = { def ppCard(e: Expr) = s"<${e.pp}>" - s"$pred(${args.map(_.pp).mkString(", ")})${ppCard(card)}${tag.pp}" +// s"$pred(${args.map(_.pp).mkString(", ")})${ppCard(card)}${tag.pp}" + s"$pred(${args.map(_.pp).mkString(", ")})${ppCard(card)}" } @@ -192,6 +211,16 @@ case class SApp(pred: Ident, args: Seq[Expr], tag: PTag, card: Expr) extends Hea case SApp(p, as, _, c) if pred == p => Some((card :: args.toList).zip(c :: as.toList).toMap) case _ => None } + + override def unifySyntactic(that: Heaplet, unificationVars: Set[Var]): Option[Subst] = that match { + case SApp(p, Seq(), _, c) if pred == p => card.unifySyntactic(c, unificationVars) + case app@SApp(p, a +: as, _, _) if pred == p => for { + sub1 <- args.head.unifySyntactic(a, unificationVars) + sub2 <- this.copy(args = args.tail).subst(sub1).unifySyntactic(app.copy(args = as), unificationVars) + } yield sub1 ++ sub2 + case _ => None + } + } diff --git a/src/main/scala/org/tygus/suslik/logic/Specifications.scala b/src/main/scala/org/tygus/suslik/logic/Specifications.scala index da4ae2a2f..92c85bc68 100644 --- a/src/main/scala/org/tygus/suslik/logic/Specifications.scala +++ b/src/main/scala/org/tygus/suslik/logic/Specifications.scala @@ -1,5 +1,6 @@ package org.tygus.suslik.logic +import org.tygus.suslik.LanguageUtils import org.tygus.suslik.language.Expressions._ import org.tygus.suslik.language.Statements._ import org.tygus.suslik.language._ @@ -118,17 +119,20 @@ object Specifications extends SepLogicUtils { extends PrettyPrinting with PureLogicUtils { - override def pp: String = + val uid: String = LanguageUtils.getTotallyFreshName("goal") + + override def pp: String = { + def postWithCall: String = { + val actualCG = callGoal.get.applySubstitution + s"${post.pp.init} ** ...}\n${actualCG.call.pp}${actualCG.calleePost.pp.init} ** ...}\n...\n${actualCG.callerPost.pp}" + } + // s"${label.pp}\n" + s"${programVars.map { v => s"${getType(v).pp} ${v.pp}" }.mkString(", ")} " + s"[${universalGhosts.map { v => s"${getType(v).pp} ${v.pp}" }.mkString(", ")}]" + s"[${existentials.map { v => s"${getType(v).pp} ${v.pp}" }.mkString(", ")}] |-\n" + s"${pre.pp}\n${sketch.pp}" + (if (callGoal.isEmpty) post.pp else postWithCall) - - def postWithCall: String = { - val actualCG = callGoal.get.applySubstitution - s"${post.pp.init} ** ...}\n${actualCG.call.pp}${actualCG.calleePost.pp.init} ** ...}\n...\n${actualCG.callerPost.pp}" } lazy val splitPost: (PFormula, PFormula) = { @@ -225,8 +229,11 @@ object Specifications extends SepLogicUtils { // Variables currently used only in specs def ghosts: Set[Var] = pre.vars ++ post.vars -- programVars - // Currently used ghosts that appear only in the postcondition - def existentials: Set[Var] = post.vars -- allUniversals + // Variables used in the suspended call (if it exists) + private def callVars: Set[Var] = callGoal.map(_.actualCall.args.flatMap(_.vars).toSet).getOrElse(Set()) + + // Currently used ghosts that appear only in the postcondition (or suspened call) + def existentials: Set[Var] = post.vars ++ callVars -- allUniversals // Determine whether `x` is a ghost variable wrt. given spec and gamma def isGhost(x: Var): Boolean = ghosts.contains(x) @@ -294,6 +301,11 @@ object Specifications extends SepLogicUtils { // Label of the top-level goal def topLabel: GoalLabel = GoalLabel(List(0), List()) + def topLevelGoal(funSpec: FunSpec, env: Environment, sketch: Statement): Goal = { + val FunSpec(name, _, formals, pre, post, var_decl) = funSpec + topLevelGoal(pre, post, formals, name, env, sketch, var_decl) + } + def topLevelGoal(pre: Assertion, post: Assertion, formals: Formals, fname: String, env: Environment, sketch: Statement, vars_decl: Formals): Goal = { val gamma0 = (formals ++ vars_decl).toMap // initial environemnt: derived from the formals val gamma = resolvePrePost(gamma0, env, pre, post) @@ -312,7 +324,7 @@ object Specifications extends SepLogicUtils { * when in call abduction mode * @param callerPre precondition of the goal where call abduction started * @param callerPost postcondition of the goal where call abduction started - * @param calleePost postcondiiton of the companion goal + * @param calleePost postcondition of the companion goal * @param call call statement */ case class SuspendedCallGoal(callerPre: Assertion, diff --git a/src/main/scala/org/tygus/suslik/logic/smt/package.scala b/src/main/scala/org/tygus/suslik/logic/smt/package.scala index c4018973e..b1de9d6e4 100644 --- a/src/main/scala/org/tygus/suslik/logic/smt/package.scala +++ b/src/main/scala/org/tygus/suslik/logic/smt/package.scala @@ -1,26 +1,26 @@ package org.tygus.suslik.logic -import org.bitbucket.franck44.scalasmt.configurations.SMTInit -import org.bitbucket.franck44.scalasmt.configurations.SMTLogics.QF_LIA -import org.bitbucket.franck44.scalasmt.configurations.SMTOptions.MODELS -import org.bitbucket.franck44.scalasmt.interpreters.SMTSolver - /** * @author Ilya Sergey */ package object smt { + val LOGGER_NAMES = List("org.bitbucket.franck44", "smt2", + "org.tygus.suslik.logic.smt", "class org.tygus.suslik.logic.smt") + def disableLogging() { - org.slf4j.LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) + for (name <- LOGGER_NAMES) + org.slf4j.LoggerFactory.getLogger(name) .asInstanceOf[ch.qos.logback.classic.Logger] .setLevel(ch.qos.logback.classic.Level.WARN) - } + } def infoLogging() { - org.slf4j.LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) + for (name <- LOGGER_NAMES) + org.slf4j.LoggerFactory.getLogger(name) .asInstanceOf[ch.qos.logback.classic.Logger] .setLevel(ch.qos.logback.classic.Level.INFO) - } + } } diff --git a/src/main/scala/org/tygus/suslik/parsing/SSLParser.scala b/src/main/scala/org/tygus/suslik/parsing/SSLParser.scala index 22ceabd33..c02738404 100644 --- a/src/main/scala/org/tygus/suslik/parsing/SSLParser.scala +++ b/src/main/scala/org/tygus/suslik/parsing/SSLParser.scala @@ -1,18 +1,18 @@ package org.tygus.suslik.parsing -import org.tygus.suslik.LanguageUtils.{cardinalityPrefix, getTotallyFreshName} import org.tygus.suslik.language.Expressions._ import org.tygus.suslik.language.Statements._ import org.tygus.suslik.language._ import org.tygus.suslik.logic.Specifications._ import org.tygus.suslik.logic._ -import org.tygus.suslik.synthesis.SynthesisException +import org.tygus.suslik.synthesis._ +import org.tygus.suslik.LanguageUtils._ import scala.annotation.tailrec import scala.collection.mutable.ListBuffer import scala.util.parsing.combinator.syntactical.StandardTokenParsers -class SSLParser extends StandardTokenParsers with SepLogicUtils { +class SSLParser(config: SynConfig = defaultConfig) extends StandardTokenParsers with SepLogicUtils { // Modified repN def repAll[T](p: => Parser[T]): Parser[List[T]] = @@ -128,11 +128,14 @@ class SSLParser extends StandardTokenParsers with SepLogicUtils { } } + private def defaultCardParameter: Expr = if (config.simple) IntConst(0) + else Var(getTotallyFreshName(cardinalityPrefix)) + def heaplet: Parser[Heaplet] = ( (identWithOffset <~ ":->") ~ expr ^^ { case (a, o) ~ b => PointsTo(Var(a), o, b) } ||| "[" ~> (ident ~ ("," ~> numericLit)) <~ "]" ^^ { case a ~ s => Block(Var(a), Integer.parseInt(s)) } ||| ident ~ ("(" ~> rep1sep(expr, ",") <~ ")") ~ opt("<" ~> expr <~ ">") ^^ { - case name ~ args ~ v => SApp(name, args, PTag(), v.getOrElse(Var(getTotallyFreshName(cardinalityPrefix)))) + case name ~ args ~ v => SApp(name, args, PTag(), v.getOrElse(defaultCardParameter)) } ) @@ -154,10 +157,6 @@ class SSLParser extends StandardTokenParsers with SepLogicUtils { opt("[" ~> ident <~ "]") ~ (("{" ~ opt("|")) ~> rep1sep(indClause, "|") <~ "}") ^^ { case name ~ formals ~ card ~ clauses => - val c = card match { - case Some(s) => s - case None => cardName(name) - } InductivePredicate(name, formals, clauses) } 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/report/ProofTrace.scala b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala index e056e7599..78c7c0182 100644 --- a/src/main/scala/org/tygus/suslik/report/ProofTrace.scala +++ b/src/main/scala/org/tygus/suslik/report/ProofTrace.scala @@ -1,16 +1,22 @@ 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 scala.language.implicitConversions +import scala.util.DynamicVariable +import org.tygus.suslik.language.{Expressions, PrettyPrinting} +import org.tygus.suslik.language.Expressions.{ExprSubst, Subst} +import org.tygus.suslik.logic.{Block, Heaplet, PointsTo, SApp, Specifications} +import org.tygus.suslik.logic.Specifications.{Goal, SuspendedCallGoal} 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 +import scala.language.implicitConversions + sealed abstract class ProofTrace { import ProofTrace._ @@ -19,29 +25,47 @@ 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(derivationTrail: DerivationTrail) { } } object ProofTrace { case class BackLink(bud: Goal, companion: Goal) - var current: ProofTrace = ProofTraceNone // oops, not thread-safe + 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]) + + object DerivationTrail { + def withSubst[A <: PrettyPrinting, B <: PrettyPrinting](from: Goal, to: Seq[Goal], + rule: SynthesisRule, + subst: Map[A, B]): DerivationTrail = + apply(from, to, rule, subst.map { case (k, v) => k.pp -> (v.pp: OrVec) }) + } + + 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 -class ProofTraceJson(val outputFile: File) extends ProofTrace { +abstract class ProofTraceJson extends ProofTrace { import ProofTrace._ import ProofTraceJson._ - val writer = new BufferedWriter(new FileWriter(outputFile)) - - def this(outputFilename: String) = this(new File(outputFilename)) - - private def writeObject[T](t: T)(implicit w: upickle.default.Writer[T]): Unit = { - writer.write(upickle.default.write(t)) - writer.write("\n\n") - writer.flush() - } + protected def writeObject[T](t: T)(implicit w: upickle.default.Writer[T]): Unit override def add(node: OrNode): Unit = writeObject(NodeEntry(node.id, "OrNode", node.pp(), GoalEntry(node.goal), -1, node.cost)) @@ -69,11 +93,28 @@ 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(derivationTrail: DerivationTrail) { + val d = derivationTrail + writeObject(DerivationTrailEntry("DerivationTrail", + d.from.uid, d.to.map(_.uid), d.rule.toString, d.subst)) } } +class ProofTraceJsonFile(val outputFile: File) extends ProofTraceJson { + val writer = new BufferedWriter(new FileWriter(outputFile)) + + def this(outputFilename: String) = this(new File(outputFilename)) + + override protected def writeObject[T](t: T)(implicit w: upickle.default.Writer[T]): Unit = { + writer.write(upickle.default.write(t)) + writer.write("\n\n") + writer.flush() + } +} object ProofTraceJson { @@ -83,23 +124,50 @@ object ProofTraceJson { implicit val rw: RW[NodeEntry] = macroRW } - case class GoalEntry(id: String, - pre: String, - post: String, + case class GoalEntry(id: GoalEntry.Id, + uid: GoalEntry.Uid, + pre: AssertionEntry, + post: AssertionEntry, sketch: String, programVars: Seq[(String, String)], existentials: Seq[(String, String)], - ghosts: Seq[(String, String)]) + ghosts: Seq[(String, String)], + callGoal: Option[GoalEntry] = None /* suspended call goal */) object GoalEntry { + type Id = String + type Uid = 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, goal.uid, + AssertionEntry(goal.pre), AssertionEntry(goal.post), goal.sketch.pp, vars(goal, goal.programVars), vars(goal, goal.existentials), - vars(goal, goal.universalGhosts)) + vars(goal, goal.universalGhosts), goal.callGoal.map(callInfo(goal, _))) private def vars(goal: Goal, vs: Iterable[Expressions.Var]) = vs.map(v => (goal.getType(v).pp, v.pp)).toSeq + + private def callInfo(goal: Goal, callGoal: SuspendedCallGoal) = { + val companion = goal.ancestorWithLabel(callGoal.call.companion.get).get + val funSpec = companion.toFunSpec + val toActual = compose(callGoal.companionToFresh, callGoal.freshToActual) + apply(callGoal.call.companion.get.pp, companion.uid, + AssertionEntry(funSpec.pre.subst(toActual)), + AssertionEntry(funSpec.post.subst(toActual)), callGoal.actualCall.pp, + Seq(), Seq(), Seq()) + } + + /** @oops copied from PureLogicUtils */ + def compose(subst1: Subst, subst2: Subst): Subst = subst1.map { case (k, e) => k -> e.subst(subst2) } + } + + 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) @@ -115,15 +183,129 @@ object ProofTraceJson { implicit val rw: RW[StatusEntry] = macroRW } - case class CyclicEntry(backlink: BackLinkEntry) - object CyclicEntry { - 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 } + + 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.Uid, + to: Seq[GoalEntry.Uid], + ruleName: String, + subst: Map[String, OrVec]) + 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 ("{}", elems) => SetLiteral(elems.map(_.toExpr).toList) + case ("ite", Seq(cond, left, right)) => IfThenElse(cond.toExpr, left.toExpr, right.toExpr) + case ("Unknown", Leaf(name) +: params :+ subst) => + Unknown(name, params.map(_.toVar).toSet, subst.toSubst) + case (kop, Seq(arg)) => + UNOP.get(kop) match { + case Some(op) => UnaryExpr(op, arg.toExpr) + case _ => throw new RuntimeException(s"unknown unary operator: '${kop}'") + } + case (kop, Seq(arg0, arg1)) => + BINOP.get(kop) match { + case Some(op: BinOp) => BinaryExpr(op, arg0.toExpr, arg1.toExpr) + case Some(op: OverloadedBinOp) => OverloadedBinaryExpr(op, arg0.toExpr, arg1.toExpr) + case _ => throw new RuntimeException(s"unknown binary operator: '${kop}'") + } + case _ => throw new RuntimeException(s"error in expression: '${this}'") + } + + def toVar: Var = toExpr.asInstanceOf[Var] + + def toSubst: Subst = subtrees.map { case AST("↦", Seq(v, e)) => v.toVar -> e.toExpr } .toMap + + def toHeaplet: Heaplet = ??? + } + + 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) => labelOf(op) -: fromExpr(arg) + case BinaryExpr(op, left, right) => AST(labelOf(op), Seq(left, right).map(fromExpr)) + case OverloadedBinaryExpr(op, left, right) => AST(labelOf(op), 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", + Seq(AST(pred), AST("()", args.map(fromExpr)), AST(tag.pp), fromExpr(card))) + } + + object Leaf { + def unapply(t: AST): Option[String] = + if (t.subtrees.isEmpty) Some(t.root) else None + } + + /* Operator serialization */ + import Expressions._ + val UNOP = Map("not" -> OpNot, "u-" -> OpUnaryMinus, "lower" -> OpLower, "upper" -> OpUpper) + val BINOP = Map("==" -> OpOverloadedEq, "<=" -> OpOverloadedLeq, "-" -> OpOverloadedMinus, + "+" -> OpOverloadedPlus, "*" -> OpOverloadedStar, "in" -> OpOverloadedIn, + "!=" -> OpNotEqual, ">" -> OpGt, ">=" -> OpGeq, + "==[bool]" -> OpBoolEq, "->" -> OpImplication, + "<=[int]" -> OpLeq, "<" -> OpLt, "&&" -> OpAnd, "||" -> OpOr, + "+[int]" -> OpPlus, "-[int]" -> OpMinus, "*[int]" -> OpMultiply, + "++" -> OpUnion, "--" -> OpDiff, "*[set[int]]" -> OpIntersect, + "in[int]" -> OpIn, "==[loc]" -> OpEq, + "==[set[int]]" -> OpSetEq, "<=[set[int]]" -> OpSubset + /** @todo interval operators */ + ) + + def labelOf(op: UnOp): String = mustGet(UNOP, op) + def labelOf(op: BinOp): String = mustGet(BINOP, op) + def labelOf(op: OverloadedBinOp): String = mustGet(BINOP, op) + + private def mustGet[A](m: Map[String, A], op: A): String = + m.toSeq.find(_._2 == op).getOrElse + { throw new NoSuchElementException(s"operator not found: ${op}") } ._1 + } } // [Certify] Collects non-backtracked SearchTree nodes (and their ancestors), used to populate the CertTree diff --git a/src/main/scala/org/tygus/suslik/synthesis/Memoization.scala b/src/main/scala/org/tygus/suslik/synthesis/Memoization.scala index fdd51ef86..9c37eb49e 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/Memoization.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/Memoization.scala @@ -7,6 +7,7 @@ import org.tygus.suslik.logic.Specifications.{Assertion, Goal, GoalLabel, Suspen import org.tygus.suslik.synthesis.SearchTree.{NodeId, OrNode} import scala.collection.mutable +import scala.util.DynamicVariable object Memoization { /** @@ -114,6 +115,11 @@ object Memoization { } - implicit val memo: Memo = new Memo() + // need to be thread-local, for `SynthesisServer` + implicit def memo: Memo = _current.value + private val _current = new DynamicVariable[Memo](new Memo()) + def init(): Unit = { + _current.value = new Memo() + } } \ No newline at end of file diff --git a/src/main/scala/org/tygus/suslik/synthesis/SearchTree.scala b/src/main/scala/org/tygus/suslik/synthesis/SearchTree.scala index 88b1fa73d..c5ba9e2c8 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/SearchTree.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/SearchTree.scala @@ -7,18 +7,13 @@ import org.tygus.suslik.synthesis.Termination.Transition import org.tygus.suslik.synthesis.rules.Rules.{GoalUpdater, RuleResult, SynthesisRule} import org.tygus.suslik.util.SynStats +import scala.util.DynamicVariable + /** * And-or tree that represents the space of all possible derivations */ -object SearchTree { - - // Node's position in the search tree - // (index of each reflexive ancestor among its siblings; youngest to oldest) - type NodeId = Vector[Int] - - type Worklist = List[OrNode] - - trait SearchNode { val id: NodeId } +class SearchTree { + import SearchTree._ // List of nodes to process var worklist: Worklist = List() @@ -27,10 +22,37 @@ object SearchTree { var successLeaves: Worklist = List() // Initialize worklist: root or-node containing the top-level goal - def init(initialGoal: Goal): Unit = { + private def init(initialGoal: Goal): SearchTree = { val root = OrNode(Vector(), initialGoal, None) worklist = List(root) successLeaves = List() + this + } +} + +object SearchTree { + trait SearchNode { val id: NodeId } + + // needs to be thread-local, for `SynthesisServer` + private val _current = new DynamicVariable[SearchTree](new SearchTree) + def st: SearchTree = _current.value + + // need to gradually get rid of those in favor of instance methods on `st` + def worklist: Worklist = st.worklist + def worklist_=(w: Worklist): Unit = { st.worklist = w } + def successLeaves: Worklist = st.successLeaves + def successLeaves_=(w: Worklist): Unit = { st.successLeaves = w } + + /** + * Node's position in the search tree + * (index of each reflexive ancestor among its siblings; youngest to oldest) + */ + type NodeId = Vector[Int] + + type Worklist = List[OrNode] + + def init(initialGoal: Goal): Unit = { + _current.value = new SearchTree().init(initialGoal) } /** @@ -56,12 +78,12 @@ object SearchTree { def fail(implicit stats: SynStats, config: SynConfig): Unit = { memo.save(goal, Failed) parent match { - case None => assert(worklist.isEmpty)// this is the root; wl must already be empty + case None => assert(st.worklist.isEmpty)// this is the root; wl must already be empty case Some(an) => { // a subgoal has failed stats.addFailedNode(an) - worklist = pruneDescendants(an.id, worklist) // prune all other descendants of an - successLeaves = pruneDescendants(an.id, successLeaves) // also from the list of succeeded leaves - if (!worklist.exists(_.hasAncestor(an.parent.id))) { // does my grandparent have other open alternatives? + st.worklist = pruneDescendants(an.id, st.worklist) // prune all other descendants of an + st.successLeaves = pruneDescendants(an.id, st.successLeaves) // also from the list of succeeded leaves + if (!st.worklist.exists(_.hasAncestor(an.parent.id))) { // does my grandparent have other open alternatives? an.parent.fail } } @@ -71,8 +93,8 @@ object SearchTree { // This node has succeeded: return either its next suspended and-sibling or the solution def succeed(s: Solution)(implicit config: SynConfig): Either[OrNode, Solution] = { memo.save(goal, Succeeded(s, id)) - worklist = pruneDescendants(id, worklist) // prune all my descendants from worklist - successLeaves = successLeaves.filterNot(n => this.isFailedDescendant(n)) // prune members of partially successful branches + st.worklist = pruneDescendants(id, st.worklist) // prune all my descendants from worklist + st.successLeaves = st.successLeaves.filterNot(n => this.isFailedDescendant(n)) // prune members of partially successful branches parent match { case None => Right(s) // this is the root: synthesis succeeded case Some(an) => { // a subgoal has succeeded @@ -143,7 +165,7 @@ object SearchTree { } // The partial derivation that this node is part of (represented as a subset of success leaves) - def partialDerivation: List[OrNode] = successLeaves.filter(isAndSibling) + def partialDerivation: List[OrNode] = st.successLeaves.filter(isAndSibling) def pp(d: Int = 0): String = parent match { case None => "-" diff --git a/src/main/scala/org/tygus/suslik/synthesis/SynConfig.scala b/src/main/scala/org/tygus/suslik/synthesis/SynConfig.scala index e7455e4d1..8ed3b6688 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/SynConfig.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/SynConfig.scala @@ -29,6 +29,7 @@ case class SynConfig( memoization: Boolean = true, delegatePure: Boolean = false, extendedPure: Boolean = false, + simple: Boolean = false, // Timeout and logging interactive: Boolean = false, printStats: Boolean = false, @@ -37,7 +38,7 @@ case class SynConfig( assertSuccess: Boolean = false, logToFile: Boolean = true, traceToJsonFile: Option[File] = None, - timeOut: Long = 1800000, + timeOut: Long = 1800000, // milliseconds // Certification certTarget: CertificationTarget = NoCert, certDest: File = null, diff --git a/src/main/scala/org/tygus/suslik/synthesis/Synthesis.scala b/src/main/scala/org/tygus/suslik/synthesis/Synthesis.scala index 5fe3d094a..15449b483 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/Synthesis.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/Synthesis.scala @@ -44,7 +44,7 @@ class Synthesis(tactic: Tactic, implicit val log: Log, implicit val trace: Proof log.print("Initial specification:", Console.RESET) log.print(s"${goal.pp}\n", Console.BLUE) SMTSolving.init() - memo.clear() + Memoization.init() ProofTrace.current = trace try { synthesize(goal)(stats = stats) match { @@ -65,7 +65,7 @@ class Synthesis(tactic: Tactic, implicit val log: Log, implicit val trace: Proof protected def synthesize(goal: Goal) (stats: SynStats): Option[Solution] = { - init(goal) + SearchTree.init(goal) processWorkList(stats, goal.env.config) } @@ -74,7 +74,7 @@ class Synthesis(tactic: Tactic, implicit val log: Log, implicit val trace: Proof config: SynConfig): Option[Solution] = { // Check for timeouts if (!config.interactive && stats.timedOut) { - throw SynTimeOutException(s"\n\nThe derivation took too long: more than ${config.timeOut} seconds.\n") + throw SynTimeOutException(s"\n\nThe derivation took too long: more than ${config.timeOut / 1000.0} seconds.\n") } val sz = worklist.length @@ -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,19 +169,18 @@ 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 andNode = AndNode(i +: node.id, node, e) - if isTerminatingExpansion(andNode) // termination check + if config.simple || isTerminatingExpansion(andNode) // termination check (disabled in simple mode) () = trace.add(andNode, andNode.nChildren) } yield { andNode.nextChild // take the first goal from each new and-node; the first goal always exists @@ -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/main/scala/org/tygus/suslik/synthesis/SynthesisRunner.scala b/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunner.scala index 318425fae..a8444e8ba 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunner.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunner.scala @@ -1,14 +1,16 @@ package org.tygus.suslik.synthesis import java.io.File - import org.tygus.suslik.certification.CertificationTarget import org.tygus.suslik.certification.CertificationTarget.NoCert import org.tygus.suslik.certification.targets._ +import org.tygus.suslik.interaction.SynthesisServer import org.tygus.suslik.report.Log import org.tygus.suslik.util.SynLogLevels import scopt.OptionParser +import scala.concurrent.duration.{Duration, MILLISECONDS} + /** * @author Ilya Sergey */ @@ -16,7 +18,7 @@ import scopt.OptionParser object SynthesisRunner extends SynthesisRunnerUtil { // Enable verbose logging - override implicit val log = new Log(SynLogLevels.Verbose) + override implicit val log: Log = new Log(SynLogLevels.Verbose) /** * Command line args: @@ -66,12 +68,13 @@ object SynthesisRunner extends SynthesisRunnerUtil { synthesizeFromSpec(testName, in, out, params) } catch { case SynthesisException(msg) => - System.err.println("Synthesis failed:") + System.err.println(msg) + case SynTimeOutException(msg) => System.err.println(msg) } } - case class RunConfig(synConfig: SynConfig, fileName: String) + case class RunConfig(synConfig: SynConfig, fileName: String, mode: String = "batch") val TOOLNAME = "SuSLik" val SCRIPTNAME = "suslik" @@ -82,20 +85,20 @@ object SynthesisRunner extends SynthesisRunnerUtil { private def getParentDir(filePath: String): String = { val file = new File(filePath) - if (!file.exists()) { - "." - } - else file.getParentFile.getAbsolutePath + if (file.exists()) file.getParentFile.getAbsolutePath + else file.getParent } private def handleInput(args: Array[String]): Unit = { val newConfig = RunConfig(SynConfig(), defaultFile) parser.parse(args, newConfig) match { - case Some(RunConfig(synConfig, file)) => + case Some(RunConfig(synConfig, file, "batch")) => val dir = getParentDir(file) val fName = new File(file).getName runSingleTestFromDir(dir, fName, synConfig) - case None => + case Some(RunConfig(synConfig, _, "server")) => + new SynthesisServer().start() /** @todo use config! */ + case _ => System.err.println("Bad argument format.") } } @@ -113,6 +116,12 @@ object SynthesisRunner extends SynthesisRunnerUtil { case _ => NoCert } + implicit val durationRead: scopt.Read[Duration] = + scopt.Read.reads { s => + try { Duration(s.toLong, MILLISECONDS) /** @todo make default be seconds? */ } + catch { case _: NumberFormatException => Duration(s) } + } + private def uncurryLens[A,B,C](lens: scalaz.Lens[A, B])(f: C => B => B) = Function.uncurried { c:C => lens =>= f(c) } @@ -128,8 +137,8 @@ object SynthesisRunner extends SynthesisRunnerUtil { _.copy(traceLevel = l) }).text("print the entire derivation trace; default: false") - opt[Long]('t', "timeout").action(cfg { t => - _.copy(timeOut = t) + opt[Duration]('t', "timeout").action(cfg { t => + _.copy(timeOut = t.toMillis) }).text("timeout for the derivation; default (in milliseconds): 1800000 (30 min)") opt[Boolean]('a', "assert").action(cfg { b => @@ -176,6 +185,10 @@ object SynthesisRunner extends SynthesisRunnerUtil { conf => conf.copy(extendedPure = b, delegatePure = b || conf.delegatePure) }).text("use extended search space for pure synthesis with CVC4; default: false") + opt[Unit](name = "simple").action(cfg { _ => + _.copy(simple = true) + }).text("use simple, unphased rules (this is very slow); default: no") + opt[Boolean]('i', "interactive").action(cfg { b => _.copy(interactive = b) }).text("interactive mode; default: false") @@ -192,7 +205,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") @@ -220,12 +233,15 @@ object SynthesisRunner extends SynthesisRunnerUtil { note("\nOnce the synthesis is done execution, statistics will be available in stats.csv (rewritten every time).\n") + cmd("server") + .text("run a Web server for interactive mode") + .action((_, c) => c.copy(mode = "server")) } def parseParams(paramString: Array[String], params: SynConfig): SynConfig = { val newConfig = RunConfig(params, defaultFile) parser.parse(paramString, newConfig) match { - case Some(RunConfig(synConfig, _)) => synConfig + case Some(RunConfig(synConfig, _, _)) => synConfig case None => throw SynthesisException("Bad argument format.") } } diff --git a/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunnerUtil.scala b/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunnerUtil.scala index 6e63c17aa..f6fb1d2ab 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunnerUtil.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/SynthesisRunnerUtil.scala @@ -7,14 +7,16 @@ import org.tygus.suslik.LanguageUtils import org.tygus.suslik.certification.CertificationTarget.NoCert import org.tygus.suslik.certification.source.SuslikProofStep import org.tygus.suslik.certification.CertTree +import org.tygus.suslik.language.Statements import org.tygus.suslik.logic.Environment import org.tygus.suslik.logic.Preprocessor._ import org.tygus.suslik.logic.smt.SMTSolving import org.tygus.suslik.parsing.SSLParser -import org.tygus.suslik.report.{Log, ProofTrace, ProofTraceCert, ProofTraceJson, ProofTraceNone, StopWatch} +import org.tygus.suslik.report.{Log, ProofTrace, ProofTraceJsonFile, ProofTraceCert, ProofTraceJson, ProofTraceNone, StopWatch} import org.tygus.suslik.synthesis.SearchTree.AndNode import org.tygus.suslik.synthesis.tactics._ import org.tygus.suslik.util._ +import resource.managed import scala.io.Source @@ -52,7 +54,7 @@ trait SynthesisRunnerUtil { case s if s.endsWith(sketchExtension) => dotSus } // The path is counted from the root - val allLines = Source.fromFile(file).getLines.toList + val allLines = readLines(file) val (params, lines) = if (allLines.nonEmpty && allLines.head.startsWith(paramPrefix)) { (SynthesisRunner.parseParams(allLines.head.drop(paramPrefix.length).split(' '), initialParams), allLines.tail) @@ -103,33 +105,8 @@ trait SynthesisRunnerUtil { } } - // Create synthesizer object, choosing search tactic based on the config - def createSynthesizer(env: Environment): Synthesis = { - val tactic = - if (env.config.interactive) - new InteractiveSynthesis(env.config, env.stats) - else if (env.config.script.nonEmpty) - new ReplaySynthesis(env.config) - else - new PhasedSynthesis(env.config) - val trace : ProofTrace = if (env.config.certTarget != NoCert) new ProofTraceCert() else { - env.config.traceToJsonFile match { - case None => ProofTraceNone - case Some(file) => new ProofTraceJson(file) - } - } - new Synthesis(tactic, log, trace) - } - - def synthesizeFromFile(dir: String, testName: String): Unit = { - val (_, _, in, out, params) = getDescInputOutput(testName) - synthesizeFromSpec(testName, in, out, params) - } - - def synthesizeFromSpec(testName: String, text: String, out: String = noOutputCheck, params: SynConfig = defaultConfig) : Unit = { - import log.out.testPrintln - - val parser = new SSLParser + def prepareSynthesisTask(text: String, params: SynConfig = defaultConfig) = { + val parser = new SSLParser(params) val res = params.inputFormat match { case `dotSyn` => parser.parseGoalSYN(text) case `dotSus` => parser.parseGoalSUS(text) @@ -147,6 +124,45 @@ trait SynthesisRunnerUtil { val spec = specs.head val env = Environment(predEnv, funcEnv, params, new SynStats(params.timeOut)) + (spec, env, body) + } + + // Create synthesizer object, choosing search tactic based on the config + def createSynthesizer(env: Environment): Synthesis = { + val tactic = + if (env.config.interactive) { + if (env.config.simple) + new InteractiveSimple(env.config, env.stats) + else + 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 AutomaticPhased(env.config) + val trace : ProofTrace = if (env.config.certTarget != NoCert) new ProofTraceCert() else { + env.config.traceToJsonFile match { + case None => ProofTraceNone + case Some(file) => new ProofTraceJsonFile(file) + } + } + new Synthesis(tactic, log, trace) + } + + def synthesizeFromFile(dir: String, testName: String, + initialParams: SynConfig = defaultConfig) : List[Statements.Procedure] = { + val fullPath = Paths.get(dir, testName) + val defs = getDefsFromDir(new File(dir)) + val (_, _, in, out, params) = getDescInputOutput(fullPath.toString, initialParams) + synthesizeFromSpec(testName, List(defs, in).mkString("\n"), out, params) + } + + def synthesizeFromSpec(testName: String, text: String, out: String = noOutputCheck, + params: SynConfig = defaultConfig) : List[Statements.Procedure] = { + import log.out.testPrintln + + val (spec, env, body) = prepareSynthesisTask(text, params) val synthesizer = createSynthesizer(env) env.stats.start() @@ -155,9 +171,6 @@ trait SynthesisRunnerUtil { SynStatUtil.log(testName, duration, params, spec, sresult._1, sresult._2) - def printHotNode(hotNode: AndNode, descs: Int): String = - s"${hotNode.rule.toString} at depth ${hotNode.parent.depth} with ${descs} descendants expanded" - def printRuleApplication(name: String, stat: RuleStat): String = s"$name: succeeded ${stat.numSuccess} times (${stat.timeSuccess}ms), failed ${stat.numFail} times (${stat.timeFail}ms)" @@ -185,7 +198,10 @@ trait SynthesisRunnerUtil { sresult._1 match { case Nil => printStats(sresult._2) - throw SynthesisException(s"Failed to synthesise:\n$sresult") + if (sresult._2.timedOut) + throw SynTimeOutException(s"Timeout after ${(sresult._2.duration / 1000.0).round.toInt} seconds") + else + throw SynthesisException(s"Failed to synthesise due to unrealizable spec or incompleteness") case procs => val result = if (params.printSpecs) { procs.map(p => { @@ -241,6 +257,7 @@ trait SynthesisRunnerUtil { }) } } + procs } } @@ -248,7 +265,13 @@ trait SynthesisRunnerUtil { if (defFiles.isEmpty) return "" assert(defFiles.size == 1, "More than one file with definitions in the folder") val file = new File(defFiles.head.getAbsolutePath) - Source.fromFile(file).getLines.toList.mkString("\n") + readLines(file).mkString("\n") + } + + def getDefsFromDir(dir: File): String = { + if (dir.exists() && dir.isDirectory) + getDefs(dir.listFiles.filter(f => f.isFile && f.getName.endsWith(s".$defExtension")).toList) + else "" } def runAllTestsFromDir(dir: String) { @@ -258,7 +281,7 @@ trait SynthesisRunnerUtil { // Create log file SynStatUtil.init(defaultConfig) // Get definitions - val defs = getDefs(testDir.listFiles.filter(f => f.isFile && f.getName.endsWith(s".$defExtension")).toList) + val defs = getDefsFromDir(testDir) // Get specs val tests = testDir.listFiles.filter(f => f.isFile && (f.getName.endsWith(s".$testExtension") || @@ -286,7 +309,7 @@ trait SynthesisRunnerUtil { // Maybe create log file (depending on params) SynStatUtil.init(params) // Get definitions - val defs = getDefs(testDir.listFiles.filter(f => f.isFile && f.getName.endsWith(s".$defExtension")).toList) + val defs = getDefsFromDir(testDir) // Get specs val tests = testDir.listFiles.filter(f => f.isFile && (f.getName.endsWith(s".$testExtension") || @@ -302,6 +325,9 @@ trait SynthesisRunnerUtil { } } + def readLines(file: File): List[String] = + managed(Source.fromFile(file)).map(_.getLines.toList) + .opt.get def removeSuffix(s: String, suffix: String): String = { if (s.endsWith(suffix)) s.substring(0, s.length - suffix.length) else s 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/main/scala/org/tygus/suslik/synthesis/rules/LogicalRules.scala b/src/main/scala/org/tygus/suslik/synthesis/rules/LogicalRules.scala index 1d124eceb..fa657992e 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/rules/LogicalRules.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/rules/LogicalRules.scala @@ -6,9 +6,12 @@ import org.tygus.suslik.language.Statements._ 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._ import org.tygus.suslik.synthesis.rules.Rules._ +import scala.Function.tupled + /** * Logical rules simplify specs and terminate the derivation; * they do not eliminate existentials. @@ -135,6 +138,10 @@ object LogicalRules extends PureLogicUtils with SepLogicUtils with RuleUtils { val newPost = Assertion(post.phi, newPostSigma) val newGoal = goal.spawnChild(newPre, newPost) val kont = IdProducer >> ExtractHelper(goal) + + ProofTrace.current.add(ProofTrace.DerivationTrail(goal, Seq(newGoal), this, + Map("Pre" -> hPre.pp, "Post" -> hPost.pp))) + List(RuleResult(List(newGoal), kont, this, goal)) } } @@ -149,6 +156,7 @@ object LogicalRules extends PureLogicUtils with SepLogicUtils with RuleUtils { object FrameFlat extends Frame with FlatPhase with InvertibleRule + object FrameSimple extends Frame with PhaseDisabled /* x ≠ nil ∉ φ @@ -251,19 +259,16 @@ object LogicalRules extends PureLogicUtils with SepLogicUtils with RuleUtils { else None } else None - findConjunctAndRest({ - case BinaryExpr(OpEq, l, r) => extractSides(l, r) - case BinaryExpr(OpBoolEq, l, r) => extractSides(l, r) - case BinaryExpr(OpSetEq, l, r) => extractSides(l, r) - case BinaryExpr(OpIntervalEq, l, r) => extractSides(l, r) - case _ => None - }, p1) match { + findConjunctAndRest(e => extractEquality(e).flatMap(tupled(extractSides)), p1) + match { case Some(((x, e), rest1)) => { val _p1 = rest1.subst(x, e) val _s1 = s1.subst(x, e) val newGoal = goal.spawnChild(Assertion(_p1, _s1), goal.post.subst(x, e)) val kont = SubstProducer(x, e) >> IdProducer >> ExtractHelper(goal) assert(goal.callGoal.isEmpty) + ProofTrace.current.add(ProofTrace.DerivationTrail(goal, Seq(newGoal), this, + Map(x.pp -> e.pp))) List(RuleResult(List(newGoal), kont, this, goal)) } case _ => Nil diff --git a/src/main/scala/org/tygus/suslik/synthesis/rules/OperationalRules.scala b/src/main/scala/org/tygus/suslik/synthesis/rules/OperationalRules.scala index 833b433ca..d5b406a12 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/rules/OperationalRules.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/rules/OperationalRules.scala @@ -5,6 +5,7 @@ import org.tygus.suslik.language.{Statements, _} import org.tygus.suslik.logic.Specifications._ import org.tygus.suslik.logic._ import org.tygus.suslik.synthesis.{ExtractHelper, PrependProducer, StmtProducer, SubstVarProducer} +import org.tygus.suslik.report.ProofTrace import org.tygus.suslik.synthesis.rules.Rules._ /** @@ -26,7 +27,7 @@ object OperationalRules extends SepLogicUtils with RuleUtils { Γ ; {φ ; x.f -> l * P} ; {ψ ; x.f -> l' * Q} ---> *x.f := l' ; S */ - object WriteRule extends SynthesisRule with GeneratesCode with InvertibleRule { + abstract class WriteAbstract extends SynthesisRule with GeneratesCode { override def toString: Ident = "Write" @@ -45,12 +46,18 @@ object OperationalRules extends SepLogicUtils with RuleUtils { findMatchingHeaplets(_ => true, isMatch, goal.pre.sigma, goal.post.sigma) match { case None => Nil - case Some((hl@PointsTo(x@Var(_), offset, e1), hr@PointsTo(_, _, e2))) => - val newPre = Assertion(pre.phi, goal.pre.sigma - hl) - val newPost = Assertion(post.phi, goal.post.sigma - hr) - val subGoal = goal.spawnChild(newPre, newPost) + case Some((hl@PointsTo(x@Var(_), offset, _), hr@PointsTo(_, _, e2))) => + // TUTORIAL: +// val newPre = Assertion(pre.phi, goal.pre.sigma - hl) +// val newPost = Assertion(post.phi, goal.post.sigma - hr) +// val subGoal = goal.spawnChild(newPre, newPost) + val newPre = Assertion(pre.phi, (goal.pre.sigma - hl) ** hr) + val subGoal = goal.spawnChild(newPre) val kont: StmtProducer = PrependProducer(Store(x, offset, e2)) >> ExtractHelper(goal) + ProofTrace.current.add(ProofTrace.DerivationTrail(goal, Seq(subGoal), this, + Map("to" -> x.pp, "offset" -> offset.toString, "value" -> e2.pp))) + List(RuleResult(List(subGoal), kont, this, goal)) case Some((hl, hr)) => ruleAssert(assertion = false, s"Write rule matched unexpected heaplets ${hl.pp} and ${hr.pp}") @@ -60,6 +67,10 @@ object OperationalRules extends SepLogicUtils with RuleUtils { } + object WriteRule extends WriteAbstract with InvertibleRule + + object WriteSimple extends WriteAbstract + /* Read rule: create a fresh typed read @@ -83,6 +94,20 @@ object OperationalRules extends SepLogicUtils with RuleUtils { findHeaplet(isGhostPoints, goal.pre.sigma) match { case None => Nil + // TUTORIAL: + case Some(pts@PointsTo(x@Var(_), offset, v@Var(name))) => + val y = freshVar(goal.vars, name) + val tpy = v.getType(goal.gamma).get + val subGoal = goal.spawnChild(pre = goal.pre.subst(v, y), + post = goal.post.subst(v, y), + gamma = goal.gamma + (y -> tpy), + programVars = y :: goal.programVars) + val kont: StmtProducer = PrependProducer(Load(y, tpy, x, offset)) >> ExtractHelper(goal) + + ProofTrace.current.add(ProofTrace.DerivationTrail(goal, Seq(subGoal), this, + Map("to" -> y.pp, "from" -> x.pp, "offset" -> offset.toString))) + + List(RuleResult(List(subGoal), kont, this, goal)) case Some(pts@PointsTo(x@Var(_), offset, e)) => val y = freshVar(goal.vars, e.pp) val tpy = e.getType(goal.gamma).get @@ -181,7 +206,7 @@ object OperationalRules extends SepLogicUtils with RuleUtils { val toRemove = mkSFormula(pts.toList) ** h val newPre = Assertion(pre.phi, pre.sigma - toRemove) - val subGoal = goal.spawnChild(newPre) + val subGoal = goal.spawnChild(newPre, isCompanion = true) val kont: StmtProducer = PrependProducer(Free(x)) >> ExtractHelper(goal) List(RuleResult(List(subGoal), kont, this, goal)) diff --git a/src/main/scala/org/tygus/suslik/synthesis/rules/Rules.scala b/src/main/scala/org/tygus/suslik/synthesis/rules/Rules.scala index e9f743b43..9a35c53f1 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/rules/Rules.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/rules/Rules.scala @@ -58,6 +58,12 @@ object Rules { // This rule produces code trait GeneratesCode + trait PhaseDisabled { + def heapletFilter(h: Heaplet): Boolean = true + + def profilesMatch(pre: SFormula, post: SFormula, exact: Boolean): Boolean = true + } + trait UnfoldingPhase { def heapletFilter(h: Heaplet): Boolean = { h.isInstanceOf[SApp] 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..22f5371d4 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.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 // TODO: Generalise this in the future @@ -98,6 +102,10 @@ object UnfoldingRules extends SepLogicUtils with RuleUtils { newGoal = goal.spawnChild(post = f.pre, gamma = newGamma, callGoal = suspendedCallGoal) } yield { val kont: StmtProducer = AbduceCallProducer(f) >> IdProducer >> ExtractHelper(goal) + + ProofTrace.current.add(ProofTrace.DerivationTrail(goal, Seq(newGoal), this, + Map("fun" -> f.name, "args" -> f.params.map(_._1.pp)))) + RuleResult(List(newGoal), kont, this, goal) } } @@ -130,6 +138,10 @@ object UnfoldingRules extends SepLogicUtils with RuleUtils { val newGoal = goal.spawnChild(pre = newPre, post = newPost, callGoal = None, isCompanion = true) val postCallTransition = Transition(goal, newGoal) val kont: StmtProducer = SubstMapProducer(callGoal.freshToActual) >> PrependProducer(call) >> ExtractHelper(goal) + + ProofTrace.current.add(ProofTrace.DerivationTrail(goal, List(newGoal), this, + Map("fun" -> call.fun.name, "args" -> call.args.map(_.toString)))) + List(RuleResult(List(newGoal), kont, this, List(postCallTransition) ++ companionTransition(callGoal, goal))) } diff --git a/src/main/scala/org/tygus/suslik/synthesis/rules/UnificationRules.scala b/src/main/scala/org/tygus/suslik/synthesis/rules/UnificationRules.scala index 8e34846e4..c3afe8898 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/rules/UnificationRules.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/rules/UnificationRules.scala @@ -4,9 +4,12 @@ import org.tygus.suslik.language.CardType import org.tygus.suslik.language.Expressions._ import org.tygus.suslik.logic.Specifications._ import org.tygus.suslik.logic._ +import org.tygus.suslik.report.ProofTrace import org.tygus.suslik.synthesis._ import org.tygus.suslik.synthesis.rules.Rules._ +import scala.Function.tupled + /** * The goal of unification rules is to eliminate existentials * via either heap unification or various forms of pure synthesis. @@ -54,6 +57,9 @@ object UnificationRules extends PureLogicUtils with SepLogicUtils with RuleUtils val newPost = Assertion(post.phi && subExpr, newPostSigma) val newGoal = goal.spawnChild(post = newPost) val kont = UnificationProducer(t, s, sub) >> IdProducer >> ExtractHelper(goal) + + ProofTrace.current.add(ProofTrace.DerivationTrail.withSubst(goal, List(newGoal), this, sub)) + RuleResult(List(newGoal), kont, this, goal) } nubBy[RuleResult, Assertion](alternatives, sub => sub.subgoals.head.post) @@ -62,12 +68,47 @@ object UnificationRules extends PureLogicUtils with SepLogicUtils with RuleUtils } } + // Unify syntactically (i.e. only allowed to unify existentials that are top-level in a pure expression) + abstract class SyntacticUnify extends SynthesisRule { + override def toString: String = "Unify" + + def heapletFilter(h: Heaplet): Boolean + + // Do we have a chance to get rid of the relevant kind of heaplets by only unification and framing? + def profilesMatch(pre: SFormula, post: SFormula, exact: Boolean): Boolean + + def apply(goal: Goal): Seq[RuleResult] = { + val pre = goal.pre + val post = goal.post + if (!profilesMatch(pre.sigma, post.sigma, goal.callGoal.isEmpty)) return Nil + + val postCandidates = post.sigma.chunks.filter(p => p.vars.exists(goal.isExistential) && heapletFilter(p)) + + val alternatives = for { + s <- postCandidates + t <- pre.sigma.chunks + sub <- s.unifySyntactic(t, goal.existentials) + newPost = post.subst(sub) + if newPost.sigma.chunks.distinct.size == newPost.sigma.chunks.size // discard substitution if is produces duplicate chunks in the post + } yield { + val newCallGoal = goal.callGoal.map(_.updateSubstitution(sub)) + val newGoal = goal.spawnChild(post = newPost, callGoal = newCallGoal) + val kont = IdProducer >> ExtractHelper(goal) + RuleResult(List(newGoal), kont, this, goal) + } + nubBy[RuleResult, Assertion](alternatives, sub => sub.subgoals.head.post) + } + } + + object HeapUnifySimple extends SyntacticUnify with PhaseDisabled object HeapUnifyUnfolding extends HeapUnify with UnfoldingPhase object HeapUnifyBlock extends HeapUnify with BlockPhase - object HeapUnifyPointer extends HeapUnify with FlatPhase with InvertibleRule { + object HeapUnifyPure extends HeapUnify with FlatPhase + + abstract class UnifyPointer extends SynthesisRule { override def toString: String = "UnifyLHS" override def apply(goal: Goal): Seq[RuleResult] = { @@ -104,7 +145,9 @@ object UnificationRules extends PureLogicUtils with SepLogicUtils with RuleUtils } } - object HeapUnifyPure extends HeapUnify with FlatPhase + object UnifyPointerFlat extends UnifyPointer with FlatPhase with InvertibleRule + + object UnifyPointerSimple extends UnifyPointer with PhaseDisabled /* X ∈ GV(post) / GV (pre) @@ -136,13 +179,8 @@ object UnificationRules extends PureLogicUtils with SepLogicUtils with RuleUtils else None } else None - findConjunctAndRest({ - case BinaryExpr(OpEq, l, r) => extractSides(l,r) - case BinaryExpr(OpBoolEq, l, r) => extractSides(l,r) - case BinaryExpr(OpSetEq, l, r) => extractSides(l,r) - case BinaryExpr(OpIntervalEq, l, r) => extractSides(l,r) - case _ => None - }, p2) match { + findConjunctAndRest(e => extractEquality(e).flatMap(tupled(extractSides)), p2) + match { case Some(((x, e), rest2)) => { val sigma = Map(x -> e) val _p2 = rest2.subst(sigma) @@ -150,6 +188,7 @@ object UnificationRules extends PureLogicUtils with SepLogicUtils with RuleUtils val newCallGoal = goal.callGoal.map(_.updateSubstitution(sigma)) val newGoal = goal.spawnChild(post = Assertion(_p2, _s2), callGoal = newCallGoal) val kont = SubstProducer(x, e) >> IdProducer >> ExtractHelper(goal) + ProofTrace.current.add(ProofTrace.DerivationTrail.withSubst(goal, Seq(newGoal), this, sigma)) List(RuleResult(List(newGoal), kont, this, goal)) } case _ => Nil @@ -164,7 +203,7 @@ object UnificationRules extends PureLogicUtils with SepLogicUtils with RuleUtils */ object Pick extends SynthesisRule { - override def toString: String = "PickExist" + override def toString: String = "Pick" def apply(goal: Goal): Seq[RuleResult] = { val constants = List(IntConst(0), SetLiteral(List()), eTrue, eFalse) @@ -173,7 +212,7 @@ object UnificationRules extends PureLogicUtils with SepLogicUtils with RuleUtils if (goal.post.sigma.isEmp) goal.existentials else goal.existentials.intersect(goal.post.sigma.vars) def uniCandidates(ex: Var): Set[Var] = { - if (goal.post.sigma.isEmp) goal.allUniversals.intersect(goal.pre.vars ++ goal.post.vars) + if (!goal.isProgramLevelExistential(ex) && goal.post.sigma.isEmp) goal.allUniversals.intersect(goal.pre.vars ++ goal.post.vars) else goal.programVars.toSet // goal.allUniversals.intersect(goal.pre.vars ++ goal.post.vars) } @@ -187,7 +226,11 @@ object UnificationRules extends PureLogicUtils with SepLogicUtils with RuleUtils newCallGoal = goal.callGoal.map(_.updateSubstitution(sigma)) newGoal = goal.spawnChild(post = newPost, callGoal = newCallGoal) kont = SubstProducer(ex, v) >> IdProducer >> ExtractHelper(goal) - } yield RuleResult(List(newGoal), kont, this, goal) + } yield { + ProofTrace.current.add(ProofTrace.DerivationTrail.withSubst( + goal, Seq(newGoal), this, sigma)) + RuleResult(List(newGoal), kont, this, goal) + } } } @@ -255,6 +298,10 @@ object UnificationRules extends PureLogicUtils with SepLogicUtils with RuleUtils val newCallGoal = goal.callGoal.map(_.updateSubstitution(sigma)) val newGoal = goal.spawnChild(post = newPost, callGoal = newCallGoal) val kont = SubstVarProducer(v, arg) >> IdProducer >> ExtractHelper(goal) + + ProofTrace.current.add(ProofTrace.DerivationTrail.withSubst( + goal, Seq(newGoal), this, sigma)) + List(RuleResult(List(newGoal), kont, this, goal)) } } diff --git a/src/main/scala/org/tygus/suslik/synthesis/tactics/InteractiveSynthesis.scala b/src/main/scala/org/tygus/suslik/synthesis/tactics/InteractiveSynthesis.scala deleted file mode 100644 index 32dc89134..000000000 --- a/src/main/scala/org/tygus/suslik/synthesis/tactics/InteractiveSynthesis.scala +++ /dev/null @@ -1,19 +0,0 @@ -package org.tygus.suslik.synthesis.tactics - -import org.tygus.suslik.synthesis.SynConfig -import org.tygus.suslik.synthesis.rules.Rules -import org.tygus.suslik.util.SynStats - -class InteractiveSynthesis(config: SynConfig, stats: SynStats) extends PhasedSynthesis(config) { - - override def filterExpansions(allExpansions: Seq[Rules.RuleResult]): Seq[Rules.RuleResult] = { - // Interactive mode: ask user to pick an expansion - val choice = if (allExpansions.length == 1) 0 else readInt - if (0 < choice && choice <= allExpansions.size) { - val res = allExpansions(choice - 1) - stats.addExpansionChoice(choice) - List(res) - } else allExpansions - } - -} diff --git a/src/main/scala/org/tygus/suslik/synthesis/tactics/PhasedSynthesis.scala b/src/main/scala/org/tygus/suslik/synthesis/tactics/PhasedSynthesis.scala index 36a92d342..d199369ca 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/tactics/PhasedSynthesis.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/tactics/PhasedSynthesis.scala @@ -5,12 +5,13 @@ import org.tygus.suslik.logic.Specifications.Goal import org.tygus.suslik.synthesis.SearchTree.OrNode import org.tygus.suslik.synthesis._ import org.tygus.suslik.synthesis.rules.LogicalRules.{FrameUnfolding, FrameUnfoldingFinal} -import org.tygus.suslik.synthesis.rules.Rules.{GeneratesCode, RuleResult, SynthesisRule} +import org.tygus.suslik.synthesis.rules.Rules.{GeneratesCode, SynthesisRule} import org.tygus.suslik.synthesis.rules.UnfoldingRules.Close import org.tygus.suslik.synthesis.rules.UnificationRules.HeapUnifyUnfolding import org.tygus.suslik.synthesis.rules._ +import org.tygus.suslik.util.SynStats -class PhasedSynthesis(config: SynConfig) extends Tactic { +abstract class PhasedSynthesis(config: SynConfig) extends Tactic { def nextRules(node: OrNode): List[SynthesisRule] = { val goal = node.goal @@ -25,8 +26,6 @@ class PhasedSynthesis(config: SynConfig) extends Tactic { else anyPhaseRules ++ specBasedRules(node) } - def filterExpansions(allExpansions: Seq[RuleResult]): Seq[RuleResult] = allExpansions - protected def specBasedRules(node: OrNode): List[SynthesisRule] = { val goal = node.goal if (goal.hasPredicates()) { @@ -111,13 +110,13 @@ class PhasedSynthesis(config: SynConfig) extends Tactic { else if (goal.hasExistentialPointers) List(LogicalRules.FrameFlat, // OperationalRules.WriteRule, - UnificationRules.HeapUnifyPointer) + UnificationRules.UnifyPointerFlat) else List(UnfoldingRules.CallRule, UnificationRules.SubstRight, LogicalRules.FrameFlat, // OperationalRules.WriteRule, - UnificationRules.PickArg, +// UnificationRules.PickArg, UnificationRules.PickCard, LogicalRules.GhostWrite, UnificationRules.HeapUnifyPure, @@ -145,7 +144,7 @@ class PhasedSynthesis(config: SynConfig) extends Tactic { // UnificationRules.SubstRight, FailRules.HeapUnreachable, LogicalRules.FrameFlat, - UnificationRules.HeapUnifyPointer, + UnificationRules.UnifyPointerFlat, ) protected def purePhaseRules: List[SynthesisRule] = { @@ -167,3 +166,6 @@ class PhasedSynthesis(config: SynConfig) extends Tactic { } } + +class AutomaticPhased(config: SynConfig) extends PhasedSynthesis(config) with AutomaticSynthesis +class InteractivePhased(config: SynConfig, override val stats: SynStats) extends PhasedSynthesis(config) with InteractiveSynthesis diff --git a/src/main/scala/org/tygus/suslik/synthesis/tactics/SimpleSynthesis.scala b/src/main/scala/org/tygus/suslik/synthesis/tactics/SimpleSynthesis.scala new file mode 100644 index 000000000..d3598fbd1 --- /dev/null +++ b/src/main/scala/org/tygus/suslik/synthesis/tactics/SimpleSynthesis.scala @@ -0,0 +1,55 @@ +package org.tygus.suslik.synthesis.tactics + +import org.tygus.suslik.logic.Specifications.Goal +import org.tygus.suslik.synthesis.SearchTree.OrNode +import org.tygus.suslik.synthesis.SynConfig +import org.tygus.suslik.synthesis.rules.Rules.SynthesisRule +import org.tygus.suslik.synthesis.rules._ +import org.tygus.suslik.util.SynStats + +abstract class SimpleSynthesis (config: SynConfig) extends Tactic { + + def nextRules(node: OrNode): List[SynthesisRule] = { + val goal = node.goal + if (goal.isUnsolvable) + Nil + else if (goal.callGoal.nonEmpty) callAbductionRules(goal) + else simpleRules(goal) + } + + protected def callAbductionRules(goal: Goal): List[SynthesisRule] = { + List( + UnfoldingRules.CallRule, + UnificationRules.SubstRight, + FailRules.PostInconsistent, + LogicalRules.FrameSimple, + UnificationRules.HeapUnifySimple, + UnificationRules.UnifyPointerSimple, + OperationalRules.WriteSimple, + UnificationRules.Pick) + } + + protected def simpleRules(goal: Goal): List[SynthesisRule] = List( + LogicalRules.NilNotLval, + LogicalRules.EmpRule, + LogicalRules.Inconsistency, + FailRules.PostInconsistent, + LogicalRules.SubstLeft, + UnificationRules.SubstRight, + OperationalRules.ReadRule, + UnfoldingRules.AbduceCall, + UnfoldingRules.Open, + UnfoldingRules.Close, + LogicalRules.FrameSimple, + UnificationRules.HeapUnifySimple, + UnificationRules.UnifyPointerSimple, + OperationalRules.FreeRule, + OperationalRules.AllocRule, + OperationalRules.WriteSimple, + UnificationRules.Pick + ) + +} + +class AutomaticSimple(config: SynConfig) extends SimpleSynthesis(config) with AutomaticSynthesis +class InteractiveSimple(config: SynConfig, override val stats: SynStats) extends SimpleSynthesis(config) with InteractiveSynthesis diff --git a/src/main/scala/org/tygus/suslik/synthesis/tactics/Tactic.scala b/src/main/scala/org/tygus/suslik/synthesis/tactics/Tactic.scala index 2a337bbc9..33a4e38b2 100644 --- a/src/main/scala/org/tygus/suslik/synthesis/tactics/Tactic.scala +++ b/src/main/scala/org/tygus/suslik/synthesis/tactics/Tactic.scala @@ -1,7 +1,9 @@ package org.tygus.suslik.synthesis.tactics import org.tygus.suslik.synthesis.SearchTree.OrNode +import org.tygus.suslik.synthesis.rules.Rules import org.tygus.suslik.synthesis.rules.Rules.{RuleResult, SynthesisRule} +import org.tygus.suslik.util.SynStats /** * a tactic guides search by pruning and prioritizing the children of an or-node @@ -14,5 +16,24 @@ trait Tactic { def nextRules(node: OrNode): List[SynthesisRule] def filterExpansions(allExpansions: Seq[RuleResult]): Seq[RuleResult] +} + +trait AutomaticSynthesis { + def filterExpansions(allExpansions: Seq[RuleResult]): Seq[RuleResult] = allExpansions +} + +trait InteractiveSynthesis { + + val stats: SynStats + + def filterExpansions(allExpansions: Seq[Rules.RuleResult]): Seq[Rules.RuleResult] = { + // Interactive mode: ask user to pick an expansion + val choice = if (allExpansions.length == 1) 0 else readInt + if (0 < choice && choice <= allExpansions.size) { + val res = allExpansions(choice - 1) + stats.addExpansionChoice(choice) + List(res) + } else allExpansions + } } diff --git a/src/test/resources/synthesis/all-benchmarks/dll/definitions.def b/src/test/resources/synthesis/all-benchmarks/dll/definitions.def index 9f35a5a8c..f98fe82de 100644 --- a/src/test/resources/synthesis/all-benchmarks/dll/definitions.def +++ b/src/test/resources/synthesis/all-benchmarks/dll/definitions.def @@ -8,3 +8,8 @@ predicate sll(loc x, set s) { | x == 0 => { s =i {} ; emp } | not (x == 0) => { s =i {v} ++ s1 ; [x, 2] ** x :-> v ** (x + 1) :-> nxt ** sll(nxt, s1) } } + +predicate sll0(loc x, set s) { +| x == 0 => { s =i {} ; emp } +| not (x == 0) => { s =i {v} ++ s1 ; [x, 3] ** x :-> v ** (x + 1) :-> nxt ** (x + 2) :-> 0 ** sll0(nxt, s1) } +} diff --git a/src/test/resources/synthesis/all-benchmarks/dll/from-sll-insitu.syn b/src/test/resources/synthesis/all-benchmarks/dll/from-sll-insitu.syn new file mode 100644 index 000000000..68555e335 --- /dev/null +++ b/src/test/resources/synthesis/all-benchmarks/dll/from-sll-insitu.syn @@ -0,0 +1,11 @@ +# -c 2 + +should be able to convert a singly-linked list to a double-linked list + +####### + +{ sll0(x, s)} +void sll_to_dll_insitu(loc x, loc y) +{ dll(x, 0, s)} + +####### diff --git a/src/test/resources/synthesis/all-benchmarks/ints/swap.syn b/src/test/resources/synthesis/all-benchmarks/ints/swap.syn index 227cb5bba..b7c1e9a9b 100644 --- a/src/test/resources/synthesis/all-benchmarks/ints/swap.syn +++ b/src/test/resources/synthesis/all-benchmarks/ints/swap.syn @@ -2,7 +2,9 @@ should be able to synthesize a swap program ### -{true; x :-> a ** y :-> b} void swap(loc x, loc y) {true ; x :-> b ** y :-> a} +{true; x :-> a ** y :-> b} +void swap(loc x, loc y) +{true ; x :-> b ** y :-> a} ### diff --git a/src/test/resources/synthesis/tutorial/account_create.sus b/src/test/resources/synthesis/tutorial/account_create.sus new file mode 100644 index 000000000..f804104be --- /dev/null +++ b/src/test/resources/synthesis/tutorial/account_create.sus @@ -0,0 +1,12 @@ +// create an account record + +predicate account(loc x, int bal) { + | true => { bal >= 0 ; [x, 1] ** x :-> bal } + } + +void create_account (loc ret) +{ ret :-> 0 } +{ ret :-> acc ** account(acc, 0) } +{ + ?? +} \ No newline at end of file diff --git a/src/test/resources/synthesis/tutorial/account_delete.sus b/src/test/resources/synthesis/tutorial/account_delete.sus new file mode 100644 index 000000000..107535beb --- /dev/null +++ b/src/test/resources/synthesis/tutorial/account_delete.sus @@ -0,0 +1,12 @@ +// dispose an account record + +predicate account(loc x, int bal) { + | true => { bal >= 0 ; [x, 1] ** x :-> bal } + } + +void delete_account (loc acc) +{ account(acc, a) } +{ emp } +{ + ?? +} \ No newline at end of file diff --git a/src/test/resources/synthesis/tutorial/account_deposit.sus b/src/test/resources/synthesis/tutorial/account_deposit.sus new file mode 100644 index 000000000..c9d3a6f10 --- /dev/null +++ b/src/test/resources/synthesis/tutorial/account_deposit.sus @@ -0,0 +1,12 @@ +// deposit into a bank account + +predicate account(loc x, int bal) { + | true => { bal >= 0 ; [x, 1] ** x :-> bal } + } + +void deposit (loc acc, int amt) +{ amt >= 0 ; account(acc, b) } +{ account(acc, amt + b) } +{ + ?? +} \ No newline at end of file diff --git a/src/test/resources/synthesis/tutorial/list-copy.sus b/src/test/resources/synthesis/tutorial/list-copy.sus new file mode 100644 index 000000000..571b71570 --- /dev/null +++ b/src/test/resources/synthesis/tutorial/list-copy.sus @@ -0,0 +1,17 @@ +// copy a singly-linked list + +predicate list(loc x, set s) { +| x == 0 => { s == {} ; emp } +| x != 0 => { s == {v} + s1 ; [x, 2] ** x :-> v ** (x + 1) :-> nxt ** list(nxt, s1) } +} + + +// Create a copy of a list starting at `x`; +// and store the address of the copy in `r`. +void copy (loc x, loc r) +{ list(x, s) ** r :-> a } +{ list(x, s) ** list(y, s) ** r :-> y } +{ + ?? +} + diff --git a/src/test/resources/synthesis/tutorial/list-dispose.sus b/src/test/resources/synthesis/tutorial/list-dispose.sus new file mode 100644 index 000000000..cdfff2598 --- /dev/null +++ b/src/test/resources/synthesis/tutorial/list-dispose.sus @@ -0,0 +1,13 @@ +// dispose a singly-linked list + +predicate list(loc x) { +| x == 0 => { emp } +| x != 0 => { [x, 2] ** x :-> v ** (x + 1) :-> y ** list(y) } +} + +void dispose(loc x) +{ list(x) } +{ emp } +{ + ?? +} \ No newline at end of file diff --git a/src/test/resources/synthesis/tutorial/rose-tree-dispose.sus b/src/test/resources/synthesis/tutorial/rose-tree-dispose.sus new file mode 100644 index 000000000..2cfb00de0 --- /dev/null +++ b/src/test/resources/synthesis/tutorial/rose-tree-dispose.sus @@ -0,0 +1,23 @@ +# -o 2 + +// deallocate a rose tree; +// a rose tree is an n-ary tree that stores child nodes in a linked list; +// this task requires uses mutual recursion + +predicate rtree(loc x) { +| x == 0 => { emp } +| x != 0 => { [x, 2] ** x :-> v ** (x + 1) :-> c ** children(c) } +} + +predicate children(loc x) { +| x == 0 => { emp } +| x != 0 => { [x, 2] ** x :-> r ** rtree(r) ** (x + 1) :-> nxt ** children(nxt) } +} + +void dispose(loc x) +{ rtree(x) } +{ emp } +{ + ?? +} + diff --git a/src/test/resources/synthesis/tutorial/sll-to-dll.sus b/src/test/resources/synthesis/tutorial/sll-to-dll.sus new file mode 100644 index 000000000..f55467e46 --- /dev/null +++ b/src/test/resources/synthesis/tutorial/sll-to-dll.sus @@ -0,0 +1,33 @@ +# -c 2 +// convert a singly-linked list with a spare cell into a doubly-linked list + +predicate sll(loc x, set s) { +| x == 0 => { s == {} ; emp } +| x != 0 => { s == {v} + s1 ; [x, 2] ** x :-> v ** (x + 1) :-> nxt ** sll(nxt, s1) } +} + +predicate sll_reserved(loc x, set s) { +| x == 0 => { s == {} ; emp } +| x != 0 => { s == {v} + s1 ; [x, 3] ** x :-> v ** (x + 1) :-> nxt ** (x + 2) :-> 0 ** sll_reserved(nxt, s1) } +} + +predicate dll(loc x, loc y, set s) { +| x == 0 => { s == {} ; emp } +| x != 0 => { s == {v} + s1 ; [x, 3] ** x :-> v ** (x + 1) :-> nxt ** (x + 2) :-> y ** dll(nxt, x, s1) } +} + + + +void to_dll(loc x, loc prev) +{ sll_reserved(x, s) } +{ dll(x, prev, s) } +// void to_dll(loc x) +// { sll_reserved(x, s) } +// { dll(x, 0, s) } +// void to_dll(loc ret) +// { ret :-> x ** sll(x, s) } +// { ret :-> y ** dll(y, 0, s) } +{ + ?? +} + diff --git a/src/test/resources/synthesis/tutorial/swap.sus b/src/test/resources/synthesis/tutorial/swap.sus new file mode 100644 index 000000000..0717e9f4a --- /dev/null +++ b/src/test/resources/synthesis/tutorial/swap.sus @@ -0,0 +1,8 @@ +// swap values of two pointers + +void swap (loc x, loc y) +{ x :-> a ** y :-> b } +{ x :-> b ** y :-> a } +{ + ?? +} \ No newline at end of file diff --git a/src/test/resources/synthesis/tutorial/tree-flatten.sus b/src/test/resources/synthesis/tutorial/tree-flatten.sus new file mode 100644 index 000000000..d99c17812 --- /dev/null +++ b/src/test/resources/synthesis/tutorial/tree-flatten.sus @@ -0,0 +1,24 @@ +// flatten a tree into a doubly-linked list in-place; +// this task needs a recursive auxiliary function! + +predicate tree(loc x, set s) { +| x == 0 => { s == {} ; emp } +| x != 0 => { s == {v} ++ s1 ++ s2 ; + [x, 3] ** x :-> v ** (x + 1) :-> l ** (x + 2) :-> r ** tree(l, s1) ** tree(r, s2) } +} + +predicate dll(loc x, loc z, set s) { +| x == 0 => { s == {} ; emp } +| x != 0 => { s == {v} ++ s1 ; + [x, 3] ** x :-> v ** (x + 1) :-> y ** (x + 2) :-> z ** dll(y, x, s1) } +} + + +// Flatten a tree with root `x` +void flatten(loc x) +{ tree(x, s) } +{ dll(x, z, s) } +{ + ?? +} + diff --git a/src/test/scala/org/tygus/suslik/overloading/OverloadedOperatorsTests.scala b/src/test/scala/org/tygus/suslik/overloading/OverloadedOperatorsTests.scala index 02c8ab29d..216ad60fd 100644 --- a/src/test/scala/org/tygus/suslik/overloading/OverloadedOperatorsTests.scala +++ b/src/test/scala/org/tygus/suslik/overloading/OverloadedOperatorsTests.scala @@ -17,7 +17,7 @@ import org.tygus.suslik.util.SynStats class OverloadedOperatorsTests extends FunSpec with Matchers with SynthesisRunnerUtil { def resolveFromSpec(testName: String, text: String, out: String = "nope", params: SynConfig = defaultConfig): Specifications.Goal = { - val parser = new SSLParser + val parser = new SSLParser(params) val res = parser.parseGoal(text) if (!res.successful) { throw SynthesisException(s"Failed to parse the input:\n$res") diff --git a/src/test/scala/org/tygus/suslik/synthesis/CyclicTests.scala b/src/test/scala/org/tygus/suslik/synthesis/CyclicTests.scala index 5833f41bf..e883a2af5 100644 --- a/src/test/scala/org/tygus/suslik/synthesis/CyclicTests.scala +++ b/src/test/scala/org/tygus/suslik/synthesis/CyclicTests.scala @@ -23,9 +23,9 @@ class CyclicTests extends FunSpec with Matchers with SynthesisRunnerUtil { runAllTestsFromDir("cyclic-benchmarks/multi-list") } - describe("Guided") { - runAllTestsFromDir("cyclic-benchmarks/guided") - } +// describe("Guided") { +// runAllTestsFromDir("cyclic-benchmarks/guided") +// } describe("Single-Linked Lists") { runAllTestsFromDir("cyclic-benchmarks/sll") diff --git a/src/viz/index.html b/src/viz/index.html index c3c2c80c3..a1da73900 100644 --- a/src/viz/index.html +++ b/src/viz/index.html @@ -2,10 +2,11 @@ + SuSLik — interactive synthesis server -
+
diff --git a/src/viz/scripts/bundle-benchmarks-for-web.mjs b/src/viz/scripts/bundle-benchmarks-for-web.mjs new file mode 100644 index 000000000..eea2845ce --- /dev/null +++ b/src/viz/scripts/bundle-benchmarks-for-web.mjs @@ -0,0 +1,30 @@ +#!/usr/bin/env node + +import fs from 'fs'; +import path from 'path'; +import find from 'find'; + +const BENCHMARKS_ROOT = 'src/test/resources/synthesis/all-benchmarks', + TUTORIAL_ROOT = 'ext/tutorial'; + +function main() { + var physical = TUTORIAL_ROOT, logical = '.', + collection = {}; + + function bucket(k) { + var v = collection[k]; + if (!v) v = collection[k] = {}; + return v; + } + + find.eachfile(/\.(sus|syn|def)$/, physical, fn => { + var rel = path.join(logical, path.relative(physical, fn)), + reldir = path.dirname(rel), base = path.basename(rel); + console.log(reldir, '/', base); + bucket(reldir)[base] = fs.readFileSync(fn, 'utf-8'); + }).end(() => { + fs.writeFileSync('dist/benchmarks.db.json', JSON.stringify(collection)); + }); +} + +main(); \ No newline at end of file diff --git a/src/viz/ts/app.ts b/src/viz/ts/app.ts new file mode 100644 index 000000000..a17b1624f --- /dev/null +++ b/src/viz/ts/app.ts @@ -0,0 +1,265 @@ +import { EventEmitter } from 'events'; +import _ from 'lodash'; +import $ from 'jquery'; +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'; + +import './ide.css'; + + + +class SuSLikApp extends EventEmitter { + view: Vue & SuSLikApp.Props + notifications: JQuery + + doc: MainDocument + docsById = new Map() + + panes: {proofTrace: any, benchmarks: any, editors: any} + + constructor(notifications: JQuery) { + super(); + this.notifications = notifications; + this.view = new Vue(app).$mount(); + this.panes = this.view.$refs; /* I like the sound they make when they break */ + + this.panes.proofTrace.$on('action', ev => { + this.emit('proofTrace:action', ev); + }); + this.panes.benchmarks.$on('action', ev => { + this.emit('benchmarks:action', ev); + }); + this.view.$on('editor:change', () => this.clearMessages()); + } + + get $el() { return this.view.$el; } + + get options() { + return this.panes.proofTrace.options; + } + + add(doc: MainDocument) { + this.docsById.get(doc.id)?.close(); + this.docsById.set(doc.id, doc); + this.doc = doc; + doc.on('error', err => this.message(err.message, err.sticky)); + this.switchTo(doc.id); + } + + has(docId: string) { + return this.docsById.has(docId); + } + + switchTo(docId: string) { + var doc = this.docsById.get(docId); + if (doc) { + this.panes.proofTrace.activeTrace = docId; + this.doc = doc; + } + else console.warn(`no such document: '${docId}'`) + } + + clear() { + for (let doc of this.docsById.values()) doc.close(); + this.docsById.clear(); + this.doc = undefined; + this.clearMessages(); + } + + setBenchmarks(bmData: BenchmarksDB.Data) { + var bm = this.panes.benchmarks; + bm.data = bmData; + } + + setActiveBenchmark(activeBenchmark: SuSLikApp.BenchmarkEntry) { + this.view.activeBenchmark = activeBenchmark; + } + + hideBenchmarks() { + /** @todo */ + } + + setEditorText(text: string) { + this.panes.editors.open(text); + } + + getEditorText() { + return this.panes.editors.current(); + } + + /* Notifications Part */ + + private _fading: JQuery + + message(msg: string, sticky = false) { + var div = $('
').text(msg); + this._fading?.remove(); + this.notifications.append(div); + div.on('click', () => div.fadeOut()); + if (!sticky) + setTimeout(() => div.fadeOut(), SuSLikApp.MESSAGE_DURATION); + } + + clearMessages() { + var msgs = this.notifications.children('div'); + this._fading = msgs; + msgs.fadeOut(100); + } +} + + +namespace SuSLikApp { + export type BenchmarkEntry = { + path: {dir: string, fn: string} + }; + + export type Props = { + activeBenchmark: BenchmarkEntry + } + + export const MESSAGE_DURATION = 4000; +} + + +class MainDocument extends EventEmitter { + id: string + pane: Vue & ProofTrace.View.PaneProps & ProofInteraction.View.PaneProps + options: DocumentOptions + + pt: ProofTrace + pi: ProofInteraction + + props: any + + storage: {'suslik:doc:lastUrl'?: string} = localStorage; + + constructor(id: string, pane: Vue & ProofTrace.View.PaneProps & ProofInteraction.View.PaneProps, + options: DocumentOptions = {}) { + super(); + this.id = id; + this.pane = pane; + this.options = options; + } + + new() { + return this.setProofTrace(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 { + return this.setProofTrace(ProofTrace.Data.parse(content)); + } + catch (e) { + if (!opts.silent) { + var msg = (e instanceof SyntaxError) ? 'JSON format error' : 'read error'; + this.emit('error', {message: `Cannot open '${opts.name}': ${msg}`}); + } + } + } + } + + async openUrl(url: string, opts?: OpenOptions) { + var pt = await this.open(await (await fetch(url)).text(), opts) + if (pt) + this.storage['suslik:doc:lastUrl'] = url; + return pt; + } + + openRecent(opts?: OpenOptions) { + return this.openUrl(this.storage['suslik:doc:lastUrl'] || MainDocument.DEFAULT_URL, opts); + } + + setProofTrace(ptData: ProofTrace.Data) { + this.pt?.destroy(); + this.pi?.destroy(); + + var pt = new ProofTrace(this.id, ptData, this.pane), + pi = new ProofInteraction(pt, this.pane); + this.pt = pt; + this.pi = pi; + pt.on('expand', (nodeView: ProofTrace.View.Node) => { + if (nodeView.value.tag == ProofTrace.Data.NodeType.OrNode && + nodeView.children.length == 0) { + /* send request to server */ + if (this.pi) this.pi.sendExpandRequest(nodeView.value.id); + } + }); + + pi.on('trace', throttleCollate((values: [any][]) => { + 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', {...err, message: `oops: ${err.message}`})); + + this.emit('open', pt); + return pt; + } + + async read(file: File) { + return new TextDecoder().decode(await file.arrayBuffer()); + } + + close() { + this.pt?.destroy(); + this.pi?.destroy(); + } +} + +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 { + + constructor(container: JQuery) { + super(); + container.on('dragover', (ev) => { + ev.preventDefault(); + }); + container.on('drop', (ev) => { + this.drop(ev.originalEvent.dataTransfer); + ev.preventDefault(); + }); + } + + async drop(dt: DataTransfer) { + if (dt.files.length == 1) { + this.emit('open', {file: dt.files[0]}); + } + else this.emit('error', "Can only process one file at a time"); + } +} + + +/** + * 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/benchmarks.ts b/src/viz/ts/benchmarks.ts new file mode 100644 index 000000000..8175bd15b --- /dev/null +++ b/src/viz/ts/benchmarks.ts @@ -0,0 +1,81 @@ + + +class BenchmarksDB { + data: BenchmarksDB.Data + + constructor(data: BenchmarksDB.Data) { + this.data = data; + } + + getSpec(dir: string, fn: string): BenchmarksDB.Data.Spec { + return { + name: `${dir}:${fn}`, + spec: { + defs: this.getDefs(dir), + ...this.getInputSpec(dir, fn) + } + }; + } + + getDefs(dir: string) { + return Object.entries(this.data[dir]) + .map(([fn, txt]) => fn.endsWith('.def') && txt).filter(x => x); + } + + getInputSpec(dir: string, fn: string) { + var prog = this.data[dir][fn]; + return {...BenchmarksDB.Data.parseInputSpec(prog), + config: {inputFormat: this.getFormat(fn)}}; + } + + getFormat(fn: string): [string] { + return fn.endsWith('.syn') ? ['syn'] : + fn.endsWith('.sus') ? ['sus'] : + undefined; + } + + static async load(url = './benchmarks.db.json') { + return new BenchmarksDB(await (await fetch(url)).json()); + } +} + +namespace BenchmarksDB { + export type Data = {[dir: string]: {[fn: string]: string}}; + + export namespace Data { + export type Spec = { + name?: string + spec: { + defs: string[] + in: string + config?: SpecConfig + } + params?: string[] + } + + export type SpecConfig = { + inputFormat?: [string] /* contained in an array to serialize as Option[String] in Scala */ + } + + export function parseSpec(name: string, text: string): Spec { + var inputSpec = parseInputSpec(text); + return {name, spec: {defs: [], ...inputSpec}, params: inputSpec.params}; + } + + export function parseInputSpec(text: string) { + var hashline = text.match(/^#[.]?(.*)\n([^]*)/), + enclosure = text.match(/###+([^]*?)###+/), + params = hashline?.[1].trim().split(/\s+/), + in_ = enclosure?.[1] || hashline?.[2] || text; + return {in: in_, params}; + } + + export function unparseSpec(spec: Spec) { + var params = spec.params ? [`# ${spec.params.join(' ')}`] : []; + return [...params, ...spec.spec.defs, spec.spec.in].join('\n'); + } + } +} + + +export { BenchmarksDB } diff --git a/src/viz/ts/editor.ts b/src/viz/ts/editor.ts new file mode 100644 index 000000000..3ebc3f98e --- /dev/null +++ b/src/viz/ts/editor.ts @@ -0,0 +1,89 @@ +import { StreamLanguage, StreamParser, StringStream } from '@codemirror/stream-parser'; +import { defaultHighlightStyle, classHighlightStyle } from '@codemirror/highlight'; + + +class SuslikSyntaxHighlighting implements StreamParser<{}> { + + rules: {start: {token: string | ((t: string) => string), regex: RegExp}[]} + token: (stream: StringStream, state: {}) => string + + constructor() { + this.rules = SuslikSyntaxHighlighting.rules(); + + this.token = (stream: StringStream, state: {}) => { + for (let {token, regex} of this.rules.start) { + let mo = stream.match(regex); + if (mo) + return (typeof token === 'function') ? token(mo[0]) : token; + } + + stream.next(); + return null; + } + } +} + +namespace SuslikSyntaxHighlighting { + + export function rules() { + var keywords = + ("if|else|true|false|emp|not|predicate|in").split("|"); + + var builtInTypes = + ("bool|int|loc|set|void").split("|"); + + var operators = + ("+|-|==|!=|<|<=|>|>=|&&|\|\||=>==>|**|:->|?|:|,|\||;").split("|"); + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + return { + "start" : [ + { + token : 'comment', + regex : /\/\/.*$/ + }, + { + token : 'bool', + regex : /(?:true|false|e)\b/ + }, + { + token : function(value) { + if (keywords.includes(value)) + return 'keyword'; + else if (builtInTypes.includes(value)) + return 'typeName'; + else + return 'variableName'; + }, + regex : /[a-zA-Z_'$][a-zA-Z0-9_'$]*\b/ + }, + { + token : 'operator', + regex : /\*\*|\+|-|==|!=|<|<=|>|>=|&&|\|\||=>|==>|:->|:|\?\??/ + }, + { + token : 'paren', + regex : /[[({]/ + }, + { + token : 'paren', + regex : /[\])}]/ + }, + { + token : null, + regex : /\s+/ + } + ], + }; + }; +} + +const parser = new SuslikSyntaxHighlighting(); + +export const suslikLanguage = [ + StreamLanguage.define(parser), + defaultHighlightStyle, + classHighlightStyle +]; \ No newline at end of file diff --git a/src/viz/ts/ide.css b/src/viz/ts/ide.css new file mode 100644 index 000000000..b22d18bd4 --- /dev/null +++ b/src/viz/ts/ide.css @@ -0,0 +1,43 @@ +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; +} + +.cm-editor .cmt-operator { + color: #88d; +} + +#notifications { + position: fixed; + bottom: 0; + right: 0; + z-index: 99; +} + +#notifications > div { + background: #fbb; + color: #333; + padding: 9px 1em; + white-space: pre-wrap; +} diff --git a/src/viz/ts/infra/event-hooks.ts b/src/viz/ts/infra/event-hooks.ts new file mode 100644 index 000000000..3bf1d742d --- /dev/null +++ b/src/viz/ts/infra/event-hooks.ts @@ -0,0 +1,27 @@ +import type Vue from 'vue'; + + +class VueEventHook { + event: string + instance: Vue + eh: Function + + constructor(event: string) { this.event = event; } + + attach(instance: Vue, eh: Function) { + this.detach(); + this.instance = instance; + this.eh = eh; + instance.$on(this.event, eh); + } + + detach() { + if (this.instance) { + this.instance.$off(this.event, this.eh); + this.instance = this.eh = undefined; + } + } +} + + +export { VueEventHook } diff --git a/src/viz/ts/main.ts b/src/viz/ts/main.ts index af1a52a10..48b30a2a6 100644 --- a/src/viz/ts/main.ts +++ b/src/viz/ts/main.ts @@ -1,5 +1,9 @@ import $ from 'jquery'; -import { MainDocument, DragDropJson } from './open'; +import { SuSLikApp, MainDocument, DragDropJson } from './app'; +import { ProofInteraction } from './proof-interaction'; +import { BenchmarksDB } from './benchmarks'; + +import ProofMode = ProofInteraction.Data.ProofMode; @@ -7,7 +11,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}); @@ -17,21 +21,124 @@ if (typeof nw !== 'undefined') { $(async () => { - var doc = new MainDocument($('#proof-trace-pane'), $('#notifications')); + var app = new SuSLikApp($('#notifications')); + + document.querySelector('#document-area').replaceWith(app.$el); + + const bench = await BenchmarksDB.load(); + if (window.location.search !== '?cheater!') + delete bench.data['solutions']; // :P + + const DEFAULT_SCRATCH = {dir: 'scratchpath', fn: 'untitled-0.sus'} + bench.data[DEFAULT_SCRATCH.dir] = { + [DEFAULT_SCRATCH.fn]: '// write your own stuff here' + }; + + app.setBenchmarks(bench.data); + + var activeBenchmark: {name: string, spec: BenchmarksDB.Data.Spec} = { + name: 'benchmark-0', /** @todo */ + spec: undefined + }; + + async function startBenchmark(w: {dir: string, fn: string}, mode: {proof: ProofMode, simple: boolean} = {proof: ProofMode.INTERACTIVE, simple: false}) { + var spec = bench.getSpec(w.dir, w.fn), + docId = makeDocId(activeBenchmark.name, mode), + doc = new MainDocument(docId, app.panes.proofTrace, + OPTIONS[mode.proof]); + doc.new(); + //app.hideBenchmarks(); + app.setActiveBenchmark({path: w}); + app.clear(); + app.setEditorText(BenchmarksDB.Data.unparseSpec(spec)); + app.add(doc); + adjustParams(spec, mode); + activeBenchmark.spec = spec; + if (mode.proof !== ProofMode.AUTOMATIC) // `startBenchmark` is a misnomer at this point... :/ + await doc.pi.start(spec, mode.proof); + } + + /** @todo Pretty hideous duplication do refactor please */ + async function restartBenchmark(mode: {proof: ProofMode, simple: boolean} = {proof: ProofMode.INTERACTIVE, simple: false}) { + var spec = BenchmarksDB.Data.parseSpec(activeBenchmark.name, app.getEditorText()), + docId = makeDocId(activeBenchmark.name, mode), + doc = new MainDocument(docId, app.panes.proofTrace, + OPTIONS[mode.proof]); + doc.new(); + app.clearMessages(); + app.add(doc); + adjustParams(spec, mode); + spec.spec.config = activeBenchmark.spec.spec.config; + await doc.pi.start(spec, mode.proof); + } + + function stopBenchmark() { + app.doc.pi?.stop(); + } + + function makeDocId(name: string, mode: {proof: ProofMode, simple: boolean}) { + return `${name}-${mode.proof}${mode.simple ? '-simple' : ''}`; + } + + function adjustParams(spec: BenchmarksDB.Data.Spec, mode: {proof: ProofMode, simple: boolean}) { + if (mode.simple) + spec.params = ['--simple', 'true', ...(spec.params || [])]; + } + + async function switchMode(mode: {proof: ProofMode, simple: boolean}) { + var docId = makeDocId(activeBenchmark.name, mode); + if (app.has(docId)) + app.switchTo(docId); + else + restartBenchmark(mode); + } + + function currentMode() { + return { + proof: app.options.auto ? ProofMode.AUTOMATIC : ProofMode.INTERACTIVE, + simple: app.options.simple + } + } + + app.view.$watch(currentMode, switchMode); /* neat ;) */ + + const OPTIONS: {[mode: string]: MainDocument.Options} = { + [ProofMode.AUTOMATIC]: {throttle: 750}, + [ProofMode.INTERACTIVE]: {expandImmediately: true} + }; + + app.on('benchmarks:action', w => startBenchmark(w, currentMode())); + app.on('proofTrace:action', (action) => { + switch (action.type) { + case 'start': + case 'restart': restartBenchmark(currentMode()); break; + case 'stop': stopBenchmark(); break; + } + }); + + /* 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}); + var doc = new MainDocument('json-0', app.panes.proofTrace) + await doc.open(file); + app.add(doc); } - catch (e) { } + catch (e) { console.error('open failed:', e); } }); - Object.assign(window, {doc}); + /* Start a benchmark on load if instructed so by local config */ + var openOnStart = localStorage['openOnStart']; + openOnStart = openOnStart ? JSON.parse(openOnStart) : DEFAULT_SCRATCH; + if (openOnStart) { + startBenchmark(openOnStart, currentMode()); + } + + Object.assign(window, {app, bench}); }); \ No newline at end of file diff --git a/src/viz/ts/open.ts b/src/viz/ts/open.ts deleted file mode 100644 index 96392ffb6..000000000 --- a/src/viz/ts/open.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { EventEmitter } from 'events'; -import $ from 'jquery'; - -import { ProofTrace } from './proof-trace'; - - - -class MainDocument { - - pane: JQuery - notifications: JQuery - - storage: {'suslik:doc:lastUrl'?: string} = localStorage; - - constructor(pane: JQuery, notifications: JQuery) { - this.pane = pane; - this.notifications = notifications; - } - - async open(content: string | File, opts: OpenOptions = {}) { - 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); - - this.pane.replaceWith(this.pane = $(pt.view.$el)); - return pt; - } - catch (e) { - if (!opts.silent) { - var msg = (e instanceof SyntaxError) ? 'JSON format error' : 'read error'; - this.message(`Cannot open '${opts.name}': ${msg}`); - } - } - } - } - - async openUrl(url: string, opts?: OpenOptions) { - this.storage['suslik:doc:lastUrl'] = url; - return this.open(await (await fetch(url)).text(), opts) - } - - openRecent(opts?: OpenOptions) { - return this.openUrl(this.storage['suslik:doc:lastUrl'] || DEFAULT_URL, opts); - } - - async read(file: File) { - return new TextDecoder().decode(await file.arrayBuffer()); - } - - message(msg: string) { - var div = $('
').text(msg); - this.notifications.append(div); - setTimeout(() => div.remove(), 4000); - } -} - -type OpenOptions = {name?: string, silent?: boolean}; -const DEFAULT_URL = '/trace.out'; - - -class DragDropJson extends EventEmitter { - - constructor(container: JQuery) { - super(); - container.on('dragover', (ev) => { - ev.preventDefault(); - }); - container.on('drop', (ev) => { - this.drop(ev.originalEvent.dataTransfer); - ev.preventDefault(); - }); - } - - async drop(dt: DataTransfer) { - if (dt.files.length == 1) { - this.emit('open', {file: dt.files[0]}); - } - else this.emit('error', "Can only process one file at a time"); - } -} - - - -export { MainDocument, OpenOptions, DragDropJson } diff --git a/src/viz/ts/proof-interaction.css b/src/viz/ts/proof-interaction.css new file mode 100644 index 000000000..8107ec8fd --- /dev/null +++ b/src/viz/ts/proof-interaction.css @@ -0,0 +1,18 @@ +.proof-interaction-choices div.goal { + display: inline-block; + max-width: 20em; + vertical-align: top; + margin-right: .5em; + border: 1px solid #888; + padding: 2px; +} + +.proof-trace .proof-trace-highlight-interact-focus { + outline: 3px solid violet; +} + +.proof-interaction-result div.procedure { + font-family: Courier, Consolas, 'Courier New', monospace; + font-size: 10pt; + white-space: pre; +} \ No newline at end of file diff --git a/src/viz/ts/proof-interaction.ts b/src/viz/ts/proof-interaction.ts new file mode 100644 index 000000000..ceca4763e --- /dev/null +++ b/src/viz/ts/proof-interaction.ts @@ -0,0 +1,178 @@ +import { EventEmitter } from 'events'; +import Vue from 'vue'; + +import { VueEventHook } from './infra/event-hooks'; +import type { ProofTrace } from './proof-trace'; +import type { BenchmarksDB } from './benchmarks'; + +import './proof-interaction.css'; + + + +class ProofInteraction extends EventEmitter { + wsURL: string + ws: WebSocket + + pt: ProofTrace + view: View.State + + _actionHook = new VueEventHook('interaction:action') + + defaultMode = ProofInteraction.Data.ProofMode.INTERACTIVE + + constructor(pt: ProofTrace, pane: Vue & View.PaneProps) { + super(); + this.wsURL = this._wsURL(); + this.pt = pt; + this.createView(pane); + } + + get id() { return this.pt.id; } + + createView(pane: Vue & View.PaneProps) { + this.view = {focused: [], choices: undefined, result: undefined}; + Vue.set(pane.docs[this.id], 'interaction', this.view); + this._actionHook.attach(pane, action => this.handleAction(action)); + } + + destroy() { + this._actionHook.detach(); + this.ws?.close(); + } + + async start(spec?: Data.Spec, mode?: Data.ProofMode) { + this.ws = new WebSocket(this.wsURL); + this.ws.addEventListener('message', m => this.handleMessage(m.data)); + await new Promise((resolve, reject) => { + 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); + } + + /** + * For auto mode, terminates ongoing computation. + */ + stop() { + this.destroy(); // possibly can still allow expanding nodes after termination; not currently supported + } + + sendSpec(spec: Data.Spec, mode: Data.ProofMode = this.defaultMode) { + this._send({mode, ...spec}, ProofInteraction.Data.Classes.SPEC); + } + + 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) { + if (this.ws.readyState !== WebSocket.OPEN) { + this.emit('error', {message: 'disconnected from server'}); + return; + } + this.ws.send(JSON.stringify($type ? {$type, ...json} : json)) + } + + handleMessage(data: string) { + try { + var msg = JSON.parse(data); + } + catch { console.error(data); return; } + + this.emit('message', msg); + + if (Array.isArray(msg)) { + this.view.focused = this.getNodesForChoices(msg); + this.view.choices = msg; + this.emit('choose', msg); + } + else if (msg.procs) { + this.view.result = msg; + this.emit('done', msg); + } + else if (msg.tag === 'SynthesisStatsEntry') { console.log('stats', msg); /** @todo */ } + else if (msg.error) this.emit('error', {message: msg.error, sticky: msg.sticky}); + else this.emit('trace', msg); + } + + handleAction(action: View.Action) { + switch (action.type) { + case 'select': + this.view.choices = undefined; // clear choices + this.sendChoose(action.goal.id); + break; + } + } + + getNodesForChoices(choices: {from: ProofTrace.Data.GoalId[]}[]): ProofTrace.Data.NodeId[] { + var ret: ProofTrace.Data.NodeId[] = []; + for (let choice of choices) { + for (let goalId of choice.from) { + let node = this.pt.nodeIndex.byGoalId.get(goalId); + if (node) ret.push(node.id); + } + } + return ret; + } + + _wsURL() { + switch (window.location.protocol) { + case 'https:': return `wss://${location.host}${location.pathname}`; + case 'http:': return `ws://${location.host}${location.pathname}`; + default: return 'ws://localhost:8033'; // dev mode + } + } +} + + +import Data = ProofInteraction.Data; +import View = ProofInteraction.View; + + +namespace ProofInteraction { + + export namespace Data { + + 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 = BenchmarksDB.Data.Spec; + + export enum ProofMode { + AUTOMATIC = "automatic", + INTERACTIVE = "interactive" + } + } + + export namespace View { + + export type PaneProps = {docs: {[id: string]: {interaction: State}}}; + + export type State = { + focused: ProofTrace.Data.NodeId[] + choices: ProofTrace.Data.GoalEntry[] + result: {procs: {pp: string}[]} + }; + + export type Action = { + type: 'select' + goal?: ProofTrace.Data.GoalEntry + }; + + } + +} + + + +export { ProofInteraction } \ No newline at end of file diff --git a/src/viz/ts/proof-trace.css b/src/viz/ts/proof-trace.css index 8ab3a29ea..1ef73ec70 100644 --- a/src/viz/ts/proof-trace.css +++ b/src/viz/ts/proof-trace.css @@ -1,14 +1,15 @@ #proof-trace-pane { padding-bottom: 25%; + padding-left: .5em; } -.proof-trace-pane-area { +.proof-trace-pane-rendered { transform: scale(var(--zoom)); transform-origin: 0 0; } .proof-trace .subtrees { - white-space: nowrap; + display: flex; } .proof-trace-node { @@ -26,11 +27,16 @@ cursor: default; } +.proof-trace-node > .title > span.pp { + margin-right: .75em; +} + .proof-trace-node > .title > span.goal-id, .proof-trace-node > .title > span.cost, .proof-trace-node > .title > span.tag, -.proof-trace-node > .title > span.num-descendants { - float: right; +.proof-trace-node > .title > span.num-descendants, +.proof-trace-node > .title > span.call { + float: right; margin-left: 1em; font-family: 'Times New Roman', Times, serif; font-size: 90%; @@ -51,12 +57,28 @@ line-height: 1pt; } +.proof-trace-node > .title > span.call::before { + content: "📣"; + line-height: 1pt; +} + .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-goal .proof-trace-sketch { + color: #66e; + font-family: Courier, Consolas, 'Courier New', monospace; + font-size: 80%; +} + .proof-trace-node:hover > .proof-trace-goal { background: #fff; } @@ -67,6 +89,7 @@ margin-right: 0.2em; margin-bottom: 0.5em; vertical-align: top; + flex-shrink: 0; } .proof-trace-vars > span:not(:last-child)::after { @@ -129,6 +152,10 @@ background: #eee; } +.proof-trace-formula span.null-cardinality { + display: none; +} + .proof-trace:not(:last-child) { border-top: 1px solid #aaa; margin-right: 0; @@ -141,6 +168,8 @@ .proof-trace-node.AndNode { background: #999; color: #ddd; + padding-left: .4em; + padding-right: .3em; } .proof-trace-node.AndNode:hover { @@ -216,6 +245,26 @@ display: inline; } +.proof-trace-node-subordinate { + background: #fffe; + border: 1px solid #aaa; +} +.proof-trace-node-subordinate > .title { + text-align: right; + padding: 0 .25em; + font-size: 90%; + margin-bottom: -.25em; +} +.proof-trace-node-subordinate > .title span.goal-id { + border: 1px solid #aaf; + border-radius: 5px; + padding: 0 3px; + background: #bbf2; +} +.proof-trace-node-subordinate > .proof-trace-goal { + border: none; +} + /* Filters */ .proof-trace-filter--only-success .proof-trace:not(.Succeeded):not(.Succeeded\*) { @@ -229,11 +278,11 @@ /* Toobar */ .proof-trace-toolbar { - position: fixed; + position: sticky; top: 0; - left: 20em; + left: 2em; + width: calc(100% - 2em); background: #ffffffd0; - padding: 1em 5em .75em 1em; z-index: 1; } @@ -249,14 +298,3 @@ padding: .1em .5em; background: #ddd; } - -#notifications { - position: fixed; - top: 0; - right: 0; -} -#notifications > div { - background: #fbb; - color: #333; - padding: 9px; -} diff --git a/src/viz/ts/proof-trace.ts b/src/viz/ts/proof-trace.ts index a8d286a3c..11729c9ec 100644 --- a/src/viz/ts/proof-trace.ts +++ b/src/viz/ts/proof-trace.ts @@ -1,65 +1,104 @@ +import { EventEmitter } from 'events'; import arreq from 'array-equal'; -import $ from 'jquery'; -import Vue from 'vue/dist/vue'; -import { VueContext } from 'vue-context' +import Vue from 'vue'; import 'vue-context/dist/css/vue-context.css'; +import { VueEventHook } from './infra/event-hooks'; + import './proof-trace.css'; import './menu.css'; -class ProofTrace { +class ProofTrace extends EventEmitter { + id: string data: Data root: Data.NodeEntry nodeIndex: { byId: JSONMap + byGoalUid: JSONMap childrenById: JSONMap subtreeSizeById: JSONMap statusById: JSONMap + derivationById: JSONMap + derivationByGoalUid: JSONMap viewById: JSONMap } - view: Vue + view: View.Props + + _actionHook = new VueEventHook('action') + _dirty: {nodes: Set} = {nodes: new Set} - constructor(data: ProofTrace.Data) { + constructor(id: string, data: ProofTrace.Data, pane?: Vue & View.PaneProps) { + super(); + this.id = id; this.data = data; this.root = this.data.nodes[0]; this.createIndex(); - this.createView(); + this.createView(pane); + } + + append(data: Data, opts: {expand?: boolean} = {}) { + Data.append(this.data, data); + this.updateIndex(data); + for (let node of data.nodes) + this.addNode(node, opts); + this.refreshView(); } createIndex() { this.nodeIndex = { - byId: new JSONMap(), - childrenById: new JSONMap(), subtreeSizeById: new JSONMap(), - statusById: new JSONMap(), - viewById: new JSONMap() + byId: new JSONMap, byGoalUid: new JSONMap, + childrenById: new JSONMap, subtreeSizeById: new JSONMap, + statusById: new JSONMap, derivationById: new JSONMap, + derivationByGoalUid: new JSONMap, + viewById: new JSONMap }; - // Build byId - for (let node of this.data.nodes) { - if (!this.nodeIndex.byId.get(node.id)) - this.nodeIndex.byId.set(node.id, node); + this.updateIndex(this.data); + } + + updateIndex(data: Data) { + // Build byId, byGoalId + for (let node of data.nodes) { + this.nodeIndex.byId.set(node.id, node); + if (node.goal) + this.nodeIndex.byGoalUid.set(node.goal.uid, 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); + } + } + + let update = (m: JSONMap, + node: Data.NodeEntry, value: T) => { + if (!node) return; + var key = node.id, old = m.get(key); + if (value !== old) { /** @todo better equality check */ + m.set(key, value); + this._dirty.nodes.add(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); + update(this.nodeIndex.statusById, + this.nodeIndex.byId.get(id), entry); } - for (let node of this.data.nodes.sort((a, b) => b.id.length - a.id.length)) { + // - compute transitive success + // This has to be computed over *all* data; can optimize by only + // considering ancestors of newly indexed nodes + var nodesBottomUp = this.data.nodes.slice().sort((a, b) => b.id.length - a.id.length) + for (let node of nodesBottomUp) { if (!this.nodeIndex.statusById.get(node.id)) { let children = (this.nodeIndex.childrenById.get(node.id) || []) .map(c => this.nodeIndex.statusById.get(c.id)); @@ -67,12 +106,14 @@ class ProofTrace { switch (node.tag) { case Data.NodeType.OrNode: if (children.some(x => x && x.status.tag === 'Succeeded')) - this.nodeIndex.statusById.set(node.id, {at: node.id, status: {tag: 'Succeeded', from: '*'}}); + update(this.nodeIndex.statusById, node, + {at: node.id, status: {tag: 'Succeeded', from: '*'}}); break; case Data.NodeType.AndNode: if (children.length == node.nChildren && children.every(x => x && x.status.tag === 'Succeeded')) - this.nodeIndex.statusById.set(node.id, {at: node.id, status: {tag: 'Succeeded', from: '*'}}); + update(this.nodeIndex.statusById, + node, {at: node.id, status: {tag: 'Succeeded', from: '*'}}); break; } } @@ -80,15 +121,35 @@ class ProofTrace { } // Build subtreeSizeById + // (same here) 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 nodesBottomUp) { 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)); + update(sz, node, 1 + children.map(u => sz.get(u.id) || 1) + .reduce((x,y) => x + y, 0)); + } + + // Build derivationById, derivationByGoalId + for (let deriv of data.trail) { + for (let goalUid of deriv.to) { + this.nodeIndex.derivationByGoalUid.set(goalUid, deriv); + let node = this.nodeIndex.byGoalUid.get(goalUid), + parent = node && this.parent(node); + if (parent) + update(this.nodeIndex.derivationById, parent, deriv); + } + } + + for (let node of data.nodes) { + if (node.goal) { + var deriv = this.nodeIndex.derivationByGoalUid.get(node.goal.uid); + if (deriv) + update(this.nodeIndex.derivationById, this.parent(node), deriv); + } } } - 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) || []; @@ -96,6 +157,11 @@ class ProofTrace { m.set(parent, l.concat([child])); } + parent(node: Data.NodeEntry) { + var id = Data.parentId(node.id); + 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); @@ -112,14 +178,48 @@ class ProofTrace { .sort(byId2); // modifies the list but that's ok } - createView() { - this.view = new (Vue.component('proof-trace-pane'))(); - this.view.root = this.createNode(this.root); - this.expandNode(this.view.root); - this.expandNode(this.view.root.children[0]); - this.view.$mount(); + createView(pane: Vue & View.PaneProps) { + this.view = {root: undefined}; + this._dirty.nodes.clear(); + if (this.root) { + this.view.root = this.createNode(this.root); + this.expandNode(this.view.root); + if (this.view.root.children?.[0]) /* a bit arbitrary I know */ + this.expandNode(this.view.root.children[0]); + } + + Vue.set(pane.docs, this.id, {trace: this.view}); + this._actionHook.attach( + pane, (ev: View.ActionEvent) => this.viewAction(ev)); + } + + refreshView() { + for (let node of this._dirty.nodes) + this.refreshNode(node); + this._dirty.nodes.clear(); + } - this.view.$on('action', (ev: View.ActionEvent) => this.viewAction(ev)); + destroy() { + this._actionHook.detach(); + } + + 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); + } + else { + var parentId = Data.parentId(node.id), + parentView = this.nodeIndex.viewById.get(parentId); + if (parentView) { + parentView.children ??= []; + parentView.children.push(this.createNode(node)); + if (opts.expand) { /** @todo only if parent is visible */ + parentView.focus = true; + parentView.expanded = true; + } + } + } } getStatus(node: Data.NodeEntry): Data.GoalStatusEntry { @@ -131,26 +231,41 @@ class ProofTrace { return this.nodeIndex.subtreeSizeById.get(node.id) || 1; } + getDerivationTrail(node: Data.NodeEntry): Data.DerivationTrailEntry { + return this.nodeIndex.derivationById.get(node.id); + } + 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)}; this.nodeIndex.viewById.set(node.id, v); return v; } - expandNode(nodeView: View.Node, focus: boolean = false) { + refreshNode(node: Data.NodeEntry) { + var view = this.nodeIndex.viewById.get(node.id); + if (view) { + view.status = this.getStatus(node); + view.derivation = this.getDerivationTrail(node); + view.numDescendants = this.getSubtreeSize(node); + } + } + + expandNode(nodeView: View.Node, focus: boolean = false, emit: boolean = true) { nodeView.focus = focus; nodeView.expanded = true; nodeView.children = this.children(nodeView.value) .map(node => this.createNode(node)); + if (emit) this.emit('expand', nodeView); } expandOrNode(nodeView: View.Node, focus: boolean = false) { this.expandNode(nodeView, focus); for (let c of nodeView.children) { if (c.value.tag == Data.NodeType.AndNode) { - this.expandOrNode(c, focus); + this.expandNode(c, focus); } } } @@ -173,12 +288,14 @@ class ProofTrace { } expandAll(nodeView: View.Node = this.view.root) { - this.expandNode(nodeView); + this.expandNode(nodeView, false, false); for (let c of nodeView.children) this.expandAll(c); } viewAction(ev: View.ActionEvent) { + if (ev.id !== this.id) return; + switch (ev.type) { case 'expand': this.expandOrNode(ev.target, true); break; @@ -200,7 +317,8 @@ namespace ProofTrace { export type Data = { nodes: Data.NodeEntry[], - statuses: Data.StatusEntry[] + statuses: Data.StatusEntry[], + trail: Data.DerivationTrailEntry[] }; export namespace Data { @@ -216,15 +334,28 @@ namespace ProofTrace { export type NodeId = number[]; export enum NodeType { AndNode = 'AndNode', OrNode = 'OrNode' }; + const NODE_TAGS = Object.values(NodeType); export type GoalEntry = { - id: string - pre: string, post: string, sketch: string, + id: GoalId + uid: GoalUid + pre: AssertionEntry, post: AssertionEntry, sketch: string, programVars: [string, string][] existentials: [string, string][] ghosts: [string, string][] }; + export type GoalId = string /* this is actually the label */ + export type GoalUid = string + + export type AssertionEntry = { + pp: String, + phi: AST[], + sigma: AST[] + }; + + export type AST = any /** @todo */ + export type Environment = Map; export type StatusEntry = { @@ -234,15 +365,46 @@ 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 empty() { + 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)); - var nodes = [], statuses = []; + 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 (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 parentId(id: NodeId) { + return id.slice(1); } export function envOfGoal(goal: GoalEntry) { @@ -262,17 +424,23 @@ namespace ProofTrace { // View Part // ========= export namespace View { + + export type PaneProps = {docs: {[id: string]: {trace: Props}}}; + + export type Props = {root: View.Node}; export type Node = { value: Data.NodeEntry children: Node[] numDescendants: number - status: Data.GoalStatusEntry + status?: Data.GoalStatusEntry + derivation?: Data.DerivationTrailEntry focus: boolean expanded: boolean }; export type ActionEvent = { + id?: string /* document id */ type: "expand" | "collapse" | "expandAll" | "menu" | "copyNodeId" | "copyGoalId" | "copyGoal", target: Node @@ -294,9 +462,10 @@ namespace ProofTrace { return {kind: 'whitespace', text: s}; else if (s.match(/^[(){}[\]]$/)) return {kind: 'brace', text: s}; - else if (mo = s.match(/^<(\w+)>$/)) { + else if (s === '<0>') + return {kind: 'null-cardinality', text: ''} + else if (mo = s.match(/^<(\w+)>$/)) return {kind: 'cardinality', text: s, pp: pprintIdentifier(mo[1])}; - } else if (s != '') return {kind: 'unknown', text: s}; }) @@ -315,7 +484,6 @@ import Data = ProofTrace.Data; import View = ProofTrace.View; - abstract class KeyedMap { _map: Map = new Map(); abstract key(k: K): K0; @@ -332,229 +500,5 @@ class JSONMap extends KeyedMap { } -Vue.component('proof-trace-pane', { - props: ['root'], - data: () => ({options: {}, zoom: 1}), - template: ` -
- - -
- -
-
`, - methods: { - toplevelAction(ev) { - switch (ev.type) { - case 'menu': this.$refs.contextMenu.open(ev); break; - } - this.$emit('action', ev); - } - } -}); - -Vue.component('proof-trace', { - props: ['root'], - data: () => ({statusClass: undefined}), - template: ` -
- -
`, - mounted() { - this.$watch('root.expanded', () => { - requestAnimationFrame(() => { - if (this.root.focus && this.$refs.subtrees) - this.focusElement(this.$refs.subtrees); - }); - }); - if (this.$refs.nroot) - this.statusClass = this.$refs.nroot.statusClass; - }, - methods: { - action(ev) { this.$emit('action', ev); }, - nodeAction(ev) { - if (ev.type == 'expand/collapse') { - this.root.expanded = !this.root.expanded; - ev.type = this.root.expanded ? 'expand' : 'collapse'; - } - this.action({...ev, target: this.root}); - }, - expandAll() { this.action({type: 'expandAll', target: this.root})}, - focusElement(el: HTMLElement) { - var box = el.getBoundingClientRect(), clrse = 50, - viewport = (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'}); - } - } -}); - -Vue.component('proof-trace-node', { - props: ['value', 'status', 'numDescendants'], - data: () => ({_anchor: false}), - template: ` -
-
- {{value.pp}} - {{value.cost}} - {{numDescendants}} - {{value.goal.id}} - {{tag}} -
- -
`, - computed: { - tag() { - var pfx = (this.value.tag == Data.NodeType.OrNode) ? 2 : 1; - return this.value.id.slice(0, pfx) - .reverse().filter((n:number) => n >= 0).join('→'); - }, - statusClass() { - if (this.status) { - var {tag, from: fr} = this.status, - suffix = fr ? (fr === '*' ? '*' : `-${fr}`) : '' - return `${tag}${suffix}`; - } - else return undefined; - } - }, - methods: { - action(ev) { this.$emit('action', ev); }, - toggle() { this.action({type: 'expand/collapse', target: this.value}); }, - showId() { $('#hint').text(JSON.stringify(this.value.id)); }, - hideId() { $('#hint').empty(); }, - - showRefs(ev) { - var el = ev.target; - if (['var', 'name', 'cardinality'].some(c => el.classList.contains(c))) { - this.varSpans(el.textContent).addClass('highlight'); - } - }, - hideRefs() { - this.varSpans().removeClass('highlight'); - }, - varSpans(nm?: string) { - if (nm) return this.varSpans().filter((_,x: Node) => x.textContent == nm); - else { - var el = $(this.$el); - return el.find('span.var, span.cardinality, .proof-trace-vars span.name'); - } - }, - - stopDbl(ev) { if (ev.detail > 1) ev.preventDefault(); }, - // boilerplate to prevent click after selection - clickStart(ev) { this.$data._anchor = {x: ev.pageX, y: ev.pageY}; }, - clickCapture(ev) { - var a = this.$data._anchor; - if (a && (Math.abs(ev.pageX - a.x) > 3 || Math.abs(ev.pageY - a.y) > 3)) - ev.stopPropagation(); - } - } -}); - -Vue.component('proof-trace-goal', { - props: ['value'], - template: ` -
- - - -
{{value.sketch}}
- -
`, - computed: { - env() { return Data.envOfGoal(this.value); } - } -}); - -Vue.component('proof-trace-vars', { - props: ['value'], - template: ` -
- -
`, - methods: { - pp: View.pprintIdentifier - } -}); - -Vue.component('proof-trace-formula', { - props: ['pp', 'env', 'css-class'], - template: ` -
- -
`, - methods: { - tokenize: View.tokenize - } -}); - -Vue.component('proof-trace-toolbar', { - props: {options: {default: () => ({})}}, - template: ` -
-
- Show: - - - - -
-
` -}); - -Vue.component('proof-trace-context-menu', { - template: ` - -
  • Expand all
  • -
  • Copy Node Id
  • -
  • Copy goal
  • -
    `, - components: {VueContext}, - methods: { - open(ev: View.ActionEvent) { - this._target = ev.target; - this.$refs.m.open(ev.$event); - }, - action(ev) { - this.$emit('action', { - type: ev.currentTarget.name, - target: this._target - }); - } - } -}); - - export { ProofTrace } diff --git a/src/viz/tsconfig.json b/src/viz/tsconfig.json index 971a287ed..a15e5ca86 100644 --- a/src/viz/tsconfig.json +++ b/src/viz/tsconfig.json @@ -2,6 +2,9 @@ "compilerOptions": { "target": "es2019", "moduleResolution": "node", - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "downlevelIteration": true, + "experimentalDecorators": true } } \ No newline at end of file diff --git a/src/viz/vue/app-context-menu.vue b/src/viz/vue/app-context-menu.vue new file mode 100644 index 000000000..ff932dcf2 --- /dev/null +++ b/src/viz/vue/app-context-menu.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/viz/vue/app-toolbar.vue b/src/viz/vue/app-toolbar.vue new file mode 100644 index 000000000..e46c99bd0 --- /dev/null +++ b/src/viz/vue/app-toolbar.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/viz/vue/app.vue b/src/viz/vue/app.vue new file mode 100644 index 000000000..f20b2bc96 --- /dev/null +++ b/src/viz/vue/app.vue @@ -0,0 +1,48 @@ + + + + + \ 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..c73f16b38 --- /dev/null +++ b/src/viz/vue/benchmark-list-pane.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/src/viz/vue/editor-pane.vue b/src/viz/vue/editor-pane.vue new file mode 100644 index 000000000..7eaeecf22 --- /dev/null +++ b/src/viz/vue/editor-pane.vue @@ -0,0 +1,55 @@ + + + + + + + \ No newline at end of file diff --git a/src/viz/vue/proof-interaction.vue b/src/viz/vue/proof-interaction.vue new file mode 100644 index 000000000..6e4d91fb9 --- /dev/null +++ b/src/viz/vue/proof-interaction.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/viz/vue/proof-trace-formula.vue b/src/viz/vue/proof-trace-formula.vue new file mode 100644 index 000000000..448665828 --- /dev/null +++ b/src/viz/vue/proof-trace-formula.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/viz/vue/proof-trace-goal.vue b/src/viz/vue/proof-trace-goal.vue new file mode 100644 index 000000000..2011c201c --- /dev/null +++ b/src/viz/vue/proof-trace-goal.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/viz/vue/proof-trace-node.vue b/src/viz/vue/proof-trace-node.vue new file mode 100644 index 000000000..50f1579d2 --- /dev/null +++ b/src/viz/vue/proof-trace-node.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/src/viz/vue/proof-trace-pane.vue b/src/viz/vue/proof-trace-pane.vue new file mode 100644 index 000000000..22095d5c1 --- /dev/null +++ b/src/viz/vue/proof-trace-pane.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/viz/vue/proof-trace-vars.vue b/src/viz/vue/proof-trace-vars.vue new file mode 100644 index 000000000..53ade9e36 --- /dev/null +++ b/src/viz/vue/proof-trace-vars.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/viz/vue/proof-trace.vue b/src/viz/vue/proof-trace.vue new file mode 100644 index 000000000..3d555bafc --- /dev/null +++ b/src/viz/vue/proof-trace.vue @@ -0,0 +1,87 @@ + + + diff --git a/src/viz/vue/widgets/slider-switch.vue b/src/viz/vue/widgets/slider-switch.vue new file mode 100644 index 000000000..4127c4d34 --- /dev/null +++ b/src/viz/vue/widgets/slider-switch.vue @@ -0,0 +1,80 @@ + + + + + \ No newline at end of file