diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml
new file mode 100644
index 0000000..cdb5e14
--- /dev/null
+++ b/.github/workflows/CI.yaml
@@ -0,0 +1,33 @@
+name: CI
+
+on: [ push ]
+
+jobs:
+ test-clj:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install Lein
+ uses: DeLaGuardo/setup-clojure@master
+ with:
+ lein: 'latest'
+ - name: Run Tests
+ run: lein test
+ test-cljs:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Prepare Java
+ uses: actions/setup-java@v2
+ with:
+ distribution: 'temurin'
+ java-version: '8'
+ - name: Install Node
+ uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+ - run: npm install
+ - name: Install shadow-cljs
+ run: npm install -g shadow-cljs
+ - name: Run Tests
+ run: shadow-cljs compile test && node out/node-tests.js
diff --git a/.gitignore b/.gitignore
index 96884b1..df3fb06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,10 @@ notes
*~
q
+# Clojure Script
+.shadow-cljs/
+node_modules/
+
# Don't commit the data directory that we'll
# use to hold the data from
# https://github.com/thelmuth/program-synthesis-benchmark-datasets
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..d73778a
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,2427 @@
+{
+ "name": "propeller-cljs",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "propeller-cljs",
+ "version": "1.0.0",
+ "license": "EPL",
+ "dependencies": {
+ "ws": "^8.2.3"
+ },
+ "devDependencies": {
+ "http-server": "^0.12.3",
+ "shadow-cljs": "^2.10.10",
+ "source-map-support": "^0.5.20"
+ }
+ },
+ "node_modules/asn1.js": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+ "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/asn1.js/node_modules/bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ },
+ "node_modules/assert": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
+ "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
+ "dev": true,
+ "dependencies": {
+ "object-assign": "^4.1.1",
+ "util": "0.10.3"
+ }
+ },
+ "node_modules/assert/node_modules/inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+ "dev": true
+ },
+ "node_modules/assert/node_modules/util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "dev": true,
+ "dependencies": {
+ "inherits": "2.0.1"
+ }
+ },
+ "node_modules/async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "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/basic-auth": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
+ "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/bn.js": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
+ "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
+ "dev": true
+ },
+ "node_modules/brorand": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+ "dev": true
+ },
+ "node_modules/browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "dev": true,
+ "dependencies": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/browserify-cipher": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+ "dev": true,
+ "dependencies": {
+ "browserify-aes": "^1.0.4",
+ "browserify-des": "^1.0.0",
+ "evp_bytestokey": "^1.0.0"
+ }
+ },
+ "node_modules/browserify-des": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+ "dev": true,
+ "dependencies": {
+ "cipher-base": "^1.0.1",
+ "des.js": "^1.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "node_modules/browserify-rsa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
+ "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^5.0.0",
+ "randombytes": "^2.0.1"
+ }
+ },
+ "node_modules/browserify-sign": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
+ "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^5.1.1",
+ "browserify-rsa": "^4.0.1",
+ "create-hash": "^1.2.0",
+ "create-hmac": "^1.1.7",
+ "elliptic": "^6.5.3",
+ "inherits": "^2.0.4",
+ "parse-asn1": "^5.1.5",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ }
+ },
+ "node_modules/browserify-sign/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "dev": true,
+ "dependencies": {
+ "pako": "~1.0.5"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "4.9.2",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
+ "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
+ "dev": true,
+ "dependencies": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4",
+ "isarray": "^1.0.0"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
+ "node_modules/buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+ "dev": true
+ },
+ "node_modules/builtin-status-codes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+ "dev": true
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/console-browserify": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
+ "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
+ "dev": true
+ },
+ "node_modules/constants-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+ "dev": true
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true
+ },
+ "node_modules/corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/create-ecdh": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
+ "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^4.1.0",
+ "elliptic": "^6.5.3"
+ }
+ },
+ "node_modules/create-ecdh/node_modules/bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ },
+ "node_modules/create-hash": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "dev": true,
+ "dependencies": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "node_modules/create-hmac": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "dev": true,
+ "dependencies": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "node_modules/crypto-browserify": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+ "dev": true,
+ "dependencies": {
+ "browserify-cipher": "^1.0.0",
+ "browserify-sign": "^4.0.0",
+ "create-ecdh": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.0",
+ "diffie-hellman": "^5.0.0",
+ "inherits": "^2.0.1",
+ "pbkdf2": "^3.0.3",
+ "public-encrypt": "^4.0.0",
+ "randombytes": "^2.0.0",
+ "randomfill": "^1.0.3"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/des.js": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
+ "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "node_modules/diffie-hellman": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^4.1.0",
+ "miller-rabin": "^4.0.0",
+ "randombytes": "^2.0.0"
+ }
+ },
+ "node_modules/diffie-hellman/node_modules/bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ },
+ "node_modules/domain-browser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4",
+ "npm": ">=1.2"
+ }
+ },
+ "node_modules/ecstatic": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz",
+ "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==",
+ "deprecated": "This package is unmaintained and deprecated. See the GH Issue 259.",
+ "dev": true,
+ "dependencies": {
+ "he": "^1.1.1",
+ "mime": "^1.6.0",
+ "minimist": "^1.1.0",
+ "url-join": "^2.0.5"
+ },
+ "bin": {
+ "ecstatic": "lib/ecstatic.js"
+ }
+ },
+ "node_modules/elliptic": {
+ "version": "6.5.4",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
+ "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^4.11.9",
+ "brorand": "^1.1.0",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.1",
+ "inherits": "^2.0.4",
+ "minimalistic-assert": "^1.0.1",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "node_modules/elliptic/node_modules/bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "dev": true,
+ "dependencies": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.14.4",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
+ "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+ "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hash-base": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+ "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/hash-base/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/hash.js": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "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/hmac-drbg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "dev": true,
+ "dependencies": {
+ "hash.js": "^1.0.3",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "node_modules/http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "dependencies": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/http-server": {
+ "version": "0.12.3",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz",
+ "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==",
+ "dev": true,
+ "dependencies": {
+ "basic-auth": "^1.0.3",
+ "colors": "^1.4.0",
+ "corser": "^2.0.1",
+ "ecstatic": "^3.3.2",
+ "http-proxy": "^1.18.0",
+ "minimist": "^1.2.5",
+ "opener": "^1.5.1",
+ "portfinder": "^1.0.25",
+ "secure-compare": "3.0.1",
+ "union": "~0.5.0"
+ },
+ "bin": {
+ "hs": "bin/http-server",
+ "http-server": "bin/http-server"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/https-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+ "dev": true
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "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/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/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "node_modules/md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
+ "dependencies": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "node_modules/miller-rabin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^4.0.0",
+ "brorand": "^1.0.1"
+ },
+ "bin": {
+ "miller-rabin": "bin/miller-rabin"
+ }
+ },
+ "node_modules/miller-rabin/node_modules/bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "dev": true
+ },
+ "node_modules/minimalistic-crypto-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+ "dev": true
+ },
+ "node_modules/minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/node-libs-browser": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
+ "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
+ "dev": true,
+ "dependencies": {
+ "assert": "^1.1.1",
+ "browserify-zlib": "^0.2.0",
+ "buffer": "^4.3.0",
+ "console-browserify": "^1.1.0",
+ "constants-browserify": "^1.0.0",
+ "crypto-browserify": "^3.11.0",
+ "domain-browser": "^1.1.1",
+ "events": "^3.0.0",
+ "https-browserify": "^1.0.0",
+ "os-browserify": "^0.3.0",
+ "path-browserify": "0.0.1",
+ "process": "^0.11.10",
+ "punycode": "^1.2.4",
+ "querystring-es3": "^0.2.0",
+ "readable-stream": "^2.3.3",
+ "stream-browserify": "^2.0.1",
+ "stream-http": "^2.7.2",
+ "string_decoder": "^1.0.0",
+ "timers-browserify": "^2.0.4",
+ "tty-browserify": "0.0.0",
+ "url": "^0.11.0",
+ "util": "^0.11.0",
+ "vm-browserify": "^1.0.1"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
+ "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/opener": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+ "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+ "dev": true,
+ "bin": {
+ "opener": "bin/opener-bin.js"
+ }
+ },
+ "node_modules/os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
+ "dev": true
+ },
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+ "dev": true
+ },
+ "node_modules/parse-asn1": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
+ "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
+ "dev": true,
+ "dependencies": {
+ "asn1.js": "^5.2.0",
+ "browserify-aes": "^1.0.0",
+ "evp_bytestokey": "^1.0.0",
+ "pbkdf2": "^3.0.3",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "node_modules/path-browserify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
+ "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
+ "dev": true
+ },
+ "node_modules/pbkdf2": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+ "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
+ "dev": true,
+ "dependencies": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/portfinder": {
+ "version": "1.0.28",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
+ "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
+ "dev": true,
+ "dependencies": {
+ "async": "^2.6.2",
+ "debug": "^3.1.1",
+ "mkdirp": "^0.5.5"
+ },
+ "engines": {
+ "node": ">= 0.12.0"
+ }
+ },
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "node_modules/public-encrypt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+ "dev": true,
+ "dependencies": {
+ "bn.js": "^4.1.0",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "parse-asn1": "^5.0.0",
+ "randombytes": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "node_modules/public-encrypt/node_modules/bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ },
+ "node_modules/punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ },
+ "node_modules/qs": {
+ "version": "6.10.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
+ "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
+ "dev": true,
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+ "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.x"
+ }
+ },
+ "node_modules/querystring-es3": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.x"
+ }
+ },
+ "node_modules/randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "node_modules/randomfill": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+ "dev": true,
+ "dependencies": {
+ "randombytes": "^2.0.5",
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/readable-stream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/readable-stream/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/readline-sync": {
+ "version": "1.4.10",
+ "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz",
+ "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
+ "node_modules/ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
+ "dependencies": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "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/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "node_modules/secure-compare": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
+ "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=",
+ "dev": true
+ },
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+ "dev": true
+ },
+ "node_modules/sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ },
+ "bin": {
+ "sha.js": "bin.js"
+ }
+ },
+ "node_modules/shadow-cljs": {
+ "version": "2.15.11",
+ "resolved": "https://registry.npmjs.org/shadow-cljs/-/shadow-cljs-2.15.11.tgz",
+ "integrity": "sha512-9a+rWi+r7a+u8CCUR/nCdfeCdCcJ2kZC7mrmGkwokMHhpnplVUzcgffGXxJWRSdQ4gMKV7B3CwqP/VxlGu9iCg==",
+ "dev": true,
+ "dependencies": {
+ "node-libs-browser": "^2.2.1",
+ "readline-sync": "^1.4.7",
+ "shadow-cljs-jar": "1.3.2",
+ "source-map-support": "^0.4.15",
+ "which": "^1.3.1",
+ "ws": "^7.4.6"
+ },
+ "bin": {
+ "shadow-cljs": "cli/runner.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/shadow-cljs-jar": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/shadow-cljs-jar/-/shadow-cljs-jar-1.3.2.tgz",
+ "integrity": "sha512-XmeffAZHv8z7451kzeq9oKh8fh278Ak+UIOGGrapyqrFBB773xN8vMQ3O7J7TYLnb9BUwcqadKkmgaq7q6fhZg==",
+ "dev": true
+ },
+ "node_modules/shadow-cljs/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/shadow-cljs/node_modules/source-map-support": {
+ "version": "0.4.18",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+ "dev": true,
+ "dependencies": {
+ "source-map": "^0.5.6"
+ }
+ },
+ "node_modules/shadow-cljs/node_modules/ws": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
+ "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.20",
+ "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==",
+ "dev": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/stream-browserify": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+ "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "~2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "node_modules/stream-http": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+ "dev": true,
+ "dependencies": {
+ "builtin-status-codes": "^3.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.3.6",
+ "to-arraybuffer": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/timers-browserify": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
+ "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
+ "dev": true,
+ "dependencies": {
+ "setimmediate": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/to-arraybuffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+ "dev": true
+ },
+ "node_modules/tty-browserify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+ "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
+ "dev": true
+ },
+ "node_modules/union": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
+ "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
+ "dev": true,
+ "dependencies": {
+ "qs": "^6.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/url": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "dev": true,
+ "dependencies": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ }
+ },
+ "node_modules/url-join": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
+ "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=",
+ "dev": true
+ },
+ "node_modules/url/node_modules/punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+ "dev": true
+ },
+ "node_modules/util": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
+ "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "2.0.3"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "node_modules/util/node_modules/inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "node_modules/vm-browserify": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
+ "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
+ "dev": true
+ },
+ "node_modules/which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.2.3",
+ "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4"
+ }
+ }
+ },
+ "dependencies": {
+ "asn1.js": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+ "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "safer-buffer": "^2.1.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
+ }
+ },
+ "assert": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
+ "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.1.1",
+ "util": "0.10.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+ "dev": true
+ },
+ "util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.1"
+ }
+ }
+ }
+ },
+ "async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true
+ },
+ "basic-auth": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
+ "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=",
+ "dev": true
+ },
+ "bn.js": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
+ "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
+ "dev": true
+ },
+ "brorand": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+ "dev": true
+ },
+ "browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "dev": true,
+ "requires": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "browserify-cipher": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+ "dev": true,
+ "requires": {
+ "browserify-aes": "^1.0.4",
+ "browserify-des": "^1.0.0",
+ "evp_bytestokey": "^1.0.0"
+ }
+ },
+ "browserify-des": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "des.js": "^1.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "browserify-rsa": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
+ "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^5.0.0",
+ "randombytes": "^2.0.1"
+ }
+ },
+ "browserify-sign": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
+ "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^5.1.1",
+ "browserify-rsa": "^4.0.1",
+ "create-hash": "^1.2.0",
+ "create-hmac": "^1.1.7",
+ "elliptic": "^6.5.3",
+ "inherits": "^2.0.4",
+ "parse-asn1": "^5.1.5",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "dev": true,
+ "requires": {
+ "pako": "~1.0.5"
+ }
+ },
+ "buffer": {
+ "version": "4.9.2",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
+ "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4",
+ "isarray": "^1.0.0"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.2",
+ "dev": true
+ },
+ "buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+ "dev": true
+ },
+ "builtin-status-codes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+ "dev": true
+ },
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
+ "cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true
+ },
+ "console-browserify": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
+ "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
+ "dev": true
+ },
+ "constants-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true
+ },
+ "corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=",
+ "dev": true
+ },
+ "create-ecdh": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
+ "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "elliptic": "^6.5.3"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
+ }
+ },
+ "create-hash": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "create-hmac": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "dev": true,
+ "requires": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "crypto-browserify": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+ "dev": true,
+ "requires": {
+ "browserify-cipher": "^1.0.0",
+ "browserify-sign": "^4.0.0",
+ "create-ecdh": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.0",
+ "diffie-hellman": "^5.0.0",
+ "inherits": "^2.0.1",
+ "pbkdf2": "^3.0.3",
+ "public-encrypt": "^4.0.0",
+ "randombytes": "^2.0.0",
+ "randomfill": "^1.0.3"
+ }
+ },
+ "debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "des.js": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
+ "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "diffie-hellman": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "miller-rabin": "^4.0.0",
+ "randombytes": "^2.0.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
+ }
+ },
+ "domain-browser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+ "dev": true
+ },
+ "ecstatic": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz",
+ "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==",
+ "dev": true,
+ "requires": {
+ "he": "^1.1.1",
+ "mime": "^1.6.0",
+ "minimist": "^1.1.0",
+ "url-join": "^2.0.5"
+ }
+ },
+ "elliptic": {
+ "version": "6.5.4",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
+ "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.11.9",
+ "brorand": "^1.1.0",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.1",
+ "inherits": "^2.0.4",
+ "minimalistic-assert": "^1.0.1",
+ "minimalistic-crypto-utils": "^1.0.1"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
+ }
+ },
+ "eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true
+ },
+ "events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "dev": true
+ },
+ "evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "dev": true,
+ "requires": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "follow-redirects": {
+ "version": "1.14.4",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
+ "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==",
+ "dev": true
+ },
+ "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-intrinsic": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+ "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "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-symbols": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
+ "dev": true
+ },
+ "hash-base": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+ "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ }
+ }
+ },
+ "hash.js": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+ "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
+ "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
+ },
+ "hmac-drbg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "dev": true,
+ "requires": {
+ "hash.js": "^1.0.3",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "http-server": {
+ "version": "0.12.3",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz",
+ "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==",
+ "dev": true,
+ "requires": {
+ "basic-auth": "^1.0.3",
+ "colors": "^1.4.0",
+ "corser": "^2.0.1",
+ "ecstatic": "^3.3.2",
+ "http-proxy": "^1.18.0",
+ "minimist": "^1.2.5",
+ "opener": "^1.5.1",
+ "portfinder": "^1.0.25",
+ "secure-compare": "3.0.1",
+ "union": "~0.5.0"
+ }
+ },
+ "https-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+ "dev": true
+ },
+ "ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
+ },
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "md5.js": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "miller-rabin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.0.0",
+ "brorand": "^1.0.1"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true
+ },
+ "minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "dev": true
+ },
+ "minimalistic-crypto-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+ "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==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node-libs-browser": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
+ "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
+ "dev": true,
+ "requires": {
+ "assert": "^1.1.1",
+ "browserify-zlib": "^0.2.0",
+ "buffer": "^4.3.0",
+ "console-browserify": "^1.1.0",
+ "constants-browserify": "^1.0.0",
+ "crypto-browserify": "^3.11.0",
+ "domain-browser": "^1.1.1",
+ "events": "^3.0.0",
+ "https-browserify": "^1.0.0",
+ "os-browserify": "^0.3.0",
+ "path-browserify": "0.0.1",
+ "process": "^0.11.10",
+ "punycode": "^1.2.4",
+ "querystring-es3": "^0.2.0",
+ "readable-stream": "^2.3.3",
+ "stream-browserify": "^2.0.1",
+ "stream-http": "^2.7.2",
+ "string_decoder": "^1.0.0",
+ "timers-browserify": "^2.0.4",
+ "tty-browserify": "0.0.0",
+ "url": "^0.11.0",
+ "util": "^0.11.0",
+ "vm-browserify": "^1.0.1"
+ }
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
+ "object-inspect": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
+ "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
+ "dev": true
+ },
+ "opener": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+ "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+ "dev": true
+ },
+ "os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
+ "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-asn1": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
+ "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
+ "dev": true,
+ "requires": {
+ "asn1.js": "^5.2.0",
+ "browserify-aes": "^1.0.0",
+ "evp_bytestokey": "^1.0.0",
+ "pbkdf2": "^3.0.3",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "path-browserify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
+ "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
+ "dev": true
+ },
+ "pbkdf2": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+ "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
+ "dev": true,
+ "requires": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "portfinder": {
+ "version": "1.0.28",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
+ "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
+ "dev": true,
+ "requires": {
+ "async": "^2.6.2",
+ "debug": "^3.1.1",
+ "mkdirp": "^0.5.5"
+ }
+ },
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+ "dev": 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
+ },
+ "public-encrypt": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+ "dev": true,
+ "requires": {
+ "bn.js": "^4.1.0",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "parse-asn1": "^5.0.0",
+ "randombytes": "^2.0.1",
+ "safe-buffer": "^5.1.2"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
+ }
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ },
+ "qs": {
+ "version": "6.10.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
+ "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
+ "dev": true,
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+ "dev": true
+ },
+ "querystring-es3": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+ "dev": true
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "randomfill": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.0.5",
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "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,
+ "requires": {
+ "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"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "readline-sync": {
+ "version": "1.4.10",
+ "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz",
+ "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==",
+ "dev": true
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
+ "ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "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
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "secure-compare": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
+ "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=",
+ "dev": true
+ },
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+ "dev": true
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "shadow-cljs": {
+ "version": "2.15.11",
+ "resolved": "https://registry.npmjs.org/shadow-cljs/-/shadow-cljs-2.15.11.tgz",
+ "integrity": "sha512-9a+rWi+r7a+u8CCUR/nCdfeCdCcJ2kZC7mrmGkwokMHhpnplVUzcgffGXxJWRSdQ4gMKV7B3CwqP/VxlGu9iCg==",
+ "dev": true,
+ "requires": {
+ "node-libs-browser": "^2.2.1",
+ "readline-sync": "^1.4.7",
+ "shadow-cljs-jar": "1.3.2",
+ "source-map-support": "^0.4.15",
+ "which": "^1.3.1",
+ "ws": "^7.4.6"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "source-map-support": {
+ "version": "0.4.18",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+ "dev": true,
+ "requires": {
+ "source-map": "^0.5.6"
+ }
+ },
+ "ws": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
+ "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
+ "dev": true,
+ "requires": {}
+ }
+ }
+ },
+ "shadow-cljs-jar": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/shadow-cljs-jar/-/shadow-cljs-jar-1.3.2.tgz",
+ "integrity": "sha512-XmeffAZHv8z7451kzeq9oKh8fh278Ak+UIOGGrapyqrFBB773xN8vMQ3O7J7TYLnb9BUwcqadKkmgaq7q6fhZg==",
+ "dev": true
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dev": true,
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "dev": true
+ },
+ "source-map-support": {
+ "version": "0.5.20",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "stream-browserify": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+ "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
+ "dev": true,
+ "requires": {
+ "inherits": "~2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "stream-http": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+ "dev": true,
+ "requires": {
+ "builtin-status-codes": "^3.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.3.6",
+ "to-arraybuffer": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "timers-browserify": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
+ "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
+ "dev": true,
+ "requires": {
+ "setimmediate": "^1.0.4"
+ }
+ },
+ "to-arraybuffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+ "dev": true
+ },
+ "tty-browserify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+ "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
+ "dev": true
+ },
+ "union": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
+ "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
+ "dev": true,
+ "requires": {
+ "qs": "^6.4.0"
+ }
+ },
+ "url": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "dev": true,
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+ "dev": true
+ }
+ }
+ },
+ "url-join": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
+ "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=",
+ "dev": true
+ },
+ "util": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
+ "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ }
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "vm-browserify": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
+ "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
+ "dev": true
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "ws": {
+ "version": "8.2.3",
+ "requires": {}
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true
+ }
+ }
+}
diff --git a/package.json b/package.json
index 33a73cb..4f5c243 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,10 @@
"license": "EPL",
"devDependencies": {
"http-server": "^0.12.3",
- "shadow-cljs": "^2.10.10"
+ "shadow-cljs": "^2.10.10",
+ "source-map-support": "^0.5.20"
+ },
+ "dependencies": {
+ "ws": "^8.2.3"
}
}
diff --git a/project.clj b/project.clj
index 4c35208..2ddf0e3 100644
--- a/project.clj
+++ b/project.clj
@@ -7,7 +7,7 @@
[org.clojure/clojurescript "1.9.946"]
[org.clojure/test.check "1.1.0"]
[net.clojars.schneau/psb2 "1.1.0"]]
+ :profiles {:profiling {:dependencies [[com.clojure-goes-fast/clj-async-profiler "0.5.1"]]}}
:main ^:skip-aot propeller.core
:repl-options {:init-ns propeller.core}
:jvm-opts ^:replace [])
-
diff --git a/propeller.iml b/propeller.iml
deleted file mode 100644
index 9f33501..0000000
--- a/propeller.iml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/shadow-cljs.edn b/shadow-cljs.edn
index 5901c31..308c1d1 100644
--- a/shadow-cljs.edn
+++ b/shadow-cljs.edn
@@ -1,7 +1,10 @@
-{:source-paths ["src"]
+{:source-paths ["src" "test"]
:dependencies []
- :dev-http {8080 "target/"}
- :builds {:app {:output-dir "target/"
- :asset-path "."
- :target :browser
- :modules {:main {:init-fn propeller.main/main!}}}}}
\ No newline at end of file
+ :dev-http {8080 "target/"}
+ :builds {:app {:output-dir "target/"
+ :asset-path "."
+ :target :browser
+ :modules {:main {:init-fn propeller.main/main!}}}
+ :test {:extra-paths ["src"]
+ :target :node-test
+ :output-to "out/node-tests.js"}}}
diff --git a/src/propeller/gp.cljc b/src/propeller/gp.cljc
index 302d8db..0d05a83 100755
--- a/src/propeller/gp.cljc
+++ b/src/propeller/gp.cljc
@@ -31,21 +31,22 @@
(defn gp
"Main GP loop."
[{:keys [population-size max-generations error-function instructions
- max-initial-plushy-size]
+ max-initial-plushy-size solution-error-threshold mapper]
+ :or {solution-error-threshold 0.0
+ ;; The `mapper` will perform a `map`-like operation to apply a function to every individual
+ ;; in the population. The default is `map` but other options include `mapv`, or `pmap`.
+ mapper #?(:clj pmap :cljs map)}
:as argmap}]
;;
(prn {:starting-args (update (update argmap :error-function str) :instructions str)})
(println)
;;
(loop [generation 0
- population (repeatedly
- population-size
- #(hash-map :plushy (genome/make-random-plushy
- instructions
- max-initial-plushy-size)))]
+ population (mapper
+ (fn [_] {:plushy (genome/make-random-plushy instructions max-initial-plushy-size)})
+ (range population-size))]
(let [evaluated-pop (sort-by :total-error
- (#?(:clj pmap
- :cljs map)
+ (mapper
(partial error-function argmap (:training-data argmap))
population))
best-individual (first evaluated-pop)]
@@ -54,11 +55,10 @@
(report evaluated-pop generation argmap))
(cond
;; Success on training cases is verified on testing cases
- (zero? (:total-error best-individual))
+ (<= (:total-error best-individual) solution-error-threshold)
(do (prn {:success-generation generation})
(prn {:total-test-error
- (:total-error (error-function argmap (:testing-data argmap) best-individual))})
- (#?(:clj shutdown-agents)))
+ (:total-error (error-function argmap (:testing-data argmap) best-individual))}))
;;
(>= generation max-generations)
nil
diff --git a/src/propeller/problems/PSB2/basement.cljc b/src/propeller/problems/PSB2/basement.cljc
index 472b993..9358220 100644
--- a/src/propeller/problems/PSB2/basement.cljc
+++ b/src/propeller/problems/PSB2/basement.cljc
@@ -78,5 +78,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
-
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/bouncing_balls.cljc b/src/propeller/problems/PSB2/bouncing_balls.cljc
index 2ccbc70..4a9c599 100644
--- a/src/propeller/problems/PSB2/bouncing_balls.cljc
+++ b/src/propeller/problems/PSB2/bouncing_balls.cljc
@@ -90,4 +90,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
\ No newline at end of file
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/bowling.cljc b/src/propeller/problems/PSB2/bowling.cljc
index 26bca23..773fdff 100644
--- a/src/propeller/problems/PSB2/bowling.cljc
+++ b/src/propeller/problems/PSB2/bowling.cljc
@@ -77,4 +77,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
\ No newline at end of file
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/camel_case.cljc b/src/propeller/problems/PSB2/camel_case.cljc
index a5449e1..5348284 100644
--- a/src/propeller/problems/PSB2/camel_case.cljc
+++ b/src/propeller/problems/PSB2/camel_case.cljc
@@ -113,4 +113,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/dice_game.cljc b/src/propeller/problems/PSB2/dice_game.cljc
index 09cef2a..bce6587 100644
--- a/src/propeller/problems/PSB2/dice_game.cljc
+++ b/src/propeller/problems/PSB2/dice_game.cljc
@@ -86,4 +86,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/fizz_buzz.cljc b/src/propeller/problems/PSB2/fizz_buzz.cljc
index 4b97416..5a0182d 100644
--- a/src/propeller/problems/PSB2/fizz_buzz.cljc
+++ b/src/propeller/problems/PSB2/fizz_buzz.cljc
@@ -82,5 +82,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
-
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/fuel_cost.cljc b/src/propeller/problems/PSB2/fuel_cost.cljc
index 29c846f..8ce4561 100644
--- a/src/propeller/problems/PSB2/fuel_cost.cljc
+++ b/src/propeller/problems/PSB2/fuel_cost.cljc
@@ -79,5 +79,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
-
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/gcd.cljc b/src/propeller/problems/PSB2/gcd.cljc
index 9c3b497..3fc10d3 100644
--- a/src/propeller/problems/PSB2/gcd.cljc
+++ b/src/propeller/problems/PSB2/gcd.cljc
@@ -87,4 +87,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/luhn.cljc b/src/propeller/problems/PSB2/luhn.cljc
index 9556cd1..0e40a88 100644
--- a/src/propeller/problems/PSB2/luhn.cljc
+++ b/src/propeller/problems/PSB2/luhn.cljc
@@ -80,6 +80,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
-
-
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/middle_character.cljc b/src/propeller/problems/PSB2/middle_character.cljc
index 55850a6..55925e4 100644
--- a/src/propeller/problems/PSB2/middle_character.cljc
+++ b/src/propeller/problems/PSB2/middle_character.cljc
@@ -82,4 +82,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/paired_digits.cljc b/src/propeller/problems/PSB2/paired_digits.cljc
index 4d8190e..4936c8d 100644
--- a/src/propeller/problems/PSB2/paired_digits.cljc
+++ b/src/propeller/problems/PSB2/paired_digits.cljc
@@ -78,5 +78,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
-
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/shopping_list.cljc b/src/propeller/problems/PSB2/shopping_list.cljc
index d6c018f..f379f8d 100644
--- a/src/propeller/problems/PSB2/shopping_list.cljc
+++ b/src/propeller/problems/PSB2/shopping_list.cljc
@@ -88,4 +88,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/snow_day.cljc b/src/propeller/problems/PSB2/snow_day.cljc
index c5b55ce..1346545 100644
--- a/src/propeller/problems/PSB2/snow_day.cljc
+++ b/src/propeller/problems/PSB2/snow_day.cljc
@@ -92,4 +92,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/solve_boolean.cljc b/src/propeller/problems/PSB2/solve_boolean.cljc
index 432f8b2..d9cf85b 100644
--- a/src/propeller/problems/PSB2/solve_boolean.cljc
+++ b/src/propeller/problems/PSB2/solve_boolean.cljc
@@ -81,4 +81,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/spin_words.cljc b/src/propeller/problems/PSB2/spin_words.cljc
index c991f95..ed37706 100644
--- a/src/propeller/problems/PSB2/spin_words.cljc
+++ b/src/propeller/problems/PSB2/spin_words.cljc
@@ -109,5 +109,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
-
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/square_digits.cljc b/src/propeller/problems/PSB2/square_digits.cljc
index 23a4304..9aa44cd 100644
--- a/src/propeller/problems/PSB2/square_digits.cljc
+++ b/src/propeller/problems/PSB2/square_digits.cljc
@@ -82,6 +82,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
-
-
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/substitution_cipher.cljc b/src/propeller/problems/PSB2/substitution_cipher.cljc
index 13152c5..d297c75 100644
--- a/src/propeller/problems/PSB2/substitution_cipher.cljc
+++ b/src/propeller/problems/PSB2/substitution_cipher.cljc
@@ -95,4 +95,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
\ No newline at end of file
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB2/twitter.cljc b/src/propeller/problems/PSB2/twitter.cljc
index 9c6acfa..2d95dee 100644
--- a/src/propeller/problems/PSB2/twitter.cljc
+++ b/src/propeller/problems/PSB2/twitter.cljc
@@ -86,4 +86,5 @@
:umad-rate 0.1
:variation {:umad 1.0 :crossover 0.0}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
\ No newline at end of file
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/simple_regression.cljc b/src/propeller/problems/simple_regression.cljc
index 6112b3d..d0f153e 100755
--- a/src/propeller/problems/simple_regression.cljc
+++ b/src/propeller/problems/simple_regression.cljc
@@ -66,17 +66,18 @@
[& args]
(gp/gp
(merge
- {:instructions instructions
- :error-function error-function
- :training-data (:train train-and-test-data)
- :testing-data (:test train-and-test-data)
- :max-generations 500
- :population-size 500
- :max-initial-plushy-size 100
- :step-limit 200
- :parent-selection :lexicase
- :tournament-size 5
- :umad-rate 0.1
- :variation {:umad 0.5 :crossover 0.5}
- :elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
\ No newline at end of file
+ {:instructions instructions
+ :error-function error-function
+ :training-data (:train train-and-test-data)
+ :testing-data (:test train-and-test-data)
+ :max-generations 500
+ :population-size 500
+ :max-initial-plushy-size 100
+ :step-limit 200
+ :parent-selection :lexicase
+ :tournament-size 5
+ :umad-rate 0.1
+ :variation {:umad 0.5 :crossover 0.5}
+ :elitism false}
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/software/fizz_buzz.cljc b/src/propeller/problems/software/fizz_buzz.cljc
index bc77ded..7711510 100644
--- a/src/propeller/problems/software/fizz_buzz.cljc
+++ b/src/propeller/problems/software/fizz_buzz.cljc
@@ -1,6 +1,9 @@
(ns propeller.problems.software.fizz-buzz
(:require [psb2.core :as psb2]))
+;; @todo This namespace is never used an it isn't a complete problem. Furthermore fizz-buzz exists in the PSB2 folder.
+;; Consider removing this file.
+
;; NOTE: Need to change directory below to location of the PSB2 files
(def train-and-test (psb2/fetch-examples "PSB2/directory/path/goes/here/" "fizz-buzz" 200 2000))
@@ -9,4 +12,4 @@
train-and-test
problems
- )
\ No newline at end of file
+ )
diff --git a/src/propeller/problems/software/number_io.cljc b/src/propeller/problems/software/number_io.cljc
index fcbef5f..aefcc09 100755
--- a/src/propeller/problems/software/number_io.cljc
+++ b/src/propeller/problems/software/number_io.cljc
@@ -108,4 +108,5 @@
:umad-rate 0.1
:variation {:umad 0.5 :crossover 0.5}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
\ No newline at end of file
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/software/smallest.cljc b/src/propeller/problems/software/smallest.cljc
index 9ca4dbb..2ad5306 100755
--- a/src/propeller/problems/software/smallest.cljc
+++ b/src/propeller/problems/software/smallest.cljc
@@ -110,4 +110,5 @@
:umad-rate 0.1
:variation {:umad 0.5 :crossover 0.5}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
\ No newline at end of file
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/string_classification.cljc b/src/propeller/problems/string_classification.cljc
index a79a6d4..77d9efb 100755
--- a/src/propeller/problems/string_classification.cljc
+++ b/src/propeller/problems/string_classification.cljc
@@ -99,4 +99,5 @@
:umad-rate 0.1
:variation {:umad 0.5 :crossover 0.5}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
\ No newline at end of file
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/valiant.cljc b/src/propeller/problems/valiant.cljc
index 29fcf5c..4224581 100644
--- a/src/propeller/problems/valiant.cljc
+++ b/src/propeller/problems/valiant.cljc
@@ -78,4 +78,5 @@
:umad-rate 0.1
:variation {:umad 0.5 :crossover 0.5}
:elitism false}
- (apply hash-map (map #(if (string? %) (read-string %) %) args)))))
+ (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+ (#?(:clj shutdown-agents)))
diff --git a/src/propeller/push/instructions/polymorphic.cljc b/src/propeller/push/instructions/polymorphic.cljc
index 100992f..4635cc4 100755
--- a/src/propeller/push/instructions/polymorphic.cljc
+++ b/src/propeller/push/instructions/polymorphic.cljc
@@ -5,7 +5,7 @@
(:require [propeller.utils :as utils]
[propeller.push.state :as state]
[propeller.push.utils.helpers :refer [make-instruction]]
- [propeller.push.utils.globals :as globals]
+ [propeller.push.utils.limits :as limit]
#?(:clj [propeller.push.utils.macros :refer [def-instruction
generate-instructions]])))
@@ -42,7 +42,7 @@
(not (state/empty-stack? state :integer))
(not (state/empty-stack? state stack))))
(let [n (min (state/peek-stack state :integer)
- (inc (- globals/max-stack-items (state/stack-size state stack))))
+ (inc (- limit/max-stack-items (state/stack-size state stack))))
popped-state (state/pop-stack state :integer)
top-item (state/peek-stack popped-state stack)
top-item-dup (take (- n 1) (repeat top-item))]
@@ -62,7 +62,7 @@
(if (state/empty-stack? state :integer)
state
(let [n (min (state/peek-stack state :integer)
- (- globals/max-stack-items (state/stack-size state stack)))
+ (- limit/max-stack-items (state/stack-size state stack)))
popped-state (state/pop-stack state :integer)
top-items (take n (get popped-state stack))]
(state/push-to-stack-many popped-state stack top-items)))))
@@ -201,7 +201,7 @@
(not (state/empty-stack? state stack))))
(let [index-raw (state/peek-stack state :integer)
popped-state (state/pop-stack state :integer)
- index (max 0 (min index-raw (dec (count (get popped-state stack)))))
+ index (max 0 (min index-raw (dec (state/stack-size popped-state stack))))
indexed-item (nth (reverse (get popped-state stack)) index)]
(state/push-to-stack popped-state stack indexed-item))
state)))
diff --git a/src/propeller/push/state.cljc b/src/propeller/push/state.cljc
index 647509c..921e2eb 100755
--- a/src/propeller/push/state.cljc
+++ b/src/propeller/push/state.cljc
@@ -1,4 +1,6 @@
-(ns propeller.push.state)
+(ns propeller.push.state
+ (:require [propeller.push.utils.limits :as l]
+ #?(:cljs [goog.string :as gstring])))
;; Empty push state - all available stacks are empty
(defonce empty-state {:boolean '()
@@ -26,6 +28,16 @@
:vector_integer :integer
:vector_string :string})
+(defonce stack-limiter {:exec l/limit-code
+ :code l/limit-code
+ :integer #(long (l/limit-number %))
+ :float l/limit-number
+ :string l/limit-string
+ :vector_boolean l/limit-string
+ :vector_float #(mapv l/limit-number (l/limit-vector %))
+ :vector_integer #(mapv (fn [i] (int (l/limit-number i))) (l/limit-vector %))
+ :vector_string #(mapv (fn [s] (l/limit-string s)) (l/limit-vector %))})
+
(def example-state {:exec '()
:integer '(1 2 3 4 5 6 7)
:string '("abc")
@@ -68,14 +80,47 @@
;; Pushes an item onto the stack
(defn push-to-stack
[state stack item]
- (if (nil? item)
+ (if (or (nil? item)
+ (>= (stack-size state stack) l/max-stack-items))
state
- (update state stack conj item)))
+ (let [limiter (get stack-limiter stack identity)]
+ (update state stack conj (limiter item)))))
;; Pushes a collection of items onto the stack, as a chunk (i.e. leaving them in
;; the order they are in)
(defn push-to-stack-many
[state stack items]
(let [items (if (coll? items) items (list items))
- items-no-nil (filter #(not (nil? %)) items)]
- (update state stack into (reverse items-no-nil))))
+ items-no-nil (filter #(not (nil? %)) items)
+ items-to-push (take (- l/max-stack-items (stack-size state stack)) items-no-nil)
+ limit (get stack-limiter stack identity)]
+ (update state stack into (map limit (reverse items-to-push)))))
+
+;; Takes a state and a collection of stacks to take args from. If there are
+;; enough args on each of the desired stacks, returns a map with keys
+;; {:state :args}, where :state is the new state and :args is a list of args
+;; popped from the stacks. If there aren't enough args on the stacks, returns
+;; :not-enough-args without popping anything
+(defn get-args-from-stacks
+ [state stacks]
+ (loop [state state
+ stacks (reverse stacks)
+ args '()]
+ (if (empty? stacks)
+ {:state state :args args}
+ (let [current-stack (first stacks)]
+ (if (empty-stack? state current-stack)
+ :not-enough-args
+ (recur (pop-stack state current-stack)
+ (rest stacks)
+ (conj args (peek-stack state current-stack))))))))
+
+
+;; Pretty-print a Push state, for logging or debugging purposes
+(defn print-state
+ [state]
+ (doseq [stack (keys empty-state)]
+ #?(:clj (printf "%-15s = " stack)
+ :cljs (print (gstring/format "%-15s = " stack)))
+ (prn (if (get state stack) (get state stack) '()))
+ (flush)))
diff --git a/src/propeller/push/utils/globals.cljc b/src/propeller/push/utils/globals.cljc
deleted file mode 100644
index 93477e2..0000000
--- a/src/propeller/push/utils/globals.cljc
+++ /dev/null
@@ -1,30 +0,0 @@
-(ns propeller.push.utils.globals)
-
-;; =============================================================================
-;; Values used by the Push instructions to keep the stack sizes within
-;; reasonable limits.
-;; =============================================================================
-
-;; Limits the number of items that can be duplicated onto a stack at once.
-;; We might want to extend this to limit all the different that things may be
-;; placed on a stack.
-(def max-stack-items 100)
-
-
-
-;; =============================================================================
-;; Values used by the Push instructions to keep computed values within
-;; reasonable size limits.
-;; =============================================================================
-
-;; Used by keep-number-reasonable as the maximum magnitude of any integer/float
-(def max-number-magnitude 1.0E6)
-
-;; Used by keep-number-reasonable as the minimum magnitude of any float
-(def min-number-magnitude 1.0E-6)
-
-;; Used by reasonable-string-length? to ensure that strings don't get too large
-(def max-string-length 1000)
-
-;; Used by keep-vector-reasonable to ensure that vectors don't get too large
-(def max-vector-length 1000)
\ No newline at end of file
diff --git a/src/propeller/push/utils/helpers.cljc b/src/propeller/push/utils/helpers.cljc
index 55ae2e6..8de76be 100755
--- a/src/propeller/push/utils/helpers.cljc
+++ b/src/propeller/push/utils/helpers.cljc
@@ -2,63 +2,10 @@
(:require [clojure.set]
[propeller.push.core :as push]
[propeller.push.state :as state]
- [propeller.push.utils.globals :as globals]
+ [propeller.utils :as u]
#?(:cljs [goog.string :as gstring])
#?(:cljs [goog.string.format])))
-;; Returns a version of the number n that is within reasonable size bounds
-(defn keep-number-reasonable
- [n]
- (cond
- (integer? n)
- (cond
- (> n globals/max-number-magnitude) (long globals/max-number-magnitude)
- (< n (- globals/max-number-magnitude)) (long (- globals/max-number-magnitude))
- :else n)
- :else
- (cond
- (#?(:clj Double/isNaN
- :cljs js/isNaN) n) 0.0
- (or (= n #?(:clj Double/POSITIVE_INFINITY
- :cljs js/Infinity))
- (> n globals/max-number-magnitude)) globals/max-number-magnitude
- (or (= n #?(:clj Double/NEGATIVE_INFINITY
- :cljs js/-Infinity))
- (< n (- globals/max-number-magnitude))) (- globals/max-number-magnitude)
- (< (- globals/min-number-magnitude) n globals/min-number-magnitude) 0.0
- :else n)))
-
-;; Returns true if the string is of a reasonable size
-(defn reasonable-string-length?
- [string]
- (let [length (count string)]
- (<= length globals/max-string-length)))
-
-;; Returns true if the vector is of a reasonable size
-(defn reasonable-vector-length?
- [vector]
- (let [length (count vector)]
- (<= length globals/max-vector-length)))
-
-;; Takes a state and a collection of stacks to take args from. If there are
-;; enough args on each of the desired stacks, returns a map with keys
-;; {:state :args}, where :state is the new state and :args is a list of args
-;; popped from the stacks. If there aren't enough args on the stacks, returns
-;; :not-enough-args without popping anything
-(defn get-args-from-stacks
- [state stacks]
- (loop [state state
- stacks (reverse stacks)
- args '()]
- (if (empty? stacks)
- {:state state :args args}
- (let [current-stack (first stacks)]
- (if (state/empty-stack? state current-stack)
- :not-enough-args
- (recur (state/pop-stack state current-stack)
- (rest stacks)
- (conj args (state/peek-stack state current-stack))))))))
-
;; A utility function for making Push instructions. Takes a state, a function
;; to apply to the args, the stacks to take the args from, and the stack to
;; return the result to. Applies the function to the args (popped from the
@@ -69,27 +16,13 @@
;; without consuming stack values.
(defn make-instruction
[state function arg-stacks return-stack]
- (let [popped-args (get-args-from-stacks state arg-stacks)]
+ (let [popped-args (state/get-args-from-stacks state arg-stacks)]
(if (= popped-args :not-enough-args)
state
(let [result (apply function (:args popped-args))
new-state (:state popped-args)]
- (cond
- (number? result)
- (state/push-to-stack new-state return-stack (keep-number-reasonable result))
- ;;
- (and (string? result)
- (not (reasonable-string-length? result)))
+ (if (= result :ignore-instruction)
state
- ;;
- (and (vector? result)
- (not (reasonable-vector-length? result)))
- state
- ;;
- (= result :ignore-instruction)
- state
- ;;
- :else
(state/push-to-stack new-state return-stack result))))))
;; Given a set of stacks, returns all instructions that operate on those stacks
@@ -99,9 +32,9 @@
(doseq [[instruction-name function] @push/instruction-table]
(assert
(:stacks (meta function))
- #?(:clj (format
- "ERROR: Instruction %s does not have :stacks defined in metadata."
- (name instruction-name))
+ #?(:clj (format
+ "ERROR: Instruction %s does not have :stacks defined in metadata."
+ (name instruction-name))
:cljs (gstring/format
"ERROR: Instruction %s does not have :stacks defined in metadata."
(name instruction-name)))))
@@ -109,39 +42,45 @@
:when (clojure.set/subset? (:stacks (meta function)) stacks)]
instruction-name))
-;; If a piece of data is a literal, return its corresponding stack name, e.g.
-;; :integer. Otherwise, return nil"
+
+#?(:clj
+ (def cls->type
+ {Boolean :boolean
+ Short :integer
+ Integer :integer
+ Long :integer
+ BigInteger :integer
+ Double :float
+ BigDecimal :float
+ Float :float
+ Character :char
+ String :string}))
+
+#?(:cljs
+ (def pred->type
+ [[boolean? :boolean]
+ [int? :integer]
+ [float? :float]
+ [string? :string]
+ [char? :char]]))
+
(defn get-literal-type
+ "If a piece of data is a literal, return its corresponding stack name
+ e.g. `:integer`. Otherwise, return `nil`."
[data]
- (let [literals [[:boolean (fn [thing] (or (true? thing) (false? thing)))]
- [:integer integer?]
- [:float float?]
- [:string string?]
- [:char char?]
- [:vector_boolean (fn [thing] (and (vector? thing)
- (or (true? (first thing))
- (false? (first thing)))))]
- [:vector_float (fn [thing] (and (vector? thing)
- (float? (first thing))))]
- [:vector_integer (fn [thing] (and (vector? thing)
- (integer? (first thing))))]
- [:vector_string (fn [thing] (and (vector? thing)
- (string? (first thing))))]
- [:generic-vector (fn [thing] (= [] thing))]]]
- (first (for [[stack function] literals
- :when (function data)]
- stack))))
+ (or (when (vector? data)
+ (if (empty? data)
+ :generic-vector
+ (keyword (str "vector_" (name (get-literal-type (u/first-non-nil data)))))))
+ #?(:clj (cls->type (type data))
+ :cljs (loop [remaining pred->type]
+ (let [[pred d-type] (first remaining)]
+ (cond
+ (empty? remaining) nil
+ (pred data) d-type
+ :else (recur (rest remaining))))))))
(defn get-vector-literal-type
"Returns the literal stack corresponding to some vector stack."
[vector-stack]
(get state/vec-stacks vector-stack))
-
-;; Pretty-print a Push state, for logging or debugging purposes
-(defn print-state
- [state]
- (doseq [stack (keys state/empty-state)]
- #?(:clj (printf "%-15s = " stack)
- :cljs (print (gstring/format "%-15s = " stack)))
- (prn (if (get state stack) (get state stack) '()))
- (flush)))
diff --git a/src/propeller/push/utils/limits.cljc b/src/propeller/push/utils/limits.cljc
new file mode 100644
index 0000000..1e4c7c4
--- /dev/null
+++ b/src/propeller/push/utils/limits.cljc
@@ -0,0 +1,72 @@
+(ns propeller.push.utils.limits
+ (:require [propeller.utils :as u]))
+
+;; =============================================================================
+;; Values used by the Push instructions to keep the stack sizes within
+;; reasonable limits.
+;; =============================================================================
+
+;; Limits the number of items that can be duplicated onto a stack at once.
+;; We might want to extend this to limit all the different that things may be
+;; placed on a stack.
+(def max-stack-items 100)
+
+;; =============================================================================
+;; Values used by the Push instructions to keep computed values within
+;; reasonable size limits.
+;; =============================================================================
+
+;; Used as the maximum magnitude of any integer/float
+(def max-number-magnitude 1.0E6)
+
+;; Used as the minimum magnitude of any float
+(def min-number-magnitude 1.0E-6)
+
+;; Used to ensure that strings don't get too large
+(def max-string-length 1000)
+
+;; Used to ensure that vectors don't get too large
+(def max-vector-length 1000)
+
+;; Used to ensure that total
+;; Set as dynamic for testing purposes.
+(def ^:dynamic max-code-points 100)
+
+;; Used to ensure that the depth of nesting for Push expressions doesn't get too deep.
+;; Set as dynamic for testing purposes.
+(def ^:dynamic max-code-depth 200)
+
+;; Returns a version of the number n that is within reasonable size bounds
+(defn limit-number
+ [n]
+ (if (int? n)
+ (cond
+ (> n max-number-magnitude) (long max-number-magnitude)
+ (< n (- max-number-magnitude)) (long (- max-number-magnitude))
+ :else n)
+ (cond
+ (#?(:clj Double/isNaN
+ :cljs js/isNaN) n) 0.0
+ (or (= n #?(:clj Double/POSITIVE_INFINITY
+ :cljs js/Infinity))
+ (> n max-number-magnitude)) max-number-magnitude
+ (or (= n #?(:clj Double/NEGATIVE_INFINITY
+ :cljs js/-Infinity))
+ (< n (- max-number-magnitude))) (- max-number-magnitude)
+ (< (- min-number-magnitude) n min-number-magnitude) 0.0
+ :else n)))
+
+(defn limit-string
+ [s]
+ (apply str (take max-string-length s)))
+
+(defn limit-vector
+ [v]
+ (vec (take max-vector-length v)))
+
+(defn limit-code
+ [code]
+ (if (or (> (u/count-points code) max-code-points)
+ (> (u/depth code) max-code-depth))
+ '() ;; Code that exceeds the limit is discarded.
+ code))
diff --git a/src/propeller/utils.cljc b/src/propeller/utils.cljc
index 4e378a9..5f0b231 100755
--- a/src/propeller/utils.cljc
+++ b/src/propeller/utils.cljc
@@ -1,4 +1,11 @@
-(ns propeller.utils)
+(ns propeller.utils
+ (:require [clojure.zip :as zip]))
+
+(defn first-non-nil
+ "Returns the first non-nil values from the collection, or returns `nil` if
+ the collection is empty or only contains `nil`."
+ [coll]
+ (first (filter some? coll)))
(defn indexof
"Returns the first index of an element in a collection. If the element is not
@@ -29,3 +36,51 @@
(if (fn? instruction)
(instruction)
instruction)))
+
+
+(defn count-points
+ "Returns the number of points in tree, where each atom and each pair of parentheses
+ counts as a point."
+ [tree]
+ (loop [remaining tree
+ total 0]
+ (cond (not (seq? remaining))
+ (inc total)
+ ;;
+ (empty? remaining)
+ (inc total)
+ ;;
+ (not (seq? (first remaining)))
+ (recur (rest remaining)
+ (inc total))
+ ;;
+ :else
+ (recur (concat (first remaining)
+ (rest remaining))
+ (inc total)))))
+
+(defn seq-zip
+ "Returns a zipper for nested sequences, given a root sequence"
+ {:added "1.0"}
+ [root]
+ (zip/zipper seq?
+ seq
+ (fn [node children] (with-meta children (meta node)))
+ root))
+
+(defn depth
+ "Returns the height of the nested list called tree.
+ Borrowed idea from here: https://stackoverflow.com/a/36865180/2023312
+ Works by looking at the path from each node in the tree to the root, and
+ finding the longest one.
+ Note: does not treat an empty list as having any height."
+ [tree]
+ (loop [zipper (seq-zip tree)
+ height 0]
+ (if (zip/end? zipper)
+ height
+ (recur (zip/next zipper)
+ (-> zipper
+ zip/path
+ count
+ (max height))))))
diff --git a/test/propeller/push/instructions/string_spec.clj b/test/propeller/push/instructions/string_spec.clj
index d0b00fb..9c19eca 100644
--- a/test/propeller/push/instructions/string_spec.clj
+++ b/test/propeller/push/instructions/string_spec.clj
@@ -1,560 +1,560 @@
-(ns propeller.push.instructions.string-spec
- (:require
- [clojure.string :as string]
- [clojure.test.check.generators :as gen]
- [clojure.test.check.properties :as prop]
- [clojure.test.check.clojure-test :as ct :refer [defspec]]
- [propeller.push.state :as state]
- [propeller.push.core :as core]
- [propeller.push.instructions.string :as string-instructions]
- [propeller.push.interpreter :as interpreter]))
-
-
-;; string/butlast
-
-(defn check-butlast
- [value]
- (let [start-state (state/push-to-stack state/empty-state
- :string
- value)
- end-state ((:string_butlast @core/instruction-table) start-state)
- expected-result (apply str (butlast value))]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec butlast-spec 100
- (prop/for-all [str gen/string]
- (check-butlast str)))
-
-
-;; string/concat
-
-(defn check-concat
- [value1 value2]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value1)
- (state/push-to-stack :string value2))
- end-state ((:string_concat @core/instruction-table) start-state)
- expected-result (str value1 value2)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec concat-spec 100
- (prop/for-all [str1 gen/string
- str2 gen/string]
- (check-concat str1 str2)))
-
-
-;; string/conj-char
-
-(defn check-conj-char
- [value char]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :char char))
- end-state ((:string_conj_char @core/instruction-table) start-state)
- expected-result (str value char)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec conj-char-spec 100
- (prop/for-all [str gen/string
- char gen/char]
- (check-conj-char str char)))
-
-
-;; string/contains
-
-(defn check-contains
- [value1 value2]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value1)
- (state/push-to-stack :string value2))
- end-state ((:string_contains @core/instruction-table) start-state)
- expected-result (string/includes? value2 value1)]
- (= expected-result
- (state/peek-stack end-state :boolean))))
-
-(defspec contains-spec 100
- (prop/for-all [str1 gen/string
- str2 gen/string]
- (check-contains str1 str2)))
-
-
-;; string/contains-char
-
-(defn check-contains-char
- [value char]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :char char))
- end-state ((:string_contains_char @core/instruction-table) start-state)
- expected-result (string/includes? value (str char))]
- (= expected-result
- (state/peek-stack end-state :boolean))))
-
-(defspec contains-char-spec 100
- (prop/for-all [str gen/string
- char gen/char]
- (check-contains-char str char)))
-
-
-;; string/drop
-
-(defn check-drop
- [value n]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :integer n))
- end-state ((:string_drop @core/instruction-table) start-state)
- expected-result (apply str (drop n value))]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec drop-spec 100
- (prop/for-all [str gen/string
- int gen/small-integer]
- (check-drop str int)))
-
-
-;; string/empty-string
-
-(defn check-empty-string
- [value]
- (let [start-state (state/push-to-stack state/empty-state :string value)
- end-state ((:string_empty_string @core/instruction-table) start-state)
- expected-result (empty? value)]
- (= expected-result
- (state/peek-stack end-state :boolean))))
-
-(defspec empty-string-spec 100
- (prop/for-all [str gen/string]
- (check-empty-string str)))
-
-
-;; string/first
-
-(defn check-first
- [value]
- (let [start-state (state/push-to-stack state/empty-state :string value)
- end-state ((:string_first @core/instruction-table) start-state)
- expected-result (first value)]
- (or
- (and (empty? value)
- (= (state/peek-stack end-state :string) value)
- (state/empty-stack? end-state :char))
- (and (= expected-result
- (state/peek-stack end-state :char))
- (state/empty-stack? end-state :string)))))
-
-(defspec first-spec 100
- (prop/for-all [str gen/string]
- (check-first str)))
-
-
-;; string/from-boolean
-
-(defn check-from-boolean
- [value]
- (let [start-state (state/push-to-stack state/empty-state :boolean value)
- end-state ((:string_from_boolean @core/instruction-table) start-state)
- expected-result (str value)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec from-boolean-spec 10
- (prop/for-all [bool gen/boolean]
- (check-from-boolean bool)))
-
-
-;; string/from-char
-
-(defn check-from-char
- [value]
- (let [start-state (state/push-to-stack state/empty-state :char value)
- end-state ((:string_from_char @core/instruction-table) start-state)
- expected-result (str value)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec from-char-spec 100
- (prop/for-all [char gen/char]
- (check-from-char char)))
-
-
-;; string/from-float
-
-(defn check-from-float
- [value]
- (let [start-state (state/push-to-stack state/empty-state :float value)
- end-state ((:string_from_float @core/instruction-table) start-state)
- expected-result (str value)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec from-float-spec 100
- (prop/for-all [float gen/double]
- (check-from-float float)))
-
-
-;; string/from-integer
-
-(defn check-from-integer
- [value]
- (let [start-state (state/push-to-stack state/empty-state :integer value)
- end-state ((:string_from_integer @core/instruction-table) start-state)
- expected-result (str value)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec from-integer-spec 100
- (prop/for-all [int gen/small-integer]
- (check-from-integer int)))
-
-
-;; string/indexof-char
-
-(defn check-indexof-char
- [value char]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :char char))
- end-state ((:string_indexof_char @core/instruction-table) start-state)
- expected-result (string/index-of value char)]
- (or
- (and (not expected-result)
- (= (state/peek-stack end-state :string) value)
- (= (state/peek-stack end-state :char) char)
- (state/empty-stack? end-state :integer))
- (= expected-result
- (state/peek-stack end-state :integer)))))
-
-(defspec indexof-char-spec 100
- (prop/for-all [str gen/string
- char gen/char]
- (check-indexof-char str char)))
-
-
-;; string/iterate
-
-(defn check-iterate
- [value]
- (let [print-instr (keyword "char_print")
- iter-instr (keyword "string_iterate")
- program [iter-instr print-instr]
- start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :output ""))
- ; 4 times the string length should be enough for this iteration, perhaps even
- ; more than we strictly need.
- end-state (interpreter/interpret-program program start-state (* 4 (count value)))]
- (= value
- (state/peek-stack end-state :output))))
-
-(defspec iterate-spec 100
- (prop/for-all [value gen/string]
- (check-iterate value)))
-
-;; string/last
-
-(defn check-last
- [value]
- (let [start-state (state/push-to-stack state/empty-state :string value)
- end-state ((:string_last @core/instruction-table) start-state)
- expected-result (last value)]
- (or
- (and (empty? value)
- (state/empty-stack? end-state :char)
- (= value (state/peek-stack end-state :string)))
- (and (state/empty-stack? end-state :string)
- (= expected-result
- (state/peek-stack end-state :char))))))
-
-(defspec last-spec 100
- (prop/for-all [str gen/string]
- (check-last str)))
-
-
-;; string/length
-
-(defn check-length
- [value]
- (let [start-state (state/push-to-stack state/empty-state :string value)
- end-state ((:string_length @core/instruction-table) start-state)
- expected-result (count value)]
- (= expected-result
- (state/peek-stack end-state :integer))))
-
-(defspec length-spec 100
- (prop/for-all [str gen/string]
- (check-length str)))
-
-
-;; string/nth
-
-(defn check-nth
- [value n]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :integer n))
- end-state ((:string_nth @core/instruction-table) start-state)]
- (or
- (and (empty? value)
- (state/empty-stack? end-state :char)
- (= value (state/peek-stack end-state :string))
- (= n (state/peek-stack end-state :integer)))
- (= (nth value (mod n (count value)))
- (state/peek-stack end-state :char)))))
-
-(defspec nth-spec 100
- (prop/for-all [str gen/string
- int gen/small-integer]
- (check-nth str int)))
-
-
-;; string/occurencesof_char
-
-(defn check-occurencesof-char
- [value char]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :char char))
- end-state ((:string_occurencesof_char @core/instruction-table) start-state)
- expected-result (count (filter #(= char %) value))]
- (= expected-result
- (state/peek-stack end-state :integer))))
-
-(defspec occurencesof-char-spec 100
- (prop/for-all [str gen/string
- char gen/char]
- (check-occurencesof-char str char)))
-
-
-;; string/parse-to-chars
-
-(defn check-parse-to-chars
- [value]
- (let [start-state (state/push-to-stack state/empty-state :string value)
- end-state ((:string_parse_to_chars @core/instruction-table) start-state)
- ;; Since split will return the empty string when given the empty string
- string-length (if (= 0 (count value)) 1 (count value))
- expected-result (string/split value #"")]
- (and
- (= expected-result
- (state/peek-stack-many end-state :string string-length))
- (-> end-state
- (state/pop-stack-many :string string-length)
- (state/empty-stack? :string)))))
-
-(defspec parse-to-chars-spec 100
- (prop/for-all [str gen/string]
- (check-parse-to-chars str)))
-
-
-;; string/remove-char
-
-(defn check-remove-char
- [value char]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :char char))
- end-state ((:string_remove_char @core/instruction-table) start-state)
- expected-result (apply str (filter #(not= char %) value))]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec remove-char-spec 100
- (prop/for-all [str gen/string
- char gen/char]
- (check-remove-char str char)))
-
-
-;; string/replace
-
-(defn check-replace
- [value1 value2 value3]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value1)
- (state/push-to-stack :string value2)
- (state/push-to-stack :string value3))
- end-state ((:string_replace @core/instruction-table) start-state)
- expected-result (string/replace value1 value2 value3)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec replace-spec 100
- (prop/for-all [str1 gen/string
- str2 gen/string
- str3 gen/string]
- (check-replace str1 str2 str3)))
-
-
-;; string/replace-char
-
-(defn check-replace-char
- [value char1 char2]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :char char1)
- (state/push-to-stack :char char2))
- end-state ((:string_replace_char @core/instruction-table) start-state)
- expected-result (string/replace value char1 char2)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec replace-char-spec 100
- (prop/for-all [str gen/string
- char1 gen/char
- char2 gen/char]
- (check-replace-char str char1 char2)))
-
-
-;; string/replace-first
-
-(defn check-replace-first
- [value1 value2 value3]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value1)
- (state/push-to-stack :string value2)
- (state/push-to-stack :string value3))
- end-state ((:string_replace_first @core/instruction-table) start-state)
- expected-result (string/replace-first value1 value2 value3)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec replace-first-spec 100
- (prop/for-all [str1 gen/string
- str2 gen/string
- str3 gen/string]
- (check-replace-first str1 str2 str3)))
-
-
-;; string/replace-first-char
-
-(defn check-replace-first-char
- [value char1 char2]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :char char1)
- (state/push-to-stack :char char2))
- end-state ((:string_replace_first_char @core/instruction-table) start-state)
- expected-result (string/replace-first value char1 char2)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec replace-first-char-spec 100
- (prop/for-all [str gen/string
- char1 gen/char
- char2 gen/char]
- (check-replace-first-char str char1 char2)))
-
-
-;; string/rest
-
-(defn check-rest
- [value]
- (let [start-state (state/push-to-stack state/empty-state :string value)
- end-state ((:string_rest @core/instruction-table) start-state)
- expected-result (apply str (rest value))]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec rest-spec 100
- (prop/for-all [str gen/string]
- (check-rest str)))
-
-
-;; string/reverse
-
-(defn check-reverse
- [value]
- (let [start-state (state/push-to-stack state/empty-state :string value)
- end-state ((:string_reverse @core/instruction-table) start-state)
- expected-result (apply str (reverse value))]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec reverse-spec 100
- (prop/for-all [str gen/string]
- (check-reverse str)))
-
-
-;; string/set-char
-
-(defn check-set-char
- [value char n]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :char char)
- (state/push-to-stack :integer n))
- end-state ((:string_set_char @core/instruction-table) start-state)]
- (or
- (and
- (empty? value)
- (= (state/peek-stack end-state :string) value)
- (= (state/peek-stack end-state :char) char)
- (= (state/peek-stack end-state :integer) n))
- (=
- (let [index (mod n (count value))
- start (subs value 0 index)
- end (subs value (+ index 1))]
- (str start char end))
- (state/peek-stack end-state :string)))))
-
-(defspec set-char-spec 100
- (prop/for-all [str gen/string
- char gen/char
- int gen/small-integer]
- (check-set-char str char int)))
-
-
-;; string/split
-
-(defn check-split
- [value]
- (let [start-state (state/push-to-stack state/empty-state :string value)
- end-state ((:string_split @core/instruction-table) start-state)
- our-split (string/split (string/trim value) #"\s+")
- num-items (count our-split)]
- (and
- (= (state/stack-size end-state :string) num-items)
- (every? identity
- (map =
- our-split
- (state/peek-stack-many end-state :string num-items))))))
-
-(defspec split-spec 100
- (prop/for-all [str gen/string]
- (check-split str)))
-
-
-;; string/substr
-
-(defn check-substr
- [instruction value start end]
- (let [start-state (-> state/empty-state
- (state/push-to-stack :string value)
- (state/push-to-stack :integer start)
- (state/push-to-stack :integer end))
- end-state ((instruction @core/instruction-table) start-state)
- str-len (count value)
- small (min str-len (max 0 start))
- big (min str-len (max 0 small end))
- expected-result (subs value small big)]
- (= expected-result
- (state/peek-stack end-state :string))))
-
-(defspec substr-spec 100
- (prop/for-all
- [tuple (gen/let [str gen/string
- int1 (gen/large-integer* {:min -5 :max (+ 5 (count str))})
- int2 (gen/large-integer* {:min -5 :max (+ 5 (count str))})]
- [:string_substr, str, int1, int2])]
- (apply check-substr tuple)))
-
-(defspec take-spec 100
- (prop/for-all
- [tuple (gen/let [str gen/string
- int (gen/large-integer* {:min -5 :max (+ 5 (count str))})]
- [:string_take, str, 0, int])]
- (apply check-substr tuple)))
\ No newline at end of file
+;(ns propeller.push.instructions.string-spec
+; (:require
+; [clojure.string :as string]
+; [clojure.test.check.generators :as gen]
+; [clojure.test.check.properties :as prop]
+; [clojure.test.check.clojure-test :as ct :refer [defspec]]
+; [propeller.push.state :as state]
+; [propeller.push.core :as core]
+; [propeller.push.instructions.string :as string-instructions]
+; [propeller.push.interpreter :as interpreter]))
+;
+;
+;;; string/butlast
+;
+;(defn check-butlast
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state
+; :string
+; value)
+; end-state ((:string_butlast @core/instruction-table) start-state)
+; expected-result (apply str (butlast value))]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec butlast-spec 100
+; (prop/for-all [str gen/string]
+; (check-butlast str)))
+;
+;
+;;; string/concat
+;
+;(defn check-concat
+; [value1 value2]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value1)
+; (state/push-to-stack :string value2))
+; end-state ((:string_concat @core/instruction-table) start-state)
+; expected-result (str value1 value2)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec concat-spec 100
+; (prop/for-all [str1 gen/string
+; str2 gen/string]
+; (check-concat str1 str2)))
+;
+;
+;;; string/conj-char
+;
+;(defn check-conj-char
+; [value char]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :char char))
+; end-state ((:string_conj_char @core/instruction-table) start-state)
+; expected-result (str value char)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec conj-char-spec 100
+; (prop/for-all [str gen/string
+; char gen/char]
+; (check-conj-char str char)))
+;
+;
+;;; string/contains
+;
+;(defn check-contains
+; [value1 value2]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value1)
+; (state/push-to-stack :string value2))
+; end-state ((:string_contains @core/instruction-table) start-state)
+; expected-result (string/includes? value2 value1)]
+; (= expected-result
+; (state/peek-stack end-state :boolean))))
+;
+;(defspec contains-spec 100
+; (prop/for-all [str1 gen/string
+; str2 gen/string]
+; (check-contains str1 str2)))
+;
+;
+;;; string/contains-char
+;
+;(defn check-contains-char
+; [value char]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :char char))
+; end-state ((:string_contains_char @core/instruction-table) start-state)
+; expected-result (string/includes? value (str char))]
+; (= expected-result
+; (state/peek-stack end-state :boolean))))
+;
+;(defspec contains-char-spec 100
+; (prop/for-all [str gen/string
+; char gen/char]
+; (check-contains-char str char)))
+;
+;
+;;; string/drop
+;
+;(defn check-drop
+; [value n]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :integer n))
+; end-state ((:string_drop @core/instruction-table) start-state)
+; expected-result (apply str (drop n value))]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec drop-spec 100
+; (prop/for-all [str gen/string
+; int gen/small-integer]
+; (check-drop str int)))
+;
+;
+;;; string/empty-string
+;
+;(defn check-empty-string
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :string value)
+; end-state ((:string_empty_string @core/instruction-table) start-state)
+; expected-result (empty? value)]
+; (= expected-result
+; (state/peek-stack end-state :boolean))))
+;
+;(defspec empty-string-spec 100
+; (prop/for-all [str gen/string]
+; (check-empty-string str)))
+;
+;
+;;; string/first
+;
+;(defn check-first
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :string value)
+; end-state ((:string_first @core/instruction-table) start-state)
+; expected-result (first value)]
+; (or
+; (and (empty? value)
+; (= (state/peek-stack end-state :string) value)
+; (state/empty-stack? end-state :char))
+; (and (= expected-result
+; (state/peek-stack end-state :char))
+; (state/empty-stack? end-state :string)))))
+;
+;(defspec first-spec 100
+; (prop/for-all [str gen/string]
+; (check-first str)))
+;
+;
+;;; string/from-boolean
+;
+;(defn check-from-boolean
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :boolean value)
+; end-state ((:string_from_boolean @core/instruction-table) start-state)
+; expected-result (str value)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec from-boolean-spec 10
+; (prop/for-all [bool gen/boolean]
+; (check-from-boolean bool)))
+;
+;
+;;; string/from-char
+;
+;(defn check-from-char
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :char value)
+; end-state ((:string_from_char @core/instruction-table) start-state)
+; expected-result (str value)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec from-char-spec 100
+; (prop/for-all [char gen/char]
+; (check-from-char char)))
+;
+;
+;;; string/from-float
+;
+;(defn check-from-float
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :float value)
+; end-state ((:string_from_float @core/instruction-table) start-state)
+; expected-result (str value)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec from-float-spec 100
+; (prop/for-all [float gen/double]
+; (check-from-float float)))
+;
+;
+;;; string/from-integer
+;
+;(defn check-from-integer
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :integer value)
+; end-state ((:string_from_integer @core/instruction-table) start-state)
+; expected-result (str value)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec from-integer-spec 100
+; (prop/for-all [int gen/small-integer]
+; (check-from-integer int)))
+;
+;
+;;; string/indexof-char
+;
+;(defn check-indexof-char
+; [value char]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :char char))
+; end-state ((:string_indexof_char @core/instruction-table) start-state)
+; expected-result (string/index-of value char)]
+; (or
+; (and (not expected-result)
+; (= (state/peek-stack end-state :string) value)
+; (= (state/peek-stack end-state :char) char)
+; (state/empty-stack? end-state :integer))
+; (= expected-result
+; (state/peek-stack end-state :integer)))))
+;
+;(defspec indexof-char-spec 100
+; (prop/for-all [str gen/string
+; char gen/char]
+; (check-indexof-char str char)))
+;
+;
+;;; string/iterate
+;
+;(defn check-iterate
+; [value]
+; (let [print-instr (keyword "char_print")
+; iter-instr (keyword "string_iterate")
+; program [iter-instr print-instr]
+; start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :output ""))
+; ; 4 times the string length should be enough for this iteration, perhaps even
+; ; more than we strictly need.
+; end-state (interpreter/interpret-program program start-state (* 4 (count value)))]
+; (= value
+; (state/peek-stack end-state :output))))
+;
+;(defspec iterate-spec 100
+; (prop/for-all [value gen/string]
+; (check-iterate value)))
+;
+;;; string/last
+;
+;(defn check-last
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :string value)
+; end-state ((:string_last @core/instruction-table) start-state)
+; expected-result (last value)]
+; (or
+; (and (empty? value)
+; (state/empty-stack? end-state :char)
+; (= value (state/peek-stack end-state :string)))
+; (and (state/empty-stack? end-state :string)
+; (= expected-result
+; (state/peek-stack end-state :char))))))
+;
+;(defspec last-spec 100
+; (prop/for-all [str gen/string]
+; (check-last str)))
+;
+;
+;;; string/length
+;
+;(defn check-length
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :string value)
+; end-state ((:string_length @core/instruction-table) start-state)
+; expected-result (count value)]
+; (= expected-result
+; (state/peek-stack end-state :integer))))
+;
+;(defspec length-spec 100
+; (prop/for-all [str gen/string]
+; (check-length str)))
+;
+;
+;;; string/nth
+;
+;(defn check-nth
+; [value n]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :integer n))
+; end-state ((:string_nth @core/instruction-table) start-state)]
+; (or
+; (and (empty? value)
+; (state/empty-stack? end-state :char)
+; (= value (state/peek-stack end-state :string))
+; (= n (state/peek-stack end-state :integer)))
+; (= (nth value (mod n (count value)))
+; (state/peek-stack end-state :char)))))
+;
+;(defspec nth-spec 100
+; (prop/for-all [str gen/string
+; int gen/small-integer]
+; (check-nth str int)))
+;
+;
+;;; string/occurencesof_char
+;
+;(defn check-occurencesof-char
+; [value char]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :char char))
+; end-state ((:string_occurencesof_char @core/instruction-table) start-state)
+; expected-result (count (filter #(= char %) value))]
+; (= expected-result
+; (state/peek-stack end-state :integer))))
+;
+;(defspec occurencesof-char-spec 100
+; (prop/for-all [str gen/string
+; char gen/char]
+; (check-occurencesof-char str char)))
+;
+;
+;;; string/parse-to-chars
+;
+;(defn check-parse-to-chars
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :string value)
+; end-state ((:string_parse_to_chars @core/instruction-table) start-state)
+; ;; Since split will return the empty string when given the empty string
+; string-length (if (= 0 (count value)) 1 (count value))
+; expected-result (string/split value #"")]
+; (and
+; (= expected-result
+; (state/peek-stack-many end-state :string string-length))
+; (-> end-state
+; (state/pop-stack-many :string string-length)
+; (state/empty-stack? :string)))))
+;
+;(defspec parse-to-chars-spec 100
+; (prop/for-all [str gen/string]
+; (check-parse-to-chars str)))
+;
+;
+;;; string/remove-char
+;
+;(defn check-remove-char
+; [value char]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :char char))
+; end-state ((:string_remove_char @core/instruction-table) start-state)
+; expected-result (apply str (filter #(not= char %) value))]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec remove-char-spec 100
+; (prop/for-all [str gen/string
+; char gen/char]
+; (check-remove-char str char)))
+;
+;
+;;; string/replace
+;
+;(defn check-replace
+; [value1 value2 value3]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value1)
+; (state/push-to-stack :string value2)
+; (state/push-to-stack :string value3))
+; end-state ((:string_replace @core/instruction-table) start-state)
+; expected-result (string/replace value1 value2 value3)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec replace-spec 100
+; (prop/for-all [str1 gen/string
+; str2 gen/string
+; str3 gen/string]
+; (check-replace str1 str2 str3)))
+;
+;
+;;; string/replace-char
+;
+;(defn check-replace-char
+; [value char1 char2]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :char char1)
+; (state/push-to-stack :char char2))
+; end-state ((:string_replace_char @core/instruction-table) start-state)
+; expected-result (string/replace value char1 char2)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec replace-char-spec 100
+; (prop/for-all [str gen/string
+; char1 gen/char
+; char2 gen/char]
+; (check-replace-char str char1 char2)))
+;
+;
+;;; string/replace-first
+;
+;(defn check-replace-first
+; [value1 value2 value3]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value1)
+; (state/push-to-stack :string value2)
+; (state/push-to-stack :string value3))
+; end-state ((:string_replace_first @core/instruction-table) start-state)
+; expected-result (string/replace-first value1 value2 value3)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec replace-first-spec 100
+; (prop/for-all [str1 gen/string
+; str2 gen/string
+; str3 gen/string]
+; (check-replace-first str1 str2 str3)))
+;
+;
+;;; string/replace-first-char
+;
+;(defn check-replace-first-char
+; [value char1 char2]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :char char1)
+; (state/push-to-stack :char char2))
+; end-state ((:string_replace_first_char @core/instruction-table) start-state)
+; expected-result (string/replace-first value char1 char2)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec replace-first-char-spec 100
+; (prop/for-all [str gen/string
+; char1 gen/char
+; char2 gen/char]
+; (check-replace-first-char str char1 char2)))
+;
+;
+;;; string/rest
+;
+;(defn check-rest
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :string value)
+; end-state ((:string_rest @core/instruction-table) start-state)
+; expected-result (apply str (rest value))]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec rest-spec 100
+; (prop/for-all [str gen/string]
+; (check-rest str)))
+;
+;
+;;; string/reverse
+;
+;(defn check-reverse
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :string value)
+; end-state ((:string_reverse @core/instruction-table) start-state)
+; expected-result (apply str (reverse value))]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec reverse-spec 100
+; (prop/for-all [str gen/string]
+; (check-reverse str)))
+;
+;
+;;; string/set-char
+;
+;(defn check-set-char
+; [value char n]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :char char)
+; (state/push-to-stack :integer n))
+; end-state ((:string_set_char @core/instruction-table) start-state)]
+; (or
+; (and
+; (empty? value)
+; (= (state/peek-stack end-state :string) value)
+; (= (state/peek-stack end-state :char) char)
+; (= (state/peek-stack end-state :integer) n))
+; (=
+; (let [index (mod n (count value))
+; start (subs value 0 index)
+; end (subs value (+ index 1))]
+; (str start char end))
+; (state/peek-stack end-state :string)))))
+;
+;(defspec set-char-spec 100
+; (prop/for-all [str gen/string
+; char gen/char
+; int gen/small-integer]
+; (check-set-char str char int)))
+;
+;
+;;; string/split
+;
+;(defn check-split
+; [value]
+; (let [start-state (state/push-to-stack state/empty-state :string value)
+; end-state ((:string_split @core/instruction-table) start-state)
+; our-split (string/split (string/trim value) #"\s+")
+; num-items (count our-split)]
+; (and
+; (= (state/stack-size end-state :string) num-items)
+; (every? identity
+; (map =
+; our-split
+; (state/peek-stack-many end-state :string num-items))))))
+;
+;(defspec split-spec 100
+; (prop/for-all [str gen/string]
+; (check-split str)))
+;
+;
+;;; string/substr
+;
+;(defn check-substr
+; [instruction value start end]
+; (let [start-state (-> state/empty-state
+; (state/push-to-stack :string value)
+; (state/push-to-stack :integer start)
+; (state/push-to-stack :integer end))
+; end-state ((instruction @core/instruction-table) start-state)
+; str-len (count value)
+; small (min str-len (max 0 start))
+; big (min str-len (max 0 small end))
+; expected-result (subs value small big)]
+; (= expected-result
+; (state/peek-stack end-state :string))))
+;
+;(defspec substr-spec 100
+; (prop/for-all
+; [tuple (gen/let [str gen/string
+; int1 (gen/large-integer* {:min -5 :max (+ 5 (count str))})
+; int2 (gen/large-integer* {:min -5 :max (+ 5 (count str))})]
+; [:string_substr, str, int1, int2])]
+; (apply check-substr tuple)))
+;
+;(defspec take-spec 100
+; (prop/for-all
+; [tuple (gen/let [str gen/string
+; int (gen/large-integer* {:min -5 :max (+ 5 (count str))})]
+; [:string_take, str, 0, int])]
+; (apply check-substr tuple)))
diff --git a/test/propeller/push/instructions/vector_spec.clj b/test/propeller/push/instructions/vector_spec.clj
index 4a16e19..18292d4 100644
--- a/test/propeller/push/instructions/vector_spec.clj
+++ b/test/propeller/push/instructions/vector_spec.clj
@@ -1,475 +1,475 @@
-(ns propeller.push.instructions.vector-spec
- (:require
- [clojure.test.check.generators :as gen]
- [clojure.test.check.properties :as prop]
- [clojure.test.check.clojure-test :as ct :refer [defspec]]
- [propeller.push.state :as state]
- [propeller.push.instructions.vector :as vector]
- [propeller.push.interpreter :as interpreter]))
-
-(def gen-type-pairs
- [['gen/small-integer "integer"]
- ['gen/double "float"]
- ['gen/boolean "boolean"]
- ['gen/string "string"]])
-
-(defn generator-for-arg-type
- [arg-type generator]
- (case arg-type
- :boolean 'gen/boolean
- :integer 'gen/small-integer
- :float 'gen/double
- :string 'gen/string
- ; This is for "generic" vectors where the element is provided by
- ; the `generator` argument.
- :vector `(gen/vector ~generator)
- :item generator
- :vector_boolean '(gen/vector gen/boolean)
- :vector_integer '(gen/vector gen/small-integer)
- :vector_float '(gen/vector gen/double)
- :vector_string '(gen/vector gen/string)))
-
-(defmacro gen-specs
- [spec-name check-fn & arg-types]
- (let [symbol-names (repeatedly (count arg-types) gensym)]
- `(do ~@(for [[generator value-type] gen-type-pairs
- :let [name (symbol (str spec-name "-spec-" value-type))]]
- `(defspec ~name
- (prop/for-all
- [~@(mapcat
- (fn [symbol-name arg-type]
- [symbol-name (generator-for-arg-type arg-type generator)])
- symbol-names
- arg-types)]
- (~check-fn ~value-type ~@symbol-names)))))))
-
-;;; vector/_butlast
-
-(defn check-butlast
- [value-type vect]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack state/empty-state
- stack-type
- vect)
- end-state (vector/_butlast stack-type start-state)
- expected-result (vec (butlast vect))]
- (= expected-result
- (state/peek-stack end-state stack-type))))
-
-(gen-specs "butlast" check-butlast :vector)
-
-;;; vector/_concat
-
-(defn check-concat
- "Creates an otherwise empty Push state with the two given vectors on the
- appropriate vector stack (assumed to be :vector_).
- It then runs the vector/_concat instruction, and confirms that the
- result (on the :vector_ stack) is the expected value.
- The order of concatenation is that the top of the stack will be
- _second_ in the concatenation, i.e., its elements will come _after_
- the elements in the vector one below it in the stack."
- [value-type first-vect second-vect]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- first-vect)
- stack-type second-vect)
- end-state (vector/_concat stack-type start-state)]
- (= (concat second-vect first-vect)
- (state/peek-stack end-state stack-type))))
-
-(gen-specs "concat" check-concat :vector :vector)
-
-;;; vecotr/_conj
-
-(defn check-conj
- [value-type vect value]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- (keyword (str value-type))
- value)
- end-state (vector/_conj stack-type start-state)
- expected-result (conj vect value)]
- (= expected-result
- (state/peek-stack end-state stack-type))))
-
-(gen-specs "conj" check-conj :vector :item)
-
-;;; vector/_contains
-
-(defn check-contains
- "Creates an otherwise empty Push state with the given vector on the
- appropriate vector stack (assumed to be :vector_), and
- the given value on the appropriate stack (determined by value-type).
- It then runs the vector/_contains instruction, and confirms that the
- result (on the :boolean stack) is the expected value."
- [value-type vect value]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- (keyword value-type) value)
- end-state (vector/_contains stack-type start-state)
- expected-result (not= (.indexOf vect value) -1)]
- (= expected-result
- (state/peek-stack end-state :boolean))))
-
-(gen-specs "contains" check-contains :vector :item)
-
-;;; vector/_emptyvector
-
-(defn check-empty-vector
- [value-type vect]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack state/empty-state
- stack-type
- vect)
- end-state (vector/_emptyvector stack-type start-state)]
- (= (empty? vect)
- (state/peek-stack end-state :boolean))))
-
-(gen-specs "empty-vector" check-empty-vector :vector)
-
-;;; vector/_first
-
-(defn check-first
- [value-type vect]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack state/empty-state
- stack-type
- vect)
- end-state (vector/_first stack-type start-state)]
- (or
- (and (empty? vect)
- (= (state/peek-stack end-state stack-type)
- vect))
- (and
- (= (first vect)
- (state/peek-stack end-state (keyword value-type)))
- (state/empty-stack? end-state stack-type)))))
-
-(gen-specs "first" check-first :vector)
-
-;;; vector/_indexof
-
-(defn check-indexof
- "Creates an otherwise empty Push state with the given vector on the
- appropriate vector stack (assumed to be :vector_), and
- the given value on the appropriate stack (determined by value-type).
- It then runs the vector/_indexof instruction, and confirms that the
- result (on the :integer stack) is the expected value."
- [value-type vect value]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- (keyword value-type) value)
- end-state (vector/_indexof stack-type start-state)
- expected-index (.indexOf vect value)]
- (= expected-index
- (state/peek-stack end-state :integer))))
-
-(gen-specs "indexof" check-indexof :vector :item)
-
-;;; vector/_iterate
-
-(defn check-iterate
- [value-type vect]
- (let [stack-type (keyword (str "vector_" value-type))
- print-instr (keyword (str value-type "_print"))
- iter-instr (keyword (str "vector_" value-type "_iterate"))
- program [iter-instr print-instr]
- start-state (-> state/empty-state
- (state/push-to-stack stack-type vect)
- (state/push-to-stack :output ""))
- ; 4 times the vector length should be enough for this iteration, perhaps even
- ; more than we strictly need.
- end-state (interpreter/interpret-program program start-state (* 4 (count vect)))
- ; pr-str adds escaped quote marks, which causes tests to fail because _print
- ; treats strings and characters specially and does not call pr-str on them.
- to-str-fn (if (= value-type "string") identity pr-str)
- expected-result (apply str (map to-str-fn vect))]
- (= expected-result
- (state/peek-stack end-state :output))))
-
-(gen-specs "iterate" check-iterate :vector)
-
-;;; vector/_last
-
-(defn check-last
- [value-type vect]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack state/empty-state
- stack-type
- vect)
- end-state (vector/_last stack-type start-state)]
- (or
- (and (empty? vect)
- (= (state/peek-stack end-state stack-type)
- vect))
- (and
- (= (last vect)
- (state/peek-stack end-state (keyword value-type)))
- (state/empty-stack? end-state stack-type)))))
-
-(gen-specs "last" check-last :vector)
-
-;;; vector/_length
-
-(defn check-length
- [value-type vect]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack state/empty-state
- stack-type
- vect)
- end-state (vector/_length stack-type start-state)
- expected-result (count vect)]
- (= expected-result
- (state/peek-stack end-state :integer))))
-
-(gen-specs "length" check-length :vector)
-
-;;; vector/_nth
-
-(defn check-nth
- [value-type vect n]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- :integer
- n)
- end-state (vector/_nth stack-type start-state)]
- (or
- (and (empty? vect)
- (= (state/peek-stack end-state stack-type)
- vect))
- (and
- (= (get vect (mod n (count vect)))
- (state/peek-stack end-state (keyword value-type)))))))
-
-(gen-specs "nth" check-nth :vector :integer)
-
-;;; vector/_occurrencesof
-
-(defn check-occurrencesof
- [value-type vect value]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- (keyword value-type)
- value)
- end-state (vector/_occurrencesof stack-type start-state)
- expected-result (count (filterv #(= value %) vect))]
- (= expected-result
- (state/peek-stack end-state :integer))))
-
-(gen-specs "occurrencesof" check-occurrencesof :vector :item)
-
-;;; vector/_pushall
-
-(defn check-pushall
- [value-type vect]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack state/empty-state
- stack-type
- vect)
- end-state (vector/_pushall stack-type start-state)
- value-stack (keyword value-type)
- vect-length (count vect)]
- (and
- (=
- (vec (state/peek-stack-many end-state value-stack vect-length))
- vect)
- (state/empty-stack?
- (state/pop-stack-many end-state value-stack vect-length)
- value-stack))))
-
-(gen-specs "pushall" check-pushall :vector)
-
-;;; vector/_remove
-
-(defn check-remove
- [value-type vect value]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- (keyword value-type)
- value)
- end-state (vector/_remove stack-type start-state)]
- (= []
- (filterv #(= % value) (state/peek-stack end-state stack-type)))))
-
-(gen-specs "remove" check-remove :vector :item)
-
-;;; vector/_replace
-
-(defn check-replace
- [value-type vect toreplace replacement]
- (let [stack-type (keyword (str "vector_" value-type))
- value-stack (keyword value-type)
- start-state (state/push-to-stack
- (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- value-stack
- toreplace)
- value-stack
- replacement)
- end-state (vector/_replace stack-type start-state)
- expected-result (replace {toreplace replacement} vect)]
- (= expected-result
- (state/peek-stack end-state stack-type))))
-
-(gen-specs "replace" check-replace :vector :item :item)
-
-;;; vector/_replacefirst
-
-(defn check-replacefirst
- [value-type vect toreplace replacement]
- (let [stack-type (keyword (str "vector_" value-type))
- value-stack (keyword value-type)
- start-state (state/push-to-stack
- (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- value-stack
- toreplace)
- value-stack
- replacement)
- end-state (vector/_replacefirst stack-type start-state)
- end-vector (state/peek-stack end-state stack-type)
- replacement-index (.indexOf vect toreplace)]
- (or
- (and (= replacement-index -1)
- (state/empty-stack? end-state value-stack)
- (= vect end-vector))
- (and (state/empty-stack? end-state value-stack)
- (= end-vector (assoc vect replacement-index replacement))))))
-
-(gen-specs "replacefirst" check-replacefirst :vector :item :item)
-
-;;; vector/_rest
-
-(defn check-rest
- [value-type vect]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack state/empty-state
- stack-type
- vect)
- end-state (vector/_rest stack-type start-state)
- expected-result (vec (rest vect))]
- (= expected-result
- (state/peek-stack end-state stack-type))))
-
-(gen-specs "rest" check-rest :vector)
-
-;;; vector/_reverse
-
-(defn check-reverse
- [value-type vect]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack state/empty-state
- stack-type
- vect)
- end-state (vector/_reverse stack-type start-state)
- expected-result (vec (reverse vect))]
- (= expected-result
- (state/peek-stack end-state stack-type))))
-
-(gen-specs "reverse" check-reverse :vector)
-
-;;; vector/_set
-
-(defn check-set
- [value-type vect value n]
- (let [stack-type (keyword (str "vector_" value-type))
- value-stack (keyword value-type)
- start-state (state/push-to-stack
- (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- value-stack
- value)
- :integer
- n)
- end-state (vector/_set stack-type start-state)]
- (or
- (and
- (empty? vect)
- (not (state/empty-stack? end-state :integer))
- (not (state/empty-stack? end-state value-stack))
- (= vect (state/peek-stack end-state stack-type)))
- (and
- (= (state/peek-stack end-state stack-type)
- (assoc vect (mod n (count vect)) value))
- (state/empty-stack? end-state :integer)
- (state/empty-stack? end-state value-stack)))))
-
-(gen-specs "set" check-set :vector :item :integer)
-
-;;; vector/_subvec
-
-(defn clean-subvec-bounds
- [start stop vect-size]
- (let [start (max 0 start)
- stop (max 0 stop)
- start (min start vect-size)
- stop (min stop vect-size)
- stop (max start stop)]
- [start stop]))
-
-(defn check-subvec
- "Creates an otherwise empty Push state with the given vector on the
- appropriate vector stack (assumed to be :vector_), and
- the given values on the integer stack.
- It then runs the vector/_subvec instruction, and confirms that the
- result (on the :vector_ stack) is the expected value."
- [value-type vect start stop]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack
- (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- :integer start)
- :integer stop)
- end-state (vector/_subvec stack-type start-state)
- [cleaned-start cleaned-stop] (clean-subvec-bounds start stop (count vect))
- expected-subvec (subvec vect cleaned-start cleaned-stop)]
- (= expected-subvec
- (state/peek-stack end-state stack-type))))
-
-(gen-specs "subvec" check-subvec :vector :integer :integer)
-
-;;; vector/_take
-
-(defn check-take
- [value-type vect n]
- (let [stack-type (keyword (str "vector_" value-type))
- start-state (state/push-to-stack
- (state/push-to-stack state/empty-state
- stack-type
- vect)
- :integer
- n)
- end-state (vector/_take stack-type start-state)
- expected-result (vec (take n vect))]
- (= expected-result
- (state/peek-stack end-state stack-type))))
-
-(gen-specs "take" check-take :vector :integer)
\ No newline at end of file
+;(ns propeller.push.instructions.vector-spec
+; (:require
+; [clojure.test.check.generators :as gen]
+; [clojure.test.check.properties :as prop]
+; [clojure.test.check.clojure-test :as ct :refer [defspec]]
+; [propeller.push.state :as state]
+; [propeller.push.instructions.vector :as vector]
+; [propeller.push.interpreter :as interpreter]))
+;
+;(def gen-type-pairs
+; [['gen/small-integer "integer"]
+; ['gen/double "float"]
+; ['gen/boolean "boolean"]
+; ['gen/string "string"]])
+;
+;(defn generator-for-arg-type
+; [arg-type generator]
+; (case arg-type
+; :boolean 'gen/boolean
+; :integer 'gen/small-integer
+; :float 'gen/double
+; :string 'gen/string
+; ; This is for "generic" vectors where the element is provided by
+; ; the `generator` argument.
+; :vector `(gen/vector ~generator)
+; :item generator
+; :vector_boolean '(gen/vector gen/boolean)
+; :vector_integer '(gen/vector gen/small-integer)
+; :vector_float '(gen/vector gen/double)
+; :vector_string '(gen/vector gen/string)))
+;
+;(defmacro gen-specs
+; [spec-name check-fn & arg-types]
+; (let [symbol-names (repeatedly (count arg-types) gensym)]
+; `(do ~@(for [[generator value-type] gen-type-pairs
+; :let [name (symbol (str spec-name "-spec-" value-type))]]
+; `(defspec ~name
+; (prop/for-all
+; [~@(mapcat
+; (fn [symbol-name arg-type]
+; [symbol-name (generator-for-arg-type arg-type generator)])
+; symbol-names
+; arg-types)]
+; (~check-fn ~value-type ~@symbol-names)))))))
+;
+;;;; vector/_butlast
+;
+;(defn check-butlast
+; [value-type vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; end-state (vector/_butlast stack-type start-state)
+; expected-result (vec (butlast vect))]
+; (= expected-result
+; (state/peek-stack end-state stack-type))))
+;
+;(gen-specs "butlast" check-butlast :vector)
+;
+;;;; vector/_concat
+;
+;(defn check-concat
+; "Creates an otherwise empty Push state with the two given vectors on the
+; appropriate vector stack (assumed to be :vector_).
+; It then runs the vector/_concat instruction, and confirms that the
+; result (on the :vector_ stack) is the expected value.
+; The order of concatenation is that the top of the stack will be
+; _second_ in the concatenation, i.e., its elements will come _after_
+; the elements in the vector one below it in the stack."
+; [value-type first-vect second-vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; first-vect)
+; stack-type second-vect)
+; end-state (vector/_concat stack-type start-state)]
+; (= (concat second-vect first-vect)
+; (state/peek-stack end-state stack-type))))
+;
+;(gen-specs "concat" check-concat :vector :vector)
+;
+;;;; vecotr/_conj
+;
+;(defn check-conj
+; [value-type vect value]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; (keyword (str value-type))
+; value)
+; end-state (vector/_conj stack-type start-state)
+; expected-result (conj vect value)]
+; (= expected-result
+; (state/peek-stack end-state stack-type))))
+;
+;(gen-specs "conj" check-conj :vector :item)
+;
+;;;; vector/_contains
+;
+;(defn check-contains
+; "Creates an otherwise empty Push state with the given vector on the
+; appropriate vector stack (assumed to be :vector_), and
+; the given value on the appropriate stack (determined by value-type).
+; It then runs the vector/_contains instruction, and confirms that the
+; result (on the :boolean stack) is the expected value."
+; [value-type vect value]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; (keyword value-type) value)
+; end-state (vector/_contains stack-type start-state)
+; expected-result (not= (.indexOf vect value) -1)]
+; (= expected-result
+; (state/peek-stack end-state :boolean))))
+;
+;(gen-specs "contains" check-contains :vector :item)
+;
+;;;; vector/_emptyvector
+;
+;(defn check-empty-vector
+; [value-type vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; end-state (vector/_emptyvector stack-type start-state)]
+; (= (empty? vect)
+; (state/peek-stack end-state :boolean))))
+;
+;(gen-specs "empty-vector" check-empty-vector :vector)
+;
+;;;; vector/_first
+;
+;(defn check-first
+; [value-type vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; end-state (vector/_first stack-type start-state)]
+; (or
+; (and (empty? vect)
+; (= (state/peek-stack end-state stack-type)
+; vect))
+; (and
+; (= (first vect)
+; (state/peek-stack end-state (keyword value-type)))
+; (state/empty-stack? end-state stack-type)))))
+;
+;(gen-specs "first" check-first :vector)
+;
+;;;; vector/_indexof
+;
+;(defn check-indexof
+; "Creates an otherwise empty Push state with the given vector on the
+; appropriate vector stack (assumed to be :vector_), and
+; the given value on the appropriate stack (determined by value-type).
+; It then runs the vector/_indexof instruction, and confirms that the
+; result (on the :integer stack) is the expected value."
+; [value-type vect value]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; (keyword value-type) value)
+; end-state (vector/_indexof stack-type start-state)
+; expected-index (.indexOf vect value)]
+; (= expected-index
+; (state/peek-stack end-state :integer))))
+;
+;(gen-specs "indexof" check-indexof :vector :item)
+;
+;;;; vector/_iterate
+;
+;(defn check-iterate
+; [value-type vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; print-instr (keyword (str value-type "_print"))
+; iter-instr (keyword (str "vector_" value-type "_iterate"))
+; program [iter-instr print-instr]
+; start-state (-> state/empty-state
+; (state/push-to-stack stack-type vect)
+; (state/push-to-stack :output ""))
+; ; 4 times the vector length should be enough for this iteration, perhaps even
+; ; more than we strictly need.
+; end-state (interpreter/interpret-program program start-state (* 4 (count vect)))
+; ; pr-str adds escaped quote marks, which causes tests to fail because _print
+; ; treats strings and characters specially and does not call pr-str on them.
+; to-str-fn (if (= value-type "string") identity pr-str)
+; expected-result (apply str (map to-str-fn vect))]
+; (= expected-result
+; (state/peek-stack end-state :output))))
+;
+;(gen-specs "iterate" check-iterate :vector)
+;
+;;;; vector/_last
+;
+;(defn check-last
+; [value-type vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; end-state (vector/_last stack-type start-state)]
+; (or
+; (and (empty? vect)
+; (= (state/peek-stack end-state stack-type)
+; vect))
+; (and
+; (= (last vect)
+; (state/peek-stack end-state (keyword value-type)))
+; (state/empty-stack? end-state stack-type)))))
+;
+;(gen-specs "last" check-last :vector)
+;
+;;;; vector/_length
+;
+;(defn check-length
+; [value-type vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; end-state (vector/_length stack-type start-state)
+; expected-result (count vect)]
+; (= expected-result
+; (state/peek-stack end-state :integer))))
+;
+;(gen-specs "length" check-length :vector)
+;
+;;;; vector/_nth
+;
+;(defn check-nth
+; [value-type vect n]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; :integer
+; n)
+; end-state (vector/_nth stack-type start-state)]
+; (or
+; (and (empty? vect)
+; (= (state/peek-stack end-state stack-type)
+; vect))
+; (and
+; (= (get vect (mod n (count vect)))
+; (state/peek-stack end-state (keyword value-type)))))))
+;
+;(gen-specs "nth" check-nth :vector :integer)
+;
+;;;; vector/_occurrencesof
+;
+;(defn check-occurrencesof
+; [value-type vect value]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; (keyword value-type)
+; value)
+; end-state (vector/_occurrencesof stack-type start-state)
+; expected-result (count (filterv #(= value %) vect))]
+; (= expected-result
+; (state/peek-stack end-state :integer))))
+;
+;(gen-specs "occurrencesof" check-occurrencesof :vector :item)
+;
+;;;; vector/_pushall
+;
+;(defn check-pushall
+; [value-type vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; end-state (vector/_pushall stack-type start-state)
+; value-stack (keyword value-type)
+; vect-length (count vect)]
+; (and
+; (=
+; (vec (state/peek-stack-many end-state value-stack vect-length))
+; vect)
+; (state/empty-stack?
+; (state/pop-stack-many end-state value-stack vect-length)
+; value-stack))))
+;
+;(gen-specs "pushall" check-pushall :vector)
+;
+;;;; vector/_remove
+;
+;(defn check-remove
+; [value-type vect value]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; (keyword value-type)
+; value)
+; end-state (vector/_remove stack-type start-state)]
+; (= []
+; (filterv #(= % value) (state/peek-stack end-state stack-type)))))
+;
+;(gen-specs "remove" check-remove :vector :item)
+;
+;;;; vector/_replace
+;
+;(defn check-replace
+; [value-type vect toreplace replacement]
+; (let [stack-type (keyword (str "vector_" value-type))
+; value-stack (keyword value-type)
+; start-state (state/push-to-stack
+; (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; value-stack
+; toreplace)
+; value-stack
+; replacement)
+; end-state (vector/_replace stack-type start-state)
+; expected-result (replace {toreplace replacement} vect)]
+; (= expected-result
+; (state/peek-stack end-state stack-type))))
+;
+;(gen-specs "replace" check-replace :vector :item :item)
+;
+;;;; vector/_replacefirst
+;
+;(defn check-replacefirst
+; [value-type vect toreplace replacement]
+; (let [stack-type (keyword (str "vector_" value-type))
+; value-stack (keyword value-type)
+; start-state (state/push-to-stack
+; (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; value-stack
+; toreplace)
+; value-stack
+; replacement)
+; end-state (vector/_replacefirst stack-type start-state)
+; end-vector (state/peek-stack end-state stack-type)
+; replacement-index (.indexOf vect toreplace)]
+; (or
+; (and (= replacement-index -1)
+; (state/empty-stack? end-state value-stack)
+; (= vect end-vector))
+; (and (state/empty-stack? end-state value-stack)
+; (= end-vector (assoc vect replacement-index replacement))))))
+;
+;(gen-specs "replacefirst" check-replacefirst :vector :item :item)
+;
+;;;; vector/_rest
+;
+;(defn check-rest
+; [value-type vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; end-state (vector/_rest stack-type start-state)
+; expected-result (vec (rest vect))]
+; (= expected-result
+; (state/peek-stack end-state stack-type))))
+;
+;(gen-specs "rest" check-rest :vector)
+;
+;;;; vector/_reverse
+;
+;(defn check-reverse
+; [value-type vect]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; end-state (vector/_reverse stack-type start-state)
+; expected-result (vec (reverse vect))]
+; (= expected-result
+; (state/peek-stack end-state stack-type))))
+;
+;(gen-specs "reverse" check-reverse :vector)
+;
+;;;; vector/_set
+;
+;(defn check-set
+; [value-type vect value n]
+; (let [stack-type (keyword (str "vector_" value-type))
+; value-stack (keyword value-type)
+; start-state (state/push-to-stack
+; (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; value-stack
+; value)
+; :integer
+; n)
+; end-state (vector/_set stack-type start-state)]
+; (or
+; (and
+; (empty? vect)
+; (not (state/empty-stack? end-state :integer))
+; (not (state/empty-stack? end-state value-stack))
+; (= vect (state/peek-stack end-state stack-type)))
+; (and
+; (= (state/peek-stack end-state stack-type)
+; (assoc vect (mod n (count vect)) value))
+; (state/empty-stack? end-state :integer)
+; (state/empty-stack? end-state value-stack)))))
+;
+;(gen-specs "set" check-set :vector :item :integer)
+;
+;;;; vector/_subvec
+;
+;(defn clean-subvec-bounds
+; [start stop vect-size]
+; (let [start (max 0 start)
+; stop (max 0 stop)
+; start (min start vect-size)
+; stop (min stop vect-size)
+; stop (max start stop)]
+; [start stop]))
+;
+;(defn check-subvec
+; "Creates an otherwise empty Push state with the given vector on the
+; appropriate vector stack (assumed to be :vector_), and
+; the given values on the integer stack.
+; It then runs the vector/_subvec instruction, and confirms that the
+; result (on the :vector_ stack) is the expected value."
+; [value-type vect start stop]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack
+; (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; :integer start)
+; :integer stop)
+; end-state (vector/_subvec stack-type start-state)
+; [cleaned-start cleaned-stop] (clean-subvec-bounds start stop (count vect))
+; expected-subvec (subvec vect cleaned-start cleaned-stop)]
+; (= expected-subvec
+; (state/peek-stack end-state stack-type))))
+;
+;(gen-specs "subvec" check-subvec :vector :integer :integer)
+;
+;;;; vector/_take
+;
+;(defn check-take
+; [value-type vect n]
+; (let [stack-type (keyword (str "vector_" value-type))
+; start-state (state/push-to-stack
+; (state/push-to-stack state/empty-state
+; stack-type
+; vect)
+; :integer
+; n)
+; end-state (vector/_take stack-type start-state)
+; expected-result (vec (take n vect))]
+; (= expected-result
+; (state/peek-stack end-state stack-type))))
+;
+;(gen-specs "take" check-take :vector :integer)
diff --git a/test/propeller/push/state_test.cljc b/test/propeller/push/state_test.cljc
new file mode 100644
index 0000000..7d1fdc5
--- /dev/null
+++ b/test/propeller/push/state_test.cljc
@@ -0,0 +1,14 @@
+(ns propeller.push.state-test
+ (:require [clojure.test :as t]
+ [propeller.push.state :as state]
+ [propeller.push.utils.limits :as l]))
+
+(t/deftest push-to-stack-test
+ (t/is (= (state/push-to-stack {:integer '()} :integer 1)
+ {:integer '(1)}))
+ (t/is (= (state/push-to-stack {:integer '()} :integer 1e100)
+ {:integer (list (long l/max-number-magnitude))})))
+
+(t/deftest push-to-stack-many-test
+ (t/is (= (state/push-to-stack-many {:string '()} :string ["a" "b" "c"])
+ {:string '("a" "b" "c")})))
diff --git a/test/propeller/push/utils/helpers_test.cljc b/test/propeller/push/utils/helpers_test.cljc
new file mode 100644
index 0000000..097a4d6
--- /dev/null
+++ b/test/propeller/push/utils/helpers_test.cljc
@@ -0,0 +1,9 @@
+(ns propeller.push.utils.helpers-test
+ (:require [clojure.test :as t]
+ [propeller.push.utils.helpers :as h]))
+
+(t/deftest get-literal-type-test
+ (t/is (= (h/get-literal-type "abc") :string))
+ (t/is (= (h/get-literal-type [1]) :vector_integer))
+ (t/is (= (h/get-literal-type false) :boolean))
+ (t/is (= (h/get-literal-type 0.0) #?(:clj :float :cljs :integer))))
diff --git a/test/propeller/push/utils/limits_test.cljc b/test/propeller/push/utils/limits_test.cljc
new file mode 100644
index 0000000..99cacce
--- /dev/null
+++ b/test/propeller/push/utils/limits_test.cljc
@@ -0,0 +1,29 @@
+(ns propeller.push.utils.limits-test
+ (:require [clojure.test :as t]
+ [propeller.push.utils.limits :as l]))
+
+(t/deftest limit-number-test
+ (t/is (= (l/limit-number (inc l/max-number-magnitude))
+ l/max-number-magnitude))
+ (t/is (l/limit-number 1.0E-10)
+ l/min-number-magnitude))
+
+(t/deftest limit-string-test
+ (t/is (= (l/limit-string (apply str (repeat (inc l/max-string-length) "!")))
+ (apply str (repeat l/max-string-length "!")))))
+
+(t/deftest limit-vector-test
+ (t/is (= (l/limit-vector (vec (repeat (inc l/max-vector-length) true)))
+ (vec (repeat l/max-vector-length true)))))
+
+(t/deftest limit-code-test
+ (binding [l/max-code-points 8]
+ (t/is (= (l/limit-code '(:a (:b (:c) :d :e :f) :g :h))
+ '()))
+ (t/is (= (l/limit-code '(:a :b :c))
+ '(:a :b :c))))
+ (binding [l/max-code-depth 2]
+ (t/is (= (l/limit-code '(:a (:b (:c) :d :e :f) :g :h))
+ '()))
+ (t/is (= (l/limit-code '(:a :b :c))
+ '(:a :b :c)))))
diff --git a/test/propeller/utils_test.cljc b/test/propeller/utils_test.cljc
new file mode 100644
index 0000000..e952249
--- /dev/null
+++ b/test/propeller/utils_test.cljc
@@ -0,0 +1,8 @@
+(ns propeller.utils-test
+ (:require [clojure.test :as t]
+ [propeller.utils :as u]))
+
+(t/deftest count-points-test
+ (t/is (= 6 (u/count-points '(:a :b (:c :d)))))
+ (t/is (= 1 (u/count-points '())))
+ (t/is (= 2 (u/count-points '(:a)))))